~andreafeletto/advent

4d3f031ca331b3e1720ecac13d58f37b61c9480a — Andrea Feletto 1 year, 9 months ago fed74ca
year 2022 day 11
3 files changed, 235 insertions(+), 0 deletions(-)

A 2022/11/input
A 2022/11/solve.zig
M build.zig
A 2022/11/input => 2022/11/input +55 -0
@@ 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

A 2022/11/solve.zig => 2022/11/solve.zig +179 -0
@@ 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});
}

M build.zig => build.zig +1 -0
@@ 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| {