Added variations in Log, added LogTest
This commit is contained in:
parent
1d2cf364bd
commit
ea8d754a72
@ -5,7 +5,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.Color;
|
||||||
import dev.kske.chess.board.Piece.Type;
|
import dev.kske.chess.board.Piece.Type;
|
||||||
|
|
||||||
@ -163,9 +163,9 @@ public class Board implements Cloneable {
|
|||||||
* Reverts the last move.
|
* Reverts the last move.
|
||||||
*/
|
*/
|
||||||
public void revert() {
|
public void revert() {
|
||||||
LoggedMove loggedMove = log.getLast();
|
MoveNode moveNode = log.getLast();
|
||||||
Move move = loggedMove.move;
|
Move move = moveNode.move;
|
||||||
Piece capturedPiece = loggedMove.capturedPiece;
|
Piece capturedPiece = moveNode.capturedPiece;
|
||||||
|
|
||||||
switch (move.type) {
|
switch (move.type) {
|
||||||
case PAWN_PROMOTION:
|
case PAWN_PROMOTION:
|
||||||
@ -509,7 +509,7 @@ public class Board implements Cloneable {
|
|||||||
if (castlingSb.length() == 0) sb.append("-");
|
if (castlingSb.length() == 0) sb.append("-");
|
||||||
sb.append(castlingSb);
|
sb.append(castlingSb);
|
||||||
|
|
||||||
final LoggedMove lastMove = log.getLast();
|
final MoveNode lastMove = log.getLast();
|
||||||
|
|
||||||
// En passant availability
|
// En passant availability
|
||||||
sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN()));
|
sb.append(" " + (lastMove == null || lastMove.enPassant == null ? "-" : lastMove.enPassant.toSAN()));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
@ -13,27 +13,30 @@ import dev.kske.chess.board.Piece.Color;
|
|||||||
*/
|
*/
|
||||||
public class Log implements Cloneable {
|
public class Log implements Cloneable {
|
||||||
|
|
||||||
private List<LoggedMove> moves;
|
private MoveNode root, current;
|
||||||
|
|
||||||
private Position enPassant;
|
private Position enPassant;
|
||||||
private Color activeColor;
|
private Color activeColor;
|
||||||
private int fullmoveCounter, halfmoveClock;
|
private int fullmoveCounter, halfmoveClock;
|
||||||
|
|
||||||
public Log() {
|
public Log() {
|
||||||
moves = new ArrayList<>();
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Adjust to variations
|
||||||
@Override
|
@Override
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
Log log = null;
|
Log log = null;
|
||||||
try {
|
try {
|
||||||
log = (Log) super.clone();
|
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) {
|
} catch (CloneNotSupportedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
log.moves = new ArrayList<>();
|
|
||||||
log.moves.addAll(this.moves);
|
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,13 +53,16 @@ public class Log implements Cloneable {
|
|||||||
if (pawnMove || capturedPiece != null) halfmoveClock = 0;
|
if (pawnMove || capturedPiece != null) halfmoveClock = 0;
|
||||||
else++halfmoveClock;
|
else++halfmoveClock;
|
||||||
activeColor = activeColor.opposite();
|
activeColor = activeColor.opposite();
|
||||||
moves.add(new LoggedMove(move, capturedPiece, enPassant, activeColor, fullmoveCounter, halfmoveClock));
|
final MoveNode leaf = new MoveNode(move, capturedPiece, enPassant, activeColor, fullmoveCounter, halfmoveClock);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (isEmpty()) {
|
||||||
* @return the last logged move, or {@code null} if there is none
|
root = leaf;
|
||||||
*/
|
current = leaf;
|
||||||
public LoggedMove getLast() { return moves.isEmpty() ? null : moves.get(moves.size() - 1); }
|
} else {
|
||||||
|
current.addVariation(leaf);
|
||||||
|
current = leaf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removed the last move from the log and adjusts its state to the previous
|
* 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() {
|
public void removeLast() {
|
||||||
if (!isEmpty()) {
|
if (!isEmpty()) {
|
||||||
moves.remove(moves.size() - 1);
|
if (current.parent == null) {
|
||||||
|
current = null;
|
||||||
|
root = null;
|
||||||
|
} else {
|
||||||
|
current = current.parent;
|
||||||
if (!isEmpty()) {
|
if (!isEmpty()) {
|
||||||
LoggedMove last = moves.get(moves.size() - 1);
|
activeColor = current.activeColor;
|
||||||
activeColor = last.activeColor;
|
enPassant = current.enPassant;
|
||||||
enPassant = last.enPassant;
|
fullmoveCounter = current.fullmoveCounter;
|
||||||
fullmoveCounter = last.fullmoveCounter;
|
halfmoveClock = current.halfmoveClock;
|
||||||
halfmoveClock = last.halfmoveClock;
|
|
||||||
} else reset();
|
} else reset();
|
||||||
|
}
|
||||||
} 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
|
* Reverts the log to its initial state corresponding to the default board
|
||||||
* position.
|
* position.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
moves.clear();
|
root = null;
|
||||||
|
current = null;
|
||||||
enPassant = null;
|
enPassant = null;
|
||||||
activeColor = Color.WHITE;
|
activeColor = Color.WHITE;
|
||||||
fullmoveCounter = 1;
|
fullmoveCounter = 1;
|
||||||
halfmoveClock = 0;
|
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; }
|
/**
|
||||||
|
* @return the last logged move, or {@code null} if there is none
|
||||||
public void setMoves(List<LoggedMove> moves) { this.moves = moves; }
|
*/
|
||||||
|
public MoveNode getLast() { return current; }
|
||||||
|
|
||||||
public Position getEnPassant() { return enPassant; }
|
public Position getEnPassant() { return enPassant; }
|
||||||
|
|
||||||
@ -111,7 +126,7 @@ public class Log implements Cloneable {
|
|||||||
|
|
||||||
public void setHalfmoveClock(int halfmoveClock) { this.halfmoveClock = halfmoveClock; }
|
public void setHalfmoveClock(int halfmoveClock) { this.halfmoveClock = halfmoveClock; }
|
||||||
|
|
||||||
public static class LoggedMove {
|
public static class MoveNode {
|
||||||
|
|
||||||
public final Move move;
|
public final Move move;
|
||||||
public final Piece capturedPiece;
|
public final Piece capturedPiece;
|
||||||
@ -119,7 +134,10 @@ public class Log implements Cloneable {
|
|||||||
public final Color activeColor;
|
public final Color activeColor;
|
||||||
public final int fullmoveCounter, halfmoveClock;
|
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) {
|
int halfmoveClock) {
|
||||||
this.move = move;
|
this.move = move;
|
||||||
this.capturedPiece = capturedPiece;
|
this.capturedPiece = capturedPiece;
|
||||||
@ -128,5 +146,17 @@ public class Log implements Cloneable {
|
|||||||
this.fullmoveCounter = fullmoveCounter;
|
this.fullmoveCounter = fullmoveCounter;
|
||||||
this.halfmoveClock = halfmoveClock;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dev.kske.chess.ui;
|
package dev.kske.chess.ui;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,7 +14,7 @@ import javax.swing.border.EmptyBorder;
|
|||||||
import javax.swing.table.DefaultTableModel;
|
import javax.swing.table.DefaultTableModel;
|
||||||
|
|
||||||
import dev.kske.chess.board.Log;
|
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.Event;
|
||||||
import dev.kske.chess.event.EventBus;
|
import dev.kske.chess.event.EventBus;
|
||||||
import dev.kske.chess.event.MoveEvent;
|
import dev.kske.chess.event.MoveEvent;
|
||||||
@ -56,7 +57,7 @@ public class LogPanel extends JPanel implements Subscribable {
|
|||||||
public void handle(Event<?> event) {
|
public void handle(Event<?> event) {
|
||||||
if (log == null) return;
|
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];
|
String[][] data = new String[moves.size() / 2 + moves.size() % 2][2];
|
||||||
for (int i = 0; i < data.length; i++) {
|
for (int i = 0; i < data.length; i++) {
|
||||||
data[i][0] = moves.get(i * 2).move.toSAN();
|
data[i][0] = moves.get(i * 2).move.toSAN();
|
||||||
|
159
test/dev/kske/chess/board/LogTest.java
Normal file
159
test/dev/kske/chess/board/LogTest.java
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user