Hi welcome to this new lesson, so we are here in the final video, this has been a five part video of this final project where we're actually really putting together everything that we've learned so far in terms of data structures and object oriented programming. To craft the behavior of a lank transient in an object-oriented structure, we've written the Langston's hand already, we're rewriting it in an object-oriented way. And we think that really looking at these two, how do you convert a script like that into an object-oriented script using two classes and how those kind of relate and dialogue with one another. It's kind of an interesting challenge for the conclusion of this course, so let's just jump back into the project and see how we can actually conclude this lesson. So this is where we left off, let's just run to see, we have two ants that if we look into our main script, so we have an instance of a grid and two instances of two, and we can actually have more of those. We can actually do ten, any number of, and at this point, and in the setup, we only are calling for the initialization of the random data, right? That the grid can actually start with random data, and then in the draw, we actually only execute one function of the ands and the grid, right? So we're using an outline style of functions, which is the run function for all of them contains the series of functions or methods in a way that we are going to be executing. So let's go back, this is the grid class that we've been writing, and this is the ant class that we've been writing. And here, one small detail, I actually moved the stay within bounds, if you look at the last video, I originally had stay within bounds within the behavior. I'm actually keeping it in the run so, as we had outlined originally, our ant's run function will contain the display of the ant, the ants behavior, and stay within bounds. So we have all the pieces, the only bit that we're going to be working on right now is the ant behavior, which we are using it as a placeholder currently with this move forward function, right. As you know, the Langton ant algorithm actually changes behavior and movement based on the data of the grid, so this was a placeholder, right. But we can actually leave it there for a moment, let's just write what we want to do, so we want to check first, if the cell is white, do something, right? If the cell is black, do something else, right? So let's just start with the if self dot grid object, right? The way we have access to the grid, as we've seen in past videos, is by this grid reference object, and here we would need to get the data, we actually want to access the data by the index, right? So if we look into the, we actually have a function that, this function here to get data function, it will give us the coordinate, just to be more precise, if we provide the x and y index is going to give us the real world coordinate for this function. So we need something else, let's call this define get data by index, And here we're going to use self, and just to be clear that we are giving the index x index comma y index, right? And then the index, Its going to be x x index plus y index times self dot columns. And finally we can return. So we're doing basically a similar thing than before, before we're actually taking in consideration a world coordinate because we had to divide that by the height. In this case, we could actually do this calculation in a simpler fashion, what we're actually trying to do is saying, hey, if I provide you an index, would you give me the data that is contained within that index, right? And that's what, this is the function that we actually need at this point in the, and let's just jump into the, and, and here use this new function, right? This function didn't exist, but it's going to be now easier to access that data if we provide now self x comma self y, right? And we're going to say if that is equals to one, which is equivalent to white, do something, right? What do we want to do, we want to rotate clockwise. And I'm doing this as a comment because we don't have these functions yet, right? We want to flip data and, then we want to move forward. And in the case, let's just do an Elif statement, in the case it's black. So elif, in the case, the same calculation returns a number, sorry, a number, zero, my bad there, right? What we want to do here is rotate counterclockwise, Flip the data, what I mean by flipping data is like, if it's black, turn it white, if it's white, turn it, and so on, right? And move forward, Right, so let's just organize this a little bit, this is kind of an outline of what we're doing. The move forward. Forward function we actually do have, right, so this we don't need anymore. Let's cut this so we can actually replace the move forward with the pieces that we actually do have. In both cases, the move forward happens, right? So now we have an outline of what it's missing. And this is what we're going to write right now, right? So we need the, let's just first, just for good measure, right. I'm going to save this and then make sure that we're running. So we are running into an error, because we added a bunch of new code. I think we're running into a missing of a parenthesis somewhere here, right? Is that what we started there? And then we are actually missing here as well, let's see. Okay, so here we are, yet again. Everything is running, okay, that's good. So let's just write the function. We've written these functions already, so if you want to go and find them or copy paste them from your past video, we can do so as well. So defined, rotate clockwise. And I'm going to do 90 because, just to make sure that we giving evidence that we're doing a 90 degree rotation, right, it's not really important, but I like kind of keeping track of how we're doing things. So if self.dir == 0, then self.dir = 1. Right, and that's our rotation, right? We're just flipping an integer from 0 to 1, assuming that 0 means to the right, 1 is facing down, 2 is facing left, and so on, right? So we can do this with a series of elif statements. So elif, now we go to the next one, right? So if the direction is 1, we move to 2. Let's just do two more between. If the direction is 2 becomes 3, 3 becomes 0. We go back to the first one. Make sure to do an elif statement as opposed to a series of if statements. If you make a series of if statements, you're going to execute the first condition, that's going to be true. The second condition that's going to be true, you're going to basically return to where you started, right? So this is the clockwise rotation function. I'm sure you can find beautiful ways of writing it way shorter than this chunk, but I invite you to consider that I'm going to add a new function here, which is counterclockwise 90, right? So if you go from 0, you're going to get 3. If you go from 1, you will get back to 0. If you have 2, you're going to end up with a 1, and if you have a 3, you're going to end up with that 2, right? So we have now the counterclockwise and the clockwise rotations. So let's just replace this. So with self.rotate clockwise and, self.rotate counterclockwise, right? So that's good. I think that the only thing that we're missing is flipping the data. Let's see if we're running into errors here, we are. Yeah, so I think we were having just a small indentation issue. I just kind of cut and paste the functions a little bit to kind of, there was no kind of syntax error, but I think we're having, I couldn't find quite quickly the indentation issue, but just by copy and pasting the function, that kind of resolved it. So now we have the behavior of the ant. As you can see here, we have the rotate clockwise when they're in white cell and rotate counterclockwise when they're in the black cell. So basically the only information that we are needing is a new flip the data, right? And for this we actually will create a final function which is going to be a handy function for altering the data. And we basically can do a function that is basically allows us to manipulate, we're going to call this set data by index. So set_data_by_index. And this set_data_ by_index function will take an x_index coordinate and the y_index and the value, right? So we're going to say, hey, what value do you want to provide here? So the index, as we have seen before, we will use the same index calculation that we've done so far. There we go, the index calculation and the data. Instead of returning, we're going to just assign the data. So self.data with that index, it's going to be changed to the value, right? So this function here, this is a helper function for the grid class, which is saying, hey, if you are in index, let's say 5,5. And you want to switch that value to a value of 1 or 2, right? Sorry, 0 or 1. Just give me the value you want, the grid will assign it to the cell. Probably what you want to do at this point is just make sure that your data validate that data in some way or another, right? Making sure that if it's a value outside the bounds of 0 and 1, you cap it to 0 and 1, right? But besides the scope of this class, what we're hoping is that we have a way of communicating, sending information from the and to the grid saying, hey, I'm here, I'm moving. I actually want to change the data where I just, where I have been. And this is going to be the function that's going to allow us to do that, right? So let's just go back to our ant class and instead of flipping the data, which was a placeholder comment on that, let's do self.grid_object, right, as you can see, we're using this grid object quite a bit. This reference set data by index, which is a function that we just wrote. And the value is going to be self.x, self.y, which are the index coordinates of the and 0 here. Because if we are in a white cell, we want to provide a value of 0. We are assigning to this cell, we're switching its value to 0. And if it's 0, we're going to switch it, we're going to do the same thing. But 2y is on a value of 1, right? Because, remember that this function set_data requires the x and y coordinates plus the value of the cell that we want to assign, right? So, black cell will become white and the white will become black. So I think we have it, let's see if we don't run into any errors again. Yeah, there we go, we have it running, right? So, what's going on? We have, as we've done before, a Langton Zen algorithm that is actually moving based on the grid it's working on, but at the same time it's changing that grid, right? So by changing that grid, there's a pattern emerging. There's a kind of a pattern of behavior emerging. And in this case, we actually have two ants, so we only have one. And so, this is what we actually call complex_system, one system that actually has interactions. There's a very interesting interaction between the ants and the grid. The grid becomes the canvas for affecting the behavior of other entities, right? This is at the foundation of many algorithms, such as Stigmergic, which is used for simulating the behavior of actual ants. Ants, as they move around, they leave a trace of a phenomenon, and that is actually being picked up by other ants to actually optimize paths. So simulations of such systems use, or might be using a system like this one, where you're actually leaving behind information in a grid, and that could actually be dissipating over time. Let's just do a small variations. Let's see a few things. What if we actually run this with larger grid? So, something like 80 and 40? Again, our ants should be able to handle that, like our system should be able to handle that. The other thing that I would like to test with you is an invitation to how we initiated data here. What I like doing, if we go into the grid, we could actually say, the init_data. Let's just create a variation of this, right? Let's just copy paste this somewhere here. And I'm going to do a version of that. This is showing you maybe how you can actually start designing with this. So, init_data_2, and instead of doing a random number, we're going to say, hey, everyone starts with a number 1, right? So instead of doing a random value, everybody starts with a white cell, right? So once, instead of calling init_data_1, How did we call it? Init_data_2, yeah. So we can actually swap to this different function. So we're leaving behind the random, but you can see we can actually start with a completely white canvas and that makes it quite more visible for the ant's pattern of behavior to emerge, right? So feel free not to necessarily start with a random canvas, you can start with a white canvas or a black canvas or half white, half black. You can create a function for that. I'm really curious to see what you will do with this. Finally, and again, the invitation with object-oriented programming, I'm going to create a third ant. And I know that this is a very manual way of doing it, you can actually do it, as we've seen, to do this in a for loop. But I think that fortix, I'm going to leave that more in your hands. I'm going to just put a 30 and maybe a 20, right? And the direction doesn't matter at this point, the direction and, Ant3.run(). And you can see we actually have three instances of these ants all operating under the same canvas. So, just to wrap up, this has been a five videos series. It's a final project that we're concluding, a data structures section. We're looking at how different data structures, such as in this case the grid, and also how we're actually using object-oriented programming to create simulations that have relationships with one another. The ants are talking to one another through the grid and the grid becomes really the canvas for some data to be stored and passed around. Yeah, when I started programming, these kind of simulations were mesmerizing and really interesting to be curious about, what else could you do with coding and using these techniques for design? So we invite you to share with us all the design variations and permutations that you might be doing as you learn how to code yourself. So, thank you for staying with us, and I'll see you in the conclusion of the class. Bye.