Added pawn promotion #11
@@ -1,6 +1,5 @@
 | 
			
		||||
package dev.kske.chess.board;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
@@ -143,8 +142,7 @@ public class Board {
 | 
			
		||||
						if (m.group("promotedTo") != null) {
 | 
			
		||||
							try {
 | 
			
		||||
								move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
 | 
			
		||||
							} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
 | 
			
		||||
									| InvocationTargetException | InstantiationException e) {
 | 
			
		||||
							} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
 | 
			
		||||
								e.printStackTrace();
 | 
			
		||||
							}
 | 
			
		||||
						} else move = new Move(pos, dest);
 | 
			
		||||
@@ -162,8 +160,7 @@ public class Board {
 | 
			
		||||
						if (m.group("promotedTo") != null) {
 | 
			
		||||
							try {
 | 
			
		||||
								move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
 | 
			
		||||
							} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
 | 
			
		||||
									| InvocationTargetException | InstantiationException e) {
 | 
			
		||||
							} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
 | 
			
		||||
								e.printStackTrace();
 | 
			
		||||
							}
 | 
			
		||||
						} else move = new Move(pos, dest);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
package dev.kske.chess.board;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -45,8 +44,7 @@ public class Move {
 | 
			
		||||
		if (move.length() == 5) {
 | 
			
		||||
			try {
 | 
			
		||||
				return new PawnPromotion(pos, dest, Piece.fromFirstChar(move.charAt(4)));
 | 
			
		||||
			} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
 | 
			
		||||
					| InstantiationException e) {
 | 
			
		||||
			} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
 | 
			
		||||
				e.printStackTrace();
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
@@ -62,7 +60,7 @@ public class Move {
 | 
			
		||||
	public boolean isDiagonal() { return getxDist() == getyDist(); }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() { return String.format("%s -> %s", getPos(), getDest()); }
 | 
			
		||||
	public String toString() { return toLAN(); }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int hashCode() { return Objects.hash(getDest(), getPos(), getxDist(), getxSign(), getyDist(), getySign()); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
package dev.kske.chess.board;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@@ -75,8 +74,7 @@ public class Pawn extends Piece {
 | 
			
		||||
					moves.add(new PawnPromotion(pos, dest, Rook.class));
 | 
			
		||||
					moves.add(new PawnPromotion(pos, dest, Knight.class));
 | 
			
		||||
					moves.add(new PawnPromotion(pos, dest, Bishop.class));
 | 
			
		||||
				} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
 | 
			
		||||
						| InstantiationException e) {
 | 
			
		||||
				} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
 | 
			
		||||
					e.printStackTrace();
 | 
			
		||||
				}
 | 
			
		||||
			} else moves.add(move);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package dev.kske.chess.board;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Constructor;
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import dev.kske.chess.board.Piece.Color;
 | 
			
		||||
 | 
			
		||||
@@ -15,19 +16,16 @@ import dev.kske.chess.board.Piece.Color;
 | 
			
		||||
 */
 | 
			
		||||
public class PawnPromotion extends Move {
 | 
			
		||||
 | 
			
		||||
	private final Class<? extends Piece>		promotionPieceClass;
 | 
			
		||||
	private final Constructor<? extends Piece>	promotionPieceConstructor;
 | 
			
		||||
	private final char							promotionPieceChar;
 | 
			
		||||
 | 
			
