Compare commits
2 Commits
413e13b601
...
14c4b266c1
Author | SHA1 | Date | |
---|---|---|---|
14c4b266c1 | |||
692b178154 |
216
src/day18.zig
Normal file
216
src/day18.zig
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const aoc = @import("./aoc.zig");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const PointLib = @import("./point.zig");
|
||||||
|
const PointI32 = PointLib.PointI32;
|
||||||
|
const PointU32 = PointLib.PointU32;
|
||||||
|
|
||||||
|
const Segment = struct {
|
||||||
|
start: PointI32,
|
||||||
|
stop: PointI32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Direction = enum {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
|
||||||
|
fn from_str(str: []const u8) ?Direction {
|
||||||
|
if (std.mem.eql(u8, str, "U")) {
|
||||||
|
return .Up;
|
||||||
|
} else if (std.mem.eql(u8, str, "D")) {
|
||||||
|
return .Down;
|
||||||
|
} else if (std.mem.eql(u8, str, "L")) {
|
||||||
|
return .Left;
|
||||||
|
} else if (std.mem.eql(u8, str, "R")) {
|
||||||
|
return .Right;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_offset(self: Direction) PointI32 {
|
||||||
|
return switch (self) {
|
||||||
|
.Up => PointI32{ .x = 0, .y = -1 },
|
||||||
|
.Down => PointI32{ .x = 0, .y = 1 },
|
||||||
|
.Left => PointI32{ .x = -1, .y = 0 },
|
||||||
|
.Right => PointI32{ .x = 1, .y = 0 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const DigInstruction = struct {
|
||||||
|
dir: Direction,
|
||||||
|
steps: u32
|
||||||
|
};
|
||||||
|
|
||||||
|
const Instructions = std.ArrayList(DigInstruction);
|
||||||
|
|
||||||
|
fn parse_dig_instruction1(line: []const u8) !DigInstruction {
|
||||||
|
var iter = std.mem.splitScalar(u8, line, ' ');
|
||||||
|
|
||||||
|
const dir_str = iter.next() orelse return error.MissingDirection;
|
||||||
|
const steps_str = iter.next() orelse return error.MissingSteps;
|
||||||
|
|
||||||
|
return DigInstruction{
|
||||||
|
.dir = Direction.from_str(dir_str) orelse return error.InvalidDirection,
|
||||||
|
.steps = try std.fmt.parseUnsigned(u32, steps_str, 10)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input1(allocator: Allocator, lines: []const []const u8) !Instructions {
|
||||||
|
var result = Instructions.init(allocator);
|
||||||
|
errdefer result.deinit();
|
||||||
|
|
||||||
|
for (lines) |line| {
|
||||||
|
try result.append(try parse_dig_instruction1(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bounds(segments: []const Segment) std.meta.Tuple(&.{ PointI32, PointI32 }) {
|
||||||
|
var upper_left = PointI32.zero();
|
||||||
|
var lower_right = PointI32.zero();
|
||||||
|
|
||||||
|
for (segments) |segment| {
|
||||||
|
inline for (&.{ segment.start, segment.stop }) |p| {
|
||||||
|
upper_left.x = @min(upper_left.x, p.x);
|
||||||
|
upper_left.y = @min(upper_left.y, p.y);
|
||||||
|
lower_right.x = @max(lower_right.x, p.x);
|
||||||
|
lower_right.y = @max(lower_right.y, p.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ upper_left, lower_right };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_segments(allocator: Allocator, insts: Instructions) !std.ArrayList(Segment) {
|
||||||
|
var segments = std.ArrayList(Segment).init(allocator);
|
||||||
|
errdefer segments.deinit();
|
||||||
|
|
||||||
|
var current = PointI32.zero();
|
||||||
|
for (insts.items) |inst| {
|
||||||
|
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
||||||
|
const next = current.add(step);
|
||||||
|
|
||||||
|
try segments.append(Segment{ .start = current, .stop = next });
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GOD DAMN IT, AGAIN WITH THIS THEOROM! I THOUGH IT WAS SCANLINES!
|
||||||
|
// Shoelace theorum + Pick's theorum
|
||||||
|
// Day 10 all over again :/
|
||||||
|
fn get_lagoon_size(allocator: Allocator, instructions: Instructions) !usize {
|
||||||
|
var boundry_points: u32 = 0;
|
||||||
|
|
||||||
|
var loop_path = std.ArrayList(PointI32).init(allocator);
|
||||||
|
defer loop_path.deinit();
|
||||||
|
|
||||||
|
var current = PointI32.zero();
|
||||||
|
try loop_path.append(current);
|
||||||
|
for (instructions.items) |inst| {
|
||||||
|
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
||||||
|
current = current.add(step);
|
||||||
|
boundry_points += inst.steps;
|
||||||
|
|
||||||
|
try loop_path.append(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
var twice_area: i64 = 0;
|
||||||
|
for (0..(loop_path.items.len-1)) |i| {
|
||||||
|
const cur = loop_path.items[i];
|
||||||
|
const next = loop_path.items[i+1];
|
||||||
|
|
||||||
|
const y_0: i64 = @intCast(cur.y);
|
||||||
|
const x_0: i64 = @intCast(cur.x);
|
||||||
|
const y_1: i64 = @intCast(next.y);
|
||||||
|
const x_1: i64 = @intCast(next.x);
|
||||||
|
|
||||||
|
twice_area += (x_0 * y_1) - (y_0 * x_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterior_points = @abs(twice_area) / 2 - boundry_points / 2 + 1;
|
||||||
|
const result = iterior_points + boundry_points;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||||
|
const allocator = input.allocator;
|
||||||
|
|
||||||
|
var instructions = Instructions.init(allocator);
|
||||||
|
defer instructions.deinit();
|
||||||
|
for (input.lines) |line| {
|
||||||
|
try instructions.append(try parse_dig_instruction1(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .uint = try get_lagoon_size(allocator, instructions) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_dig_instruction2(line: []const u8) !DigInstruction {
|
||||||
|
var iter = std.mem.splitScalar(u8, line, ' ');
|
||||||
|
|
||||||
|
_ = iter.next();
|
||||||
|
_ = iter.next();
|
||||||
|
|
||||||
|
const color_str = iter.next() orelse return error.MissingColor;
|
||||||
|
const color_trimmed = std.mem.trim(u8, color_str, "()#");
|
||||||
|
if (color_trimmed.len != 6) return error.ColorTooShort;
|
||||||
|
|
||||||
|
const dir: Direction = switch (color_trimmed[5]) {
|
||||||
|
'0' => .Right,
|
||||||
|
'1' => .Down,
|
||||||
|
'2' => .Left,
|
||||||
|
'3' => .Up,
|
||||||
|
else => return error.InvalidDirection
|
||||||
|
};
|
||||||
|
|
||||||
|
return DigInstruction{
|
||||||
|
.dir = dir,
|
||||||
|
.steps = try std.fmt.parseUnsigned(u32, color_trimmed[0..5], 16)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||||
|
const allocator = input.allocator;
|
||||||
|
|
||||||
|
var instructions = Instructions.init(allocator);
|
||||||
|
defer instructions.deinit();
|
||||||
|
for (input.lines) |line| {
|
||||||
|
try instructions.append(try parse_dig_instruction2(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .uint = try get_lagoon_size(allocator, instructions) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const example_input = [_][]const u8{
|
||||||
|
"R 6 (#70c710)",
|
||||||
|
"D 5 (#0dc571)",
|
||||||
|
"L 2 (#5713f0)",
|
||||||
|
"D 2 (#d2c081)",
|
||||||
|
"R 2 (#59c680)",
|
||||||
|
"D 2 (#411b91)",
|
||||||
|
"L 5 (#8ceee2)",
|
||||||
|
"U 2 (#caa173)",
|
||||||
|
"L 1 (#1b58a2)",
|
||||||
|
"U 2 (#caa171)",
|
||||||
|
"R 2 (#7807d2)",
|
||||||
|
"U 3 (#a77fa3)",
|
||||||
|
"L 2 (#015232)",
|
||||||
|
"U 2 (#7a21e3)",
|
||||||
|
};
|
||||||
|
|
||||||
|
test "part 1 example" {
|
||||||
|
try aoc.expectAnswerUInt(part1, 62, &example_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "part 2 example" {
|
||||||
|
try aoc.expectAnswerUInt(part2, 952408144115, &example_input);
|
||||||
|
}
|
@ -38,6 +38,7 @@ const Days = [_]aoc.Day{
|
|||||||
create_day(@import("./day15.zig")),
|
create_day(@import("./day15.zig")),
|
||||||
create_day(@import("./day16.zig")),
|
create_day(@import("./day16.zig")),
|
||||||
create_day(@import("./day17.zig")),
|
create_day(@import("./day17.zig")),
|
||||||
|
create_day(@import("./day18.zig")),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn kilobytes(count: u32) u32 {
|
fn kilobytes(count: u32) u32 {
|
||||||
@ -198,4 +199,5 @@ test {
|
|||||||
_ = @import("./day15.zig");
|
_ = @import("./day15.zig");
|
||||||
_ = @import("./day16.zig");
|
_ = @import("./day16.zig");
|
||||||
_ = @import("./day17.zig");
|
_ = @import("./day17.zig");
|
||||||
|
_ = @import("./day18.zig");
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,13 @@ pub fn Point(comptime T: type) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mul(self: Self, scale: T) Self {
|
||||||
|
return Self{
|
||||||
|
.x = self.x * scale,
|
||||||
|
.y = self.y * scale
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_i32(self: Self) Point(i32) {
|
pub fn to_i32(self: Self) Point(i32) {
|
||||||
return Point(i32){
|
return Point(i32){
|
||||||
.x = @intCast(self.x),
|
.x = @intCast(self.x),
|
||||||
|
Loading…
Reference in New Issue
Block a user