Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link
Source Link
coderodde
  • 31.8k
  • 15
  • 77
  • 202

Noughts and Crosses GUI game in Java - Part 2/2: GUI

(See also Noughts and Crosses GUI game in Java - Part 1/2: AI)

This part is dedicated to the View/Controller of the MVC pattern. So once again these are the building blocks of the Noughts and Crosses game:

Configuring the game

Playing

ConfigurationFrame.java:

package net.coderodde.game.crosses;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import static net.coderodde.game.crosses.Application.centerFrame;
/**
 * This class implements a configuration frame.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Oct 8, 2015)
 */
public class ConfigurationFrame extends JFrame {
 private final JTextField heightField;
 private final JTextField widthField;
 private final JTextField patternLengthField;
 private final JTextField depthField;
 private final JLabel heightLabel;
 private final JLabel widthLabel;
 private final JLabel patternLengthLabel;
 private final JLabel depthLabel;
 private final JButton startGameButton;
 private final GameFrame gameFrame;
 public ConfigurationFrame() {
 this(5, 5, 4, 5);
 }
 public ConfigurationFrame(int height, 
 int width, 
 int patternLength, 
 int depth) {
 super("Configure your game");
 this.heightField = new JTextField("" + height);
 this.widthField = new JTextField("" + width);
 this.patternLengthField = new JTextField("" + patternLength);
 this.depthField = new JTextField("" + depth);
 this.heightLabel = new JLabel("Field height");
 this.widthLabel = new JLabel("Field width");
 this.patternLengthLabel = new JLabel("Winning pattern length");
 this.depthLabel = new JLabel("AI depth");
 this.startGameButton = new JButton("Start");
 this.gameFrame = new GameFrame(this);
 Border labelBorder = new EmptyBorder(0, 10, 0, 10);
 heightLabel .setBorder(labelBorder);
 widthLabel .setBorder(labelBorder);
 patternLengthLabel.setBorder(labelBorder);
 depthLabel. setBorder(labelBorder);
 Border panelBorder = BorderFactory.createLineBorder(Color.RED);
 JPanel heightPanel = new JPanel();
 JPanel widthPanel = new JPanel();
 JPanel patternLengthPanel = new JPanel();
 JPanel depthPanel = new JPanel();
 heightPanel .setBorder(panelBorder);
 widthPanel .setBorder(panelBorder);
 patternLengthPanel .setBorder(panelBorder);
 depthPanel .setBorder(panelBorder);
 heightPanel .setLayout(new GridLayout(1, 2));
 widthPanel .setLayout(new GridLayout(1, 2));
 patternLengthPanel .setLayout(new GridLayout(1, 2));
 depthPanel .setLayout(new GridLayout(1, 2));
 heightPanel.add(heightLabel);
 heightPanel.add(heightField);
 widthPanel.add(widthLabel);
 widthPanel.add(widthField);
 patternLengthPanel.add(patternLengthLabel);
 patternLengthPanel.add(patternLengthField);
 depthPanel.add(depthLabel);
 depthPanel.add(depthField);
 getContentPane().setLayout(new GridLayout(5, 1, 20, 10));
 getContentPane().add(heightPanel);
 getContentPane().add(widthPanel);
 getContentPane().add(patternLengthPanel);
 getContentPane().add(depthPanel);
 getContentPane().add(startGameButton);
 StartButtonActionListener startButtonActionListener = 
 new StartButtonActionListener(heightField,
 widthField,
 patternLengthField,
 depthField);
 startGameButton.addActionListener(startButtonActionListener);
 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 pack();
 centerFrame(this);
 setResizable(false);
 startGameButton.requestFocus();
 setVisible(true);
 }
 public void setHeight(int height) {
 this.heightField.setText("" + height);
 }
 public void setWidth(int width) {
 this.widthField.setText("" + width);
 }
 public void setPatternLength(int patternLength) {
 this.patternLengthField.setText("" + patternLength);
 }
 public void setDepth(int depth) {
 this.depthField.setText("" + depth);
 }
 private class StartButtonActionListener implements ActionListener {
 private final JTextField heightField;
 private final JTextField widthField;
 private final JTextField patternLengthField;
 private final JTextField depthField;
 private TicTacToeGrid resultGrid;
 StartButtonActionListener(JTextField heightField,
 JTextField widthField,
 JTextField patternLengthField,
 JTextField depthField) {
 this.heightField = heightField;
 this.widthField = widthField;
 this.patternLengthField = patternLengthField;
 this.depthField = depthField;
 }
 @Override
 public void actionPerformed(ActionEvent e) {
 resultGrid = null;
 String stmp = heightField.getText().trim();
 if (stmp.isEmpty()) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this,
 "Please input the field height.",
 "Input error",
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 int height;
 try {
 height = Integer.parseInt(stmp);
 } catch (NumberFormatException ex) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this, 
 "Bad height: " + stmp, 
 "Input error", 
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 stmp = widthField.getText().trim();
 if (stmp.isEmpty()) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this,
 "Please input the field width.",
 "Input error",
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 int width;
 try {
 width = Integer.parseInt(stmp);
 } catch (NumberFormatException ex) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this, 
 "Bad width: " + stmp, 
 "Input error", 
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 stmp = patternLengthField.getText().trim();
 if (stmp.isEmpty()) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this,
 "Please input the winning pattern length.",
 "Input error",
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 int patternLength;
 try {
 patternLength = Integer.parseInt(stmp);
 } catch (NumberFormatException ex) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this, 
 "Bad pattern length: " + stmp, 
 "Input error", 
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 stmp = depthField.getText().trim();
 if (stmp.isEmpty()) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this,
 "Please input the AI depth.",
 "Input error",
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 int depth;
 try {
 depth = Integer.parseInt(stmp);
 } catch (NumberFormatException ex) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this, 
 "Bad depth: " + stmp, 
 "Input error", 
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 try {
 resultGrid = new TicTacToeGrid(height, width, patternLength); 
 } catch (Exception ex) {
 JOptionPane.showMessageDialog(
 ConfigurationFrame.this,
 "Bad configuration: " + ex.getMessage(),
 "Input error",
 JOptionPane.ERROR_MESSAGE);
 return;
 }
 ConfigurationFrame.this.setVisible(false);
 gameFrame.startGame(resultGrid, depth);
 gameFrame.setVisible(true);
 }
 }
}

