--- Day 21: Monkey Math ---

December 21

Listening to: City Girl - Neon Impasse


I worked today. It was supposed to be a day off, but I was so close to finishing my first task at my new job that I just wanted to finish it before the holiday break. Not going to lie, it felt good to be focused on a job after months of being variably employed.


This seems pretty simple. It's essentially a tree of operations.

I think I'm just going to make a simple map that corresponds to a monkey. If a monkey has incomplete information, it'll just go down the list looking for it.

struct Monkey {
    int64_t answer;
    char operation;
    string left, right;
};

int64_t GetMonkeyNumber(string name)
{
    Monkey m = bunch[name];
    if (m.answer != -1) return m.answer;

    int64_t l = GetMonkeyNumber(m.left);
    int64_t r = GetMonkeyNumber(m.right);

    int64_t result;
    switch(m.operation)
    {
        case '+': result = l + r; break;
        case '-': result = l - r; break;
        case '*': result = l * r; break;
        case '/': result = l / r; break;
    }

    return result;
}

The numbers got big, but that was pretty quick.


Okay, this is interesting now. Basically I have to determine equality, so one of the room monkey's callouts is known, and the other is unknown. I have to find the value of the 'human' monkey (er... myself? rude.) that makes it equal to the known.

Simple solution: Calculate non-human branch, then with the human branch, simply start from 0 and keep calculating until the right number is found. Problem: There's enough potentional answers that it takes a long time to figure out, even with optimizations.

Next solution: Work backwards. Since the known number is, well, known, I can start from that, and recursively go down the monkey paths, figuring out which one the human is in and isn't in, and perform the operation in reverse. And as an easy self-check, just replace the humn number with your result, test the root left and right are the same, and bam!

int64_t GetHumanNumber(string name, int64_t target)
{
    if (name == HUM_MONKEY) return target;

    Monkey m = bunch[name];
    string known = m.left;
    string unknown = m.right;
    bool swapped;
    if (HasHuman(m.left)) { swapped = true; swap(known, unknown); };
    
    int64_t pair = GetMonkeyNumber(known);
    int64_t newTarget;
    switch(m.operation)
    {
        case '+': newTarget = target - pair; break;
        case '-': newTarget = swapped ? target + pair : -1*(target - pair); break;
        case '*': newTarget = target / pair; break;
        case '/': newTarget = swapped ? target * pair : pair / target; break;
    }

    return GetHumanNumber(unknown, newTarget);
}

Time taken: 1 hour 20 minutes

My solutions for today's puzzles