Last active
August 27, 2018 20:53
-
-
Save aramperes/2a02101595b3c924d5c4a41ca125d2f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tictactoegame.ui; | |
import javax.swing.*; | |
import java.awt.*; | |
public class SwingTicTacToe extends JFrame { | |
/** | |
* The font used for the buttons. | |
*/ | |
private static final Font FONT = new Font("Arial", Font.PLAIN, 50); | |
/** | |
* The board map (2D array, each char is one of '-', 'x', 'o'). | |
*/ | |
private final char[][] board = {{'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'}}; | |
/** | |
* The buttons corresponding to the board. | |
*/ | |
private final JButton[][] buttons = new JButton[3][3]; | |
/** | |
* Whether it is X's turn currently. | |
*/ | |
private boolean turnX = true; | |
private SwingTicTacToe(String title, int width, int height) { | |
super(title); | |
// Sets the size of the window | |
setSize(width, height); | |
// Puts the window in the middle of the screen, instead of the top left | |
setLocationRelativeTo(null); | |
// Makes the application exit when the window is closed | |
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); | |
// Makes the window not resizable | |
setResizable(false); | |
Container pane = getContentPane(); | |
// Makes the grid 3x3 | |
pane.setLayout(new GridLayout(3, 3)); | |
// Initializes the buttons | |
for (int y = 0; y < 3; y++) { | |
for (int x = 0; x < 3; x++) { | |
JButton button = new JButton(); | |
button.setFont(FONT); | |
// Loop cursors are copied to final values, so they can be used inside anonymous classes | |
int finalX = x; | |
int finalY = y; | |
// Adds action listeners for each button | |
button.addActionListener(e -> { | |
// Sets the board value | |
board[finalY][finalX] = turnX ? 'x' : 'o'; | |
updateButtons(); | |
// Switches whose turn it is | |
turnX = !turnX; | |
// Checks if the game has ended | |
checkBoard(); | |
}); | |
// Removes the outline on buttons | |
button.setFocusable(false); | |
// Adds the button to the grid | |
pane.add(button); | |
buttons[y][x] = button; | |
} | |
} | |
updateButtons(); | |
} | |
private void checkBoard() { | |
if (!someoneHasWon() && isBoardFull()) { | |
// If nobody won and the board is full, the game is a tie | |
JOptionPane.showMessageDialog(this, "It's a tie!"); | |
// Start over | |
resetBoard(); | |
} | |
if (someoneHasWon()) { | |
// Someone won, announce the winner | |
if (!turnX) { | |
JOptionPane.showMessageDialog(this, "X won!"); | |
} else { | |
JOptionPane.showMessageDialog(this, "O won!"); | |
} | |
// Start over | |
resetBoard(); | |
} | |
} | |
/** | |
* Checks if whether someone has completed a winning move. | |
*/ | |
private boolean someoneHasWon() { | |
// Diagonals | |
if (board[1][1] != '-') { | |
if (board[0][0] == board[1][1] && board[1][1] == board[2][2]) | |
return true; | |
if (board[0][2] == board[1][1] && board[1][1] == board[2][0]) | |
return true; | |
} | |
// Test rows | |
for (int i = 0; i < 3; ++i) { | |
if (board[i][0] != '-' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) | |
return true; | |
} | |
// Test columns | |
for (int j = 0; j < 3; ++j) { | |
if (board[0][j] != '-' && board[0][j] == board[1][j] && board[1][j] == board[2][j]) | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Checks whether no tiles are left empty. | |
*/ | |
private boolean isBoardFull() { | |
for (int i = 0; i < 3; i++) { | |
for (int j = 0; j < 3; j++) { | |
if (board[i][j] == '-') { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
/** | |
* Resets the board to its original (empty) state. | |
*/ | |
private void resetBoard() { | |
for (int y = 0; y < 3; y++) { | |
for (int x = 0; x < 3; x++) { | |
board[y][x] = '-'; | |
} | |
} | |
turnX = true; | |
updateButtons(); | |
} | |
/** | |
* Updates the buttons to reflect the board. | |
*/ | |
private void updateButtons() { | |
for (int y = 0; y < 3; y++) { | |
for (int x = 0; x < 3; x++) { | |
char tile = board[y][x]; | |
if (tile == '-') { | |
buttons[y][x].setEnabled(true); | |
buttons[y][x].setText(""); | |
} else { | |
buttons[y][x].setText(String.valueOf(board[y][x])); | |
buttons[y][x].setEnabled(false); | |
} | |
} | |
} | |
} | |
public static void main(String[] args) throws Exception { | |
// Overrides the Swing look to the OS look. | |
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | |
// Start | |
SwingTicTacToe window = new SwingTicTacToe("TicTacToe", 500, 500); | |
window.setVisible(true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment