155 lines
4.4 KiB
Zig
155 lines
4.4 KiB
Zig
const std = @import("std");
|
|
|
|
const example = @embedFile("example");
|
|
const input = @embedFile("input");
|
|
|
|
var allocator: std.mem.Allocator = undefined;
|
|
|
|
pub fn main() anyerror!void {
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
defer arena.deinit();
|
|
allocator = arena.allocator();
|
|
|
|
try std.testing.expectEqual(try solve(example), 13);
|
|
const result = try solve(input);
|
|
try std.io.getStdOut().writer().print("{}\n", .{result});
|
|
}
|
|
|
|
const ListErrors = error{
|
|
OutOfMemory,
|
|
};
|
|
|
|
const List = struct {
|
|
data: std.ArrayList(Elt),
|
|
fn init(reader: anytype) !*List {
|
|
var l = try allocator.create(List);
|
|
l.data = std.ArrayList(Elt).init(allocator);
|
|
while (true) {
|
|
const c = reader.readByte() catch break;
|
|
switch (c) {
|
|
'[' => {
|
|
var e = try l.data.addOne();
|
|
e.* = Elt{ .list = try List.init(reader) };
|
|
},
|
|
']' => {
|
|
return l;
|
|
},
|
|
',' => { // comma after a list ending, ignore
|
|
},
|
|
else => { // a digit
|
|
var e = try l.data.addOne();
|
|
e.* = Elt{ .int = c - '0' };
|
|
while (true) {
|
|
const d = reader.readByte() catch unreachable;
|
|
if (d == ']') {
|
|
return l;
|
|
} else if (d == ',') {
|
|
break;
|
|
}
|
|
e.int = e.int * 10 + d;
|
|
}
|
|
},
|
|
}
|
|
}
|
|
return l;
|
|
}
|
|
fn initSingleton(n: u8) !*List {
|
|
var l = try allocator.create(List);
|
|
l.data = std.ArrayList(Elt).init(allocator);
|
|
var e = try l.data.addOne();
|
|
e.* = Elt{ .int = n };
|
|
return l;
|
|
}
|
|
fn isLowerThan(l: *List, o: *List) ListErrors!?bool {
|
|
var i: usize = 0;
|
|
while (true) : (i += 1) {
|
|
if (o.len() <= i) {
|
|
if (l.len() <= i) {
|
|
return null;
|
|
}
|
|
return false;
|
|
}
|
|
if (l.len() <= i) {
|
|
return true;
|
|
}
|
|
const t = try l.data.items[i].isLowerThan(&(o.data.items[i]));
|
|
if (t != null) {
|
|
return t;
|
|
}
|
|
}
|
|
}
|
|
inline fn len(l: *List) usize {
|
|
return l.data.items.len;
|
|
}
|
|
fn print(l: *List) void {
|
|
for (l.data.items) |e| {
|
|
switch (e) {
|
|
Elt.int => |i| std.debug.print("{d} ", .{i}),
|
|
Elt.list => |o| {
|
|
std.debug.print("[", .{});
|
|
o.print();
|
|
std.debug.print("]", .{});
|
|
},
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const EltType = enum {
|
|
int,
|
|
list,
|
|
};
|
|
|
|
const Elt = union(EltType) {
|
|
int: u8,
|
|
list: *List,
|
|
fn isLowerThan(e: *Elt, f: *Elt) !?bool {
|
|
switch (e.*) {
|
|
Elt.int => |i| switch (f.*) {
|
|
Elt.int => |j| {
|
|
if (i == j) {
|
|
return null;
|
|
}
|
|
return i < j;
|
|
},
|
|
Elt.list => |o| {
|
|
var l = try List.initSingleton(i);
|
|
return l.isLowerThan(o);
|
|
},
|
|
},
|
|
Elt.list => |l| switch (f.*) {
|
|
Elt.int => |j| {
|
|
f.* = Elt{ .list = try List.initSingleton(j) };
|
|
return e.isLowerThan(f);
|
|
},
|
|
Elt.list => |o| {
|
|
return l.isLowerThan(o);
|
|
},
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
fn solve(puzzle: []const u8) !u64 {
|
|
var it = std.mem.tokenize(u8, puzzle, "\n");
|
|
var i: usize = 1;
|
|
var tot: usize = 0;
|
|
while (it.next()) |line| {
|
|
var firstLine = std.io.fixedBufferStream(line);
|
|
var first = try List.init(firstLine.reader());
|
|
var secondLine = std.io.fixedBufferStream(it.next() orelse unreachable);
|
|
var second = try List.init(secondLine.reader());
|
|
const t = try first.isLowerThan(second);
|
|
//first.print();
|
|
//std.debug.print("\n", .{});
|
|
//second.print();
|
|
//std.debug.print("\n{d}: {?}\n", .{ i, t });
|
|
if (t) |s| {
|
|
if (s) {
|
|
tot += i;
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
return tot;
|
|
}
|