diff --git a/2024/src/day11.zig b/2024/src/day11.zig new file mode 100644 index 0000000..3f63131 --- /dev/null +++ b/2024/src/day11.zig @@ -0,0 +1,118 @@ +const std = @import("std"); +const aoc = @import("aoc.zig"); + +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; + +pub fn main() !void { + var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const file = try std.fs.cwd().openFile("input/day11.txt", .{}); + defer file.close(); + + const text = try file.readToEndAlloc(allocator, comptime 1 << 30); + defer allocator.free(text); + + var stones = try Stones.parse(allocator, text); + defer stones.deinit(); + + const stdout_file = std.io.getStdOut().writer(); + var bw = std.io.bufferedWriter(stdout_file); + const stdout = bw.writer(); + + try stdout.print("{d}\n", .{try part1(allocator, stones)}); + try bw.flush(); +} + +fn part1(allocator: Allocator, start: Stones) !usize { + var stones = try start.clone(); + defer stones.deinit(); + + for (0..25) |_| { + try stones.blink(allocator); + } + + return stones.list.items.len; +} + +const Stones = struct { + list: ArrayList(u64), + + const Self = @This(); + + fn deinit(self: *Self) void { + self.list.deinit(); + } + + fn clone(self: Self) !Self { + return .{ .list = try self.list.clone() }; + } + + fn parse(allocator: Allocator, text: []const u8) !Self { + var list = ArrayList(u64).init(allocator); + errdefer list.deinit(); + + var lines = std.mem.tokenizeScalar(u8, text, '\n'); + var it = std.mem.tokenizeScalar(u8, lines.next().?, ' '); + while (it.next()) |level| { + const i = try std.fmt.parseInt(u64, level, 10); + try list.append(i); + } + + return .{ .list = list }; + } + + pub fn format( + self: Self, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + if (self.list.items.len > 0) { + try writer.print("{}", .{self.list.items[0]}); + } + for (self.list.items[1..]) |i| { + try writer.print(" {}", .{i}); + } + } + + fn blink(self: *Self, allocator: Allocator) !void { + var prev = self.list; + defer prev.deinit(); + + var next = ArrayList(u64).init(allocator); + errdefer next.deinit(); + + for (prev.items) |i| { + if (i == 0) { + try next.append(1); + } else if (split(i)) |parts| { + try next.append(parts.@"0"); + try next.append(parts.@"1"); + } else { + try next.append(i * 2024); + } + } + + self.list = next; + } +}; + +fn split(n: u64) ?struct { u64, u64 } { + const digits = 1 + std.math.log10(n); + if (digits % 2 == 0) { + const x = std.math.pow(u64, 10, digits / 2); + return .{ n / x, n % x }; + } + return null; +} + +test "split" { + const expectEqual = std.testing.expectEqual; + + try expectEqual(.{ 1, 0 }, split(10)); + try expectEqual(.{ 10, 0 }, split(1000)); + try expectEqual(.{ 9, 9 }, split(99)); +}