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.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();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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(); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user