GameFrame.java:

package net.coderodde.game.crosses;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JProgressBar;
import static net.coderodde.game.crosses.Application.centerFrame;
/**
 * This class implements a frame showing the game grid.
 *
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Oct 8, 2015)
 */
public class GameFrame extends JFrame {
 private final JProgressBar progressBar;
 private final ConfigurationFrame configurationFrame;
 public GameFrame(ConfigurationFrame configurationFrame) {
 this.progressBar = new JProgressBar();
 this.configurationFrame = configurationFrame;
 }
 public void startGame(TicTacToeGrid grid, int depth) {
 getContentPane().removeAll();
 progressBar.setVisible(false);
 centerFrame(this);
 getContentPane().setLayout(new GridBagLayout());
 setDefaultCloseOperation(EXIT_ON_CLOSE);
 MoveGenerator moveGenerator = new MoveGenerator();
 HeuristicFunction heuristicFunction = new HeuristicFunction();
 TicTacToePanel panel = new TicTacToePanel(progressBar,
 moveGenerator,
 heuristicFunction,
 depth,
 configurationFrame,
 this);
 panel.setCurrentGrid(grid);
 panel.unlock();
 panel.repaint();
 GridBagConstraints c = new GridBagConstraints();
 c.gridx = 0;
 c.gridy = 0;
 c.fill = GridBagConstraints.BOTH;
 c.weightx = 1.0;
 c.weighty = 1.0;
 getContentPane().add(panel, c);
 c = new GridBagConstraints();
 c.gridx = 0;
 c.gridy = 1;
 c.weightx = 1.0;
 c.weighty = 0.0;
 c.fill = GridBagConstraints.HORIZONTAL;
 getContentPane().add(progressBar, c);
 setMinimumSize(panel.getMinimumSize());
 centerFrame(this);
 pack();
 }
}

