Unable to load image

ADVENT OF CODE DAY 11: MONKEY BUSINESS :marseymonke:

Those FRICKING monkeys stole your stuff! Get it back! :soycry: :!marseymonke:

(Also, remember to leave a comment if you did something interesting :marseylove:)

35
Jump in the discussion.

No email address required.

Going great for me...

![](/images/16707536920945232.webp)

Jump in the discussion.

No email address required.

there's only * and + tho

Jump in the discussion.

No email address required.

yes eventually i figured that one out

Jump in the discussion.

No email address required.

    monkeys = []
    @dataclass
    class Monkey:
        items : List[int] = dataclass_field(default_factory=list)
        operation = None
        test = 0
        test_true = 0
        test_false= 0
        inspected = 0

    def consume(s, prefix):
        assert s.startswith(prefix)
        return s[len(prefix):]

    for s in data:
        op, args = s.split(':')
        # print(f'{op!r}: {args!r}')
        if op.startswith('Monkey'):
            assert not args
            _, arg = op.split()
            assert int(arg) == len(monkeys)
            monke = Monkey()
            monkeys.append(monke)
        elif op == 'Starting items':
            monke.items = [int(s.strip()) for s in args.split(',')]
        elif op == 'Operation':
            args = consume(args, ' new = old ')
            op = args[0]
            assert op in '*+'
            arg = args[1:].strip()
            if arg != 'old':
                arg = int(arg)
            if op == '+':
                monke.operation = lambda x, arg=arg: x + (x if arg == 'old' else arg)
            else:
                monke.operation = lambda x, arg=arg: x * (x if arg == 'old' else arg)
        elif op == 'Test':
            args = consume(args, ' divisible by ')
            monke.test = int(args)
        elif op == 'If true':
            args = consume(args, ' throw to monkey ')
            monke.test_true = int(args)
        elif op == 'If false':
            args = consume(args, ' throw to monkey ')
            monke.test_false = int(args)
        else:
            assert False

    # pprint(monkeys)

    modulo = functools.reduce(operator.mul, [m.test for m in monkeys], 1)

    for round in range(10_000 if second else 20):
        for i, m in enumerate(monkeys):
            # print(f'Monke {i}')
            items = m.items
            m.items = []
            for it in items:
                m.inspected += 1
                # print(f'inspect {it}')
                it = m.operation(it)
                # print(f'worry to {it}')
                if not second:
                    it //= 3
                it %= modulo
                # print(f'worry to {it}')
                target = m.test_false if it % m.test else m.test_true
                # print(f'target {target}')
                monkeys[target].items.append(it)
        # pprint(monkeys)

    top = [-m.inspected for m in monkeys]
    heapify(top)
    a, b = heappop(top), heappop(top)
    return a * b
Jump in the discussion.

No email address required.

 top = [-m.inspected for m in monkeys]
     heapify(top)
     a, b = heappop(top), heappop(top)
     return a * b

@JollyMoon look at this shit, me being O(n) instead of sorting the whole array!

Jump in the discussion.

No email address required.

heap creation is O(n logn) tho

Jump in the discussion.

No email address required.

Are you feeling okay bud?

Jump in the discussion.

No email address required.

Did anyone get it to loop through state space correctly? I tried for a few hours but couldn't get it :marseyraging:

Jump in the discussion.

No email address required.

Not that bad today. Took me an embarrassingly long time to realize I needed to reduce worry levels on part 2 though

Jump in the discussion.

No email address required.

That second half took me longer than I would've liked... I understood the problem but I was trying to do crazy stuff with prime factors which were way off-track. Also hard-coded the inputs because fuck that noise.

monke = [[85, 77, 77], [80, 99], [74, 60, 74, 63, 86, 92, 80], [71, 58, 93, 65, 80, 68, 54, 71], [97, 56, 79, 65, 58], [77], [99, 90, 84, 50], [50, 66, 61, 92, 64, 78]]
count = [0,0,0,0,0,0,0,0]

def take_turn(i, n):
    div_check = [[19, 6, 7], [3, 3, 5], [13, 0, 6], [7, 2, 4], [5, 2, 0], [11, 4, 3], [17, 7, 1], [2, 5, 1]]
    vals = [n*7, n*11, n+8, n+7, n+5, n+4, n*n, n+3]
    val = vals[i]
    if val%div_check[i][0] == 0:
        return div_check[i][1], val%(2*3*5*7*11*13*17*19)
    else:
        return div_check[i][2], val%(2*3*5*7*11*13*17*19)

for n in range(10000):
    for m in range(len(monke)):
        for i in range(len(monke[m])):
            count[m] += 1
            item = monke[m][0]
            monke[m] = monke[m][1:]
            new_monke, new_val = take_turn(m, item)
            monke[new_monke] = [new_val] + monke[new_monke]