		||||
	public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPiece) throws NoSuchMethodException, SecurityException,
 | 
			
		||||
			IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
 | 
			
		||||
	public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPieceClass) throws NoSuchMethodException, SecurityException {
 | 
			
		||||
		super(pos, dest);
 | 
			
		||||
		this.promotionPieceClass = promotionPieceClass;
 | 
			
		||||
 | 
			
		||||
		// Cache piece constructor
 | 
			
		||||
		promotionPieceConstructor = promotionPiece.getDeclaredConstructor(Color.class, Board.class);
 | 
			
		||||
		promotionPieceConstructor = promotionPieceClass.getDeclaredConstructor(Color.class, Board.class);
 | 
			
		||||
		promotionPieceConstructor.setAccessible(true);
 | 
			
		||||
 | 
			
		||||
		// Cache piece first char
 | 
			
		||||
		promotionPieceChar = (char) promotionPiece.getMethod("firstChar").invoke(promotionPieceConstructor.newInstance(null, null));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public PawnPromotion(int xPos, int yPos, int xDest, int yDest, Class<? extends Piece> promotionPiece)
 | 
			
		||||
@@ -53,5 +51,31 @@ public class PawnPromotion extends Move {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toLAN() { return pos.toLAN() + dest.toLAN() + promotionPieceChar; }
 | 
			
		||||
	public String toLAN() {
 | 
			
		||||
		char promotionPieceChar = '-';
 | 
			
		||||
		try {
 | 
			
		||||
			promotionPieceChar = (char) promotionPieceClass.getMethod("firstChar").invoke(promotionPieceConstructor.newInstance(null, null));
 | 
			
		||||
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException
 | 
			
		||||
				| InstantiationException e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
		return pos.toLAN() + dest.toLAN() + promotionPieceChar;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int hashCode() {
 | 
			
		||||
		final int	prime	= 31;
 | 
			
		||||
		int			result	= super.hashCode();
 | 
			
		||||
		result = prime * result + Objects.hash(promotionPieceClass);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean equals(Object obj) {
 | 
			
		||||
		if (this == obj) return true;
 | 
			
		||||
		if (!super.equals(obj)) return false;
 | 
			
		||||
		if (getClass() != obj.getClass()) return false;
 | 
			
		||||
		PawnPromotion other = (PawnPromotion) obj;
 | 
			
		||||
		return Objects.equals(promotionPieceClass, other.promotionPieceClass);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,11 @@ import java.awt.event.MouseListener;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import dev.kske.chess.board.Board;
 | 
			
		||||
import javax.swing.JComboBox;
 | 
			
		||||
import javax.swing.JOptionPane;
 | 
			
		||||
 | 
			
		||||
import dev.kske.chess.board.Move;
 | 
			
		||||
import dev.kske.chess.board.Piece;
 | 
			
		||||
import dev.kske.chess.board.Piece.Color;
 | 
			
		||||
import dev.kske.chess.board.Position;
 | 
			
		||||
import dev.kske.chess.ui.OverlayComponent;
 | 
			
		||||
@@ -24,7 +27,8 @@ public class NaturalPlayer extends Player implements MouseListener {
 | 
			
		||||
	private final OverlayComponent overlayComponent;
 | 
			
		||||
 | 
			
		||||
	private boolean		moveRequested;
 | 
			
		||||
	private Position	pos;
 | 
			
		||||
	private Piece		selectedPiece;
 | 
			
		||||
	private List<Move>	possibleMoves;
 | 
			
		||||
 | 
			
		||||
	public NaturalPlayer(Color color, OverlayComponent overlayComponent) {
 | 
			
		||||
		super(color);
 | 
			
		||||
@@ -47,22 +51,52 @@ public class NaturalPlayer extends Player implements MouseListener {
 | 
			
		||||
	@Override
 | 
			
		||||
	public void mousePressed(MouseEvent evt) {
 | 
			
		||||
		if (!moveRequested) return;
 | 
			
		||||
		if (pos == null) {
 | 
			
		||||
			pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
 | 
			
		||||
		if (selectedPiece == null) {
 | 
			
		||||
 | 
			
		||||
			Board board = new Board(this.board);
 | 
			
		||||
			if (board.get(pos) != null && board.get(pos).getColor() == color) {
 | 
			
		||||
				List<Position> positions = board.getMoves(pos).stream().map(move -> move.getDest()).collect(Collectors.toList());
 | 
			
		||||
				overlayComponent.displayDots(positions);
 | 
			
		||||
			} else pos = null;
 | 
			
		||||
			// Get selected Piece
 | 
			
		||||
			final Position pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
 | 
			
		||||
			selectedPiece = board.get(pos);
 | 
			
		||||
 | 
			
		||||
			// Check if a piece was selected
 | 
			
		||||
			if (selectedPiece != null) {
 | 
			
		||||
 | 
			
		||||
				// Discard selection if the piece has the wrong color
 | 
			
		||||
				if (selectedPiece.getColor() == color.opposite()) selectedPiece = null;
 | 
			
		||||
				else {
 | 
			
		||||
 | 
			
		||||
					// Generate all moves possible with the selected piece and display their
 | 
			
		||||
					// destinations
 | 
			
		||||
					possibleMoves = selectedPiece.getMoves(pos);
 | 
			
		||||
					overlayComponent.displayDots(possibleMoves.stream().map(move -> move.getDest()).collect(Collectors.toList()));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			Position dest = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
 | 
			
		||||
 | 
			
		||||
			overlayComponent.clearDots();
 | 
			
		||||
			// Get all moves leading to the specified destination
 | 
			
		||||
			List<Move> selectedMoves = possibleMoves.stream().filter(m -> m.getDest().equals(dest)).collect(Collectors.toList());
 | 
			
		||||
			if (!selectedMoves.isEmpty()) {
 | 
			
		||||
				Move move;
 | 
			
		||||
 | 
			
		||||
				// Process pawn promotion if necessary
 | 
			
		||||
				if (selectedMoves.size() > 1) {
 | 
			
		||||
 | 
			
		||||
					// Let the user select a promotion piece
 | 
			
		||||
					JComboBox<Move> comboBox = new JComboBox<Move>(selectedMoves.toArray(new Move[0]));
 | 
			
		||||
					JOptionPane.showMessageDialog(overlayComponent, comboBox, "Select a promotion", JOptionPane.QUESTION_MESSAGE);
 | 
			
		||||
 | 
			
		||||
					move = selectedMoves.get(comboBox.getSelectedIndex());
 | 
			
		||||
				} else move = selectedMoves.get(0);
 | 
			
		||||
 | 
			
		||||
				// Tell the game to execute the move
 | 
			
		||||
				moveRequested = false;
 | 
			
		||||
			// TODO: Special moves
 | 
			
		||||
			game.onMove(NaturalPlayer.this, new Move(pos, dest));
 | 
			
		||||
			pos = null;
 | 
			
		||||
				game.onMove(NaturalPlayer.this, move);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Discard the selection
 | 
			
		||||
			overlayComponent.clearDots();
 | 
			
		||||
			selectedPiece	= null;
 | 
			
		||||
			possibleMoves	= null;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user