Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
* * * * * 1 votes

Java Tutorial: TicTacToe (Revised)

tictactoe java game tutorial

  • Please log in to reply
16 replies to this topic

#1 Chall

Chall

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 349 posts
  • Location:Cedar Rapids, IA
  • Programming Language:Java
  • Learning:C, Java, C++, C#, Python, JavaScript, Assembly

Posted 11 October 2012 - 04:18 PM

Introduction

While browsing the Java tutorials, I discovered that there was one in particular, tic tac toe, that got viewed the most. When seeing that it was an older tutorial, and that it was only at the intermediate level, I decided I would make my own revised version. So, here we are. This tutorial is on how to make a tic tac toe game using the Java programming language developed by Sun Microsystems. This tutorial is designed to be as in detail and explanatory as possible. I hope you all enjoy what I have spent the last few days working on.

What you will find in this tutorial
Since this tutorial is on how to make a tic tac toe game, obviously first off we are going to be making a tic tac toe game. While telling you how to make it, I am going to try my best to explain what I’m doing, and why I am doing it. At the end of this tutorial I will also show you how to make a basic dynamic AI for single player game play. This is the game you will be creating:

Attached File  TicTacToe.jar   9.82KB   1078 downloads Has AI

Posted Image

What you should know beforehand

Before I start, I hope that you all know how to use Java, and are fairly adept at the language. If you are not so great, but do know a decent amount, I am going to try and explain my process as detailed as possible. I highly recommend using an IDE, as the game will be spread over multiple classes, and using an IDE helps the process of development tremendously.

Getting started

Okay, let’s get started. First off, if you are using an IDE, make a new project and call it whatever you please. Inside the new project, make sure you make the package game. If you are not using an IDE, make a new folder wherever you are going to be making your game at, and call the folder game. This will be our package (area to contain and organize sources/classes), and all of our source files are going to be going into this package.

Making the game

Now we are going to add our source files to our game package. Since this is a multi source game, I am going to tell you what methods and fields to add to each file, so that all we have to do is add the “filling” later on.

Lets start with our main file, TicTacToe.java . If you are on an IDE, just create a class inside the package game, and call it TicTacToe. If you are not using an IDE, inside the folder game, create the file TicTacToe.java . Now that we have our file, it’s time to add the structures. Lets start by packaging the file under “game”. You will do this like so:

package game;

Next, lets make the class final. We are going to do this because it prevents unruly players from sub-classing our game so that they can modify it. We also want to add a main method, as we want this class to be able to execute on it’s own. Inside the main method we are going to have the game create another one of itself, so that the rest of the class does not have to be static. I am doing this because it makes life for us a bit easier, and it doesn’t effect security of our game, as it cannot be subclassed, and we are going to make as many variables final as possible, so that they cannot be modified during runtime (by hackware and the likes). We will do this like so:

package game;

public final class TicTacToe {
// Other methods excluded. If you didn’t know, this is a comment. Do NOT type this, as it does not have any purpose other than informing the reader of the source about something.
public static void main(String[] args){

}

}

Great! Now our game can be executed. Before we continue with our fields and methods, etc, I think it best if we also create the other classes. The classes you need to make are:
  • ClickHandler.java - This will handle all the clicks received by the game screen.
  • Holder.java - This will be our Enum type that specifies X, O, and GAME, which are all states that a Tile may hold at any given time.
  • Tile.java - This is what our map will be made up of. These are held by either X, O, or GAME (Meaning the tile is not yet claimed by either X or O, and can still be claimed by either player).
  • TilePainter.java - This will display, or paint, all of the Tiles currently on the field, and what their holder is.
Lets start with ClickHandler. Inside the game package/folder create a new class, and call it ClickHandler.java . Since this is not an executable class, we need to specify a constructer. We are also going to make the class final, and make sure it is packed under game, for the same reasons as our TicTacToe class. We also need to import two files, MouseEvent and MouseListener. Do not worry, I will provide you with them. This is what it should look like (This is the whole class. No further changes will be required):

package game;

