diff --git a/day6.zig b/day6.zig new file mode 100644 index 0000000..92e5212 --- /dev/null +++ b/day6.zig @@ -0,0 +1,456 @@ +const std = @import("std"); + +const utils = @import("utils.zig"); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const alloc = gpa.allocator(); + + const filename = "inputs/day6.txt"; + + { + const file_reader = try utils.FileReader.init(alloc, filename); + defer file_reader.deinit(); + + const result = try part1(alloc, file_reader.reader()); + + try std.io.getStdOut().writer().print("Day 6, part 1: {}\n", .{result}); + } + + { + const file_reader = try utils.FileReader.init(alloc, filename); + defer file_reader.deinit(); + + const result = try part2(alloc, file_reader.reader()); + + try std.io.getStdOut().writer().print("Day 6, part 1: {}\n", .{result}); + } +} + +const Orientation = enum { + up, + right, + down, + left, +}; + +const MapElem = enum { + empty, + obstacle, + guard, + visited, +}; + +const GuardPos = struct { + x: i32, + y: i32, + orientation: Orientation, +}; + +const Map = [][]MapElem; + +const MapState = struct { + alloc: std.mem.Allocator, + + size_x: usize, + size_y: usize, + + map: Map, + + guard_pos: GuardPos, + + pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + _ = fmt; + _ = options; + + for (self.map) |line| { + for (line) |elem| { + const c: u8 = switch (elem) { + .empty => '.', + .guard => switch (self.guard_pos.orientation) { + .up => '^', + .down => 'v', + .left => '<', + .right => '>', + }, + .obstacle => '#', + .visited => 'X', + }; + + try writer.print("{c}", .{c}); + } + + try writer.print("\n", .{}); + } + } + + fn deinit(self: MapState) void { + for (self.map) |map_line| { + self.alloc.free(map_line); + } + + self.alloc.free(self.map); + } + + fn copyFrom(self: *MapState, other: MapState) void { + for (self.map, other.map) |*map_line, map_line_orig| { + @memcpy(map_line.*, map_line_orig); + } + } + + fn clone(self: MapState, alloc: std.mem.Allocator) !MapState { + const map_orig = self.map; + + const map = try alloc.alloc([]MapElem, map_orig.len); + + for (map, map_orig) |*map_line, map_line_orig| { + map_line.* = try alloc.alloc(MapElem, map_line_orig.len); + } + + var new_map_state = MapState{ + .alloc = alloc, + .size_x = self.size_x, + .size_y = self.size_y, + .guard_pos = self.guard_pos, + .map = map, + }; + + new_map_state.copyFrom(self); + + return new_map_state; + } + + fn parse(alloc: std.mem.Allocator, reader: anytype) !MapState { + var line_reader = utils.lineReader(alloc, reader); + defer line_reader.deinit(); + + var map = std.ArrayList([]MapElem).init(alloc); + + var guard_pos: GuardPos = undefined; + + var x: usize = 0; + while (try line_reader.next()) |line| : (x += 1) { + const map_line = try alloc.alloc(MapElem, line.len); + + for (0.., line, map_line) |y, c, *map_elem| { + map_elem.* = switch (c) { + '.' => .empty, + '#' => .obstacle, + '^' => blk: { + guard_pos = GuardPos{ + .x = @intCast(x), + .y = @intCast(y), + .orientation = .up, + }; + + break :blk .guard; + }, + else => unreachable, + }; + } + + try map.append(map_line); + } + + const map_slice = try map.toOwnedSlice(); + map.deinit(); + + const size_x = map_slice.len; + const size_y = map_slice[0].len; + + for (map_slice) |map_line| { + std.debug.assert(map_line.len == size_y); + } + + return .{ + .alloc = alloc, + .size_x = size_x, + .size_y = size_y, + .map = map_slice, + .guard_pos = guard_pos, + }; + } + + fn get(self: MapState, x: i32, y: i32) MapElem { + std.debug.assert(0 <= x and x < (self.size_x)); + std.debug.assert(0 <= y and y < (self.size_y)); + + return self.map[@intCast(x)][@intCast(y)]; + } + + fn set(self: *MapState, x: i32, y: i32, elem: MapElem) void { + std.debug.assert(0 <= x and x < (self.size_x)); + std.debug.assert(0 <= y and y < (self.size_y)); + + self.map[@intCast(x)][@intCast(y)] = elem; + } + + fn turn(self: *MapState) void { + self.guard_pos.orientation = switch (self.guard_pos.orientation) { + .up => .right, + .right => .down, + .down => .left, + .left => .up, + }; + } + + fn nextPos(self: MapState) ?struct { x: i32, y: i32 } { + const guard_pos = self.guard_pos; + + const x = guard_pos.x; + const y = guard_pos.y; + + var new_x: i32 = undefined; + var new_y: i32 = undefined; + + switch (guard_pos.orientation) { + .up => { + new_x = x - 1; + new_y = y; + + if (new_x < 0) { + return null; + } + }, + .right => { + new_x = x; + new_y = y + 1; + + if (new_y >= self.size_y) { + return null; + } + }, + .down => { + new_x = x + 1; + new_y = y; + + if (new_x >= self.size_x) { + return null; + } + }, + .left => { + new_x = x; + new_y = y - 1; + + if (new_y < 0) { + return null; + } + }, + } + + return .{ .x = new_x, .y = new_y }; + } + + fn advance(self: *MapState) enum { not_done, done } { + const guard_pos = &self.guard_pos; + + const x = guard_pos.x; + const y = guard_pos.y; + + if (self.get(x, y) != .guard) { + std.debug.print("x: {} y: {}\n", .{ x, y }); + std.debug.print("map on failure:\n{}\n", .{self}); + } + + std.debug.assert(self.get(x, y) == .guard); + + const new_pos = self.nextPos() orelse { + // walked out of the map + std.debug.assert(self.get(x, y) == .guard); + + self.set(x, y, .visited); + + return .done; + }; + + const new_x = new_pos.x; + const new_y = new_pos.y; + + if (self.get(new_x, new_y) == .obstacle) { + // found obstacle: turn and advance + self.turn(); + return advance(self); + } + + std.debug.assert(self.get(x, y) == .guard); + self.set(x, y, .visited); + + guard_pos.x = new_x; + guard_pos.y = new_y; + + self.set(new_x, new_y, .guard); + + return .not_done; + } + + fn countVisited(self: MapState) u64 { + var count: u64 = 0; + + for (self.map) |line| { + for (line) |elem| { + std.debug.assert(elem != .guard); + + if (elem == .visited) { + count += 1; + } + } + } + + return count; + } +}; + +fn part1(alloc: std.mem.Allocator, reader: anytype) !u64 { + var map_arena = std.heap.ArenaAllocator.init(alloc); + defer map_arena.deinit(); + + var map_state = try MapState.parse(map_arena.allocator(), reader); + + while (map_state.advance() != .done) {} + + const visited_count = map_state.countVisited(); + + return visited_count; +} + +fn part2(alloc: std.mem.Allocator, reader: anytype) !u64 { + var map_arena = std.heap.ArenaAllocator.init(alloc); + defer map_arena.deinit(); + + const map_state_orig = try MapState.parse(map_arena.allocator(), reader); + + var map_state_iter = try map_state_orig.clone(map_arena.allocator()); + + var tmp_arena = std.heap.ArenaAllocator.init(alloc); + defer tmp_arena.deinit(); + + var num_loops: u64 = 0; + + var map_state_all_obstacles = try map_state_orig.clone(alloc); + defer map_state_all_obstacles.deinit(); + + var guard_pos_set = std.AutoHashMap(GuardPos, void).init(alloc); + defer guard_pos_set.deinit(); + + while (map_state_iter.advance() != .done) { + + // current guard pos after last step + const cur_guard_pos = map_state_iter.guard_pos; + + const cur_x = cur_guard_pos.x; + const cur_y = cur_guard_pos.y; + + if (cur_x == map_state_orig.guard_pos.x and cur_y == map_state_orig.guard_pos.y) { + // don't put obstacle at initial position! + continue; + } + + if (map_state_all_obstacles.get(cur_x, cur_y) == .obstacle) { + // we already tried this one + continue; + } + + // clone original map state + var map_state_modified = try map_state_orig.clone(tmp_arena.allocator()); + + // put a new obstacle at the current position of the guard + // since obstacles only influence the path of the guard if she would step on, + // conversely the only relevant positions for new obstacles are the tiles she actually + // steps on + map_state_modified.set(cur_x, cur_y, .obstacle); + map_state_all_obstacles.set(cur_x, cur_y, .obstacle); + + guard_pos_set.clearRetainingCapacity(); + + try guard_pos_set.put(map_state_modified.guard_pos, {}); + + while (map_state_modified.advance() != .done) { + // std.debug.print("modified map:\n{}\n", .{map_state_modified}); + + const guard_pos = map_state_modified.guard_pos; + + if (guard_pos_set.contains(guard_pos)) { + num_loops += 1; + break; + } + + try guard_pos_set.put(map_state_modified.guard_pos, {}); + } + + _ = tmp_arena.reset(.retain_capacity); + } + + return num_loops; +} + +test "part1 example" { + const alloc = std.testing.allocator; + + const example = + \\....#..... + \\.........# + \\.......... + \\..#....... + \\.......#.. + \\.......... + \\.#..^..... + \\........#. + \\#......... + \\......#... + ; + + var stream = std.io.fixedBufferStream(example); + + const result = try part1(alloc, stream.reader()); + + try std.testing.expect(result == 41); +} + +test "part1 input" { + const alloc = std.testing.allocator; + + const filename = "inputs/day6.txt"; + + const file_reader = try utils.FileReader.init(alloc, filename); + defer file_reader.deinit(); + + const result = try part1(alloc, file_reader.reader()); + + try std.testing.expect(result == 4722); +} + +test "part2 example" { + const alloc = std.testing.allocator; + + const example = + \\....#..... + \\.........# + \\.......... + \\..#....... + \\.......#.. + \\.......... + \\.#..^..... + \\........#. + \\#......... + \\......#... + ; + + var stream = std.io.fixedBufferStream(example); + + const result = try part2(alloc, stream.reader()); + + try std.testing.expect(result == 6); +} + +test "part2 input" { + const alloc = std.testing.allocator; + + const filename = "inputs/day6.txt"; + + const file_reader = try utils.FileReader.init(alloc, filename); + defer file_reader.deinit(); + + const result = try part2(alloc, file_reader.reader()); + + try std.testing.expect(result == 1602); +} diff --git a/inputs/day6.txt b/inputs/day6.txt new file mode 100644 index 0000000..3c8989d --- /dev/null +++ b/inputs/day6.txt @@ -0,0 +1,130 @@ +..#.....................#............#....#...........#...............................#.....#..................................... +.................#............................#.............##..#...............................#....#..#.........#............... +.............................................##.........................................#....................#...............#...# +...##....................#...............#.....#....................#......##..............#............................#....#.... +.................................#..#..............#...........#.............#..#........................#............#........... +.................#.........................#...........................#........................#........................#........ +...#....................................#....#.........#................#...............#.....#................#.....#............ +.............#.#..........................................................#...#..................#....#.......#.....#...#......... +.....#........................#....##...#............................................................#............................ +..................#...#.........................................#..................#.............................#.#........#..... +......#...............................#.#..........##..#...........#.........................#.......#....................#....... +.................................#..............#...............#........#..........#.........#............#.........#.......#...# +..#..#............#...#.....................#...............#............#.#........................#........#...............#.... +..............#..#.#........................#.........#...........##.......#..........#.....................#..............#...#.. +..........................#.................##...................................#....#.........#................................. +..................#..#........#....#...............#..............#.......#.......#......................................#..#...#. +..........#.#.................#.........#...................#.......................##......#....................#.......#........ +..........#.........#...#......................................................................#.....#............#........#...... +...##.............#...........................................................#..#....................##.#...#.#..#.........#..#.. +.....#......#.............................#.......#...#...#...............#.....#............#........#..#.#...................... +........#................#.........#.......................................................................#..........#........... +.......#........................................#..........#...............................#..#................................... +..................##.......#.......#.....#............#.......#...#.........#....##...............#..#.............#..........#... +.......#...........#...........#...........................#.............#.........#..#........................#.##............... +.....................................................................#........#....#...........................................#.. +....#...........#......#.........#....................................#.................................#......#.................. +...#........................................#..#...............................#.....................#.#......#................... +..#.....#.................................#.................#....#............................................#......#............ +...................................................##...........#.......#.............#.................#.......#................. +..........................................................##..............#....#....#.............#............................... +........................................................#.....................................#................................#.. +..............##....#..#..........#...........#......#..#....#.......#................#............................#..#...#....... +..........................#....................#.................................................#................................ +#................................................#.....................#..#...............##........#...#...#.........#........... +...........#.................................#..#....................#.#.......#..........................#.......#.......#....... +..............................#......#......#.................#.................#.................#.#.............#..#.#.......... +.......................#....................#....................................#.....#.#.......#............................#... +...............................................................................................#.#................................ +#..................#.....#...............................#..............#...#..................................................... +..........................................................#.................................................#..................... +..........#.........................#.....................................................#.........#..........#................#. +........#..............#..#......................................#.........#............#.................................#....... +.......#.........................................................#.........#................#...............................#..... +...........#............................................#...#.............................#.....^................................# +................#.............#...#..............................#..................................#............................. +.........................................................................................................#........................ +.................................................#........#.......................#.#.....#......................#................ +.........#.........#...#....................................................#..................................................... +##.##..#...................................#...................................................................................... +.................#...........................................................................................#........#........... +.........................................................................#........................#....#......................#... +..............#......................#........#..........................#.........#.............................................. +.......................#............................................................................##............................ +.....#.................#........#...#...............#.............................#......................#........................ +....#...................................................................................#............##........................... +................#............................#............................................#....................................... +.......................................................................................................#......#................... +......................................................................................#...#....................................... +...............................................#........#..........#............................#..............#.......#.......... +..............#.....................#........#..#............................#...#..#.#...................................#....... +..........#...............................#............................#...........................................#.............. +....#............#.#....#......................................................................#.................................. +.......................#.......................#................................#..............#.....................#.........#.. +...........#.........................#.............#.#........#........#..........................................#............... +.......#......................#....................#...............................#......................#...........#........... +............#..................................................................................................................... +....#.......#............................................................#.........#.............#..........#....#..........#..... +.......#.........................................................................#..................#..#....#.......#............. +............................#....#.......#......#.......#.....................#.................#................................. +.......................................................#.............#..........................#................................. +....................................#.....................................##......................#............................#.. +..............#...............#....................#.......................#................#......................#.............. +....................#...........................#...................................................................#............. +...#..........................#...........................#............................................................#.......... +..............#.................#.............................#..#.......#.......................#.##............................. +....................#.....#...#..............................................#......#...........#.................#..#....#....... +#......................................#.....................#..#..#.#...........#.............#.................................# +.....................#...........................................................#..........#............##..........#............ +.......#..................................#...............#..........#....#...................................................#... +.............#.................#...........................#..............#.................................................#..... +...............................#......................................##...................................#.#......#..........#.. +.................##....................#.................................................#......................#................# +........#....................................#..........#.........................#..................#......................#..... +...#....#...........................#..............................#.#..........................#................................. +.#...................................#..#......#.................................................................#................ +.................................#...........#................#.#........................#....................................##.. +#..#.....##...............#................................................................#....#......#.........................# +.#....#......................................................#.........................#.......................................#.. +.#..............................................#.................................................................#............... +...............#..........................................#...#...............................#.#..#.#........#................... +..............#................................#.......#..................................#.........................#........#.... +.......................##..................................................#...................................................... +..............................#...............................##.................................................................. +#....................#...........................................................#.............................#.................. +#..................................................................#...#.......................................................... +#..#........#...................................#..#..........##..............#................................................... +.......................#.....................#.................................................................................... +.....................#...........#.............................................................#........................#....#.... +...............#............................................................................##...#..........................#..... +...#......................................#....................................................................................... +....#...........................#.........#.................................................#..........#...#........#....#........ +......#....#.#............................#..........................................#........................................#... +...........#...#.............................................#......................#..................#.....................#.... +...#..........#........#..........#.......#..............#.............................#.......................#................#. +...........#...............#...........................................................#.......................................... +..#..........##.................................................#...#...............#.......................#...............##.... +.......................#..............#.............#......................................................#..................#... +..............#..#........##..........#...................................................#.............##....................#... +...................#..................................................#................#......#.....#.........#.#...#............. +..................#.................................................#.................................................#.........#. +......................................#.#........#.....#...#..........#..............#.........................#...#.............. +.................................#..............#..#.....................#................#.............#..#..#................... +.........#.......#.#..............#..#...............#.................#..................................#..#.................... +.............................#....#.......##..................................................................................##.. +.....................................................................................#........#.......#......#.................... +........#...........#..........#..........#............................#...............#........#.#...........................#... +.#.................#...#..............#...#...................#........#...............#.......................................... +.........#............................................##........#......#.....................#.......................#............ +.......................................#..........#..#......#........#..........#..........................#....................#. +....#......#..........................#....................#.......................................#.....###.......#.............. +.......#..................#....#.......................................................................#.......................... +....#........................#.............................................................#.......#..........................#... +......................#.................................#..........#................#..#.........................#................ +...........#....................................................#..............#...........................#...................... +.....#................#........#...#....#........#............#...............#.......................#..#.........#.............. +#..................................................#...........................#....#...........#................................. +....#.#.....................................#.#...............#................#....................................#............. +............#....................#.#.#...............................................#...................##....................... +...##..............#........................#.............#.......#...........#.#.##..............................#....##......... +......#...........#....................................................#.........................##...............................