I am working on a project to try and create a neural net that will learn how to play checkers using NEAT. In my checkers game, I use recursion to find all the available moves a specific piece can make. Running the program normally, it works great.
The problem is when I run the part of the program that tries to train the neural network. In my training program, I run countless checkers games (10000+) to try to evolve my neural network. Training works great for the first thousand games or so, but then I get hit with a stackoverflow error that is caused from the recursion part of the program that checks for available moves. This makes no sense to me as the method works fine for the first thousand games or so, but it always eventually breaks down with a stackoverflow error.
EDIT: Here is the main overview of the recursive method I cut out a lot of the if statements. Also, I apologize for the length of this, I probably could have implemented in a more readable and efficient way.
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);
}
}
}
EDIT #2: I think this has to do something with a memory leak. I was using the Intellij Debug tool and the Intellij Memory Analyzer showed this.
Why wouldn't the garbage collector destroy the arraylists and LegalMove objects after I am done using them though?