From 51f3fd8980c4cac15fba86aae91debf6d5188fd8 Mon Sep 17 00:00:00 2001 From: delvh Date: Tue, 23 Jul 2019 10:38:19 +0200 Subject: [PATCH] Improved BoardOverlay, disabled color swap in natural-vs-natural game --- src/dev/kske/chess/game/Game.java | 49 +++++++++++---------- src/dev/kske/chess/ui/MainWindow.java | 14 +++--- src/dev/kske/chess/ui/MenuBar.java | 27 ++++++------ src/dev/kske/chess/ui/OverlayComponent.java | 42 ++++++++++++------ 4 files changed, 76 insertions(+), 56 deletions(-) diff --git a/src/dev/kske/chess/game/Game.java b/src/dev/kske/chess/game/Game.java index 095f17b..8bd4456 100644 --- a/src/dev/kske/chess/game/Game.java +++ b/src/dev/kske/chess/game/Game.java @@ -20,16 +20,16 @@ import dev.kske.chess.ui.OverlayComponent; */ public class Game { - private Map players; - private Board board; - private OverlayComponent overlayComponent; - private BoardComponent boardComponent; + private Map players; + private Board board; + private OverlayComponent overlayComponent; + private BoardComponent boardComponent; public Game(Map players, BoardPane boardPane) { - this.players = players; - this.overlayComponent = boardPane.getOverlayComponent(); - this.boardComponent = boardPane.getBoardComponent(); - this.board = new Board(); + this.players = players; + this.overlayComponent = boardPane.getOverlayComponent(); + this.boardComponent = boardPane.getBoardComponent(); + this.board = new Board(); boardComponent.setBoard(board); // Initialize the game variable in each player @@ -37,8 +37,8 @@ public class Game { } public static Game createNatural(BoardPane boardPane) { - Map players = new HashMap<>(); - OverlayComponent overlay = boardPane.getOverlayComponent(); + Map players = new HashMap<>(); + OverlayComponent overlay = boardPane.getOverlayComponent(); players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, 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) { - Map players = new HashMap<>(); - OverlayComponent overlay = boardPane.getOverlayComponent(); + Map 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)); @@ -76,18 +76,19 @@ public class Game { System.out.println("FEN: " + board.toFEN()); GameState eventType = board.getGameEventType(board.getDest(move).getColor().opposite()); switch (eventType) { - case CHECKMATE: - case STALEMATE: - System.out.printf("%s in %s!%n", player.color.opposite(), eventType); - break; - case CHECK: - System.out.printf("%s in check!%n", player.color.opposite()); - default: - boardComponent.repaint(); - players.get(board.getActiveColor()).requestMove(); + case CHECKMATE: + case STALEMATE: + System.out.printf("%s in %s!%n", player.color.opposite(), eventType); + break; + case CHECK: + System.out.printf("%s in check!%n", player.color.opposite()); + default: + boardComponent.repaint(); + players.get(board.getActiveColor()).requestMove(); } overlayComponent.displayArrow(move); - } else player.requestMove(); + } else + player.requestMove(); } public void start() { @@ -108,7 +109,7 @@ public class Game { public void disconnect() { players.values().forEach(Player::disconnect); } - + public void swapColors() { players.values().forEach(Player::cancelMove); Player white = players.get(Color.WHITE); @@ -121,4 +122,6 @@ public class Game { } public Board getBoard() { return board; } + + public Map getPlayers() { return players; } } diff --git a/src/dev/kske/chess/ui/MainWindow.java b/src/dev/kske/chess/ui/MainWindow.java index ea84de0..b103a47 100644 --- a/src/dev/kske/chess/ui/MainWindow.java +++ b/src/dev/kske/chess/ui/MainWindow.java @@ -10,6 +10,7 @@ import javax.swing.JPanel; import dev.kske.chess.board.Piece.Color; import dev.kske.chess.game.Game; +import dev.kske.chess.game.NaturalPlayer; /** * Project: Chess
@@ -20,6 +21,7 @@ import dev.kske.chess.game.Game; public class MainWindow { private JFrame mframe; + private JButton btnRestart, btnSwapColors; private BoardPane boardPane; private Game game; private Color activeColor; @@ -53,7 +55,7 @@ public class MainWindow { */ private void initialize() { mframe = new JFrame(); - mframe.setResizable(false); + mframe.setResizable(true); mframe.setBounds(100, 100, 494, 565); mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -62,12 +64,10 @@ public class MainWindow { boardPane = new BoardPane(); mframe.getContentPane().add(boardPane, BorderLayout.CENTER); - mframe.setJMenuBar(new MenuBar(this)); - JPanel toolPanel = new JPanel(); mframe.getContentPane().add(toolPanel, BorderLayout.NORTH); - JButton btnRestart = new JButton("Restart"); + btnRestart = new JButton("Restart"); btnRestart.addActionListener((evt) -> { if (game != null) game.reset(); @@ -75,7 +75,7 @@ public class MainWindow { }); activeColor = Color.WHITE; - JButton btnSwapColors = new JButton("Play as black"); + btnSwapColors = new JButton("Play as black"); btnSwapColors.addActionListener((evt) -> { game.swapColors(); btnSwapColors.setText("Play as " + activeColor.toString().toLowerCase()); @@ -85,6 +85,8 @@ public class MainWindow { toolPanel.add(btnRestart); toolPanel.add(btnSwapColors); + mframe.setJMenuBar(new MenuBar(this)); + mframe.pack(); mframe.setLocationRelativeTo(null); } @@ -101,5 +103,7 @@ public class MainWindow { if (this.game != null) this.game.disconnect(); this.game = game; + btnSwapColors.setEnabled(!(game.getPlayers().get(Color.WHITE) instanceof NaturalPlayer + && game.getPlayers().get(Color.BLACK) instanceof NaturalPlayer)); } } diff --git a/src/dev/kske/chess/ui/MenuBar.java b/src/dev/kske/chess/ui/MenuBar.java index fe2b806..d4c9564 100644 --- a/src/dev/kske/chess/ui/MenuBar.java +++ b/src/dev/kske/chess/ui/MenuBar.java @@ -17,12 +17,12 @@ public class MenuBar extends JMenuBar { private static final long serialVersionUID = -7221583703531248228L; - private final MainWindow mainWindow; - private final BoardPane boardPane; + private final MainWindow mainWindow; + private final BoardPane boardPane; public MenuBar(MainWindow mainWindow) { - this.mainWindow = mainWindow; - boardPane = mainWindow.getBoardPane(); + this.mainWindow = mainWindow; + boardPane = mainWindow.getBoardPane(); initGameMenu(); } @@ -30,11 +30,11 @@ public class MenuBar extends JMenuBar { private void initGameMenu() { JMenu gameMenu = new JMenu("Game"); - JMenuItem naturalMenuItem = new JMenuItem("Game against natural opponent"); - JMenuItem aiMenuItem = new JMenuItem("Game against artificial opponent"); - JMenuItem aiVsAiMenuItem = new JMenuItem("Watch AI vs. AI"); - JMenuItem uciMenuItem = new JMenuItem("UCI"); - + JMenuItem naturalMenuItem = new JMenuItem("Game against natural opponent"); + JMenuItem aiMenuItem = new JMenuItem("Game against artificial opponent"); + JMenuItem aiVsAiMenuItem = new JMenuItem("Watch AI vs. AI"); + JMenuItem uciMenuItem = new JMenuItem("UCI"); + naturalMenuItem.addActionListener((evt) -> startGame(Game.createNatural(boardPane))); aiMenuItem.addActionListener((evt) -> { @@ -48,17 +48,16 @@ public class MenuBar extends JMenuBar { uciMenuItem.addActionListener((evt) -> { String enginePath = JOptionPane.showInputDialog(getParent(), - "Enter the path to a UCI-compatible chess engine:", - "Engine selection", + "Enter the path to a UCI-compatible chess engine:", "Engine selection", JOptionPane.QUESTION_MESSAGE); - if (enginePath != null) startGame(Game.createUCI(boardPane, enginePath)); + if (enginePath != null) + startGame(Game.createUCI(boardPane, enginePath)); }); - + gameMenu.add(naturalMenuItem); gameMenu.add(aiMenuItem); gameMenu.add(aiVsAiMenuItem); gameMenu.add(uciMenuItem); - add(gameMenu); diff --git a/src/dev/kske/chess/ui/OverlayComponent.java b/src/dev/kske/chess/ui/OverlayComponent.java index 4cc8015..723f1af 100644 --- a/src/dev/kske/chess/ui/OverlayComponent.java +++ b/src/dev/kske/chess/ui/OverlayComponent.java @@ -1,5 +1,6 @@ package dev.kske.chess.ui; +import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; @@ -27,8 +28,8 @@ public class OverlayComponent extends JComponent { private final BoardPane boardPane; - private List dots; - private Move arrow; + private List dots; + private Move arrow; public OverlayComponent(BoardPane boardPane) { this.boardPane = boardPane; @@ -47,18 +48,29 @@ public class OverlayComponent extends JComponent { g.setColor(Color.green); int radius = tileSize / 4; for (Position dot : dots) - g.fillOval(dot.x * tileSize + tileSize / 2 - radius / 2, - dot.y * tileSize + tileSize / 2 - radius / 2, - radius, - radius); + g.fillOval(dot.x * tileSize + tileSize / 2 - radius / 2, dot.y * tileSize + tileSize / 2 - radius / 2, + radius, radius); } + // Draw an arrow representing the last move and mark its position and destination 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)); - 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) g).fill(createArrowShape(pos, dest)); + g2d.fill(arrowShape); + g2d.setColor(Color.black); + g2d.draw(arrowShape); } + } private Shape createArrowShape(Point pos, Point dest) { @@ -73,10 +85,10 @@ public class OverlayComponent extends JComponent { Point midPoint = midpoint(pos, dest); - double rotate = Math.atan2(dest.y - pos.y, dest.x - pos.x); - double ptDistance = pos.distance(dest); - double scale = ptDistance / 12.0; // 12 because it's the length of the arrow - // polygon. + double rotate = Math.atan2(dest.y - pos.y, dest.x - pos.x); + double ptDistance = pos.distance(dest); + double scale = ptDistance / 12.0; // 12 because it's the length of the arrow + // polygon. AffineTransform transform = new AffineTransform(); @@ -112,5 +124,7 @@ public class OverlayComponent extends JComponent { repaint(); } - public int getTileSize() { return boardPane.getTileSize(); } + public int getTileSize() { + return boardPane.getTileSize(); + } }