TicTacToePanel.java:

package net.coderodde.game.crosses;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
/**
 * This class implements the panel for playing Tic Tac Toe.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Oct 5, 2015)
 */
public class TicTacToePanel extends JPanel {
 private static final int DEFAULT_PADDING = 10;
 private static final int DEFAULT_BORDER_WIDTH = 3;
 private static final int MINIMUM_CELL_LENGTH = 60;
 private static final Font DEFAULT_FONT = new Font("Times New Roman", 
 Font.BOLD, 
 50);
 private final JProgressBar progressBar;
 private final MoveGenerator moveGenerator;
 private final HeuristicFunction heuristicFunction;
 private final int maximumDepth;
 private final ConfigurationFrame configurationFrame;
 private final GameFrame gameFrame;
 private TicTacToeGrid currentGrid;
 private int padding;
 private int borderWidth;
 private Color backgroundColor;
 private Color borderColor;
 private Color foregroundColor; 
 private Color highlightOccupiedBorderColor;
 private Color highlightOccupiedCellColor;
 private Color highlightFreeBorderColor;
 private Color highlightFreeCellColor;
 private int highlightCellX;
 private int highlightCellY;
 private int previousHighlightCellX;
 private int previousHighlightCellY;
 private int lastValidCellX = -1;
 private int lastValidCellY = -1;
 /**
 * Specifies whether the AI is currently computing its next move. If the
 * lock is on, the user's input will be ignored. The default value is 
 * {@code false}.
 */
 private volatile boolean lock;
 public TicTacToePanel(JProgressBar progressBar,
 MoveGenerator moveGenerator,
 HeuristicFunction heuristicFunction,
 int maximumDepth,
 ConfigurationFrame configurationFrame,
 GameFrame gameFrame) {
 this.progressBar = progressBar;
 this.moveGenerator = moveGenerator;
 this.heuristicFunction = heuristicFunction;
 this.maximumDepth = maximumDepth;
 this.configurationFrame = configurationFrame;
 this.gameFrame = gameFrame;
 this.padding = DEFAULT_PADDING;
 this.borderWidth = DEFAULT_BORDER_WIDTH;
 this.backgroundColor = Color.WHITE;
 this.borderColor = Color.GRAY;
 this.foregroundColor = Color.BLACK;
 this.highlightFreeBorderColor = new Color(100, 200, 100);
 this.highlightFreeCellColor = Color.GREEN;
 this.highlightOccupiedBorderColor = Color.PINK;
 this.highlightOccupiedCellColor = Color.RED;
 setFont(DEFAULT_FONT);
 this.setMinimumSize(new Dimension(100, 100));
 CanvasMouseListener mouseListener = new CanvasMouseListener();
 this.addMouseListener(mouseListener);
 this.addMouseMotionListener(mouseListener);
 CanvasKeyListener keyListener = new CanvasKeyListener();
 this.addKeyListener(keyListener);
 this.setFocusable(true);
 this.requestFocus();
 }
 public void lock() {
 lock = true;
 }
 public void unlock() {
 lock = false;
 }
 public void setPadding(int padding) {
 this.padding = Math.max(1, padding);
 }
 public void setBorderWidth(int borderWidth) {
 this.borderWidth = Math.max(1, borderWidth);
 }
 public void setBackgroundColor(Color color) {
 this.backgroundColor = color;
 }
 public void setBorderColor(Color color) {
 this.borderColor = color;
 }
 public void setForegroundColor(Color color) {
 this.foregroundColor = color;
 }
 public void setHighlightOccupiedBorderColor(Color color) {
 this.highlightOccupiedBorderColor = color;
 }
 public void setHighlightOccupiedCellColor(Color color) {
 this.highlightOccupiedCellColor = color;
 }
 public void setHighlightFreeBorderColor(Color color) {
 this.highlightFreeBorderColor = color;
 }
 public void setHighlightFreeCellColor(Color color) {
 this.highlightFreeCellColor = color;
 }
 public void setCurrentGrid(TicTacToeGrid grid) {
 if (this.currentGrid == null) {
 this.highlightCellX = grid.getWidth() / 2;
 this.highlightCellY = grid.getHeight() / 2;
 this.lastValidCellX = this.highlightCellX;
 this.lastValidCellY = this.highlightCellY;
 this.previousHighlightCellX = this.highlightCellX;
 this.previousHighlightCellY = this.highlightCellY;
 }
 this.currentGrid = grid;
 repaint();
 }
 public TicTacToeGrid getCurrentGrid() {
 return currentGrid;
 }
 @Override
 public Dimension getMinimumSize() {
 int horizontalCells = currentGrid.getWidth();
 int verticalCells = currentGrid.getHeight();
 return new Dimension(2 * padding + horizontalCells * 
 (borderWidth + MINIMUM_CELL_LENGTH) + 
 borderWidth,
 (2 * padding + verticalCells * 
 (borderWidth + MINIMUM_CELL_LENGTH) + 
 borderWidth));
 }
 @Override
 public Dimension getPreferredSize() {
 return getMinimumSize();
 }
 @Override
 public void update(Graphics g) {
 int availableWidth = getWidth() - 2 * padding;
 int availableHeight = getHeight() - 2 * padding;
 int horizontalCells = currentGrid.getWidth();
 int verticalCells = currentGrid.getHeight();
 int cellWidth = (availableWidth - (horizontalCells + 1) * borderWidth) 
 / horizontalCells;
 int cellHeight = (availableHeight - (verticalCells + 1) * borderWidth) 
 / verticalCells;
 int cellLength = Math.min(cellWidth, cellHeight);
 g.setColor(backgroundColor);
 g.fillRect(0, 0, getWidth(), getHeight());
 int occupiedWidth = (horizontalCells * (cellLength + borderWidth)) + 
 borderWidth;
 int occupiedHeight = (verticalCells * (cellLength + borderWidth)) +
 borderWidth;
 int skipX = (getWidth() - occupiedWidth) / 2;
 int skipY = (getHeight() - occupiedHeight) / 2;
 g.setColor(borderColor);
 // Draw horizontal borders.
 for (int y = 0; y <= verticalCells; ++y) {
 g.fillRect(skipX, 
 skipY + y * (borderWidth + cellLength), 
 horizontalCells * (borderWidth + cellLength) + borderWidth, 
 borderWidth);
 }
 // Draw vertical borders.
 for (int x = 0; x <= horizontalCells; ++x) {
 g.fillRect(skipX + x * (borderWidth + cellLength),
 skipY,
 borderWidth,
 verticalCells * (borderWidth + cellLength) + borderWidth);
 }
 if (highlightCellX >= 0
 && highlightCellX < horizontalCells
 && highlightCellY >= 0
 && highlightCellY < verticalCells) {
 boolean cellOccupied = currentGrid.read(highlightCellX,
 highlightCellY) != null;
 if (cellOccupied) {
 g.setColor(this.highlightOccupiedBorderColor);
 } else {
 g.setColor(this.highlightFreeBorderColor);
 }
 // Draw the border.
 g.fillRect(skipX + highlightCellX * (borderWidth + cellLength),
 skipY + highlightCellY * (borderWidth + cellLength), 
 2 * borderWidth + cellLength,
 2 * borderWidth + cellLength);
 if (cellOccupied) {
 g.setColor(this.highlightOccupiedCellColor);
 } else {
 g.setColor(this.highlightFreeCellColor);
 }
 // Draw the cell.
 g.fillRect(skipX + highlightCellX * (borderWidth + cellLength) + borderWidth,
 skipY + highlightCellY * (borderWidth + cellLength) + borderWidth, 
 cellLength ,
 cellLength);
 }
 g.setColor(foregroundColor);
 g.setFont(getFont());
 if (currentGrid == null) {
 return;
 }
 int verticalSkip = 16;
 Font font = prepareFont(cellLength, verticalSkip, g);
 g.setFont(font);
 Graphics2D g2 = (Graphics2D) g;
 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 FontMetrics fm = g.getFontMetrics(font);
 int textHeight = fm.getAscent();
 int textWidth = fm.stringWidth("X");
 int dx = (cellLength - textWidth) / 2;
 int dy = (cellLength - textHeight) / 2;
 // Draw the marks.
 for (int y = 0; y < currentGrid.getHeight(); ++y) {
 for (int x = 0; x < currentGrid.getWidth(); ++x) { 
 Mark mark = currentGrid.read(x, y);
 if (mark == null) {
 continue;
 }
 g.drawString(mark.equals(Mark.X) ? "X" : "O", 
 skipX + dx + borderWidth * (1 + x) + x * cellLength,
 skipY - dy - 8 + borderWidth * (1 + y) + (1 + y) * cellLength);
 }
 }
 }
 private Font prepareFont(int cellLength, int verticalSkip, Graphics g) {
 Font currentFont = getFont();
 for (int fontSize = 1; ; ++fontSize) {
 Font f = new Font(currentFont.getFontName(), Font.BOLD, fontSize);
 FontMetrics fm = g.getFontMetrics(f);
 int height = fm.getAscent();
 if (height >= cellLength - verticalSkip) {
 return new Font(currentFont.getFontName(), 
 Font.BOLD, 
 fontSize - 1);
 }
 }
 }
 @Override
 public void paint(Graphics g) {
 update(g);
 }
 private Point toCellCoordinates(int x, int y) {
 Point ret = new Point();
 int availableWidth = getWidth() - 2 * padding;
 int availableHeight = getHeight() - 2 * padding;
 int horizontalCells = currentGrid.getWidth();
 int verticalCells = currentGrid.getHeight();
 int cellWidth = (availableWidth - (horizontalCells + 1) * borderWidth) 
 / horizontalCells;
 int cellHeight = (availableHeight - (verticalCells + 1) * borderWidth) 
 / verticalCells;
 int cellLength = Math.min(cellWidth, cellHeight);
 int occupiedWidth = (horizontalCells * (cellLength + borderWidth)) + 
 borderWidth;
 int occupiedHeight = (verticalCells * (cellLength + borderWidth)) +
 borderWidth;
 x -= (getWidth() - occupiedWidth) / 2;
 y -= (getHeight() - occupiedHeight) / 2;
 if (x % (cellLength + borderWidth) < borderWidth
 || y % (cellLength + borderWidth) < borderWidth) {
 ret.x = -1;
 return ret;
 }
 ret.x = x / (cellLength + borderWidth);
 ret.y = y / (cellLength + borderWidth);
 return ret;
 }
 private void tryClick(int x, int y) {
 Point p = toCellCoordinates(x, y);
 if (p.x >= 0 && p.x < currentGrid.getWidth() 
 && p.y >= 0 && p.y < currentGrid.getHeight()) {
 try {
 currentGrid.mark(p.x, p.y, Mark.X);
 repaint();
 AIThread ai = new AIThread(configurationFrame,
 gameFrame,
 currentGrid,
 this,
 progressBar,
 moveGenerator,
 heuristicFunction,
 maximumDepth);
 ai.start();
 } catch (Exception ex) {
 return;
 }
 }
 }
 private void tryHighlight(int x, int y) {
 Point p = toCellCoordinates(x, y);
 // Check that the mouse is on top of a border.
 if (p.x < 0) {
 if (previousHighlightCellX != p.x) {
 highlightCellX = p.x;
 previousHighlightCellX = p.x;
 repaint();
 }
 return;
 }
 if (p.x >= 0 && p.x < currentGrid.getWidth()) {
 this.lastValidCellX = p.x;
 this.lastValidCellY = p.y;
 }
 this.highlightCellX = p.x;
 this.highlightCellY = p.y;
 if (highlightCellX != previousHighlightCellX 
 || highlightCellY != previousHighlightCellY) {
 previousHighlightCellX = highlightCellX;
 previousHighlightCellY = highlightCellY;
 repaint();
 }
 }
 private class CanvasKeyListener implements KeyListener {
 @Override
 public void keyTyped(KeyEvent e) {
 process(e);
 }
 @Override
 public void keyPressed(KeyEvent e) {
 process(e);
 }
 @Override
 public void keyReleased(KeyEvent e) {
 }
 private void process(KeyEvent e) {
 int cellX = lastValidCellX;
 int cellY = lastValidCellY;
 switch (e.getKeyCode()) {
 case KeyEvent.VK_UP:
 case KeyEvent.VK_W:
 if (cellY > 0) {
 previousHighlightCellY = lastValidCellY;
 highlightCellY = --lastValidCellY;
 repaint();
 }
 break;
 case KeyEvent.VK_RIGHT:
 case KeyEvent.VK_D:
 if (cellX < currentGrid.getWidth() - 1) {
 previousHighlightCellX = lastValidCellX;
 highlightCellX = ++lastValidCellX;
 repaint();
 }
 break;
 case KeyEvent.VK_DOWN:
 case KeyEvent.VK_S:
 if (cellY < currentGrid.getHeight() - 1) {
 previousHighlightCellY = lastValidCellY;
 highlightCellY = ++lastValidCellY;
 repaint();
 }
 break;
 case KeyEvent.VK_LEFT: 
 case KeyEvent.VK_A:
 if (cellX > 0) {
 previousHighlightCellX = lastValidCellX;
 highlightCellX = --lastValidCellX;
 repaint();
 }
 break;
 case KeyEvent.VK_SPACE:
 if (!lock) {
 // Try mark.
 try {
 currentGrid.mark(lastValidCellX,
 lastValidCellY,
 Mark.X);
 repaint();
 AIThread ai = new AIThread(configurationFrame,
 gameFrame,
 TicTacToePanel.this.currentGrid,
 TicTacToePanel.this,
 progressBar,
 moveGenerator,
 heuristicFunction,
 maximumDepth);
 ai.start();
 } catch (Exception ex) {
 }
 Mark winner = currentGrid.getWinner();
 String message = null;
 if (winner != null) {
 message = winner.equals(Mark.X) ? 
 "You won!" : 
 "You lost.";
 } else if (currentGrid.isFull()) {
 message = "It's a tie.";
 }
 if (message != null) {
 JOptionPane.showMessageDialog(
 gameFrame, 
 message,
 "Game over",
 JOptionPane.INFORMATION_MESSAGE);
 gameFrame.setVisible(false);
 configurationFrame.setHeight(currentGrid.getHeight());
 configurationFrame.setWidth(currentGrid.getWidth());
 configurationFrame.setPatternLength(currentGrid.getWinningLength());
 configurationFrame.setDepth(maximumDepth);
 configurationFrame.setVisible(true);
 }
 }
 break;
 }
 }
 }
 private class CanvasMouseListener implements MouseListener,
 MouseMotionListener {
 @Override
 public void mouseClicked(MouseEvent e) {
 if (!lock) {
 tryClick(e.getX(), e.getY());
 }
 }
 @Override
 public void mousePressed(MouseEvent e) {
 }
 @Override
 public void mouseReleased(MouseEvent e) {
 }
 @Override
 public void mouseEntered(MouseEvent e) {
 }
 @Override
 public void mouseExited(MouseEvent e) {
 }
 @Override
 public void mouseDragged(MouseEvent e) {
 }
 @Override
 public void mouseMoved(MouseEvent e) {
 tryHighlight(e.getX(), e.getY());
 }
 }
}

The entire game project lives in https://github.com/coderodde/NoughtsAndCrosses in case you want to run it.

lang-java

AltStyle によって変換されたページ (->オリジナル) /