diff options
Diffstat (limited to 'src/common/aoc.zig')
| -rw-r--r-- | src/common/aoc.zig | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/common/aoc.zig b/src/common/aoc.zig new file mode 100644 index 0000000..cd35c43 --- /dev/null +++ b/src/common/aoc.zig @@ -0,0 +1,145 @@ +const std = @import("std"); + +pub const Error = error{InvalidInput}; + +pub var debug = false; +pub var debuglvl: u32 = 0; + +pub fn debugfmt(comptime fmt: []const u8, args: anytype) void { + if (debug) + std.debug.print(fmt, args); +} + +const part_type = fn (alloc: std.mem.Allocator, input: []u8, args: [][]u8) anyerror!?[]u8; +pub fn main(comptime part1: part_type, comptime part2: part_type, comptime sols: [2]?[]const u8) fn () anyerror!void { + const impl = struct { + fn main() !void { + const envvar = std.os.getenv("AOC_DEBUG"); + if (envvar != null) { + debuglvl = try std.fmt.parseInt(u32, envvar.?, 10); + debug = debuglvl != 0; + } + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + var heapalloc = gpa.allocator(); + + const args = try std.process.argsAlloc(heapalloc); + defer heapalloc.free(args); + if (args.len < 2) return; + + var filename: []const u8 = std.mem.span("input"); + for (std.os.environ) |v| { + const kv = std.mem.span(v); + if (std.mem.indexOfScalar(u8, kv, '=')) |sep| { + if (sep == kv.len - 1) continue; + if (std.mem.eql(u8, kv[0..sep], "AOC_INPUT")) { + filename = kv[sep + 1 ..]; + std.debug.print("Using input file: {s}\n", .{filename}); + break; + } else if (std.mem.eql(u8, kv[0..sep], "AOCDEBUG")) { + debug = true; + debuglvl = try std.fmt.parseInt(u32, kv[sep + 1 ..], 10); + } + } + } + + const file = try std.fs.cwd().openFile(filename, .{}); + const text = try file.reader().readAllAlloc(heapalloc, std.math.maxInt(u32)); + defer heapalloc.free(text); + + var part = try std.fmt.parseInt(u8, args[1], 10); + var answer: ?[]u8 = null; + switch (part) { + 1 => answer = try part1(heapalloc, text, args[2..]), + 2 => answer = try part2(heapalloc, text, args[2..]), + else => { + std.debug.print("Invalid part number!\n", .{}); + std.os.exit(1); + }, + } + part = part - 1; + + if (answer != null) { + const stdout = std.io.getStdOut().writer(); + try std.fmt.format(stdout, "{s}\n", .{answer.?}); + if (sols[part] != null and !std.mem.eql(u8, answer.?, sols[part].?)) { + std.debug.print("Invalid answer\n", .{}); + std.os.exit(1); + } + heapalloc.free(answer.?); + } + + if (sols[part] == null) { + std.debug.print("Missing solution\n", .{}); + std.os.exit(1); + } + } + }; + return impl.main; +} + +pub const Pos = struct { + x: i64, + y: i64, + const Self = @This(); + + pub fn add(self: Self, other: Self) Self { + return Self{ .x = self.x + other.x, .y = self.y + other.y }; + } + + pub fn mult(self: Self, val: i64) Self { + return Self{ .x = self.x * val, .y = self.y * val }; + } +}; + +pub const Dir = struct { + pub const East = Pos{ .x = 1, .y = 0 }; + pub const West = Pos{ .x = -1, .y = 0 }; + pub const South = Pos{ .x = 0, .y = -1 }; + pub const North = Pos{ .x = 0, .y = 1 }; + + pub const Name = enum(u8) { NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3 }; + pub const dirs = [_]Pos{ North, East, South, West }; + + pub fn get(name: Name) Pos { + return dirs[@enumToInt(name)]; + } + + pub fn nextCW(dir: usize, offset: usize) usize { + return (dir + @intCast(u32, offset)) % @intCast(u32, dirs.len); + } + + pub fn nextCCW(dir: usize, offset: usize) usize { + const constrained = offset % dirs.len; + if (dir >= constrained) { + return dir - constrained; + } else { + return dirs.len - (constrained - dir); + } + } + + const cos90vs = [_]i32{ 1, 0, -1, 0 }; + const sin90vs = [_]i32{ 0, 1, 0, -1 }; + + pub fn rotCW(pos: Pos, offset: usize) Pos { + const constrained = (4 - offset % 4) % 4; + return Pos{ + .x = cos90vs[constrained] * pos.x - sin90vs[constrained] * pos.y, + .y = sin90vs[constrained] * pos.x + cos90vs[constrained] * pos.y, + }; + } + + pub fn rotCCW(pos: Pos, offset: usize) Pos { + const constrained = offset % 4; + return Pos{ + .x = cos90vs[constrained] * pos.x - sin90vs[constrained] * pos.y, + .y = sin90vs[constrained] * pos.x + cos90vs[constrained] * pos.y, + }; + } +}; + +pub fn unwrap(v: anytype) !@TypeOf(v.?) { + if (v == null) return Error.InvalidInput; + return v.?; +} |
