Added pawn promotion selection
* Letting a NaturalPlayer select the promotion piece with a combo box * Optimized reflection use in PawnPromotion * Changed toString method of Move to use LAN Closes #9
This commit is contained in:
		| @@ -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()); | ||||
|  | ||||
| 			// 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; | ||||
| 				game.onMove(NaturalPlayer.this, move); | ||||
| 			} | ||||
|  | ||||
| 			// Discard the selection | ||||
| 			overlayComponent.clearDots(); | ||||
| 			moveRequested = false; | ||||
| 			// TODO: Special moves | ||||
| 			game.onMove(NaturalPlayer.this, new Move(pos, dest)); | ||||
| 			pos = null; | ||||
| 			selectedPiece	= null; | ||||
| 			possibleMoves	= null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user