import std; void main() { slurp!(char, long)("input", "%c%d").getManhattanDistanceForInstructions.writeln; } alias Instruction = Tuple!(char, long); alias RelativeWaypoint = Tuple!(long, long); auto rotateLeft(RelativeWaypoint relativeWaypoint, long n) { n = (n + 4) % 4; if (n == 0) return relativeWaypoint; return tuple(-relativeWaypoint[1], relativeWaypoint[0]).rotateLeft(n - 1); } struct ShipState { immutable long posX = 0; immutable long posY = 0; RelativeWaypoint relativeWaypoint = tuple(10, 1); ShipState withInstructionApplied(Instruction instruction) { return [ 'E': (long value) => ShipState(posX, posY, tuple(relativeWaypoint[0] + value, relativeWaypoint[1])), 'N': (long value) => ShipState(posX, posY, tuple(relativeWaypoint[0], relativeWaypoint[1] + value)), 'W': (long value) => ShipState(posX, posY, tuple(relativeWaypoint[0] - value, relativeWaypoint[1])), 'S': (long value) => ShipState(posX, posY, tuple(relativeWaypoint[0], relativeWaypoint[1] - value)), 'L': (long value) => ShipState(posX, posY, relativeWaypoint.rotateLeft(value / 90)), 'R': (long value) => ShipState(posX, posY, relativeWaypoint.rotateLeft((360 - value) / 90)), 'F': (long value) => ShipState(posX + relativeWaypoint[0] * value, posY + relativeWaypoint[1] * value, relativeWaypoint) ][instruction[0]](instruction[1]); } ShipState withInstructionsApplied(Instruction[] instructions) { if (instructions.empty) { return this; } return withInstructionApplied(instructions[0]).withInstructionsApplied(instructions[1 .. $]); } } auto getManhattanDistanceForInstructions(Instruction[] instructions) { auto finalState = ShipState().withInstructionsApplied(instructions); return abs(finalState.posX) + abs(finalState.posY); } unittest { auto input = [ tuple('F', 10L), tuple('N', 3L), tuple('F', 7L), tuple('R', 90L), tuple('F', 11L) ]; assert(input.getManhattanDistanceForInstructions == 286); }