Hi, welcome to this new lesson. We are going to continue, this is the third video of a series of videos for our final project. We are writing Langton's ant algorithm once more, which we actually initiated in week four. We're writing this time using object-oriented programming. Now that we've learned about object-oriented programming, we are rewriting those ideas into classes, right, and multiple classes that interact with each other. This time, we're actually writing a grid class. And let it kind of have conversations if you want to send message to this ant that is going to be moving around and wandering around. So let's jump into the project. If you haven't seen the last two videos, I'm going to continue from code from those videos. What we currently have, it's a grid class that basically spreads itself throughout the size of a screen. And we are initializing it with some random data, right? So we're actually calling two functions here for the grid, the main_grid class, initialize the data, which is random at this point. You can put a comment there. I mean, you could initialize the data in different ways. You could have multiple ways of initiating the data, and we can look into that. You also have the grid.run, which currently it's being called within the setup because this is not a dynamic script yet. But we might want to later move that into a draw function if that data, for whatever reason, starts changing. And we'll see that the ant that we're going to draw, the agent that we're going to draw on top of the grid, will be able to manipulate the data. It will be able to switch data around, right? So we will be able to have a dynamic rendition or representation of this grid. But we don't have that ant yet, we only have one class, which is our Grid class. So let's go ahead and create another tab, which is going to be called the Langton, _Ant_Class. And we have a whole new area here. Just for good measure, I'm going to import, random, just because I know we're going to need it. And let's just start writing our class, right? So class Langton_Ant. Right, and here, we can actually write our constructor, which is going to be defined by our init function. And again, this is a class, the algorithm we covered already. So let's just think about what defines an agent that we will call the ant, right? Well, it needs to have a position in the grid. It needs to be located somewhere in an index in the grid, right? So we will need a variable for x and a variable for y. If you remember the videos on the Langton side, we will also need a direction, right? The ant can switch directions, it can move in different directions. So identifying the direction, we did that with an integer, 0, 1, 2, 3, defining four different kernel axis of movement. So we can actually use a similar thing. And maybe that's enough for now. Let's just close here our constructor, and let's just equate our internal variables of self.x to x, self.y to y, and self.dir. The problem that we are seeing right now is that this ant, actually, this x and y refers specifically to a position in the grid, right? And this being a class, we would need to be having a reference or some kind of information about the grid that we are relating to, right? There might be different ways of addressing the passing of information, but this is basically what this lesson is trying to address. Which is how do we start creating conversations or messages or interactions between different classes, right? So the first thing I'm going to do here is start thinking, well, I'm going to need to bring the grid, which is going to have its own definitions. We're going to need to bring that into the script. So I'm thinking, well, let's just bring a grid object, Right? So somewhere in the world, whenever I construct this class, this class will be needing a reference to that grid object, right? Because we're going to be able to use that grid object for the calculations, like neighbors. Move to a neighboring cell or affect the data of that grid and whatnot, all sorts of different behaviors, right? So for now, let's just create a simple function to display. Well, the way we're going to do this is we're going to create a run function, which is going to be a summary of all the functions that we will write for this ant, right? And let's just make some comments of those functions, right? So we're going to start with the display, or the drawing of the ant. Later, we're going to move to the ant behavior. And finally, we're going to check some form of stay within bounds, Functionality, right? And all of those we will cover over maybe a few different videos, right. So we will not just do all of those right now, but let's start with the display, right? So, Let's define the draw_ant. My apologies, I'm working on, not my personal keyword. There we go. So we have the draw_ant here. And if we really wanted to just draw something, let's do an ellipse, right? And we could say, well, self.x, self.y. And oops, same problem. I have self, Comma 20, 20. And the fill, let's just do a red fill for now, just to see this entity in this screen, right? We could draw the direction as well, if we wanted, as a line. But let's just for now keep this simple function. So instead of display, we're going to do self., draw_ant. We have something that looks And it should actually not be positioned in the x and y coordinate of the world. It should actually be located somewhere in the grid. But, this way we could actually start testing if to see, we're running into errors and how do we can call this Ant into the world, right? So, first of all, if we run this, we haven't called the ant yet so, we don't have any issue. So, let's create an instance of this Ant in the world, right? So, the first thing we're going to do is import Langton_Ant_ Class as Langtons or LA, right? And then, we created one instance of the grid here, right? And let's just make a comment. [SOUND] And here, we're going to do the Ant. I'm going to make plural, because, we'll see that we could potentially have more than one. Like one of the things that we couldn't do, or at least the way we wrote first Ant, was written in such a way that basically you're learning the algorithm. You're understanding how everything works but it's very difficult to scale, right? We actually wrote it as a one-off version of the script and someone looking at the script might think, well, this is not a very efficient way of doing it. Because if you want to have two Ants, it's actually you have to kind of duplicate a lot, right? You have to kind of, change a lot of that script. Well, the object oriented version of this script will give us the chance to have multiple instances of this Ant, all of them operating under the same grid. And that's kind of what we want. So let's just create Ant_1 = to LA.Langton_ Ant. And here, we will provide, this is a constructor, right? So, let's just provide some data. And what are the data that we suggested was important and needed for this class? Well, we said x, let's just give a value of 50, right? Then y, it's going to value of 50, direction. Let's just give it a value of 1. And, you can do everything in one line. But I just like, spacing out, these variables just to make them a little bit more, visible, grid object. So what is the grid object, right? So, the grid object is going to be our main grid, right? So, this is where we're going to be passing, right? One of the attributes of the Ant is, hey, give me a grid object that I can work with, right? I need to live within a grid structure, which is kind of a requirement of what we're intending, right? So we are actually referencing we're passing, as a grid object, the main grid, that was created here. So now we have our Ant we have satisfied all the different requirements of the constructor, right? So we should have, an Ant_1 object, right? And we could test, to see we can call some of its functions. So let's go and, do Ant_1.run, right? So, what we're trying to do here is invoking the run function which in itself is going to call the draw function, right? Which is currently only drawing an ellipse but we're going to replace that code with the actual calculation, right? So, let's just save this and see we're running into errors, right? So we're not we have an instance of the Ant here as you can see, is nowhere. It's actually quite arbitrarily placed in space, because it's using its x and y, which is in this case 50, 50, to place an ellipse, a red ellipse, of an arbitrary size again, right? So, we do have an instance of that class, in the world. Just for good measure we could actually do the following which is, copy paste all this, and have, two instances, of this class. So, I'm going to do maybe something like, 80, right? So, same data, but, basically a second instance of that class, right? Let's call it Ant_ 2 and then, we're going to call the function run for both of those. And, you'll see that we now have two instances of the class, right? So, as you see, this is kind of the beauty of working with object-oriented code, where we are writing one class. But it's rather easy to kind of create a new instance of this class, give it different data, maybe a different location to start, or perhaps even different behavior later on. And let them, operate independently and, behave and relate to one another as well. So, we have two of these Ants in the world, but they're actually as you can see here, they're actually a pretty. Sorry, this is the grid class, but let's just kind of focus on the Ant class. So, we're using a very placeholder function for drawing, right? So, let's just draw, a correct representation of what we want this Ant to be, right? So, we're going to keep the red color. Okay, so, in order to access some information of how to draw in this Langton Ant correctly into the grid. As we do have a reference to the grid object, we can actually access functions from this grid object, right? And there's some functions that it would be really useful to have. So I'm going to go back to the grid object for a moment. And you see here we actually got this get data, function, which is a kind of a handy function. But there's going to be a few others that are going to be incredibly important for us to have and it's going to make our life easier, right? So, let's just provide some kind of functions that are not used internally, but they might be used by the Ant, right? So, let's create a function call index coordinate in x, and it's going to use a self and an x, as an argument, right. So, we're going to return, I'm going to be a very quick function. It's going to return the x times the self.screen_width divided by self.com. So, I don't want to be doing this calculation in the Ant. I technically could have access to all this information in the Ant, but, I want to be able to access one line. Which is, hey, if I give you an x value, can you give me the information of what would be the coordinate of that index in x, right? So if I give you the index value, right, I need to get the real-world coordinates of that, right? So this would be the function for doing so, right? Let's just do another one of those, and we're going to do that, this for y as well. And again, these functions are going to be very useful for us as we are converting. Converting index data into real world coordinates, right? And making a graphic representation of an entity that is operating within, Within an index of a grid, right? So let's go screen_height and rows, right? So those two functions, again, what I want to do, like think about the ant, right? The ant wants to be drawn using an index value like x, is going to be its own internal x. And this function is going to return where in the grid? What are the world coordinates for that grid position, right, for x and y? So what other functions might we need? One of the things that we actually do here is the calculation of the cell size, right, which we use for the size of the rectangle. But that might be some information that it's not really known by the ant, right? So let's create a function that will help understand the cell size for another entity, right? What internal is being called cell size, right? Is something that could be accessed by the ant as well, right? So let's return, in this case, self.screen_width divided by self.cols, right? Which is the same division that we've done before to split the screen into the number of columns we have, right? If you can look into here, this is the same calculation, but now, we're doing it as a kind of a function. And we could have written this as a function in the first place. I guess that could have been slightly more convenient way of doing it. But here we are, screen_height and rows. So I guess, my thought process here is that these functions, I'm realizing, the ant will need to establish communication with the grid. And in order to have that communication be smoother, if you want, not really kind of involved a lot of this math in the ant side. We can actually create these functions, which are going to be almost messaging systems in a way that we have between the and. Or the ant will be asking to agree that, hey, what is your cell size? The cell size is actually this calculation. If I give you an index, what is the world coordinates for this index? And I'm going to get this back, right? That's the logic behind what we're doing here. These are four different messaging functions, and they're specifically needed for this ant to be able to be displayed, right? As you think about it, the ant wants to show in one of the cells, specifically in one of the cells in the grid, right? So let's create the x coordinate of the ant. It's going to be self.grid_object, Dot. And with the dot operator, we're actually going to access the index coordinate, right, index x, right? Of what? Here, we need to provide the argument, right? So self, .x, which is the ant x value, right? So that's the x coordinate, right? I'm going to just leave this for now, we're going to see there is something missing here. And let's do this for the y, And coordinate y, and then self.y, right? So we have that. And then finally, instead of using the x and y, which now we're going to consider those to be index positions, not real world or world positions. We're going to use this new variables here, right? So that's good. This slightly smaller, just to kind of be able to see, or how these rectangles, or this ellipse. So we don't see them in the screen. That means that we're probably running into a mistake at the moment, right? So let's see what is our issue at the moment. Okay, the first thing we need to check is what coordinates are we actually asking them to draw, right? Let's just go into our grid. If we think about it, our grid has 80 columns, and we are saying, well, draw in the coordinate 50, but this is an index now, it's not a world coordinate, right? So, and why? We only have 40 columns, or sorry, rows, right? So we're actually kind of out of bounds. We're actually asking for something that would not show up in the screen at all. So let's just do a five and a five. And in this case, 10 and a 5, Right, let's see. So we can see here now these circles appearing in these positions, right? So now we know that the x and y represent indexes, one, two, three, four, five, right? The indices in the grid as opposed to world coordinates, right? But it actually seems that Ruby's cutting through, it's not really positioned very neatly in the grid, right? So let's just correct a little bit how this is actually displayed. And that's because we have to take in consideration the cell size and how we're drawing that circle or rectangle. Let's just switch it to a rectangle so that we have a little bit more control, right? So one of the things that we're missing is the cell size information. So let's call this cell_x. And the cell in x is going to be self., same thing, grid_object. But we're going to use the second function we created, right, if you remember, cell size in x, To calculate that. And we're going to say, well, the cell size, that's a cell size, right, In x. And let's just get it in X and in Y. And we have the cell size. What we really need for the coordinate to be right is that we need to add to the coordinate half of the cell in x and half >> Half on the cell in y, right, just because we need to push it, half of its size into the grid, right, so cell size x divided by 2 and plus cell size y divided by 2, right? And we can actually use the cell size as well for now we know that the coordinate is going to be, Like so, and here, let's just switch this to a rectangle. And let's also say that the rect mode, which is the mode by which we are drawing the rectangle, just make clear that we are using the center mode. You can look into the documentation of processing, but there's different ways of drawing a rectangle. We're going to be placing the x and y coordinate in the center of the rectangle and expanding it in both directions from there, right? Let's see what we get now. So you can see here now we have two rectangles in the grid and they should be matching quite accurately the grid itself, right? And that's what we wanted, we actually wanted a system of a unit, a grid, sorry, an ant, that feels like it belongs to the grid. And everything that we're going to do from this position onwards is going to be demonstrating that the ants belong or participate in a way to this grid. Let's just do what we have done in past videos of just changing a little bit the resolution here maybe to see this better, right? And as you can see, as we change the resolution size to something a bit more visible for us, the size of the ant also changes. And the index position, it's always referring to, the coordinate we're providing is actually based not on world coordinates, but it's actually index coordinates, right? So we have the units in five and five and then the ten and five, right? So we finally have a grid entity and completed. And we also have an ant that is displaying itself on the screen in and really taking in consideration its index information in order to kind of displace itself correctly. So now we're actually ready to start working on the behavior, so we're going to to continue on that in the next lesson, so I'll see you then.