const std = @import("std");
const path = "../data/day11/input.txt";
const RetType = u9;
const grid_row = 10;
const grid_col = 10;
const GridType = u4;
const Grid = [grid_row][grid_col]GridType;
const Seen = [grid_row][grid_col]bool;
const directions = [8][2]i2{
.{ -1, 0 },
.{ 1, 0 },
.{ 0, -1 },
.{ 0, 1 },
.{ -1, -1 },
.{ 1, 1 },
.{ 1, -1 },
.{ -1, 1 },
};
fn parseInput() anyerror!Grid {
const input = @embedFile(path);
var lines = std.mem.tokenize(u8, input, "\n");
var g: Grid = undefined;
var row: usize = 0;
while (lines.next()) |line| : (row += 1) {
for (line) |_, col| {
g[row][col] = try std.fmt.parseUnsigned(GridType, line[col .. col + 1], 10);
}
}
return g;
}
pub fn second() anyerror!RetType {
var grid = try parseInput();
var step: RetType = 0;
while (true) : (step += 1) {
// increase each octupus energy by 1
for (grid) |line, row| {
for (line) |_, col| {
grid[row][col] +|= 1;
}
}
var seen = [_][grid_col]bool{[_]bool{false} ** grid_col} ** grid_row;
// flash every octupus > 9
for (grid) |line, row| {
for (line) |energy, col| {
if (energy > 9) {
_ = flash(&seen, &grid, row, col);
}
}
}
// reset flashed
for (grid) |line, row| {
for (line) |energy, col| {
if (energy > 9) {
grid[row][col] = 0;
}
}
}
if (fullFlash(&grid)) {
break;
}
}
return step + 1;
}
fn fullFlash(grid: *Grid) bool {
for (grid) |line| {
for (line) |energy| {
if (energy != 0) {
return false;
}
}
}
return true;
}
fn flash(seen: *Seen, grid: *Grid, row: usize, col: usize) RetType {
var ret: RetType = 0;
if ((seen[row][col]) or (grid[row][col] <= 9)) {
return ret;
}
seen[row][col] = true;
ret += 1;
for (directions) |dir| {
const diffrow = @intCast(i8, row) + dir[0];
if ((diffrow < 0) or (diffrow >= grid_row)) continue;
const diffcol = @intCast(i8, col) + dir[1];
if ((diffcol < 0) or (diffcol >= grid_col)) continue;
grid[@intCast(usize, diffrow)][@intCast(usize, diffcol)] +|= 1;
ret += flash(seen, grid, @intCast(usize, diffrow), @intCast(usize, diffcol));
}
return ret;
}
pub fn main() anyerror!void {
var timer = try std.time.Timer.start();
const ret = try second();
const t = timer.lap() / 1000;
try std.testing.expectEqual(@as(RetType, 273), ret);
std.debug.print("Day 11b result: {d} \t\ttime: {d}µs\n", .{ ret, t });
}
test "day11a" {
try std.testing.expectEqual(@as(RetType, 273), try second());
}