diff --git a/day1.zig b/day1.zig index 8888312..5c79583 100644 --- a/day1.zig +++ b/day1.zig @@ -2,7 +2,9 @@ const std = @import("std"); const utils = @import("lib/utils.zig"); -const filename = "inputs/day1.txt"; +const day = "1"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -14,7 +16,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 1, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -23,7 +25,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 1, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day10.zig b/day10.zig index 656012a..566d186 100644 --- a/day10.zig +++ b/day10.zig @@ -4,7 +4,9 @@ const utils = @import("lib/utils.zig"); const spice = @import("lib/spice.zig"); -const filename = "inputs/day10.txt"; +const day = "10"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -16,7 +18,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 10, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -25,7 +27,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 10, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day11.zig b/day11.zig new file mode 100644 index 0000000..7c28dae --- /dev/null +++ b/day11.zig @@ -0,0 +1,154 @@ +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); +} diff --git a/day2.zig b/day2.zig index bef5bfc..36bfcef 100644 --- a/day2.zig +++ b/day2.zig @@ -2,7 +2,9 @@ const std = @import("std"); const utils = @import("lib/utils.zig"); -const filename = "inputs/day2.txt"; +const day = "2"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -14,7 +16,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 2, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -23,7 +25,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 2, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day3.zig b/day3.zig index 32d1ed7..37307e0 100644 --- a/day3.zig +++ b/day3.zig @@ -4,7 +4,9 @@ const utils = @import("lib/utils.zig"); const isDigit = std.ascii.isDigit; -const filename = "inputs/day3.txt"; +const day = "3"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -16,7 +18,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 3, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -25,7 +27,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 3, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day4.zig b/day4.zig index 504b0a3..ab6dd23 100644 --- a/day4.zig +++ b/day4.zig @@ -2,7 +2,9 @@ const std = @import("std"); const utils = @import("lib/utils.zig"); -const filename = "inputs/day4.txt"; +const day = "4"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -14,7 +16,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 4, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -23,7 +25,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 4, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day5.zig b/day5.zig index dbb14c7..4706bb6 100644 --- a/day5.zig +++ b/day5.zig @@ -4,7 +4,9 @@ const utils = @import("lib/utils.zig"); const List = std.DoublyLinkedList(u8); -const filename = "inputs/day5.txt"; +const day = "5"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -16,7 +18,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 5, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -25,7 +27,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 5, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day6.zig b/day6.zig index 3bc18f1..0793ac2 100644 --- a/day6.zig +++ b/day6.zig @@ -2,7 +2,9 @@ const std = @import("std"); const utils = @import("lib/utils.zig"); -const filename = "inputs/day6.txt"; +const day = "6"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -14,7 +16,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 6, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -23,7 +25,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 6, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day7.zig b/day7.zig index 6d110df..0e81391 100644 --- a/day7.zig +++ b/day7.zig @@ -4,7 +4,9 @@ const utils = @import("lib/utils.zig"); const spice = @import("lib/spice.zig"); -const filename = "inputs/day7.txt"; +const day = "7"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -16,7 +18,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 7, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -25,7 +27,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 7, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day8.zig b/day8.zig index 9fe2b66..0885f8b 100644 --- a/day8.zig +++ b/day8.zig @@ -4,7 +4,9 @@ const utils = @import("lib/utils.zig"); const spice = @import("lib/spice.zig"); -const filename = "inputs/day8.txt"; +const day = "8"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -16,7 +18,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 8, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -25,7 +27,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 8, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/day9.zig b/day9.zig index 506c47b..d8b67d4 100644 --- a/day9.zig +++ b/day9.zig @@ -4,7 +4,9 @@ const utils = @import("lib/utils.zig"); const spice = @import("lib/spice.zig"); -const filename = "inputs/day9.txt"; +const day = "9"; + +const filename = "inputs/day" ++ day ++ ".txt"; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -16,7 +18,7 @@ pub fn main() !void { const result = try part1(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 9, part 1: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 1: {}\n", .{result}); } { @@ -25,7 +27,7 @@ pub fn main() !void { const result = try part2(alloc, file_reader.reader()); - try std.io.getStdOut().writer().print("Day 9, part 2: {}\n", .{result}); + try std.io.getStdOut().writer().print("Day " ++ day ++ ", part 2: {}\n", .{result}); } } diff --git a/inputs/day11.txt b/inputs/day11.txt new file mode 100644 index 0000000..d252362 --- /dev/null +++ b/inputs/day11.txt @@ -0,0 +1 @@ +0 89741 316108 7641 756 9 7832357 91 diff --git a/lib/utils.zig b/lib/utils.zig index ed80b7b..e8037dc 100644 --- a/lib/utils.zig +++ b/lib/utils.zig @@ -92,12 +92,14 @@ pub fn NumberParser(comptime T: type) type { }; } -pub fn numberParser(comptime T: type, input: []const u8) NumberParser(T) { - return NumberParser(T){ .token_it = std.mem.tokenizeScalar(u8, input, ' ') }; +pub fn numberParserWithDelimiter(comptime T: type, input: []const u8, delimiter: u8) NumberParser(T) { + const input_trimmed = std.mem.trim(u8, input, "\n"); + + return NumberParser(T){ .token_it = std.mem.tokenizeScalar(u8, input_trimmed, delimiter) }; } -pub fn numberParserWithDelimiter(comptime T: type, input: []const u8, delimiter: u8) NumberParser(T) { - return NumberParser(T){ .token_it = std.mem.tokenizeScalar(u8, input, delimiter) }; +pub fn numberParser(comptime T: type, input: []const u8) NumberParser(T) { + return numberParserWithDelimiter(T, input, ' '); } pub fn allocGrid(comptime T: type, alloc: std.mem.Allocator, n: usize, m: usize) ![][]T {