aoc-2020-zig

Advent of Code 2020 Solutions in Zig
git clone https://git.sinitax.com/sinitax/aoc-2020-zig
Log | Files | Refs | README | sfeed.txt

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}