Implemented game serialization to the PGN format #16
@ -32,4 +32,13 @@ public class Castling extends Move {
|
|||||||
super.revert(board, capturedPiece);
|
super.revert(board, capturedPiece);
|
||||||
rookMove.revert(board, null);
|
rookMove.revert(board, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code O-O-O} for a queenside castling or {@code O-O} for a kingside
|
||||||
|
* castling
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toSAN(Board board) {
|
||||||
|
return rookMove.pos.x == 0 ? "O-O-O" : "O-O";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,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 | IllegalArgumentException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ public class Move {
|
|||||||
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 | IllegalArgumentException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else move = new Move(pos, dest);
|
} else move = new Move(pos, dest);
|
||||||
@ -130,7 +130,7 @@ public class Move {
|
|||||||
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 | IllegalArgumentException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else move = new Move(pos, dest);
|
} else move = new Move(pos, dest);
|
||||||
@ -147,7 +147,27 @@ public class Move {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toSAN(Board board) { return null; }
|
public String toSAN(Board board) {
|
||||||
|
final Piece piece = board.get(pos);
|
||||||
|
StringBuilder sb = new StringBuilder(8);
|
||||||
|
|
||||||
|
// Piece symbol
|
||||||
|
if(!(piece instanceof Pawn))
|
||||||
|
sb.append(Character.toUpperCase(piece.firstChar()));
|
||||||
|
|
||||||
|
// Position
|
||||||
|
// TODO: Deconstruct position into optional file or rank
|
||||||
|
// TODO: Omit if the move is a pawn push
|
||||||
|
sb.append(pos.toLAN());
|
||||||
|
|
||||||
|
// Capture indicator
|
||||||
|
if (board.get(dest) != null) sb.append('x');
|
||||||
|
|
||||||
|
// Destination
|
||||||
|
sb.append(dest.toLAN());
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isHorizontal() { return getyDist() == 0; }
|
public boolean isHorizontal() { return getyDist() == 0; }
|
||||||
|
|
||||||
|
@ -74,7 +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 | IllegalArgumentException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else moves.add(move);
|
} else moves.add(move);
|
||||||
|
@ -16,21 +16,23 @@ 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> promotionPieceClass) throws NoSuchMethodException, SecurityException {
|
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPieceClass)
|
||||||
|
throws ReflectiveOperationException, RuntimeException {
|
||||||
super(pos, dest);
|
super(pos, dest);
|
||||||
this.promotionPieceClass = promotionPieceClass;
|
|
||||||
|
|
||||||
// Cache piece constructor
|
// Cache piece constructor
|
||||||
promotionPieceConstructor = promotionPieceClass.getDeclaredConstructor(Color.class, Board.class);
|
promotionPieceConstructor = promotionPieceClass.getDeclaredConstructor(Color.class, Board.class);
|
||||||
promotionPieceConstructor.setAccessible(true);
|
promotionPieceConstructor.setAccessible(true);
|
||||||
|
|
||||||
|
// Get piece char
|
||||||
|
promotionPieceChar = (char) promotionPieceClass.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)
|
||||||
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
throws ReflectiveOperationException, RuntimeException {
|
||||||
InstantiationException {
|
|
||||||
this(new Position(xPos, yPos), new Position(xDest, yDest), promotionPiece);
|
this(new Position(xPos, yPos), new Position(xDest, yDest), promotionPiece);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,22 +53,19 @@ public class PawnPromotion extends Move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toLAN() {
|
public String toLAN() { return pos.toLAN() + dest.toLAN() + promotionPieceChar; }
|
||||||
char promotionPieceChar = '-';
|
|
||||||
try {
|
@Override
|
||||||
promotionPieceChar = (char) promotionPieceClass.getMethod("firstChar").invoke(promotionPieceConstructor.newInstance(null, null));
|
public String toSAN(Board board) {
|
||||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException
|
String san = super.toSAN(board);
|
||||||
| InstantiationException e) {
|
return san + Character.toUpperCase(promotionPieceChar);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return pos.toLAN() + dest.toLAN() + promotionPieceChar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = prime * result + Objects.hash(promotionPieceClass);
|
result = prime * result + Objects.hash(promotionPieceChar, promotionPieceConstructor);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +73,8 @@ public class PawnPromotion extends Move {
|
|||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
if (!super.equals(obj)) return false;
|
if (!super.equals(obj)) return false;
|
||||||
if (getClass() != obj.getClass()) return false;
|
if (!(obj instanceof PawnPromotion)) return false;
|
||||||
PawnPromotion other = (PawnPromotion) obj;
|
PawnPromotion other = (PawnPromotion) obj;
|
||||||
return Objects.equals(promotionPieceClass, other.promotionPieceClass);
|
return promotionPieceChar == other.promotionPieceChar && Objects.equals(promotionPieceConstructor, other.promotionPieceConstructor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dev.kske.chess.ui;
|
package dev.kske.chess.ui;
|
||||||
|
|
||||||
|
import java.awt.Desktop;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.dnd.DropTarget;
|
import java.awt.dnd.DropTarget;
|
||||||
@ -168,7 +169,6 @@ public class MainWindow extends JFrame {
|
|||||||
|
|
||||||
public void saveFile(File file) {
|
public void saveFile(File file) {
|
||||||
final int dotIndex = file.getName().lastIndexOf('.');
|
final int dotIndex = file.getName().lastIndexOf('.');
|
||||||
final String name = file.getName().substring(0, dotIndex);
|
|
||||||
final String extension = file.getName().substring(dotIndex).toLowerCase();
|
final String extension = file.getName().substring(dotIndex).toLowerCase();
|
||||||
|
|
||||||
if (extension.equals(".pgn")) try {
|
if (extension.equals(".pgn")) try {
|
||||||
@ -178,6 +178,12 @@ public class MainWindow extends JFrame {
|
|||||||
PGNDatabase pgnDB = new PGNDatabase();
|
PGNDatabase pgnDB = new PGNDatabase();
|
||||||
pgnDB.getGames().add(pgnGame);
|
pgnDB.getGames().add(pgnGame);
|
||||||
pgnDB.save(file);
|
pgnDB.save(file);
|
||||||
|
|
||||||
|
if (JOptionPane.showConfirmDialog(this,
|
||||||
|
"Game export finished. Do you want to view the created file?",
|
||||||
|
"Game export finished",
|
||||||
|
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
|
||||||
|
Desktop.getDesktop().open(file);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
|
Reference in New Issue
Block a user