Drone Rescue Mission
A Java exploration command center for the Island serious game, built with two teammates. It talks to the game engine, interprets what the drone observes, keeps its own picture of where it has been, and decides where to fly next across an unknown island, reporting the creek closest to the emergency site when the search is done.
The brief was to fly a drone over an unknown island and find the creek closest to an emergency site, then report that one creek id. The catch is what the drone can perceive. It cannot see the map. It can echo in a direction and be told what is out there and how far, it can scan the ground under itself, and it can fly or turn. Every one of those costs battery, and when the battery runs out the mission is over wherever it happens to be. So the whole problem is deciding what to do next from a very thin slice of information, over and over, without ever seeing the thing you are exploring.
The engine drives us rather than the other way round. It calls initialize with a heading and a budget, then loops: acknowledgeResults hands us the JSON reply to our last action, takeDecision asks for the next one, and at the end deliverFinalReport wants the creek id. Explorer is the class that satisfies that interface, and it is deliberately thin. It translates the reply into an Information object, passes it to the drone, asks the drone for a command, and serialises it. Every real decision happens behind that.
The flight splits into two jobs that have almost nothing in common. Crossing open water to find land is a search for a coastline: echo ahead, echo to the sides, turn when something is out there. Sweeping the island once you are on it is a lawnmower pattern: fly, scan, U-turn at the edge, come back one lane over. Writing both into one method would have produced exactly the tangle of flags the report warns about, so they are two implementations of a DecisionMaker interface, and the Drone holds one of each. FindLand runs first. Once it reports that it has reached land, the drone builds a GridSearch from the heading FindLand ended on and asks that one from then on. Switching phases is a reference being reassigned.
Inside each strategy the same problem repeats one level down, because a drone is never simply flying: it is echoing forward, or turning toward land, or halfway through a U-turn. Rather than track that with booleans, each strategy is a state machine whose states are classes. FindLand moves through StartingState, EchoForwardState, EchoRightState, EchoLeftState, TurnToLandState and FlyForwardState. GridSearch adds BigUTurnState, ScanState, FlyToEndState, FlyToUTurnState and the rest, fourteen in all. A state does one thing: look at what came back, return the command to send, and name the state to switch to. Adding a phase means adding a class rather than editing a conditional that everything else depends on.
Two smaller pieces carry more weight than their size suggests. The engine never tells the drone where it is, so VirtualCoordinateMap keeps that itself, updating x and y on every move and accounting for the fact that a turn moves the drone sideways as well as forward. Without those coordinates the creeks and the emergency site are just ids with no geometry, and the question cannot be answered. CalculateClosestCreek then does the arithmetic: Euclidean distance from each creek to the site, skipping duplicate coordinates, returning the nearest id.
Commands and DroneCommands sit between the decision and the wire. DroneCommands builds the vocabulary, fly, scan, echo, heading and stop, and Commands is the single place that knows the engine expects a JSON object with an action key and sometimes a direction. The report describes this as an adapter between the drone's actions and the engine's protocol. Whatever it is called, the value is that no state class anywhere assembles JSON by hand.
The stack is deliberately small: Java 21 with Maven, the org.json library for the engine dialogue, log4j2 for tracing a run, and JUnit for the tests. The whole thing is a jar the competition arena loads, so there is no server, no framework and nowhere to hide behind one.
The part of the report I still like is the part that admits what is wrong. The drone stops when the battery drops below 0.002 of what it started with, a number we arrived at by running different map sizes and battery levels until it stopped stranding itself, and it is hardcoded. Several fields are protected rather than private purely so the tests can reach them. We noted that an Observer would have handled environment updates more cleanly than passing Information down the chain, and that a Factory would have suited building the decision makers. None of that got fixed before the deadline. Writing it down was the assignment, but reading it back is the more useful part: the design was good enough that its weaknesses were specific, which is not true of the code I was writing a year before this.
Watch the island get found
This is a real run, not an illustration. We pointed the command center at map03.json from the repository and let it fly, and the engine wrote back everything below: 1,593 actions of dialogue, the points of interest the drone reported, and its own fog-of-war render of what got seen.
Watch the shape of it rather than the dot. The first stretch is FindLand: a straight run west into open water, echoing ahead for something solid, because at that point the drone knows nothing except which way it is pointing. The moment it makes landfall the flight changes character completely, and that is GridSearch taking over: long parallel passes with a U-turn at each end, scanning as it goes. Two strategies, one interface, and the handover is visible without anyone having to say where it happened.
The drone is not drawing this map. It cannot see the island at all: it gets a reply per action and keeps its own coordinates from the moves it has made. The island underneath is the one the map file describes, drawn here so you can see what the search was up against, and the fog is the honest half of the picture.
- Status
- Standby
- Explored
- Unknown
- Points of interest
- 0 / 11
- Map
- map03.json
- Land
- 17.51% of 25600.00 ha
- Budget spent
- 7,118 of 30,000
- Actions flown
- 1,593
Turquoise dots are creeks, the white one is the emergency site, and both sit where _pois.json puts them, appearing at the moment the transcript says the drone saw them. Finding them is not the goal in itself: the mission answers with the id of the creek closest to that site, which is the last line the log prints.
The design report
The write-up we submitted with it: an honest account of what the design got right and what it did not, including the hardcoded battery threshold we settled on after testing against different map sizes.