// Day 3! I chose the worst way to do this and then stuck with it // Also zig is hell I want rust... const std = @import("std"); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const alloc = arena.allocator(); const test_data = @embedFile("test"); const test_data2 = @embedFile("test2"); const input_data = @embedFile("input"); pub fn main() !void { const stdout = std.io.getStdOut().writer(); const value1 = try run1(input_data); try stdout.print("{d}\n", .{value1}); const value2 = try run2(input_data); try stdout.print("{d}\n", .{value2}); } test "test input part 1" { const value = try run1(test_data); std.debug.print("{d}\n", .{value}); try std.testing.expectEqual(value, 161); } test "test input part 2" { const value = try run2(test_data2); std.debug.print("{d}\n", .{value}); try std.testing.expectEqual(value, 48); } const STATE = enum { waiting, m, u, l, open, d, o, n, open_do, close_do, apo, t, open_dont, close_dont, rewind }; fn parseIntFromReader(reader: anytype) anyerror!u64 { const f = try reader.readByte(); if (f < '0' or f > '9') return error.BadCharacter; var v: u64 = f - '0'; while (true) { const c = try reader.readByte(); if (c < '0' or c > '9') { break; } else { v = (v * 10) + (c - '0'); } } return v; } fn run2(s: []const u8) !u64 { // zig doesn't have regex // sobs var s_fbs = std.io.fixedBufferStream(s); var reader = s_fbs.reader(); var state = STATE.waiting; var total: u64 = 0; var do_mul: bool = true; // i tried a state machine. // god i don't know zig at all // this is so genuinely awful read: while (true) { const err_state = sw: { break :sw switch (state) { STATE.rewind => { try s_fbs.seekBy(-1); break :sw STATE.waiting; }, STATE.waiting => { switch (reader.readByte() catch |e| break :sw e) { 'm' => { break :sw STATE.m; }, 'd' => { break :sw STATE.d; }, else => { break :sw STATE.waiting; }, } }, STATE.m => if ((reader.readByte() catch |e| break :sw e) == 'u') STATE.u else STATE.rewind, STATE.u => if ((reader.readByte() catch |e| break :sw e) == 'l') STATE.l else STATE.rewind, STATE.l => if ((reader.readByte() catch |e| break :sw e) == '(') STATE.open else STATE.rewind, STATE.d => if ((reader.readByte() catch |e| break :sw e) == 'o') STATE.o else STATE.rewind, STATE.o => switch (reader.readByte() catch |e| break :sw e) { 'n' => STATE.n, '(' => STATE.open_do, else => STATE.rewind, }, STATE.n => if ((reader.readByte() catch |e| break :sw e) == '\'') STATE.apo else STATE.rewind, STATE.apo => if ((reader.readByte() catch |e| break :sw e) == 't') STATE.t else STATE.rewind, STATE.t => if ((reader.readByte() catch |e| break :sw e) == '(') STATE.open_dont else STATE.rewind, STATE.open_do => if ((reader.readByte() catch |e| break :sw e) == ')') STATE.close_do else STATE.rewind, STATE.open_dont => if ((reader.readByte() catch |e| break :sw e) == ')') STATE.close_dont else STATE.rewind, STATE.close_do => { do_mul = true; break :sw STATE.waiting; }, STATE.close_dont => { do_mul = false; break :sw STATE.waiting; }, STATE.open => { const num0 = parseIntFromReader(reader) catch |e| break :sw e; try s_fbs.seekBy(-1); if ((reader.readByte() catch |e| break :sw e) != ',') break :sw error.BadCharacter; const num1 = parseIntFromReader(reader) catch |e| break :sw e; try s_fbs.seekBy(-1); if ((reader.readByte() catch |e| break :sw e) != ')') break :sw error.BadCharacter; std.debug.print("{d} {d}\n", .{ num0, num1 }); if (do_mul) total += num0 * num1; break :sw STATE.waiting; }, };}; state = err_state catch |e| switch (e) { error.EndOfStream => { break :read; }, error.BadCharacter => STATE.rewind, else => return e }; } return total; } fn run1(s: []const u8) !u64 { // zig doesn't have regex // sobs var s_fbs = std.io.fixedBufferStream(s); var reader = s_fbs.reader(); var state = STATE.waiting; var total: u64 = 0; // i tried a state machine. // god i don't know zig at all // this is so genuinely awful read: while (true) { const err_state = sw: { break :sw switch (state) { STATE.waiting => if ((reader.readByte() catch |e| break :sw e) == 'm') STATE.m else STATE.waiting, STATE.m => if ((reader.readByte() catch |e| break :sw e) == 'u') STATE.u else STATE.waiting, STATE.u => if ((reader.readByte() catch |e| break :sw e) == 'l') STATE.l else STATE.waiting, STATE.l => if ((reader.readByte() catch |e| break :sw e) == '(') STATE.open else STATE.waiting, STATE.open => { const num0 = parseIntFromReader(reader) catch |e| break :sw e; try s_fbs.seekBy(-1); if ((reader.readByte() catch |e| break :sw e) != ',') break :sw error.BadCharacter; const num1 = parseIntFromReader(reader) catch |e| break :sw e; try s_fbs.seekBy(-1); if ((reader.readByte() catch |e| break :sw e) != ')') break :sw error.BadCharacter; std.debug.print("{d} {d}\n", .{ num0, num1 }); total += num0 * num1; break :sw STATE.waiting; }, else => STATE.waiting, };}; state = err_state catch |e| switch (e) { error.EndOfStream => { break :read; }, error.BadCharacter => STATE.rewind, else => return e }; } return total; }