// Import the required classes so that they can be used for later
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public final class ClickHandler implements MouseListener { // Implementing MouseListener so that our class can be used to check for clicks on our game.

private final TicTacToe game; // Make final instance of TicTacToe for use by our class, but do not instantiate that, as we want to use the one provided in the constructor.

public ClickHandler(TicTacToe game) { // Constructor
this.game = game; // Set the game inside ClickHandler to the game provided by the contructor parameter game.
}

public void mouseReleased(MouseEvent e) { // Mouse released event. Inside this is what happens when the mouse is released over our game.
game.attemptClaim(e.getX() - 3, e.getY() - 26); // Subtracts fromt the values to eliminate interference from the frame border.
game.getGameframe().repaint(); // Make sure that changes made here are shown right away.
}
// The rest is just required by MouseListener. Pay it no mind.

@Override
public void mouseClicked(MouseEvent e) {

}

@Override
public void mousePressed(MouseEvent e) {

}

@Override
public void mouseEntered(MouseEvent e) {

}

@Override
public void mouseExited(MouseEvent e) {

}

}

Greate! Now lets add our Enum type that tells us who controls what. If you do not not what an enum is, don't worry. It's a class (or collection of classes) that replace lists of variables, and specify them under one namespace. They are also final, and thus will never change. For our enum type, Holder, I am just going to give you the source, and explain it in comments. This is what it looks like:

package game;

import java.awt.Color; // Import the Color class, so that our Enum type can return the color of its type.

public enum Holder {
X, O, GAME, ANY; // All the enums that will be under the Holder namespace.

public String getText() { // Get the text to display on the Tile
switch (this) {
case X:
return "X";
case O:
return "O";
default:
return " ";
}
}

public Holder getOpposite() { // Get the opposite of this Enum. If it was X, then the opposite is O, and likewise.
switch (this) {
case X:
return O;
case O:
return X;
default:
return GAME;
}
}

public Color getColor() { // Get the background color to color the Tile.
switch (this) {
case X:
return Color.LIGHT_GRAY;
case O:
return Color.DARK_GRAY;
default:
return Color.WHITE;
}
}

public Color getTextColor() { // Get the color to make the text of the Tile.
switch (this) {
case X:
return Color.BLACK;
case O:
return Color.WHITE;
default:
return Color.MAGENTA;
}
}
}

Alright. Next is Tile class, one of the most important in our game. We want it to be final, and contain all the required values for displaying the Tile. It looks like this:

package game;

import java.awt.Graphics; // Import the abstract class Graphics. Used for displaying this Tile.

public final class Tile {

private final int x, y, width, height; // The x, y, width, and height of this class. Can be final, as we are going to reuse the same Tiles, and there is no need to change the position once created.
private boolean claimed = false; // This is used by the getter to tell whether or not this instance is claimed by a Holder.
private Holder heldBy = Holder.GAME; // This is the holder of this Tile. By default it is held by GAME, which means no one has claimed it yet.
private final TicTacToe game; // Private final instance of our TicTacToe game, used to interact with our game.

public Tile(int x, int y, int width, int height, TicTacToe game) { // Constructer. Include the dimensions, and the TicTacToe instance used for communication.
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.game = game;
}

public void claim(Holder h) { // Used by TicTacToe to claim this Tile under the holder specified in the parameters.
if (heldBy == Holder.GAME && !claimed) { // Make sure no one has claimed this yet.
claimed = true; // Claiming this Tile.
heldBy = h; // Setting the holder to the claimer
}
}

public Holder getHolder() { // Used to get the holder who possesses control over this Tile.
return heldBy;
}

public void paint(Graphics g) { // Paints (Displays) this Tile on our game's frame.
g.setColor(heldBy.getColor()); // Getting the color to use. Uses the color of the current holder.
g.fillRect(x, y, width, height); // Creating the rectangle of the background using the dimensions specified.
g.setColor(heldBy.getTextColor()); // Getting the color that the text should be. Uses the current holder to get the color.
g.drawString(heldBy.getText(), middleX() - (game.getFontSize() / 3), middleY() + (game.getFontSize() / 3)); // Drawing the text (X or O) specified by the Holder. Subtracts one third and adds one third of the font size used by the game, so that the text will be centered.
}

private int middleX() { // Get the middle x value of this Tile
return (x + width / 2); // Returns the middle x value.
}

private int middleY() { // Get the middle y value of this Tile
return (y + height / 2); // Returns the middle y value.
}

public void reset() { // Used to reset this Tile after the game is over.
this.heldBy = Holder.GAME; // Remove the Holder.
this.claimed = false; // Make sure that it is not claimed.
}

public boolean inArea(int x, int y) { // Checks whether the x y parameters are within the range of this Tile.
return (this.x <= x && this.x + this.width >= x)
&& (this.y <= y && this.y + this.height >= y);
}

public boolean isClaimed() { // Returns whether or not this Tile is claimed.
return claimed;
}

public int getX() { // Returns the X value of this Tile.
return x;
}

public int getY() { // Returns the Y value of this Tile.
return y;
}

public int getWidth() { // Returns the width of this Tile.
return width;
}

public int getHeight() { // Returns the height of this Tile.
return height;
}
}

Great! Only one more class left to make, then we can finish our TicTacToe class, and thus finish the game! All we need to add now is the TilePainter. Since graphics are relatively hard to understand at first, I will try to explain it as best I can. What the painter does is, whenever the TicTacToe game calls a repaint on the games frame, it will send a paint call to the method contained within. From inside this class, the paint method will paint (display) all the Tiles of the game, in their current state. This is the core graphical component, and so very important to the game. Now, you might be thinking "Oh no, now I gota make this HUGE file. Ughh". No. Infact, TilePainter is the smallest class in our game. As with all the other classes, we are going to declare it as final. We also need to import some graphical components. This is what TilePainter looks like:

package game;

// Graphical component imports.
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;

public final class TilePainter extends Component {

private static final long serialVersionUID = 1L; // Default serialized value. Required by all classes that extend Component. We do not need to worry about this, in this tutorial, as we are not going to be messing with serializable classes and methods.

private final TicTacToe game; // Private final reference to the TicTacToe game. Instantiated by the constructor.

public TilePainter(TicTacToe game) { // Constructor. Requires a TicTacToe game to be specified.
this.game = game; // Make sure that the game in this class is that of the one being used.
}

public void paint(Graphics g) { // Paint method. Called when the repaint method is called on the JFrame this is attached to.
Graphics2D g2d = (Graphics2D) g; // Create a Graphics2D out of casting the Graphics provided.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Create Anti-aliasing so our characters are smooth.
g2d.setFont(new Font("Dialogue", Font.BOLD, game.getFontSize())); // Since all the Xs and Os need to be bold, and their is no other text to be displayed, simply make it bold. Uses the font size provided by the TicTacToe game.
for (Tile t : game.getTiles()) { // For-Each loop to iterate throught the Tiles of our game.
g.setColor(Color.BLACK); // Set the color to black, so that we can draw an outline to show the different Tiles and their boundaries.
g.drawRect(t.getX() - 1, t.getY() - 1, t.getWidth() + 1,
t.getHeight() + 1); // Drawing the outline using the dimensions of the Tile being shown. Makes the dimensions either 1px smaller or larger, so that acts as an outline.
t.paint(g2d); // Call paint on the Tile itself, so that the tile can display itself.
}
}

}

Yay! Now all we have to do is finish our TicTacToe class, and then we can play our game! Since we are going to instantiate a new TicTacToe game within our class, we are going to provide a modified constructor. This will help set up the game, and it will also allow for use to add AI later. Because it is difficult to explain features without visual reference, I will give you the finished TicTacToe, and provide comments to explain things. This is our finished TicTacToe class:

package game;

import java.awt.Dimension; // This is used as a compact way to store the dimensions. Used for the JFrame.
import java.util.concurrent.TimeUnit; // I'm using this to put a time delay on the game loops, so that it doesn't use all of your processor.

import javax.swing.JFrame; // This is used to show the game to the player(s).
import javax.swing.JLabel; // This is used to display a simple String, without the need to get deep into the Graphics.

