所以我正在尝试为奥赛罗游戏实施蒙特卡罗搜索树。我有一个根节点和子节点,其中' x'是一个孩子的“孩子”。如果你可以从' y'到' x'在一次合法的举动中。
在每个节点,我都会存储一个' Board'保存所有电路板信息的对象,例如每个磁贴的值。我遇到的第一个问题是,如果我更改了子节点的board对象,它也会更改父节点的值。我通过创建一个新的'来解决这个问题。每个子节点的Board对象,但这导致在我运行模拟几千次时使用了过多的内存,直至我内存不足。
如果有一种方法可以改变子节点中的板信息而不改变父节点的板信息,或者如果有更好的方法在每个节点上存储板信息而不是创建每个节点都有一个新的Board对象。
如果有任何需要澄清下面的评论,感谢阅读!
编辑:
for (int x = 0; x < numberOfChildren; x += 1) {
// Resets *currentBoard to the same state as the node being expanded
Board *currentBoard = nodeToExpand->getCurrentBoard();
// Retrives the board value information
int** temporaryBoardValues = currentBoard->getBoardValues();
// Makes a new board object with the previous parameters
Board *temporaryBoard = new Board(blockSize, boardSize, offset);
// Sets the new board values to the same as the old ones
temporaryBoard->setBoardValues(temporaryBoardValues);
// Creates a clone of that board state
// Board *temporaryBoard = cloneBoard(*currentBoard);
// Creates a node with the cloned board state, setting the parent to be the node being expanded.
// Assigns it one of the available moves
// Produces the array of child nodes
myChildren[x] = new Node(nodeToExpand, temporaryBoard, availableMoves[x], currentPlayer);
//delete temporaryBoard;
}
小代码段。它是我创建一个耗尽所有内存的新Board对象的部分。
答案 0 :(得分:1)
蒙特卡罗树搜索(MCTS)的典型实现不使用任何技巧来明确避免内存不足。从理论上讲,如果你继续模拟,你确实会耗尽内存,但这通常需要的不仅仅是你在OP中提到的几千个模拟。
现在,MCTS的大多数实现仅在每次模拟时将树扩展一个节点。您发布的代码看起来像每个模拟将b
节点添加到树中,其中b
是分支因子(子节点数)。所以这是你可以考虑改变的东西。
此外,你可以看一下你在Board课程中存储的内容,并确保你真的只有那里必要的内容而已。只是游戏状态的数据,仅此而已。例如,确保你没有任何只有GUI需要的数据(这是我多年前犯的错误)。
如果在查看这两点后仍然存在内存问题,可以考虑jaggedSpire评论的建议。您可以存储移动而不是板状态,并在模拟中运行节点时重新构建板状态。这将显着降低您的内存消耗,但也会增加每次模拟的处理时间。如果你每回合只有有限的思考时间,这可能导致一个较弱的玩家。
最后,考虑到你使用我在你发布的代码中看到的new
操作进行手动内存管理,你总是有可能忘记在某个地方匹配delete
并且有记忆泄漏。如果在查看上述几点后仍然只有几千个模拟的内存问题,这是最可能的原因,因为MCTS确实不应该遇到内存问题,直到你达到比几千个更高的模拟计数。