const std = @import("std");
const path = "../data/day05/input.txt";
const RetType = u16;
const grid_size = 1000;
const max_grid_value = u2;
const Vents = [grid_size][grid_size]max_grid_value;
const CoordType = i20;
const Coord = struct { x: CoordType, y: CoordType };
fn countVents(directions: []const Coord, nodiag: bool) anyerror!RetType {
const input = @embedFile(path);
var lines = std.mem.split(u8, input, "\n");
var vts: Vents = [_][grid_size]max_grid_value{[_]max_grid_value{0} ** grid_size} ** grid_size;
var counter: RetType = 0;
while (lines.next()) |line| {
if (line.len == 0) continue;
var crop_line = std.mem.tokenize(u8, line, " -> ");
// parse coordinates
var l: [2]Coord = undefined;
var idx: usize = 0;
while (crop_line.next()) |cl| : (idx += 1) {
var coords = std.mem.tokenize(u8, cl, ",");
l[idx].x = try std.fmt.parseUnsigned(CoordType, coords.next().?, 10);
l[idx].y = try std.fmt.parseUnsigned(CoordType, coords.next().?, 10);
}
// check if diagonal lines count or not
if (nodiag and !((l[0].x == l[1].x) or (l[0].y == l[1].y))) continue;
// setup lines
const dir = try getDirection(l, directions);
var v = vts[@intCast(usize, l[1].x)][@intCast(usize, l[1].y)];
if (v == 1) {
counter += 1;
}
v +|= 1;
vts[@intCast(usize, l[1].x)][@intCast(usize, l[1].y)] = v;
while ((l[0].x != l[1].x) or (l[0].y != l[1].y)) {
v = vts[@intCast(usize, l[0].x)][@intCast(usize, l[0].y)];
if (v == 1) {
counter += 1;
}
v +|= 1;
vts[@intCast(usize, l[0].x)][@intCast(usize, l[0].y)] = v;
l[0].x += dir.x;
l[0].y += dir.y;
}
}
return counter;
}
fn getDirection(c: [2]Coord, directions: []const Coord) !Coord {
var min = try manhattan(c[0], c[1]);
var ret: Coord = undefined;
for (directions) |d| {
if ((try manhattan(Coord{ .x = c[0].x + d.x, .y = c[0].y + d.y }, c[1])) < min) {
ret = d;
}
}
return ret;
}
fn manhattan(f: Coord, s: Coord) !CoordType {
const xdiff = try std.math.absInt(f.x - s.x);
const ydiff = try std.math.absInt(f.y - s.y);
return xdiff + ydiff;
}
fn first() anyerror!RetType {
const directions = [_]Coord{
.{ .x = -1, .y = 0 },
.{ .x = 1, .y = 0 },
.{ .x = 0, .y = -1 },
.{ .x = 0, .y = 1 },
};
return try countVents(directions[0..], true);
}
fn second() anyerror!RetType {
const directions = [_]Coord{
.{ .x = -1, .y = 0 },
.{ .x = 1, .y = 0 },
.{ .x = 0, .y = -1 },
.{ .x = 0, .y = 1 },
.{ .x = -1, .y = -1 },
.{ .x = -1, .y = 1 },
.{ .x = 1, .y = -1 },
.{ .x = 1, .y = 1 },
};
return try countVents(directions[0..], false);
}
pub fn main() anyerror!void {
var timer = try std.time.Timer.start();
_ = try first();
const f = timer.lap() / 1000;
_ = try second();
const s = timer.lap() / 1000;
std.debug.print("Day 5 \t\tfirst: {d}µs \t\tsecond: {d}µs\n", .{ f, s });
}
test "first" {
try std.testing.expectEqual(@as(RetType, 8060), try first());
}
test "second" {
try std.testing.expectEqual(@as(RetType, 21577), try second());
}