const std = @import("std"); const Str = []const u8; const PATH = "input/day18.txt"; const ROWS = 100; const COLS = 100; const ROUND = 100; pub fn first(allocator: std.mem.Allocator) !usize { _ = allocator; var gif = GIF.init(@embedFile(PATH)); var next_grid: [ROWS][COLS]State = undefined; var round: usize = 0; while (round < ROUND) : (round += 1) { for (gif.grid) |line, row| { for (line) |light, col| { const nbrs = gif.countNeighbor(row, col); if (light == .on) { next_grid[row][col] = if (nbrs == 2 or nbrs == 3) .on else .off; } else { next_grid[row][col] = if (nbrs == 3) .on else .off; } } } gif.grid = next_grid; } var count: usize = 0; for (gif.grid) |line| { for (line) |ch| { if (ch == .on) count += 1; } } return count; } pub fn second(allocator: std.mem.Allocator) !usize { _ = allocator; var gif = GIF.init(@embedFile(PATH)); gif.alwaysOn(); var next_grid: [ROWS][COLS]State = undefined; var round: usize = 0; while (round < ROUND) : (round += 1) { for (gif.grid) |line, row| { for (line) |light, col| { const nbrs = gif.countNeighbor(row, col); if (light == .on) { next_grid[row][col] = if (nbrs == 2 or nbrs == 3) .on else .off; } else { next_grid[row][col] = if (nbrs == 3) .on else .off; } } } gif.grid = next_grid; gif.alwaysOn(); } var count: usize = 0; for (gif.grid) |line| { for (line) |ch| { if (ch == .on) count += 1; } } return count; } test "day18a" { try std.testing.expectEqual(@as(usize, 1061), try first(std.testing.allocator)); } test "day18b" { try std.testing.expectEqual(@as(usize, 1006), try second(std.testing.allocator)); } const State = enum { on, off, }; const GIF = struct { grid: [ROWS][COLS]State, const neighbors = [8][2]i2{ .{ -1, 0 }, .{ 1, 0 }, .{ 0, -1 }, .{ 0, 1 }, .{ -1, -1 }, .{ -1, 1 }, .{ 1, -1 }, .{ 1, 1 }, }; fn init(in: Str) @This() { return @This(){ .grid = parseInput(in), }; } fn parseInput(in: Str) [ROWS][COLS]State { var grid: [ROWS][COLS]State = undefined; var lines = std.mem.tokenize(u8, in, "\n"); var row: usize = 0; while (lines.next()) |line| : (row += 1) { for (line) |ch, col| { grid[row][col] = switch (ch) { '.' => .off, '#' => .on, else => unreachable, }; } } return grid; } fn countNeighbor(self: @This(), row: usize, col: usize) u4 { var ret: u4 = 0; for (neighbors) |n| { const dr = @intCast(isize, row) + n[0]; if (dr < 0 or dr >= ROWS) continue; const dc = @intCast(isize, col) + n[1]; if (dc < 0 or dc >= COLS) continue; if (self.grid[@intCast(usize, dr)][@intCast(usize, dc)] == .on) ret += 1; } return ret; } fn alwaysOn(self: *@This()) void { self.grid[0][0] = .on; self.grid[0][COLS - 1] = .on; self.grid[ROWS - 1][0] = .on; self.grid[ROWS - 1][COLS - 1] = .on; } }; const test_input = \\.#.#.# \\...##. \\#....# \\..#... \\#.#..# \\####.. ;