Implemented game restarting

+ Restarting method in Game
+ Abstract cancelMove method in Player
+ Stopping calculations in AIPlayer when the game has been restarted
This commit is contained in:
Kai S. K. Engelbart 2019-07-14 12:03:45 +02:00
parent fe8ae1826e
commit a3b5531f09
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
6 changed files with 70 additions and 25 deletions

View File

@ -29,10 +29,6 @@ public class Game {
players.values().forEach(player -> player.setGame(this)); players.values().forEach(player -> player.setGame(this));
} }
public void start() {
players.get(Color.WHITE).requestMove();
}
public void onMove(Player player, Move move) { public void onMove(Player player, Move move) {
if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) { if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) {
System.out.printf("%s: %s%n", player.color, move); System.out.printf("%s: %s%n", player.color, move);
@ -51,4 +47,15 @@ public class Game {
} }
} else player.requestMove(); } 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();
}
} }

View File

@ -61,4 +61,9 @@ public class NaturalPlayer extends Player {
public void requestMove() { public void requestMove() {
moveRequested = true; moveRequested = true;
} }
@Override
public void cancelMove() {
moveRequested = false;
}
} }

View File

@ -22,6 +22,8 @@ public abstract class Player {
public abstract void requestMove(); public abstract void requestMove();
public abstract void cancelMove();
public Game getGame() { return game; } public Game getGame() { return game; }
public void setGame(Game game) { this.game = game; } public void setGame(Game game) { this.game = game; }

View File

@ -6,6 +6,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@ -25,14 +26,19 @@ public class AIPlayer extends Player {
private int availableProcessors; private int availableProcessors;
private int maxDepth; private int maxDepth;
private volatile boolean exitRequested;
private volatile ExecutorService executor;
public AIPlayer(Board board, Color color, int maxDepth) { public AIPlayer(Board board, Color color, int maxDepth) {
super(board, color); super(board, color);
availableProcessors = Runtime.getRuntime().availableProcessors(); availableProcessors = Runtime.getRuntime().availableProcessors();
this.maxDepth = maxDepth; this.maxDepth = maxDepth;
exitRequested = false;
} }
@Override @Override
public void requestMove() { public void requestMove() {
exitRequested = false;
/* /*
* Define some processing threads, split the available moves between them and * Define some processing threads, split the available moves between them and
* retrieve the result after their execution. * 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. * Get a copy of the board and the available moves.
*/ */
Board board = (Board) AIPlayer.this.board.clone(); Board board = (Board) AIPlayer.this.board.clone();
List<Move> moves = board.getMoves(color); List<Move> moves = board.getMoves(color);
/* /*
* Define move processors and split the available moves between them. * 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 * Execute processors, get the best result and pass it back to the Game class
*/ */
ExecutorService executor = Executors.newFixedThreadPool(numThreads); executor = Executors.newFixedThreadPool(numThreads);
List<ProcessingResult> results = new ArrayList<>(numThreads); List<ProcessingResult> results = new ArrayList<>(numThreads);
try { try {
List<Future<ProcessingResult>> futures = executor.invokeAll(processors); List<Future<ProcessingResult>> futures = executor.invokeAll(processors);
@ -74,7 +80,18 @@ public class AIPlayer extends Player {
ex.printStackTrace(); ex.printStackTrace();
} }
results.sort((r1, r2) -> Integer.compare(r2.score, r1.score)); 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(); }, "AIPlayer calculation setup").start();
} }
@Override
public void cancelMove() {
exitRequested = true;
executor.shutdownNow();
try {
executor.awaitTermination(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }

View File

@ -26,10 +26,16 @@ public class GameModeDialog extends JDialog {
private static final long serialVersionUID = 5470026233924735607L; 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<Color, Player> players;
/** /**
* Create the dialog. * Create the dialog.
*/ */
public GameModeDialog(BoardPane boardPane) { public GameModeDialog(MainWindow parent, BoardPane boardPane) {
super(); super();
setModal(true); setModal(true);
setTitle("Game Mode Selection"); setTitle("Game Mode Selection");
@ -46,40 +52,43 @@ public class GameModeDialog extends JDialog {
} }
}); });
final BoardComponent boardComponent = boardPane.getBoardComponent(); this.parent = parent;
final OverlayComponent overlayComponent = boardPane.getOverlayComponent(); boardComponent = boardPane.getBoardComponent();
final Board board = boardComponent.getBoard(); overlayComponent = boardPane.getOverlayComponent();
board = boardComponent.getBoard();
players = new HashMap<>();
JButton btnNatural = new JButton("Game against natural opponent"); JButton btnNatural = new JButton("Game against natural opponent");
btnNatural.addActionListener((evt) -> { btnNatural.addActionListener((evt) -> {
Map<Color, Player> players = new HashMap<>();
players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent)); players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent));
players.put(Color.BLACK, new NaturalPlayer(board, Color.BLACK, overlayComponent)); players.put(Color.BLACK, new NaturalPlayer(board, Color.BLACK, overlayComponent));
new Game(players, boardComponent).start(); startGame();
dispose();
}); });
getContentPane().add(btnNatural); getContentPane().add(btnNatural);
JButton btnAI = new JButton("Game against AI"); JButton btnAI = new JButton("Game against AI");
btnAI.addActionListener((evt) -> { btnAI.addActionListener((evt) -> {
Map<Color, Player> players = new HashMap<>();
players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent)); players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent));
players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 5)); players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 5));
new Game(players, boardComponent).start(); startGame();
dispose();
}); });
getContentPane().add(btnAI); getContentPane().add(btnAI);
JButton btnAI2 = new JButton("AI against AI"); JButton btnAI2 = new JButton("AI against AI");
btnAI2.addActionListener((evt) -> { btnAI2.addActionListener((evt) -> {
Map<Color, Player> players = new HashMap<>();
players.put(Color.WHITE, new AIPlayer(board, Color.WHITE, 5)); players.put(Color.WHITE, new AIPlayer(board, Color.WHITE, 5));
players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 4)); players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 4));
new Game(players, boardComponent).start(); startGame();
dispose();
}); });
getContentPane().add(btnAI2); getContentPane().add(btnAI2);
setLocationRelativeTo(null); setLocationRelativeTo(null);
} }
private void startGame() {
Game game = new Game(players, boardComponent);
parent.setGame(game);
game.start();
dispose();
}
} }

View File

@ -8,7 +8,7 @@ import javax.swing.JFrame;
import javax.swing.JPanel; import javax.swing.JPanel;
import dev.kske.chess.board.Board; import dev.kske.chess.board.Board;
import dev.kske.chess.game.Game;
/** /**
* Project: <strong>Chess</strong><br> * Project: <strong>Chess</strong><br>
@ -18,7 +18,8 @@ import dev.kske.chess.board.Board;
*/ */
public class MainWindow { public class MainWindow {
private JFrame mframe; private JFrame mframe;
private Game game;
/** /**
* Launch the application. * Launch the application.
@ -61,12 +62,16 @@ public class MainWindow {
mframe.getContentPane().add(toolPanel, BorderLayout.NORTH); mframe.getContentPane().add(toolPanel, BorderLayout.NORTH);
JButton btnRestart = new JButton("Restart"); 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); toolPanel.add(btnRestart);
mframe.pack(); mframe.pack();
mframe.setLocationRelativeTo(null); mframe.setLocationRelativeTo(null);
// Display dialog for game mode selection // 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; }
} }