Created
January 10, 2021 01:29
-
-
Save j-mao/2f09d958958dfbe5064aac0f645eb25f to your computer and use it in GitHub Desktop.
Battlecode 2021 Pathfinding lecture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Battlecode 2021 | |
* Pathfinding Lecture - sample code | |
* | |
* Bug pathing and communication strategies. Run this on the map "Quadrants" for a sense of how | |
* this strategy behaves: watch the red robots in the bottom-left corner. | |
* | |
* https://www.battlecode.org/ | |
* https://github.com/battlecode/battlecode21 | |
*/ | |
package examplefuncsplayer; | |
import battlecode.common.*; | |
public strictfp class RobotPlayer { | |
static RobotController rc; | |
/** | |
* run() is the method that is called when a robot is instantiated in the Battlecode world. | |
* If this method returns, the robot dies! | |
**/ | |
@SuppressWarnings("unused") | |
public static void run(RobotController rc) throws GameActionException { | |
// This is the RobotController object. You use it to perform actions from this robot, | |
// and to get information on its current status. | |
RobotPlayer.rc = rc; | |
System.out.println("I'm a " + rc.getType() + " and I just got created!"); | |
while (true) { | |
// Try/catch blocks stop unhandled exceptions, which cause your robot to freeze | |
try { | |
// Here, we've separated the controls into a different method for each RobotType. | |
// You may rewrite this into your own control structure if you wish. | |
switch (rc.getType()) { | |
case ENLIGHTENMENT_CENTER: runEnlightenmentCenter(); break; | |
case POLITICIAN: runPolitician(); break; | |
default: return; // we're not creating these here | |
} | |
// Clock.yield() makes the robot wait until the next turn, then it will perform this loop again | |
Clock.yield(); | |
} catch (Exception e) { | |
System.out.println(rc.getType() + " Exception"); | |
e.printStackTrace(); | |
} | |
} | |
} | |
/** Enlightenment centers spam politicians */ | |
static void runEnlightenmentCenter() throws GameActionException { | |
RobotType toBuild = RobotType.POLITICIAN; | |
int influence = 50; | |
for (Direction dir : Direction.values()) { | |
if (rc.canBuildRobot(toBuild, dir, influence)) { | |
rc.buildRobot(toBuild, dir, influence); | |
} else { | |
break; | |
} | |
} | |
// a bit silly, but something for the sake of example: | |
sendLocation(rc.getLocation().translate(15, 7)); | |
} | |
static int enlightenmentCenterId = -1; | |
static MapLocation politicianTarget = null; | |
static void runPolitician() throws GameActionException { | |
if (enlightenmentCenterId == -1) { | |
for (RobotInfo robot : rc.senseNearbyRobots(-1, rc.getTeam())) { | |
if (robot.type == RobotType.ENLIGHTENMENT_CENTER) { | |
enlightenmentCenterId = robot.ID; | |
} | |
} | |
} | |
if (rc.canGetFlag(enlightenmentCenterId)) { | |
politicianTarget = getLocationFromFlag(rc.getFlag(enlightenmentCenterId)); | |
} | |
if (politicianTarget != null) { | |
basicBug(politicianTarget); | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////// | |
// COMMUNICATION | |
static final int NBITS = 7; | |
static final int BITMASK = (1 << NBITS) - 1; | |
static void sendLocation(MapLocation location) throws GameActionException { | |
int x = location.x, y = location.y; | |
int encodedLocation = ((x & BITMASK) << NBITS) + (y & BITMASK); | |
if (rc.canSetFlag(encodedLocation)) { | |
rc.setFlag(encodedLocation); | |
} | |
} | |
@SuppressWarnings("unused") | |
static void sendLocation(MapLocation location, int extraInformation) throws GameActionException { | |
int x = location.x, y = location.y; | |
int encodedLocation = (extraInformation << (2*NBITS)) + ((x & BITMASK) << NBITS) + (y & BITMASK); | |
if (rc.canSetFlag(encodedLocation)) { | |
rc.setFlag(encodedLocation); | |
} | |
} | |
static MapLocation getLocationFromFlag(int flag) { | |
int y = flag & BITMASK; | |
int x = (flag >> NBITS) & BITMASK; | |
// int extraInformation = flag >> (2*NBITS); | |
MapLocation currentLocation = rc.getLocation(); | |
int offsetX128 = currentLocation.x >> NBITS; | |
int offsetY128 = currentLocation.y >> NBITS; | |
MapLocation actualLocation = new MapLocation((offsetX128 << NBITS) + x, (offsetY128 << NBITS) + y); | |
// You can probably code this in a neater way, but it works | |
MapLocation alternative = actualLocation.translate(-(1 << NBITS), 0); | |
if (rc.getLocation().distanceSquaredTo(alternative) < rc.getLocation().distanceSquaredTo(actualLocation)) { | |
actualLocation = alternative; | |
} | |
alternative = actualLocation.translate(1 << NBITS, 0); | |
if (rc.getLocation().distanceSquaredTo(alternative) < rc.getLocation().distanceSquaredTo(actualLocation)) { | |
actualLocation = alternative; | |
} | |
alternative = actualLocation.translate(0, -(1 << NBITS)); | |
if (rc.getLocation().distanceSquaredTo(alternative) < rc.getLocation().distanceSquaredTo(actualLocation)) { | |
actualLocation = alternative; | |
} | |
alternative = actualLocation.translate(0, 1 << NBITS); | |
if (rc.getLocation().distanceSquaredTo(alternative) < rc.getLocation().distanceSquaredTo(actualLocation)) { | |
actualLocation = alternative; | |
} | |
return actualLocation; | |
} | |
//////////////////////////////////////////////////////////////////////////// | |
// BASIC BUG - just follow the obstacle while it's in the way | |
// not the best bug, but works for "simple" obstacles | |
// for better bugs, think about Bug 2! | |
static final double passabilityThreshold = 0.7; | |
static Direction bugDirection = null; | |
static void basicBug(MapLocation target) throws GameActionException { | |
Direction d = rc.getLocation().directionTo(target); | |
if (rc.getLocation().equals(target)) { | |
// do something else, now that you're there | |
// here we'll just explode | |
if (rc.canEmpower(1)) { | |
rc.empower(1); | |
} | |
} else if (rc.isReady()) { | |
if (rc.canMove(d) && rc.sensePassability(rc.getLocation().add(d)) >= passabilityThreshold) { | |
rc.move(d); | |
bugDirection = null; | |
} else { | |
if (bugDirection == null) { | |
bugDirection = d; | |
} | |
for (int i = 0; i < 8; ++i) { | |
if (rc.canMove(bugDirection) && rc.sensePassability(rc.getLocation().add(bugDirection)) >= passabilityThreshold) { | |
rc.setIndicatorDot(rc.getLocation().add(bugDirection), 0, 255, 255); | |
rc.move(bugDirection); | |
bugDirection = bugDirection.rotateLeft(); | |
break; | |
} | |
rc.setIndicatorDot(rc.getLocation().add(bugDirection), 255, 0, 0); | |
bugDirection = bugDirection.rotateRight(); | |
} | |
} | |
} | |
} | |
} | |
// vim: set ts=4 sts=4 sw=4 : |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment