Implemented game serialization to the PGN format #16
@ -6,8 +6,6 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
@ -98,83 +96,7 @@ public class Board {
|
|||||||
* @param sanMove The move to execute in SAN (Standard Algebraic Notation)
|
* @param sanMove The move to execute in SAN (Standard Algebraic Notation)
|
||||||
*/
|
*/
|
||||||
public void move(String sanMove) {
|
public void move(String sanMove) {
|
||||||
Map<String, Pattern> patterns = new HashMap<>();
|
move(Move.fromSAN(sanMove, this));
|
||||||
patterns.put("pieceMove",
|
|
||||||
Pattern.compile(
|
|
||||||
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
|
|
||||||
patterns.put("pawnCapture",
|
|
||||||
Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)?$"));
|
|
||||||
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)$"));
|
|
||||||
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
|
|
||||||
|
|
||||||
patterns.forEach((patternName, pattern) -> {
|
|
||||||
Matcher m = pattern.matcher(sanMove);
|
|
||||||
if (m.find()) {
|
|
||||||
Position pos = null, dest = null;
|
|
||||||
Move move = null;
|
|
||||||
switch (patternName) {
|
|
||||||
case "pieceMove":
|
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
|
||||||
if (m.group("fromSquare") != null) pos = Position.fromLAN(m.group("fromSquare"));
|
|
||||||
else {
|
|
||||||
Class<? extends Piece> pieceClass = Piece.fromFirstChar(m.group("pieceType").charAt(0));
|
|
||||||
char file;
|
|
||||||
int rank;
|
|
||||||
if (m.group("fromFile") != null) {
|
|
||||||
file = m.group("fromFile").charAt(0);
|
|
||||||
rank = get(pieceClass, file);
|
|
||||||
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
|
||||||
} else if (m.group("fromRank") != null) {
|
|
||||||
rank = Integer.parseInt(m.group("fromRank").substring(0, 1));
|
|
||||||
file = get(pieceClass, rank);
|
|
||||||
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
|
||||||
} else pos = get(pieceClass, dest);
|
|
||||||
}
|
|
||||||
move = new Move(pos, dest);
|
|
||||||
break;
|
|
||||||
case "pawnCapture":
|
|
||||||
char file = m.group("fromFile").charAt(0);
|
|
||||||
int rank = m.group("fromRank") == null ? get(Pawn.class, file) : Integer.parseInt(m.group("fromRank"));
|
|
||||||
|
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
|
||||||
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
|
||||||
|
|
||||||
if (m.group("promotedTo") != null) {
|
|
||||||
try {
|
|
||||||
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else move = new Move(pos, dest);
|
|
||||||
break;
|
|
||||||
case "pawnPush":
|
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
|
||||||
int step = log.getActiveColor() == Color.WHITE ? 1 : -1;
|
|
||||||
|
|
||||||
// One step forward
|
|
||||||
if (boardArr[dest.x][dest.y + step] != null) pos = new Position(dest.x, dest.y + step);
|
|
||||||
|
|
||||||
// Double step forward
|
|
||||||
else pos = new Position(dest.x, dest.y + 2 * step);
|
|
||||||
|
|
||||||
if (m.group("promotedTo") != null) {
|
|
||||||
try {
|
|
||||||
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else move = new Move(pos, dest);
|
|
||||||
break;
|
|
||||||
case "castling":
|
|
||||||
pos = new Position(4, log.getActiveColor() == Color.WHITE ? 7 : 0);
|
|
||||||
dest = new Position(m.group("kingside") != null ? 6 : 2, pos.y);
|
|
||||||
move = new Castling(pos, dest);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
move(move);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -53,6 +59,96 @@ public class Move {
|
|||||||
|
|
||||||
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a move string from standard algebraic notation to a {@link Move}
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @param sanMove the move string to convert from
|
||||||
|
* @param board the board on which the move has to be executed
|
||||||
|
* @return the converted {@link Move} object
|
||||||
|
*/
|
||||||
|
public static Move fromSAN(String sanMove, Board board) {
|
||||||
|
Map<String, Pattern> patterns = new HashMap<>();
|
||||||
|
patterns.put("pieceMove",
|
||||||
|
Pattern.compile(
|
||||||
|
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
|
||||||
|
patterns.put("pawnCapture",
|
||||||
|
Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)?$"));
|
||||||
|
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)$"));
|
||||||
|
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
|
||||||
|
|
||||||
|
for (Map.Entry<String, Pattern> entry : patterns.entrySet()) {
|
||||||
|
Matcher m = entry.getValue().matcher(sanMove);
|
||||||
|
if (m.find()) {
|
||||||
|
Position pos = null, dest = null;
|
||||||
|
Move move = null;
|
||||||
|
switch (entry.getKey()) {
|
||||||
|
case "pieceMove":
|
||||||
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
|
if (m.group("fromSquare") != null) pos = Position.fromLAN(m.group("fromSquare"));
|
||||||
|
else {
|
||||||
|
Class<? extends Piece> pieceClass = Piece.fromFirstChar(m.group("pieceType").charAt(0));
|
||||||
|
char file;
|
||||||
|
int rank;
|
||||||
|
if (m.group("fromFile") != null) {
|
||||||
|
file = m.group("fromFile").charAt(0);
|
||||||
|
rank = board.get(pieceClass, file);
|
||||||
|
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
||||||
|
} else if (m.group("fromRank") != null) {
|
||||||
|
rank = Integer.parseInt(m.group("fromRank").substring(0, 1));
|
||||||
|
file = board.get(pieceClass, rank);
|
||||||
|
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
||||||
|
} else pos = board.get(pieceClass, dest);
|
||||||
|
}
|
||||||
|
move = new Move(pos, dest);
|
||||||
|
break;
|
||||||
|
case "pawnCapture":
|
||||||
|
char file = m.group("fromFile").charAt(0);
|
||||||
|
int rank = m.group("fromRank") == null ? board.get(Pawn.class, file) : Integer.parseInt(m.group("fromRank"));
|
||||||
|
|
||||||
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
|
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
||||||
|
|
||||||
|
if (m.group("promotedTo") != null) {
|
||||||
|
try {
|
||||||
|
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
||||||
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else move = new Move(pos, dest);
|
||||||
|
break;
|
||||||
|
case "pawnPush":
|
||||||
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
|
int step = board.getLog().getActiveColor() == Color.WHITE ? 1 : -1;
|
||||||
|
|
||||||
|
// One step forward
|
||||||
|
if (board.getBoardArr()[dest.x][dest.y + step] != null) pos = new Position(dest.x, dest.y + step);
|
||||||
|
|
||||||
|
// Double step forward
|
||||||
|
else pos = new Position(dest.x, dest.y + 2 * step);
|
||||||
|
|
||||||
|
if (m.group("promotedTo") != null) {
|
||||||
|
try {
|
||||||
|
move = new PawnPromotion(pos, dest, Piece.fromFirstChar(m.group("promotedTo").charAt(0)));
|
||||||
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else move = new Move(pos, dest);
|
||||||
|
break;
|
||||||
|
case "castling":
|
||||||
|
pos = new Position(4, board.getLog().getActiveColor() == Color.WHITE ? 7 : 0);
|
||||||
|
dest = new Position(m.group("kingside") != null ? 6 : 2, pos.y);
|
||||||
|
move = new Castling(pos, dest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toSAN(Board board) { return null; }
|
||||||
|
|
||||||
public boolean isHorizontal() { return getyDist() == 0; }
|
public boolean isHorizontal() { return getyDist() == 0; }
|
||||||
|
|
||||||
public boolean isVertical() { return getxDist() == 0; }
|
public boolean isVertical() { return getxDist() == 0; }
|
||||||
|
Reference in New Issue
Block a user