#import "String";
#import "Sort";
#import "Basic";
solve_day11 :: (test: bool) {
contents := read_entire_file(ifx test then "inputs/day11_test.txt" else "inputs/day11.txt");
sections := split(contents, "\n\n");
part1 := solve(true, sections);
print("Part 1: %\n", part1);
part2 := solve(false, sections);
print("Part 2: %\n", part2);
}
solve :: (part1: bool, sections: []string) -> s64 {
monkeys: [..]Monkey;
for section: sections {
section_lines := split(section, "\n");
starting_items_split := split(slice(section_lines[1], 18, section_lines[1].count - 18), ", ");
operation_number := ifx ends_with(section_lines[2], "old") then -1 else string_to_int(slice(section_lines[2], 24, section_lines[2].count - 24), 10, s16);
new_monkey := array_add(*monkeys);
<< new_monkey = .{
operation = section_lines[2][23],
operation_number = to_s128(operation_number),
test = string_to_int(slice(section_lines[3], 20, section_lines[3].count - 20), 10, s64),
test_true = string_to_int(slice(section_lines[4], 28, section_lines[4].count - 28), 10, s64),
test_false = string_to_int(slice(section_lines[5], 29, section_lines[5].count - 29), 10, s64),
};
for starting_items_split {
array_add(*new_monkey.items, to_s128(string_to_int(it, 10, s64)));
}
}
minus_one := to_s128(-1);
zero := to_s128(0);
modulus := 3;
if !part1 {
modulus = 1;
for monkeys {
modulus *= it.test;
}
}
run_to := ifx part1 then 20 else 10_000;
for 1..run_to {
for *monkey, monkey_id: monkeys {
for *monkey.items {
monkey.handled += 1;
op_num := ifx monkey.operation_number != minus_one then monkey.operation_number else << it;
old_val := << it;
if monkey.operation == {
case #char "+";
<< it = op_num + << it;
case #char "*";
<< it= << it * op_num;
case;
assert(false, "Unknown operation: %", monkey.operation);
}
assert(old_val <= << it, "Wrapping? %, %", old_val, << it);
f := u8.[monkey.operation];
res, remainder := signed_divide_with_remainder(<< it, to_s128(modulus));
<< it = ifx part1 then << it / modulus else remainder;
give_to := -1;
res, remainder = signed_divide_with_remainder(<< it, to_s128(monkey.test));
if remainder == zero {
give_to = monkey.test_true;
} else {
give_to = monkey.test_false;
}
item := << it;
remove it;
array_add(*monkeys[give_to].items, item);
}
}
}
quick_sort(monkeys, (a, b) => b.handled - a.handled);
return monkeys[0].handled * monkeys[1].handled;
}
#scope_file
Monkey :: struct {
items: [..]S128;
operation: u8;
operation_number: S128;
test: s64;
test_true: s64;
test_false: s64;
handled: s64;
}