// find all spaces where it is possible to go to from current node public LinkedList<FieldNode> findSons(FieldNode node) { LinkedList<FieldNode> sons = new LinkedList<FieldNode>(); int x = node.x; int y = node.y; if (x >= sizeX || y >= sizeY || x < 0 || y < 0) return null; if (y + 1 < sizeY && map[x, y + 1] <= 0) sons.AddLast(new FieldNode(x, y + 1)); if (x + 1 < sizeX && y + 1 < sizeY && map[x + 1, y + 1] <= 0) sons.AddLast(new FieldNode(x + 1, y + 1)); if (x + 1 < sizeX && map[x + 1, y] <= 0) sons.AddLast(new FieldNode(x + 1, y)); if (x + 1 < sizeX && y - 1 >= 0 && map[x + 1, y - 1] <= 0) sons.AddLast(new FieldNode(x + 1, y - 1)); if (y - 1 >= 0 && map[x, y - 1] <= 0) sons.AddLast(new FieldNode(x, y - 1)); if (x - 1 >= 0 && y - 1 >= 0 && map[x - 1, y - 1] <= 0) sons.AddLast(new FieldNode(x - 1, y - 1)); if (x - 1 >= 0 && map[x - 1, y] <= 0) sons.AddLast(new FieldNode(x - 1, y)); if (x - 1 >= 0 && y + 1 < sizeY && map[x - 1, y + 1] <= 0) sons.AddLast(new FieldNode(x - 1, y + 1)); return sons; }
public static LinkedList<Direction> FindPath(FieldMap map, FieldNode start, FieldNode goal) { LinkedList<FieldNode> path = new LinkedList<FieldNode>(); Stack<FieldNode> stack = new Stack<FieldNode>(); stack.Push(start); while (stack.Count > 0) { FieldNode node = stack.Pop(); //AddToPath(path, node); if (node.Equals(goal)) return TranslateToDirections(path); LinkedList<FieldNode> sons = map.findSons(node); //Iterator<Node> iter = sons.descendingIterator(); foreach (FieldNode son in sons) { if (!stack.Contains(son) && !path.Contains(son)) stack.Push(son); } } return null; }
// find first available space to move to public FieldNode firstSon(FieldNode node) { int x = node.x; int y = node.y; if (x >= sizeX || y >= sizeY || x < 0 || y < 0) return null; if (y + 1 < sizeY && map[x, y + 1] <= 0) return new FieldNode(x, y + 1); if (x + 1 < sizeX && y + 1 < sizeY && map[x + 1, y + 1] <= 0) return new FieldNode(x + 1, y + 1); if (x + 1 < sizeX && map[x + 1, y] <= 0) return new FieldNode(x + 1, y); if (x + 1 < sizeX && y - 1 >= 0 && map[x + 1, y - 1] <= 0) return new FieldNode(x + 1, y - 1); if (y - 1 >= 0 && map[x, y - 1] <= 0) return new FieldNode(x, y - 1); if (x - 1 >= 0 && y - 1 >= 0 && map[x - 1, y - 1] <= 0) return new FieldNode(x - 1, y - 1); if (x - 1 >= 0 && map[x - 1, y] <= 0) return new FieldNode(x - 1, y); if (x - 1 >= 0 && y + 1 < sizeY && map[x - 1, y + 1] <= 0) return new FieldNode(x - 1, y + 1); return null; }
// find the neighbor where the Seeker has been least recently public FieldNode findBestNotSeen(FieldNode node, int[,] seenMap) { if (seenMap.GetLength(0) != sizeX || seenMap.GetLength(1) != sizeY) return null; LinkedList<FieldNode> sons = new LinkedList<FieldNode>(); int x = node.x; int y = node.y; if (x >= sizeX || y >= sizeY || x < 0 || y < 0) return null; //if there is a neighbor which hasn't been seen recently, return it if (y + 1 < sizeY && map[x, y + 1] <= 0 && seenMap[x, y + 1] == 0) return new FieldNode(x, y + 1); if (x + 1 < sizeX && y + 1 < sizeY && map[x + 1, y + 1] <= 0 && seenMap[x + 1, y + 1] == 0) return new FieldNode(x + 1, y + 1); if (x + 1 < sizeX && map[x + 1, y] <= 0 && seenMap[x + 1, y] == 0) return new FieldNode(x + 1, y); if (x + 1 < sizeX && y - 1 >= 0 && map[x + 1, y - 1] <= 0 && seenMap[x + 1, y - 1] == 0) return new FieldNode(x + 1, y - 1); if (y - 1 >= 0 && map[x, y - 1] <= 0 && seenMap[x, y - 1] == 0) return new FieldNode(x, y - 1); if (x - 1 >= 0 && y - 1 >= 0 && map[x - 1, y - 1] <= 0 && seenMap[x - 1, y - 1] == 0) return new FieldNode(x - 1, y - 1); if (x - 1 >= 0 && map[x - 1, y] <= 0 && seenMap[x - 1, y] == 0) return new FieldNode(x - 1, y); if (x - 1 >= 0 && y + 1 < sizeY && map[x - 1, y + 1] <= 0 && seenMap[x - 1, y+1] == 0) return new FieldNode(x - 1, y + 1); FieldNode best = null; int bestVal = 101; // go through all neighbors and find the one that has been seen least recently if (y + 1 < sizeY && map[x, y + 1] <= 0) { FieldNode next = new FieldNode(x, y + 1); int val = seenMap[x, y + 1]; if (val < bestVal) { bestVal = val; best = next; } } if (x + 1 < sizeX && y + 1 < sizeY && map[x + 1, y + 1] <= 0) { FieldNode next = new FieldNode(x + 1, y + 1); int val = seenMap[x + 1, y + 1]; if (val < bestVal) { bestVal = val; best = next; } } if (x + 1 < sizeX && map[x + 1, y] <= 0) { FieldNode next = new FieldNode(x + 1, y); int val = seenMap[x + 1, y]; if (val < bestVal) { bestVal = val; best = next; } } if (x + 1 < sizeX && y - 1 >= 0 && map[x + 1, y - 1] <= 0) { FieldNode next = new FieldNode(x + 1, y - 1); int val = seenMap[x + 1, y - 1]; if (val < bestVal) { bestVal = val; best = next; } } if (y - 1 >= 0 && map[x, y - 1] <= 0) { FieldNode next = new FieldNode(x, y - 1); int val = seenMap[x, y - 1]; if (val < bestVal) { bestVal = val; best = next; } } if (x - 1 >= 0 && y - 1 >= 0 && map[x - 1, y - 1] <= 0) { FieldNode next = new FieldNode(x - 1, y - 1); int val = seenMap[x - 1, y - 1]; if (val < bestVal) { bestVal = val; best = next; } } if (x - 1 >= 0 && map[x - 1, y] <= 0) { FieldNode next = new FieldNode(x - 1, y); int val = seenMap[x - 1, y]; if (val < bestVal) { bestVal = val; best = next; } } if (x - 1 >= 0 && y + 1 < sizeY && map[x - 1, y + 1] <= 0) { FieldNode next = new FieldNode(x - 1, y + 1); int val = seenMap[x - 1, y + 1]; if (val < bestVal) { bestVal = val; best = next; } } //return the neighbor which has been seen least recently return best; }
//lower count of objects in a certain space internal void removeBlock(FieldNode fieldNode) { map[fieldNode.x, fieldNode.y]--; }
//returns whether location is in conflict with one of the items internal bool isConflict(Vector3 location, FieldNode fieldNode) { List<Item> items = itemMap[fieldNode.x, fieldNode.y]; if (items == null) return false; foreach (Item item in items) if (item.isConflict(location)) return true; return false; }
//check if space on map is still available internal bool isAvailable(FieldNode fieldNode) { return (map[fieldNode.x, fieldNode.y] == 0); }
//find best space to go to while racing to tree internal FieldNode findRunSpace(FieldNode node) { if (node == null) return null; int x = node.x; int y = node.y; //if possible, go to the nodes which are closer to the tree (meaning a smaller y value) if (y - 1 >= 0 && map[x, y - 1] == 0) return new FieldNode(x, y - 1); if (y - 1 >= 0 && x - 1 >= 0 && map[x - 1, y - 1] == 0) return new FieldNode(x - 1, y - 1); if (y - 1 >= 0 && x + 1 < sizeX && map[x + 1, y - 1] == 0) return new FieldNode(x + 1, y - 1); //otherwise, go sideways (equal y value) if (x - 1 >= 0 && map[x - 1, y] == 0) return new FieldNode(x - 1, y); if (x + 1 < sizeX && map[x + 1, y] == 0) return new FieldNode(x + 1, y); //if none of the above nodes are available, go to nodes which are farther away from the tree (larger y value) if (y + 1 < sizeY && x - 1 >= 0 && map[x - 1, y + 1] == 0) return new FieldNode(x - 1, y + 1); if (y + 1 < sizeY && map[x, y + 1] == 0) return new FieldNode(x, y + 1); if (y + 1 < sizeY && x + 1 < sizeX && map[x + 1, y + 1] == 0) return new FieldNode(x + 1, y + 1); return null; }
//notify map that someone moved from [x,y] to [z,w] public void moveSomeone(FieldNode node1, FieldNode node2) { if (node1 != null && node1.x >= 0 && node1.y >= 0) map[node1.x, node1.y]--; if (node2 != null && node2.x >= 0 && node2.y >= 0) map[node2.x, node2.y]++; }
//returns available node which is closest to goal (using manhattan distance) public FieldNode getClosestNext(FieldNode node, FieldNode goal) { //if the goal is a neighbor if (Math.Abs(node.x - goal.x) == 1 || Math.Abs(node.y - goal.y) == 1) { //if the only item in the goal space is the hiding spot, return it if (map[goal.x, goal.y] == 1) return goal; //otherwise, need to find a new hiding spot else throw new SpotTakenException(); } int x = node.x; int y = node.y; if (x >= sizeX || y >= sizeY || x < 0 || y < 0) return null; //go through all neighbors and find the one which is closest to the hiding spot, using Manhattan distancea FieldNode best = null; double bestVal = 300; if (y + 1 < sizeY && map[x, y + 1] <= 0) { FieldNode next = new FieldNode(x, y + 1); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (x + 1 < sizeX && y + 1 < sizeY && map[x + 1, y + 1] <= 0) { FieldNode next = new FieldNode(x + 1, y + 1); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (x + 1 < sizeX && map[x + 1, y] <= 0) { FieldNode next = new FieldNode(x + 1, y); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (x + 1 < sizeX && y - 1 >= 0 && map[x + 1, y - 1] <= 0) { FieldNode next = new FieldNode(x + 1, y - 1); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (y - 1 >= 0 && map[x, y - 1] <= 0) { FieldNode next = new FieldNode(x, y - 1); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (x - 1 >= 0 && y - 1 >= 0 && map[x - 1, y - 1] <= 0) { FieldNode next = new FieldNode(x - 1, y - 1); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (x - 1 >= 0 && map[x - 1, y] <= 0) { FieldNode next = new FieldNode(x - 1, y); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } if (x - 1 >= 0 && y + 1 < sizeY && map[x - 1, y + 1] <= 0) { FieldNode next = new FieldNode(x - 1, y + 1); double val = next.EuclideanDist(goal); if (val < bestVal) { bestVal = val; best = next; } } return best; }
// convert node to 3D location public float[] nodeToLoc(FieldNode node) { float[] res = new float[4]; res[0] = node.x * squareSize + borders[1].X; res[1] = -node.y * squareSize; res[2] = (node.x + 1) * squareSize + borders[1].X; res[3] = -(node.y + 1) * squareSize; return res; }
//calculate distance between to spaces public double EuclideanDist(FieldNode other) { //return Math.Abs(x - other.x) + Math.Abs(y - other.y); return Math.Sqrt((x-other.x)*(x-other.x)+(y-other.y)*(y-other.y)); }
// convert node to 3D location public float[] nodeToLoc(FieldNode node) { if (node == null || node.x < 0 || node.y < 0) return null; float[] res = new float[4]; res[0] = node.x * squareSize + borders[1].X; res[1] = -node.y * squareSize; res[2] = (node.x + 1) * squareSize + borders[1].X; res[3] = -(node.y + 1) * squareSize; return res; }
/// <summary> /// Allows the game component to perform any initialization it needs to before starting /// to run. This is where it can query for any required services and load content. /// </summary> public override void Initialize() { //initialize game space borders borders = new Vector3[4]; borders[0] = new Vector3(20, 0, 0); borders[1] = new Vector3(-20, 0, 0); borders[2] = new Vector3(20, 0, -2000); borders[3] = new Vector3(-20, 0, -2000); //create map int sizeX = (int)Math.Abs(borders[0].X - borders[3].X) / squareSize; int sizeY = (int)(Math.Abs(borders[0].Z - borders[3].Z) / squareSize); map = new FieldMap(sizeX, sizeY); //if game is a real game and not a practice if (gameType == GameType.Hide || gameType == GameType.Seek) { Random rand = new Random(10); items = new Item[numOfItems]; for (int i = 0; i < numOfItems; i++) { //choose space on map which has no item in it yet FieldNode node = null; int x; int y; do { x = rand.Next(sizeX); y = rand.Next(sizeY); node = new FieldNode(x, y); } while (!map.isAvailable(node)); //find optimal location in space for item Vector3 loc = Rock.findBestLoc(nodeToLoc(node), ItemType.Rock); items[i] = new Rock(Game, loc, new Vector3(0.4f, 0.4f, 0.4f), 0, i); map.addItem(items[i], x, y); } } hiders = new Hider[numOfHiders]; //if human player is a hider if (gameType == GameType.Hide) { //create human hider humanPlayer = new HumanHider(Game, new Vector3(0, 0, 0), 5, 10, 0); hiders[0] = (Hider)humanPlayer; //create rest of hiders to be virtual players for (int i = 1; i < numOfHiders; i++) hiders[i] = new VirtualHider(Game, new Vector3(10 * i, 0, 0) + borders[1], 5, 10, i + 1); //create virtual seeker seeker = new VirtualSeeker(Game, new Vector3(5, 0, 0), 5, 10, 1, countNum); } //if human player is a seeker else if (gameType == GameType.Seek) { //create human seeker humanPlayer = new HumanSeeker(Game, new Vector3(0, 0, 0), 5, 10, 0, countNum); seeker = (Seeker)humanPlayer; //create all hiders to be virtual players for (int i = 0; i < numOfHiders; i++) hiders[i] = new VirtualHider(Game, new Vector3(5 * i, 0, 0), 5, 10, i + 1); } if (gameType == GameType.HidePractice) { numOfItems = 1; numOfHiders = 1; items = new Item[1]; items[0] = new Rock(Game, new Vector3(0, 0, -20), new Vector3(1f, 1f, 1f), 0, 1); Console.WriteLine("only item: " + items[0]); hiders = new Hider[1]; humanPlayer = new HumanHider(Game, new Vector3(0, 0, 0), 5, 10, 0); hiders[0] = (Hider)humanPlayer; seeker = null; } else if (gameType == GameType.SeekPractice) { numOfItems = 2; numOfHiders = 1; items = new Item[2]; //TODO: is this the right place for intialization? // if so, get the missing parameters to here, // or alternatively, put Tree & Billboard intialization elsewhere! //BillboardSystem bbs = BillboardSystem.factory(2, graphicsDevice, BasicEffect); items[0] = new /*Tree*/Rock(Game, new Vector3(20, 0, -20), new Vector3(0.4f, 0.4f, 0.4f), 0, 1); items[1] = new /*Tree*/Rock(Game, new Vector3(-20, 0, -20), new Vector3(0.4f, 0.4f, 0.4f), 0, 2); hiders = new Hider[1]; hiders[0] = new VirtualHider(Game, new Vector3(10, 0, 0), 5, 10, 2); seeker = new HumanSeeker(Game, new Vector3(0, 0, 0), 5, 10, 1, 0); humanPlayer = (HumanPlayer)seeker; Random rand = new Random(); int i = rand.Next(2); ((VirtualHider)hiders[0]).skipSearch(items[i]); ((HumanSeeker)seeker).skipCounting(); } else { //tell map that locations of all players are off-limits for (int i = 0; i < numOfHiders; i++) map.addBlock((int)Math.Abs(hiders[i].Location.X - borders[1].X) / squareSize, (int)-(hiders[i].Location.Z / squareSize)); map.addBlock((int)Math.Abs((seeker.Location.X - borders[1].X)) / squareSize, (int)-seeker.Location.Z / squareSize); } base.Initialize(); }