public final class TicTacToe { // Declares our new class. Final to prevent subclassing.

private final Tile[] TILES = new Tile[9]; // The final array of Tiles. Final because we will only ever need the specified amount, in this case, 9.
private final int TILE_SPACING = 96; // This is the final integer primitive of how far appart (in pixels) the Tiles are.
private final int WIDTH = 96, HEIGHT = 96; // Normal dimensions for our Tiles to use.
private final JFrame GAMEFRAME = new JFrame("Tic-Tac-Toe"); // The game frame. The whole game will be shown on this Object. Final because we never need to make a new one.
private final TilePainter PAINTER = new TilePainter(this); // This will get added into GAMEFRAME so that the repaint call will affect it. Final because, just like the GAMEFRAME, it will never need to be reinstantiated.
private final ClickHandler CLICK_HANDLER = new ClickHandler(this); // Creates the ClickHandler to get attached to GAMEFRAME to handle clicks. Is declared final for the same reason as PAINTER.
private Holder turn = Holder.X; // Current holder. Instantiates as X.
private int whoseTurn = 0; // Whose turn is it? Used to tell when to swap who startes the game.
private final Dimension FRAME_SIZE = new Dimension(295, 304); // Creates the dimensions to be added to GAMEFRAME. Represents the only size our game will ever become. Final because it will never change.
private final int FONT_SIZE = 64; // The integer primitive that represents the size of all global fonts, to this game.
private int oWins = 0; // How many times the player O has won.
private int xWins = 0; // How many times the player X has won.
private boolean gameOver = false; // Whether or not to stop the game loop, and start a new game.
private boolean nextTurn = false; // Used to tell the game loop when it is time to switch players.
private JFrame outcome = new JFrame(); // Outcome frame. This will be shown whenever a player wins, or a draw occurs.

private final int[][] WINS = { { 1, 1, 1, 0, 0, 0, 0, 0, 0 },

{ 0, 0, 0, 1, 1, 1, 0, 0, 0 },

{ 0, 0, 0, 0, 0, 0, 1, 1, 1 },

{ 1, 0, 0, 0, 1, 0, 0, 0, 1 },

{ 1, 0, 0, 1, 0, 0, 1, 0, 0 },

{ 0, 1, 0, 0, 1, 0, 0, 1, 0 },

{ 0, 0, 1, 0, 0, 1, 0, 0, 1 },

{ 0, 0, 1, 0, 1, 0, 1, 0, 0 } }; // This array represents all possible winning arrangements. The reason they are 1 and 0 is because the game's win checker will use the current turn, and the 1s mean that the current player has to control this tile. If the player controls all 3 tiles that are represented as 1, then they win this game, and gameOver is set to true.

public boolean allFull() { // Returns whether or not any more moves can be made. Positive means that all tiles are claimed, and false means there are still move(s) to be made.
for (Tile t : TILES) { // For-Each loop to iterate through all the tiles.
if (!t.isClaimed()) { // If even one tile isn't claimed yet, return false, as there is atleast 1 more move to be made.
return false;
}
}
return true; // If the For-Each never returned false, then there must not be any moves left. Returns true.
}

public boolean hasWon(Holder h) { // Check whether the specified holder has won the game.
boolean hasWon; // Uses this value to check whether or not they have won.
for (int[] i : WINS) {
hasWon = true; // Set it to true. Unless proved otherwise, this player has won.
for (int j = 0; j < i.length; j++) { // Iterate through the possible wins.
if (i[j] == 1) { // If the encountered value is a 1 (Meaning the player must control this tile)...
if (TILES[j].getHolder() != h) { // If the player does NOT control this tile...
hasWon = false; // Proves otherwise (Sets hasWon to false, meaning this win combo is not possible.
j = i.length; // Set j to the length of this win, so that we can exit this loop, as we have already proven the player has not won this one.
}
}
}
if (hasWon) // If hasWon is still true, then they must have won.
return true; // Return true, as the player has won.
}
return false; // Else, if it gets throught the entire wins array, and non of them have been achieved, return false, this player has not won.
}

public int getFontSize() { // Used by the other classes to get the font size they should use.
return FONT_SIZE; // Return the specified font size.
}

public TicTacToe(boolean ai) { // Constructor
PAINTER.setSize(FRAME_SIZE); // Set the size of PAINTER to that of FRAME_SIZE.
buildFrame(); // Frame Builder method. Only used once, but it improves code readability.
loadTiles(); // Load the tiles. Gets them set up with the correct coordinates and dimensions.
}

public void loadTiles() { // Loads the tiles (Gets them ready for use).
int tile = 0; // Current tile being set. Increases each time a tile is set. Starts at 0, ends at 8.
for (int i = 0; i < TILES.length / 3; i++) { // iterate through TILES by a third of the size of our game (3). This iteration is the columns.
for (int j = 0; j < TILES.length / 3; j++) { // iterate throught TILES in a similar maner as above. This iteration is the rows.
TILES[tile] = new Tile(i * this.TILE_SPACING, j
* this.TILE_SPACING, this.WIDTH, this.HEIGHT, this); // Instantiate a new tile at the specified position, using the default values. Uses the iteration value * whatever the default size is, so that they will be equally spread apart.
tile++; // Increases tile by 1, so that next time, it will be a different tile being set.
}
}
}

private void nextTurn() { // Used to switch turns. Called each time a valid move is made.
if (hasWon(turn)) { // Check to see if the move the current player made was a winning move.
gameOver = true; // If it was, then set gameOver to true;
sendWin(turn); // Also, display a window informing the user(s) of what occured. Also shows scores.
return; // Exit this method. Nothing left to do.
}
if (allFull()) { // If there are no moves left, and the last players move wasn't a winning one...
gameOver = true; // The game is over
sendDraw(); // Call the method that creates a frame informing the user(s) of the draw. Also shows scores.
return; // Exit this method. Nothing left to do.
}
turn = turn.getOpposite(); // Switch turns.
}

public void attemptClaim(int x, int y) { // Used to claim a Tile. Checks to get which tile is within coordinates, and then if it isn't claimed, claims it.
for (int i = 0; i < TILES.length; i++) { // Iterate through all the tiles.
if (!TILES[i].isClaimed() && TILES[i].inArea(x, y)) { // If the tile isn't claimed, and the tiles is in the required area.
TILES[i].claim(turn); // Claim the tile under the current player.
nextTurn = true; // on next game loop, ensure that the players will be switched, as the current players turn has ended.
return; // Return. Nothing left to do.
}
}
}

private void buildFrame() { // Sets up GAMEFRAME.
getGameframe().addMouseListener(CLICK_HANDLER); // Add ClickHandler
getGameframe().setSize(FRAME_SIZE); // Add the dimensions
getGameframe().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Make it so game exits when this frame closes.
getGameframe().setResizable(false); // Make it so that this frame is always the same size.
getGameframe().setMaximumSize(FRAME_SIZE); // Honestly, these probably arn't needed, but just in case.
getGameframe().setMinimumSize(FRAME_SIZE);
getGameframe().add(PAINTER); // Add the TilePainter.
getGameframe().pack(); // Pack all the changes.
}

private void sendWin(Holder winner) { // Create the win frame based on the winner defined in parameters.
outcome.setVisible(false); // If there was already a copy of outcome in use, remove it from site.
outcome.dispose(); // Remove any current outcome's members.
outcome = null; // Destroy any current outcome.
if (winner == Holder.X) // If the winner is X
xWins++; // X wins +1
else if (winner == Holder.O) // Else if the winner is O
oWins++; // O wins +1
outcome = new JFrame(winner.getText() + " has won!"); // Create new JFrame with winning title.
JLabel winMessage = new JLabel(" " + winner.getText()
+ " has won! Score is X: " + xWins + ", O: " + oWins); // Create a message that informs of win, and displays current score.
outcome.add(winMessage); // Add the message to the JFrame.
outcome.setResizable(false); // Set the size to constant.
outcome.setAlwaysOnTop(true); // Make it always on top.
outcome.pack(); // Pack it.
outcome.setVisible(true); // Set it visible so it can be seen.
}

private void sendDraw() { // Send a JFrame with Draw. Practically the same as sendWin, but different event.
outcome.setVisible(false); // If any current instance is visible, not any more.
outcome.dispose(); // Remove members.
outcome = null; // Destroy
outcome = new JFrame("Draw!"); // Declare the match a draw.
JLabel drawMessage = new JLabel(" Its a Draw! Score is X: " + xWins
+ ", O: " + oWins); // Display Draw, and score.
outcome.add(drawMessage); // Add the message to the JFrame.
outcome.setResizable(false); // Set the size to constant.
outcome.setAlwaysOnTop(true); // Make it always on top.
outcome.pack(); // Pack it.
outcome.setVisible(true); // Set it visible to be seen.
}

private void resetTiles() { // Resets the tiles
for (Tile t : TILES) // Iterate through all the tiles.
t.reset(); // Reset each tile.
}

public void newGame() { // Called when our game is executed. This is the game loop.
while (true) { // Repeat forever. Makes sure you can keep playing using the same settings, as this way, it just repeats the game startup process.
gameOver = false; // Game is no longer over.
resetTiles(); // Reset the tiles to clear the data from the previous game.
GAMEFRAME.setVisible(true); // Set GAMEFRAME visible, so you can see it.
	 turn = Holder.X; // By default, X will start every game.
while (!gameOver) { // Loop until game over is true.
if (nextTurn) { // If nextTurn was set to true..
nextTurn = false; // set back to false, so it doesn't repeat next loop.
nextTurn(); // Switch turns.
}
try {
TimeUnit.MILLISECONDS.sleep(25); // Wait 25 milliseconds. Added to decrease the load on your CPU from constant updates.
} catch (InterruptedException e) {
e.printStackTrace();
}
GAMEFRAME.repaint(); // Repaint. Displays any changes made.
}
		 // Game is now over.

try {
TimeUnit.SECONDS.sleep(5); // Wait 5 seconds, so user(s) can see why they lost/won/ had a draw.
} catch (InterruptedException e) {
e.printStackTrace();
}
getGameframe().setVisible(false); // Remove GAMEFRAME from sight so it's members can be reset.
}
}

public Holder getTurn() { // Returns the current turn (player who is playing).
return turn;
}

public Tile[] getTiles() { // Returns TILES so that other classes can use them.
return TILES;
}

public static void main(String[] args) { // Main method.
	 TicTacToe game = new TicTacToe(); // Instantiate new instance of TicTacToe.
	 game.newGame(); // Start a new game.
}

public JFrame getGameframe() { // Returns GAMEFRAME.
return GAMEFRAME;
}
}

