Files
aoc2024/03/src/main.zig

177 lines
6.2 KiB
Zig

// 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;
}