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

console8.zig (2934B)


      1const std = @import("std");
      2const aoc = @import("aoc.zig");
      3
      4pub const OpError = error{ InstructionPointerOOB, InvalidFormat, InstructionUnknown };
      5pub const OpFuncSig = fn (ctx: *Console, arg: i64) OpError!void;
      6pub const Instruction = struct { opcode: []const u8, opfunc: *const OpFuncSig, argval: i64 };
      7
      8pub const Console = struct {
      9    accumulator: i64 = 0,
     10    instructptr: u64 = 0,
     11
     12    jumpAddr: i65 = 0,
     13
     14    code: []const u8,
     15    instlist: [][]const u8,
     16    allocator: std.mem.Allocator,
     17    const Self = @This();
     18
     19    pub fn init(code: []const u8, allocator: std.mem.Allocator) !Self {
     20        var instvec = std.ArrayList([]const u8).init(allocator);
     21        errdefer instvec.deinit();
     22
     23        var instit = std.mem.tokenize(u8, code, "\n");
     24        while (instit.next()) |inst| {
     25            try instvec.append(inst);
     26        }
     27        return Console{
     28            .code = code,
     29            .instlist = instvec.toOwnedSlice(),
     30            .allocator = allocator,
     31        };
     32    }
     33
     34    pub fn deinit(self: *Self) void {
     35        self.allocator.free(self.instlist);
     36    }
     37
     38    pub fn reset(self: *Self) void {
     39        self.accumulator = 0;
     40        self.instructptr = 0;
     41    }
     42
     43    const instructionMap = std.ComptimeStringMap(*const OpFuncSig, .{
     44        .{ "jmp", jumpInstruction },
     45        .{ "acc", accInstruction },
     46        .{ "nop", nopInstruction },
     47    });
     48
     49    pub fn jumpInstruction(self: *Self, arg: i64) OpError!void {
     50        self.jumpAddr = @intCast(i65, self.instructptr) + @intCast(i65, arg);
     51        if (self.jumpAddr < 0 or self.jumpAddr >= self.instlist.len)
     52            return error.InstructionPointerOOB;
     53        self.instructptr = @intCast(u64, self.jumpAddr);
     54    }
     55
     56    pub fn accInstruction(self: *Self, arg: i64) OpError!void {
     57        self.accumulator += arg;
     58        self.instructptr += 1;
     59    }
     60
     61    pub fn nopInstruction(self: *Self, arg: i64) OpError!void {
     62        _ = arg;
     63        self.instructptr += 1;
     64    }
     65
     66    pub fn parseNext(self: *Self) !?Instruction {
     67        if (self.instructptr >= self.instlist.len)
     68            return null;
     69
     70        const inststr = self.instlist[self.instructptr];
     71        const sep = std.mem.indexOfScalar(u8, inststr, ' ');
     72        if (sep == null) return OpError.InvalidFormat;
     73
     74        const opcode = inststr[0..sep.?];
     75        if (instructionMap.get(opcode)) |opfunc| {
     76            const arg = inststr[sep.? + 1 ..];
     77            const val = std.fmt.parseInt(i64, arg, 10) catch {
     78                aoc.debugfmt("Failed to parse arg value: {s}\n", .{arg});
     79                return OpError.InvalidFormat;
     80            };
     81            return Instruction{ .opcode = opcode, .opfunc = opfunc, .argval = val };
     82        } else {
     83            aoc.debugfmt("Unknown instruction: {s}\n", .{inststr});
     84            return OpError.InstructionUnknown;
     85        }
     86    }
     87
     88    pub fn exec(self: *Self, inst: *Instruction) !void {
     89        try inst.opfunc(self, inst.argval);
     90    }
     91};