3

Explanation

I have a list of all possible current moves in a position. At each node, I want to then generate all possible moves and continue. The problem is that my code is modifying the list of moves in the node above. At least I think this is the case!

I am open to completely changing the way I handle moves, as I feel this isn't very efficient since I have a struct for every move.

Output

This is the current output.

PS D:\Users\kmont\Desktop\ChessEngine> dotnet run
Number of moves at depth 1 is 4. It is White's turn.
Number of moves at depth 2 is 4. It is Black's turn. Previous move was knight to a3
Unhandled exception. System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
    at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
    at System.Collections.Generic.List`1.Enumerator.MoveNext()
    at Program.search(Int32 depth, Board board, String prevMove) in D:\Users\kmont\Desktop\ChessEngine\Main\main.cs:line 55
    at Program.search(Int32 depth, Board board, String prevMove) in D:\Users\kmont\Desktop\ChessEngine\Main\main.cs:line 60
    at Program.Main(String[] args) in D:\Users\kmont\Desktop\ChessEngine\Main\main.cs:line 33

Code

The Move Struct:

public struct Move{
    public Piece.Type pieceType;
    public UInt64 piece;
    public UInt64 moveTo;
    public int color;

    public bool quiet;
    public UInt64 capturedPiece;
    public int capturedColor;
}

Search function:

public static void search(int depth, Board board, string prevMove = "nothing"){

    // If at the end of the tree, return.

    depth++;
    if (depth == maxDepth) return;

    Console.Write("Number of moves at depth {0} is {1}. It is {2}'s turn.", depth, board.allMoves.Count, board.color == 0 ? "White" : "Black");
    if (prevMove != "nothing") Console.WriteLine(" Previous move was knight to " + prevMove);
    else Console.WriteLine("");

    // Uncomment below line for a list of all possible moves.
    //if (true) foreach (Board.Move move in board.allMoves) Console.WriteLine(String.Format("    {0} {1} on square {2} can move to {3}.", move.color == 0 ? "White" : "Black", move.pieceType.ToString(), help.square(move.piece), help.square(move.moveTo)));

    foreach (Board.Move move in board.allMoves){
        Board newBoard = board;
        newBoard.color = 1 - board.color;
        initialiseBoard(newBoard);
        newBoard = makeMove(newBoard, move);
        search(depth, newBoard, help.square(move.moveTo));
    }
}

Make move function:

public static Board makeMove(Board board, Board.Move move){

    string moveColor = move.color == 0 ? "White" : "Black";
    string boardColor = board.color == 0 ? "White" : "Black";
    string pmove = help.square(move.moveTo);
    //Console.WriteLine(String.Format("    Making {0} move {2}: It is {1}'s turn.", moveColor, boardColor, pmove));
    
    Board toReturn = board;
    // Remove piece from board
    if (toReturn.color == 0 & move.color == 0){
        if (move.pieceType == Piece.Type.Knight){
            toReturn.WhiteKnightsBitboard &= ~move.piece; // Get rid of piece on board
            toReturn.WhiteKnightsBitboard |= move.moveTo; // Add piece to board
        }
    }
    else if (toReturn.color == 1 & move.color == 1){
        if (move.pieceType == Piece.Type.Knight){
            toReturn.BlackKnightsBitboard &= ~move.piece;
            toReturn.BlackKnightsBitboard |= move.moveTo;
        }
    }

    Game.node++; // To count nodes
    return toReturn;

}

Initialise Board function:

static void initialiseBoard(Board board){
    BoardOperations.updatePieces(board); // Sets all pieces and finds empty squares 
    board.generateAttackSquares(board);  // Finds white knight moves and puts them into board.allMoves
}
5

The issue may be here:

Board newBoard = board;

This creates a new variable, but it doesn't actually create a new Board. board and newBoard are pointing to the exact same Board object. So, when your code changes anything in newBoard, it also changes it in board, and when it changes, you get this error.

What you may want to do is make an actual copy of board, so when you change it, it doesn't change the original.

| improve this answer | |
  • That's strange, but I can see how it makes sense. How would I make a copy? Would I have to start with Board newBoard = new Board(); then copy over all components? Is there an easier way to do this? Is this efficient too? Thank you very much! – Kieran Montgomery Jul 4 at 17:26
  • Thank you very much! I just made my own and this fixed the problem. I will look into performance soon! – Kieran Montgomery Jul 4 at 17:39
  • Yes, that's pretty much it, unless you have an easier way of making a new Board or there's already a built-in copy function. Also note that those components themselves may need to be copied, because the same thing might happen. newBoard.someObject = board.someObject would make someObject be literally the same object in both. – D M Jul 4 at 17:39
  • I don't know what the Board class looks like, but presumably you're going to want to add a Copy method to it, and you might be able to implement such a method like so: public Board Copy() { return MemberwiseClone(); } – Tanner Swett Jul 7 at 19:48
  • alternatively you could add an undoMove function to put the board back the way it was. You would call it after search in your for-loop. – Jeff Wilson Jul 8 at 17:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.