Hi, welcome to this second video of how do we write a wave function collapse algorithm? And we're going to start with setting up our environment. We will actually write two classes. One class would be for the environment, which it's going to be our grid, and that's going to be basically a list of tiles. And not to be confused with the tileset. The second class we're going to actually create will be the tiles, right? We need to make sure that each cell in the grid has four instances of the different tiles, basically all the different tiles that it could actually be, right, so representations of the tileset, right? So let's get started by writing these classes in processing, we have here the boilerplate code that we usually use. These are setup and draw. Let's just create a new tab, we're going to call this environment. And we're going to also create a second tab called tiles. We're going to use this one for the grid, and we're going to use this one for the tileset. Let's actually start with the tiles because they're a little bit easier, for good measure I like always imported in random. I'm not sure if we're going to be using that, but still. So we're going to use the class Tile, and define the constructor without any data for now, right? So self.name = None. Just to have something, we're going to be adding a lot of information to the style as we go along, right? But I do want to have something. Let's define a display function so that we can actually see the tile in the screen. In order to kind of look at this tile in the screen, we're going to need a location, an x and a y, which is going to be the location. And we're going to need the cell_size of the tile. And we're going to use a variable called entropy. So the entropy is how many possibilities this tile can actually be in. We're going to be calling that entropy because if it has very many possibilities, or reducing its entropy would mean reducing its possibilities, right, it's going to have a more clear kind of definition of what that tile is, right? So let's start by giving it a stroke of white and 80. This is just some values that I tested before in terms of visualizing the styles correctly. So let's do a pushMatrix. There we go. And a popMatrix, right? And between here, let's translate this tile to x, y. Let's define the rectMode. It's going to be CORNER, and the rectangle will be 0,0, cell_size, cell_size. So this is kind of as simple as a class we could get. It's actually just a tile that basically has a position. It's basically a rectangle, but we're going to be using it with a lot more information than this. So let's just roll with it. At the moment we have a very simple tile. What we want this tile eventually to have is possible different states, right? The tileset would represent different compatibilities that it will have with adjacent tiles around it. So that information is not quite relevant just yet, we're setting up the environment. So start with that, right? Now let's just write a grid class. And I think we've done this several times. So if you want to skip a little bit ahead, I don't think there's going to be any very important lessons here. We're going to import the tiles from the tiles file the class Tile. I think that that's how we call it, right? So Tile, yeah, perfect. So the class Environment, we are going to define it as, It's going to have a certain number of columns and certain number of rows. We also want to know how large the world is in x and in y, so that we can adapt to the size of the world. In this case, the size of the world will be the size of the window. But yeah, if you wanted to have a more specific kind of this algorithm working in a different size, that's something that you could specify as well. Let's just go ahead and, Making sure that. Let's do that for y. Right? And here we're going to add a new variable that is going to be self.cells, and it's going to be an empty list, right? So we're going to have all the cells of this grid as an empty list, right? I also want to have a variable that defines the tileset, right? So we do have a tile. But we're going to define the tileset. So self.tiles equals, and here it's going to be a list. And I'm going to close this list somewhere here. And here's where I'm going to initiate my tile. So like that, right? So this is going to be our first possibility. This is going to be our second possibility, right? And right now all of them are the same, right? But bear with me later we're going to start adding arguments to this tile so that each one of them has different connectivity. But let's imagine that we want to have a tileset of four tiles, right? So this variable tiles, or you could call it possible tiles, will represent what are the possible tiles that each cell can actually be? So we're going to do four options, right? So this list contains four copies of this, or instances of this class tile, right? So that's going to be our A bit little space for this. Let's just create a bit of space here. So that's great, we have that going on. That's the main data that we will need for the environment. Let's just, now what we want to do here is create a function that will initiate the cells so that we can initiate all the cells and it would actually create instances for each one of those. So let's call that function def init_cells, Right? And init each cells, as we've seen before, it's going to be a nested for loop, for i in range(self.cols). We're going to create a row, it's going to be an empty list, and for j in range(self.rows). So now we will append, so let's pick the row and append to that row. What do we want to append to that row? We want to append a copy of our tiles, right, so self.tiles. And here's a trick, not a trick, but in a way a technique that if we would just assign that, basically we would be referencing, right, this variable here, right? But what we want is to, because we want to do this in a loop and we want to do it like create a copy of that variable to each one of our cells. We're going to use this slice notation. So this is a notation that allows us to slice a list and say, well, I want the elements from, maybe in element 0 to element 3. Or we could actually select elements within the list. But if we just use this column symbol, it would actually give us the whole list, basically all four elements. But it will give us a copy of this list as opposed to a reference to it, right? Because we don't want all cells to have a reference, we want to have individual copies of the tile set, right? That's perfect, and now we can actually do a self.cells.append(row), right? So in this way we are actually initiating all the cells. Each one of the cells will have four copies. Now this function, we could actually call it, in the beginning here, we could say self.init_cells, right? So that's great. We at this point we should have the cells initiated. We wouldn't be able to see anything just yet. For that, we're going to do a function as we always do. We do a function run. It's going to be like what we want to be running every frame, right? So let's do a function run. And that function run will only have an instance of one function for now, which is going to be displaying the grid. So let's create that function called self.display_grid, which we haven't built yet. So let's just make that function, so def display_grid(). And what is a display_grid? Similarly to the construction of the grid, we have to do a nested loop, right? So we know that we want to do for loop. We can copy that from here. We're going to do a loop, for x in range of columns, and for y in rows, right? The other thing we want to do is calculate the size. So let's just do a variable here, tile size. It's going to be a float, which is the division between self.world_x. Let's divide that by self.cols, right? So that's going to give us the size of the tile. And if you think within these two loops, what we want to be doing is calling this function display. What I would like to do is eventually separate the visualization of this tile. If it has multiple options, if it has, let's say four options, I would like to see a cell that shows me a number four. But if it's in fact collapsed, we would like to see that cell having the representation of its actual tile. So I would like to expand this a little bit. Let's just write that down and saying if your possibility space, right, how do we check for that? We would need to check if the cells x and y, right, which is what we're checking within these tiles, has only one tile, right? Then in fact is collapsed. Otherwise it has many possibilities, right? So let's just write it right away, actually. So we're going to go here and say if, let's first check, if the length of, So if the length of these cells equals 1 here, we will say that the tile self.cells[x] [y] [0], right? And that is what we're doing here. We have a list within lists, right? x and y, it's representing the grid position. But then each one of those cells has many options, right. We're seeing, if there's only one left, if the cell has been collapsed, right? This is a way of saying if the cell has been collapsed, it will only have one option, therefore we're going to pick its first element. So let's imagine that you have four tiles. If you have four, that's more than one. So that's not going to be the case. But if you only have one, let's just pick the first one. If that's the case, we could tile.display. And here we're going to use the display function, I might need a little bit more extra space just to give the coordinate, because here the coordinate will be x. Roughly what we want to say is x, y, it's not quite right, the math for the position, but bear with me here, tile_size. And the entropy right now, let's just put a 0, right, for now, it doesn't really matter too much, but this is not going to be the right coordinate location. We want to use the tile size multiplied by the x. X and y, which is just the count, right? So this tile is going to be in x times tile_size, in times tile_size, right? We've done this before is how do we kind of position the cell in the right location, right? Okay, so that's one way of visualizing the cell. Else, meaning that if it has only one option, else we would like to use random.choice. So pick one of the possible tiles. This is just not really necessary, but if you wanted, you could actually visualize a random tile. What we actually want to do is have a different visualization method. You see how the tile has display method, right? Which is this display method. Let's just write a display method that allows us to see all the possibilities of. lf the tile hasn't been collapsed, we want to see a number four, right? Let's say that shows this tile hasn't been collapsed yet, it has four different options. So how we would do that? Let's do define display_entropy. And we're going to use self. It's going to be very similar to the previous one. So you can actually copy-paste some of this information. Because basically, it's not going to change its location. It's not going to change anything at all. Except that instead of showing an actual tile, we're going to be showing a bit of text. Let's just define the font. So I would select the Consolas font Bold. The text size is a variable. So we could say, let's start with something simple, something kind of arbitrary. And then, later down the line, we could see how we can maybe modify the size if it has many options, or small number of options. So let's say the size of this tile. Let's say something like 12, right? And then, the textFont would be f. And finally, we can do this kind of push and pop matrix sequence which we've done before. Basically, push translate to x. Let's just make sure, let's say fill (0). And we do want to do a rectangle. Yes, we want to draw the boundary of that cell. But let's just also do the text, which is going to be the str, the string version of entropy, right? And entropy is a variable that we're going to be passing. Meaning, how many options do we have? And where is the location of this would be cell_size 2- 6. This is kind of something I pre-tested, but feel free to modify this number. And see, we're just trying to kind of displace a little bit the location of the text in relation to the cell. So cell_size/2, in this case, plus 6, right? So let's just see if it works. We've been writing a lot of code without testing. So I would at this point, really would like to make sure. Let's just do one more fill here, which is 255, just to make sure that the text is white, right? So the rectangle for the cell is going to be black background. But the cell itself, which had a white text that would show the variable entropy, which we are defining here as an argument. So as we said, when we're displaying the grid, if the cell has been collapsed, we will show the actual cell, but at this point, all cells will have four options. So we would actually, in fact, use this different display function, which is called display_entropy. So a tile.display_entropy. Is that the way we called? Yeah, display_entropy. That's the name of the barrier of the function. So display_entropy. And here, we can actually use the same attributes of location, right? Exactly the same arguments. Let's just give a bit of room here. The only difference that we want is that instead of, say, presenting a number 0, we want to present the actual entropy size, right? Which we could say the entropy equals the length of how many possible tiles we have available, right? So if we just look at the cell xy, right? How many options do we have? Do we have four? Do we have one? Do we have 16, right? That's the entropy that we're passing, right? So let's just use this entropy value here. And we could do that also for this one. But this one is not going to be displaying its entropy. This is going to be just displaying the cell. But at this point, because all cells will start with four options, should always default to this visualization, the visualization of entropy, right? So we have quite a bit already written down for our environment, and this video is getting quite long. So let's just kind of wrap it up by calling this function and see if it all works here. So let's, from environment import. We're going to import that class, and let's create an instance of that class. Let's just create a, just for good measure, a global my_environment. And my_environment would be an instance of environment. Let's do a grid of 30 by 15. And using canvas_width and canvas_height as the world size, right? And finally, we can run that environment. We're going to save here, and make sure. And we're going to try to run this, and see if we have errors somewhere. I'm sure we're going to have a few errors, so let's just figure it out. Okay, so we are running into some errors. Let's just see where those are. By checking a little bit the code here, I think I realized we had a bit of an issue with indentation. There wasn't really kind of many syntax errors. But make sure that all your indentation here, for some reason, I didn't see that my indentation was off, so I just corrected that. Making sure that all the definition of functions is actually happening in relation to one another, especially in this environment. Class, I think the other class is actually working pretty well. Let's see what we have right now. So what you could see is this number 4. A small error, or something else that we would like to add here is that this display_entropy. Let's just do here, where it says fill (0). Let's do also a stroke (255, 80) of white edge to this cell. So we can see now the grid, right? With a number 4 inside. If you think that the number 4 is too small, you can increase the size of the text size here. Maybe 16, something like that. So that's pretty expressive, right? And what is basically happening at this point is that we are not using at all this first part of the if statement that is showing the tile. We're going to get here, we're going to get to the moment of collapsing the tile and showing something. But so far we are just going straight into the display entropy because each one of the tiles has four possible options. Right, we have our nested loop for X and Y, which determines where the cells are located. But then, inside each cell, we have four possible tiles. That is what we're calling entropy, right? So with that in mind, we have our data structure, basically the two classes, the grid and the tile set. Ready to start kind of using some information, and we start moving into what is the collapsing of the cell, and the propagation, and so forth. So with that, I leave it here and I'll see you in the next video.