 Hello, everyone. In this video, we're going to talk about Chapter 15 of Think Java. The topic is arrays of arrays or multidimensional arrays, and as a running example, we're going to play Conway's Game of Life. Now, this is a mathematical game, a simulation, if you will. If you set up a 2D grid of cells, the white ones are considered dead and the black ones are considered alive, and there's three simple rules that each cell in the grid abides by for each round of the simulation. Any live cell with fewer than two neighbors dies, as if it were underpopulated, and any live cell with more than three neighbors also dies, as if it were overpopulated. The dead cells, the white ones that have exactly three neighbors, like this one down here that I'm pointing at, that becomes alive, as if by reproduction. Mathematicians have studied this game extensively because it has very interesting emergent properties. So let me actually click this Wikipedia article that is linked in the chapter and scroll down to this table down here. Depending on various starting configurations of the game, they have either stable configurations that are still, or ones that oscillate, and they have this sort of repetitive nature given their initial state. They even have a variety of what are called spaceships that tend to move or fly across the game. And it's very interesting that you get these patterns that go on seemingly forever. This is called a glider gun, because based on the starting configuration, the cells come alive and die in just the right way to shoot out these gliders infinitely. There's also some starting configurations that are very surprising, like the R pentamino. So let me actually open this up in a new window. And this is the website comwaylife.com. If they actually have an interactive game player, so I can launch the player for the R pentamino, let me actually move my window temporarily. And I'm just going to hit the play button and watch this has five cells that are starting alive. But after, I think over 1000 iterations, it finally stops, right? So just with that very simple starting configuration and those three short rules of the game, you get these emergent properties that are kind of exciting to study and look at. Anyway, let me close these other tabs. And the point of this video today is to show you the source code for how to implement this game in Java. So I'm going to switch over to Eclipse and show you the three source files that are described in the chapter. The first one is cell.java, which represents a single cell of the 2d grid. The second file is grid canvas, which represents not only the grid itself, but also a canvas for drawing the graphics in Java. And finally, we have Conway.java, which implements the logic of the game. This is the class that actually has the main method. A good way to understand how code works in Eclipse, when you get it for the first time, is to step through the code with the debugger because then you can see the code executing one line at a time. So I'm going to double click this line 138 here to set a breakpoint and then click the bug button to run the debugger. If you haven't been using Eclipse for a while, you'll probably get a perspective switch window like this saying, hey, you want to switch to debugging perspective since you're about to debug now, you can click remember my decision. If you don't always want to see this window, I'm going to leave it for now and click the switch button. And a perspective in Eclipse is the window layout. So you'll see now I've switched to the debugging window layout and I can click this button in the upper right corner here to switch back to the Java development layout. So typically you're going to alternate between these two window layouts depending on whether you're writing a program or debugging a program. In the debugger perspective, you can see now my program is paused on line 138 here, which is this line that declares a string. And I'm just going to step over each of these lines, you'll see the shortcut key is f six for that. So I create the string Conway's game of life, I construct a new Conway object, I created j frame, and then I set some properties of that frame. And as soon as I say frame dot set visible true, you'll see this window pops up here. But let me make this one always on top so I can go back and forth between it and the code. And this is the initial state of my game. I want to actually rewind to where it ran the constructor code right here, and show you what that code looks like in the file. So here is the constructor for the, the default Conway game in the book, you're welcome to change this code if you'd like to have a different starting configuration. But you see it creates a grid canvas of five by 10. So that's five rows by 10 columns. And it turns on certain cells of that grid. So row two would be 012 down. And column one, which is one over, that's the first black cell here. This one is 22, this one is 23. And likewise, if I go down one row and over seven to index one comma seven, I get that cell, there's 27, here's 37. So again, all the constructor does is sets the initial state of the game. And then finally, there's a game.main loop. Instead of stepping over this line, I'm going to step into it. And that will then go to that method. And let me see all of its code. You'll see that the basic idea of the game is an infinite loop. So it's going to run this simulation forever. There are two steps. I update the state of the game, and then I repaint the canvas to show how it had changed in that particular round. And then it's going to do a short delay after each phase. So you can actually see the animation as a human being. Right now, the delay is set to 500 milliseconds, which is half a second. So before I go any further, I think it might help to stop this particular running program and take a look at some of the supporting classes. We'll come back and step through the rest of this code in just a minute. Cell.java is the simplest class. And this represents the state of a single cell on that 2d grid. So you can see the attributes of this cell are its x and y location on the screen or rather within the window on the screen. And then the size of that cell, which is how many pixels wide and tall, so cells or squares, you only need to store size, you don't need to store like width and height. Finally, the state of the cell, which is an index into the static array of colors. And the reason why there's a static array is if you go farther in the book, think Java, there's ways to extend this game to have more than just two states. So you might have like a white and a gray and a blue and a green state in addition to white and black. So but right now it's just an array of two options, white or black. The constructor of a cell basically just tells you where to place it on the screen. So it's just copying those parameters and attributes and setting the initial state to zero or white. And then there's a draw method for each cell that does the actual 2d graphics commands. So given the graphics context of where you would like to draw this cell, it gets, it sets the color to whatever state you're in. It fills a rectangle of that size at that x and y location. And then it draws a light gray border around the cell at well at the x and y location. So this one goes x plus one, y plus one. So you're inside by one pixel. And ultimately, if you have a 10 by 10 grid, sorry, a 10 by 10 cell, then it's going to be 10 pixels wide and 10 pixels tall. The rest of the methods are just helper methods for maintaining the state of the cell. You can see if it's offer on and you can turn it offer on, given those convenience methods. Let's take a look now at grid canvas, which is what actually is the 2d array example in this chapter. So you can see I have a two dimensional ray of cells, and I'll just call this array. This is the variable that maintains the state of the entire grid. And when I go to construct the grid canvas, you can see it creates a new cell given the number of rows and columns. So we call this row major order, it's an array of rows of columns as opposed to an array of columns of rows. And ultimately, it doesn't matter whether you store your data by rows and then by columns or by columns and by rows, as long as you're consistent everywhere in the code. And so you can't call the x dimension y and vice versa. You have if you're going to do rows as the first index of the 2d array, then that always refers to a row number. And that tends to trip up beginners if they flip their indexes on accident. Anyway, what this constructor does in grid canvas is it given the number of rows and columns, it figures out the y and x location of each cell, which is based on the row and column number times the size of the actual cell, right? So the first cell is going to be a zero zero, the next one's going to be 10 over, right, but also at y zero and so forth. And then it creates a cell at that particular x and y location and stores it in the array. Finally, it calls the set size method, which is part of the canvas class. And that sets the size of the drawing canvas on the screen. There's a bunch of other methods in this class for convenience. So if you want to get the number of rows, that's the length of the outer array. If you want to get the number of columns, that's the length of any one of the inner arrays. So I just say a race of zero to get the first row. And the length of that first row is the number of columns in the 2d array. There's also a get cell method, which will just get the cell at row R and column C. And there's a turn on method that will go to row R and column C and then call the turn on method, which is in this other cell class to toggle its state to black. And then there's some other methods like test and draw. So the test method is going to tell you if the cell at RNC is on, or it returns a zero if it's not. So this actually returns an integer, because as you see, as you'll see in a minute, we're going to add up these integers to count the number of neighbors. So rather than return true or false, we return one or zero. One means there is a cell at RNC and it's on zero means either the cell doesn't exist or it's turned off. The last arrays are just for doing graphics. So the draw command, sorry, the draw method will take a graphics context. And for every cell in the 2d array, it calls the draw method on that cell, which does the actual graphics command to draw it on the screen. One thing I want to point out about this example is it uses an enhanced for loop. So if you're looking for examples of 2d arrays, both with the standard for loop that just says int something is less than something plus plus, there's also the enhanced for loop that says for each row in my outer array, and for each cell in my row array, draw that cell. So go ahead and study those two methods to get a feel for what nested for loops look like on 2d arrays, both the standard for loop and the enhanced for loop. And finally, the paint method, which is called by the operating system to actually draw the thing on the screen that simply just hands it over to the draw method to do all the work. And there's an update method as well that's there just for convenience. So now that we've seen cell dot Java and grid canvas dot Java, we can actually take a look at this running application. You'll recall we ended here in the main loop that calls update and then repaint. Well, grid repaint is just oops, it's just this method over here that eventually called paint. What I want to show you is the update method. So I'm going to set a breakpoint right here in the update method to run the application up to that point. Let me go ahead and clear my breakpoint at the start of the program. So I only have this one that's currently active. I'll push the little bug icon on the toolbar. You'll see it's going to ask me again to switch to debug perspective. Let me remember my decision this time. I don't always want to have to click this button. So switch. Okay, now I'm in debug mode. I'm going to take my little game of life here and put it always on top. So I can just keep an eye on that as we're actually running the code itself. You'll see right now the program is paused because it's waiting for me to step through the debugger. And the very first step is to count the number of neighbors. So you'll recall from the rules of the game of life whether a cell becomes alive or becomes dead or stays the same depends on how many neighboring cells it has. And by the way, there's an illustration of this concept in the book when you get to section, it looks like where did it go here section 15.9 that explains the counting of neighbors and it sort of visually draws how many neighbors a cell might have depending on whether it's in the middle and the corner or on the edge of the grid. Okay. Anyway, I'm going to call this I'm going to step into this method, which is F five is the shortcut key. And let me show you what this particular method does. First, it gets the number of rows and columns just for convenience. So I don't have to keep calling grid dot num rows and grid dot num calls, right? So it's five rows and 10 columns. And then I create a 2d array of integers, which represents the number of neighbors for each cell at position r, c, right at row r and column C. And so for each row and for each column, I'm going to call this count alive method. Well, let me step into that particular method. And this is what count alive looks like. Again, it's going to call this test method, which I was showing you earlier in the grid canvas class, and looking at the previous row, the previous column, the previous row in the same column, and the previous row in the next column. So again, going back to this picture of the book, it's looking at all eight neighbors around a cell. And in fact, some of those neighbors might not exist. And so if they don't exist, the test method simply returns zero saying nope, that one's not alive, right? And if as I go through, I'm just going to step over these lines. But if you want, when you're running the code, you can step into them to see more detail. You can see that after calling grid dot test eight times, the count for this very first cell is zero. And we would expect that because you can see visually, none of its neighbors has any black cells. And so the total count is zero for that particular item. So let me go ahead and step back. And in fact, if I run the code to line 85, there's a really nifty way to do this. I have to remember what the shortcut key is. Well, maybe it's under the run menu. Yes, run to line is control R and Eclipse. So you can get out of a 2d loop that's going to take you forever to step through all the code if you just put your cursor on where you want to go and then run to line. And and in the debugger, you can click on the word counts and examine what that 2d array looks like even before it returns if you're just curious, if the code is working or what what the actual values are. So anything you click on in this particular variables window pane will show you the value of that contents, especially if it's something like an array or a 2d array, it's nice to examine the code in that window. Maybe I should pull this up just a little bit so you can still see it. Okay, so I'm going to return counts. Let me go ahead and step over this. And that was the very first step of the update method. The next step is to update the grid based on the neighbor counts. So if I step into that code, you'll see it also has a 2d, or sorry, a nested for loop structure to operate on this 2d array of counts. And the logic here is for each cell in the grid, I'm going to get this cell at that RC, and then call the update cell method. Well, the update cell method if I step into it is what encodes the logic of Conway's game of life. So in other words, if the cell is turned on, and if the count is less than two or greater than three, then I need to turn it off. And this is just repeating the rules from the textbook in comments, you can see how that corresponds to the code. Otherwise, if the cell is not turned on, and it has exactly three neighbors, then I turn it on, right? And, and so it's just one simple nested if statement in this method, and that basically encodes the entire logic of the game, which I find fascinating that such simple code can create very elaborate animations and simulations like the ones that were on Wikipedia or the, the arpintomino one that we saw in the Conway life wiki as well. So I'm going to go ahead and step return that basically runs all the code in this method returns to where it was called. And in fact, I think that's all the code in this file. The only thing left was count alive, which we already saw in the constructor. So I'm just going to let the program run. I'll hit the play button. Oh, let me remove this breakpoint so it can play for real. And you can see the simulation that was provided with the book includes two blinkers. These shapes are called blinkers. And the reason why is this piece in the middle always has exactly two neighbors. So it lives on the ones on the edge only have one neighbor so they die and then repeatedly come back alive back and forth. So it oscillates like up and down like that. So I'd encourage you to play around with the code step through with a debugger on your own computer, perhaps change the constructor and try different starting configurations to see that how that affects the code. But most importantly, make sure you understand how to manipulate 2d arrays, both through indexing them like r sub c, but also dealing with them in for loops, whether that's a standard set of nested for loops that just uses integers, or whether that is the enhanced for loop that uses the array and sell objects directly. That's it for today. Happy reading and good luck.