--- Day 20: Decrypt ---

December 20

Listening to: PlayStation jungle mix


I made traditional eggnog today. It was good. But also very filled with booze. It was nice though.


This is a strange encryption algorithm that I'm not sure would work in the real world... but the elves are kinda strange, so maybe it makes sense to them.

A naieve approach would be to... hmm... maybe insert all of these values into a list of some sort, and instead of the raw values, I put in a pair, with the first being the initial index of the value. It would mean that I would have to iterate over the collection N^2 times, but I think, at least for an initial attempt, it would still run in enough time.

for (int i = 0; i < m.size(); i++)
{
    // Find element w/ current index
    int j;
    pair<int, int> elem;
    for (int k = 0; k < m.size(); k++)
        if (m[k].first == i) 
        {
            j = k;
            elem = m[k];
            break;
        }
    
    // Calculate it's new intended index
    int newIndex = (j + m[j].second);

    if (newIndex == 0) newIndex = m.size() - 1;
    if (newIndex > (int)m.size()) newIndex = newIndex - m.size() + 1;
    if (newIndex < 0) newIndex = m.size() + newIndex - 1;
    
    m.erase(m.begin()+j);
    m.emplace(m.begin()+newIndex, elem);
}

There may be a more efficient or elegant way of doing this. I know in python you can just have negative indexes and it automatically wraps around, that would have been very convienent. And oddly enough... this doesn't work.

Since it's circular... maybe I can try a linked list? A simple doubly-linked one, and one intentionally circular? I think the logic for figuring out indexes in the vector may be messing it up.

struct Node
{
    int value, order;
    Node *next, *last;
};

// ...

for (int i = 0; i < count; i++)
{
    // Find element for current index
    Node *cur = first;
    while (cur->order != i)
    {
        cur = cur->next;
    }

    if (cur->value > 0)
        for (int j = cur->value; j > 0; j--)
        {
            swap(cur->value, cur->next->value);
            swap(cur->order, cur->next->order);
            cur = cur->next;
        }

    else if (cur->value < 0)
        for (int j = cur->value; j < 0; j++)
        {
            swap(cur->value, cur->last->value);
            swap(cur->order, cur->last->order);
            cur = cur->last;
        }
}

It runs fairly quickly (nearly instantly), and more importantly, gives the right answer! I imagine my mistake before was an off-by-one somewhere. But by simply swapping in a circular list rather than trying to 'calculate' it, I just do the swaps, and it's all just easier.


Oh. Yeah. Sure. The elves can't just say "If something goes wrong, meet us back at this landmark", no, they have to have me memorize a random 9-digit number.

Also now the numbers are stupidly large. Fun.

At the very least this doesn't materially change things. The only think to keep in mind is that as a pretty easy shortcut, just modulo the value by the count of the list of numbers. Otherwise it's just billions of swaps per single mix.

int n = cur->value % (count-1);

The -1 is to account for the list without the piece itself. Or something something modulo calculus. I had eggnog, it made sense at the time.


Time taken: 2 hours 20 minutes

My solutions for today's puzzles