Simplified game creation, added new configuration dialog

This commit is contained in:
Kai S. K. Engelbart 2019-07-25 07:21:07 +02:00
parent 4c0432ca30
commit 8bcd89d975
5 changed files with 151 additions and 99 deletions

View File

@ -12,6 +12,8 @@ import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.game.ai.AIPlayer; import dev.kske.chess.game.ai.AIPlayer;
import dev.kske.chess.ui.BoardComponent; import dev.kske.chess.ui.BoardComponent;
import dev.kske.chess.ui.BoardPane; import dev.kske.chess.ui.BoardPane;
import dev.kske.chess.ui.EngineUtil;
import dev.kske.chess.ui.EngineUtil.EngineInfo;
import dev.kske.chess.ui.OverlayComponent; import dev.kske.chess.ui.OverlayComponent;
/** /**
@ -27,53 +29,40 @@ public class Game {
private OverlayComponent overlayComponent; private OverlayComponent overlayComponent;
private BoardComponent boardComponent; private BoardComponent boardComponent;
public Game(Map<Color, Player> players, BoardPane boardPane) { public Game(BoardPane boardPane, String whiteName, String blackName) {
this.players = players; players = new HashMap<>();
this.overlayComponent = boardPane.getOverlayComponent(); board = new Board();
this.boardComponent = boardPane.getBoardComponent(); overlayComponent = boardPane.getOverlayComponent();
this.board = new Board(); boardComponent = boardPane.getBoardComponent();
boardComponent.setBoard(board); boardComponent.setBoard(board);
players.put(Color.WHITE, getPlayer(whiteName, Color.WHITE));
players.put(Color.BLACK, getPlayer(blackName, Color.BLACK));
// Initialize the game variable in each player // Initialize the game variable in each player
players.values().forEach(player -> player.setGame(this)); players.values().forEach(player -> player.setGame(this));
} }
public static Game createNatural(BoardPane boardPane) { private Player getPlayer(String name, Color color) {
Map<Color, Player> players = new HashMap<>(); switch (name) {
OverlayComponent overlay = boardPane.getOverlayComponent(); case "Natural Player":
return new NaturalPlayer(color, overlayComponent);
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, overlay)); case "AI Player":
players.put(Color.BLACK, new NaturalPlayer(Color.BLACK, overlay)); return new AIPlayer(color, 4, -10);
return new Game(players, boardPane); default:
for (EngineInfo info : EngineUtil.getEngineInfos())
if (info.name.equals(name)) return new UCIPlayer(color, info.path);
System.err.println("Invalid player name: " + name);
return null;
} }
public static Game createNaturalVsAI(BoardPane boardPane, int maxDepth, int alphaBeta) {
Map<Color, Player> players = new HashMap<>();
OverlayComponent overlay = boardPane.getOverlayComponent();
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, overlay));
players.put(Color.BLACK, new AIPlayer(Color.BLACK, maxDepth, alphaBeta));
return new Game(players, boardPane);
}
public static Game createAIVsAI(BoardPane boardPane, int maxDepthW, int maxDepthB, int alphaBetaW, int alphaBetaB) {
Map<Color, Player> players = new HashMap<>();
players.put(Color.WHITE, new AIPlayer(Color.WHITE, maxDepthW, alphaBetaW));
players.put(Color.BLACK, new AIPlayer(Color.BLACK, maxDepthB, alphaBetaB));
return new Game(players, boardPane);
}
public static Game createUCI(BoardPane boardPane, String enginePath) {
Map<Color, Player> players = new HashMap<>();
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, boardPane.getOverlayComponent()));
players.put(Color.BLACK, new UCIPlayer(Color.BLACK, enginePath));
return new Game(players, boardPane);
} }
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)) {
// Redraw
boardComponent.repaint();
overlayComponent.displayArrow(move);
System.out.printf("%s: %s%n", player.color, move); System.out.printf("%s: %s%n", player.color, move);
System.out.println("FEN: " + board.toFEN()); System.out.println("FEN: " + board.toFEN());
GameState eventType = board.getGameEventType(board.getDest(move).getColor().opposite()); GameState eventType = board.getGameEventType(board.getDest(move).getColor().opposite());
@ -87,12 +76,9 @@ public class Game {
case CHECK: case CHECK:
System.out.printf("%s in check!%n", player.color.opposite()); System.out.printf("%s in check!%n", player.color.opposite());
default: default:
boardComponent.repaint();
players.get(board.getActiveColor()).requestMove(); players.get(board.getActiveColor()).requestMove();
} }
overlayComponent.displayArrow(move); } else player.requestMove();
} else
player.requestMove();
} }
public void start() { public void start() {

View File

@ -78,5 +78,4 @@ public class AIConfigDialog extends JDialog {
public boolean isStartGame() { return startGame; } public boolean isStartGame() { return startGame; }
public void setStartGame(boolean startGame) { this.startGame = startGame; } public void setStartGame(boolean startGame) { this.startGame = startGame; }
} }

View File

@ -0,0 +1,82 @@
package dev.kske.chess.ui;
import java.awt.Font;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>GameConfigurationDialog.java</strong><br>
* Created: <strong>24.07.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class GameConfigurationDialog extends JDialog {
private static final long serialVersionUID = 9080577278529876972L;
private String whiteName, blackName;
private boolean startGame;
/**
* Create the dialog.
*/
public GameConfigurationDialog() {
setTitle("Game Configuration");
setBounds(100, 100, 281, 142);
setModal(true);
setLocationRelativeTo(null);
getContentPane().setLayout(null);
startGame = false;
List<String> options = new ArrayList<>(Arrays.asList("Natural Player", "AI Player"));
EngineUtil.getEngineInfos().forEach(info -> options.add(info.name));
JLabel lblWhite = new JLabel("White:");
lblWhite.setFont(new Font("Tahoma", Font.PLAIN, 14));
lblWhite.setBounds(10, 11, 49, 14);
getContentPane().add(lblWhite);
JComboBox<Object> cbWhite = new JComboBox<>();
cbWhite.setModel(new DefaultComboBoxModel<Object>(options.toArray()));
cbWhite.setBounds(98, 9, 159, 22);
getContentPane().add(cbWhite);
JLabel lblBlack = new JLabel("Black:");
lblBlack.setFont(new Font("Tahoma", Font.PLAIN, 14));
lblBlack.setBounds(10, 38, 49, 14);
getContentPane().add(lblBlack);
JComboBox<Object> cbBlack = new JComboBox<>();
cbBlack.setModel(new DefaultComboBoxModel<Object>(options.toArray()));
cbBlack.setBounds(98, 36, 159, 22);
getContentPane().add(cbBlack);
JButton btnStart = new JButton("Start");
btnStart.addActionListener((evt) -> {
startGame = true;
whiteName = options.get(cbWhite.getSelectedIndex());
blackName = options.get(cbBlack.getSelectedIndex());
dispose();
});
btnStart.setBounds(20, 73, 89, 23);
getContentPane().add(btnStart);
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener((evt) -> dispose());
btnCancel.setBounds(157, 73, 89, 23);
getContentPane().add(btnCancel);
}
public String getWhiteName() { return whiteName; }
public String getBlackName() { return blackName; }
public boolean isStartGame() { return startGame; }
}

