solve day 13

This commit is contained in:
Rokas Puzonas 2024-04-14 19:48:24 +03:00
parent 71d4c1bf17
commit c36f8c6805
2 changed files with 236 additions and 0 deletions

235
src/day13.zig Normal file
View File

@ -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);
}

View File

@ -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 {