我正在研究一個項目,嘗試創建一個神經網絡,它將學習如何使用NEAT玩跳棋。在我的跳棋遊戲中,我使用遞歸來查找特定棋子可以製作的所有可用棋步。通常運行程序,效果很好。長時間運行程序時遞歸導致的Java StackOverflowError
問題是當我運行試圖訓練神經網絡的程序部分時。在我的訓練計劃中,我運行無數跳棋遊戲(10000+)來嘗試發展我的神經網絡。訓練對於上千場比賽非常有用,但後來我遇到了一個由檢查可用動作的程序的遞歸部分引起的stackoverflow錯誤。這對我來說沒有任何意義,因爲這種方法對於前1000場比賽來說工作得很好,但最終總是會因爲一個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 Memory Analyzer顯示了這一點。
爲什麼垃圾收集器在我完成使用它們之後不會破壞arraylist和LegalMove對象?
後遞歸碼 – Aaron
是你的代碼,即拍即遞歸調用?如果是這樣,你有沒有考慮嘗試一種不同的非遞歸方法? – Obicere
你能發佈一些相關的代碼嗎?不是全部,只是遞歸的關鍵部分。 – degs