public double BuildABTree(StishMiniMaxNode CurrentNode, int DepthCount, double Alpha, double Beta, int colour) { if (CurrentNode == null || DepthCount == 0) { //returns if this is the root node or is a leaf node return(colour * CurrentNode.FindValue(CurrentNode, CurrentNode.NodeBoardState, CurrentNode.Allegiance)); } double Value = double.MinValue; double ChildValue; ForeSight.Instance.GenerateChildren(CurrentNode); for (int index = 0; index < CurrentNode.CountChildren(); index++) { ChildValue = -1 * BuildABTree((StishMiniMaxNode)CurrentNode.GetChild(index), DepthCount - 1, -Beta, -Alpha, -colour); if (Value < ChildValue) { Value = ChildValue; CurrentNode.BestChild = (StishMiniMaxNode)CurrentNode.GetChild(index); CurrentNode.NegaMaxValue = Value; } Alpha = Math.Max(Alpha, Value); if (Alpha > Beta) { //this return statement "prunes" the tree and prevents further growth on the tree in those bad areas return(colour * CurrentNode.FindValue(CurrentNode, CurrentNode.NodeBoardState, CurrentNode.Allegiance)); } } //if the node does not need to be pruned return(colour * CurrentNode.FindValue(CurrentNode, CurrentNode.NodeBoardState, CurrentNode.Allegiance)); }
public double TraverseTree(StishMiniMaxNode CurrentNode, int DepthCount, int colour) { //Depth count is given as 0 when called at root if (CurrentNode == null || DepthCount == 0) { //the number 3 is a variable to be changed as sight increases return(colour * CurrentNode.FindValue(CurrentNode, CurrentNode.NodeBoardState, CurrentNode.Allegiance)); } double Value = double.MinValue; double ChildValue; for (int index = 0; index < CurrentNode.CountChildren(); index++) { ChildValue = -TraverseTree((StishMiniMaxNode)CurrentNode.GetChild(index), DepthCount - 1, -colour); if (Value < ChildValue) { Value = ChildValue; CurrentNode.BestChild = (StishMiniMaxNode)CurrentNode.GetChild(index); CurrentNode.NegaMaxValue = Value; } } return(Value); }
//the foresight class helps us build new nodes by predicting all possible moves from a node //these functions will be called by the node objects in order to tell the nodes, how to configure their children public void UnitBasedMovement(StishMiniMaxNode Sibling, BoardState Now, List <Coordinate> Path, Player Side) { //this will check what is on the destination square and then use the game master function. //the game master currently only works with the StishBoard. if i make StishBoard a dervived class from the board state, i can generalize the game master functions and use them here Player NewSide; BoardState UnitMovedChild = new BoardState(Now); if (Side.GetPlayerNum == "Player1") { NewSide = UnitMovedChild.Player1; } else { NewSide = UnitMovedChild.Player2; } for (int index = 0; index < Path.Count - 1; index++) { //from index to the one ahead of it therefore the function finishes one place short of the end GameMaster.Instance.Action(Path[index], Path[index + 1], NewSide, UnitMovedChild); } //Parent.Parent as "parent" is actually just an updated model of the "real" parent where no actions were taken StishMiniMaxNode UnitMoveNode = new StishMiniMaxNode(Sibling.Parent, Sibling.Allegiance, UnitMovedChild); PredctionCount(); //changes to the boardstate are made here using the FindPath function and itterating through the list with the gamemaster functions }
//this may not need to be void however i dont yet know if or what the output will be (currently just counts) public void SweepSearch(StishMiniMaxNode Sibling, BoardState Now, Coordinate UnitPos, Player Side) { Coordinate Upper = new Coordinate(); Coordinate Lower = new Coordinate(); Coordinate Look = new Coordinate(); //upper refers to the upper left corner (lower coordinate values) //assigns full values to the bounds and then changes them if they are inappropriate Upper.X = UnitPos.X - StishBoard.Instance.GameMP; Upper.Y = UnitPos.Y - StishBoard.Instance.GameMP; Lower.X = UnitPos.X + StishBoard.Instance.GameMP; Lower.Y = UnitPos.Y + StishBoard.Instance.GameMP; //checks if the unit is losing movement positions because it is too close to the edge of the board if (UnitPos.X < StishBoard.Instance.GameMP) { Upper.X = 0; } if (UnitPos.X > Now.BoardSizeX - StishBoard.Instance.GameMP) { Lower.X = Now.BoardSizeX; } if (UnitPos.Y < StishBoard.Instance.GameMP) { Upper.Y = 0; } if (UnitPos.Y > Now.BoardSizeY - StishBoard.Instance.GameMP) { Lower.Y = Now.BoardSizeY; } for (uint y = Upper.Y; y <= Lower.Y; y++) { for (uint x = Upper.X; x <= Lower.X; x++) { Look.X = x; Look.Y = y; //stishboard.instance is okay here as this variable is global and is not dependant on a particular state if (UnitPos.Get2DDistance(Look) <= StishBoard.Instance.GameMP) { //general squares around unit within range if ((Now.getSquare(Look) != null) && !((Now.getSquare(Look).Owner) == Side && ((Now.getSquare(Look).Dep.DepType == "Unit") || (Now.getSquare(Look).Dep.DepType == "Base")))) { //the unit can legally move to any of these positions however the events of this action are not distinguished //obstructions are not accounted for List <Coordinate> Path = FindPath(UnitPos, Look, Now); if (Path != null) { UnitBasedMovement(Sibling, Now, Path, Side); } } } } } }
private void TestSquare(StishMiniMaxNode Sibling, BoardState Now, Player Side, Coordinate Invest, uint cost) { if ((Now.getSquare(Invest).Owner == Side) && (Now.getSquare(Invest).Dep.DepType == "Empty")) { //can buy possibly buy BuyPossibility(Sibling, Now, Side, Invest, cost); } if ((Now.getSquare(Invest).Owner == Side) && (Now.getSquare(Invest).Dep.DepType == "Unit")) { //sweeps through all possible unit moves SweepSearch(Sibling, Now, Invest, Side); } }
public override void MakeMove() { StishMiniMaxNode GameNode = new StishMiniMaxNode(null, StishBoard.Instance.Player1); GameNode.NodeBoardState = new BoardState(StishBoard.Instance); //double evaluation = MiniMaxMind.Instance.BuildABTree(GameNode, 4, int.MinValue, int.MaxValue, -1); MiniMaxMind.Instance.RecBuildMMTree(GameNode, 4); double evaluation = MiniMaxMind.Instance.TraverseTree(GameNode, 4, -1); //ForeSight.Instance.PredctionCount(); StishBoard.Instance.ReplaceState(GameNode.BestChild.NodeBoardState); }
public void RecBuildMMTree(StishMiniMaxNode CurrentNode, int DepthCount) { //Depth count is given as 0 when called at root //the number quoted below will not occur in the depth sequence if (CurrentNode == null || DepthCount == 0) { return; } ForeSight.Instance.GenerateChildren(CurrentNode); for (int index = 0; index < CurrentNode.CountChildren(); index++) { RecBuildMMTree((StishMiniMaxNode)CurrentNode.GetChild(index), DepthCount - 1); } }
public void GenerateChildren(StishMiniMaxNode NodeParent) { //parent argument will always contain "this" when called. Player OppositeAllegience; //ASSUMES THAT PLAYER 2 IS COMPUTER! if (NodeParent.Allegiance.GetPlayerNum == "Player1") { OppositeAllegience = new Computer((Computer)NodeParent.NodeBoardState.Player2); } else { OppositeAllegience = new Human(NodeParent.NodeBoardState.Player1); } //is a child of NodeParent as this is a turn spent doing nothing. the balance and MP are updated below and then this node is used as an example for others BoardState SiblingBoardState = new BoardState(NodeParent.NodeBoardState); StishMiniMaxNode Sibling = new StishMiniMaxNode(NodeParent, OppositeAllegience, SiblingBoardState); m_TurnPredictionCount = 0; Sibling.Allegiance.TurnBalance(Sibling.NodeBoardState); Sibling.Allegiance.MaxMP(Sibling.NodeBoardState); uint cost = BarracksCost(Sibling.NodeBoardState, Sibling.Allegiance); Coordinate Look = new Coordinate(); for (uint y = 0; y < Sibling.NodeBoardState.BoardSizeY; y++) { for (uint x = 0; x < Sibling.NodeBoardState.BoardSizeX; x++) { Look.Y = y; Look.X = x; TestSquare(Sibling, Sibling.NodeBoardState, Sibling.Allegiance, Look, cost); } } }
public void BuildMMTree(StishMiniMaxNode RootNode, int DepthLimit) { StishMiniMaxNode InvestNode; List <StishMiniMaxNode> GenQueue = new List <StishMiniMaxNode>(); GenQueue.Add(RootNode); while (GenQueue.Count > 0) { InvestNode = GenQueue[0]; ForeSight.Instance.GenerateChildren(InvestNode); //creates the depth layer but doesnt generate from them if (InvestNode.FindDepth() + 1 < DepthLimit) { for (int index = 0; index < InvestNode.CountChildren(); index++) { GenQueue.Add((StishMiniMaxNode)InvestNode.GetChild(index)); } } GenQueue.Remove(InvestNode); } }
public void BuyPossibility(StishMiniMaxNode Sibling, BoardState Now, Player Side, Coordinate look, uint cost) { if (Side.Balance > 0) { //can afford a unit BoardState UnitBoardState = new BoardState(Now); if (Side.GetPlayerNum == "Player1") { GameMaster.Instance.BuyUnit(look, UnitBoardState.Player1, UnitBoardState); } else { GameMaster.Instance.BuyUnit(look, UnitBoardState.Player2, UnitBoardState); } /* * if (Side.GetPlayerNum == "Player1") * { * //opposite allegiance to it's parent * PlayersTurn = UnitBoardState.Player2; * } * else * { * PlayersTurn = UnitBoardState.Player1; * } */ //Parent.Parent as "parent" is actually just an updated model of the "real" parent where no actions were taken StishMiniMaxNode UnitCaseNode = new StishMiniMaxNode(Sibling.Parent, Sibling.Allegiance, UnitBoardState); PredctionCount(); } if (Side.Balance >= cost) { //can afford a barracks BoardState BarracksBoardState = new BoardState(Now); if (Side.GetPlayerNum == "Player1") { GameMaster.Instance.BuyBarracks(look, BarracksBoardState.Player1, BarracksBoardState); } else { GameMaster.Instance.BuyBarracks(look, BarracksBoardState.Player2, BarracksBoardState); } /* * if (Side.GetPlayerNum == "Player1") * { * //opposite allegiance to it's parent * PlayersTurn = BarracksBoardState.Player2; * } * else * { * PlayersTurn = BarracksBoardState.Player1; * } */ //Parent.Parent as "parent" is actually just an updated model of the "real" parent where no actions were taken StishMiniMaxNode BarracksCaseNode = new StishMiniMaxNode(Sibling.Parent, Sibling.Allegiance, BarracksBoardState); PredctionCount(); } }