count.sort()
print(count[-1]*count[-2])
Jump in the discussion.

No email address required.

The puzzle in Part 2 was a homework problem when I was in college. Not with the monkeys, just the part where you need to use a ring with the product of prime numbers as a modulus to determine divisibility.

Unfortunately college was more than 20 years ago so it took me a long fricking time to remember that.

Jump in the discussion.

No email address required.

Yeah, fricked up part b. Even though I was quick in trying modulo but i have embarrassingly added all the divisors instead of multiplying them. It took me 30 min for finding that out :marseyspecial:

Jump in the discussion.

No email address required.

let pop = s => {
  if (s === 'old * old')return a=>a*a
  let q = /^old \* (\d*)$/.exec(s); if (q) return a=>a*(+q[1])
  q = /^old \+ (\d*)$/.exec(s); if (q) return a=>a+(+q[1])
}
let p2 = true
let s = fs.readFileSync('/tmp/input','utf8').split('\n\n').map(a=>/Monkey .*:\n *Starting items: (?<items>.*)\n *Operation: new = (?<op>.*)\n *Test: divisible by (?<div>.*)\n *If true: throw to monkey (?<true>.*)\n *If false: throw to monkey (?<false>.*)/.exec(a).groups).map(a=>({...a, items: a.items.split(', ').map(a=>+a), op: pop(a.op), act: 0}))
let modulo = s.map(a=>a.div).reduce((a,b)=>a*b)
for (let x = 0; x < (p2 ? 10000 : 20); x++)
for (let m of s) {
  for (let i of m.items) {
    m.act++
    i = m.op(i)
    if (!p2) i = floor(i/3)
    else i %= modulo
    s[i%m.div === 0 ? m.true : m.false].items.push(i)
  }
  m.items = []
}

let q = s.map(a=>a.act).sort((a,b)=>a-b)
let out = q.at(-1)*q.at(-2)

the above has two main sources of bloat: writing out the parser instead of just doing 'eval("old => " + op)' bc eval BAD and actually parsing with a big regex instead of just a.split('\n')[3].slice(5) or whatever

why do they need to create retarded narratives? it's just a 'throwing numbers around in a datastructure problem' that has nothing to do with monkeys. they've all been very boring so far, hopefully it'll get better.

Jump in the discussion.

No email address required.

This is just a dumb brute force solution that's been written out in the most boring way possible. It's not even close to the best solution and it's just a waste of time.

Jump in the discussion.

No email address required.

hey @bbbb what's the big(O) of @ejrqiowae89q8h9 's solution?

Jump in the discussion.

No email address required.

Hey you, what's the big deal with your solution? It's O(1), which is obviously not as good as my solution.

Jump in the discussion.

No email address required.

darn @bbbb has got solutions faster than O(1)?!

Jump in the discussion.

No email address required.

Yeah, well I'm not fricking O(1), so get used to it.

Jump in the discussion.

No email address required.

who r u fricking @bbbb?

Jump in the discussion.

No email address required.

I'm fricking you, you fricking idiot.

Jump in the discussion.

No email address required.

darn really? shit i almost forgot. don't worry, i'll hit u back later @bbbb

Jump in the discussion.

No email address required.

More comments

That was a mistake. You're about to find out the hard way why.

Jump in the discussion.

No email address required.

Got stuck on part 2 because of big numbers and had to get help :marseygiveup:

Added gcd after getting help

with open('./input11.txt') as infile:
    text = infile.read()

class Monkey:
    def __init__(self, op, test:int, true:int, false:int) -> None:
        self.op = op
        self.test = test
        self.true = true
        self.false = false
        self.items = []
        self.items_checked = 0

    def inspect(self):
        for item in self.items:
            self.items_checked += 1
            item = self.op(item)
            item = item % gcd
            if item % self.test == 0:
                monkeys[self.true].items.append(item)
            else:
                monkeys[self.false].items.append(item)
        self.items = []

monkeys = []

def parse_op(op):
    _, out = map(str.strip, op.split('='))
    func  = "lambda old:" + out
    return eval(func)

gcd = 1

for m in text.split('\n\n'):
    _, items, op, test, true, false = m.splitlines()
    op = parse_op(op)
    test = int(test.split()[-1])
    true = int(true.split()[-1])
    false = int(false.split()[-1])
    monkey = Monkey(op, test, true, false)
    _, items = items.split(':')
    items = map(int, items.strip().split(', '))
    monkey.items.extend(items)
    monkeys.append(monkey)
    gcd *= test

for i in range(10000):
    for m in monkeys:
        m.inspect()

a , b = sorted([m.items_checked for m in monkeys])[-2:]
print(a*b)
Jump in the discussion.

No email address required.

