private List <float> GetHardWeights(AIBoard board) { float p1spWeight = 1f; float p2spWeight = 1f; //Variables used in weight calculations. int playerOneSP = BoardAnalysis.FindShortestPath(board, true); int playerTwoSP = BoardAnalysis.FindShortestPath(board, true); int playerTwoNumWalls = CurrentBoard.GetPlayerTwoNumWalls(); int distanceBetweenPlayers = BoardAnalysis.FindDistanceBetween(CurrentBoard, CurrentBoard.GetPlayerOnePos(), CurrentBoard.GetPlayerTwoPos()); if (playerOneSP - playerTwoSP > 2) { p1spWeight = 5; } else if (playerOneSP < 5) { p1spWeight = 2; } List <float> w = new List <float> { p1spWeight, p2spWeight }; return(w); }
public WallDiffNode(AIBoard copy) { Board = new AIBoard(copy); Depth = 0; MoveMade = "rootnode"; Diff = BoardAnalysis.FindShortestPath(Board, true) - BoardAnalysis.FindShortestPath(Board, false); }
public override void StartGame(Dictionary <PlayerInfo, int> allPlayersAndScores) { _turnAdviser = new TurnAdviser { MyId = Info.ID }; _boardAnalysis = new BoardAnalysis { MyId = Info.ID }; }
//This returns all walls adjacent to the wall move made in public List <WallDiffNode> GetChildren() { List <WallDiffNode> children = new List <WallDiffNode>(); List <string> adjacentWalls = DictionaryLookup.PerformWallsOfInterestLookup(MoveMade); foreach (string wall in adjacentWalls) { AIBoard tempBoard = new AIBoard(Board); tempBoard.MakeMove(wall); if (BoardAnalysis.CheckPathExists(tempBoard, true) && BoardAnalysis.CheckPathExists(tempBoard, false)) { children.Add(new WallDiffNode(this, wall)); } } return(children); }
//Constructs a list of treenodes that result from every move made that is possible. //Pruning function (SetNodesOfInterest) will cut of many nodes that are not of interest. public List <TreeNode> GetChildren() { List <TreeNode> children = new List <TreeNode>(); foreach (string move in Board.GetPawnMoves()) { //This checks to make sure walls are valid AIBoard tempBoard = new AIBoard(Board); tempBoard.MakeMove(move); children.Add(new TreeNode(tempBoard, move)); } //This gets only valid walls but is done here so that it will only check walls of interest. //This avoids checking if a ton of walls are valid that we don't care about. //This is why we do not just call GetWallMoves() if ((Board.GetIsPlayerOneTurn() && Board.GetPlayerOneNumWalls() == 0) || (!Board.GetIsPlayerOneTurn() && Board.GetPlayerTwoNumWalls() == 0)) { } else { HashSet <string> wallMoves = Board.GetAllValidWalls(); SetNodesOfInterest(ref wallMoves); foreach (string wall in wallMoves) { //This checks to make sure walls are valid AIBoard tempBoard = new AIBoard(Board); tempBoard.MakeMove(wall); if (BoardAnalysis.CheckPathExists(tempBoard, true) && BoardAnalysis.CheckPathExists(tempBoard, false)) { children.Add(new TreeNode(tempBoard, wall)); } } } //end of wall selection return(children); }
public List <string> GetWallMoves() { List <string> possibleMoves = new List <string>(); if ((IsPlayerOneTurn && PlayerOneNumWalls == 0) || (!IsPlayerOneTurn && PlayerTwoNumWalls == 0)) { } else { foreach (string wall in ValidWallPlacements) { //This checks to make sure walls are valid AIBoard tempBoard = new AIBoard(this); tempBoard.MakeMove(wall); if (BoardAnalysis.CheckPathExists(tempBoard, true) && BoardAnalysis.CheckPathExists(tempBoard, false)) { possibleMoves.Add(wall); } } } return(possibleMoves); }
//Static evaluation function of the gameboard. private void EvaluateNode() { value = 0; //If a player won, assigns node proper value and then returns. if (EvaluateWinPossibility(ref value)) { } //Calculates factors of interest and calculates the value. else { int P1SP = BoardAnalysis.FindShortestPath(Board, true); int P2SP = BoardAnalysis.FindShortestPath(Board, false); int P1NumWalls = Board.GetPlayerOneNumWalls(); int P2NumWalls = Board.GetPlayerTwoNumWalls(); for (int i = 0; i < P2NumWalls; ++i) { value += wallValues[i]; } value += (weights[0] * P1SP - weights[1] * P2SP); } }
//If it is positive P2SP's path got that much shorter. public int CalcChangeInDiff() { Diff = BoardAnalysis.FindShortestPath(Board, true) - BoardAnalysis.FindShortestPath(Board, false); return(PreviousDiff - Diff); }
//Initiates a minimax search 2 layers deep. public string GetHardMove(string playerMove) { timer.Start(); TreeNode.weights = GetHardWeights(CurrentBoard); TreeNode.wallValues = new List <float> { 2f, 2f, 2f, 2f, 1f, 1f, 1f, 1f, 1f, 0f }; //AI starts on e9 and makes the first move of the game. if (playerMove == "gamestart") { CurrentBoard.PlayerTwoGoesFirst(); } //AI starts on e1 and makes the first move of the game. else if (playerMove == "") { } //Updates the board with the player's move. else { CurrentBoard.MakeMove(playerMove); } TreeNode rootNode = new TreeNode(CurrentBoard); float rootNodeValue = rootNode.CalcValue(); List <TreeNode> possibleMoves = rootNode.GetChildren(); //Create dictionary of all useful values of first two levels of analysis. Dictionary <string, MoveInfo> moveValues = new Dictionary <string, MoveInfo>(); foreach (TreeNode moveNode in possibleMoves) { if (timer.ElapsedMilliseconds > 5980) { break; } MoveInfo thisMovesInfo = new MoveInfo(); foreach (TreeNode childNode in moveNode.GetChildren()) { thisMovesInfo.UpdateValues(childNode.CalcValue(), moveNode.CalcValue()); } moveValues.Add(moveNode.GetMoveMade(), thisMovesInfo); } string selectedMove = "none1"; //Minimax of the first two levels. List <string> movesSelected = new List <string>(); float value = float.NegativeInfinity; foreach (KeyValuePair <string, MoveInfo> pair in moveValues) { if (pair.Value.singleLevelValue > 10000) { value = pair.Value.singleLevelValue; movesSelected.Clear(); movesSelected.Add(pair.Key); break; } if (pair.Value.min > value) { value = pair.Value.min; movesSelected.Clear(); movesSelected.Add(pair.Key); } else if (pair.Value.min == value) { movesSelected.Add(pair.Key); } } selectedMove = movesSelected[new System.Random().Next(0, movesSelected.Count)]; //If selected move isn't a wall then use the pawn moves single level evaluation. //And if jump next move isn't a possibility. bool isPawnMove = !(selectedMove.EndsWith("h") || selectedMove.EndsWith("v")); bool jumpPossible = BoardAnalysis.FindDistanceBetween(CurrentBoard, CurrentBoard.GetPlayerOnePos(), CurrentBoard.GetPlayerTwoPos()) == 2; if (isPawnMove && !jumpPossible) { List <string> pawnMoves = CurrentBoard.GetPawnMoves(); value = float.NegativeInfinity; selectedMove = "none2"; foreach (string pm in pawnMoves) { float tempVal = moveValues[pm].singleLevelValue; if (tempVal > value) { selectedMove = pm; value = tempVal; } } } float testVal = value - rootNodeValue; if (value - rootNodeValue < 3) { float currentPotential = float.NegativeInfinity; float currentRisk = float.NegativeInfinity; movesSelected.Clear(); foreach (KeyValuePair <string, MoveInfo> pair in moveValues) { if (pair.Key.EndsWith("h") || pair.Key.EndsWith("v")) { float optimisticPotential = pair.Value.max - rootNodeValue; float pessemisticPotential = pair.Value.min - rootNodeValue; float risk = optimisticPotential - pessemisticPotential; if (optimisticPotential > 2) { if (optimisticPotential > currentPotential) { movesSelected.Clear(); movesSelected.Add(pair.Key); currentPotential = optimisticPotential; currentRisk = risk; } else if (optimisticPotential == currentPotential) { if (risk < currentRisk) { movesSelected.Clear(); movesSelected.Add(pair.Key); currentPotential = optimisticPotential; currentRisk = risk; } else if (risk == currentRisk) { movesSelected.Add(pair.Key); } } } } } if (movesSelected.Count > 0) { selectedMove = movesSelected[new System.Random().Next(0, movesSelected.Count)]; } } timer.Reset(); CurrentBoard.MakeMove(selectedMove); return(selectedMove); }
/** * Returns a list of all possible pawn moves for whichever players turn it is. **/ public List <string> GetPawnMoves() { List <string> possibleMoves; if (IsPlayerOneTurn) { possibleMoves = GetAdjacentMoves(PlayerOneLocation); foreach (string move in possibleMoves.ToArray()) { if (PlayerTwoLocation == move) { possibleMoves.Remove(move); string jumpDirection = BoardAnalysis.GetMoveDirection(PlayerOneLocation, PlayerTwoLocation); List <string> possibleJumps = GetAdjacentMoves(PlayerTwoLocation); List <string> perpendicularJumps = new List <string>(); string straightJump = "n"; possibleJumps.Remove(PlayerOneLocation); foreach (string jump in possibleJumps) { string possibleDirection = BoardAnalysis.GetMoveDirection(PlayerTwoLocation, jump); if (possibleDirection == jumpDirection) { straightJump = jump; } else { perpendicularJumps.Add(jump); } } if (straightJump != "n") { possibleMoves.Add(straightJump); } else { possibleMoves.AddRange(perpendicularJumps); } break; } } } else { possibleMoves = GetAdjacentMoves(PlayerTwoLocation); foreach (string move in possibleMoves.ToArray()) { if (PlayerOneLocation == move) { possibleMoves.Remove(move); string jumpDirection = BoardAnalysis.GetMoveDirection(PlayerTwoLocation, PlayerOneLocation); List <string> possibleJumps = GetAdjacentMoves(PlayerOneLocation); List <string> perpendicularJumps = new List <string>(); string straightJump = "n"; possibleJumps.Remove(PlayerTwoLocation); foreach (string jump in possibleJumps) { string possibleDirection = BoardAnalysis.GetMoveDirection(PlayerOneLocation, jump); if (possibleDirection == jumpDirection) { straightJump = jump; } else { perpendicularJumps.Add(jump); } } if (straightJump != "n") { possibleMoves.Add(straightJump); } else { possibleMoves.AddRange(perpendicularJumps); } break; } } } return(possibleMoves); }