diff --git a/src/dev/kske/chess/game/Game.java b/src/dev/kske/chess/game/Game.java index cbe4ba8..09ba1dd 100644 --- a/src/dev/kske/chess/game/Game.java +++ b/src/dev/kske/chess/game/Game.java @@ -29,10 +29,6 @@ public class Game { players.values().forEach(player -> player.setGame(this)); } - public void start() { - players.get(Color.WHITE).requestMove(); - } - public void onMove(Player player, Move move) { if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) { System.out.printf("%s: %s%n", player.color, move); @@ -51,4 +47,15 @@ public class Game { } } else player.requestMove(); } + + public void start() { + players.get(Color.WHITE).requestMove(); + } + + public void restart() { + players.forEach((k, v) -> v.cancelMove()); + board.initializeDefaultPositions(); + boardComponent.repaint(); + start(); + } } diff --git a/src/dev/kske/chess/game/NaturalPlayer.java b/src/dev/kske/chess/game/NaturalPlayer.java index d346a71..2c97782 100644 --- a/src/dev/kske/chess/game/NaturalPlayer.java +++ b/src/dev/kske/chess/game/NaturalPlayer.java @@ -61,4 +61,9 @@ public class NaturalPlayer extends Player { public void requestMove() { moveRequested = true; } + + @Override + public void cancelMove() { + moveRequested = false; + } } diff --git a/src/dev/kske/chess/game/Player.java b/src/dev/kske/chess/game/Player.java index fd34dde..a67d7ac 100644 --- a/src/dev/kske/chess/game/Player.java +++ b/src/dev/kske/chess/game/Player.java @@ -22,6 +22,8 @@ public abstract class Player { public abstract void requestMove(); + public abstract void cancelMove(); + public Game getGame() { return game; } public void setGame(Game game) { this.game = game; } diff --git a/src/dev/kske/chess/game/ai/AIPlayer.java b/src/dev/kske/chess/game/ai/AIPlayer.java index 21a1155..003afd8 100644 --- a/src/dev/kske/chess/game/ai/AIPlayer.java +++ b/src/dev/kske/chess/game/ai/AIPlayer.java @@ -6,6 +6,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import javax.swing.SwingUtilities; @@ -25,14 +26,19 @@ public class AIPlayer extends Player { private int availableProcessors; private int maxDepth; + private volatile boolean exitRequested; + private volatile ExecutorService executor; + public AIPlayer(Board board, Color color, int maxDepth) { super(board, color); availableProcessors = Runtime.getRuntime().availableProcessors(); this.maxDepth = maxDepth; + exitRequested = false; } @Override public void requestMove() { + exitRequested = false; /* * Define some processing threads, split the available moves between them and * retrieve the result after their execution. @@ -41,8 +47,8 @@ public class AIPlayer extends Player { /* * Get a copy of the board and the available moves. */ - Board board = (Board) AIPlayer.this.board.clone(); - List moves = board.getMoves(color); + Board board = (Board) AIPlayer.this.board.clone(); + List moves = board.getMoves(color); /* * Define move processors and split the available moves between them. @@ -63,7 +69,7 @@ public class AIPlayer extends Player { /* * Execute processors, get the best result and pass it back to the Game class */ - ExecutorService executor = Executors.newFixedThreadPool(numThreads); + executor = Executors.newFixedThreadPool(numThreads); List results = new ArrayList<>(numThreads); try { List> futures = executor.invokeAll(processors); @@ -74,7 +80,18 @@ public class AIPlayer extends Player { ex.printStackTrace(); } results.sort((r1, r2) -> Integer.compare(r2.score, r1.score)); - SwingUtilities.invokeLater(() -> game.onMove(this, results.get(0).move)); + if (!exitRequested) SwingUtilities.invokeLater(() -> game.onMove(this, results.get(0).move)); }, "AIPlayer calculation setup").start(); } + + @Override + public void cancelMove() { + exitRequested = true; + executor.shutdownNow(); + try { + executor.awaitTermination(500, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } } diff --git a/src/dev/kske/chess/ui/GameModeDialog.java b/src/dev/kske/chess/ui/GameModeDialog.java index 9c37a80..d7e04c5 100644 --- a/src/dev/kske/chess/ui/GameModeDialog.java +++ b/src/dev/kske/chess/ui/GameModeDialog.java @@ -26,10 +26,16 @@ public class GameModeDialog extends JDialog { private static final long serialVersionUID = 5470026233924735607L; + private final MainWindow parent; + private final Board board; + private final OverlayComponent overlayComponent; + private final BoardComponent boardComponent; + private final Map players; + /** * Create the dialog. */ - public GameModeDialog(BoardPane boardPane) { + public GameModeDialog(MainWindow parent, BoardPane boardPane) { super(); setModal(true); setTitle("Game Mode Selection"); @@ -46,40 +52,43 @@ public class GameModeDialog extends JDialog { } }); - final BoardComponent boardComponent = boardPane.getBoardComponent(); - final OverlayComponent overlayComponent = boardPane.getOverlayComponent(); - final Board board = boardComponent.getBoard(); + this.parent = parent; + boardComponent = boardPane.getBoardComponent(); + overlayComponent = boardPane.getOverlayComponent(); + board = boardComponent.getBoard(); + players = new HashMap<>(); JButton btnNatural = new JButton("Game against natural opponent"); btnNatural.addActionListener((evt) -> { - Map players = new HashMap<>(); players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent)); players.put(Color.BLACK, new NaturalPlayer(board, Color.BLACK, overlayComponent)); - new Game(players, boardComponent).start(); - dispose(); + startGame(); }); getContentPane().add(btnNatural); JButton btnAI = new JButton("Game against AI"); btnAI.addActionListener((evt) -> { - Map players = new HashMap<>(); players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent)); players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 5)); - new Game(players, boardComponent).start(); - dispose(); + startGame(); }); getContentPane().add(btnAI); JButton btnAI2 = new JButton("AI against AI"); btnAI2.addActionListener((evt) -> { - Map players = new HashMap<>(); players.put(Color.WHITE, new AIPlayer(board, Color.WHITE, 5)); players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 4)); - new Game(players, boardComponent).start(); - dispose(); + startGame(); }); getContentPane().add(btnAI2); setLocationRelativeTo(null); } + + private void startGame() { + Game game = new Game(players, boardComponent); + parent.setGame(game); + game.start(); + dispose(); + } } diff --git a/src/dev/kske/chess/ui/MainWindow.java b/src/dev/kske/chess/ui/MainWindow.java index f6c2630..2c9c7fd 100644 --- a/src/dev/kske/chess/ui/MainWindow.java +++ b/src/dev/kske/chess/ui/MainWindow.java @@ -8,7 +8,7 @@ import javax.swing.JFrame; import javax.swing.JPanel; import dev.kske.chess.board.Board; - +import dev.kske.chess.game.Game; /** * Project: Chess
@@ -18,7 +18,8 @@ import dev.kske.chess.board.Board; */ public class MainWindow { - private JFrame mframe; + private JFrame mframe; + private Game game; /** * Launch the application. @@ -61,12 +62,16 @@ public class MainWindow { mframe.getContentPane().add(toolPanel, BorderLayout.NORTH); JButton btnRestart = new JButton("Restart"); - btnRestart.addActionListener((evt) -> System.err.println("Resetting not implemented!")); + btnRestart.addActionListener((evt) -> { if (game != null) game.restart(); }); toolPanel.add(btnRestart); mframe.pack(); mframe.setLocationRelativeTo(null); // Display dialog for game mode selection - new GameModeDialog(boardPane).setVisible(true); + new GameModeDialog(this, boardPane).setVisible(true); } + + public Game getGame() { return game; } + + public void setGame(Game game) { this.game = game; } }