/// <summary> /// The main game loop. plays while both kings are still standing. /// </summary> public void GameLoop() { DisplayGameBoard(); SmartAgent myAgent = new SmartAgent(); while (FindKings()) { if (currentTurn) { // List<PotentialMove> chosenMoveList = myAgent.MiniMaxDecision(board, 6, currentTurn, null, null, -999, 999); // PotentialMove chosenMove = chosenMoveList[chosenMoveList.Count - 2]; // ValidateFieldAndPiece(chosenMove.PreviousPosition[0], chosenMove.PreviousPosition[1], chosenMove.NewPosition[0], chosenMove.NewPosition[1]); PlayTurn(); DisplayGameBoard(); } else { List <PotentialMove> chosenMoveList = myAgent.MiniMaxDecision(board, 6, currentTurn, null, null, -999, 999); PotentialMove chosenMove = chosenMoveList[chosenMoveList.Count - 2]; ValidateFieldAndPiece(chosenMove.PreviousPosition[0], chosenMove.PreviousPosition[1], chosenMove.NewPosition[0], chosenMove.NewPosition[1]); DisplayGameBoard(); Console.WriteLine("Player " + currentTurn + " brought piece from field " + chosenMove.PreviousPosition[0] + "," + chosenMove.PreviousPosition[1] + " to field " + chosenMove.NewPosition[0] + "," + chosenMove.NewPosition[1]); } currentTurn = !currentTurn; } DisplayGameBoard(); }
/// <summary> /// The recursive function to pick a move using the minimax algorithm /// </summary> /// <param name="currentState">The current gameboard's state</param> /// <param name="depth">the depth of the recursive calls</param> /// <param name="currentPlayer">The player currently playing</param> /// <param name="previousPosition">The previous position of the piece that moved in the last round</param> /// <param name="newPosition">The new position of the piece that moved in the last round</param> /// <param name="bestAlpha">The best move alpha could make. Used for pruning</param> /// <param name="bestBeta">The best move beta could make. Used for pruning</param> /// <returns>the list of optimal moves</returns> public List <PotentialMove> MiniMaxDecision(Piece[,] currentState, int depth, bool currentPlayer, int[] previousPosition, int[] newPosition, int bestAlpha, int bestBeta) { List <PotentialMove> possibleActions, evalList; List <PotentialMove> bestAction = new List <PotentialMove>(); List <int> possibleActionsEvaluation = new List <int>(); if (depth == 0) { PotentialMove move = new PotentialMove(previousPosition, newPosition, currentState); List <PotentialMove> returnList = new List <PotentialMove>(); returnList.Add(move); return(returnList); } else if (currentPlayer) { int maxEval = -999; possibleActions = ListAllPossibleActions(currentState, currentPlayer); foreach (var v in possibleActions) { evalList = MiniMaxDecision(v.CurrentState, depth - 1, !currentPlayer, v.PreviousPosition, v.NewPosition, bestAlpha, bestBeta); PotentialMove eval = evalList[evalList.Count - 1]; if (CountUtility(eval.CurrentState) > maxEval) { evalList.Add(new PotentialMove(previousPosition, newPosition, currentState)); bestAction = evalList; maxEval = CountUtility(eval.CurrentState); } if (bestAlpha < CountUtility(eval.CurrentState)) { bestAlpha = CountUtility(eval.CurrentState); } if (bestBeta <= bestAlpha) { break; } } return(bestAction); } else { int minEval = 999; possibleActions = ListAllPossibleActions(currentState, currentPlayer); foreach (var v in possibleActions) { evalList = MiniMaxDecision(v.CurrentState, depth - 1, !currentPlayer, v.PreviousPosition, v.NewPosition, bestAlpha, bestBeta); PotentialMove eval = evalList[evalList.Count - 1]; if (CountUtility(eval.CurrentState) < minEval) { evalList.Add(new PotentialMove(previousPosition, newPosition, currentState)); bestAction = evalList; minEval = CountUtility(eval.CurrentState); } if (bestBeta > CountUtility(eval.CurrentState)) { bestBeta = CountUtility(eval.CurrentState); } if (bestBeta <= bestAlpha) { break; } } return(bestAction); } }