diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java
index 28d6cca..c634dff 100644
--- a/src/dev/kske/chess/board/Board.java
+++ b/src/dev/kske/chess/board/Board.java
@@ -8,6 +8,8 @@ import java.util.Map;
import java.util.Objects;
import dev.kske.chess.board.Piece.Color;
+import dev.kske.chess.event.EventBus;
+import dev.kske.chess.event.MoveEvent;
/**
* Project: Chess
@@ -120,6 +122,32 @@ public class Board {
log.removeLast();
}
+ public void selectPreviousNode() {
+ MoveNode moveNode = log.getLast();
+ Move move = moveNode.move;
+
+ // Revert the move
+ move.revert(this, moveNode.capturedPiece);
+
+ // Select previous move node
+ log.selectPreviousNode();
+
+ // Dispatch move event
+ EventBus.getInstance().dispatch(new MoveEvent(move.invert(), getGameEventType(log.getActiveColor().opposite())));
+ }
+
+ public void selectNextNode(int index) {
+ log.selectNextNode(index);
+ MoveNode moveNode = log.getLast();
+ Move move = moveNode.move;
+
+ // Execute the next move
+ move.execute(this);
+
+ // Dispatch move event
+ EventBus.getInstance().dispatch(new MoveEvent(move, getGameEventType(log.getActiveColor().opposite())));
+ }
+
/**
* Generated every legal move for one color
*
diff --git a/src/dev/kske/chess/board/Move.java b/src/dev/kske/chess/board/Move.java
index 2ff63e2..267f53e 100644
--- a/src/dev/kske/chess/board/Move.java
+++ b/src/dev/kske/chess/board/Move.java
@@ -43,6 +43,10 @@ public class Move {
board.set(pos, board.get(dest));
board.set(dest, capturedPiece);
}
+
+ public Move invert() {
+ return new Move(dest, pos);
+ }
public static Move fromLAN(String move) {
Position pos = Position.fromLAN(move.substring(0, 2));
diff --git a/src/dev/kske/chess/game/Game.java b/src/dev/kske/chess/game/Game.java
index 2005cd0..b3f5171 100644
--- a/src/dev/kske/chess/game/Game.java
+++ b/src/dev/kske/chess/game/Game.java
@@ -29,7 +29,7 @@ import dev.kske.chess.ui.OverlayComponent;
*/
public class Game {
- private Map players = new HashMap<>();
+ private Map players = new HashMap<>(2);
private Board board;
private OverlayComponent overlayComponent;
private BoardComponent boardComponent;
diff --git a/src/dev/kske/chess/ui/GamePane.java b/src/dev/kske/chess/ui/GamePane.java
index b8bf02d..2b542eb 100644
--- a/src/dev/kske/chess/ui/GamePane.java
+++ b/src/dev/kske/chess/ui/GamePane.java
@@ -12,6 +12,7 @@ import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
@@ -95,11 +96,29 @@ public class GamePane extends JComponent {
moveSelectionPanel.add(btnFirst);
btnPrevious = new JButton("Previous");
- btnPrevious.setEnabled(false);
+ btnPrevious.addActionListener((evt) -> {
+ if (game != null) {
+ game.getBoard().selectPreviousNode();
+ getBoardPane().getOverlayComponent().clearArrow();
+ repaint();
+ }
+ });
moveSelectionPanel.add(btnPrevious);
btnNext = new JButton("Next");
- btnNext.setEnabled(false);
+ btnNext.addActionListener((evt) -> {
+ if(game != null) {
+ int numVariations = game.getBoard().getLog().getLast().getVariations().size();
+ int index;
+ if(numVariations == 1)
+ index = 1;
+ else
+ index = Integer.parseInt(JOptionPane.showInputDialog("Enter the variation index."));
+ game.getBoard().selectNextNode(index);
+ getBoardPane().getOverlayComponent().clearArrow();
+ repaint();
+ }
+ });
moveSelectionPanel.add(btnNext);
btnLast = new JButton("Last");
diff --git a/src/dev/kske/chess/ui/MoveNodeRenderer.java b/src/dev/kske/chess/ui/MoveNodeRenderer.java
index f78bea5..7553052 100644
--- a/src/dev/kske/chess/ui/MoveNodeRenderer.java
+++ b/src/dev/kske/chess/ui/MoveNodeRenderer.java
@@ -26,7 +26,10 @@ public class MoveNodeRenderer extends JLabel implements ListCellRenderer list, MoveNode node, int index,
boolean isSelected, boolean cellHasFocus) {
setBorder(new EmptyBorder(5, 5, 5, 5));
- setText(node.move.toLAN());
+
+ int numVariations = node.hasVariations() ? node.getVariations().size() : 0;
+ setText(String.format("%s (%d)", node.move.toLAN(), numVariations));
+
setBackground(isSelected ? Color.red : Color.white);
setOpaque(true);
return this;