mirror of
https://github.com/MorizzG/aoc-2024.git
synced 2025-12-06 04:22:43 +00:00
154 lines
4.2 KiB
Zig
154 lines
4.2 KiB
Zig
|
|
const std = @import("std");
|
||
|
|
|
||
|
|
const utils = @import("lib/utils.zig");
|
||
|
|
|
||
|
|
const spice = @import("lib/spice.zig");
|
||
|
|
|
||
|
|
const day = "11";
|
||
|
|
|
||
|
|
const filename = "inputs/day" ++ day ++ ".txt";
|
||
|
|
|
||
|
|
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());
|
||
|
|
|
||
|
|
try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
const file_reader = try utils.FileReader.init(alloc, filename);
|
||
|
|
defer file_reader.deinit();
|
||
|
|
|
||
|
|
const result = try part2(alloc, file_reader.reader());
|
||
|
|
|
||
|
|
try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const CacheKey = struct { n: u64, depth: u8 };
|
||
|
|
|
||
|
|
fn countStones(n: u64, remaining_depth: u8, cache: *std.AutoHashMap(CacheKey, u64)) u64 {
|
||
|
|
if (remaining_depth == 0) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cache.get(.{ .n = n, .depth = remaining_depth })) |result| {
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (n == 0) {
|
||
|
|
const result = countStones(1, remaining_depth - 1, cache);
|
||
|
|
cache.put(.{ .n = n, .depth = remaining_depth }, result) catch @panic("cache put failed");
|
||
|
|
|
||
|
|
return result;
|
||
|
|
// try countStones(count, 1, remaining_depth);
|
||
|
|
// return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (utils.num_digits(n) % 2 == 0) {
|
||
|
|
const num_digits = utils.num_digits(n);
|
||
|
|
|
||
|
|
const pow10 = std.math.powi(u32, 10, num_digits / 2) catch @panic("powi failed");
|
||
|
|
|
||
|
|
const left = n / pow10;
|
||
|
|
const right = n % pow10;
|
||
|
|
|
||
|
|
// return countStones(left, remaining_depth - 1, cache) + countStones(right, remaining_depth - 1, cache);
|
||
|
|
|
||
|
|
const left_result = countStones(left, remaining_depth - 1, cache);
|
||
|
|
const right_result = countStones(right, remaining_depth - 1, cache);
|
||
|
|
|
||
|
|
const result = left_result + right_result;
|
||
|
|
|
||
|
|
cache.put(.{ .n = n, .depth = remaining_depth }, result) catch @panic("cache put failed");
|
||
|
|
|
||
|
|
return left_result + right_result;
|
||
|
|
|
||
|
|
// try countStones(count, left, remaining_depth - 1);
|
||
|
|
// try countStones(count, right, remaining_depth - 1);
|
||
|
|
// return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = countStones(n * 2024, remaining_depth - 1, cache);
|
||
|
|
cache.put(.{ .n = n, .depth = remaining_depth }, result) catch @panic("cache put failed");
|
||
|
|
|
||
|
|
return result;
|
||
|
|
|
||
|
|
// try countStones(count, 2024 * n, remaining_depth - 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn part1(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
||
|
|
const input = try reader.readAllAlloc(alloc, std.math.maxInt(usize));
|
||
|
|
defer alloc.free(input);
|
||
|
|
|
||
|
|
var count: u64 = 0;
|
||
|
|
|
||
|
|
var cache = std.AutoHashMap(CacheKey, u64).init(alloc);
|
||
|
|
defer cache.deinit();
|
||
|
|
|
||
|
|
var number_parser = utils.numberParser(u64, input);
|
||
|
|
|
||
|
|
while (try number_parser.next()) |n| {
|
||
|
|
count += countStones(n, 25, &cache);
|
||
|
|
}
|
||
|
|
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
fn part2(alloc: std.mem.Allocator, reader: anytype) !u64 {
|
||
|
|
const input = try reader.readAllAlloc(alloc, std.math.maxInt(usize));
|
||
|
|
defer alloc.free(input);
|
||
|
|
|
||
|
|
var count: u64 = 0;
|
||
|
|
|
||
|
|
var cache = std.AutoHashMap(CacheKey, u64).init(alloc);
|
||
|
|
defer cache.deinit();
|
||
|
|
|
||
|
|
var number_parser = utils.numberParser(u64, input);
|
||
|
|
|
||
|
|
while (try number_parser.next()) |n| {
|
||
|
|
count += countStones(n, 75, &cache);
|
||
|
|
}
|
||
|
|
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
test "part1 example" {
|
||
|
|
const alloc = std.testing.allocator;
|
||
|
|
|
||
|
|
const example = "125 17";
|
||
|
|
|
||
|
|
var stream = std.io.fixedBufferStream(example);
|
||
|
|
|
||
|
|
const result = try part1(alloc, stream.reader());
|
||
|
|
|
||
|
|
try std.testing.expectEqual(55312, 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(193899, 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(229682160383225, result);
|
||
|
|
}
|