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 40ef31dd1f
commit 5984f4119e
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));
}
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();
}
}

View File

@ -61,4 +61,9 @@ public class NaturalPlayer extends Player {
public void requestMove() {
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 cancelMove();
public Game getGame() { return 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.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<Move> moves = board.getMoves(color);
Board board = (Board) AIPlayer.this.board.clone();
List<Move> 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<ProcessingResult> results = new ArrayList<>(numThreads);
try {
List<Future<ProcessingResult>> 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();
}
}
}

View File

@ -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<Color, Player> 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<Color, Player> 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<Color, Player> 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<Color, Player> 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();
}
}

View File

@ -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: <strong>Chess</strong><br>
@ -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; }
}