Fixed UI bugs, added move drawing to OverlayComponent

This commit is contained in:
Kai S. K. Engelbart 2019-07-16 15:32:02 +02:00
parent 8ea0c7a603
commit cde7f63996
5 changed files with 91 additions and 26 deletions

View File

@ -7,6 +7,8 @@ import dev.kske.chess.board.GameState;
import dev.kske.chess.board.Move;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.ui.BoardComponent;
import dev.kske.chess.ui.BoardPane;
import dev.kske.chess.ui.OverlayComponent;
/**
* Project: <strong>Chess</strong><br>
@ -18,11 +20,13 @@ public class Game {
private Map<Color, Player> players;
private Board board;
private OverlayComponent overlayComponent;
private BoardComponent boardComponent;
public Game(Map<Color, Player> players, BoardComponent boardComponent) {
public Game(Map<Color, Player> players, BoardPane boardPane) {
this.players = players;
this.boardComponent = boardComponent;
this.overlayComponent = boardPane.getOverlayComponent();
this.boardComponent = boardPane.getBoardComponent();
this.board = boardComponent.getBoard();
// Initialize the game variable in each player
@ -42,6 +46,7 @@ public class Game {
System.out.printf("%s in check!%n", player.color.opposite());
default:
boardComponent.repaint();
overlayComponent.displayArrow(move);
players.get(player.color.opposite()).requestMove();
}
@ -56,6 +61,8 @@ public class Game {
players.forEach((k, v) -> v.cancelMove());
board.initializeDefaultPositions();
boardComponent.repaint();
overlayComponent.clearDots();
overlayComponent.clearArrow();
start();
}
}

View File

@ -27,15 +27,15 @@ public class AIPlayer extends Player {
private int maxDepth;
private int alphaBetaThreshold;
private volatile boolean exitRequested;
private volatile boolean exitRequested;
private volatile ExecutorService executor;
public AIPlayer(Board board, Color color, int maxDepth, int alphaBetaThreshold) {
super(board, color);
availableProcessors = Runtime.getRuntime().availableProcessors();
this.maxDepth = maxDepth;
availableProcessors = Runtime.getRuntime().availableProcessors();
this.maxDepth = maxDepth;
this.alphaBetaThreshold = alphaBetaThreshold;
exitRequested = false;
exitRequested = false;
}
@Override
@ -63,9 +63,8 @@ public class AIPlayer extends Player {
for (int i = 0; i < numThreads; i++) {
if (rem-- > 0) ++endIndex;
endIndex += step;
processors.add(
new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color, maxDepth,
alphaBetaThreshold));
processors.add(new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color,
maxDepth, alphaBetaThreshold));
beginIndex = endIndex;
}
@ -73,7 +72,7 @@ public class AIPlayer extends Player {
* Execute processors, get the best result and pass it back to the Game class
*/
executor = Executors.newFixedThreadPool(numThreads);
List<ProcessingResult> results = new ArrayList<>(numThreads);
List<ProcessingResult> results = new ArrayList<>(numThreads);
try {
List<Future<ProcessingResult>> futures = executor.invokeAll(processors);
for (Future<ProcessingResult> f : futures)
@ -90,11 +89,13 @@ public class AIPlayer extends Player {
@Override
public void cancelMove() {
exitRequested = true;
executor.shutdownNow();
try {
executor.awaitTermination(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
if (executor != null) {
executor.shutdownNow();
try {
executor.awaitTermination(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

View File

@ -23,24 +23,24 @@ public class AIConfigDialog extends JDialog {
private boolean startGame = false;
public AIConfigDialog() {
setSize(new Dimension(293, 212));
setSize(new Dimension(337, 212));
setModal(true);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setTitle("AI Configuration");
getContentPane().setLayout(null);
JSpinner spAlphaBetaThreshold = new JSpinner();
spAlphaBetaThreshold.setBounds(170, 0, 95, 28);
spAlphaBetaThreshold.setBounds(222, 68, 95, 28);
getContentPane().add(spAlphaBetaThreshold);
spAlphaBetaThreshold.setModel(new SpinnerNumberModel(-10, -100, 100, 5));
JSpinner spMaxDepth = new JSpinner();
spMaxDepth.setBounds(170, 68, 95, 28);
spMaxDepth.setBounds(222, 6, 95, 28);
getContentPane().add(spMaxDepth);
spMaxDepth.setModel(new SpinnerNumberModel(4, 1, 10, 1));
JLabel lblAlphabetaThreshold = new JLabel("Alpha-Beta Threshold:");
lblAlphabetaThreshold.setBounds(16, 68, 119, 28);
lblAlphabetaThreshold.setBounds(16, 68, 194, 28);
getContentPane().add(lblAlphabetaThreshold);
JButton btnOk = new JButton("OK");
@ -55,13 +55,13 @@ public class AIConfigDialog extends JDialog {
btnOk.setToolTipText("Start the game");
JButton btnCancel = new JButton("Cancel");
btnCancel.setBounds(170, 137, 95, 28);
btnCancel.setBounds(222, 137, 95, 28);
getContentPane().add(btnCancel);
btnCancel.addActionListener((evt) -> dispose());
btnCancel.setToolTipText("Cancel the game start");
JLabel lblMaximalRecursionDepth = new JLabel("Maximal Recursion Depth:");
lblMaximalRecursionDepth.setBounds(16, 6, 141, 16);
lblMaximalRecursionDepth.setBounds(16, 12, 194, 16);
getContentPane().add(lblMaximalRecursionDepth);
setLocationRelativeTo(null);

View File

@ -25,6 +25,7 @@ public class MenuBar extends JMenuBar {
private static final long serialVersionUID = -7221583703531248228L;
private final MainWindow mainWindow;
private final BoardPane boardPane;
private final OverlayComponent overlayComponent;
private final BoardComponent boardComponent;
private final Board board;
@ -32,8 +33,9 @@ public class MenuBar extends JMenuBar {
public MenuBar(MainWindow mainWindow) {
this.mainWindow = mainWindow;
overlayComponent = mainWindow.getBoardPane().getOverlayComponent();
boardComponent = mainWindow.getBoardPane().getBoardComponent();
boardPane = mainWindow.getBoardPane();
overlayComponent = boardPane.getOverlayComponent();
boardComponent = boardPane.getBoardComponent();
board = boardComponent.getBoard();
players = new HashMap<>();
@ -78,7 +80,8 @@ public class MenuBar extends JMenuBar {
}
private void startGame() {
Game game = new Game(players, boardComponent);
// TODO: Re-init board and overlay component
Game game = new Game(players, boardPane);
mainWindow.setGame(game);
game.start();
}

View File

@ -2,11 +2,17 @@ package dev.kske.chess.ui;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import dev.kske.chess.board.Move;
import dev.kske.chess.board.Position;
/**
@ -22,11 +28,12 @@ public class OverlayComponent extends JComponent {
private final BoardPane boardPane;
private List<Position> dots;
private Move arrow;
public OverlayComponent(BoardPane boardPane) {
this.boardPane = boardPane;
setSize(boardPane.getPreferredSize());
dots = new ArrayList<>();
dots = new ArrayList<>();
}
@Override
@ -34,7 +41,7 @@ public class OverlayComponent extends JComponent {
super.paintComponent(g);
final int tileSize = getTileSize();
// Draw possible moves if a piece was selected
if (!dots.isEmpty()) {
g.setColor(Color.green);
@ -45,6 +52,43 @@ public class OverlayComponent extends JComponent {
radius,
radius);
}
if (arrow != null) {
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));
}
}
private Shape createArrowShape(Point pos, Point dest) {
Polygon arrowPolygon = new Polygon();
arrowPolygon.addPoint(-6, 1);
arrowPolygon.addPoint(3, 1);
arrowPolygon.addPoint(3, 3);
arrowPolygon.addPoint(6, 0);
arrowPolygon.addPoint(3, -3);
arrowPolygon.addPoint(3, -1);
arrowPolygon.addPoint(-6, -1);
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.
AffineTransform transform = new AffineTransform();
transform.translate(midPoint.x, midPoint.y);
transform.rotate(rotate);
transform.scale(scale, 5);
return transform.createTransformedShape(arrowPolygon);
}
private Point midpoint(Point p1, Point p2) {
return new Point((int) ((p1.x + p2.x) / 2.0), (int) ((p1.y + p2.y) / 2.0));
}
public void displayDots(List<Position> dots) {
@ -58,5 +102,15 @@ public class OverlayComponent extends JComponent {
repaint();
}
public void displayArrow(Move arrow) {
this.arrow = arrow;
repaint();
}
public void clearArrow() {
arrow = null;
repaint();
}
public int getTileSize() { return boardPane.getTileSize(); }
}