/// <summary> /// Get the Command.Move direction that moves from fromsq to tosq, /// or null if none exists. /// </summary> Command.Move GetMoveDirection(PathSquare fromsq, PathSquare tosq) { if (fromsq.X == tosq.X) { if (fromsq.Y == tosq.Y - 1) { return(Command.Move.Up); } else if (fromsq.Y == tosq.Y + 1) { return(Command.Move.Down); } } else if (fromsq.Y == tosq.Y) { if (fromsq.X == tosq.X - 1) { return(Command.Move.Right); } else if (fromsq.X == tosq.X + 1) { return(Command.Move.Left); } } return(Command.Move.Stay); // no legal move from fromsq to tosq }
/// <summary> /// Move along MyPath - always turn to face the direction of travel (or else I can get stuck /// behind a block that I cannot see). /// Return false if this move is likely to fail because the next square is blocked /// </summary> public bool MoveAlongMyPath() { if (MyPath != null && MyPathIndex < MyPath.Count) // not yet at end of path { PathSquare nextsquare = MyPath[MyPathIndex]; if (nextsquare.IsBlocked) { return(false); // next square is blocked so find a new path } Command.Move dir = GetMoveDirection(nextsquare.Parent, nextsquare); Command.Move rot = GetMoveRotation(dir); if (rot != Command.Move.Stay) { MyCommand = new Command(rot, false); // rotate to face direction of travel } else { MyCommand = new Command(dir, false); // move along path MyPathIndex++; // so go to next square of path } return(true); } else { return(false); } }
/// <summary> /// Check whether the path from parent to P is cheaper than the current path, for P on the open list. /// Note parent must be adjacent to P. /// </summary> /// <param name="P"></param> /// <param name="parent"></param> public void UpdateOpenListEntry(PathSquare P, PathSquare parent) { if (P.G > parent.G + 1) { P.Parent = parent; P.G = parent.G + 1; } }
/// <summary> /// Finds a path from grid square (fromX,fromY) to grid square (toX,toY), avoiding all fixed /// obstacles, and returns the result as an ArrayList. The start and finish points are not included /// in the path (since the start point will usually be an Ant and the finish point will usually /// be food, and anthill or another ant). /// </summary> /// <param name="fromX">The X co-ordinate of the start square.</param> /// <param name="fromY">The Y co-ordinate of the start square.</param> /// <param name="toX">The X co-ordinate of the target square.</param> /// <param name="toY">The Y co-ordinate of the target square.</param> /// <returns>Returns an ArrayList storing the path, if one has been found, or null otherwise. /// This ArrayList is also held in the Path class variable.</returns> public List <PathSquare> FindPath(int fromX, int fromY, int toX, int toY) { if (GetEstimatedDistance(fromX, fromY, toX, toY) == 0) { return(new List <PathSquare>()); // already at goal so return empty path } // New path so increment this so that marks in Map[,] can be distinguished from those // of previous paths. PathIndex++; // Note that if you change terrain without reloading your AI the Map will // not be updated and you will get (weird!) results for the previous terrain. // set the target square - we want to get adjacent to this square. TargetSquare = MyMap[toX, toY]; // label destination square. Note that there can be more than one, but here, only one is considered. MyMap[toX, toY].G = -1; MyMap[toX, toY].H = 1; MyMap[toX, toY].IsGoal = PathIndex; // this square is a goal for this path. MyMap[toX, toY].OnClosedList = -1; MyMap[toX, toY].OnOpenList = -1; MyMap[toX, toY].Parent = null; // set the start square - the first square the the path will be adjacent // to this square. StartSquare = MyMap[fromX, fromY]; StartSquare.G = 0; // Distance from StartSquare to StartSquare is zero StartSquare.H = GetEstimatedDistanceToGoal(StartSquare); // Now initialise the OpenList with the neighbours of StartSquare // and put StartSquare on the closed list. List <PathSquare> fromsq = GetReachableNeighbours(fromX, fromY); if (fromsq.Count == 0) { return(null); // no reachable squares adjacent to (fromX, fromY) } OpenList.Clear(); foreach (PathSquare ps in fromsq) { if (ps.IsGoal == PathIndex) { // path (of length 1) found. ps.Parent = StartSquare; List <PathSquare> path = new List <PathSquare>(); path.Add(ps); return(path); } AddToOpenList(ps, StartSquare); } StartSquare.OnClosedList = PathIndex; // Put StartSquare on closed list return(AStarSearch()); // search for the path. }
/// <summary> /// Finds a path to the destination square and set the A* object to move along that path. /// </summary> private void FindAndMoveAlongPath(int x1, int y1, int x2, int y2) { aStar.MyPath = aStar.FindPath(x1, y1, x2, y2); // find a path if (aStar.MyPath != null) // path exists { TargetSquare = MyMap[x2, y2]; // (x,y) is unseen aStar.MyPathIndex = 0; aStar.MoveAlongMyPath(); return; } }
/// <summary> /// Is square S on the open list of squares will be investigated soon? /// </summary> private bool IsOnOpenList(PathSquare S) { if (S.OnOpenList == PathIndex) { return(true); } else { return(false); } }
/// <summary> /// Saves the current path to ArrayList Path. /// </summary> /// <param name="S"></param> private List <PathSquare> SavePath(PathSquare goal) { List <PathSquare> path = new List <PathSquare>(); PathSquare p = goal; while (p.Parent.G > 0) { path.Insert(0, p); p = p.Parent; } path.Insert(0, p); return(path); }
/// <summary> /// Add a PathSquare to the correct sorted position on the open list, and update the PathSquare's data. /// P and parent are guaranteed to be adjacent. /// </summary> public void AddToOpenList(PathSquare P, PathSquare parent) { P.G = parent.G + 1; P.H = GetEstimatedDistanceToGoal(P); P.OnClosedList = -1; P.OnOpenList = PathIndex; P.Parent = parent; int i; for (i = 0; i < OpenList.Count; i++) { PathSquare ps = (PathSquare)OpenList[i]; if (ps.F >= P.F) { break; } } OpenList.Insert(i, P); // insert in sorted position }
/// <summary> /// Finds a new unseen square. Gets all the unseen squares and choose one randomly. /// </summary> private void FindUnseenSquare() { List <PathSquare> SquaresNotSeen = new List <PathSquare>(); foreach (var square in MyMap) { if (MyMap[square.X, square.Y].HasBeenSeen == false) { SquaresNotSeen.Add(square); } } if (SquaresNotSeen.Count > 0) { PathSquare Location = SquaresNotSeen[new Random().Next(SquaresNotSeen.Count)]; FindAndMoveAlongPath(MyWorldState.MyGridSquare.X, MyWorldState.MyGridSquare.Y, Location.X, Location.Y); } else { FindAndMoveAlongPath(MyWorldState.MyGridSquare.X, MyWorldState.MyGridSquare.Y, MyWorldState.MyGridSquare.X, MyWorldState.MyGridSquare.Y); } }
/// <summary> /// Get an optimistic estimate of the distance from P to TargetSquare. /// The estimate assumes that there is no terrain blocking the path. /// </summary> public int GetEstimatedDistanceToGoal(PathSquare P) { return(Math.Abs(TargetSquare.X - P.X) + Math.Abs(TargetSquare.Y - P.Y)); // x distance + y distance }