const std = @import("std");
const path = "../data/day22/input.txt";
pub fn main() !void {
var timer = try std.time.Timer.start();
const ret = try first();
const t = timer.lap() / 1000;
try std.testing.expectEqual(@as(usize, 1267133912086024), ret);
std.debug.print("Day 22b result: {d} \t\ttime: {d}µs\n", .{ ret, t });
}
const CoordList = std.ArrayList(isize);
pub fn first() !usize {
const allocator = std.testing.allocator;
var X = CoordList.init(allocator);
defer X.deinit();
var Y = CoordList.init(allocator);
defer Y.deinit();
var Z = CoordList.init(allocator);
defer Z.deinit();
const input = try parseInput(allocator, &X, &Y, &Z);
defer allocator.free(input);
std.sort.sort(isize, X.items, {}, comptime std.sort.asc(isize));
std.sort.sort(isize, Y.items, {}, comptime std.sort.asc(isize));
std.sort.sort(isize, Z.items, {}, comptime std.sort.asc(isize));
var N: usize = X.items.len;
// XXX: this one is _really_ sloooooow..., why?
// const grid_size = 840;
// var grid = [_][grid_size][grid_size]bool{[_][grid_size]bool{[_]bool{false} ** grid_size} ** grid_size} ** grid_size;
var grid = try std.DynamicBitSet.initEmpty(allocator, N * N * N);
defer grid.deinit();
for (input) |cube| {
const x0 = getIndex(&X, cube.xmin);
const x1 = getIndex(&X, cube.xmax);
const y0 = getIndex(&Y, cube.ymin);
const y1 = getIndex(&Y, cube.ymax);
const z0 = getIndex(&Z, cube.zmin);
const z1 = getIndex(&Z, cube.zmax);
var x = x0;
while (x < x1) : (x += 1) {
var y = y0;
while (y < y1) : (y += 1) {
var z = z0;
while (z < z1) : (z += 1) {
grid.setValue(x * N * N + y * N + z, cube.state);
}
}
}
}
var sum: isize = 0;
var x: usize = 0;
while (x < N - 1) : (x += 1) {
var y: usize = 0;
while (y < N - 1) : (y += 1) {
var z: usize = 0;
while (z < N - 1) : (z += 1) {
if (grid.isSet(x * N * N + y * N + z)) {
sum += (X.items[x + 1] - X.items[x]) *
(Y.items[y + 1] - Y.items[y]) *
(Z.items[z + 1] - Z.items[z]);
}
}
}
}
return @intCast(usize, sum);
}
fn getIndex(list: *CoordList, value: isize) usize {
for (list.items) |val, idx| {
if (val == value) {
return idx;
}
}
unreachable;
}
const Cuboid = struct {
state: bool,
xmin: isize,
xmax: isize,
ymin: isize,
ymax: isize,
zmin: isize,
zmax: isize,
};
const Cubes = []Cuboid;
fn parseInput(a: std.mem.Allocator, X: *CoordList, Y: *CoordList, Z: *CoordList) !Cubes {
const input = @embedFile(path);
var lines = std.mem.split(u8, input, "\n");
var ret = std.ArrayList(Cuboid).init(a);
while (lines.next()) |line| {
if (line.len == 0) break;
var cube: Cuboid = undefined;
var st_coord = std.mem.tokenize(u8, line, " ");
// set cuboid state
if (std.mem.eql(u8, st_coord.next().?, "on")) cube.state = true else cube.state = false;
var axes = std.mem.tokenize(u8, st_coord.next().?, ",");
var cntr: u2 = 0;
while (axes.next()) |ax| : (cntr += 1) {
const axis = ax[2..]; // strip x=, y=, z=
std.debug.assert(cntr < 3);
var min_max = std.mem.tokenize(u8, axis, "..");
// coordinates
if (cntr == 0) {
cube.xmin = try std.fmt.parseInt(isize, min_max.next().?, 10);
cube.xmax = try std.fmt.parseInt(isize, min_max.next().?, 10);
cube.xmax += 1;
try X.append(cube.xmin);
try X.append(cube.xmax);
}
if (cntr == 1) {
cube.ymin = try std.fmt.parseInt(isize, min_max.next().?, 10);
cube.ymax = try std.fmt.parseInt(isize, min_max.next().?, 10);
cube.ymax += 1;
try Y.append(cube.ymin);
try Y.append(cube.ymax);
}
if (cntr == 2) {
cube.zmin = try std.fmt.parseInt(isize, min_max.next().?, 10);
cube.zmax = try std.fmt.parseInt(isize, min_max.next().?, 10);
cube.zmax += 1;
try Z.append(cube.zmin);
try Z.append(cube.zmax);
}
}
try ret.append(cube);
}
return ret.toOwnedSlice();
}
test "day22b" {
try std.testing.expectEqual(@as(usize, 1267133912086024), try first());
}