diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java
index f99b2c9..b8da2ba 100644
--- a/src/dev/kske/chess/board/Board.java
+++ b/src/dev/kske/chess/board/Board.java
@@ -458,11 +458,11 @@ public class Board implements Cloneable {
if (castlingSb.length() == 0) sb.append("-");
sb.append(castlingSb);
- // TODO: en passant availability
- sb.append(" -");
-
final LoggedMove lastMove = log.getLast();
+ // En passant availabillity
+ sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN()));
+
// Halfmove clock
sb.append(" " + String.valueOf(lastMove == null ? 0 : lastMove.halfmoveClock));
diff --git a/src/dev/kske/chess/board/Log.java b/src/dev/kske/chess/board/Log.java
index 22d8bf2..6211983 100644
--- a/src/dev/kske/chess/board/Log.java
+++ b/src/dev/kske/chess/board/Log.java
@@ -22,6 +22,11 @@ public class Log implements Cloneable {
}
public void add(Move move, Piece capturedPiece, boolean pawnMove) {
+ // En passant availability
+ Position enPassant = null;
+ if (pawnMove && move.yDist == 2) enPassant = new Position(move.pos.x, move.pos.y + move.ySign);
+
+ // Fullmove counter and halfmove clock
int fullmoveCounter, halfmoveClock;
if (moves.isEmpty()) {
fullmoveCounter = 1;
@@ -32,7 +37,7 @@ public class Log implements Cloneable {
halfmoveClock = capturedPiece != null || pawnMove ? 0 : getLast().halfmoveClock + 1;
}
activeColor = activeColor.opposite();
- moves.add(new LoggedMove(move, capturedPiece, fullmoveCounter, halfmoveClock));
+ moves.add(new LoggedMove(move, capturedPiece, enPassant, fullmoveCounter, halfmoveClock));
}
public LoggedMove getLast() { return moves.isEmpty() ? null : moves.get(moves.size() - 1); }
@@ -63,11 +68,13 @@ public class Log implements Cloneable {
public final Move move;
public final Piece capturedPiece;
+ public final Position enPassant;
public final int fullmoveCounter, halfmoveClock;
- public LoggedMove(Move move, Piece capturedPiece, int fullmoveCounter, int halfmoveClock) {
+ public LoggedMove(Move move, Piece capturedPiece, Position enPassant, int fullmoveCounter, int halfmoveClock) {
this.move = move;
this.capturedPiece = capturedPiece;
+ this.enPassant = enPassant;
this.fullmoveCounter = fullmoveCounter;
this.halfmoveClock = halfmoveClock;
}
diff --git a/src/dev/kske/chess/board/Move.java b/src/dev/kske/chess/board/Move.java
index eafb9b9..06d7ba9 100644
--- a/src/dev/kske/chess/board/Move.java
+++ b/src/dev/kske/chess/board/Move.java
@@ -30,9 +30,9 @@ public class Move {
this(new Position(xPos, yPos), new Position(xDest, yDest));
}
- public static Move fromAlgebraicNotation(String move) {
- return new Move(Position.fromAlgebraicNotation(move.substring(0, 2)),
- Position.fromAlgebraicNotation(move.substring(2)));
+ public static Move fromSAN(String move) {
+ return new Move(Position.fromSAN(move.substring(0, 2)),
+ Position.fromSAN(move.substring(2)));
}
public boolean isHorizontal() { return yDist == 0; }
diff --git a/src/dev/kske/chess/board/Position.java b/src/dev/kske/chess/board/Position.java
index 69bb03b..ac9638d 100644
--- a/src/dev/kske/chess/board/Position.java
+++ b/src/dev/kske/chess/board/Position.java
@@ -15,8 +15,12 @@ public class Position {
this.y = y;
}
- public static Position fromAlgebraicNotation(String pos) {
- return new Position(pos.charAt(0) - 97, 7 - (Character.getNumericValue(pos.charAt(1)) - 1));
+ public static Position fromSAN(String pos) {
+ return new Position(pos.charAt(0) - 97, 8 - Character.getNumericValue(pos.charAt(1)));
+ }
+
+ public String toSAN() {
+ return String.valueOf((char) (x + 97)) + String.valueOf(8 - y);
}
@Override
diff --git a/src/dev/kske/chess/game/UCIPlayer.java b/src/dev/kske/chess/game/UCIPlayer.java
index 0af08b2..edf1a56 100644
--- a/src/dev/kske/chess/game/UCIPlayer.java
+++ b/src/dev/kske/chess/game/UCIPlayer.java
@@ -74,7 +74,7 @@ public class UCIPlayer extends Player implements UCIListener {
@Override
public void onBestMove(String move) {
- Move moveObj = Move.fromAlgebraicNotation(move);
+ Move moveObj = Move.fromSAN(move);
game.onMove(this, moveObj);
}
diff --git a/test/dev/kske/chess/test/PositionTest.java b/test/dev/kske/chess/test/PositionTest.java
new file mode 100644
index 0000000..c98c2ba
--- /dev/null
+++ b/test/dev/kske/chess/test/PositionTest.java
@@ -0,0 +1,52 @@
+package dev.kske.chess.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import dev.kske.chess.board.Position;
+
+/**
+ * Project: Chess
+ * File: PositionTest.java
+ * Created: 24.07.2019
+ * Author: Kai S. K. Engelbart
+ */
+class PositionTest {
+
+ List positions;
+ List sans;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @BeforeEach
+ void setUp() throws Exception {
+ positions = Arrays.asList(new Position(0, 0), new Position(7, 7), new Position(0, 7), new Position(7, 0));
+ sans = Arrays.asList("a8", "h1", "a1", "h8");
+ }
+
+ /**
+ * Test method for
+ * {@link dev.kske.chess.board.Position#fromSAN(java.lang.String)}.
+ */
+ @Test
+ void testFromSAN() {
+ IntStream.range(0, positions.size())
+ .forEach(i -> assertEquals(positions.get(i), Position.fromSAN(sans.get(i))));
+ }
+
+ /**
+ * Test method for {@link dev.kske.chess.board.Position#toSAN()}.
+ */
+ @Test
+ void testToSAN() {
+ IntStream.range(0, positions.size()).forEach(i -> assertEquals(sans.get(i), positions.get(i).toSAN()));
+ }
+
+}