// The minimax algorithm itself private ScoreMovePair minimax(Dictionary <int, PieceState> board, int turn, int maxDepth, int currDepth, int prune, int moveCount) { // Checks if either at end of game state or as far down in the tree we are suppose to be. If so uses the // static evaluation method appropriate for diffulty settings if (isGameOver(board) || currDepth == maxDepth) { if (GameOptions.Instance.SMART) { if (currDepth % 2 == 0) { if (moveCount >= SWITCH_TIME) // If at the end of game try to maximize the number of pieces instead of playing position { return(new ScoreMovePair(-1, unweightedEvaluation(board, (turn)))); } else { return(new ScoreMovePair(-1, weightedEvaluation(board, (turn)))); } } else { if (moveCount >= SWITCH_TIME) // If at the end of game try to maximize the number of pieces instead of playing position { return(new ScoreMovePair(-1, unweightedEvaluation(board, (turn == 0) ? 1 : 0))); } else { return(new ScoreMovePair(-1, weightedEvaluation(board, (turn == 0) ? 1 : 0))); // uses positional strategy } } } else { if (maxDepth % 2 == 0) { return(new ScoreMovePair(-1, unweightedEvaluation(board, (turn)))); } else { return(new ScoreMovePair(-1, unweightedEvaluation(board, (turn == 0) ? 1 : 0))); } } } ScoreMovePair best = new ScoreMovePair(-1, 0); // Initialize best move to none if (turn == 0) // Turn is AI's { best.Score = int.MinValue; } else // Turn is player's { best.Score = int.MaxValue; } for (int i = 0; i < 60; i++) // Iterate through board positions { int id = (turn == 0) ? ordered[i] : reverseOrdered[i]; // If move not available skip if (board[id] != PieceState.NONE || !isViable(board, id, turn)) { continue; } // Create copy of board for new board Dictionary <int, PieceState> newBoard = new Dictionary <int, PieceState>(); foreach (KeyValuePair <int, PieceState> b in board) { newBoard.Add(b.Key, b.Value); } // Attempt a move and evaluate it if (MakeMove(newBoard, id, turn, false) == 0) { continue; } newBoard[id] = (turn == 0) ? PieceState.BLACK : PieceState.WHITE; ScoreMovePair current = minimax(newBoard, (turn == 0) ? 1 : 0, maxDepth, currDepth + 1, best.Score, moveCount + 1); if (turn == 0) // Maximize { if (current.Score > prune) { return(current); } if (current.Score > best.Score) { best.Score = current.Score; best.Move = id; } } else // Minimize { if (current.Score < prune) { return(current); } if (current.Score < best.Score) { best.Score = current.Score; best.Move = id; } } } return(best); }
private ScoreMovePair minimax(Dictionary <int, PieceState> board, int turn, int maxDepth, int currDepth, int prune) { if (isGameOver(board) || currDepth == maxDepth) { if (GameOptions.Instance.SMART) { return(new ScoreMovePair(-1, weightedEvaluation(board, (turn == 0) ? 1 : 0))); } else { return(new ScoreMovePair(-1, unweightedEvaluation(board, (turn == 0) ? 1 : 0))); } } ScoreMovePair best = new ScoreMovePair(-1, 0); // Initialize best move to none if (turn == 0) // Turn is AI's { best.Score = int.MinValue; } else // Turn is player's { best.Score = int.MaxValue; } for (int i = 0; i < 64; i++) // Iterate through board positions { // If move not available skip if (board[i] != PieceState.NONE) { continue; } // Create copy of board for new board Dictionary <int, PieceState> newBoard = new Dictionary <int, PieceState>(); foreach (KeyValuePair <int, PieceState> b in board) { newBoard.Add(b.Key, b.Value); } // Attempt a move and evaluate it if (MakeMove(newBoard, i, turn, false) == 0) { continue; } newBoard[i] = (turn == 0) ? PieceState.BLACK : PieceState.WHITE; ScoreMovePair current = minimax(newBoard, (turn == 0) ? 1 : 0, maxDepth, currDepth + 1, best.Score); if (turn == 0) // Maximize { if (current.Score > prune) { return(current); } if (current.Score > best.Score) { best.Score = current.Score; best.Move = i; } } else // Minimize { if (current.Score < prune) { return(current); } if (current.Score < best.Score) { best.Score = current.Score; best.Move = i; } } } return(best); }