protected PointOfInterest standingOrder(Point2D whereIAm) { Point2D target = new Point2D.Double( whereIAm.getX() + (spiralHeading.getDx() * MOVEMENT_LENGTH), whereIAm.getY() + (spiralHeading.getDy() * MOVEMENT_LENGTH)); while (!StaticDiver.pointIsOnBoard(target.getX(), target.getY(), boardRadius)) { switch (spiralHeading) { case N: spiralHeading = Direction.W; break; case E: spiralHeading = Direction.N; break; case S: spiralHeading = Direction.E; break; case W: spiralHeading = Direction.S; break; } target = new Point2D.Double( whereIAm.getX() + (spiralHeading.getDx() * MOVEMENT_LENGTH), whereIAm.getY() + (spiralHeading.getDy() * MOVEMENT_LENGTH)); } return new PointOfInterest(target); }
/*Should only be called once*/ private void findDanger() { for (Observation o : whatYouSee) { // logger.trace("What I see: " + o.getName() + "\t\tIs it dangerous? " + o.isDangerous()); if (!o.isDangerous()) continue; Point2D predictedLocation; int speed = 0; int happy = 0; // can't use o.happiness() because that is 0 when you are on boat! for (SeaLifePrototype life : seaLifePossibilities) { if (life.getName().equals(o.getName())) { speed = life.getSpeed(); happy = life.getHappiness(); break; } } // Get the location and distance based on predicted location // (taking into account whether creature is stationary or moving). if (speed == 0 || o.getDirection() == null) { predictedLocation = o.getLocation(); } else { // predict where it will be Point2D loc = new Point2D.Double( // o.getLocation().getX() + (o.getDirection().getDx() * // (o.getDirection().isDiag() ? 3 : 2)), // o.getLocation().getY() + (o.getDirection().getDy() * // (o.getDirection().isDiag() ? 3 : 2)) o.getLocation().getX() + (o.getDirection().getDx()), o.getLocation().getY() + (o.getDirection().getDy())); if (ourBoard.inBounds((int) loc.getX(), (int) loc.getY())) { predictedLocation = loc; } else { predictedLocation = o.getLocation(); } } // For each Direction that diver can move, calculate the sum of danger from all creatures // affecting it. // The danger is scaled based on distance (decreases by a factor of radius). for (Direction d : Direction.values()) { Point2D nextPosition = new Point2D.Double(myPosition.getX() + d.getDx(), myPosition.getY() + d.getDy()); if (!ourBoard.inBounds((int) nextPosition.getX(), (int) nextPosition.getY())) continue; double distanceToCreature = Math.max(1.0, nextPosition.distance(predictedLocation)); // logger.debug("Direction:"+d+" distanceToCreature = " + distanceToCreature); // Only consider dangerous creatures if: // 1. They are stationary and affect cells next to the candidate cell, OR // 2. They are moving and affect cells within DANGER_MAX_DISTANCE of the candidate cell. if (o.isDangerous() && ((speed == 0 && distanceToCreature <= STATIONARY_DANGER_DISTANCE) || (speed > 0 && distanceToCreature <= DANGER_MAX_DISTANCE))) { double formerDirectionDanger = 0; if (directionDanger.containsKey(d)) { formerDirectionDanger = directionDanger.get(d); // logger.debug("formerDirectionDanger = " + formerDirectionDanger); } directionDanger.put( d, new Double( formerDirectionDanger + (Math.abs(happy * DANGER_MULTIPLIER) / Math.pow(distanceToCreature, 2)))); } } } }
public Direction findSafestDirection( Point2D myPosition, Point2D myPreviousPosition, Set<Observation> whatYouSee, Direction preferredDirection, boolean shouldReturnToBoat) { updateCoordinates(myPosition, myPreviousPosition, whatYouSee); findDanger(); // if we are at boat, reset the tracked helper state if (myPosition.equals(new Point2D.Double(0, 0))) { backtrackLocations.clear(); } // logger.debug("in find safest direction"); double minDanger = Integer.MAX_VALUE; ArrayList<DirectionAndDanger> directionsSafeToDangerous = new ArrayList<DirectionAndDanger>(); ArrayList<Direction> safestDirections = new ArrayList<Direction>(); // First, find the minimum danger. Create an equivalence class of directions sharing this value. for (Direction d : Direction.values()) { double curDanger; if (directionDanger.containsKey(d)) { curDanger = Math.abs(directionDanger.get(d)); // logger.trace("directionDanger.get("+d+") = "+curDanger); } else { curDanger = 0; } Point2D nextPosition = new Point2D.Double(myPosition.getX() + d.getDx(), myPosition.getY() + d.getDy()); // Do not consider directions that take us too close to the walls if (ourBoard.isNearBoundary( nextPosition, Math.max(WALL_MAX_DISTANCE, (double) r / Math.sqrt(2.0) - 1.0))) { continue; } // Do not consider directions that put us in backtracked locations // i.e. we are trying to go around danger, so don't go backwards if (backtrackLocations.contains(nextPosition)) { continue; } // logger.debug("current danger in direction " + d + ":" + curDanger); if (curDanger < minDanger) { safestDirections.clear(); safestDirections.add(d); // logger.debug("Min Danger so far in Direction: " + d); minDanger = curDanger; } else if (curDanger == minDanger) { safestDirections.add(d); } directionsSafeToDangerous.add(new DirectionAndDanger(d, curDanger)); } // Sort from least dangerous to most dangerous Collections.sort(directionsSafeToDangerous); mySafestDirection = null; if (shouldReturnToBoat) { // If returning to boat, always head in preferredDirection if it is among the safest if (preferredDirection == null) { mySafestDirection = null; } else if (safestDirections.contains(preferredDirection)) { mySafestDirection = preferredDirection; } else { // Prioritize the directions closer to the safest // And de-prioritize the previous location Direction previousDirection = OurBoard.getDirectionTowards(myPosition, myPreviousPosition); for (Direction d : DirectionUtil.getClosestDirections(preferredDirection)) { if (safestDirections.contains(d) && !d.equals(previousDirection)) { mySafestDirection = d; break; } } // We excluded previous direction in above loop. // If mySafestDirection == null, that means safest is previous direction. if (mySafestDirection == null) { if (!directionsSafeToDangerous.isEmpty()) { mySafestDirection = directionsSafeToDangerous.get(0).getDirection(); } else { // just go back towards boat... mySafestDirection = OurBoard.getDirectionTowards(myPosition, new Point2D.Double(0, 0)); } } // we did not pick preferredDirection, so next time make sure we don't come back backtrackLocations.add(myPreviousPosition); } } else { // 80% of the time, continue in preferredDirection if it is among the safest if (preferredDirection != null && safestDirections.contains(preferredDirection) && random.nextDouble() <= 0.80) { mySafestDirection = preferredDirection; } else { List<Direction> closestDirections = DirectionUtil.getClosestDirections(preferredDirection); // Try to pick the safest direction out of [forward-left, forward-right, left, right] List<Direction> firstTwo = closestDirections.subList(0, 2); List<Direction> nextTwo = closestDirections.subList(2, 4); // Look at the top 3 safest directions if (directionsSafeToDangerous.size() >= 3) { for (DirectionAndDanger dad : directionsSafeToDangerous.subList(0, 3)) { // skip the one going backwards if (dad.equals(OurBoard.getDirectionTowards(myPosition, myPreviousPosition))) { continue; } if (firstTwo.contains(dad.getDirection())) { mySafestDirection = dad.getDirection(); break; } else if (nextTwo.contains(dad.getDirection())) { mySafestDirection = dad.getDirection(); break; } } } if (mySafestDirection == null) { if (!safestDirections.isEmpty()) { Collections.shuffle(safestDirections); mySafestDirection = safestDirections.get(0); } else { // no safe directions?? return to boat then... mySafestDirection = OurBoard.getDirectionTowards(myPosition, new Point2D.Double(0, 0)); } } // we did not pick preferredDirection, so next time make sure we don't come back backtrackLocations.add(myPreviousPosition); } } // if we end up going in preferredDirection, no need to avoid backtrack areas anymore backtrackLocations.clear(); // logger.debug("Safest direction: " + mySafestDirection + " (from among " + // safestDirections.toString() + ")"); return mySafestDirection; }