@@ 0,0 1,55 @@
+Monkey 0:
+ Starting items: 63, 84, 80, 83, 84, 53, 88, 72
+ Operation: new = old * 11
+ Test: divisible by 13
+ If true: throw to monkey 4
+ If false: throw to monkey 7
+
+Monkey 1:
+ Starting items: 67, 56, 92, 88, 84
+ Operation: new = old + 4
+ Test: divisible by 11
+ If true: throw to monkey 5
+ If false: throw to monkey 3
+
+Monkey 2:
+ Starting items: 52
+ Operation: new = old * old
+ Test: divisible by 2
+ If true: throw to monkey 3
+ If false: throw to monkey 1
+
+Monkey 3:
+ Starting items: 59, 53, 60, 92, 69, 72
+ Operation: new = old + 2
+ Test: divisible by 5
+ If true: throw to monkey 5
+ If false: throw to monkey 6
+
+Monkey 4:
+ Starting items: 61, 52, 55, 61
+ Operation: new = old + 3
+ Test: divisible by 7
+ If true: throw to monkey 7
+ If false: throw to monkey 2
+
+Monkey 5:
+ Starting items: 79, 53
+ Operation: new = old + 1
+ Test: divisible by 3
+ If true: throw to monkey 0
+ If false: throw to monkey 6
+
+Monkey 6:
+ Starting items: 59, 86, 67, 95, 92, 77, 91
+ Operation: new = old + 5
+ Test: divisible by 19
+ If true: throw to monkey 4
+ If false: throw to monkey 0
+
+Monkey 7:
+ Starting items: 58, 83, 89
+ Operation: new = old * 19
+ Test: divisible by 17
+ If true: throw to monkey 2
+ If false: throw to monkey 1
@@ 0,0 1,179 @@
+const std = @import("std");
+const fmt = std.fmt;
+const fs = std.fs;
+const heap = std.heap;
+const io = std.io;
+const mem = std.mem;
+const process = std.process;
+const sort = std.sort;
+
+const Monkey = struct {
+ items: std.ArrayList(u64),
+ operation: Operation,
+ tester: Tester,
+ business: u64,
+
+ pub fn parse(alloc: mem.Allocator, str: []const u8) !Monkey {
+ var monkey: Monkey = undefined;
+ monkey.items = std.ArrayList(u64).init(alloc);
+ monkey.business = 0;
+
+ var lines = mem.split(u8, str, "\n");
+ _ = lines.next();
+
+ const items_str = lines.next().?[18..];
+ var items = mem.split(u8, items_str, ", ");
+ while (items.next()) |item| {
+ const value = try fmt.parseUnsigned(u64, item, 10);
+ try monkey.items.append(value);
+ }
+
+ const op_str = lines.next().?[23..];
+ monkey.operation = try Operation.parse(op_str);
+
+ const divisor_str = lines.next().?[21..];
+ monkey.tester.divisor = try fmt.parseUnsigned(u64, divisor_str, 10);
+
+ const if_true_str = lines.next().?[29..];
+ monkey.tester.if_true = try fmt.parseUnsigned(u64, if_true_str, 10);
+
+ const if_false_str = lines.next().?[30..];
+ monkey.tester.if_false = try fmt.parseUnsigned(u64, if_false_str, 10);
+
+ return monkey;
+ }
+
+ pub fn deinit(self: *Monkey) void {
+ self.items.deinit();
+ }
+
+ pub fn compare(_: void, lhs: Monkey, rhs: Monkey) bool {
+ return lhs.business > rhs.business;
+ }
+};
+
+const Operation = struct {
+ kind: enum { add, mul, pow },
+ value: u64,
+
+ pub fn parse(str: []const u8) !Operation {
+ if (mem.eql(u8, str[2..], "old")) {
+ return .{ .kind = .pow, .value = 1 };
+ }
+ const value = try fmt.parseUnsigned(u64, str[2..], 10);
+ return switch (str[0]) {
+ '+' => Operation{ .kind = .add, .value = value },
+ '*' => Operation{ .kind = .mul, .value = value },
+ else => unreachable,
+ };
+ }
+
+ pub fn apply(self: Operation, value: u64) !u64 {
+ return switch (self.kind) {
+ .add => value + self.value,
+ .mul => value * self.value,
+ .pow => value * value,
+ };
+ }
+};
+
+const Tester = struct {
+ divisor: u64,
+ if_true: u64,
+ if_false: u64,
+
+ pub fn apply(self: Tester, value: u64) !u64 {
+ return if (value % self.divisor == 0) self.if_true else self.if_false;
+ }
+};
+
+const Fight = struct {
+ alloc: mem.Allocator,
+ monkeys: []Monkey,
+ divider: u64,
+
+ pub fn parse(alloc: mem.Allocator, str: []const u8) !Fight {
+ var monkeys = try alloc.alloc(Monkey, 8);
+
+ var blocks = mem.split(u8, str, "\n\n");
+ for (monkeys) |*monkey| {
+ const block = blocks.next().?;
+ monkey.* = try Monkey.parse(alloc, block);
+ }
+
+ return Fight{
+ .alloc = alloc,
+ .monkeys = monkeys,
+ .divider = 1,
+ };
+ }
+
+ pub fn deinit(self: *Fight) void {
+ for (self.monkeys) |*monkey| {
+ monkey.deinit();
+ }
+ self.alloc.free(self.monkeys);
+ }
+
+ pub fn fight(self: *Fight, count: u64) !void {
+ var moved = std.ArrayList(u64).init(self.alloc);
+ defer moved.deinit();
+
+ var wrap: u64 = 1;
+ for (self.monkeys) |monkey| {
+ wrap *= monkey.tester.divisor;
+ }
+
+ var round: u64 = 0;
+ while (round < count) : (round += 1) {
+ for (self.monkeys) |*monkey| {
+ monkey.business += monkey.items.items.len;
+ for (monkey.items.items) |*item, i| {
+ item.* = try monkey.operation.apply(item.*);
+ item.* /= self.divider;
+ item.* %= wrap;
+
+ var index = try monkey.tester.apply(item.*);
+ try moved.append(i);
+ try self.monkeys[index].items.append(item.*);
+ }
+ for (moved.items) |index, i| {
+ _ = monkey.items.orderedRemove(index - i);
+ }
+ moved.clearRetainingCapacity();
+ }
+ }
+ }
+};
+
+pub fn main() !void {
+ const stdout = io.getStdOut().writer();
+
+ var gpa: heap.GeneralPurposeAllocator(.{}) = .{};
+ defer _ = gpa.deinit();
+ const alloc = gpa.allocator();
+
+ var args = process.args();
+ _ = args.next();
+ const filename = args.next() orelse @panic("error: missing input arg.");
+
+ var buffer: [2048]u8 = undefined;
+ const content = try fs.cwd().readFile(filename, &buffer);
+
+ var fight1 = try Fight.parse(alloc, content);
+ defer fight1.deinit();
+ fight1.divider = 3;
+ try fight1.fight(20);
+
+ sort.sort(Monkey, fight1.monkeys, {}, Monkey.compare);
+ const business1 = fight1.monkeys[0].business * fight1.monkeys[1].business;
+ try stdout.print("result 1: {d}\n", .{business1});
+
+ var fight2 = try Fight.parse(alloc, content);
+ defer fight2.deinit();
+ try fight2.fight(10000);
+
+ sort.sort(Monkey, fight2.monkeys, {}, Monkey.compare);
+ const business2 = fight2.monkeys[0].business * fight2.monkeys[1].business;
+ try stdout.print("result 2: {d}\n", .{business2});
+}
@@ 53,6 53,7 @@ pub fn build(builder: *Builder) !void {
.{ .year = "2022", .day = "08" },
.{ .year = "2022", .day = "09" },
.{ .year = "2022", .day = "10" },
+ .{ .year = "2022", .day = "11" },
};
for (problems) |*problem| {