Java | コピーを使った Undo 機能

Java Java
スポンサーリンク

では「ゲーム盤面を題材にした実践的なUndo/Redo」の例を紹介します。ここでは オセロや将棋のような盤面を配列で表現し、Undo/Redoで一手戻す/やり直す 仕組みを作ります。


シナリオ

  • 盤面を 2次元配列 で表現(例: 3×3の簡易ボード)。
  • プレイヤーが「手」を打つたびに盤面を更新。
  • 更新前の盤面を 履歴(undoStack) に保存。
  • Undoで1手前に戻り、Redoでやり直しができる。

コード例:ゲーム盤面のUndo/Redo

import java.util.*;

public class GameBoardUndoRedo {
    public static void main(String[] args) {
        // 3x3の盤面(0=空, 1=プレイヤーX, 2=プレイヤーO)
        int[][] board = new int[3][3];

        List<int[][]> undoStack = new ArrayList<>();
        List<int[][]> redoStack = new ArrayList<>();

        // 初期状態を保存
        undoStack.add(deepCopy(board));

        // ---- プレイヤーの手 ----
        board[0][0] = 1; // Xが左上に置く
        undoStack.add(deepCopy(board));

        board[1][1] = 2; // Oが中央に置く
        undoStack.add(deepCopy(board));

        board[2][2] = 1; // Xが右下に置く
        undoStack.add(deepCopy(board));

        System.out.println("現在の盤面:");
        printBoard(board);

        // ---- Undo ----
        board = undo(board, undoStack, redoStack);
        System.out.println("Undo後:");
        printBoard(board);

        board = undo(board, undoStack, redoStack);
        System.out.println("さらにUndo後:");
        printBoard(board);

        // ---- Redo ----
        board = redo(board, undoStack, redoStack);
        System.out.println("Redo後:");
        printBoard(board);

        board = redo(board, undoStack, redoStack);
        System.out.println("さらにRedo後:");
        printBoard(board);
    }

    // 深いコピー(2次元配列)
    private static int[][] deepCopy(int[][] src) {
        int[][] copy = new int[src.length][];
        for (int i = 0; i < src.length; i++) {
            copy[i] = Arrays.copyOf(src[i], src[i].length);
        }
        return copy;
    }

    // Undo処理
    private static int[][] undo(int[][] state, List<int[][]> undoStack, List<int[][]> redoStack) {
        if (undoStack.size() > 1) {
            redoStack.add(deepCopy(state));
            undoStack.remove(undoStack.size() - 1);
            return deepCopy(undoStack.get(undoStack.size() - 1));
        }
        return state;
    }

    // Redo処理
    private static int[][] redo(int[][] state, List<int[][]> undoStack, List<int[][]> redoStack) {
        if (!redoStack.isEmpty()) {
            int[][] redoState = redoStack.remove(redoStack.size() - 1);
            undoStack.add(deepCopy(redoState));
            return redoState;
        }
        return state;
    }

    // 盤面表示
    private static void printBoard(int[][] board) {
        for (int[] row : board) {
            for (int cell : row) {
                char mark = (cell == 0) ? '.' : (cell == 1 ? 'X' : 'O');
                System.out.print(mark + " ");
            }
            System.out.println();
        }
        System.out.println();
    }
}
Java

実行イメージ

現在の盤面:
X . .
. O .
. . X

Undo後:
X . .
. O .
. . .

さらにUndo後:
X . .
. . .
. . .

Redo後:
X . .
. O .
. . .

さらにRedo後:
X . .
. O .
. . X

応用ポイント

  • オセロや将棋: 盤面を配列で管理すれば、Undo/Redoで「一手戻す/やり直す」が可能。
  • 複雑なゲーム: 盤面だけでなく「手番」「スコア」なども一緒にコピーすれば完全な履歴管理ができる。
  • GUIゲーム: この仕組みをGUIに組み込めば「戻るボタン」「やり直すボタン」が作れる。

✅ これで「ゲーム盤面を題材にした実践的なUndo/Redo」の完成版です。

Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました