Added variations in Log, added LogTest

This commit is contained in:
Kai S. K. Engelbart 2019-09-13 18:13:34 +02:00
parent 7258e96b1a
commit 1723c44524
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
4 changed files with 225 additions and 35 deletions

View File

@ -5,7 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dev.kske.chess.board.Log.LoggedMove;
import dev.kske.chess.board.Log.MoveNode;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.board.Piece.Type;
@ -163,9 +163,9 @@ public class Board implements Cloneable {
* Reverts the last move.
*/
public void revert() {
LoggedMove loggedMove = log.getLast();
Move move = loggedMove.move;
Piece capturedPiece = loggedMove.capturedPiece;
MoveNode moveNode = log.getLast();
Move move = moveNode.move;
Piece capturedPiece = moveNode.capturedPiece;
switch (move.type) {
case PAWN_PROMOTION:
@ -509,7 +509,7 @@ public class Board implements Cloneable {
if (castlingSb.length() == 0) sb.append("-");
sb.append(castlingSb);
final LoggedMove lastMove = log.getLast();
final MoveNode lastMove = log.getLast();
// En passant availability
sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN()));

View File

@ -1,7 +1,7 @@
package dev.kske.chess.board;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import dev.kske.chess.board.Piece.Color;
@ -13,27 +13,30 @@ import dev.kske.chess.board.Piece.Color;
*/
public class Log implements Cloneable {
private List<LoggedMove> moves;
private MoveNode root, current;
private Position enPassant;
private Color activeColor;
private int fullmoveCounter, halfmoveClock;
public Log() {
moves = new ArrayList<>();
reset();
}
// TODO: Adjust to variations
@Override
public Object clone() {
Log log = null;
try {
log = (Log) super.clone();
if (!isEmpty()) {
log.current = (MoveNode) current.clone();
if (current == root) log.root = log.current;
else log.root = (MoveNode) root.clone();
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
log.moves = new ArrayList<>();
log.moves.addAll(this.moves);
return log;
}
@ -50,13 +53,16 @@ public class Log implements Cloneable {
if (pawnMove || capturedPiece != null) halfmoveClock = 0;
else++halfmoveClock;
activeColor = activeColor.opposite();
moves.add(new LoggedMove(move, capturedPiece, enPassant, activeColor, fullmoveCounter, halfmoveClock));
}
final MoveNode leaf = new MoveNode(move, capturedPiece, enPassant, activeColor, fullmoveCounter, halfmoveClock);
/**
* @return the last logged move, or {@code null} if there is none
*/
public LoggedMove getLast() { return moves.isEmpty() ? null : moves.get(moves.size() - 1); }
if (isEmpty()) {
root = leaf;
current = leaf;
} else {
current.addVariation(leaf);
current = leaf;
}
}
/**
* Removed the last move from the log and adjusts its state to the previous
@ -64,36 +70,45 @@ public class Log implements Cloneable {
*/
public void removeLast() {
if (!isEmpty()) {
moves.remove(moves.size() - 1);
if (current.parent == null) {
current = null;
root = null;
} else {
current = current.parent;
if (!isEmpty()) {
LoggedMove last = moves.get(moves.size() - 1);
activeColor = last.activeColor;
enPassant = last.enPassant;
fullmoveCounter = last.fullmoveCounter;
halfmoveClock = last.halfmoveClock;
activeColor = current.activeColor;
enPassant = current.enPassant;
fullmoveCounter = current.fullmoveCounter;
halfmoveClock = current.halfmoveClock;
} else reset();
}
} else reset();
}
public boolean isEmpty() { return moves.isEmpty(); }
public boolean isEmpty() { return root == null; }
/**
* Reverts the log to its initial state corresponding to the default board
* position.
*/
public void reset() {
moves.clear();
root = null;
current = null;
enPassant = null;
activeColor = Color.WHITE;
fullmoveCounter = 1;
halfmoveClock = 0;
}
public List<LoggedMove> getLoggedMoves() { return moves; }
/**
* @return The first logged move, or {@code null} if there is none
*/
public MoveNode getRoot() { return root; }
public List<LoggedMove> getMoves() { return moves; }
public void setMoves(List<LoggedMove> moves) { this.moves = moves; }
/**
* @return the last logged move, or {@code null} if there is none
*/
public MoveNode getLast() { return current; }
public Position getEnPassant() { return enPassant; }
@ -111,7 +126,7 @@ public class Log implements Cloneable {
public void setHalfmoveClock(int halfmoveClock) { this.halfmoveClock = halfmoveClock; }
public static class LoggedMove {
public static class MoveNode {
public final Move move;
public final Piece capturedPiece;
@ -119,7 +134,10 @@ public class Log implements Cloneable {
public final Color activeColor;
public final int fullmoveCounter, halfmoveClock;
public LoggedMove(Move move, Piece capturedPiece, Position enPassant, Color activeColor, int fullmoveCounter,
private MoveNode parent;
private Set<MoveNode> variations = new HashSet<>();
public MoveNode(Move move, Piece capturedPiece, Position enPassant, Color activeColor, int fullmoveCounter,
int halfmoveClock) {
this.move = move;
this.capturedPiece = capturedPiece;
@ -128,5 +146,17 @@ public class Log implements Cloneable {
this.fullmoveCounter = fullmoveCounter;
this.halfmoveClock = halfmoveClock;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void addVariation(MoveNode variation) {
if (!variations.contains(variation)) {
variations.add(variation);
variation.parent = this;
}
}
}
}

View File

@ -1,6 +1,7 @@
package dev.kske.chess.ui;
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@ -13,7 +14,7 @@ import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import dev.kske.chess.board.Log;
import dev.kske.chess.board.Log.LoggedMove;
import dev.kske.chess.board.Log.MoveNode;
import dev.kske.chess.event.Event;
import dev.kske.chess.event.EventBus;
import dev.kske.chess.event.MoveEvent;
@ -56,7 +57,7 @@ public class LogPanel extends JPanel implements Subscribable {
public void handle(Event<?> event) {
if (log == null) return;
final List<LoggedMove> moves = log.getLoggedMoves();
final List<MoveNode> moves = /* log.getLoggedMoves() */ new ArrayList<>();
String[][] data = new String[moves.size() / 2 + moves.size() % 2][2];
for (int i = 0; i < data.length; i++) {
data[i][0] = moves.get(i * 2).move.toSAN();

View File

@ -0,0 +1,159 @@
package dev.kske.chess.board;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
import dev.kske.chess.board.Piece.Color;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>LogTest.java</strong><br>
* Created: <strong>13 Sep 2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
class LogTest {
Log log = new Log();
/**
* Test method for {@link dev.kske.chess.board.Log#Log()}.
*/
@Test
void testLog() {
assertTrue(log.isEmpty());
assertNull(log.getLast());
assertNull(log.getRoot());
assertEquals(log.getActiveColor(), Color.WHITE);
assertNull(log.getEnPassant());
assertEquals(log.getFullmoveCounter(), 1);
assertEquals(log.getHalfmoveClock(), 0);
}
/**
* Test method for {@link dev.kske.chess.board.Log#clone()}.
*/
@Test
void testClone() {
Log other = (Log) log.clone();
log.setActiveColor(Color.WHITE);
other.setActiveColor(Color.BLACK);
assertNotEquals(other.getActiveColor(), log.getActiveColor());
}
/**
* Test method for {@link dev.kske.chess.board.Log#add(dev.kske.chess.board.Move, dev.kske.chess.board.Piece, boolean)}.
*/
@Test
void testAdd() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#removeLast()}.
*/
@Test
void testRemoveLast() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#isEmpty()}.
*/
@Test
void testIsEmpty() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#reset()}.
*/
@Test
void testReset() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#getRoot()}.
*/
@Test
void testGetRoot() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#getLast()}.
*/
@Test
void testGetLast() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#getEnPassant()}.
*/
@Test
void testGetEnPassant() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#setEnPassant(dev.kske.chess.board.Position)}.
*/
@Test
void testSetEnPassant() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#getActiveColor()}.
*/
@Test
void testGetActiveColor() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#setActiveColor(dev.kske.chess.board.Piece.Color)}.
*/
@Test
void testSetActiveColor() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#getFullmoveCounter()}.
*/
@Test
void testGetFullmoveCounter() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#setFullmoveCounter(int)}.
*/
@Test
void testSetFullmoveCounter() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#getHalfmoveClock()}.
*/
@Test
void testGetHalfmoveClock() {
fail("Not yet implemented");
}
/**
* Test method for {@link dev.kske.chess.board.Log#setHalfmoveClock(int)}.
*/
@Test
void testSetHalfmoveClock() {
fail("Not yet implemented");
}
}