>"huh this is taking a long time"

>throw in a random modulo that just feels right

>it werks

:#taysilly: :#marseypartyxmas: :#!taysilly:

Jump in the discussion.

No email address required.

Yes i needed to include an external library to split a string in c++ :gigachad2: and no dont ask me why i decided to make things into pointers or i have struct that only stores one value.

Also at first i assume that all throws needed to happen at the same time. So if Monkey 1 throws to Monkey 3, Monkey 3 will not throw that item in the same round again. This was not the case, and Monkey 3 would immediately keep throwing it further in the next throw.

#include <vector>
#include <memory>
#include <fstream>
#include <string>
#include <queue>
#include <scn/scn.h>
#include <fmt/core.h>
#include <boost/algorithm/string.hpp>

struct Operation {
    char operand;
    std::string rhs;
    int32_t rhs_int{ -1 };
};

struct Item {
public:
    int64_t worry;
};

class Monkey {
public:
    int32_t id;
    int32_t divisible_test;
    int32_t items_seen{ 0 };

    std::pair<int32_t, int32_t> next_monkeys;
    std::vector<std::unique_ptr<Item>> items;

    Operation op;

    int64_t do_operation(int64_t worry) {
        int64_t rhs{ 0 };
        if (op.rhs == "old") rhs = worry;
        else {
            if (op.rhs_int < 0) {
                op.rhs_int = std::stoi(op.rhs);
            }
            rhs = op.rhs_int;
        }

        if (op.operand == '*') return worry * rhs;
        if (op.operand == '+') return worry + rhs;
        if (op.operand == '-') return worry - rhs;
        return worry / rhs;
    }

    void simulate_throw(const std::vector<std::unique_ptr<Monkey>>& storage, int32_t mod, int32_t division = 3) {
        for (auto it = items.begin(); it != items.end();) {
            int32_t move_to{ next_monkeys.second };
            this->items_seen++;

            int64_t worry{ do_operation((*it)->worry) };

            if (mod == 1) (*it)->worry = worry / division;
            else (*it)->worry = worry % mod;

            if ((*it)->worry % this->divisible_test == 0) {
                move_to = next_monkeys.first;
            }  

            storage[move_to]->items.push_back(std::move(*it));
            it = items.erase(it);
        }
    }
};

auto load_monkeys()
{
    std::vector<std::unique_ptr<Monkey>> monkey_storage;

    std::ifstream file("input.txt");
    std::string line;

    while (std::getline(file, line)) {
        monkey_storage.push_back(std::make_unique<Monkey>());
        scn::scan(line, "Monkey {}:", monkey_storage.back()->id);
        std::getline(file, line, ':'); // skip until : in Operation: {}, ...
        std::getline(file, line);

        std::vector<std::string> results;
        boost::split(results, line, boost::is_any_of(","));
        for (auto item : results) {
            monkey_storage.back()->items.push_back(std::make_unique<Item>(std::stoi(item)));
        }

        std::getline(file, line);
        scn::scan(line, "  Operation: new = old {} {}", monkey_storage.back()->op.operand, monkey_storage.back()->op.rhs);

        std::getline(file, line);
        scn::scan(line, "  Test: divisible by {}", monkey_storage.back()->divisible_test);

        std::getline(file, line);
        scn::scan(line, "    If true: throw to monkey {}", monkey_storage.back()->next_monkeys.first);

        std::getline(file, line);
        scn::scan(line, "    If false: throw to monkey {}", monkey_storage.back()->next_monkeys.second);

        std::getline(file, line);
    }
    return monkey_storage;
}

std::string run(bool partTwo) {
    auto monkey_storage = load_monkeys();

    int32_t mod{ 1 };
    int32_t runs{ 20 };

    if (partTwo) {
        runs = 10'000;
        for (const auto& monkey : monkey_storage) {
            mod *= monkey->divisible_test;
        }
    } else runs = 20;

    for (int32_t i = { 0 }; i < runs; i++) {
        for (const auto& monkey : monkey_storage) {
            monkey->simulate_throw(monkey_storage, mod);
        }
    }
    std::vector<int64_t> monkey_seen;
    for (const auto& monkey : monkey_storage) {
        monkey_seen.push_back(monkey.get()->items_seen);
    }
    std::sort(monkey_seen.begin(), monkey_seen.end(), std::greater<int64_t>());

    return fmt::format("{}", monkey_seen[0] * monkey_seen[1]);
}

int main() {
    fmt::print("Part One: {}\n", run(false));
    fmt::print("Part Two: {}\n", run(true));
}


Jump in the discussion.

No email address required.

es i needed to include an external library to split a string in c++

lmao I just used std::regex :marseysick: (yeah I know) another way would be to use size_t pos; std::stoull(line.substr(18, &pos)) and then recall substr and stoull from position pos + 1 until you're left with an empty substring

