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:
parent
e92664dd07
commit
1dc97ba3de
@ -1,6 +1,5 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -143,8 +142,7 @@ public class Board {
|
|||||||
if (m.group("promotedTo") != null) {
|
if (m.group("promotedTo") != null) {
|
||||||
try {
|
try {
|
||||||
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
||||||
| InvocationTargetException | InstantiationException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else move = new Move(pos, dest);
|
} else move = new Move(pos, dest);
|
||||||
@ -162,8 +160,7 @@ public class Board {
|
|||||||
if (m.group("promotedTo") != null) {
|
if (m.group("promotedTo") != null) {
|
||||||
try {
|
try {
|
||||||
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
||||||
| InvocationTargetException | InstantiationException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else move = new Move(pos, dest);
|
} else move = new Move(pos, dest);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,8 +44,7 @@ public class Move {
|
|||||||
if (move.length() == 5) {
|
if (move.length() == 5) {
|
||||||
try {
|
try {
|
||||||
return new PawnPromotion(pos, dest, Piece.fromFirstChar(move.charAt(4)));
|
return new PawnPromotion(pos, dest, Piece.fromFirstChar(move.charAt(4)));
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
||||||
| InstantiationException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -62,7 +60,7 @@ public class Move {
|
|||||||
public boolean isDiagonal() { return getxDist() == getyDist(); }
|
public boolean isDiagonal() { return getxDist() == getyDist(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() { return String.format("%s -> %s", getPos(), getDest()); }
|
public String toString() { return toLAN(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return Objects.hash(getDest(), getPos(), getxDist(), getxSign(), getyDist(), getySign()); }
|
public int hashCode() { return Objects.hash(getDest(), getPos(), getxDist(), getxSign(), getyDist(), getySign()); }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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, Rook.class));
|
||||||
moves.add(new PawnPromotion(pos, dest, Knight.class));
|
moves.add(new PawnPromotion(pos, dest, Knight.class));
|
||||||
moves.add(new PawnPromotion(pos, dest, Bishop.class));
|
moves.add(new PawnPromotion(pos, dest, Bishop.class));
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
||||||
| InstantiationException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else moves.add(move);
|
} else moves.add(move);
|
||||||
|
@ -2,6 +2,7 @@ package dev.kske.chess.board;
|
|||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
@ -15,19 +16,16 @@ import dev.kske.chess.board.Piece.Color;
|
|||||||
*/
|
*/
|
||||||
public class PawnPromotion extends Move {
|
public class PawnPromotion extends Move {
|
||||||
|
|
||||||
|
private final Class<? extends Piece> promotionPieceClass;
|
||||||
private final Constructor<? extends Piece> promotionPieceConstructor;
|
private final Constructor<? extends Piece> promotionPieceConstructor;
|
||||||
private final char promotionPieceChar;
|
|
||||||
|
|
||||||
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPiece) throws NoSuchMethodException, SecurityException,
|
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPieceClass) throws NoSuchMethodException, SecurityException {
|
||||||
IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
|
|
||||||
super(pos, dest);
|
super(pos, dest);
|
||||||
|
this.promotionPieceClass = promotionPieceClass;
|
||||||
|
|
||||||
// Cache piece constructor
|
// Cache piece constructor
|
||||||
promotionPieceConstructor = promotionPiece.getDeclaredConstructor(Color.class, Board.class);
|
promotionPieceConstructor = promotionPieceClass.getDeclaredConstructor(Color.class, Board.class);
|
||||||
promotionPieceConstructor.setAccessible(true);
|
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)
|
public PawnPromotion(int xPos, int yPos, int xDest, int yDest, Class<? extends Piece> promotionPiece)
|
||||||
@ -53,5 +51,31 @@ public class PawnPromotion extends Move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.List;
|
||||||
import java.util.stream.Collectors;
|
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.Move;
|
||||||
|
import dev.kske.chess.board.Piece;
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.board.Position;
|
import dev.kske.chess.board.Position;
|
||||||
import dev.kske.chess.ui.OverlayComponent;
|
import dev.kske.chess.ui.OverlayComponent;
|
||||||
@ -24,7 +27,8 @@ public class NaturalPlayer extends Player implements MouseListener {
|
|||||||
private final OverlayComponent overlayComponent;
|
private final OverlayComponent overlayComponent;
|
||||||
|
|
||||||
private boolean moveRequested;
|
private boolean moveRequested;
|
||||||
private Position pos;
|
private Piece selectedPiece;
|
||||||
|
private List<Move> possibleMoves;
|
||||||
|
|
||||||
public NaturalPlayer(Color color, OverlayComponent overlayComponent) {
|
public NaturalPlayer(Color color, OverlayComponent overlayComponent) {
|
||||||
super(color);
|
super(color);
|
||||||
@ -47,22 +51,52 @@ public class NaturalPlayer extends Player implements MouseListener {
|
|||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent evt) {
|
public void mousePressed(MouseEvent evt) {
|
||||||
if (!moveRequested) return;
|
if (!moveRequested) return;
|
||||||
if (pos == null) {
|
if (selectedPiece == null) {
|
||||||
pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
|
|
||||||
|
|
||||||
Board board = new Board(this.board);
|
// Get selected Piece
|
||||||
if (board.get(pos) != null && board.get(pos).getColor() == color) {
|
final Position pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
|
||||||
List<Position> positions = board.getMoves(pos).stream().map(move -> move.getDest()).collect(Collectors.toList());
|
selectedPiece = board.get(pos);
|
||||||
overlayComponent.displayDots(positions);
|
|
||||||
} else pos = null;
|
// 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 {
|
} else {
|
||||||
Position dest = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
|
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;
|
moveRequested = false;
|
||||||
// TODO: Special moves
|
game.onMove(NaturalPlayer.this, move);
|
||||||
game.onMove(NaturalPlayer.this, new Move(pos, dest));
|
}
|
||||||
pos = null;
|
|
||||||
|
// Discard the selection
|
||||||
|
overlayComponent.clearDots();
|
||||||
|
selectedPiece = null;
|
||||||
|
possibleMoves = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user