aspose file tools*
The moose likes Beginning Java and the fly likes Game Tutorials -->> TicTacToe Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Game Tutorials -->> TicTacToe" Watch "Game Tutorials -->> TicTacToe" New topic
Author

Game Tutorials -->> TicTacToe

Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Let's tackle the first item on Ilja's list and display an empty playing board (notice that we don't need X's or O's for this!).
Still working with applets from the beginning, let's make a blank applet.

and the html page

Next, knowing that we want to display a board of empty cells, I'd like to follow Michael's lead a bit and make use of polymorphism as he has pointed out that our situation is almost asking for it (at least as far as my hearing is concerned). But what is that tune that they are singing exactly? Is it Interface or Abstract Class? Interface? Abstract Class? Let's view at what both might look like.
Cell class structure with an Abstract Class

Right away I discovered that the reason I was considering implementing an abstract base class is because I had some left over thoughts involving a previous design with some possibly inherited behavior. I'm not seeing this inheritance anymore. Let's go with the interface design.
Cell class structure with an Interface

Do note that each class description (source) should be in its own file and I will be following much of The JavaRanch Style Guide when formatting my code (I've just cheated a bit here in order to reduce space).
[breathe]
Let's display something already! Oh... time to define the board class.
( If you'd like to see a pretty version, take a look at Class-Board-01.html )
I've just used a bit of math to break the allocated display area (the Rectangle) into a three by three grid, allowing for grid lines with a width of 15 pixels. These grid lines themselves are simply filled rectangles.
Finally, let's add to the TicTacToe applet to get a look at the empty board.
And we have a first applet to look at - TicTacToe.html .
[ June 18, 2002: Message edited by: Dirk Schreckmann ]

[How To Ask Good Questions] [JavaRanch FAQ Wiki] [JavaRanch Radio]
David Weitzman
Ranch Hand

Joined: Jul 27, 2001
Posts: 1365
Wouldn't it be much simpler to draw the board with some combination of JComponent.setBackground(), setForeground(), new java.awt.GridLayout(3, 3).setH/VGap()?
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Originally posted by David Weitzman:
Wouldn't it be much simpler to draw the board with some combination of JComponent.setBackground(), setForeground(), new java.awt.GridLayout(3, 3).setH/VGap()?

That sounds like a very reasonable approach and I'd be very interested to see how you'd create this game without constraints such as avoiding Swing (as I previously expressed I won't be using - yet) and trying to put a simple program together the way a new programmer might.
This entire exercise is made far more interesting the more that different approaches are discussed and demonstrated.
So, please, show us what you'd do.
Thank You.
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
The next task in our list that I hope to accomplish is to let [the] user place X's by clicking on an empty field.
So, what's first? We already have an 'X' image to use, let's create a cell class that displays this image.
How does a cell object know what image to display? I like Michael Matola's suggestion that we assure use of the same 'X' image for all instances of an XCell in our program. A potential XCell class:I've initialized all of our cells in the board to be XCell objects. Let's see if an XCell displays itself as expected... It does ( TestBoard-02.gif ).
While we're at it, let's quickly define the OCell class that will probably look just like the XCell class excepting the replacement of 'x' or 'X' with 'o' or 'O' here and there. A board of OCells also looks as expected ( TestBoard-03.gif ).
It looks like we're ready to make the board clickable and when the user clicks on an EmptyCell, the cell should become an XCell.
An important question at this point would concern how to make the board clickable. What part of our program should be responsible for detecting and handling mouse clicks?
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Dirk Schreckmann:
What part of our program should be responsible for detecting and handling mouse clicks?

Well, we click on a cell to change its state, don't we? So, shouldn't it be the cells responsibility to change its state when it gets clicked on? Of course, this would imply that we don't have different cell classes, but one cell class having different states.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
(Again, note that in order to preserve some page space, I've (apparently) placed the three classes and interface into one file. In reality I'm using seperate files (one for each class or interface definitions) and following most of the practices described in The JavaRanch Java Programming Style Guide.)
Cell classThe only changes to the Board class were in its constructor:For testing purposes, I've set all the cells to x's because an empty cell isn't much to look at.
Now, to actually give our Cells the ability to handle the mouse clicks... Any ideas?
[ June 18, 2002: Message edited by: Dirk Schreckmann ]
Rex Ashworth
Greenhorn

Joined: Apr 04, 2002
Posts: 20
Will there be a cumulative count of how many games each has won? And what indication of winning is given? Can the count be saved for later use?
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Compnstuff:
Will there be a cumulative count of how many games each has won? And what indication of winning is given? Can the count be saved for later use?

When you read through the first page of this tutorial, you should find a link to "The final version of our Requirements Statement".
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Dirk Schreckmann:
Now, to actually give our Cells the ability to handle the mouse clicks... Any ideas?

Three ideas:
- the Applet receives the mouse clicks - let it delegate the processing of them to the gameboard, which should further delegate to the correct Cell, or
- as the first, but let the cells "listen to" the applet (the Observer Pattern) to better decouple them. For this, the cells needed to know their position, though - or
- let the cells be awt-Components and receive the mouse clicks directly.
I think I would tend to use the latter, as in this way we can rely on AWT to calculate which cell was clicked on.
What do you think?
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Let's discuss each of the possiblities that Ilja has proposed.
the Applet receives the mouse clicks - let it delegate the processing of them to the gameboard, which should further delegate to the correct Cell
This seems like a pretty straight forward proposition. One of the first programs I wrote was an Applet that handled a similar situation in this fashion.
For our initial purposes (to display an 'X' in whatever Cell is clicked), the strategy could be:
  • Main Applet detects mouse click and passes coordinates to Board
  • Board passes request to change to 'X' to appropriate Cell
  • Cell changes (if possible)
  • The first time I wrote an Applet that made use of mouse clicks, I probably did something like this:(Note: In anticipation of soon needing the Board accessible outside of the paint method, I've made board an instance variable.)
    I no longer like handling events in this manner exactly, for many of the reasons mentioned in the following articles at JavaWorld:
  • It might be efficient, but it ain't OO
  • With listener design, OO matters
  • Inner Classes
  • Innovative ways to handle events in AWT and JFC
  • So, let's make a habit of following the good advice in those articles, and make use of an inner class to handle our events.Do we really need all those silly emtpy methods hanging around? Not really. We can take advantage of one of the adapter classes.Let's add the function of actually getting the coordinates and passing them to the Board to the mouseClicked method:This won't work, as our Board class doesn't yet have a setX( int , int ) method. So, let's give it one:Of course, this doesn't actually do anything yet. How does the board know which Cell to turn into an X? Does the board even care which one? Should it maybe just tell the Cells, "Whichever one of you has these coordinates, would you please turn into an XCell?"
    I usually don't like to program asking objects to do things that they may not be able to do. So, my inclination is for the Board to figure out which Cell has the coordinates, and then requests the change of that Cell.
    How then should the Board figure out which Cell has the coordinates? We could use a bit of math to create the appropriate array indexes, but I'd rather just ask each Cell if it contains the coordinates. So, the Cell object must be changed to know its location and area outside of the display method.The setX method of the Board class then might resemble:Everything compiles fine. When it's run, a blank board is displayed, but nothing seems to happen when clicking on a Cell. That's because I forgot to tell it repaint after a mouse click.Solved. It ain't perfect and it's very interesting to learn the parts that you don't like.
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    I changed my mind. I'm going to postphone initiation of further discussion of how to design our program to handle the mouse clicks. Of course, anybody else is always welcome to talk about any part that interests them.
    When I consider the implementation of the next item on our task list, everytime after the user placed an X, let the computer place an O on a random empty field, and the next couple of items, I see a situation where somebody has to be responsible for controlling the flow of the game, including determining who goes next and when the game is over. This sounds a bit like a referee to me.
    Any ideas on who should be responsible for controlling the game flow? How is it determined who goes next and when the game is over? How should this game controller interact with our existing objects?
    [ June 15, 2002: Message edited by: Dirk Schreckmann ]
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Dirk Schreckmann:
    I usually don't like to program asking objects to do things that they may not be able to do.

    Mhh, interesting. Can you explain why you usually don't like to do this? What are the unusual situations where you'd like to do it?
    Curious, Ilja
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Dirk Schreckmann:
    When I consider the implementation of the next item on our task list, everytime after the user placed an X, let the computer place an O on a random empty field, and the next couple of items, I see a situation where somebody has to be responsible for controlling the flow of the game, including determining who goes next and when the game is over. This sounds a bit like a referee to me.
    Any ideas on who should be responsible for controlling the game flow? How is it determined who goes next and when the game is over? How should this game controller interact with our existing objects?

    Ideas I have, yes. But I am not that sure that those are the ones we will really need. I *am* sure, though, that we don't need them *know*...
    "everytime after the user placed an X, let the computer place an O on a random empty field" sounds like a very simple loop to me. Shouldn't we start this simple? We probably can move this (or parts of it) to a referee class (or something else) later, can't we? (It might in fact be a little bit risky, as we don't have automated tests to cover refactorings - but well, we are here to learn from mistakes anyway, aren't we? )
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    we are here to learn from mistakes anyway, aren't we?
    I am at least. It's a darn fine way to learn.
    Shouldn't we start this simple?
    I agree.
    So, where should the code to decide where to set the 'O' go? I really think that the main GUI class should be responsible for as little as possible - it's too easy to load up a bunch of responsibilities on it. I can't make sense out of giving the Cell any real game control responsiblity. So, the Board seems to me to be the best place.
    So, after a setX, then an 'O' in a random Cell.(Yes, I can hear Marilyn hollering. She's right, of course.)
    Not quite like the real game yet, but it's sure getting closer. Remember that this task list item requires that the computer place an 'O' in an available space, so let's add a little bit of intelligence to our algorithm.It's not the most efficient algorithm I can imagine, but it's simple and it'll get the job done fast enough. Of course, our Cell class has no such method getCellState - so let's give it one.I don't like handing out references to private members, let's later figure out some way to return a reference to a new object of the same type.
    It's almost working. When there are no more available cells for the computer to place its 'O' after we've placed our last 'X', then the computer goes into a never ending loop looking for an available cell. Remember our while loop? Let's fix it so that the computer only looks for an available cell if a cell is available.Well, it's working (except for that part where we can take a Cell after the computer has placed an 'O' there - we'll get to that).
    On to the next task, after some commentary if we're lucky.
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    Next task: stop game when board is full
    So, let's add a check if the game is full and not allow any more placing of X's or O's if it is. If the Board is full, then the isAnyCellAvailable method would return false. Adding this check to the setX method seems simple.After testing it by playing with it a bit, it seems to work as expected. Of course, the user can still change an 'O' to an 'X' before the Board is full. Let's fix that quickly by allowing the user to place an 'X' only if the cell is empty..I've also moved the invocation of setO to only occur if the user has successfully placed an 'X'.
    It seems to be working properly.
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Dirk Schreckmann:
    I don't like handing out references to private members, let's later figure out some way to return a reference to a new object of the same type.

    Perhaps we shouldn't ask the Cell for its state anyway? IMO, OOP should be more about asking an object questions and asking it to do something - less about "processing data". So perhaps instead of a getCellState and setCellState method, a Cell should have methods like isEmpty, putX and putO ?
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    OOP should be more about asking an object questions and asking it to do something - less about "processing data". So perhaps instead of a getCellState and setCellState method, a Cell should have methods like isEmpty, putX and putO
    That sounds like a very nice solution. Our new and improved Cell class then might be:Three methods in the Board class should also be adjusted to work with our changed Cell class:Playing with it (testing) would seem to indicate that it is working as expected.
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    How do we decide to stop the game at a winning condition?
    Who knows about the state of the Board? The Board does. Could the Board determine if a winning condition were met? What about the Referee idea? Is the Board maybe taking on too many responsibilities? Why should the Board care about the status of the game play? Should the Board have rules associated with it that do affect the game play? What should those rules be?
    As it would seem to be a simple next step (perhaps simpler than introducing a Referee), and in order to see what it would be like, let's have the Board decide when a winning condition is met.
    So, no longer is it enough that a Cell should be empty before allowing the placement of an 'X' or 'O', it must also be determined that nobody has won. Let's add a method to the Board class that performs this check, and let's perform the check at the appropriate times.What are the conditions when the game has been won? Either three X's or three O's in a row. What's a straight forward way to detect such a condition? Lots of boolean checks.
    We'll need to be able to ask a Cell if it is an X or if it is an O. So, let's add these two methods to the Cell class:Now, the Board's isGameWon method can do its dirty work.(I smell some possible for loops. How might you improve this method?)
    Testing (playing with it) indicates that it does seem to work as expected.
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    restart game after winning condition or draw
    What does it mean to restart a game? Is it to simply clear the board - set each Cell to be an empty cell?
    Without adding any new functionality to the Cell class, we could just drop the references to our initial Cells and use brand new Cells - new Cells begin life as empty. Or would it for some reason be smarter to just change the state of each Cell?Since we do this exact same thing in the Board's constructor, let's change the constructor to invoke clearBoard.Otherwise, clearBoard should be invoked after a game is over. A game is over, if either an 'X' cannot be placed or an 'O' cannot be placed.That's not exactly the behavior I'd like the game to have. It just clears the Board immediately after the player wins or the Board is full - if the computer wins, it does wait to clear the Board until after the user clicks on the Board. We could either delay the Board clearing until after the user clicks one more time after the game is over, or we could perhaps provide a button that would clear the Board when pressed. What would be simpler?
    [ June 16, 2002: Message edited by: Dirk Schreckmann ]
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Dirk Schreckmann:
    restart game after winning condition or draw
    [...]
    We could either delay the Board clearing until after the user clicks one more time after the game is over, or we could perhaps provide a button that would clear the Board when pressed. What would be simpler?

    Mhh, probably providing a "new game" button would be both simpler *and* more user friendly?
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    providing a "new game" button would be both simpler *and* more user friendly?
    If I were the user, that's how I'd prefer the game were controlled.
    Now, who gets the button?
    [ June 17, 2002: Message edited by: Dirk Schreckmann ]
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    Let's see what happens when the main GUI class (the Applet) gets the button.
    TicTacToe class additions:Can somebody think of better identifier for the Button?
    Obviously, the Board class has no method called newGame, so let's give it one - or simple rename the clearBoard method. Here are the two changes necessary:Would it have been better to simply drop the reference to the initial Board in the TicTacToe class and just create a new Board to use?
    Oops! Don't forget to repaint after a button click.Well, it's working - maybe.
    [ June 22, 2002: Message edited by: Dirk Schreckmann ]
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Dirk Schreckmann:
    Can somebody think of better identifier for the Button?

    Well, what about "newGameButton"? :roll:
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    It's fun to see if somebody is reading this.
    Michael Matola
    whippersnapper
    Ranch Hand

    Joined: Mar 25, 2001
    Posts: 1740
        
        2
    I'm like 20 posts behind. I'll eventually catch up.
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    Cool. That should give me a couple of days yet to sneak a few more things in.
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Dirk, it would be cool if you could make the applet available online, perhaps even in the different stages.
    Another nice thing would be to make the full source available online, perhaps as html with syntax highlighting (I think somewhere I have a tool for doing that - contact me if you are interested).
    That should give you something to do, so that Michael has time to catch up...
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    Ilja,
    Those are good ideas. I will do so.
    Dirk Schreckmann
    Sheriff

    Joined: Dec 10, 2001
    Posts: 7023
    count wins
    This data relates only to a given instance of a Board and it does not persist beyond the existence of the associated Board. So, let's count wins and losses in the Board class and add two ints to the class to keep track of these wins.When is a win added to either count? When either the player has won or the computer has won. In its current form, the Board class only keeps track of whether anybody has won. Let's add methods to determine if one or the other has won.Then let's move some of the checks in the isGameWon method to these two new methods as is appropriate, and tell the isGameWon method to ask these other two if either has won.(Those two new methods sure do look a lot like one another.)
    Our win counters aren't yet being incremented at the appropriate times. Let's change that.(To repeat myself: Those two new methods sure do look a lot like one another.)
    All this win counting is nice, but this information isn't actually being used yet. Let's actually use it, then, by displaying it.
    In its display method, a Board is given a specified Rectangle in which to display itself. We're currently using the entire display area allocated a Board. We could have the Board use a little less of that Rectangle to display the Cells and Grid lines, in order to free up some screen space to display the score. Here's what that could look like:Well, at least everything is lined up correctly.
    Trying it out reveals that our score keeping strategy isn't working properly. We seem to have a couple of obvious mistakes:
  • After a game is won, clicking on the Board increments the win count of whomever last won.
  • The computer's win count isn't incremented following a win (without the extra cheater clicks previously mentioned).
  • (Must not have been thinking clearly.)
    Anybody going to suggest changes in score keeping strategy before I do?
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Game Tutorials -->> TicTacToe
     
    Similar Threads
    Game Tutorials -->> Creating An Applet
    Game Tutorials -->> Introduction
    Game Tutorials -->> Table Of Contents
    Create Java executables
    Game Tutorials -->> Development Process