https://en.cppreference.com/w/cpp/string/basic_string/stoul

If pos is not a null pointer, then a pointer ptr, internal to the conversion functions, will receive the address of the first unconverted character in str.c_str(), and the index of that character will be calculated and stored in *pos, giving the number of characters that were processed by the conversion.

Jump in the discussion.

No email address required.

it = items.erase(it);

Actually found a way to optimize this. erase on a vector is slow because it had to rearrange the entire vector, but since we know that a monkey will throw all items, the vector will be empty at the end and we can just reset it with clear.

With that optimization 70% of the cpu time is spent on doing modulo operations

![](/images/1670768188503464.webp)

Jump in the discussion.

No email address required.

Wow, you must be a JP fan.

Jump in the discussion.

No email address required.

me vs snakes vs @everyone

logarithmic scales, each point is the average of three measurements, figures in milliseconds

:#marseydance:

C++chads simply cannot stop winning @drama_enthusiast discuss

![](/images/1670755872127088.webp)

![](/images/16707559142307742.webp)

Jump in the discussion.

No email address required.

aight fruitcake, ready for your :marseyl:

plot these assemblyscript stats:

10 100 1000100001000005000001000000
112985429861
0121086423848
1111085423871

let lsd: i64 = 1;

class Monkey {
  items: Array<i64>;
  n: i64;

  op1: i64;
  op2: i64;
  opAdd: boolean;

  d: i32;
  tM: i32;
  fM: i32;

  constructor (lines: String) {
    const l = lines.split('\n');
    
    this.items = l[1]
      .split(':')[1]
      .split(', ')
      .map((s: string) => i64.parse(s));
    
    const opStr = l[2].split('=')[1].trim() || '';
    const m = opStr.split(' ');
    this.op1 = m[0] === 'old' ? 0 : i64.parse(m[0])||0;
    this.op2 = m[2] === 'old' ? 0 : i64.parse(m[2])||0;
    this.opAdd = m[1] === '+';
    
    this.d = i32.parse(l[3].trim().split(' ')[3]);
    if (lsd % this.d) lsd *= this.d;
    this.tM = i32.parse(l[4].trim().split(' ')[5]);
    this.fM = i32.parse(l[5].trim().split(' ')[5]);
    
    this.n = 0;
  }

  op (old: i64): i64 {
    return this.opAdd ?
        (this.op1 || old) + (this.op2 || old)
      : (this.op1 || old) * (this.op2 || old)
  }

  test (w: i64): i32 {
    return (w % this.d) ? this.fM : this.tM;
  }
}

const monkeys: Array<Monkey> = [];

export function run(input: string, itr: i32): void {
  input.split('\n\n').forEach((lines) => {
    monkeys.push(new Monkey(lines));
  });

  for (let i = 0; i < itr; i++) {
    monkeys.forEach(monk => {
      while (monk.items.length) {
        let w = monk.items.pop()
        const newW = (monk.op(w)%lsd);
        const newM = monk.test(newW);
        monk.n++;
        monkeys[newM].items.push(newW);
      }
    });
  };

  console.log(
    monkeys.map((m:Monkey) => m.n)
      .sort((a,b) => i32(b-a))
      .slice(0,2)
      .reduce((p, n) => p * n, i64(1))
      .toString()
    );
}

here's the calling ts code:

import * as fs from 'fs';
import {run} from '../build/release.js'

const start = Date.now();
const input = fs.readFileSync(process.argv[2], 'utf-8')
run(input, Number(process.argv[3]));
console.log((Date.now() - start));

and the compiled code's actually portable too, u can run it in a web browser.

god i miss closures tho ... not that u'd know what those r ...

Jump in the discussion.

No email address required.

taking double digit millisecond for 10.000 throws :marseysmug2:

![](/images/1670793727086256.webp)

Those are average over 3 runs

Jump in the discussion.

No email address required.

if i hardcode the LCM mod number, it is even faster, the compiler then can actually try to optimize it.

![](/images/16707940227049947.webp)

here is the final code if anyone cares: https://pastebin.com/hxuNpb0v

Jump in the discussion.

No email address required.

couldn't make it that much faster. tried my own push/pop with static arrays, inlined lcd, inlined all my functions, removed error case branching, swapping forEach for whiles, and got the 1M time down to ~700ms.

almost within spitting distance, but i might be running up against a vm tax here.

you running on anything fancy?

Jump in the discussion.

No email address required.

>you running on anything fancy?

no just an old ryzen 5 2600, that boost to like 3.9GHz

Is there a profiler for this kind of code? The visual studio profiler helped a lot in finding the exact lines of codes that take a while to run.

Jump in the discussion.

No email address required.