Congrats! You have successfully completed this tutorial! You should now be able to compile, and run your game. Currently it is only single player, but AI will be comming soon (After I finish my current Battleship project).

Please feel free to comment suggestions or questions. I am open to criticism, so don't hold back.

Source Files (No AI) (All are declared inside package "main"):
Attached File  ClickHandler.java   644bytes   674 downloads
Attached File  Holder.java   711bytes   712 downloads
Attached File  TicTacToe.java   4.54KB   844 downloads
Attached File  Tile.java   1.4KB   663 downloads
Attached File  TilePainter.java   698bytes   742 downloads

Modified/Added Source Files(Has AI) (All are declared inside package "main"):
Attached File  AI.java   1.56KB   858 downloads
Attached File  ClickHandler.java   672bytes   626 downloads
Attached File  TicTacToe.java   6.06KB   781 downloads
The rest are the same as above.
  • 2
Speaks fluent Java

#2 VNFox

VNFox

    CC Devotee

  • Senior Member
  • PipPipPipPipPipPip
  • 648 posts
  • Programming Language:C#, PHP
  • Learning:Assembly

Posted 12 October 2012 - 02:26 PM

Very good +1 ... looks like a lot of work.
  • 0

www.pickmike.com
I don't just develop software. I find solutions to your business needs.


