2024-12-07 23:27:28 +01:00
|
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
|
|
const utils = @import("lib/utils.zig");
|
|
|
|
|
|
|
|
|
|
const spice = @import("lib/spice.zig");
|
|
|
|
|
|
2024-12-11 22:22:04 +01:00
|
|
|
const day = "7";
|
|
|
|
|
|
|
|
|
|
const filename = "inputs/day" ++ day ++ ".txt";
|
2024-12-07 23:27:28 +01:00
|
|
|
|
|
|
|
|
pub fn main() !void {
|
|
|
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
|
|
|
const alloc = gpa.allocator();
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
|
|
|
|
defer file_reader.deinit();
|
|
|
|
|
|
|
|
|
|
const result = try part1(alloc, file_reader.reader());
|
|
|
|
|
|
2024-12-11 22:22:04 +01:00
|
|
|
try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result});
|
2024-12-07 23:27:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
|
|
|
|
defer file_reader.deinit();
|
|
|
|
|
|
|
|
|
|
const result = try part2(alloc, file_reader.reader());
|
|
|
|
|
|
2024-12-11 22:22:04 +01:00
|
|
|
try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result});
|
2024-12-07 23:27:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn checkEqnPlusMul(test_value: u64, cur_value: u64, eqn: []const u64) bool {
|
|
|
|
|
if (eqn.len == 0) {
|
|
|
|
|
return cur_value == test_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const x = eqn[0];
|
|
|
|
|
|
|
|
|
|
// +
|
|
|
|
|
{
|
|
|
|
|
const next_value = cur_value + x;
|
|
|
|
|
|
|
|
|
|
// if next_value > test_value: abort, can never get smaller
|
|
|
|
|
if (next_value <= test_value) {
|
|
|
|
|
if (checkEqnPlusMul(test_value, next_value, eqn[1..])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// *
|
|
|
|
|
{
|
|
|
|
|
const next_value = cur_value * x;
|
|
|
|
|
|
|
|
|
|
// if next_value > test_value: abort, can never get smaller
|
|
|
|
|
if (next_value <= test_value) {
|
|
|
|
|
if (checkEqnPlusMul(test_value, next_value, eqn[1..])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn checkEqnPlusMulPar(
|
|
|
|
|
t: *spice.Task,
|
|
|
|
|
args: struct {
|
|
|
|
|
test_value: u64,
|
|
|
|
|
cur_value: u64,
|
|
|
|
|
eqn: []const u64,
|
|
|
|
|
},
|
|
|
|
|
) bool {
|
|
|
|
|
const test_value = args.test_value;
|
|
|
|
|
const cur_value = args.cur_value;
|
|
|
|
|
const eqn = args.eqn;
|
|
|
|
|
|
|
|
|
|
if (cur_value > test_value) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eqn.len == 0) {
|
|
|
|
|
return cur_value == test_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const x = eqn[0];
|
|
|
|
|
|
|
|
|
|
var plus_fut = spice.Future(@TypeOf(args), bool).init();
|
|
|
|
|
|
|
|
|
|
// +
|
|
|
|
|
{
|
|
|
|
|
const next_value = cur_value + x;
|
|
|
|
|
|
|
|
|
|
// if next_value > test_value: abort, can never get smaller
|
|
|
|
|
plus_fut.fork(t, checkEqnPlusMulPar, .{
|
|
|
|
|
.test_value = test_value,
|
|
|
|
|
.cur_value = next_value,
|
|
|
|
|
.eqn = eqn[1..],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// *
|
|
|
|
|
{
|
|
|
|
|
const next_value = cur_value * x;
|
|
|
|
|
|
|
|
|
|
// if next_value > test_value: abort, can never get smaller
|
|
|
|
|
if (next_value <= test_value) {
|
|
|
|
|
if (t.call(bool, checkEqnPlusMulPar, .{ .test_value = test_value, .cur_value = next_value, .eqn = eqn[1..] })) {
|
|
|
|
|
_ = plus_fut.join(t);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (plus_fut.join(t)) |b| {
|
|
|
|
|
return b;
|
|
|
|
|
} else {
|
|
|
|
|
const next_value = cur_value + x;
|
|
|
|
|
|
|
|
|
|
return t.call(bool, checkEqnPlusMulPar, .{ .test_value = test_value, .cur_value = next_value, .eqn = eqn[1..] });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn checkEqnPlusMulConcat(test_value: u64, cur_value: u64, eqn: []u64) bool {
|
|
|
|
|
if (eqn.len == 0) {
|
|
|
|
|
return cur_value == test_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const x = eqn[0];
|
|
|
|
|
|
|
|
|
|
// +
|
|
|
|
|
{
|
|
|
|
|
const next_value = cur_value + x;
|
|
|
|
|
|
|
|
|
|
// if next_value > test_value: abort, can never get smaller
|
|
|
|
|
if (next_value <= test_value) {
|
|
|
|
|
if (checkEqnPlusMulConcat(test_value, next_value, eqn[1..])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cur_value == 0) {
|
|
|
|
|
// for first value only plus is posible
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// *
|
|
|
|
|
{
|
|
|
|
|
const next_value = cur_value * x;
|
|
|
|
|
|
|
|
|
|
// if next_value > test_value: abort, can never get smaller
|
|
|
|
|
if (next_value <= test_value) {
|
|
|
|
|
if (checkEqnPlusMulConcat(test_value, next_value, eqn[1..])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ||
|
|
|
|
|
{
|
|
|
|
|
const x_num_digits = utils.num_digits(x);
|
|
|
|
|
|
|
|
|
|
const shift = std.math.powi(u64, 10, x_num_digits) catch unreachable;
|
|
|
|
|
|
|
|
|
|
const new_value = shift * cur_value + x;
|
|
|
|
|
|
|
|
|
|
// check with concatted value
|
|
|
|
|
|
|
|
|
|
if (checkEqnPlusMulConcat(test_value, new_value, eqn[1..])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn part1(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
|
|
|
|
var sum_calibration: u64 = 0;
|
|
|
|
|
|
|
|
|
|
// var thread_pool = spice.ThreadPool.init(alloc);
|
|
|
|
|
// defer thread_pool.deinit();
|
|
|
|
|
|
|
|
|
|
// thread_pool.start(.{});
|
|
|
|
|
|
|
|
|
|
var eqn = std.ArrayList(u64).init(alloc);
|
|
|
|
|
defer eqn.deinit();
|
|
|
|
|
|
|
|
|
|
var line_reader = utils.lineReader(alloc, reader);
|
|
|
|
|
defer line_reader.deinit();
|
|
|
|
|
|
|
|
|
|
while (try line_reader.next()) |line| {
|
|
|
|
|
const colon_idx = std.mem.indexOfScalar(u8, line, ':') orelse unreachable;
|
|
|
|
|
|
|
|
|
|
const test_value = try std.fmt.parseUnsigned(u64, line[0..colon_idx], 10);
|
|
|
|
|
|
|
|
|
|
eqn.clearRetainingCapacity();
|
|
|
|
|
|
|
|
|
|
var number_parser = utils.numberParser(u64, line[colon_idx + 1 ..]);
|
|
|
|
|
|
|
|
|
|
while (try number_parser.next()) |n| {
|
|
|
|
|
try eqn.append(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checkEqnPlusMul(test_value, 0, eqn.items)) {
|
|
|
|
|
sum_calibration += test_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (thread_pool.call(bool, checkEqnPlusMulPar, .{
|
|
|
|
|
// .test_value = test_value,
|
|
|
|
|
// .cur_value = 0,
|
|
|
|
|
// .eqn = eqn.items,
|
|
|
|
|
// })) {
|
|
|
|
|
// sum_calibration += test_value;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sum_calibration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn part2(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
|
|
|
|
var sum_calibration: u64 = 0;
|
|
|
|
|
|
|
|
|
|
// var thread_pool = spice.ThreadPool.init(alloc);
|
|
|
|
|
// defer thread_pool.deinit();
|
|
|
|
|
|
|
|
|
|
// thread_pool.start(.{});
|
|
|
|
|
|
|
|
|
|
var eqn = std.ArrayList(u64).init(alloc);
|
|
|
|
|
defer eqn.deinit();
|
|
|
|
|
|
|
|
|
|
var line_reader = utils.lineReader(alloc, reader);
|
|
|
|
|
defer line_reader.deinit();
|
|
|
|
|
|
|
|
|
|
while (try line_reader.next()) |line| {
|
|
|
|
|
const colon_idx = std.mem.indexOfScalar(u8, line, ':') orelse unreachable;
|
|
|
|
|
|
|
|
|
|
const test_value = try std.fmt.parseUnsigned(u64, line[0..colon_idx], 10);
|
|
|
|
|
|
|
|
|
|
eqn.clearRetainingCapacity();
|
|
|
|
|
|
|
|
|
|
var number_parser = utils.numberParser(u64, line[colon_idx + 1 ..]);
|
|
|
|
|
|
|
|
|
|
while (try number_parser.next()) |n| {
|
|
|
|
|
try eqn.append(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checkEqnPlusMulConcat(test_value, 0, eqn.items)) {
|
|
|
|
|
sum_calibration += test_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (thread_pool.call(bool, checkEqnPar, .{
|
|
|
|
|
// .test_value = test_value,
|
|
|
|
|
// .cur_value = 0,
|
|
|
|
|
// .eqn = eqn.items,
|
|
|
|
|
// })) {
|
|
|
|
|
// sum_calibration += test_value;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sum_calibration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "part1 example" {
|
|
|
|
|
const alloc = std.testing.allocator;
|
|
|
|
|
|
|
|
|
|
const example =
|
|
|
|
|
\\190: 10 19
|
|
|
|
|
\\3267: 81 40 27
|
|
|
|
|
\\83: 17 5
|
|
|
|
|
\\156: 15 6
|
|
|
|
|
\\7290: 6 8 6 15
|
|
|
|
|
\\161011: 16 10 13
|
|
|
|
|
\\192: 17 8 14
|
|
|
|
|
\\21037: 9 7 18 13
|
|
|
|
|
\\292: 11 6 16 20
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
var stream = std.io.fixedBufferStream(example);
|
|
|
|
|
|
|
|
|
|
const result = try part1(alloc, stream.reader());
|
|
|
|
|
|
|
|
|
|
try std.testing.expectEqual(3749, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "part1 input" {
|
|
|
|
|
const alloc = std.testing.allocator;
|
|
|
|
|
|
|
|
|
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
|
|
|
|
defer file_reader.deinit();
|
|
|
|
|
|
|
|
|
|
const result = try part1(alloc, file_reader.reader());
|
|
|
|
|
|
|
|
|
|
try std.testing.expectEqual(1985268524462, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "part2 example" {
|
|
|
|
|
const alloc = std.testing.allocator;
|
|
|
|
|
|
|
|
|
|
const example =
|
|
|
|
|
\\190: 10 19
|
|
|
|
|
\\3267: 81 40 27
|
|
|
|
|
\\83: 17 5
|
|
|
|
|
\\156: 15 6
|
|
|
|
|
\\7290: 6 8 6 15
|
|
|
|
|
\\161011: 16 10 13
|
|
|
|
|
\\192: 17 8 14
|
|
|
|
|
\\21037: 9 7 18 13
|
|
|
|
|
\\292: 11 6 16 20
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
var stream = std.io.fixedBufferStream(example);
|
|
|
|
|
|
|
|
|
|
const result = try part2(alloc, stream.reader());
|
|
|
|
|
|
|
|
|
|
try std.testing.expectEqual(11387, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test "part2 input" {
|
|
|
|
|
const alloc = std.testing.allocator;
|
|
|
|
|
|
|
|
|
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
|
|
|
|
defer file_reader.deinit();
|
|
|
|
|
|
|
|
|
|
const result = try part2(alloc, file_reader.reader());
|
|
|
|
|
|
|
|
|
|
try std.testing.expectEqual(150077710195188, result);
|
|
|
|
|
}
|