const std = @import("std"); const PATH = "input/day11.txt"; const Str = []const u8; const Seat = enum { floor, empty, occupied, }; const GRID_ROWS = 93; const GRID_COLS = 97; const Grid = struct { grd: [GRID_ROWS][GRID_COLS]Seat, const directions = [_][2]i2{ .{ -1, -1 }, .{ -1, 0 }, .{ -1, 1 }, .{ 1, -1 }, .{ 1, 0 }, .{ 1, 1 }, .{ 0, -1 }, .{ 0, 1 }, }; fn countOccupied(self: *const @This()) usize { var sum: usize = 0; for (self.grd) |gr| { for (gr) |item| { if (item == .occupied) sum += 1; } } return sum; } fn adjacentOccupied(self: *const @This(), row: usize, col: usize) u4 { var ret: u4 = 0; for (directions) |d| { const diffrow = @intCast(isize, row) + d[0]; if (diffrow < 0 or diffrow >= GRID_ROWS) continue; const diffcol = @intCast(isize, col) + d[1]; if (diffcol < 0 or diffcol >= GRID_COLS) continue; if (self.grd[@intCast(usize, diffrow)][@intCast(usize, diffcol)] == .occupied) ret += 1; } return ret; } fn seenOccupied(self: *const @This(), row: usize, col: usize) u4 { var ret: u4 = 0; for (directions) |d| { var diffrow = @intCast(isize, row); var diffcol = @intCast(isize, col); while (true) { diffrow += d[0]; if (diffrow < 0 or diffrow >= GRID_ROWS) break; diffcol += d[1]; if (diffcol < 0 or diffcol >= GRID_COLS) break; switch (self.grd[@intCast(usize, diffrow)][@intCast(usize, diffcol)]) { .occupied => { ret += 1; break; }, .empty => break, .floor => continue, } } } return ret; } }; pub fn first(allocator: ?std.mem.Allocator) anyerror!usize { _ = allocator; var grid = parseInput(@embedFile(PATH)); while (true) { var next_grid = grid.grd; var changed = false; for (grid.grd) |grid_row, row| { for (grid_row) |item, col| { switch (item) { .empty => { if (grid.adjacentOccupied(row, col) == 0) { next_grid[row][col] = .occupied; changed = true; } }, .occupied => { if (grid.adjacentOccupied(row, col) >= 4) { next_grid[row][col] = .empty; changed = true; } }, .floor => {}, } } } grid.grd = next_grid; if (!changed) break; } return grid.countOccupied(); } pub fn second(allocator: ?std.mem.Allocator) anyerror!usize { _ = allocator; var grid = parseInput(@embedFile(PATH)); while (true) { var next_grid = grid.grd; var changed = false; for (grid.grd) |grid_row, row| { for (grid_row) |item, col| { switch (item) { .empty => { if (grid.seenOccupied(row, col) == 0) { next_grid[row][col] = .occupied; changed = true; } }, .occupied => { if (grid.seenOccupied(row, col) >= 5) { next_grid[row][col] = .empty; changed = true; } }, .floor => {}, } } } grid.grd = next_grid; if (!changed) break; } return grid.countOccupied(); } fn parseInput(input: Str) Grid { var lines = std.mem.tokenize(u8, input, "\n"); var grid: Grid = undefined; var row: usize = 0; while (lines.next()) |line| : (row += 1) { for (line) |ch, col| { grid.grd[row][col] = switch (ch) { '.' => .floor, 'L' => .empty, '#' => .occupied, else => unreachable, }; } } return grid; } test "day11a" { try std.testing.expectEqual(@as(usize, 2316), try first(std.testing.allocator)); } test "day11b" { try std.testing.expectEqual(@as(usize, 2128), try second(std.testing.allocator)); }