【发布时间】:2017-02-13 06:56:35
【问题描述】:
我正在做一个项目来尝试创建一个神经网络,该网络将学习如何使用 NEAT 下跳棋。在我的跳棋游戏中,我使用递归来查找特定棋子可以做出的所有可用动作。正常运行程序,效果很好。
问题是当我运行试图训练神经网络的程序部分时。在我的训练计划中,我运行了无数的跳棋游戏(10000+)来尝试进化我的神经网络。训练在前一千场左右的比赛中效果很好,但随后我遇到了堆栈溢出错误,这是由检查可用动作的程序的递归部分引起的。这对我来说毫无意义,因为该方法在前一千场左右的游戏中运行良好,但它最终总是会因 stackoverflow 错误而崩溃。
编辑:这是递归方法的主要概述,我删除了很多 if 语句。另外,对于本文的篇幅,我深表歉意,我可能本可以以更易读和更有效的方式实现。
private void checkAvailableTilesRecursion(GameBoardTile oldTile, LegalMove newMove) {
ArrayList<LegalMove> recursiveCheck = new ArrayList<>();
// Find available pieces if piece is king
if (!edgePiece) {
// Code to get the different tiles adjacent to this tile
if (legalMoveCheckerPiece.getIsKing()) {
// Up right
// If the tile up right is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() + 2], newMove, null, upRight, MoveDirections.UP_RIGHT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move); // defined elsewhere
recursiveCheck.add(move);
}
// Up left
// If the tile up left is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() - 2], newMove, null, upLeft, MoveDirections.UP_LEFT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move); // defined elsewhere
recursiveCheckRecursive.add(move);
}
// Down right
// If tile down right is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() + 2], newMove, null, downRight, MoveDirections.DOWN_RIGHT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move); // defined elsewhere
recursiveCheckRecursive.add(move);
}
//Down left
// If tile down left is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() - 2], newMove, null, downLeft, MoveDirections.DOWN_LEFT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move); // defined elsewhere
recursiveCheckRecursive.add(move);
}
} else {
// Find available tiles for normal pieces
if (legalMoveCheckerPiece.getColor() == PieceColors.BLUE) {
// Up right
// If tile up right is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() + 2], newMove, null, upRight, MoveDirections.UP_RIGHT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move);
recursiveCheckRecursive.add(move);
}
// Up left
// If tile up left is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() - 2][newMove.returnNewX() - 2], newMove, null, upLeft, MoveDirections.UP_LEFT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move);
recursiveCheckRecursive.add(move);
}
} else {
// Red Team
// Down right
// If tile down right is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() + 2], newMove, null, downRight, MoveDirections.DOWN_RIGHT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move);
recursiveCheckRecursive.add(move);
}
//Down left
// If tile down left is clear
LegalMove move = new LegalMove(newMove.getNewTile(), board.getTile()[newMove.returnNewY() + 2][newMove.returnNewX() - 2], newMove, null, downLeft, MoveDirections.DOWN_LEFT);
newMove.setMoveAfter(move);
availableLegalMoves.add(move);
recursiveCheckRecursive.add(move);
}
}
}
}
if (recursiveCheckRecursive.size() > 0) {
for (LegalMove moveToCheck : recursiveCheckRecursive) {
checkAvailableTilesRecursion(newMove.getNewTile(), moveToCheck);
}
}
}
编辑#2:我认为这与内存泄漏有关。我正在使用 Intellij 调试工具,而 Intellij 内存分析器显示了这一点。
为什么垃圾收集器不会在我使用完数组列表和 LegalMove 对象后销毁它们?
【问题讨论】:
-
贴出递归代码
-
是您的代码在进行递归调用吗?如果是这样,您是否考虑过尝试不同的非递归方法?
-
你能发布一些相关的代码吗?不是全部,只是递归的关键部分。
-
您是否考虑过跳棋游戏可能是无限的(或者至少真的很长)?考虑每边的一个王牌,它来回移动而不会互相跳跃。检查游戏长度并考虑修剪超出合理移动计数的游戏。
-
该代码绝对可以以非递归方式完成。考虑更改算法以避免递归调用。它可能最终也会快一吨。
标签: java recursion stack-overflow