#3 Chall

Chall

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 349 posts
  • Location:Cedar Rapids, IA
  • Programming Language:Java
  • Learning:C, Java, C++, C#, Python, JavaScript, Assembly

Posted 12 October 2012 - 03:21 PM

Took one afternoon to get it all working properly (including AI), and another afternoon the next day to write the tutorial. :) Thanks to wim DC for telling me about anti-aliasing :) Didn't even know Java had anti-aliasing.
  • 0
Speaks fluent Java

#4 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 14 October 2012 - 11:26 PM

just a tip about:
public final class ClickHandler implements MouseListener { // Implementing MouseListener so that our class can be used to check for clicks on our game.
private final TicTacToe game; // Make final instance of TicTacToe for use by our class, but do not instantiate that, as we want to use the one provided in the constructor.
public ClickHandler(TicTacToe game) { // Constructor
this.game = game; // Set the game inside ClickHandler to the game provided by the contructor parameter game.
}
public void mouseReleased(MouseEvent e) { // Mouse released event. Inside this is what happens when the mouse is released over our game.
game.attemptClaim(e.getX() - 3, e.getY() - 26); // Subtracts fromt the values to eliminate interference from the frame border.
game.getGameframe().repaint(); // Make sure that changes made here are shown right away.
}
// The rest is just required by MouseListener. Pay it no mind.
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}

