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 =
\\.#.#.#
\\...##.
\\#....#
\\..#...
\\#.#..#
\\####..
;