probably. there are both rust and cpp front ends to wasm, and both have profilers ... but i choose assemblyscript cause i'm a filthy web app programmer, and i dunno about anything easy to plug and play with that. since when do web programmers care about optimization?

but alas ... today's a work day, i have too much non-programming bs to deal with for fun stuff like micro-optimizing code. who gives a shit about that when ur at a multibillion dollar company?

Jump in the discussion.

No email address required.

huh, hardcoding lcd didn't seem to affect my runtime.

but i'm pretty tired maybe i'll take another look at it when it get up.

did i mention my code is actually portable?

Jump in the discussion.

No email address required.

cpu? I ran my benchmark on a 5800X with conservative as frequency governor. Also I'm benchmarking the whole process' time, not only console.log((Date.now() - start)); kinda unfair

Jump in the discussion.

No email address required.

Also I'm benchmarking the whole process' time, not only console.log((Date.now() - start)); kinda unfair

lol, ok there snowflake. i ran the calling code as js instead of ts and timed the process with the shell time built in.

my 1mil count stats are between 890-910ms. not a big diff. if u want to go add 50ms to all the stats, that's fine. maybe i could find a way to run the wasm directly, and shave that, but i care not.

Jump in the discussion.

No email address required.

apple m1 max, just stock. not plugged in, but that prolly didn't matter.

this is using release build, so max compiler optimizations i think. idk, i never used assemblyscript or webassembly before this ... i just installed and darn i'm impressed.

data structure awareness helps. going from a shift() to pop() on my item processing saw 30% reduction in my 1mil count runtime.

Jump in the discussion.

No email address required.

All them words won't bring your pa back.

Jump in the discussion.

No email address required.

Nice work king but,

  • replace std::list with a higher performance datastructure

  • Replace obsolete types for example: long long vs int64_t

  • split that biggest line and make it more readable

  • use avx-512 instructions to further humilate the competition :marseytrollgun:

Jump in the discussion.

No email address required.

i forgot that i was mutating the input for part 2 and was wondering where i was fucking up for a good hour and change. i also shamelessly stole the old = monkey[0] % maximum because 4096+ digit ints dont really chooch u_u

![](/images/1670755023233026.webp)

Jump in the discussion.

No email address required.

IT DOESN'T WORK FOR PART B

:#marseytrollcrazy::#marseytrollcrazy::#marseytrollcrazy:

ANY IDEA WHYYYYY

I AM GOING INSANE AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

:#marseytrollgun::#marseytrollgun::#marseytrollgun:

SNAKES DISCUSS

![](/images/16707486870484462.webp)


k it wasn't that difficult I just had to re-think about discrete math n shit

![](/images/16707499620766914.webp)

Jump in the discussion.

No email address required.

You'll need to find another way to keep your worry levels manageable.

:#marseyhmm: :#marseybug2:

Jump in the discussion.

No email address required.

Yeah I just used amd64's 1024bits register extensions

:#gigachad3::#marseyantischizo:

Jump in the discussion.

No email address required.

mathcels seething rn :marseynerd:

Jump in the discussion.

No email address required.

Unfortunately, that relief was all that was keeping your worry :marseyveryworriedfed: levels from reaching ridiculous levels. You'll need to find another way to keep :marseykys2: your worry :marseyveryworried: levels manageable.

At this :marseysharksoup: rate, you might be putting up with these monkeys for a very long :marseylongsurfing: time :marseywait: - possibly 10000 rounds!

Jump in the discussion.

No email address required.

I knew it! All I need were 2048bits registers!

Jump in the discussion.

No email address required.

hey bro one of your comments say "Money ID" instead of "Monkey ID" please fix kthx

Hint : check overflows

Jump in the discussion.

No email address required.

zoz

Jump in the discussion.

No email address required.

zle

Jump in the discussion.

No email address required.

zozzle

Jump in the discussion.

No email address required.

my first time getting zozzed

:#marseyhappening::#taddance::#marseyhappening:

Jump in the discussion.

No email address required.

sentient

Jump in the discussion.

No email address required.

Tidied up version. Not all that different from my live solve, aside from switching to eval for the Monkey Operations because it's funnier to use eval, despite it being noticeably slower.

![](/images/16707481594352322.webp)

Jump in the discussion.

No email address required.

you can take out the eval to make it faster, because here it will call it everytime you call the lambda function instead of only doing the eval once for each function

Jump in the discussion.

No email address required.