Various listeners in Java have an 'adapter' too. An adapter is an implemention of the Listener with empty methods.
If your class doesn't have the need to extend something else, you can extend the adapter instead of implementing the Listener.

Why? Then you only have to write the method you really want, and you don't have to deal with the empty methods, just because the interface defines it.

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public final class ClickHandler extends MouseAdapter { 

    private final TicTacToe game; 

    public ClickHandler(TicTacToe game) {
        this.game = game; 
    }

    public void mouseReleased(MouseEvent e) {
        game.attemptClaim(e.getX() - 3, e.getY() - 26);
        game.getGameframe().repaint(); 
    }
}

  • 0

#5 Chall

Chall

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 349 posts
  • Location:Cedar Rapids, IA
  • Programming Language:Java
  • Learning:C, Java, C++, C#, Python, JavaScript, Assembly

Posted 15 October 2012 - 03:44 PM

just a tip about:

public final class ClickHandler implements MouseListener { // Implementing MouseListener so that our class can be used to check for clicks on our game.
private final TicTacToe game; // Make final instance of TicTacToe for use by our class, but do not instantiate that, as we want to use the one provided in the constructor.
public ClickHandler(TicTacToe game) { // Constructor
this.game = game; // Set the game inside ClickHandler to the game provided by the contructor parameter game.
}
public void mouseReleased(MouseEvent e) { // Mouse released event. Inside this is what happens when the mouse is released over our game.
game.attemptClaim(e.getX() - 3, e.getY() - 26); // Subtracts fromt the values to eliminate interference from the frame border.
game.getGameframe().repaint(); // Make sure that changes made here are shown right away.
}
// The rest is just required by MouseListener. Pay it no mind. If you wanted to remove this, however, you could have your listener extend MouseAdapter, so that you only have to override what you need to. The choice is yours.
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}

Various listeners in Java have an 'adapter' too. An adapter is an implemention of the Listener with empty methods.
If your class doesn't have the need to extend something else, you can extend the adapter instead of implementing the Listener.

Why? Then you only have to write the method you really want, and you don't have to deal with the empty methods, just because the interface defines it.

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public final class ClickHandler extends MouseAdapter {

private final TicTacToe game;

public ClickHandler(TicTacToe game) {
this.game = game;
}

public void mouseReleased(MouseEvent e) {
game.attemptClaim(e.getX() - 3, e.getY() - 26);
game.getGameframe().repaint();
}
}

Yes, but for a small file it wouldn't have any noticeable performance hindrances, nor would it take up much more memory. And while extending a class so that you would be able to add less methods wouldn't have much effect if you were to create a centralized input handler that handles all forms of input, as you can only extend one object, but you can implement multiple interfaces.

Also, I'm not sure about this, but if you wanted to subclass the class in the future, wouldn't the excluded methods be excluded in the subclass too? so that if you only wanted to subclass it so that you could change the way something works inside it, and you also wanted to add something not included in the original, it wouldn't work, as the original method didn't exist in the parent, and since you have used your one extend to extend the previous class, you cannot extend the Adapter, and including the Listener goes against the sole reason for why you would be using the Adapter in the first place.

