// Add state to open list. If it is alreay in closed, ignore. // If it is already in open, update parent and gCost (if shorter path found) // Otherwise add to open void AddToOpen(xyLoc s, float gCost, xyLoc parent) { // Write code here. if (!openClosed[s.x, s.y].open && openClosed[s.x, s.y].round == round) { return; } else if (openClosed[s.x, s.y].round != round) { openClosed[s.x, s.y].open = true; openClosed[s.x, s.y].parent = parent; openClosed[s.x, s.y].gCost = gCost; openClosed[s.x, s.y].hCost = h.HCost(s, g); openClosed[s.x, s.y].fCost = openClosed[s.x, s.y].gCost + openClosed[s.x, s.y].hCost; openClosed[s.x, s.y].round = round; } else if (openClosed[s.x, s.y].open && openClosed[s.x, s.y].round == round) { float fCos = gCost + openClosed[s.x, s.y].hCost; if (fCos < openClosed[s.x, s.y].fCost) { //Debug.Log("Previous gCost: " + openClosed[s.x,s.y].gCost + " vs. new gCost: " + gCost); openClosed[s.x, s.y].parent = parent; openClosed[s.x, s.y].fCost = fCos; openClosed[s.x, s.y].gCost = gCost; } } }
// Update is called once per frame void Update() { // Left mouse is down in this frame if (Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 100)) { startLoc = new xyLoc(Mathf.RoundToInt(hit.point.x), Mathf.RoundToInt(hit.point.z)); endLoc = startLoc; } } else if (Input.GetMouseButton(0) || Input.GetMouseButtonUp(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 100)) { endLoc = new xyLoc(Mathf.RoundToInt(hit.point.x), Mathf.RoundToInt(hit.point.z)); } } bool legal = false; if (LineOfSight(startLoc, endLoc)) { legal = true; } Debug.DrawLine(new Vector3(startLoc.x, 0.5f, startLoc.y), new Vector3(endLoc.x, 0.5f, endLoc.y), legal ? Color.blue : Color.red); }
void Expand(Map m, xyLoc s) { xyLoc tmp = new xyLoc(); for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { if (x == 0 && y == 0) { continue; } float cost = 1.5f; if (x == 0 || y == 0) { cost = 1.0f; } tmp.x = s.x + x; tmp.y = s.y + y; if (m.CanMove(s.x, s.y, s.x + x, s.y + y)) { AddToOpen(tmp, openClosed [s.x, s.y].gCost + cost, s); } } } }
// Find the next best state to expand xyLoc GetNextToExpand() { xyLoc best = new xyLoc(-1, -1); bool valid = false; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (openClosed [x, y].round == round && openClosed [x, y].open) { if (valid == false) { best.x = x; best.y = y; valid = true; } else if (openClosed [x, y].fCost < openClosed [best.x, best.y].fCost) { best.x = x; best.y = y; } else if (openClosed [x, y].fCost == openClosed [best.x, best.y].fCost) { if (openClosed [x, y].gCost > openClosed [best.x, best.y].gCost) { best.x = x; best.y = y; } } } } } return(best); }
public float HCost(xyLoc s, xyLoc g) { float xDiff = Mathf.Abs(s.x - g.x); float yDiff = Mathf.Abs(s.y - g.y); return(Mathf.Max(xDiff, yDiff) + ((Mathf.Sqrt(2) - 1) * Mathf.Min(xDiff, yDiff))); }
// Add state to open list. If it is alreay in closed, ignore. // If it is already in open, update parent and gCost (if shorter path found) // Otherwise add to open void AddToOpen(xyLoc s, float gCost, xyLoc parent) { // check if already here if (openClosed [s.x, s.y].round == round) { if (openClosed [s.x, s.y].open == false) { return; } if (openClosed [s.x, s.y].gCost <= gCost) { return; } openClosed [s.x, s.y].gCost = gCost; openClosed [s.x, s.y].parent = parent; openClosed [s.x, s.y].fCost = gCost + openClosed [s.x, s.y].hCost; } else { float hCost = h.HCost(s, g); openClosed [s.x, s.y].gCost = gCost; openClosed [s.x, s.y].hCost = hCost; openClosed [s.x, s.y].fCost = gCost + hCost; openClosed [s.x, s.y].parent = parent; openClosed [s.x, s.y].round = round; openClosed [s.x, s.y].open = true; } }
public float HCost(xyLoc s, xyLoc g) { int minv = Mathf.Min(Mathf.Abs(s.x - g.x), Mathf.Abs(s.y - g.y)); int maxv = Mathf.Max(Mathf.Abs(s.x - g.x), Mathf.Abs(s.y - g.y)); return(minv * 0.5f + maxv); }
xyLoc GetClosestGhostLoc(GameController c, out float distance) { float minDist = Mathf.Infinity; xyLoc pacLoc = c.pacmanLoc; xyLoc returnLoc = new xyLoc(); float pinkDist, clydeDist, inkDist, blinkDist; pinkDist = distances[c.pinkyLoc.x / 8, c.pinkyLoc.y / 8]; //GhostController.Dist(pacLoc.x / 8, pacLoc.y / 8, c.pinkyLoc.x / 8, c.pinkyLoc.y / 8); clydeDist = distances[c.clydeLoc.x / 8, c.clydeLoc.y / 8]; //GhostController.Dist(pacLoc.x / 8, pacLoc.y / 8, c.clydeLoc.x / 8, c.clydeLoc.y / 8); inkDist = distances[c.inkyLoc.x / 8, c.inkyLoc.y / 8]; //GhostController.Dist(pacLoc.x / 8, pacLoc.y / 8, c.inkyLoc.x / 8, c.inkyLoc.y / 8); blinkDist = distances[c.blinkyLoc.x / 8, c.blinkyLoc.y / 8]; //GhostController.Dist(pacLoc.x / 8, pacLoc.y / 8, c.blinkyLoc.x / 8, c.blinkyLoc.y / 8); if (pinkDist < minDist) { minDist = pinkDist; returnLoc = c.pinkyLoc; } if (clydeDist < minDist) { minDist = clydeDist; returnLoc = c.clydeLoc; } if (inkDist < minDist) { minDist = inkDist; returnLoc = c.inkyLoc; } if (blinkDist < minDist) { minDist = blinkDist; returnLoc = c.blinkyLoc; } distance = minDist; return(new xyLoc(returnLoc.x / 8, returnLoc.y / 8)); }
void DoGamePlayLogic() { if (pacmanElapsed > frameRate) { pacmanLoc = HandleAction(pacmanLoc, pacman.GetComponent <ControlledObject> (), true); pacmanElapsed = 0f; //-= 1.0f / 30.0f; } if (blinkyElapsed > frameRate) { blinkyLoc = HandleAction(blinkyLoc, blinky.GetComponent <ControlledObject> (), false); blinkyElapsed = 0f; //-= 1.0f / 30.0f; } if (pinkyElapsed > frameRate) { pinkyLoc = HandleAction(pinkyLoc, pinky.GetComponent <ControlledObject> (), false); pinkyElapsed = 0f; //-= 1.0f / 30.0f; } if (inkyElapsed > frameRate) { inkyLoc = HandleAction(inkyLoc, inky.GetComponent <ControlledObject> (), false); inkyElapsed = 0f; //-= 1.0f / 30.0f; } if (clydeElapsed > frameRate) { clydeLoc = HandleAction(clydeLoc, clyde.GetComponent <ControlledObject> (), false); clydeElapsed = 0f; //-= 1.0f / 30.0f; } CheckPacmanCollision(blinkyLoc, blinky.GetComponent <ControlledObject> ()); CheckPacmanCollision(pinkyLoc, pinky.GetComponent <ControlledObject> ()); CheckPacmanCollision(inkyLoc, inky.GetComponent <ControlledObject> ()); CheckPacmanCollision(clydeLoc, clyde.GetComponent <ControlledObject> ()); }
// Continue the previous search. (Assumes Init is called first.) // Returns true when search is complete public bool Step(xyLoc start, xyLoc goal, Map m) { xyLoc nodeToExplore = GetNextToExpand(); if (nodeToExplore.x != -1 && nodeToExplore != g) { Expand(m, nodeToExplore); AddToClosed(nodeToExplore); } else if (nodeToExplore.x == -1) { success = false; return(true); } else if (nodeToExplore == g) { success = true; return(true); } //Get best from open // Expand best //Put best on closed // Write code here. return(false); }
public occupancy GetCellType(xyLoc loc) { if (loc.x < 0 || loc.x >= boardWidth || loc.y < 0 || loc.y >= boardHeight) { return(occupancy.kOutOfBounds); } loc.y = boardHeight - loc.y - 1; return(board[loc.y, loc.x]); }
// Initialize any variables specific for this search public void Init(xyLoc start, xyLoc goal, Map m, Heuristic heur) { h = heur; g = goal; round++; success = false; AddToOpen(start); }
public GameController.direction GetAction(GameMaze m, GameController c, xyLoc yourLoc) { if (c.CanMove(yourLoc, currentDirection)) { lastDirection = currentDirection; return(currentDirection); } return(lastDirection); }
float GetChasePowerPelletValue(GameController c, xyLoc closestPowerPellet) { if (powerUp) { return(0); } //return 1 - GetQuadraticCurveValue(GhostController.Dist(c.pacmanLoc, GetClosestGhostLoc(c)), .01f, 4); return(1 - GetLinearCurveValue(GhostController.Dist(new xyLoc(c.pacmanLoc.x / 8, c.pacmanLoc.y / 8), closestPowerPellet) * 4, .01f)); }
// Initialize any variables specific for this search public void Init(xyLoc start, xyLoc goal, Map m, Heuristic heur) { // Write code here. round++; g = goal; h = heur; success = false; AddToOpen(start); }
void ResetCharacterLocations() { pacmanLoc = new xyLoc(13 * 8 + 4, 9 * 8); blinkyLoc = new xyLoc(13 * 8 + 4, 21 * 8); pinkyLoc = new xyLoc(13 * 8 + 4, 18 * 8); inkyLoc = new xyLoc(12 * 8, 18 * 8); clydeLoc = new xyLoc(15 * 8, 18 * 8); blinky.GetComponent <ControlledObject> ().Reset(); inky.GetComponent <ControlledObject> ().Reset(); pinky.GetComponent <ControlledObject> ().Reset(); clyde.GetComponent <ControlledObject> ().Reset(); }
// Find complete path from start to goal using incremental search // functions defined above public List <xyLoc> GetPath(xyLoc start, xyLoc goal, Map m, Heuristic heur) { if (start == goal) { return(new List <xyLoc>()); } Init(start, goal, m, heur); while (Step(start, goal, m) == false) { } return(ExtractPath()); }
// Assume we are in quadrant 0 bool LineOfSight(xyLoc p1, xyLoc p2) { Vector2 slope = new Vector2((p2.x - p1.x), (p2.y - p1.y)); Vector2 currentSpot = new Vector2(p1.x, p1.y); for (int i = p1.x; i < p2.x; i++) { currentSpot += slope / Mathf.Abs(p1.x - p2.x); if (map.IsOccupied((int)currentSpot.x, (int)currentSpot.y) || map.IsOccupied((int)currentSpot.x, (int)currentSpot.y + 1) || map.IsOccupied((int)currentSpot.x, (int)currentSpot.y - 1)) { return(false); } } return(true); }
// Extract the path from the given state to the goal. // (Only runs if search successfully found the goal.) public List <xyLoc> ExtractPath() { List <xyLoc> result = new List <xyLoc> (); if (!success) { return(result); } xyLoc s = g; while (openClosed [s.x, s.y].parent != s) { result.Add(s); s = openClosed [s.x, s.y].parent; } return(result); }
GameController.direction MoveToTarget(int targetx, int targety, xyLoc myLoc, GameController.direction forbiddenDirection, GameController c) { GameController.direction best = GameController.direction.kUp; float distance = 1000f; if (c.CanMove(myLoc, GameController.direction.kUp) && forbiddenDirection != GameController.direction.kUp) { float thisDist = Dist(targetx, targety, myLoc.x / 8, myLoc.y / 8 + 1); if (thisDist < distance) { best = GameController.direction.kUp; distance = thisDist; } } if (c.CanMove(myLoc, GameController.direction.kLeft) && forbiddenDirection != GameController.direction.kLeft) { float thisDist = Dist(targetx, targety, myLoc.x / 8 - 1, myLoc.y / 8); if (thisDist < distance) { best = GameController.direction.kLeft; distance = thisDist; } } if (c.CanMove(myLoc, GameController.direction.kDown) && forbiddenDirection != GameController.direction.kDown) { float thisDist = Dist(targetx, targety, myLoc.x / 8, myLoc.y / 8 - 1); if (thisDist < distance) { best = GameController.direction.kDown; distance = thisDist; } } if (c.CanMove(myLoc, GameController.direction.kRight) && forbiddenDirection != GameController.direction.kRight) { float thisDist = Dist(targetx, targety, myLoc.x / 8 + 1, myLoc.y / 8); if (thisDist < distance) { best = GameController.direction.kRight; distance = thisDist; } } return(best); }
void GetAgentLocation() { currentLoc = new xyLoc(-1, -1); for (int x = 0; x < 100; x++) { if (map.IsOccupied(currentLoc.x, currentLoc.y)) { currentLoc.x = Random.Range(0, Map.width); currentLoc.y = Random.Range(0, Map.height); } else { transform.position = GetLocation(currentLoc); return; } } Debug.Log("Failure placing agent"); }
// Find the next best state to expand xyLoc GetNextToExpand() { xyLoc best = new xyLoc(-1, -1); float fCost = Mathf.Infinity; // Write code here. for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (openClosed[x, y].round == round && openClosed[x, y].open && openClosed[x, y].fCost < fCost) { fCost = openClosed[x, y].fCost; best.x = x; best.y = y; } } } return(best); }
void GetDistances(GameController c, GameMaze m, int x, int y) { dotx = doty = 1000; pelletx = pellety = 1000; for (int xLoc = 0; xLoc < GameMaze.boardWidth; xLoc++) { for (int yLoc = 0; yLoc < GameMaze.boardHeight; yLoc++) { distances[xLoc, yLoc] = 1000; } } distances [x, y] = 0; // Here we are using xyLoc to store grid cells, not pixel cells Queue <xyLoc> q = new Queue <xyLoc> (); AddNeighbors(q, m, x, y); while (q.Count > 0) { xyLoc l = q.Dequeue(); if (distances[l.x, l.y] == 1000) { if (dotx == 1000 && (m.GetCellType(l.x, l.y) == GameMaze.occupancy.kDot)) { dotx = l.x; doty = l.y; } if (pelletx == 1000 && m.GetCellType(l.x, l.y) == GameMaze.occupancy.kPowerUp) { pelletx = l.x; pellety = l.y; } distances [l.x, l.y] = GetBestNeighborDist(l.x, l.y) + 1; AddNeighbors(q, m, l.x, l.y); } } }
GameController.direction MoveTowards(xyLoc loc) { if (distances[loc.x, loc.y] == 0) { return(lastDirection); } if (distances[loc.x, loc.y] == 1) { // Move is to get to our loc; need to reverse it switch (GetBestNeighborMove(loc.x, loc.y)) { case GameController.direction.kLeft: return(GameController.direction.kRight); case GameController.direction.kRight: return(GameController.direction.kLeft); case GameController.direction.kUp: return(GameController.direction.kDown); case GameController.direction.kDown: return(GameController.direction.kUp); } } switch (GetBestNeighborMove(loc.x, loc.y)) { case GameController.direction.kLeft: return(MoveTowards(loc.x - 1, loc.y)); case GameController.direction.kRight: return(MoveTowards(loc.x + 1, loc.y)); case GameController.direction.kUp: return(MoveTowards(loc.x, loc.y + 1)); case GameController.direction.kDown: return(MoveTowards(loc.x, loc.y - 1)); } return(GameController.direction.kNone); }
public GameController.direction GetAction(GameMaze m, GameController c, xyLoc yourLoc) { if ((yourLoc.x / 8 != lastx || yourLoc.y / 8 != lasty) && (yourLoc.x % 8 == 0 && yourLoc.y % 8 == 0)) { lastx = yourLoc.x / 8; lasty = yourLoc.y / 8; GetDistances(c, m, lastx, lasty); float lUtil, rUtil, dUtil, uUtil; lUtil = GetDirectionUtility(c, m, GameController.direction.kLeft); rUtil = GetDirectionUtility(c, m, GameController.direction.kRight); dUtil = GetDirectionUtility(c, m, GameController.direction.kDown); uUtil = GetDirectionUtility(c, m, GameController.direction.kUp); float max = Mathf.NegativeInfinity; if (lUtil > max) { lastDirection = GameController.direction.kLeft; max = lUtil; } if (rUtil > max) { lastDirection = GameController.direction.kRight; max = rUtil; } if (dUtil > max) { lastDirection = GameController.direction.kDown; max = dUtil; } if (uUtil > max) { lastDirection = GameController.direction.kUp; max = uUtil; } } return(lastDirection); }
void CheckPacmanCollision(xyLoc ghost, ControlledObject obj) { if (!obj.IsAlive()) { return; } if ((pacmanLoc.x + 4) / 8 == (ghost.x + 4) / 8 && (pacmanLoc.y + 4) / 8 == (ghost.y + 4) / 8) { if (currentGameMode == gameMode.kPowerUpGameMode) { obj.Kill(); GetSound(gameSound.kEatGhost).Play(); } else { currentGameMode = gameMode.kLifeOver; elapsedTime = 0; GetSound(gameSound.kBackgroundSound).Stop(); GetSound(gameSound.kDieSound).Play(); } } }
// Extract the path from the given state to the goal. // (Only runs if search successfully found the goal.) public List <xyLoc> ExtractPath() { List <xyLoc> result = new List <xyLoc>(); if (!success) { return(result); } // Write code here. xyLoc item = new xyLoc(g.x, g.y); result.Add(item); xyLoc parentNode; do { parentNode = openClosed[item.x, item.y].parent; result.Add(parentNode); item.x = parentNode.x; item.y = parentNode.y; } while (item != openClosed[item.x, item.y].parent); return(result); }
// Continue the previous search. (Assumes Init is called first.) public bool Step(xyLoc start, xyLoc goal, Map m) { xyLoc next = GetNextToExpand(); // Found optimal path if (next == goal) { success = true; return(true); } // Exhausted open list if (next.x == -1) { return(true); } // Continue search Expand(m, next); AddToClosed(next); return(false); }
GameController.direction MakeRandomAction(xyLoc myLoc, GameController.direction forbidden, GameController c) { while (true) { switch (Random.Range(0, 4)) { case 0: if (c.CanMove(myLoc, GameController.direction.kUp) && forbidden != GameController.direction.kUp) { return(GameController.direction.kUp); } break; case 1: if (c.CanMove(myLoc, GameController.direction.kLeft) && forbidden != GameController.direction.kLeft) { return(GameController.direction.kLeft); } break; case 2: if (c.CanMove(myLoc, GameController.direction.kDown) && forbidden != GameController.direction.kDown) { return(GameController.direction.kDown); } break; case 3: if (c.CanMove(myLoc, GameController.direction.kRight) && forbidden != GameController.direction.kRight) { return(GameController.direction.kRight); } break; } } }
public void GetTarget(out int x, out int y, GhostController.ghostMode currentMode, GameController c) { // default code that needs to be written x = y = 0; switch (currentMode) { case GhostController.ghostMode.kChase: // Where do you go in chase mode? //Vector2 offset = new Vector2 (c.inkyLoc.x, c.inkyLoc.y) - new Vector2 (c.pacmanLoc.x, c.pacmanLoc.y); xyLoc offset = new xyLoc(c.blinkyLoc.x - c.pacmanLoc.x, c.blinkyLoc.y - c.pacmanLoc.y); int xOff = 0; int yOff = 0; switch (c.pacmanLastMove) { case GameController.direction.kLeft: xOff = c.pacmanLoc.x - 2; yOff = c.pacmanLoc.y; x = (xOff + offset.x) / 8; y = (yOff + offset.y) / 8; break; case GameController.direction.kRight: xOff = c.pacmanLoc.x + 2; yOff = c.pacmanLoc.y; x = (xOff + offset.x) / 8; y = (yOff + offset.y) / 8; break; case GameController.direction.kUp: xOff = c.pacmanLoc.x; yOff = c.pacmanLoc.y + 2; x = (xOff + offset.x) / 8; y = (yOff + offset.y) / 8; break; case GameController.direction.kDown: xOff = c.pacmanLoc.x; yOff = c.pacmanLoc.y - 2; x = (xOff + offset.x) / 8; y = (yOff + offset.y) / 8; break; default: break; } break; case GhostController.ghostMode.kScatter: // Where do you go in scatter mode? y = 0; x = 244 / 8; break; case GhostController.ghostMode.kDead: // back in ghost box // Moves to top of ghost box before regenerating x = 13; y = 21; break; case GhostController.ghostMode.kLeavingHouse: // back in ghost box // Moves to top of ghost box before starting regular behavior x = 13; y = 21; break; default: // no target x = y = 0; break; } }