day 3
This commit is contained in:
231
03/src/main.zig
Normal file
231
03/src/main.zig
Normal file
@@ -0,0 +1,231 @@
|
||||
// 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 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);
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
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 buf: [1024]u8 = undefined;
|
||||
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) {
|
||||
// state transition
|
||||
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.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.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.open_do => if (reader.readByte() catch {
|
||||
break :read;
|
||||
} == ')') STATE.close_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.open_dont => if (reader.readByte() catch {
|
||||
break :read;
|
||||
} == ')') 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 => {
|
||||
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;
|
||||
}
|
||||
|
||||
break :sw STATE.waiting;
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
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 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,
|
||||
|
||||
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;
|
||||
|
||||
break :sw STATE.waiting;
|
||||
},
|
||||
else => STATE.waiting,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
Reference in New Issue
Block a user