aoc.zig (4898B)
1const std = @import("std"); 2 3pub const Error = error{InvalidInput}; 4 5pub var debug = false; 6pub var debuglvl: u32 = 0; 7 8pub fn debugfmt(comptime fmt: []const u8, args: anytype) void { 9 if (debug) 10 std.debug.print(fmt, args); 11} 12 13const part_type = fn (alloc: std.mem.Allocator, input: []u8, args: [][]u8) anyerror!?[]u8; 14pub fn main(comptime part1: part_type, comptime part2: part_type, comptime sols: [2]?[]const u8) fn () anyerror!void { 15 const impl = struct { 16 fn main() !void { 17 const envvar = std.os.getenv("AOC_DEBUG"); 18 if (envvar != null) { 19 debuglvl = try std.fmt.parseInt(u32, envvar.?, 10); 20 debug = debuglvl != 0; 21 } 22 23 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 24 defer _ = gpa.deinit(); 25 var heapalloc = gpa.allocator(); 26 27 const args = try std.process.argsAlloc(heapalloc); 28 defer heapalloc.free(args); 29 if (args.len < 2) return; 30 31 var filename: []const u8 = std.mem.span("input"); 32 for (std.os.environ) |v| { 33 const kv = std.mem.span(v); 34 if (std.mem.indexOfScalar(u8, kv, '=')) |sep| { 35 if (sep == kv.len - 1) continue; 36 if (std.mem.eql(u8, kv[0..sep], "AOC_INPUT")) { 37 filename = kv[sep + 1 ..]; 38 std.debug.print("Using input file: {s}\n", .{filename}); 39 break; 40 } else if (std.mem.eql(u8, kv[0..sep], "AOCDEBUG")) { 41 debug = true; 42 debuglvl = try std.fmt.parseInt(u32, kv[sep + 1 ..], 10); 43 } 44 } 45 } 46 47 const file = try std.fs.cwd().openFile(filename, .{}); 48 const text = try file.reader().readAllAlloc(heapalloc, std.math.maxInt(u32)); 49 defer heapalloc.free(text); 50 51 var part = try std.fmt.parseInt(u8, args[1], 10); 52 var answer: ?[]u8 = null; 53 switch (part) { 54 1 => answer = try part1(heapalloc, text, args[2..]), 55 2 => answer = try part2(heapalloc, text, args[2..]), 56 else => { 57 std.debug.print("Invalid part number!\n", .{}); 58 std.os.exit(1); 59 }, 60 } 61 part = part - 1; 62 63 if (answer != null) { 64 const stdout = std.io.getStdOut().writer(); 65 try std.fmt.format(stdout, "{s}\n", .{answer.?}); 66 if (sols[part] != null and !std.mem.eql(u8, answer.?, sols[part].?)) { 67 std.debug.print("Invalid answer\n", .{}); 68 std.os.exit(1); 69 } 70 heapalloc.free(answer.?); 71 } 72 73 if (sols[part] == null) { 74 std.debug.print("Missing solution\n", .{}); 75 std.os.exit(1); 76 } 77 } 78 }; 79 return impl.main; 80} 81 82pub const Pos = struct { 83 x: i64, 84 y: i64, 85 const Self = @This(); 86 87 pub fn add(self: Self, other: Self) Self { 88 return Self{ .x = self.x + other.x, .y = self.y + other.y }; 89 } 90 91 pub fn mult(self: Self, val: i64) Self { 92 return Self{ .x = self.x * val, .y = self.y * val }; 93 } 94}; 95 96pub const Dir = struct { 97 pub const East = Pos{ .x = 1, .y = 0 }; 98 pub const West = Pos{ .x = -1, .y = 0 }; 99 pub const South = Pos{ .x = 0, .y = -1 }; 100 pub const North = Pos{ .x = 0, .y = 1 }; 101 102 pub const Name = enum(u8) { NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3 }; 103 pub const dirs = [_]Pos{ North, East, South, West }; 104 105 pub fn get(name: Name) Pos { 106 return dirs[@enumToInt(name)]; 107 } 108 109 pub fn nextCW(dir: usize, offset: usize) usize { 110 return (dir + @intCast(u32, offset)) % @intCast(u32, dirs.len); 111 } 112 113 pub fn nextCCW(dir: usize, offset: usize) usize { 114 const constrained = offset % dirs.len; 115 if (dir >= constrained) { 116 return dir - constrained; 117 } else { 118 return dirs.len - (constrained - dir); 119 } 120 } 121 122 const cos90vs = [_]i32{ 1, 0, -1, 0 }; 123 const sin90vs = [_]i32{ 0, 1, 0, -1 }; 124 125 pub fn rotCW(pos: Pos, offset: usize) Pos { 126 const constrained = (4 - offset % 4) % 4; 127 return Pos{ 128 .x = cos90vs[constrained] * pos.x - sin90vs[constrained] * pos.y, 129 .y = sin90vs[constrained] * pos.x + cos90vs[constrained] * pos.y, 130 }; 131 } 132 133 pub fn rotCCW(pos: Pos, offset: usize) Pos { 134 const constrained = offset % 4; 135 return Pos{ 136 .x = cos90vs[constrained] * pos.x - sin90vs[constrained] * pos.y, 137 .y = sin90vs[constrained] * pos.x + cos90vs[constrained] * pos.y, 138 }; 139 } 140}; 141 142pub fn unwrap(v: anytype) !@TypeOf(v.?) { 143 if (v == null) return Error.InvalidInput; 144 return v.?; 145}