我在Java中为一种变体的野生井字游戏实现了极小化极大算法,但遇到了一个问题。我有一个Node类,用于保存游戏网格和一个包含其子节点的Node对象的ArrayList,以及一个递归实现该算法的极小化极大方法。
我得到的错误是:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at Grid.<init>(Grid.java:35) at MiniMax$Node.findChildren(MiniMax.java:27) at MiniMax.minimax(MiniMax.java:135) at MiniMax.minimax(MiniMax.java:126) at MiniMax.minimax(MiniMax.java:139) at MiniMax.minimax(MiniMax.java:126) at MiniMax.minimax(MiniMax.java:139) at MiniMax.minimax(MiniMax.java:126) at MiniMax.minimax(MiniMax.java:139) at MiniMax.nextMove(MiniMax.java:77) at ComputerPlayer.play(ComputerPlayer.java:12) at TicTacToe.main(TicTacToe.java:146)Process finished with exit code 1
我认为问题出在每次递归创建并存储到ArrayList中的子节点数量过多(总节点数:2^8 * 8!)。
这是Node类:
private static class Node { protected Grid grid; protected ArrayList<Node> children; public Node(Grid grid) { this.grid = grid; children = new ArrayList<>(); } //查找所有可能的下一步 public void findChildren() { char[][] board = grid.getGrid(); for(int i = 0; i < board.length; i++) { for(int j = 0; j < board.length; j++) { if(board[i][j] == ' ') { board[i][j] = 'X'; children.add(new Node(new Grid(board))); board[i][j] = 'O'; children.add( new Node(new Grid(board))); board[i][j] = ' '; } } } } }
这是极小化极大算法的实现:
private int minimax(Node state, int depth, boolean isMaximizer) { //如果游戏处于终止状态或已达到预定深度 boolean someoneWon = state.grid.someoneHasWon(); boolean isDraw = state.grid.isDraw(); if(someoneWon || isDraw || depth == 3) { return evaluateState(someoneWon, isDraw, !isMaximizer);//评估状态 } //MAX玩家的回合 if(isMaximizer) { //查找所有可能状态的最高分数 int bestScore = Integer.MIN_VALUE; state.findChildren(); for(int i = 0; i < state.children.size(); i++) { Node child = state.children.get(i); int score = minimax(child, depth + 1, false); bestScore = Math.max(bestScore, score); } return bestScore; } else//MIN玩家的回合 { //查找所有可能移动的最低分数 int bestScore = Integer.MAX_VALUE; state.findChildren(); for(int i = 0; i < state.children.size(); i++) { Node child = state.children.get(i); int score = minimax(child, depth + 1, true); bestScore = Math.min(bestScore, score); } return bestScore; } }
回答:
不要创建子节点列表,而是将迭代移到Node
类中(或等效类)。你会发现不需要每次都创建一个新棋盘 – 只需在完成后替换你更改的状态即可。