import * as fs from 'fs'
const monkeys: {
  items: number[],
  op: (old: number) => number,
  test: (num: number) => number,
  n: number,
}[] = [];
let lsd = 1;
fs.readFileSync(process.argv[2], 'utf-8').split('\n\n').forEach((ls) => {
  const l = ls.split('\n');
  const opStr = l[2].split('=')[1] || '';
  const d = Number(l[3].match(/\d+/)?.[0]) || 0;
  if (lsd % d) lsd *= d;
  const tM =  Number(l[4].match(/\d+/)?.[0]) || 0;
  const fM = Number(l[5].match(/\d+/)?.[0]) || 0;
  monkeys.push({
    items: l[1].match(/\d+/g)?.map(Number) || [],
    op: (old: number) => Number(eval(opStr.replace(/old/g, String(old)))),
    test: (num: number) => (num % d) ? fM : tM,
    n: 0,
  });
});
const round = () => monkeys.forEach(monk => {
  const items = monk.items;
  monk.items = [];
  items.forEach(w => {
    const newW = monk.op(w) % lsd;
    const newM = monk.test(newW);
    monk.n++;
    monkeys[newM].items.push(newW);
  })
});
for (let i = 0; i < 10000; i++) round();
console.log(monkeys.sort((m1, m2) => m2.n-m1.n).slice(0,2).reduce((p, m) => p * m.n, 1));
Jump in the discussion.

No email address required.

Sorry I haven't been able to keep up with it for the past three days. I have been sleeping a lot from the semester ending and stuff. Will probably catch up later :marseyill:

Jump in the discussion.

No email address required.

butt : washed

did most of the obvious optimizations (thanks profiler) so it's down to 3.5 seconds of runtime

No, I will not use something other than a bajillion cell arrays

![](/images/16707454283486094.webp)

Jump in the discussion.

No email address required.

wat? my js runs in < 0.7.s for the full 10,000 cycles, and that's just how i wrote it ... wtf r u doing even?

Jump in the discussion.

No email address required.

It's probably just matlab jank, and maybe a poor choice of data structure since I'm not sure what are the fastest ones to use.

I'm not a programmer, just a scripter (for physics) so I just keep using high level languages (Matlab, python and some embedded C) because I don't want to bother with low level shit when I don't need it.

Jump in the discussion.

No email address required.

yeah low shit sucks, but js is about as far from low level as u can get.

but i'm surprised u wouldn't want to be experienced in basic algorithmic runtime complexity cause if ur doing simulations, that's going to determine speed of the simulation.

Jump in the discussion.

No email address required.

I do have some experience in complexity, it's just that I can't exactly do anything when the language just mostly sucks butt in pure speed, or I don't have the specific knowledge to optimize it. We only ever got into coding either very formally with the math behind complexity and proofs, or very liberally with what's basically the bare minimum to put the language on your CV.

We have no "real" CS class so I just gradually learn what is usually the fastest shit to use when I find info on it. Like a few months back I saw that the string to int conversions were horribly slow in matlab and tried shit until I stumbled upon remnants of C with sscanf, which does the job infinitely faster, and now I can't do without it.

Jump in the discussion.

No email address required.

anyone who wants nice :marseyfingergoodjob: data :marseychartgaussian: prep code... lol no

from y2022.scaffold import *

class Day11(Day):
	def __init__(self):
		super()
	
	@property
	def day(self): return :marseymonke: 11

	def prepare_data(self) -> Any:
		data = self.get_data().split('\n\n')
		#data = open('y2022/day11test.txt').read().split('\n\n')
		data2 = []
		for i in range(len(data)):
			key = i
			monkey_raw = data[i]
			monkey_raw2 = data[i].splitlines()
			monkey2 = SimpleNamespace()
			monkey2.number = key
			for j in range(len(monkey_raw2)):
				#print(monkey_raw[j])
				#if i > 7: continue
				if j == 1:
					if i == 0: monkey2.items = [59, 74, 65, 86]
					if i == 1: monkey2.items = [62, 84, 72, 91, 68, 78, 51]
					if i == 2: monkey2.items = [78, 84, 96]
					if i == 3: monkey2.items = [97, 86]
					if i == 4: monkey2.items = [50]
					if i == 5: monkey2.items = [73, 65, 69, 65, 51]
					if i == 6: monkey2.items = [69, 82, 97, 93, 82, 84, 58, 63]
					if i == 7: monkey2.items = [81, 78, 82, 76, 79, 80]
					
					'''### TEST :marseyitsrigged: ###
					if i == 0: monkey2.items = [79, 98]
					if i == 1: monkey2.items = [54, 65, 75, 74]
					if i == 2: monkey2.items = [79, 60, 97]
					if i == 3: monkey2.items = [74]
					### END TEST :marseyitsrigged: ###
					'''
					#if i > 7: raise :marseysuspicious: Exception("TOO MANY :marseymanysuchcases: MONKEYS!!!!!1")
					#idx_start = monkey_raw.find('s: ')
					#idx_end = monkey_raw.
					#items = monkey_raw.split(',')
					#items[0] = items[0].replace('Starting items:', '').strip()
					#monkey2.items = list(map(lambda x:int(x), items))
				elif j == 2:
					#print(monkey_raw2[j])
					idk_anymore = monkey_raw2[j].replace('  Operation: new = old ', '')
					monkey2.op = 'o' if 'old' in idk_anymore else idk_anymore[0]
					idk_anymore = idk_anymore[2:].strip()
					monkey2.operand = int(idk_anymore) if not 'ld' in idk_anymore else 111111111
					#r = search('Operation: new = old {} {:g}', monkey_raw, evaluate_result=True)
					#if not r: raise :marseysuspicious: Exception("COULD NOT PARASES DAHFADGAHGFSG")
					#monkey2.op, monkey2.operand = r[0], r[1]
				elif j == 3:
					r = search('Test: divisible by {:g}{:g}', monkey_raw, evaluate_result=True)
					if r:
						r = r = (int(r[0]) * 10) + int(r[1])
					else:
						r = search('Test: divisible by {:g}', monkey_raw, evaluate_result=True)
					if not r: raise :marseysuspicious: Exception('parse 2')
					monkey2.divisible = int(r[0] if not isinstance(r, int) else r)
				elif j == 4:
					r = search('If true: throw :marseypuke: to monkey :marseybrasileiro: {:g}', monkey_raw, evaluate_result=True)
					if not r: raise :marseysuspicious: Exception('parse 3')
					monkey2.throw_if_true = int(r[0])
				elif j == 5:
					r = search('If false: throw :marseypuke: to monkey :marseybigfoot: {:g}', monkey_raw, evaluate_result=True)
					if not r: raise :marseysuspicious: Exception('parse 4')
					monkey2.throw_if_false = int(r[0])
			monkey2.inspected = 0
			data2.append(monkey2)
		return data2

	def a(self):
		return
		monkeys = self.prepare_data()
		# level of monkey :marseybigfoot: business after 20 rounds
		SIMULATION_ROUNDS = 20
		TOP_FOCUS = 2
		# multiply the top two together
		for round_no in range(SIMULATION_ROUNDS):
			debug = True
			for monkey :marseysopa: in monkeys:
				while monkey.items:
					#if debug:
					#	print(monkey)
					value = int(monkey.items[0])
					old_value = int(monkey.items[0])
					try: operand = int(monkey.operand)
					except: operand = value
					#if debug: repl(locals())
					#print(monkey)
					if monkey.op == '+': value += operand
					elif monkey.op == '*': value *= operand
					elif monkey.op == 'o': value **= 2
					else: raise :marseysuspicious: Exception(f'Unknown operation type {monkey.op}!')

					if debug:
						pass
						#print_filtered_locals(locals())
						#print(f"{old_value} {monkey.op} {operand} = {value}")
						#debug = False

					monkey.inspected += 1
					value //= 3

					if value % monkey.divisible == 0:
						monkeys[monkey.throw_if_true].items.append(value)
					else:
						#print(monkey)
						#print(monkey.throw_if_false)
						#print(monkeys[5])
						monkeys[monkey.throw_if_false].items.append(value)
					del monkey.items[0]

					if debug:
						#continue
						#print(monkey)
						#print(monkeys[3])
						#print("---")
						debug = False
				#print("--------- SIMUL ROUND ----------")
		# 59760 is too low, 63000 is not right :marseyhesright: agbhdsjfsf
		#s = list(monkeys)
		s = list(sorted(monkeys, key=lambda m:m.inspected, reverse=True))
		for item in s[:2]:
			print(item)
	
	def b(self):
		monkeys = self.prepare_data()
		SIMULATION_ROUNDS = 10000
		max2 = 1
		for monkey :marseysopa: in monkeys:
			max2 *= monkey.divisible
		for round_no in range(SIMULATION_ROUNDS):
			if round_no % 2500 == 0: print(f"SIMULATION ROUND {round_no}")
			for monkey :marseybigfoot: in monkeys:
				while monkey.items:
					value = int(monkey.items[0])
					try: operand = int(monkey.operand)
					except: operand = value

					if monkey.op == '+': value += operand
					elif monkey.op == '*': value *= operand
					elif monkey.op == 'o': value *= value# % max2

					#value //= 100000000000
					value %= max2
					#value %= monkey.divisible

					monkey.inspected += 1

					if value % monkey.divisible % monkey.divisible == 0:
						monkeys[monkey.throw_if_true].items.append(value)
					else:
						monkeys[monkey.throw_if_false].items.append(value)# % monkey.divisible)
					del monkey.items[0]
		s = list(map(lambda m:m.inspected, sorted(monkeys, key=lambda m:m.inspected, reverse=True)))
		for item in s[:2]:
			print(item)
		## TOO LOW  8100990030
		## NO HINT :marseywink: 14400239965
		## TOO LOW 14401560030
		## NO HINT :marseywink: 14400959980
		## NO HINT :marseywink: 19203834231 (139343/137817)
		## TOO HIGH :marseycocaine: 22037989580
		## TOO HIGH :marseyrick: 27846764496

