Fixed LogPanel to support new log data model

This commit is contained in:
Kai S. K. Engelbart 2019-09-23 17:37:42 +02:00
parent 69261303c5
commit ff3f064a7f
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
4 changed files with 119 additions and 27 deletions

View File

@ -1,8 +1,10 @@
package dev.kske.chess.board;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import dev.kske.chess.board.Log.MoveNode;
import dev.kske.chess.board.Piece.Color;
/**
@ -11,7 +13,7 @@ import dev.kske.chess.board.Piece.Color;
* Created: <strong>09.07.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class Log {
public class Log implements Iterable<MoveNode> {
private MoveNode root, current;
@ -46,6 +48,28 @@ public class Log {
}
}
@Override
public Iterator<MoveNode> iterator() {
return new Iterator<MoveNode>() {
private MoveNode current = root;
private boolean hasNext = true;
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public MoveNode next() {
MoveNode result = current;
if (current.hasVariations()) current = current.variations.get(0);
else hasNext = false;
return result;
}
};
}
/**
* Adds a move to the move history and adjusts the log to the new position.
*
@ -75,18 +99,19 @@ public class Log {
* move.
*/
public void removeLast() {
if (!isEmpty() && current.parent != null) {
if (hasParent()) {
current.parent.variations.remove(current);
current = current.parent;
activeColor = current.activeColor;
enPassant = current.enPassant;
fullmoveCounter = current.fullmoveCounter;
halfmoveClock = current.halfmoveClock;
update();
} else reset();
}
public boolean isEmpty() { return root == null; }
public boolean hasParent() {
return !isEmpty() && current.parent != null;
}
/**
* Reverts the log to its initial state corresponding to the default board
* position.
@ -100,6 +125,44 @@ public class Log {
halfmoveClock = 0;
}
/**
*
* @param index
*/
public void selectNextNode(int index) {
if (!isEmpty() && current.variations != null && index < current.variations.size()) {
current = current.variations.get(index);
update();
}
}
/**
* Selects the parent of the current {@link MoveNode} as the current node.
*/
public void selectPreviousNode() {
if (hasParent()) {
current = current.parent;
update();
}
}
/**
* Selects the root {@link MoveNode} as the current node.
*/
public void selectRootNode() {
if (!isEmpty()) {
current = root;
update();
}
}
private void update() {
activeColor = current.activeColor;
enPassant = current.enPassant;
fullmoveCounter = current.fullmoveCounter;
halfmoveClock = current.halfmoveClock;
}
/**
* @return The first logged move, or {@code null} if there is none
*/
@ -196,5 +259,9 @@ public class Log {
* @return A list of all variations associated with this {@link MoveNode}
*/
public List<MoveNode> getVariations() { return variations; }
public boolean hasVariations() {
return variations != null && variations.size() > 0;
}
}
}

View File

@ -80,8 +80,6 @@ public class Game {
// Run garbage collection
System.gc();
System.out.printf("%s: %s%n", player.color, move);
System.out.println("FEN: " + board.toFEN());
EventBus.getInstance().dispatch(new MoveEvent(move));
GameState eventType = board.getGameEventType(board.getDest(move).getColor().opposite());
switch (eventType) {

View File

@ -28,6 +28,10 @@ public class GamePane extends JComponent {
private LogPanel logPanel;
private Game game;
private Color activeColor;
private JPanel moveSelectionPanel;
private JButton btnNext;
private JButton btnFirst;
private JButton btnLast;
public GamePane() {
activeColor = Color.WHITE;
@ -35,8 +39,8 @@ public class GamePane extends JComponent {
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[] { 450, 1, 0 };
gridBagLayout.rowHeights = new int[] { 33, 267, 1, 0 };
gridBagLayout.columnWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE };
gridBagLayout.rowWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE };
gridBagLayout.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
gridBagLayout.rowWeights = new double[] { 1.0, 0.0, 0.0, Double.MIN_VALUE };
setLayout(gridBagLayout);
JPanel toolPanel = new JPanel();
@ -58,7 +62,31 @@ public class GamePane extends JComponent {
gbc_toolPanel.fill = GridBagConstraints.HORIZONTAL;
gbc_toolPanel.gridx = 0;
gbc_toolPanel.gridy = 0;
gbc_toolPanel.gridwidth = 2;
add(toolPanel, gbc_toolPanel);
moveSelectionPanel = new JPanel();
GridBagConstraints gbc_moveSelectionPanel = new GridBagConstraints();
gbc_moveSelectionPanel.fill = GridBagConstraints.BOTH;
gbc_moveSelectionPanel.gridx = 2;
gbc_moveSelectionPanel.gridy = 0;
add(moveSelectionPanel, gbc_moveSelectionPanel);
btnFirst = new JButton("First");
btnFirst.setEnabled(false);
moveSelectionPanel.add(btnFirst);
JButton btnPreviousMove = new JButton("Previous");
btnPreviousMove.setEnabled(false);
moveSelectionPanel.add(btnPreviousMove);
btnNext = new JButton("Next");
btnNext.setEnabled(false);
moveSelectionPanel.add(btnNext);
btnLast = new JButton("Last");
btnLast.setEnabled(false);
moveSelectionPanel.add(btnLast);
boardPane = new BoardPane();
GridBagConstraints gbc_boardPane = new GridBagConstraints();
gbc_boardPane.fill = GridBagConstraints.BOTH;
@ -97,6 +125,7 @@ public class GamePane extends JComponent {
gbc_logPanel.fill = GridBagConstraints.VERTICAL;
gbc_logPanel.gridx = 2;
gbc_logPanel.gridy = 1;
gbc_logPanel.gridheight = 2;
add(logPanel, gbc_logPanel);
}

View File

@ -1,10 +1,9 @@
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;
import java.util.Iterator;
import java.util.Set;
import javax.swing.JPanel;
@ -53,18 +52,17 @@ public class LogPanel extends JPanel implements Subscribable {
return new HashSet<>(Arrays.asList(MoveEvent.class));
}
// TODO: Implement support for variation selection
@Override
public void handle(Event<?> event) {
if (log == null) return;
// TODO: Display log with variations
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();
if (i * 2 + 1 < moves.size()) data[i][1] = moves.get(i * 2 + 1).move.toSAN();
if (log == null || log.isEmpty()) return;
final DefaultTableModel model = new DefaultTableModel(new String[] { "White", "Black" }, 0);
for (Iterator<MoveNode> iter = log.iterator(); iter.hasNext();) {
String[] row = new String[] { iter.next().move.toSAN(), "" };
if (iter.hasNext()) row[1] = iter.next().move.toSAN();
model.addRow(row);
}
mtable.setModel(new DefaultTableModel(data, new String[] { "White", "Black" }));
mtable.setModel(model);
}
public Log getLog() { return log; }