Improved BoardOverlay, disabled color swap in natural-vs-natural game
This commit is contained in:
parent
0e75aae421
commit
4e008954ad
@ -20,16 +20,16 @@ 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(Map<Color, Player> players, BoardPane boardPane) {
|
||||||
this.players = players;
|
this.players = players;
|
||||||
this.overlayComponent = boardPane.getOverlayComponent();
|
this.overlayComponent = boardPane.getOverlayComponent();
|
||||||
this.boardComponent = boardPane.getBoardComponent();
|
this.boardComponent = boardPane.getBoardComponent();
|
||||||
this.board = new Board();
|
this.board = new Board();
|
||||||
boardComponent.setBoard(board);
|
boardComponent.setBoard(board);
|
||||||
|
|
||||||
// Initialize the game variable in each player
|
// Initialize the game variable in each player
|
||||||
@ -37,8 +37,8 @@ public class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Game createNatural(BoardPane boardPane) {
|
public static Game createNatural(BoardPane boardPane) {
|
||||||
Map<Color, Player> players = new HashMap<>();
|
Map<Color, Player> players = new HashMap<>();
|
||||||
OverlayComponent overlay = boardPane.getOverlayComponent();
|
OverlayComponent overlay = boardPane.getOverlayComponent();
|
||||||
|
|
||||||
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, overlay));
|
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, overlay));
|
||||||
players.put(Color.BLACK, new NaturalPlayer(Color.BLACK, overlay));
|
players.put(Color.BLACK, new NaturalPlayer(Color.BLACK, overlay));
|
||||||
@ -46,8 +46,8 @@ public class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Game createNaturalVsAI(BoardPane boardPane, int maxDepth, int alphaBeta) {
|
public static Game createNaturalVsAI(BoardPane boardPane, int maxDepth, int alphaBeta) {
|
||||||
Map<Color, Player> players = new HashMap<>();
|
Map<Color, Player> players = new HashMap<>();
|
||||||
OverlayComponent overlay = boardPane.getOverlayComponent();
|
OverlayComponent overlay = boardPane.getOverlayComponent();
|
||||||
|
|
||||||
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, overlay));
|
players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, overlay));
|
||||||
players.put(Color.BLACK, new AIPlayer(Color.BLACK, maxDepth, alphaBeta));
|
players.put(Color.BLACK, new AIPlayer(Color.BLACK, maxDepth, alphaBeta));
|
||||||
@ -76,18 +76,19 @@ public class Game {
|
|||||||
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:
|
||||||
System.out.printf("%s in %s!%n", player.color.opposite(), eventType);
|
System.out.printf("%s in %s!%n", player.color.opposite(), eventType);
|
||||||
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();
|
boardComponent.repaint();
|
||||||
players.get(board.getActiveColor()).requestMove();
|
players.get(board.getActiveColor()).requestMove();
|
||||||
}
|
}
|
||||||
overlayComponent.displayArrow(move);
|
overlayComponent.displayArrow(move);
|
||||||
} else player.requestMove();
|
} else
|
||||||
|
player.requestMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
@ -108,7 +109,7 @@ public class Game {
|
|||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
players.values().forEach(Player::disconnect);
|
players.values().forEach(Player::disconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -121,4 +122,6 @@ public class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Board getBoard() { return board; }
|
public Board getBoard() { return board; }
|
||||||
|
|
||||||
|
public Map<Color, Player> getPlayers() { return players; }
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import javax.swing.JPanel;
|
|||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.game.Game;
|
import dev.kske.chess.game.Game;
|
||||||
|
import dev.kske.chess.game.NaturalPlayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -20,6 +21,7 @@ import dev.kske.chess.game.Game;
|
|||||||
public class MainWindow {
|
public class MainWindow {
|
||||||
|
|
||||||
private JFrame mframe;
|
private JFrame mframe;
|
||||||
|
private JButton btnRestart, btnSwapColors;
|
||||||
private BoardPane boardPane;
|
private BoardPane boardPane;
|
||||||
private Game game;
|
private Game game;
|
||||||
private Color activeColor;
|
private Color activeColor;
|
||||||
@ -53,7 +55,7 @@ public class MainWindow {
|
|||||||
*/
|
*/
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
mframe = new JFrame();
|
mframe = new JFrame();
|
||||||
mframe.setResizable(false);
|
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);
|
||||||
|
|
||||||
@ -62,12 +64,10 @@ public class MainWindow {
|
|||||||
boardPane = new BoardPane();
|
boardPane = new BoardPane();
|
||||||
mframe.getContentPane().add(boardPane, BorderLayout.CENTER);
|
mframe.getContentPane().add(boardPane, BorderLayout.CENTER);
|
||||||
|
|
||||||
mframe.setJMenuBar(new MenuBar(this));
|
|
||||||
|
|
||||||
JPanel toolPanel = new JPanel();
|
JPanel toolPanel = new JPanel();
|
||||||
mframe.getContentPane().add(toolPanel, BorderLayout.NORTH);
|
mframe.getContentPane().add(toolPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
JButton btnRestart = new JButton("Restart");
|
btnRestart = new JButton("Restart");
|
||||||
btnRestart.addActionListener((evt) -> {
|
btnRestart.addActionListener((evt) -> {
|
||||||
if (game != null)
|
if (game != null)
|
||||||
game.reset();
|
game.reset();
|
||||||
@ -75,7 +75,7 @@ public class MainWindow {
|
|||||||
});
|
});
|
||||||
|
|
||||||
activeColor = Color.WHITE;
|
activeColor = Color.WHITE;
|
||||||
JButton btnSwapColors = new JButton("Play as black");
|
btnSwapColors = new JButton("Play as black");
|
||||||
btnSwapColors.addActionListener((evt) -> {
|
btnSwapColors.addActionListener((evt) -> {
|
||||||
game.swapColors();
|
game.swapColors();
|
||||||
btnSwapColors.setText("Play as " + activeColor.toString().toLowerCase());
|
btnSwapColors.setText("Play as " + activeColor.toString().toLowerCase());
|
||||||
@ -85,6 +85,8 @@ public class MainWindow {
|
|||||||
toolPanel.add(btnRestart);
|
toolPanel.add(btnRestart);
|
||||||
toolPanel.add(btnSwapColors);
|
toolPanel.add(btnSwapColors);
|
||||||
|
|
||||||
|
mframe.setJMenuBar(new MenuBar(this));
|
||||||
|
|
||||||
mframe.pack();
|
mframe.pack();
|
||||||
mframe.setLocationRelativeTo(null);
|
mframe.setLocationRelativeTo(null);
|
||||||
}
|
}
|
||||||
@ -101,5 +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
|
||||||
|
&& game.getPlayers().get(Color.BLACK) instanceof NaturalPlayer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,12 @@ public class MenuBar extends JMenuBar {
|
|||||||
|
|
||||||
private static final long serialVersionUID = -7221583703531248228L;
|
private static final long serialVersionUID = -7221583703531248228L;
|
||||||
|
|
||||||
private final MainWindow mainWindow;
|
private final MainWindow mainWindow;
|
||||||
private final BoardPane boardPane;
|
private final BoardPane boardPane;
|
||||||
|
|
||||||
public MenuBar(MainWindow mainWindow) {
|
public MenuBar(MainWindow mainWindow) {
|
||||||
this.mainWindow = mainWindow;
|
this.mainWindow = mainWindow;
|
||||||
boardPane = mainWindow.getBoardPane();
|
boardPane = mainWindow.getBoardPane();
|
||||||
|
|
||||||
initGameMenu();
|
initGameMenu();
|
||||||
}
|
}
|
||||||
@ -30,11 +30,11 @@ public class MenuBar extends JMenuBar {
|
|||||||
private void initGameMenu() {
|
private void initGameMenu() {
|
||||||
JMenu gameMenu = new JMenu("Game");
|
JMenu gameMenu = new JMenu("Game");
|
||||||
|
|
||||||
JMenuItem naturalMenuItem = new JMenuItem("Game against natural opponent");
|
JMenuItem naturalMenuItem = new JMenuItem("Game against natural opponent");
|
||||||
JMenuItem aiMenuItem = new JMenuItem("Game against artificial opponent");
|
JMenuItem aiMenuItem = new JMenuItem("Game against artificial opponent");
|
||||||
JMenuItem aiVsAiMenuItem = new JMenuItem("Watch AI vs. AI");
|
JMenuItem aiVsAiMenuItem = new JMenuItem("Watch AI vs. AI");
|
||||||
JMenuItem uciMenuItem = new JMenuItem("UCI");
|
JMenuItem uciMenuItem = new JMenuItem("UCI");
|
||||||
|
|
||||||
naturalMenuItem.addActionListener((evt) -> startGame(Game.createNatural(boardPane)));
|
naturalMenuItem.addActionListener((evt) -> startGame(Game.createNatural(boardPane)));
|
||||||
|
|
||||||
aiMenuItem.addActionListener((evt) -> {
|
aiMenuItem.addActionListener((evt) -> {
|
||||||
@ -48,17 +48,16 @@ public class MenuBar extends JMenuBar {
|
|||||||
|
|
||||||
uciMenuItem.addActionListener((evt) -> {
|
uciMenuItem.addActionListener((evt) -> {
|
||||||
String enginePath = JOptionPane.showInputDialog(getParent(),
|
String enginePath = JOptionPane.showInputDialog(getParent(),
|
||||||
"Enter the path to a UCI-compatible chess engine:",
|
"Enter the path to a UCI-compatible chess engine:", "Engine selection",
|
||||||
"Engine selection",
|
|
||||||
JOptionPane.QUESTION_MESSAGE);
|
JOptionPane.QUESTION_MESSAGE);
|
||||||
if (enginePath != null) startGame(Game.createUCI(boardPane, enginePath));
|
if (enginePath != null)
|
||||||
|
startGame(Game.createUCI(boardPane, enginePath));
|
||||||
});
|
});
|
||||||
|
|
||||||
gameMenu.add(naturalMenuItem);
|
gameMenu.add(naturalMenuItem);
|
||||||
gameMenu.add(aiMenuItem);
|
gameMenu.add(aiMenuItem);
|
||||||
gameMenu.add(aiVsAiMenuItem);
|
gameMenu.add(aiVsAiMenuItem);
|
||||||
gameMenu.add(uciMenuItem);
|
gameMenu.add(uciMenuItem);
|
||||||
|
|
||||||
|
|
||||||
add(gameMenu);
|
add(gameMenu);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dev.kske.chess.ui;
|
package dev.kske.chess.ui;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
@ -27,8 +28,8 @@ public class OverlayComponent extends JComponent {
|
|||||||
|
|
||||||
private final BoardPane boardPane;
|
private final BoardPane boardPane;
|
||||||
|
|
||||||
private List<Position> dots;
|
private List<Position> dots;
|
||||||
private Move arrow;
|
private Move arrow;
|
||||||
|
|
||||||
public OverlayComponent(BoardPane boardPane) {
|
public OverlayComponent(BoardPane boardPane) {
|
||||||
this.boardPane = boardPane;
|
this.boardPane = boardPane;
|
||||||
@ -47,18 +48,29 @@ public class OverlayComponent extends JComponent {
|
|||||||
g.setColor(Color.green);
|
g.setColor(Color.green);
|
||||||
int radius = tileSize / 4;
|
int radius = tileSize / 4;
|
||||||
for (Position dot : dots)
|
for (Position dot : dots)
|
||||||
g.fillOval(dot.x * tileSize + tileSize / 2 - radius / 2,
|
g.fillOval(dot.x * tileSize + tileSize / 2 - radius / 2, dot.y * tileSize + tileSize / 2 - radius / 2,
|
||||||
dot.y * tileSize + tileSize / 2 - radius / 2,
|
radius, radius);
|
||||||
radius,
|
|
||||||
radius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw an arrow representing the last move and mark its position and destination
|
||||||
if (arrow != null) {
|
if (arrow != null) {
|
||||||
|
Point pos = new Point(arrow.pos.x * tileSize + tileSize / 2, arrow.pos.y * tileSize + tileSize / 2);
|
||||||
|
Point dest = new Point(arrow.dest.x * tileSize + tileSize / 2, arrow.dest.y * tileSize + tileSize / 2);
|
||||||
|
|
||||||
|
Graphics2D g2d = (Graphics2D) g;
|
||||||
|
g2d.setStroke(new BasicStroke(3));
|
||||||
|
|
||||||
|
g2d.setColor(Color.yellow);
|
||||||
|
g2d.drawRect(arrow.pos.x * tileSize, arrow.pos.y * tileSize, tileSize, tileSize);
|
||||||
|
g2d.drawRect(arrow.dest.x * tileSize, arrow.dest.y * tileSize, tileSize, tileSize);
|
||||||
|
|
||||||
|
Shape arrowShape = createArrowShape(pos, dest);
|
||||||
g.setColor(new Color(255, 0, 0, 127));
|
g.setColor(new Color(255, 0, 0, 127));
|
||||||
Point pos = new Point(arrow.pos.x * tileSize + tileSize / 2, arrow.pos.y * tileSize + tileSize / 2);
|
g2d.fill(arrowShape);
|
||||||
Point dest = new Point(arrow.dest.x * tileSize + tileSize / 2, arrow.dest.y * tileSize + tileSize / 2);
|
g2d.setColor(Color.black);
|
||||||
((Graphics2D) g).fill(createArrowShape(pos, dest));
|
g2d.draw(arrowShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Shape createArrowShape(Point pos, Point dest) {
|
private Shape createArrowShape(Point pos, Point dest) {
|
||||||
@ -73,10 +85,10 @@ public class OverlayComponent extends JComponent {
|
|||||||
|
|
||||||
Point midPoint = midpoint(pos, dest);
|
Point midPoint = midpoint(pos, dest);
|
||||||
|
|
||||||
double rotate = Math.atan2(dest.y - pos.y, dest.x - pos.x);
|
double rotate = Math.atan2(dest.y - pos.y, dest.x - pos.x);
|
||||||
double ptDistance = pos.distance(dest);
|
double ptDistance = pos.distance(dest);
|
||||||
double scale = ptDistance / 12.0; // 12 because it's the length of the arrow
|
double scale = ptDistance / 12.0; // 12 because it's the length of the arrow
|
||||||
// polygon.
|
// polygon.
|
||||||
|
|
||||||
AffineTransform transform = new AffineTransform();
|
AffineTransform transform = new AffineTransform();
|
||||||
|
|
||||||
@ -112,5 +124,7 @@ public class OverlayComponent extends JComponent {
|
|||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTileSize() { return boardPane.getTileSize(); }
|
public int getTileSize() {
|
||||||
|
return boardPane.getTileSize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user