Simplified game creation, added new configuration dialog
This commit is contained in:
parent
4c0432ca30
commit
8bcd89d975
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,77 +24,61 @@ import dev.kske.chess.ui.OverlayComponent;
|
|||||||
*/
|
*/
|
||||||
public class Game {
|
public class Game {
|
||||||
|
|
||||||
private Map<Color, Player> players;
|
private Map<Color, Player> players;
|
||||||
private Board board;
|
private Board board;
|
||||||
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);
|
||||||
public static Game createNaturalVsAI(BoardPane boardPane, int maxDepth, int alphaBeta) {
|
System.err.println("Invalid player name: " + name);
|
||||||
Map<Color, Player> players = new HashMap<>();
|
return null;
|
||||||
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());
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case CHECKMATE:
|
case CHECKMATE:
|
||||||
case STALEMATE:
|
case STALEMATE:
|
||||||
String result = String.format("%s in %s!%n", player.color.opposite(), eventType);
|
String result = String.format("%s in %s!%n", player.color.opposite(), eventType);
|
||||||
System.out.print(result);
|
System.out.print(result);
|
||||||
JOptionPane.showMessageDialog(boardComponent, result);
|
JOptionPane.showMessageDialog(boardComponent, result);
|
||||||
break;
|
break;
|
||||||
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() {
|
||||||
@ -116,8 +102,8 @@ public class Game {
|
|||||||
|
|
||||||
public void swapColors() {
|
public void swapColors() {
|
||||||
players.values().forEach(Player::cancelMove);
|
players.values().forEach(Player::cancelMove);
|
||||||
Player white = players.get(Color.WHITE);
|
Player white = players.get(Color.WHITE);
|
||||||
Player black = players.get(Color.BLACK);
|
Player black = players.get(Color.BLACK);
|
||||||
white.setColor(Color.BLACK);
|
white.setColor(Color.BLACK);
|
||||||
black.setColor(Color.WHITE);
|
black.setColor(Color.WHITE);
|
||||||
players.put(Color.WHITE, black);
|
players.put(Color.WHITE, black);
|
||||||
|
@ -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; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
82
src/dev/kske/chess/ui/GameConfigurationDialog.java
Normal file
82
src/dev/kske/chess/ui/GameConfigurationDialog.java
Normal 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; }
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,46 +34,26 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user