const std = @import("std");
const builtin = @import("builtin");
fn readInputFile(allocator: std.mem.Allocator, filename: []const u8) ![]u32 {
var result = std.ArrayList(u32).init(allocator);
const file = try std.fs.cwd().openFile(filename, .{ .read = true });
defer file.close();
const reader = file.reader();
while (true) {
var line: []u8 = undefined;
if (builtin.os.tag == .windows) {
// NOTE: Read another byte on windows due to two-byte eol.
line = reader.readUntilDelimiterAlloc(allocator, '\r', 512) catch break;
_ = try reader.readByte();
} else {
line = reader.readUntilDelimiterAlloc(allocator, '\n', 512) catch break;
}
defer allocator.free(line);
for (line) |char| {
try result.append(@as(u32, char - 48));
}
}
return result.items;
}
pub fn drawGrid(width: u32, height: u32, grid: []u32) void {
var y: u32 = 0;
while (y < height) : (y += 1) {
std.log.debug("{any}", .{grid[(y * width)..((y + 1) * width)]});
}
}
fn flash(x: u32, y: u32, width: u32, height: u32, squid: []u32) void {
var yy: i32 = -1;
while (yy < 2) : (yy += 1) {
if (yy + @intCast(i32, y) < 0 or yy + @intCast(i32, y) >= @intCast(i32, height)) {
continue;
}
var i = @intCast(u32, yy + @intCast(i32, y)) * width;
var xx: i32 = -1;
while (xx < 2) : (xx += 1) {
if (xx + @intCast(i32, x) < 0 or xx + @intCast(i32, x) >= @intCast(i32, width)) {
continue;
}
if (!(xx == 0 and yy == 0)) {
squid[i + @intCast(u32, xx + @intCast(i32, x))] += 1;
}
}
}
}
pub fn iterateEnergy(width: u32, height: u32, squid: []u32) u32 {
var result: u32 = 0;
var y: u32 = 0;
while (y < height) : (y += 1) {
var i = y * width;
var x: u32 = 0;
while (x < width) : (x += 1) {
squid[i + x] += 1;
}
}
while (true) {
var did_flash: bool = false;
y = 0;
while (y < height) : (y += 1) {
var i = y * width;
var x: u32 = 0;
while (x < width) : (x += 1) {
if (squid[i + x] > 9 and squid[i + x] < 99) {
squid[i + x] = 99;
flash(x, y, width, height, squid);
did_flash = true;
}
}
}
if (!did_flash) {
break;
}
}
y = 0;
while (y < height) : (y += 1) {
var i = y * width;
var x: u32 = 0;
while (x < width) : (x += 1) {
if (squid[i + x] > 9) {
squid[i + x] = 0;
result += 1;
}
}
}
return result;
}
pub fn task1(width: u32, height: u32, input: []u32) u32 {
var result: u32 = 0;
//std.log.debug("\ninitial", .{});
//drawGrid(width, height, input);
var i: u32 = 0;
while (i < 100) : (i += 1) {
result += iterateEnergy(width, height, input);
//std.log.debug("\nafter {} step", .{i + 1});
//drawGrid(width, height, input);
}
return result;
}
pub fn task2(width: u32, height: u32, input: []u32) u32 {
var result: u32 = 1;
while (true) : (result += 1) {
if (iterateEnergy(width, height, input) == width * height) {
//std.log.debug("\nafter {} steps", .{result});
//drawGrid(width, height, input);
break;
}
}
return result;
}
pub fn main() !void {
var buffer: [2000000]u8 = undefined;
var fixed_buffer = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fixed_buffer.allocator();
const input = try readInputFile(allocator, "input.txt");
var input_copy = std.ArrayList(u32).init(allocator);
try input_copy.appendSlice(input);
const task_1_result = task1(10, 10, input_copy.items);
std.log.info("Task 1 result: {}", .{task_1_result});
input_copy.clearAndFree();
try input_copy.appendSlice(input);
const task_2_result = task2(10, 10, input_copy.items);
std.log.info("Task 2 result: {}", .{task_2_result});
input_copy.clearAndFree();
}