diff --git a/03/src/main.zig b/03/src/main.zig index bb51b7b..4fcd7e7 100644 --- a/03/src/main.zig +++ b/03/src/main.zig @@ -34,23 +34,19 @@ test "test input part 2" { const STATE = enum { waiting, m, u, l, open, d, o, n, open_do, close_do, apo, t, open_dont, close_dont, rewind }; -fn integerUntilDelimiter(reader: anytype, writer: anytype, delimiter: u8, optional_max_size: ?usize) anyerror!void { - if (optional_max_size) |max_size| { - for (0..max_size) |_| { - const byte: u8 = try reader.readByte(); - if (byte == delimiter) return; - if (byte < '0' or byte > '9') return error.BadCharacter; - try writer.writeByte(byte); +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 error.StreamTooLong; - } else { - while (true) { - const byte: u8 = try reader.readByte(); - if (byte == delimiter) return; - try writer.writeByte(byte); - } - // Can not throw `error.StreamTooLong` since there are no boundary. } + return v; } fn run2(s: []const u8) !u64 { @@ -60,7 +56,6 @@ fn run2(s: []const u8) !u64 { var s_fbs = std.io.fixedBufferStream(s); var reader = s_fbs.reader(); var state = STATE.waiting; - var buf: [1024]u8 = undefined; var total: u64 = 0; var do_mul: bool = true; @@ -68,75 +63,66 @@ fn run2(s: []const u8) !u64 { // god i don't know zig at all // this is so genuinely awful read: while (true) { - // state transition - state = sw: { - break :sw switch (state) { - STATE.rewind => { - try s_fbs.seekBy(-1); - break :sw STATE.waiting; - }, + 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 { break :read; }) { - 'm' => { break :sw STATE.m; }, - 'd' => { break :sw STATE.d; }, - else => { 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 { break :read; } == 'u') STATE.u else STATE.rewind, - STATE.u => if (reader.readByte() catch { break :read; } == 'l') STATE.l else STATE.rewind, - STATE.l => if (reader.readByte() catch { break :read; } == '(') STATE.open else STATE.rewind, + 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 { break :read; } == 'o') STATE.o else STATE.rewind, - STATE.o => switch (reader.readByte() catch { break :read; }) { - 'n' => STATE.n, - '(' => STATE.open_do, - else => STATE.rewind, - }, - STATE.n => if (reader.readByte() catch { break :read; } == '\'') STATE.apo else STATE.rewind, - STATE.apo => if (reader.readByte() catch { break :read; } == 't') STATE.t else STATE.rewind, - STATE.t => if (reader.readByte() catch { break :read; } == '(') STATE.open_dont 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 { break :read; } == ')') STATE.close_do else STATE.rewind, - STATE.open_dont => if (reader.readByte() catch { break :read; } == ')') STATE.close_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.close_do => { + do_mul = true; + break :sw STATE.waiting; + }, + STATE.close_dont => { + do_mul = false; + break :sw STATE.waiting; + }, - STATE.open => { - var fbs = std.io.fixedBufferStream(&buf); - integerUntilDelimiter(reader, fbs.writer(), ',', 1024) catch { - state = STATE.waiting; - continue :read; - }; - const num0 = std.fmt.parseInt(u64, fbs.getWritten(), 10) catch { - state = STATE.waiting; - continue :read; - }; - fbs = std.io.fixedBufferStream(&buf); - integerUntilDelimiter(reader, fbs.writer(), ')', 1024) catch { - state = STATE.waiting; - continue :read; - }; - const num1 = std.fmt.parseInt(u64, fbs.getWritten(), 10) catch { - state = STATE.waiting; - continue :read; - }; - if (do_mul) { - std.debug.print("{d} {d}\n", .{ num0, num1 }); - total += num0 * num1; - } + 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; - break :sw STATE.waiting; - }, - }; + 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 }; } @@ -150,47 +136,39 @@ fn run1(s: []const u8) !u64 { var s_fbs = std.io.fixedBufferStream(s); var reader = s_fbs.reader(); var state = STATE.waiting; - var buf: [1024]u8 = undefined; 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) { - // state transition - state = sw: { - break :sw switch (state) { - STATE.waiting => if (reader.readByte() catch { break :read; } == 'm') STATE.m else STATE.waiting, - STATE.m => if (reader.readByte() catch { break :read; } == 'u') STATE.u else STATE.waiting, - STATE.u => if (reader.readByte() catch { break :read; } == 'l') STATE.l else STATE.waiting, - STATE.l => if (reader.readByte() catch { break :read; } == '(') STATE.open else STATE.waiting, + 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 => { - var fbs = std.io.fixedBufferStream(&buf); - integerUntilDelimiter(reader, fbs.writer(), ',', 1024) catch { - state = STATE.waiting; - continue :read; - }; - const num0 = std.fmt.parseInt(u64, fbs.getWritten(), 10) catch { - state = STATE.waiting; - continue :read; - }; - fbs = std.io.fixedBufferStream(&buf); - integerUntilDelimiter(reader, fbs.writer(), ')', 1024) catch { - state = STATE.waiting; - continue :read; - }; - const num1 = std.fmt.parseInt(u64, fbs.getWritten(), 10) catch { - state = STATE.waiting; - continue :read; - }; - std.debug.print("{d} {d}\n", .{ num0, num1 }); - total += num0 * num1; + 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; - break :sw STATE.waiting; - }, - else => STATE.waiting, - }; + 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 }; }