What does this mean? Well, it means that we need a graphical representation of a Tic Tac Toe board. This board, when the correct places on the board are clicked on by the mouse, should add the X's and O's that are needed to play the game. When someone has won the game, the program should do something to let the user know that they won, lost, or tied the game.
Understanding the specifications, this is what I came up with.
Do you want more indepth specifications? Check out Saul's: Specifications and Silly Premise
The first thing I did when I realized I had to program Tic Tac Toe was to sit down and play a few games of it. I looked at the Tic Tac Toe board and thought about the easiest way to draw it using GP shapes. I originally thought about using GP lines to draw the board, but then I had a problem, how would the other parts of the board be able to react to a mouse click?
That's when I came up with a better idea (or so I thought). I decided to represent the board as squares that had small spaces between them to simulate lines. To make this look more convincing, I set the frame color to be black and the squares to be gray, so it looks as if the applet window is made up of lines, when in reality its made up of squares.
Squares helped me because all GP.Graphics.Shape's have a React() method that automatically gets called whenever the mouse clicks on it. This means that if I made the board out of GP.Graphics.FilledRectangle's (since there is no actual square, you just set the width and height of the rectangle to be the same) then all I'd need to do is redefine the squares React() method to insert a new shape, an X or an O.
Having this general idea about how I wanted to represent my game, I decided to make up a quick design diagram. I thought I'd have an abstract Piece class, and then have three subclasses of it. The abstract Piece class would extend from a GP.Grahpics.FilledRectangle, so all of my pieces would be squares. The three subclasses would be just a blank square, a square that contained an X, and a square that contained an O.
The blank squares would be used to make the board at the beginning of the game. Instead of having a loop going through and waiting to get the player's input, I realized that I could just redefine the blank square's React() method to insert a new Xpiece or Opiece. This way, the game isn't controlled in a loop, the players just keep clicking until the game is over. When the game ends, I could set a boolean flag to tell whatever was inserting the new pieces not to do anything.
After figuring out how to represent the different pieces, I thought about how to represent the board in a data structure. I thought the best way to do this was to have a Board class that contained a two dimensional array of Piece's. When the game started, the array would be full of BlankPiece's, and as X's and O's were inserted the array would be updated. This made it quite easy to insert new pieces, since all the Board needed was the piece's array coordinates, and then it could store it. The Board class would also have a method to see if the game was over, since it could look through the array for a Tic Tac Toe.
Now that I had a way to represent my board and my pieces, I thought more about my design and realized I had a few problems.
Problem 1: My original idea in having BlankPiece's was to redefine their React() method to insert a new X or O into the Board array and on the screen. This proved to be a problem, how could a BlankPiece know if it needed to make an X or an O? How would a BlankPiece know if the game was over so that it shouldn't insert a Piece?
Solution 1: The first solution that jumped into my mind was to use a holder pattern. Every BlankPiece could have a reference to a holder that contained a Piece. The holder would return its piece, and then be in charge of making the next piece of the correct type. This seemed like a good idea except that there was still no good way to use a holder to check to see if the game was over. Then I thought about what class was in charge of checking to see if the game was over: the board. Why not delegate the authority of inserting the new piece to the class that actually has the reference to the array and knows if the game is over?
Solution 2: Instead of using a holder pattern, I delegated the responsibility of inserting to the board. All the BlankPiece's would get a reference to the board, and then when clicked on they would tell the Board to insert a new piece at their coordinates. This way, the BlankPiece's don't need to worry about if the game is over nor whose turn it is. Instead, there is an instance variable in the Board class that keeps track of whose turn it is. Also, we make sure that we only insert the new piece if the game isn't over. This way, once someone wins no more pieces can be added to the board.
Problem 2: I represent the X's and O's using classes that extend off of a filled rectangles, how can I get them to draw an X or an O?
Solution 1: Why not have the Xpiece and the Opiece classes have a reference to their own GP.Graphics.Shape? This way, when we instantiate an Xpiece or an Opiece, we can also instantiate the X or the O in its constructor. Since the piece itself needs to be positioned (it is a square on the board just like the BlankPiece's) we can simply position its GP.Graphics.Shape at the same time. This way we get the square in the right place on the board with its X or O in it.
Problem 3: How can I get the Applet so shrink wrap without putting all my squares in a column?
Solution 1: Use a GP.Containers.Frame. This way the Applet shrinks to fit the frame, and doesn't mess up the positioning of the squares.
Problem 4: How can I make Tic Tac Toe more extensible? Well, I thought that if I put all the constants in an interface, size of the board, size of squares, etc….. and write everything in terms of these constants, I can change the size of the game whenever I want. This way we can play 7x7 Tic Tac Toe just by changing one number.
I think my design is now in order, and I will start coding it.
Now that I have thought about my design, coding it is extremely easy. I added a TicTacToe class to abstract code from the Applet. The TicTacToe class also has the frame that we put all of our squares into. This way we can call a geometry manager on the Applet so that it shrinks to fit around the frame without putting all the squares into a column.
The hardest part of coding the whole program was trying to write the methods that check to see if someone has won in terms of the constants defined in the BoardSize interface. The methods that check the diagonals were difficult to implement in terms of the size of the Board, but I hand simulated out the checking and it quickly became apparent.
Setting all the positions and copying all the math over and over again started to get very tedious. I thought about a better way to do it, and came up with the idea of using a static method. I created a Positioner class that had a static method that took an array index and computed its on screen position. For more information about static methods, check out the header comment for the Positioner class.
Getting the board up and the piece's inserting correctly didn't take a very long time, so I decided to add in some examples of GP behaviors. I made my own color changing behavior, and decided that I would add it to the winning row of pieces. This proved to be far more difficult than I thought. I had to look over how I checked to see if someone had won, and luckily the way I had done allowed me figure out where the line of winning pieces was. Since I knew what Pieces needed the behavior added to them, it was just a matter or adding another for loop to get the behaviors added to the pieces.
Once this was done I played for a while, and realized that if the game ended in a tie nothing happened. Also, I realized there was no way to know whose turn it was when the game started other than clicking and seeing what appeared. This made me think, hey, why not add some GP.Graphics.Text? Since everything in the Applet window is placed into a column, I instantiate the GP.Graphics.Text in the Applet's container, not the frame. This way the text appears below the game, as opposed to inside the Board.
Now, everywhere that I test to see if someone has won, I update the text to say who won, or if there was a tie. In addition, after I insert a Piece I update the text's reference to say whose turn it is. This was incredibly easy to add since I already had all the code to check these conditions in place. It was a simple matter of adding three lines of code in a few places.
In this case, I found that my WonTheGame() method in the Board class was very long, so I broke it up into smaller methods. Instead of having one long method, I have three methods. The first method calls the other two. The second method checks the rows and columns for a Tic Tac Toe, while the third method checks the diagonals. This made the code much easier to follow, and made for a cleaner program.
Now that you have a better understanding of what I was thinking, here is all the wonderful code for the program! The class names should be pretty self explanatory, if they're not, take a look at the header comments and it will become very clear.
Applet.java. This is the Appelt.
TicTacToe.java This abstracts code from the applet, it instantiates everything we need for a new game.
Board.java This models the TicTacToe board
Piece.java This is the absract piece class
BlankPiece.java This is the blank square.
XPiece.java This is the square that has an X
OPiece.java This is the square that has an O
BoardSize.java This is the interface of Board constants: size, shape width, etc.
Positioner.java This is used to position things on the screen
ColorBehavior.java This is the behavior we add to make the squares change colors.
Any questions? Send me some mail..... Matt A.