If you wanted to release this as an API, I personally would prefer to see the unused methods anyways, as it helps me see that there are other things, and it gives me examples of those other things. And since this is a tutorial, I feel the reader should be given as many chances to learn as possible.
  • 0
Speaks fluent Java

#6 lethalwire

lethalwire

    while(false){ ... }

  • Senior Member
  • PipPipPipPipPipPip
  • 766 posts
  • Programming Language:C, Java, PHP, JavaScript
  • Learning:PHP

Posted 16 October 2012 - 01:46 PM

Also, I'm not sure about this, but if you wanted to subclass the class in the future, wouldn't the excluded methods be excluded in the subclass too? so that if you only wanted to subclass it so that you could change the way something works inside it, and you also wanted to add something not included in the original, it wouldn't work, as the original method didn't exist in the parent, and since you have used your one extend to extend the previous class, you cannot extend the Adapter, and including the Listener goes against the sole reason for why you would be using the Adapter in the first place.

The unimplemented methods were implemented within the Adapter class, therefore they do exist within the subclass. So if you were to subclass your ClickHandler with another handler, you could still implement all of the Adapter methods without having to re-extend MouseAdapter again.

There are several benefits and downfalls when you use adapters in any language, but it is worth noting that the option is on the table to those reading the tutorial. Most programmers like to write concise code and try to exclude anything that is not necessarily needed which leads to such things as the MouseAdapter class.
  • 0

#7 Chall

Chall

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 349 posts
  • Location:Cedar Rapids, IA
  • Programming Language:Java
  • Learning:C, Java, C++, C#, Python, JavaScript, Assembly

Posted 16 October 2012 - 07:18 PM

Added, thanks :)
  • 0
Speaks fluent Java

#8 sawatd

sawatd

    CC Lurker

  • Just Joined
  • Pip
  • 2 posts
  • Programming Language:PHP, JavaScript
  • Learning:Java, PHP

Posted 22 October 2012 - 07:37 PM

Thank for tutorial, I called O/X game.
  • 0

#9 Chall

Chall

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 349 posts
  • Location:Cedar Rapids, IA
  • Programming Language:Java
  • Learning:C, Java, C++, C#, Python, JavaScript, Assembly

Posted 22 October 2012 - 07:47 PM

Thank for tutorial, I called O/X game.

No problem :) Glad you enjoyed it. Soon I'll start making more tutorials again, but I'm currently creating a collection of utility classes that will help with my future projects.
  • 0
Speaks fluent Java

#10 KekeJordan

KekeJordan

    CC Lurker

  • Just Joined
  • Pip
  • 1 posts

Posted 24 June 2013 - 12:00 PM

Hello I am trying to make my tic tac toe single player game for a research project with out using your code I want to make it my own why did you use different classes instead of just putting them in one class all together

 


  • 0

#11 RyanyannixDespi

RyanyannixDespi

    CC Lurker

  • Just Joined
  • Pip
  • 2 posts
  • Programming Language:Java, PHP
  • Learning:Java, C#, PHP, JavaScript, Visual Basic .NET

Posted 25 June 2013 - 08:10 PM

Tnx for this... i got an idea on my TicTacToe


  • 0

#12 Chall

Chall

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 349 posts
  • Location:Cedar Rapids, IA
  • Programming Language:Java
  • Learning:C, Java, C++, C#, Python, JavaScript, Assembly

Posted 29 August 2013 - 10:15 AM

Hello I am trying to make my tic tac toe single player game for a research project with out using your code I want to make it my own why did you use different classes instead of just putting them in one class all together

Because It's neater to keep things separate, or I at least think it is. I guess the reason is because if you are programming in an object oriented language, it would make sense to separate different "objects", TicTacToe, the game,  is it's own object, and provides a bridge of communication for the other objects, such as Tile and ClickHandler.


Edited by Chall, 29 August 2013 - 10:28 AM.

  • 0
Speaks fluent Java





Also tagged with one or more of these keywords: tictactoe, java, game, tutorial