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;