// Sets a Token on a Field from the given Move on the GameField // (The Validation is handled via button enabling. // There the placement is allowed!) // Return the winner or null public Player?SetTokenOnField(Move move) { Player?winner = null; // Only do something when token is not covered if (!TokenIsCovered(move.Token)) { // Remove the Token if it's on an upper Field RemoveTokenFromField(move.Token); // Check if the Field is empty if (GameField.ContainsKey(move.Field)) { // Compare with the upper Token on the Field if (System.Convert.ToInt32(move.Token.tag) > System.Convert.ToInt32(GameField[move.Field].Peek().tag)) { // Place the Token on the highest position of the Field GameField[move.Field].Push(move.Token); } } else { Stack <GameObject> tokenStack = new Stack <GameObject>(); tokenStack.Push(move.Token); // Place the Token on the Field GameField.Add(move.Field, tokenStack); } // Check if game is won with the converted state of string tokens winner = WinDetection.CheckWinner(TypeConverter.ConvertState(GameField)); } return(winner); }
// The recursive alpha beta function // Checks every possible move for every recursion step (depth) // Stops the search by the alpha and beta cap value // Optimization: Checks for win or loose when depth is not reached yet // Returns the value for the root move, calculated by the evaluation function private static int AlphaBeta(int depth, StringState state, Player player, int alpha, int beta) { // Optimization: Checks for win or loose when depth is not reached yet // It is not necessary to look any further if win or loose // The earlier the detection the higher the value if (depth > 0) { // Check for the winner (may be empty) Player?winner = WinDetection.CheckWinner(state); // Has the ai won the game? if (winner == Constants.AI_PLAYER) { // Return high value (like 1000) // The higher the left recursion count the better the value return(1000 * Constants.AI_DEPTH); } // Has the ai lost the game? if (winner == TypeConverter.GetOpponent(Constants.AI_PLAYER)) { // Return low value (like -1000) // The higher the left recursion count the lower the value return(-1000 * Constants.AI_DEPTH); } } // Otherwise the depth is reached (last recursion step) else { // Evaluate the leaf return(EvaluateState(state, player)); } // Switch player after win detection // After evaluation this won't be necessary anymore // But eval has to be calculated for the player for which the current recursion call was made player = TypeConverter.GetOpponent(player); // Get all possible moves for the current state and player List <MoveString> possibleMoves = GetPossibleMoves(state, player); // If the Player is the ai the vale will be maxed if (player == Constants.AI_PLAYER) { // Start with lowest possible value int bestValue = int.MinValue; // Iterate through each possible move foreach (MoveString move in possibleMoves) { // Generate a new reference state with the move on the previous state StringState moveState = GetStateWithMove(state, move); // Check for the highest value in the recursion bestValue = Math.Max(bestValue, AlphaBeta(depth - 1, moveState, player, alpha, beta)); // Alpha beta Pruning alpha = Math.Max(alpha, bestValue); if (beta <= alpha) { return(bestValue); } } return(bestValue); } // Otherwise the value will be minned for the opponent else { // Start with highest possible value int bestValue = int.MaxValue; // Iterate through each possible move foreach (MoveString move in possibleMoves) { // Generate a new reference state with the move on the previous state StringState moveState = GetStateWithMove(state, move); // Check for the lowest value in the recursion bestValue = Math.Min(bestValue, AlphaBeta(depth - 1, moveState, player, alpha, beta)); // Alpha beta Pruning beta = Math.Min(beta, bestValue); if (beta <= alpha) { return(bestValue); } } return(bestValue); } }