const std = @import("std"); const PATH = "input/day12.txt"; const CardinalType = u2; const Cardinal = enum(CardinalType) { north, east, south, west, }; const Ship = struct { dir: Cardinal = .east, x: isize = 0, y: isize = 0, fn manhattan(self: @This()) usize { const absx = std.math.absInt(self.x) catch unreachable; const absy = std.math.absInt(self.y) catch unreachable; return @intCast(usize, absx + absy); } }; pub fn first(allocator: ?std.mem.Allocator) anyerror!usize { _ = allocator; const file = @embedFile(PATH); var lines = std.mem.tokenize(u8, file, "\n"); var ship = Ship{}; while (lines.next()) |line| { var op = line[0]; if (op == 'F') { switch (ship.dir) { .north => op = 'N', .east => op = 'E', .west => op = 'W', .south => op = 'S', } } switch (op) { 'N' => ship.y -= try std.fmt.parseUnsigned(isize, line[1..], 0), 'S' => ship.y += try std.fmt.parseUnsigned(isize, line[1..], 0), 'W' => ship.x -= try std.fmt.parseUnsigned(isize, line[1..], 0), 'E' => ship.x += try std.fmt.parseUnsigned(isize, line[1..], 0), 'R' => { const deg = try std.fmt.parseUnsigned(u9, line[1..], 0); const pos: i4 = @enumToInt(ship.dir); ship.dir = @intToEnum(Cardinal, @mod(pos + @intCast(i4, deg / 90), std.math.maxInt(CardinalType) + 1)); }, 'L' => { const deg = try std.fmt.parseUnsigned(u9, line[1..], 0); const pos: i4 = @enumToInt(ship.dir); ship.dir = @intToEnum(Cardinal, @mod(pos - @intCast(i4, deg / 90), std.math.maxInt(CardinalType) + 1)); }, else => unreachable, } } return ship.manhattan(); } const Waypoint = struct { x: isize = 10, y: isize = -1, }; pub fn second(allocator: ?std.mem.Allocator) anyerror!usize { _ = allocator; var file = @embedFile(PATH); var lines = std.mem.tokenize(u8, file, "\n"); var ship = Ship{}; var wp = Waypoint{}; while (lines.next()) |line| { switch (line[0]) { 'N' => wp.y -= try std.fmt.parseUnsigned(isize, line[1..], 0), 'S' => wp.y += try std.fmt.parseUnsigned(isize, line[1..], 0), 'W' => wp.x -= try std.fmt.parseUnsigned(isize, line[1..], 0), 'E' => wp.x += try std.fmt.parseUnsigned(isize, line[1..], 0), 'R', 'L' => { var deg = try std.fmt.parseUnsigned(u9, line[1..], 0); // R90 == L270 and R270 == L90 if (deg == 90 and line[0] == 'L') deg = 270 else if (deg == 270 and line[0] == 'L') deg = 90; // Rotate right with `deg` degrees switch (deg) { 0 => {}, 90 => { const tmp = wp.x; wp.x = -wp.y; wp.y = tmp; }, 180 => { wp.x *= -1; wp.y *= -1; }, 270 => { const tmp = wp.x; wp.x = wp.y; wp.y = -tmp; }, else => unreachable, } }, 'F' => { const times = try std.fmt.parseUnsigned(isize, line[1..], 0); ship.x += wp.x * times; ship.y += wp.y * times; }, else => unreachable, } } return ship.manhattan(); } test "day12a" { try std.testing.expectEqual(@as(usize, 1589), try first(std.testing.allocator)); } test "day12b" { try std.testing.expectEqual(@as(usize, 23960), try second(std.testing.allocator)); }