View File

@ -54,7 +54,7 @@ public class MainWindow {
* Initialize the contents of the frame. * Initialize the contents of the frame.
*/ */
private void initialize() { private void initialize() {
mframe = new JFrame(); mframe = new JFrame("Chess by Kai S. K. Engelbart");
mframe.setResizable(true); mframe.setResizable(true);
mframe.setBounds(100, 100, 494, 565); mframe.setBounds(100, 100, 494, 565);
mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@ -103,7 +103,7 @@ public class MainWindow {
if (this.game != null) if (this.game != null)
this.game.disconnect(); this.game.disconnect();
this.game = game; this.game = game;
btnSwapColors.setEnabled(!(game.getPlayers().get(Color.WHITE) instanceof NaturalPlayer btnSwapColors.setEnabled(game.getPlayers().get(Color.WHITE) instanceof NaturalPlayer
&& game.getPlayers().get(Color.BLACK) instanceof NaturalPlayer)); ^ game.getPlayers().get(Color.BLACK) instanceof NaturalPlayer);
} }
} }

View File

@ -35,45 +35,25 @@ public class MenuBar extends JMenuBar {
private void initGameMenu() { private void initGameMenu() {
JMenu gameMenu = new JMenu("Game"); JMenu gameMenu = new JMenu("Game");
JMenuItem newGameMenuItem = new JMenuItem("New Game");
JMenuItem naturalMenuItem = new JMenuItem("Game against natural opponent"); newGameMenuItem.addActionListener((evt) -> {
JMenuItem aiMenuItem = new JMenuItem("Game against artificial opponent"); GameConfigurationDialog dialog = new GameConfigurationDialog();
JMenuItem aiVsAiMenuItem = new JMenuItem("Watch AI vs. AI");
JMenuItem uciMenuItem = new JMenuItem("UCI");
naturalMenuItem.addActionListener((evt) -> startGame(Game.createNatural(boardPane)));
aiMenuItem.addActionListener((evt) -> {
AIConfigDialog dialog = new AIConfigDialog();
dialog.setVisible(true); dialog.setVisible(true);
if (dialog.isStartGame()) if (dialog.isStartGame()) startGame(new Game(boardPane, dialog.getWhiteName(), dialog.getBlackName()));
startGame(Game.createNaturalVsAI(boardPane, dialog.getMaxDepth(), dialog.getAlphaBetaThreshold()));
}); });
gameMenu.add(newGameMenuItem);
aiVsAiMenuItem.addActionListener((evt) -> startGame(Game.createAIVsAI(boardPane, 4, 3, -10, -10)));
uciMenuItem.addActionListener((evt) -> {
String enginePath = JOptionPane.showInputDialog(getParent(),
"Enter the path to a UCI-compatible chess engine:",
"Engine selection",
JOptionPane.QUESTION_MESSAGE);
if (enginePath != null) startGame(Game.createUCI(boardPane, enginePath));
});
gameMenu.add(naturalMenuItem);
gameMenu.add(aiMenuItem);
gameMenu.add(aiVsAiMenuItem);
gameMenu.add(uciMenuItem);
add(gameMenu); add(gameMenu);
// Start a game // Start a game
naturalMenuItem.doClick(); startGame(new Game(boardPane, "Natural Player", "Natural Player"));
} }
private void initEngineMenu() { private void initEngineMenu() {
JMenu engineMenu = new JMenu("Engine"); JMenu engineMenu = new JMenu("Engine");
// TODO: Adjust menu
JMenuItem addEngineMenuItem = new JMenuItem("Add engine"); JMenuItem addEngineMenuItem = new JMenuItem("Add engine");
addEngineMenuItem.addActionListener((evt) -> { addEngineMenuItem.addActionListener((evt) -> {
String enginePath = JOptionPane.showInputDialog(getParent(), String enginePath = JOptionPane.showInputDialog(getParent(),
@ -84,20 +64,25 @@ public class MenuBar extends JMenuBar {
EngineUtil.addEngine(enginePath, () -> { EngineUtil.addEngine(enginePath, () -> {
EngineInfo info = EngineUtil.getEngineInfos() EngineInfo info = EngineUtil.getEngineInfos()
.get(EngineUtil.getEngineInfos().size() - 1); .get(EngineUtil.getEngineInfos().size() - 1);
JMenuItem engineMenuItem = new JMenuItem(info.name); /*
engineMenuItem.addActionListener((evt2) -> startGame(Game.createUCI(boardPane, info.path))); * JMenuItem engineMenuItem = new JMenuItem(info.name);
engineMenu.add(engineMenuItem); * engineMenuItem.addActionListener((evt2) ->
* startGame(Game.createUCI(boardPane, info.path)));
* engineMenu.add(engineMenuItem);
*/
}); });
} }
}); });
engineMenu.add(addEngineMenuItem); engineMenu.add(addEngineMenuItem);
for (EngineInfo info : EngineUtil.getEngineInfos()) { /*
JMenuItem engineMenuItem = new JMenuItem(info.name); * for (EngineInfo info : EngineUtil.getEngineInfos()) {
engineMenuItem.addActionListener((evt) -> startGame(Game.createUCI(boardPane, info.path))); * JMenuItem engineMenuItem = new JMenuItem(info.name);
engineMenu.add(engineMenuItem); * engineMenuItem.addActionListener((evt) -> startGame(Game.createUCI(boardPane,
} * info.path)));
* engineMenu.add(engineMenuItem);
* }
*/
add(engineMenu); add(engineMenu);
} }