Fixed UI bugs, added move drawing to OverlayComponent
This commit is contained in:
		@@ -7,6 +7,8 @@ import dev.kske.chess.board.GameState;
 | 
				
			|||||||
import dev.kske.chess.board.Move;
 | 
					import dev.kske.chess.board.Move;
 | 
				
			||||||
import dev.kske.chess.board.Piece.Color;
 | 
					import dev.kske.chess.board.Piece.Color;
 | 
				
			||||||
import dev.kske.chess.ui.BoardComponent;
 | 
					import dev.kske.chess.ui.BoardComponent;
 | 
				
			||||||
 | 
					import dev.kske.chess.ui.BoardPane;
 | 
				
			||||||
 | 
					import dev.kske.chess.ui.OverlayComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>Chess</strong><br>
 | 
					 * Project: <strong>Chess</strong><br>
 | 
				
			||||||
@@ -18,11 +20,13 @@ public class Game {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	private Map<Color, Player>	players;
 | 
						private Map<Color, Player>	players;
 | 
				
			||||||
	private Board				board;
 | 
						private Board				board;
 | 
				
			||||||
 | 
						private OverlayComponent	overlayComponent;
 | 
				
			||||||
	private BoardComponent		boardComponent;
 | 
						private BoardComponent		boardComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Game(Map<Color, Player> players, BoardComponent boardComponent) {
 | 
						public Game(Map<Color, Player> players, BoardPane boardPane) {
 | 
				
			||||||
		this.players		= players;
 | 
							this.players		= players;
 | 
				
			||||||
		this.boardComponent	= boardComponent;
 | 
							this.overlayComponent	= boardPane.getOverlayComponent();
 | 
				
			||||||
 | 
							this.boardComponent		= boardPane.getBoardComponent();
 | 
				
			||||||
		this.board			= boardComponent.getBoard();
 | 
							this.board			= boardComponent.getBoard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Initialize the game variable in each player
 | 
							// Initialize the game variable in each player
 | 
				
			||||||
@@ -42,6 +46,7 @@ public class Game {
 | 
				
			|||||||
					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();
 | 
				
			||||||
 | 
										overlayComponent.displayArrow(move);
 | 
				
			||||||
					players.get(player.color.opposite()).requestMove();
 | 
										players.get(player.color.opposite()).requestMove();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -56,6 +61,8 @@ public class Game {
 | 
				
			|||||||
		players.forEach((k, v) -> v.cancelMove());
 | 
							players.forEach((k, v) -> v.cancelMove());
 | 
				
			||||||
		board.initializeDefaultPositions();
 | 
							board.initializeDefaultPositions();
 | 
				
			||||||
		boardComponent.repaint();
 | 
							boardComponent.repaint();
 | 
				
			||||||
 | 
							overlayComponent.clearDots();
 | 
				
			||||||
 | 
							overlayComponent.clearArrow();
 | 
				
			||||||
		start();
 | 
							start();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,15 +27,15 @@ public class AIPlayer extends Player {
 | 
				
			|||||||
	private int	maxDepth;
 | 
						private int	maxDepth;
 | 
				
			||||||
	private int	alphaBetaThreshold;
 | 
						private int	alphaBetaThreshold;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private volatile boolean exitRequested;
 | 
						private volatile boolean			exitRequested;
 | 
				
			||||||
	private volatile ExecutorService	executor;
 | 
						private volatile ExecutorService	executor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public AIPlayer(Board board, Color color, int maxDepth, int alphaBetaThreshold) {
 | 
						public AIPlayer(Board board, Color color, int maxDepth, int alphaBetaThreshold) {
 | 
				
			||||||
		super(board, color);
 | 
							super(board, color);
 | 
				
			||||||
		availableProcessors	= Runtime.getRuntime().availableProcessors();
 | 
							availableProcessors		= Runtime.getRuntime().availableProcessors();
 | 
				
			||||||
		this.maxDepth		= maxDepth;
 | 
							this.maxDepth			= maxDepth;
 | 
				
			||||||
		this.alphaBetaThreshold	= alphaBetaThreshold;
 | 
							this.alphaBetaThreshold	= alphaBetaThreshold;
 | 
				
			||||||
		exitRequested		= false;
 | 
							exitRequested			= false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
@@ -63,9 +63,8 @@ public class AIPlayer extends Player {
 | 
				
			|||||||
			for (int i = 0; i < numThreads; i++) {
 | 
								for (int i = 0; i < numThreads; i++) {
 | 
				
			||||||
				if (rem-- > 0) ++endIndex;
 | 
									if (rem-- > 0) ++endIndex;
 | 
				
			||||||
				endIndex += step;
 | 
									endIndex += step;
 | 
				
			||||||
				processors.add(
 | 
									processors.add(new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color,
 | 
				
			||||||
						new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color, maxDepth,
 | 
											maxDepth, alphaBetaThreshold));
 | 
				
			||||||
								alphaBetaThreshold));
 | 
					 | 
				
			||||||
				beginIndex = endIndex;
 | 
									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
 | 
								 * Execute processors, get the best result and pass it back to the Game class
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			executor = Executors.newFixedThreadPool(numThreads);
 | 
								executor = Executors.newFixedThreadPool(numThreads);
 | 
				
			||||||
			List<ProcessingResult>	results		= new ArrayList<>(numThreads);
 | 
								List<ProcessingResult> results = new ArrayList<>(numThreads);
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				List<Future<ProcessingResult>> futures = executor.invokeAll(processors);
 | 
									List<Future<ProcessingResult>> futures = executor.invokeAll(processors);
 | 
				
			||||||
				for (Future<ProcessingResult> f : futures)
 | 
									for (Future<ProcessingResult> f : futures)
 | 
				
			||||||
@@ -90,11 +89,13 @@ public class AIPlayer extends Player {
 | 
				
			|||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public void cancelMove() {
 | 
						public void cancelMove() {
 | 
				
			||||||
		exitRequested = true;
 | 
							exitRequested = true;
 | 
				
			||||||
		executor.shutdownNow();
 | 
							if (executor != null) {
 | 
				
			||||||
		try {
 | 
								executor.shutdownNow();
 | 
				
			||||||
			executor.awaitTermination(500, TimeUnit.MILLISECONDS);
 | 
								try {
 | 
				
			||||||
		} catch (InterruptedException e) {
 | 
									executor.awaitTermination(500, TimeUnit.MILLISECONDS);
 | 
				
			||||||
			e.printStackTrace();
 | 
								} catch (InterruptedException e) {
 | 
				
			||||||
 | 
									e.printStackTrace();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,24 +23,24 @@ public class AIConfigDialog extends JDialog {
 | 
				
			|||||||
	private boolean	startGame	= false;
 | 
						private boolean	startGame	= false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public AIConfigDialog() {
 | 
						public AIConfigDialog() {
 | 
				
			||||||
		setSize(new Dimension(293, 212));
 | 
							setSize(new Dimension(337, 212));
 | 
				
			||||||
		setModal(true);
 | 
							setModal(true);
 | 
				
			||||||
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 | 
							setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 | 
				
			||||||
		setTitle("AI Configuration");
 | 
							setTitle("AI Configuration");
 | 
				
			||||||
		getContentPane().setLayout(null);
 | 
							getContentPane().setLayout(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JSpinner spAlphaBetaThreshold = new JSpinner();
 | 
							JSpinner spAlphaBetaThreshold = new JSpinner();
 | 
				
			||||||
		spAlphaBetaThreshold.setBounds(170, 0, 95, 28);
 | 
							spAlphaBetaThreshold.setBounds(222, 68, 95, 28);
 | 
				
			||||||
		getContentPane().add(spAlphaBetaThreshold);
 | 
							getContentPane().add(spAlphaBetaThreshold);
 | 
				
			||||||
		spAlphaBetaThreshold.setModel(new SpinnerNumberModel(-10, -100, 100, 5));
 | 
							spAlphaBetaThreshold.setModel(new SpinnerNumberModel(-10, -100, 100, 5));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JSpinner spMaxDepth = new JSpinner();
 | 
							JSpinner spMaxDepth = new JSpinner();
 | 
				
			||||||
		spMaxDepth.setBounds(170, 68, 95, 28);
 | 
							spMaxDepth.setBounds(222, 6, 95, 28);
 | 
				
			||||||
		getContentPane().add(spMaxDepth);
 | 
							getContentPane().add(spMaxDepth);
 | 
				
			||||||
		spMaxDepth.setModel(new SpinnerNumberModel(4, 1, 10, 1));
 | 
							spMaxDepth.setModel(new SpinnerNumberModel(4, 1, 10, 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JLabel lblAlphabetaThreshold = new JLabel("Alpha-Beta Threshold:");
 | 
							JLabel lblAlphabetaThreshold = new JLabel("Alpha-Beta Threshold:");
 | 
				
			||||||
		lblAlphabetaThreshold.setBounds(16, 68, 119, 28);
 | 
							lblAlphabetaThreshold.setBounds(16, 68, 194, 28);
 | 
				
			||||||
		getContentPane().add(lblAlphabetaThreshold);
 | 
							getContentPane().add(lblAlphabetaThreshold);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JButton btnOk = new JButton("OK");
 | 
							JButton btnOk = new JButton("OK");
 | 
				
			||||||
@@ -55,13 +55,13 @@ public class AIConfigDialog extends JDialog {
 | 
				
			|||||||
		btnOk.setToolTipText("Start the game");
 | 
							btnOk.setToolTipText("Start the game");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JButton btnCancel = new JButton("Cancel");
 | 
							JButton btnCancel = new JButton("Cancel");
 | 
				
			||||||
		btnCancel.setBounds(170, 137, 95, 28);
 | 
							btnCancel.setBounds(222, 137, 95, 28);
 | 
				
			||||||
		getContentPane().add(btnCancel);
 | 
							getContentPane().add(btnCancel);
 | 
				
			||||||
		btnCancel.addActionListener((evt) -> dispose());
 | 
							btnCancel.addActionListener((evt) -> dispose());
 | 
				
			||||||
		btnCancel.setToolTipText("Cancel the game start");
 | 
							btnCancel.setToolTipText("Cancel the game start");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JLabel lblMaximalRecursionDepth = new JLabel("Maximal Recursion Depth:");
 | 
							JLabel lblMaximalRecursionDepth = new JLabel("Maximal Recursion Depth:");
 | 
				
			||||||
		lblMaximalRecursionDepth.setBounds(16, 6, 141, 16);
 | 
							lblMaximalRecursionDepth.setBounds(16, 12, 194, 16);
 | 
				
			||||||
		getContentPane().add(lblMaximalRecursionDepth);
 | 
							getContentPane().add(lblMaximalRecursionDepth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		setLocationRelativeTo(null);
 | 
							setLocationRelativeTo(null);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ 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 OverlayComponent		overlayComponent;
 | 
						private final OverlayComponent		overlayComponent;
 | 
				
			||||||
	private final BoardComponent		boardComponent;
 | 
						private final BoardComponent		boardComponent;
 | 
				
			||||||
	private final Board					board;
 | 
						private final Board					board;
 | 
				
			||||||
@@ -32,8 +33,9 @@ public class MenuBar extends JMenuBar {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public MenuBar(MainWindow mainWindow) {
 | 
						public MenuBar(MainWindow mainWindow) {
 | 
				
			||||||
		this.mainWindow		= mainWindow;
 | 
							this.mainWindow		= mainWindow;
 | 
				
			||||||
		overlayComponent	= mainWindow.getBoardPane().getOverlayComponent();
 | 
							boardPane			= mainWindow.getBoardPane();
 | 
				
			||||||
		boardComponent		= mainWindow.getBoardPane().getBoardComponent();
 | 
							overlayComponent	= boardPane.getOverlayComponent();
 | 
				
			||||||
 | 
							boardComponent		= boardPane.getBoardComponent();
 | 
				
			||||||
		board				= boardComponent.getBoard();
 | 
							board				= boardComponent.getBoard();
 | 
				
			||||||
		players				= new HashMap<>();
 | 
							players				= new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,7 +80,8 @@ public class MenuBar extends JMenuBar {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void startGame() {
 | 
						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);
 | 
							mainWindow.setGame(game);
 | 
				
			||||||
		game.start();
 | 
							game.start();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,17 @@ package dev.kske.chess.ui;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.awt.Color;
 | 
					import java.awt.Color;
 | 
				
			||||||
import java.awt.Graphics;
 | 
					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.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.JComponent;
 | 
					import javax.swing.JComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.kske.chess.board.Move;
 | 
				
			||||||
import dev.kske.chess.board.Position;
 | 
					import dev.kske.chess.board.Position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -22,11 +28,12 @@ public class OverlayComponent extends JComponent {
 | 
				
			|||||||
	private final BoardPane boardPane;
 | 
						private final BoardPane boardPane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private List<Position>	dots;
 | 
						private List<Position>	dots;
 | 
				
			||||||
 | 
						private Move			arrow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public OverlayComponent(BoardPane boardPane) {
 | 
						public OverlayComponent(BoardPane boardPane) {
 | 
				
			||||||
		this.boardPane = boardPane;
 | 
							this.boardPane = boardPane;
 | 
				
			||||||
		setSize(boardPane.getPreferredSize());
 | 
							setSize(boardPane.getPreferredSize());
 | 
				
			||||||
		dots			= new ArrayList<>();
 | 
							dots = new ArrayList<>();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
@@ -34,7 +41,7 @@ public class OverlayComponent extends JComponent {
 | 
				
			|||||||
		super.paintComponent(g);
 | 
							super.paintComponent(g);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		final int tileSize = getTileSize();
 | 
							final int tileSize = getTileSize();
 | 
				
			||||||
		
 | 
					
 | 
				
			||||||
		// Draw possible moves if a piece was selected
 | 
							// Draw possible moves if a piece was selected
 | 
				
			||||||
		if (!dots.isEmpty()) {
 | 
							if (!dots.isEmpty()) {
 | 
				
			||||||
			g.setColor(Color.green);
 | 
								g.setColor(Color.green);
 | 
				
			||||||
@@ -45,6 +52,43 @@ public class OverlayComponent extends JComponent {
 | 
				
			|||||||
						radius,
 | 
											radius,
 | 
				
			||||||
						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) {
 | 
						public void displayDots(List<Position> dots) {
 | 
				
			||||||
@@ -58,5 +102,15 @@ public class OverlayComponent extends JComponent {
 | 
				
			|||||||
		repaint();
 | 
							repaint();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void displayArrow(Move arrow) {
 | 
				
			||||||
 | 
							this.arrow = arrow;
 | 
				
			||||||
 | 
							repaint();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void clearArrow() {
 | 
				
			||||||
 | 
							arrow = null;
 | 
				
			||||||
 | 
							repaint();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public int getTileSize() { return boardPane.getTileSize(); }
 | 
						public int getTileSize() { return boardPane.getTileSize(); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user