From c36f8c68052f74bb5f4d2528c76e04b6dc932082 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 14 Apr 2024 19:48:24 +0300 Subject: [PATCH] solve day 13 --- src/day13.zig | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.zig | 1 + 2 files changed, 236 insertions(+) create mode 100644 src/day13.zig diff --git a/src/day13.zig b/src/day13.zig new file mode 100644 index 0000000..07c5cbe --- /dev/null +++ b/src/day13.zig @@ -0,0 +1,235 @@ +const std = @import("std"); +const aoc = @import("./aoc.zig"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; + +const Map = struct { + tiles: std.ArrayList(bool), + width: u32, + height: u32, + + fn deinit(self: Map) void { + self.tiles.deinit(); + } + + fn print(self: Map) void { + for (0..self.height) |y| { + for (0..self.width) |x| { + const idx = y * self.width + x; + if (self.tiles.items[idx]) { + std.debug.print("#", .{}); + } else { + std.debug.print(".", .{}); + } + } + std.debug.print("\n", .{}); + } + } + + fn get(self: Map, x: u32, y: u32) bool { + assert(x < self.width); + assert(y < self.height); + return self.tiles.items[y * self.width + x]; + } +}; + +const Input = struct { + maps: std.ArrayList(Map), + + fn init(allocator: Allocator) Input { + return Input{ + .maps = std.ArrayList(Map).init(allocator) + }; + } + + fn deinit(self: Input) void { + for (self.maps.items) |map| { + map.deinit(); + } + self.maps.deinit(); + } +}; + +fn parse_map(allocator: Allocator, lines: []const []const u8) !Map { + var width: u32 = @intCast(lines[0].len); + var height: u32 = @intCast(lines.len); + var tiles = try std.ArrayList(bool).initCapacity(allocator, width*height); + errdefer tiles.deinit(); + + for (lines) |line| { + for (line) |tile| { + try tiles.append(tile == '#'); + } + } + + return Map{ + .tiles = tiles, + .width = width, + .height = height + }; +} + +fn parse_input(allocator: Allocator, lines: []const []const u8) !Input { + var parsed = Input.init(allocator); + errdefer parsed.deinit(); + + var first_map_line: usize = 0; + for (0.., lines) |i, line| { + if (line.len == 0) { + const map_lines = lines[first_map_line..i]; + try parsed.maps.append(try parse_map(allocator, map_lines)); + first_map_line = i+1; + } + } + + if (first_map_line != lines.len) { + const map_lines = lines[first_map_line..]; + try parsed.maps.append(try parse_map(allocator, map_lines)); + } + + return parsed; +} + +fn check_horizontal_reflection(map: Map, reflect_x: u32) bool { + assert(reflect_x < map.width-1); + const left_start = reflect_x; + const right_start = reflect_x + 1; + + const distance_to_edge = @min(map.width - right_start, left_start + 1); + for (0..map.height) |y| { + for (0..distance_to_edge) |offset| { + const left_cursor = left_start - @as(u32, @intCast(offset)); + const right_cursor = right_start + @as(u32, @intCast(offset)); + + const left_tile = map.get(left_cursor , @intCast(y)); + const right_tile = map.get(right_cursor, @intCast(y)); + if (left_tile != right_tile) { + return false; + } + } + } + + return true; +} + +fn find_horizontal_reflection(map: Map, skip_x: ?u32) ?u32 { + for (0..map.width-1) |x| { + const x_u32: u32 = @intCast(x); + if (x_u32 == skip_x) continue; + if (check_horizontal_reflection(map, x_u32)) { + return @intCast(x); + } + } + + return null; +} + +fn check_vertical_reflection(map: Map, reflect_y: u32) bool { + assert(reflect_y < map.height-1); + const top_start = reflect_y; + const bottom_start = reflect_y + 1; + + const distance_to_edge = @min(map.height - bottom_start, top_start + 1); + for (0..map.width) |x| { + for (0..distance_to_edge) |offset| { + const top_cursor = top_start - @as(u32, @intCast(offset)); + const bottom_cursor = bottom_start + @as(u32, @intCast(offset)); + + const top_tile = map.get(@intCast(x), top_cursor); + const bottom_tile = map.get(@intCast(x), bottom_cursor); + if (top_tile != bottom_tile) { + return false; + } + } + } + + return true; +} + +fn find_vertical_reflection(map: Map, skip_y: ?u32) ?u32 { + for (0..map.height-1) |y| { + const y_u32: u32 = @intCast(y); + if (y_u32 == skip_y) continue; + if (check_vertical_reflection(map, y_u32)) { + return @intCast(y); + } + } + + return null; +} + +pub fn part1(input: *aoc.Input) !aoc.Result { + var parsed = try parse_input(input.allocator, input.lines); + defer parsed.deinit(); + + var result: u64 = 0; + for (parsed.maps.items) |map| { + if (find_horizontal_reflection(map, null)) |x| { + result += (x+1); + } + if (find_vertical_reflection(map, null)) |y| { + result += 100 * (y+1); + } + } + + return .{ .uint = result }; +} + +pub fn part2(input: *aoc.Input) !aoc.Result { + var parsed = try parse_input(input.allocator, input.lines); + defer parsed.deinit(); + + var result: u64 = 0; + for (parsed.maps.items) |map| { + const original_reflect_x = find_horizontal_reflection(map, null); + const original_reflect_y = find_vertical_reflection(map, null); + + var reflect_x: ?u32 = null; + var reflect_y: ?u32 = null; + const tiles = map.tiles.items; + for (0..tiles.len) |i| { + tiles[i] = !tiles[i]; + reflect_x = find_horizontal_reflection(map, original_reflect_x); + reflect_y = find_vertical_reflection(map, original_reflect_y); + tiles[i] = !tiles[i]; + + if (reflect_x != null or reflect_y != null) break; + } + + assert(reflect_x != null or reflect_y != null); + if (reflect_x) |x| { + result += (x+1); + } + if (reflect_y) |y| { + result += 100 * (y+1); + } + } + + return .{ .uint = result }; +} + +const example_input = &.{ + "#.##..##.", + "..#.##.#.", + "##......#", + "##......#", + "..#.##.#.", + "..##..##.", + "#.#.##.#.", + "", + "#...##..#", + "#....#..#", + "..##..###", + "#####.##.", + "#####.##.", + "..##..###", + "#....#..#", +}; + +test "part 1 example" { + try aoc.expectAnswerUInt(part1, 405, &example_input); +} + +test "part 2 example" { + try aoc.expectAnswerUInt(part2, 400, &example_input); +} diff --git a/src/main.zig b/src/main.zig index 8884c14..0a262eb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -33,6 +33,7 @@ const Days = [_]aoc.Day{ create_day(@import("day10.zig")), create_day(@import("day11.zig")), create_day(@import("day12.zig")), + create_day(@import("day13.zig")), }; fn kilobytes(count: u32) u32 {