/** * Run the game with time limit (asynchronous mode). This is how it will be done in the * competition. Can be played with and without visual display of game states. * * @param pacManController The Pac-Man controller * @param ghostController The Ghosts controller * @param visual Indicates whether or not to use visuals */ public void runGameTimed( Controller<MOVE> pacManController, Controller<EnumMap<GHOST, MOVE>> ghostController, boolean visual) { Game game = new Game(0); GameView gv = null; if (visual) gv = new GameView(game).showGame(); if (pacManController instanceof HumanController) gv.getFrame().addKeyListener(((HumanController) pacManController).getKeyboardInput()); new Thread(pacManController).start(); new Thread(ghostController).start(); while (!game.gameOver()) { pacManController.update(game.copy(), System.currentTimeMillis() + DELAY); ghostController.update(game.copy(), System.currentTimeMillis() + DELAY); try { Thread.sleep(DELAY); } catch (InterruptedException e) { e.printStackTrace(); } game.advanceGame(pacManController.getMove(), ghostController.getMove()); if (visual) gv.repaint(); } pacManController.terminate(); ghostController.terminate(); }
private Junction[] junctionDistances(Game game) { Maze m = game.getCurrentMaze(); int[] indices = m.junctionIndices; Junction[] junctions = new Junction[indices.length]; for (int q = 0; q < indices.length; q++) // from { MOVE[] possibleMoves = m.graph[indices[q]].allPossibleMoves.get(MOVE.NEUTRAL); // all possible moves junctions[q] = new Junction(q, indices[q], indices.length); for (int z = 0; z < indices.length; z++) // to (we need to include distance to itself) { for (int i = 0; i < possibleMoves.length; i++) { int neighbour = game.getNeighbour(indices[q], possibleMoves[i]); int[] p = m.astar.computePathsAStar(neighbour, indices[z], possibleMoves[i], game); m.astar.resetGraph(); junctions[q].addPath(z, possibleMoves[i], p); } } } return junctions; }
@Override public MOVE getMove(Game g, long t) { if (g.gameOver()) { currentDirection = null; } else if (!moved) { moved = true; return currentDirection; } else if (!g.isJunction(g.getPacmanCurrentNodeIndex()) && currentDirection != null) { ArrayList<MOVE> moves = new ArrayList<MOVE>(Arrays.asList(g.getPossibleMoves(g.getPacmanCurrentNodeIndex()))); // MOVE[]g.getPossibleMoves(pacmanNode) if (moves.contains(currentDirection)) { return currentDirection; } else { moves.remove(currentDirection.opposite()); currentDirection = moves.get(0); return moves.get(0); } } if (0 < t) { return run(g, t); } else { // TESTING MOVE m = run(g); return m; // // return run(g); } }
/** * Changes the state. Checks if there is active power pills nearby, if true go eat. Checks if * there still is a ghost close, if true stay in state Defaults to eat pill state * * @return returns change state. Returns null if it remains in this state */ public State changeState(Game game, long timeDue) { int pacmanPos = game.getPacmanCurrentNodeIndex(); // Check for power pill int closestPowerPill = 0; int closestDistPowerPill = -1; if (game.getNumberOfActivePowerPills() > 0) { for (int i : game.getActivePowerPillsIndices()) { int temp = game.getShortestPathDistance(pacmanPos, i); if (closestDistPowerPill > temp || closestDistPowerPill == -1) { closestPowerPill = i; closestDistPowerPill = temp; } } } if (game.getNumberOfActivePowerPills() > 0 && game.getShortestPathDistance(pacmanPos, closestPowerPill) < mach.DistToPowerPill) { // System.out.println("(RunFromGhost)Try power pill"); return (State) mach.dataStruc.get("moveNearestPowerPill"); } // Check for ghost distance for (GHOST ghost : GHOST.values()) { if (game.getGhostLairTime(ghost) > 0 || game.isGhostEdible(ghost)) { continue; } if (game.getShortestPathDistance(pacmanPos, game.getGhostCurrentNodeIndex(ghost)) < mach.DistFromNonEdible) { mach.dataStruc.put("ghost", ghost); return null; } } // System.out.println("(RunFromGhost) Try nearest pill"); return (State) mach.dataStruc.get("moveNearestPill"); }
private int Asearch(Game game) { Comparator<PacManNode> comparator = new PacComparator(); PriorityQueue<PacManNode> open = new PriorityQueue<PacManNode>(1, comparator); // because we are conducting tree-search, so 'closed' may not be used, but I'll still leave it // here HashSet<PacManNode> closed = new HashSet<PacManNode>(); open.add(new PacManNode(game.copy(), 0)); int score = game.getScore(); while (!open.isEmpty()) { PacManNode node = open.poll(); closed.add(node); if (node.depth == DEPTH) { // System.out. score = node.currentState.getScore(); return score; } MOVE[] moves = MOVE.values(); for (MOVE move : moves) { Game gameCopy = node.currentState.copy(); gameCopy.advanceGame(move, ghosts.getMove(gameCopy, 0)); open.add(new PacManNode(gameCopy, node.depth + 1)); } } return score; }
/** runs from current ghost */ @Override public MOVE run(Game game, long timeDue) { return game.getNextMoveAwayFromTarget( game.getPacmanCurrentNodeIndex(), game.getGhostCurrentNodeIndex((GHOST) mach.dataStruc.get("ghost")), DM.PATH); }
private double averageGhostDistance(Game state) { double sumDistance = 0; for (Constants.GHOST g : Constants.GHOST.values()) { double d = state.getManhattanDistance( state.getPacmanCurrentNodeIndex(), state.getGhostCurrentNodeIndex(g)); sumDistance += d; } return (sumDistance / Constants.GHOST.values().length); }
/** * Close to power. * * @param game the game * @return true, if successful */ private boolean closeToPower(Game game) { int pacmanIndex = game.getPacmanCurrentNodeIndex(); int[] powerPillIndices = game.getActivePowerPillsIndices(); for (int i = 0; i < powerPillIndices.length; i++) if (game.getShortestPathDistance(powerPillIndices[i], pacmanIndex) < PILL_PROXIMITY) return true; return false; }
public MOVE getMove(EnumMap<GHOST, MOVE> ghostMoves, Tree tree) { long start = System.currentTimeMillis(); LinkedList<Node> nodes = new LinkedList<Node>(); nodes.add(tree.getHeadNode()); int leftValue = Integer.MIN_VALUE; int rightValue = Integer.MIN_VALUE; int upValue = Integer.MIN_VALUE; int downValue = Integer.MIN_VALUE; while (!nodes.isEmpty()) { Node node = nodes.removeFirst(); node.setVisited(true); if (node.getPredecessor() != null) { // regular Node // set gameState and advance move based on current node Game gameState = node.getPredecessor().getGameState().copy(); gameState.advanceGame(node.getMove(), ghostMoves); node.setGameState(gameState); } if (node.getNeighbors() == null) { // end of tree branch int value = Evaluation.evaluateGameState(node.getGameState()); // get head node move type Node nodeType = node.getPredecessor(); while (nodeType.getPredecessor().getMove() != MOVE.NEUTRAL) { nodeType = nodeType.getPredecessor(); } switch (nodeType.getMove()) { case LEFT: if (value > leftValue) leftValue = value; break; case RIGHT: if (value > rightValue) rightValue = value; break; case UP: if (value > upValue) upValue = value; break; case DOWN: if (value > downValue) downValue = value; break; case NEUTRAL: break; } } else { // regular node // add neighbors to be searched ArrayList<Node> neighbors = node.getNeighbors(); for (Node neighbor : neighbors) { if (!neighbor.isVisited()) nodes.add(neighbor); } } } if (Evaluation.LOG_TIME) System.out.println(System.currentTimeMillis() - start); return Evaluation.getBestMove(leftValue, rightValue, upValue, downValue); }
/** * Checks if is crowded. * * @param game the game * @return true, if is crowded */ private boolean isCrowded(Game game) { GHOST[] ghosts = GHOST.values(); float distance = 0; for (int i = 0; i < ghosts.length - 1; i++) for (int j = i + 1; j < ghosts.length; j++) distance += game.getShortestPathDistance( game.getGhostCurrentNodeIndex(ghosts[i]), game.getGhostCurrentNodeIndex(ghosts[j])); return (distance / 6) < CROWDED_DISTANCE ? true : false; }
/* (non-Javadoc) * @see pacman.controllers.Controller#getMove(pacman.game.Game, long) */ public EnumMap<GHOST, MOVE> getMove(Game game, long timeDue) { int pacmanIndex = game.getPacmanCurrentNodeIndex(); for (GHOST ghost : GHOST.values()) { if (game.doesGhostRequireAction(ghost)) { int currentIndex = game.getGhostCurrentNodeIndex(ghost); // if ghosts are all in close proximity and not near Ms Pac-Man, disperse if (isCrowded(game) && !closeToMsPacMan(game, currentIndex)) myMoves.put(ghost, getRetreatActions(game, ghost)); // go towards the power pill locations // if edible or Ms Pac-Man is close to power pill, move away from Ms Pac-Man else if (game.getGhostEdibleTime(ghost) > 0 || closeToPower(game)) myMoves.put( ghost, game.getApproximateNextMoveAwayFromTarget( currentIndex, pacmanIndex, game.getGhostLastMoveMade(ghost), DM.PATH)); // move away from ms pacman // else go towards Ms Pac-Man else myMoves.put( ghost, game.getApproximateNextMoveTowardsTarget( currentIndex, pacmanIndex, game.getGhostLastMoveMade(ghost), DM.PATH)); // go towards ms pacman } } return myMoves; }
/** * Run the game in asynchronous mode but proceed as soon as both controllers replied. The time * limit still applies so so the game will proceed after 40ms regardless of whether the * controllers managed to calculate a turn. * * @param pacManController The Pac-Man controller * @param ghostController The Ghosts controller * @param fixedTime Whether or not to wait until 40ms are up even if both controllers already * responded * @param visual Indicates whether or not to use visuals */ public void runGameTimedSpeedOptimised( Controller<MOVE> pacManController, Controller<EnumMap<GHOST, MOVE>> ghostController, boolean fixedTime, boolean visual) { Game game = new Game(0); GameView gv = null; if (visual) gv = new GameView(game).showGame(); if (pacManController instanceof HumanController) gv.getFrame().addKeyListener(((HumanController) pacManController).getKeyboardInput()); new Thread(pacManController).start(); new Thread(ghostController).start(); while (!game.gameOver()) { pacManController.update(game.copy(), System.currentTimeMillis() + DELAY); ghostController.update(game.copy(), System.currentTimeMillis() + DELAY); try { int waited = DELAY / INTERVAL_WAIT; for (int j = 0; j < DELAY / INTERVAL_WAIT; j++) { Thread.sleep(INTERVAL_WAIT); if (pacManController.hasComputed() && ghostController.hasComputed()) { waited = j; break; } } if (fixedTime) Thread.sleep(((DELAY / INTERVAL_WAIT) - waited) * INTERVAL_WAIT); game.advanceGame(pacManController.getMove(), ghostController.getMove()); } catch (InterruptedException e) { e.printStackTrace(); } if (visual) gv.repaint(); } pacManController.terminate(); ghostController.terminate(); }
/** * Method which simulates the game from a given node/state * * @param n * @return */ private int defaultPolicy(Node n) { Game currentState = n.getState().copy(); int d = 0; while (!isStateTerminal(currentState) && d != depth) { MOVE localCurrentDirection = null; if (d == 0 || currentState.isJunction( currentState.getPacmanCurrentNodeIndex())) { // is in a junction MOVE[] moves = currentState.getPossibleMoves(currentState.getPacmanCurrentNodeIndex()); int i = rng.nextInt(moves.length); localCurrentDirection = moves[i]; while (moves[i] == localCurrentDirection.opposite()) { i = rng.nextInt(moves.length); } localCurrentDirection = moves[i]; } currentState.advanceGame( localCurrentDirection, controller.Controller.getGhostController().getMove(currentState, 0)); d++; } if (isStateTerminal(currentState)) { return -1; } return currentState.getScore(); }
/** * Gets the retreat actions. * * @param game the game * @param ghost the ghost * @return the retreat actions */ private MOVE getRetreatActions(Game game, GHOST ghost) { int currentIndex = game.getGhostCurrentNodeIndex(ghost); int pacManIndex = game.getPacmanCurrentNodeIndex(); if (game.getGhostEdibleTime(ghost) == 0 && game.getShortestPathDistance(currentIndex, pacManIndex) < PACMAN_DISTANCE) return game.getApproximateNextMoveTowardsTarget( currentIndex, pacManIndex, game.getGhostLastMoveMade(ghost), DM.PATH); else return game.getApproximateNextMoveTowardsTarget( currentIndex, game.getPowerPillIndices()[cornerAllocation.get(ghost)], game.getGhostLastMoveMade(ghost), DM.PATH); }
@Override public MOVE getMove(Game game, long timeDue) { int score = -1; MOVE ret = MOVE.NEUTRAL; MOVE[] moves = MOVE.values(); for (MOVE move : moves) { Game gameCopy = game.copy(); gameCopy.advanceGame(move, ghosts.getMove(gameCopy, timeDue)); int cur = Asearch(gameCopy); System.out.println(move.toString() + "\t score: " + cur); if (cur >= score) { score = cur; ret = move; } } System.out.println("Move to: " + ret.toString()); System.out.println("\t--------"); return ret; }
/** * Replay a previously saved game. * * @param fileName The file name of the game to be played * @param visual Indicates whether or not to use visuals */ public void replayGame(String fileName, boolean visual) { ArrayList<String> timeSteps = loadReplay(fileName); Game game = new Game(0); GameView gv = null; if (visual) gv = new GameView(game).showGame(); for (int j = 0; j < timeSteps.size(); j++) { game.setGameState(timeSteps.get(j)); try { Thread.sleep(DELAY); } catch (InterruptedException e) { e.printStackTrace(); } if (visual) gv.repaint(); } }
/** * Run a game in asynchronous mode: the game waits until a move is returned. In order to slow * thing down in case the controllers return very quickly, a time limit can be used. If fasted * gameplay is required, this delay should be put as 0. * * @param pacManController The Pac-Man controller * @param ghostController The Ghosts controller * @param visual Indicates whether or not to use visuals * @param delay The delay between time-steps */ public void runGame( Controller<MOVE> pacManController, Controller<EnumMap<GHOST, MOVE>> ghostController, boolean visual, int delay) { try { PrintStream out = new PrintStream("replay.txt"); Game game = new Game(0); GameView gv = null; if (visual) gv = new GameView(game).showGame(); while (!game.gameOver()) { game.advanceGame( pacManController.getMove(game.copy(), -1), ghostController.getMove(game.copy(), System.currentTimeMillis() + Long.MAX_VALUE)); try { Thread.sleep(delay); } catch (Exception e) { } if (visual) gv.repaint(); out.println(game.getGameState()); out.flush(); } out.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
@Override public Constants.MOVE getMove(Game game, long timeDue) { // Random random = new Random(); Constants.MOVE[] allMoves = Constants.MOVE.values(); int highSorce = -1; Constants.MOVE highMove = null; // Start State // int[] a = new int[5]; HashMap<MOVE, Integer> map = new HashMap<>(); HashMap<Integer, MOVE> map2 = new HashMap<>(); for (Constants.MOVE m : allMoves) { Game gameCopy = game.copy(); Game gameATM = gameCopy; gameATM.advanceGame(m, ghosts.getMove(gameATM, timeDue)); // Neighbors int tempHightSocre = this.hill_climbing_value(gameATM); map.put(m, tempHightSocre); map2.put(tempHightSocre, m); System.out.println("PacMan Trying Move:" + m + ", Socre:" + tempHightSocre); } int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; // Pick one with the highest score, if higher than cuurent state, move to the child state for (Map.Entry<MOVE, Integer> it : map.entrySet()) { min = Math.min(min, it.getValue()); max = Math.max(max, it.getValue()); } if (min == max) { highMove = MOVE.LEFT; } else { highMove = map2.get(max); } System.out.println("High Score:" + highSorce + ", High Move:" + highMove); return highMove; }
/** * Run a game in asynchronous mode: the game waits until a move is returned. In order to slow * thing down in case the controllers return very quickly, a time limit can be used. If fasted * gameplay is required, this delay should be put as 0. * * @param pacManController The Pac-Man controller * @param ghostController The Ghosts controller * @param visual Indicates whether or not to use visuals * @param delay The delay between time-steps */ public void runGame( Controller<MOVE> pacManController, Controller<EnumMap<GHOST, MOVE>> ghostController, boolean visual, int delay) { Game game = new Game(0); GameView gv = null; if (visual) gv = new GameView(game).showGame(); while (!game.gameOver()) { game.advanceGame( pacManController.getMove(game.copy(), -1), ghostController.getMove(game.copy(), -1)); try { Thread.sleep(delay); } catch (Exception e) { } if (visual) gv.repaint(); } }
public PathsCache(int mazeIndex) { junctionIndexConverter = new HashMap<Integer, Integer>(); this.game = new Game(0, mazeIndex); Maze m = game.getCurrentMaze(); int[] jctIndices = m.junctionIndices; for (int i = 0; i < jctIndices.length; i++) junctionIndexConverter.put(jctIndices[i], i); nodes = assignJunctionsToNodes(game); junctions = junctionDistances(game); for (int i = 0; i < junctions.length; i++) junctions[i].computeShortestPaths(); }
private DNode[] assignJunctionsToNodes(Game game) { Maze m = game.getCurrentMaze(); int numNodes = m.graph.length; DNode[] allNodes = new DNode[numNodes]; for (int i = 0; i < numNodes; i++) { boolean isJunction = game.isJunction(i); allNodes[i] = new DNode(i, isJunction); if (!isJunction) { MOVE[] possibleMoves = m.graph[i].allPossibleMoves.get(MOVE.NEUTRAL); for (int j = 0; j < possibleMoves.length; j++) { ArrayList<Integer> path = new ArrayList<Integer>(); MOVE lastMove = possibleMoves[j]; int currentNode = game.getNeighbour(i, lastMove); path.add(currentNode); while (!game.isJunction(currentNode)) { MOVE[] newPossibleMoves = game.getPossibleMoves(currentNode); for (int q = 0; q < newPossibleMoves.length; q++) if (newPossibleMoves[q].opposite() != lastMove) { lastMove = newPossibleMoves[q]; break; } currentNode = game.getNeighbour(currentNode, lastMove); path.add(currentNode); } int[] array = new int[path.size()]; for (int w = 0; w < path.size(); w++) array[w] = path.get(w); allNodes[i].addPath(array[array.length - 1], possibleMoves[j], i, array, lastMove); } } } return allNodes; }
/** * For running multiple games without visuals. This is useful to get a good idea of how well a * controller plays against a chosen opponent: the random nature of the game means that * performance can vary from game to game. Running many games and looking at the average score * (and standard deviation/error) helps to get a better idea of how well the controller is likely * to do in the competition. * * @param pacManController The Pac-Man controller * @param ghostController The Ghosts controller * @param trials The number of trials to be executed */ public void runExperiment( Controller<MOVE> pacManController, Controller<EnumMap<GHOST, MOVE>> ghostController, int trials) { double avgScore = 0; Random rnd = new Random(0); Game game; for (int i = 0; i < trials; i++) { game = new Game(rnd.nextLong()); while (!game.gameOver()) { long due = System.currentTimeMillis() + DELAY; game.advanceGame( pacManController.getMove(game.copy(), due), ghostController.getMove(game.copy(), due)); } avgScore += game.getScore(); System.out.println(i + "\t" + game.getScore()); } System.out.println(avgScore / trials); }
// Funcion que ejecuta varias veces el juego con los controladores que se le pasan por parametro y // devuelve la media de la puntiacion de todas las partidas public double runGenetico( Controller<MOVE> pacManController, Controller<EnumMap<GHOST, MOVE>> ghostController, int trials) { double avgScore = 0; Random rnd = new Random(0); Game game; for (int i = 0; i < trials; i++) { game = new Game(rnd.nextLong()); while (!game.gameOver()) { game.advanceGame( pacManController.getMove(game.copy(), System.currentTimeMillis() + DELAY), ghostController.getMove(game.copy(), System.currentTimeMillis() + DELAY)); } avgScore += game.getScore(); } // System.out.println(avgScore/trials); return (avgScore / trials); }
/** * Returns an exact copy of the game. This may be used for forward searches such as minimax. The * copying is relatively efficient. * * @return the game */ public Game copy() { Game copy = new Game(); copy.seed = seed; copy.rnd = new Random(seed); copy.laberintoActua = laberintoActua; copy.pills = (BitSet) pills.clone(); copy.powerPills = (BitSet) powerPills.clone(); copy.indiceDeLaberinto = indiceDeLaberinto; copy.cuentaElLvl = cuentaElLvl; copy.tiempoLvlActual = tiempoLvlActual; copy.tiempoTotal = tiempoTotal; copy.score = score; copy.fastamasComerMultiplicador = fastamasComerMultiplicador; copy.juegoTerminado = juegoTerminado; copy.timeOfLastGlobalReversal = timeOfLastGlobalReversal; copy.pacmanFueComido = pacmanFueComido; copy.pastillaFueComida = pastillaFueComida; copy.pildoraPoderFueComida = pildoraPoderFueComida; copy.pacman = pacman.copy(); copy.fantasmaComido = new EnumMap<GHOST, Boolean>(GHOST.class); copy.fantasmas = new EnumMap<GHOST, Ghost>(GHOST.class); for (GHOST ghostType : GHOST.values()) { copy.fantasmas.put(ghostType, fantasmas.get(ghostType).copy()); copy.fantasmaComido.put(ghostType, fantasmaComido.get(ghostType)); } return copy; }
public boolean test(Game game) { int totalTime = game.getTotalTime(); return (totalTime >= _min) && (totalTime <= _max); }
private boolean isStateTerminal(Game g) { return g.gameOver(); }
/* (non-Javadoc) * @see pacman.controllers.Controller#getMove(pacman.game.Game, long) */ public EnumMap<GHOST, MOVE> getMove(Game game, long timeDue) { myMoves.clear(); int targetNode = game.getPacmanCurrentNodeIndex(); if (game.doesGhostRequireAction(GHOST.BLINKY)) myMoves.put( GHOST.BLINKY, game.getApproximateNextMoveTowardsTarget( game.getGhostCurrentNodeIndex(GHOST.BLINKY), targetNode, game.getGhostLastMoveMade(GHOST.BLINKY), DM.PATH)); if (game.doesGhostRequireAction(GHOST.INKY)) myMoves.put( GHOST.INKY, game.getApproximateNextMoveTowardsTarget( game.getGhostCurrentNodeIndex(GHOST.INKY), targetNode, game.getGhostLastMoveMade(GHOST.INKY), DM.MANHATTAN)); if (game.doesGhostRequireAction(GHOST.PINKY)) myMoves.put( GHOST.PINKY, game.getApproximateNextMoveTowardsTarget( game.getGhostCurrentNodeIndex(GHOST.PINKY), targetNode, game.getGhostLastMoveMade(GHOST.PINKY), DM.EUCLID)); if (game.doesGhostRequireAction(GHOST.SUE)) myMoves.put(GHOST.SUE, moves[rnd.nextInt(moves.length)]); return myMoves; }
/** * Hill-climbing-value * * @param gameState * @return */ public int hill_climbing_value(Game gameState) { return gameState.getScore(); }
public int[] getPathFromA2B(int a, int b, MOVE lastMoveMade) { // not going anywhere if (a == b) return new int[] {}; // first, go to closest junction (there is only one since we can't reverse) JunctionData fromJunction = nodes[a].getNearestJunction(lastMoveMade); // if target is on the way to junction, then we are done for (int i = 0; i < fromJunction.path.length; i++) if (fromJunction.path[i] == b) return Arrays.copyOf(fromJunction.path, i + 1); // we have reached a junction, fromJunction, which we entered with moveEnteredJunction int junctionFrom = fromJunction.nodeID; int junctionFromId = junctionIndexConverter.get(junctionFrom); MOVE moveEnteredJunction = fromJunction.lastMove.equals(MOVE.NEUTRAL) ? lastMoveMade : fromJunction.lastMove; // if we are at a junction, consider last move instead // now we need to get the 1 or 2 target junctions that enclose the target point ArrayList<JunctionData> junctionsTo = nodes[b].closestJunctions; int minDist = Integer.MAX_VALUE; int[] shortestPath = null; int closestJunction = -1; boolean onTheWay = false; for (int q = 0; q < junctionsTo.size(); q++) { int junctionToId = junctionIndexConverter.get(junctionsTo.get(q).nodeID); if (junctionFromId == junctionToId) { if (!game.getMoveToMakeToReachDirectNeighbour( junctionFrom, junctionsTo.get(q).reversePath[0]) .equals(moveEnteredJunction.opposite())) { int[] reversepath = junctionsTo.get(q).reversePath; int cutoff = -1; for (int w = 0; w < reversepath.length; w++) if (reversepath[w] == b) cutoff = w; shortestPath = Arrays.copyOf(reversepath, cutoff + 1); minDist = shortestPath.length; closestJunction = q; onTheWay = true; } } else { EnumMap<MOVE, int[]> paths = junctions[junctionFromId].paths[junctionToId]; Set<MOVE> set = paths.keySet(); for (MOVE move : set) { if (!move.opposite().equals(moveEnteredJunction) && !move.equals(MOVE.NEUTRAL)) { int[] path = paths.get(move); if (path.length + junctionsTo.get(q).path.length < minDist) // need to take distance from toJunction to target into account { minDist = path.length + junctionsTo.get(q).path.length; shortestPath = path; closestJunction = q; onTheWay = false; } } } } } if (!onTheWay) return concat(fromJunction.path, shortestPath, junctionsTo.get(closestJunction).reversePath); else return concat(fromJunction.path, shortestPath); // return concat(fromJunction.path, junctionsTo.get(closestJunction).reversePath); }
@Override public MOVE getMove(Game game, long timeDue) { int current = game.getPacmanCurrentNodeIndex(); // Strategy 1: if any non-edible ghost is too close (less than MIN_DISTANCE), run away for (GHOST ghost : GHOST.values()) if (game.getGhostEdibleTime(ghost) == 0 && game.getGhostLairTime(ghost) == 0) if (game.getShortestPathDistance(current, game.getGhostCurrentNodeIndex(ghost)) < MIN_DISTANCE) return game.getNextMoveAwayFromTarget( game.getPacmanCurrentNodeIndex(), game.getGhostCurrentNodeIndex(ghost), DM.PATH); // Strategy 2: find the nearest edible ghost and go after them int minDistance = Integer.MAX_VALUE; GHOST minGhost = null; for (GHOST ghost : GHOST.values()) if (game.getGhostEdibleTime(ghost) > 0) { int distance = game.getShortestPathDistance(current, game.getGhostCurrentNodeIndex(ghost)); if (distance < minDistance) { minDistance = distance; minGhost = ghost; } } if (minGhost != null) // we found an edible ghost return game.getNextMoveTowardsTarget( game.getPacmanCurrentNodeIndex(), game.getGhostCurrentNodeIndex(minGhost), DM.PATH); // Strategy 3: go after the pills and power pills int[] pills = game.getPillIndices(); int[] powerPills = game.getPowerPillIndices(); ArrayList<Integer> targets = new ArrayList<Integer>(); for (int i = 0; i < pills.length; i++) // check which pills are available if (game.isPillStillAvailable(i)) targets.add(pills[i]); for (int i = 0; i < powerPills.length; i++) // check with power pills are available if (game.isPowerPillStillAvailable(i)) targets.add(powerPills[i]); int[] targetsArray = new int[targets.size()]; // convert from ArrayList to array for (int i = 0; i < targetsArray.length; i++) targetsArray[i] = targets.get(i); // return the next direction once the closest target has been identified return game.getNextMoveTowardsTarget( current, game.getClosestNodeIndexFromNodeIndex(current, targetsArray, DM.PATH), DM.PATH); }