no comments removed because fuck :marseyracistgrandpa: you

Jump in the discussion.

No email address required.

My favorite part is how monkey2 represents an arbitrary monkey in a loop and not actually monkey #2.

Jump in the discussion.

No email address required.

me too

Jump in the discussion.

No email address required.

Your pulitzer's in the mail

Jump in the discussion.

No email address required.

:marseydunkon:

Jump in the discussion.

No email address required.

When do we break the news about the bunkey?

Jump in the discussion.

No email address required.

:#marseymonke:

was part 2 supposed to take a while to calculate?

![](/images/167074125022877.webp)

Jump in the discussion.

No email address required.

it does for me

Jump in the discussion.

No email address required.

did*

Jump in the discussion.

No email address required.

Got a late start, fun problem

import numpy as np
def monkeyOp(num,x):
    if num == 0:
        return x*19
    elif num == 1:
        return x+1
    elif num == 2:
        return x+8
    elif num == 3:
        return x*x
    elif num == 4:
        return x+6
    elif num == 5:
        return x*17
    elif num == 6:
        return x+5
    elif num == 7:
        return x+3
def mOpTest(num,x):
    if num == 0:
        return x*19
    elif num == 1:
        return x+6
    elif num == 2:
        return x*x
    elif num == 3:
        return x+3
class Monkey:
    def __init__(self,string):
        lines = string.split('\n')
        self.monkeynum = int(lines[0].split(' ')[-1][:-1])
        self.items = [int(i) for i in lines[1].split(':')[-1].split(',')]
        self.test = int(lines[3].split(' ')[-1])
        self.ifTrue = int(lines[4].split(' ')[-1])
        self.ifFalse = int(lines[5].split(' ')[-1])
        self.inspecs = 0
    def test_result(self,num):
        if (num % self.test == 0):
            return self.ifTrue
        return self.ifFalse
    def doOp(self,x):
        return monkeyOp(self.monkeynum,x)
lcd = 7*2*19*3*13*11*5*17
f = open('AOC2022Day11.txt')
lines = f.read().strip().split('\n\n')
monkeys = [Monkey(s) for s in lines]
for _ in range(10000):
    for monkey in monkeys:
        for item in monkey.items:
            monkey.inspecs += 1
            level = monkey.doOp(item)
            #level = level //3
            level = level % lcd
            newM = monkey.test_result(level)
            monkeys[newM].items.append(level)
        monkey.items = []
lst = sorted([m.inspecs for m in monkeys])
print(lst)
print(lst[-1]*lst[-2])
Jump in the discussion.

No email address required.

>hardcoding

Jump in the discussion.

No email address required.

I didn't know about python's eval() function :marseycry:

Thankfully, hardcoding took like 2 min

Jump in the discussion.

No email address required.

Hardcoding sucks if you have bugs and want to switch between the provided example(s) and the actual problem.

Jump in the discussion.

No email address required.

don't worry too much, because eval mostly shouldn't be used, and it seems to be slow

idk if there's a way to do it without hardcoding but without using eval

Jump in the discussion.

No email address required.

oh boy its going to frick me in the butt with the parsing dildo again isn't it/?!

Jump in the discussion.

No email address required.

learn regex?

Jump in the discussion.

No email address required.

I did, but then I never used it and now I don't remember even 15% of it, just the basics. Anyway done. Thank frick for c# pattern matching

Jump in the discussion.

No email address required.

Nice post, bro! I posted it to twitter.

Jump in the discussion.

No email address required.

ADVENT OF PARSING

one-off error edition

![](/images/16707377685544004.webp)

Jump in the discussion.

No email address required.

and ANOTHER one on part 2, but this time it's not supposed to bug out since it's the same code (my 'puter can run it just fine on matlab, optimizing scrubs need not apply)

on round 20 of the example, I have a 2 diff compared to his

![](/images/16707391110296469.webp)

Jump in the discussion.

No email address required.

no I'm just r-slurred it was the point of the p2

Jump in the discussion.

No email address required.

It breaks when I try running it in python without the fix. The point is that the worry number will grow too large for the computer to deal with, but all the comparisons are the same if you choose the least common multiple of the tests.

Jump in the discussion.

No email address required.

yeah that was it, it's just that matlab somehow doesn't tell me it overflows

Jump in the discussion.

No email address required.

:#marseyxd:

Jump in the discussion.

No email address required.

Link copied to clipboard
Action successful!
Error, please refresh the page and try again.