Java Programming: Create a graphical Swing implementation of Tic Tac Toe. Your l
ID: 664396 • Letter: J
Question
Java Programming:
Create a graphical Swing implementation of Tic Tac Toe.
Your layout should have a JFrame with the Tic Tac Toe title, a label at the top of the content pane that gives status (X to play, O to play, X wins, O wins, Draw...), and a button at the bottom to restart the game. The label and button should not fill their entire sections in the BorderLayout. (Fixing that, recall, involves using a JPanel)
The game board itself should consist of 9 buttons in a grid layout located in the center portion of the JFrame's BorderLayout. The default text for the buttons should be empty (""). If an empty button is pressed, its text should be changed to an X or an O depending on who's turn it is. If a button with an X or an O on it is clicked, no change should be made to the board and the turn should not advance to the next player.
If a player makes a winning move, that should be recognized by the program. The status should update for the win and no further button presses should do anything until the restart button has been pressed. If the last move is made without a win, the status should change to draw and only the restart button should do anything.
Getting the initial layout of the game correct is worth 20 points. Getting that and all of the interface-related rules correct is worth 36 points. Correctly detecting and acting on a win or draw is worth the remaining 4 points. Naturally these aren't subsets of each other, so errors in the basic layout would still deduct from a game that runs correctly.
I would suggest storing the game board buttons in an array for easy access. Have the game have both a one- and two-player mode. The two-player version is the base version. Have two buttons at the bottom rather than one to allow the user to start a one- or two-player game. The one-player computer should be able to win the game and not be able to lose the game. The computer should also always play a winning move if one is available.
Explanation / Answer
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.Random;
public class TicTacToe extends JFrame implements ChangeListener, ActionListener {
private JSlider slider;
private JButton oButton, xButton;
private Board board;
private int lineThickness=4;
private Color oColor=Color.BLUE, xColor=Color.RED;
static final char BLANK=' ', O='O', X='X';
private char position[]={ // Board position (BLANK, O, or X)
BLANK, BLANK, BLANK,
BLANK, BLANK, BLANK,
BLANK, BLANK, BLANK};
private int wins=0, losses=0, draws=0; // game count by user
// Start the game
public static void main(String args[]) {
new TicTacToe();
}
// Initialize
public TicTacToe() {
super("Tic Tac Toe demo");
JPanel topPanel=new JPanel();
topPanel.setLayout(new FlowLayout());
topPanel.add(new JLabel("Line Thickness:"));
topPanel.add(slider=new JSlider(SwingConstants.HORIZONTAL, 1, 20, 4));
slider.setMajorTickSpacing(1);
slider.setPaintTicks(true);
slider.addChangeListener(this);
topPanel.add(oButton=new JButton("O Color"));
topPanel.add(xButton=new JButton("X Color"));
oButton.addActionListener(this);
xButton.addActionListener(this);
add(topPanel, BorderLayout.NORTH);
add(board=new Board(), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
setVisible(true);
}
// Change line thickness
public void stateChanged(ChangeEvent e) {
lineThickness = slider.getValue();
board.repaint();
}
// Change color of O or X
public void actionPerformed(ActionEvent e) {
if (e.getSource()==oButton) {
Color newColor = JColorChooser.showDialog(this, "Choose a new color for O", oColor);
if (newColor!=null)
oColor=newColor;
}
else if (e.getSource()==xButton) {
Color newColor = JColorChooser.showDialog(this, "Choose a new color for X", xColor);
if (newColor!=null)
xColor=newColor;
}
board.repaint();
}
// Board is what actually plays and displays the game
private class Board extends JPanel implements MouseListener {
private Random random=new Random();
private int rows[][]={{0,2},{3,5},{6,8},{0,6},{1,7},{2,8},{0,8},{2,6}};
// Endpoints of the 8 rows in position[] (across, down, diagonally)
public Board() {
addMouseListener(this);
}
// Redraw the board
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w=getWidth();
int h=getHeight();
Graphics2D g2d = (Graphics2D) g;
// Draw the grid
g2d.setPaint(Color.WHITE);
g2d.fill(new Rectangle2D.Double(0, 0, w, h));
g2d.setPaint(Color.BLACK);
g2d.setStroke(new BasicStroke(lineThickness));
g2d.draw(new Line2D.Double(0, h/3, w, h/3));
g2d.draw(new Line2D.Double(0, h*2/3, w, h*2/3));
g2d.draw(new Line2D.Double(w/3, 0, w/3, h));
g2d.draw(new Line2D.Double(w*2/3, 0, w*2/3, h));
// Draw the Os and Xs
for (int i=0; i<9; ++i) {
double xpos=(i%3+0.5)*w/3.0;
double ypos=(i/3+0.5)*h/3.0;
double xr=w/8.0;
double yr=h/8.0;
if (position[i]==O) {
g2d.setPaint(oColor);
g2d.draw(new Ellipse2D.Double(xpos-xr, ypos-yr, xr*2, yr*2));
}
else if (position[i]==X) {
g2d.setPaint(xColor);
g2d.draw(new Line2D.Double(xpos-xr, ypos-yr, xpos+xr, ypos+yr));
g2d.draw(new Line2D.Double(xpos-xr, ypos+yr, xpos+xr, ypos-yr));
}
}
}
// Draw an O where the mouse is clicked
public void mouseClicked(MouseEvent e) {
int xpos=e.getX()*3/getWidth();
int ypos=e.getY()*3/getHeight();
int pos=xpos+3*ypos;
if (pos>=0 && pos<9 && position[pos]==BLANK) {
position[pos]=O;
repaint();
putX(); // computer plays
repaint();
}
}
// Ignore other mouse events
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
// Computer plays X
void putX() {
// Check if game is over
if (won(O))
newGame(O);
else if (isDraw())
newGame(BLANK);
// Play X, possibly ending the game
else {
nextMove();
if (won(X))
newGame(X);
else if (isDraw())
newGame(BLANK);
}
}
// Return true if player has won
boolean won(char player) {
for (int i=0; i<8; ++i)
if (testRow(player, rows[i][0], rows[i][1]))
return true;
return false;
}
// Has player won in the row from position[a] to position[b]?
boolean testRow(char player, int a, int b) {
return position[a]==player && position[b]==player
&& position[(a+b)/2]==player;
}
// Play X in the best spot
void nextMove() {
int r=findRow(X); // complete a row of X and win if possible
if (r<0)
r=findRow(O); // or try to block O from winning
if (r<0) { // otherwise move randomly
do
r=random.nextInt(9);
while (position[r]!=BLANK);
}
position[r]=X;
}
// Return 0-8 for the position of a blank spot in a row if the
// other 2 spots are occupied by player, or -1 if no spot exists
int findRow(char player) {
for (int i=0; i<8; ++i) {
int result=find1Row(player, rows[i][0], rows[i][1]);
if (result>=0)
return result;
}
return -1;
}
// If 2 of 3 spots in the row from position[a] to position[b]
// are occupied by player and the third is blank, then return the
// index of the blank spot, else return -1.
int find1Row(char player, int a, int b) {
int c=(a+b)/2; // middle spot
if (position[a]==player && position[b]==player && position[c]==BLANK)
return c;
if (position[a]==player && position[c]==player && position[b]==BLANK)
return b;
if (position[b]==player && position[c]==player && position[a]==BLANK)
return a;
return -1;
}
// Are all 9 spots filled?
boolean isDraw() {
for (int i=0; i<9; ++i)
if (position[i]==BLANK)
return false;
return true;
}
// Start a new game
void newGame(char winner) {
repaint();
// Announce result of last game. Ask user to play again.
String result;
if (winner==O) {
++wins;
result = "You Win!";
}
else if (winner==X) {
++losses;
result = "I Win!";
}
else {
result = "Tie";
++draws;
}
if (JOptionPane.showConfirmDialog(null,
"You have "+wins+ " wins, "+losses+" losses, "+draws+" draws "
+"Play again?", result, JOptionPane.YES_NO_OPTION)
!=JOptionPane.YES_OPTION) {
System.exit(0);
}
// Clear the board to start a new game
for (int j=0; j<9; ++j)
position[j]=BLANK;
// Computer starts first every other game
if ((wins+losses+draws)%2 == 1)
nextMove();
}
} // end inner class Board
} // end class TicTacToe
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.