--- Day 22: Cube ---

December 22

Listening to: lofi hip hop radio - beats to relax/study to


Here's a big push for me now. It's Christmas Eve for me today, and I'm hoping to finish the rest of Advent of Code by the end of tonight. Specifically, I'm hoping to be able to do the last puzzle when it comes out. It's a little before noon right now, so I have 9 hours to do what are likely 3 of the most difficult puzzles. But at least I'm doing this during the day, instead of very late at night when my brain is mush. Let's get to it!


This looks like an odd map traversal.... the map is oddly shaped. I think part 1 is kind of a fake out and part 2 is likely going to be traversing the same board but on the surface of the cube. The actual instructions don't seem difficult for part 1, but if I'm right, part 2 is going to be a headache of logic to deal with.

for (int j = 0; j < dist; j++)
{
    // Current row + direction + adjustment (for wrapping around the map)
    int r = ra == -1 ? row + dir[di][0] : ra;
    int c = ca == -1 ? col + dir[di][1] : ca;
    ra = -1; ca = -1;

    if (r >= (int)map.size()) r = 0;
    if (r < 0) r = map.size()-1;
    if (c >= (int)map[row].size()) c=  0;
    if (c < 0) c = map[r].size()-1;

    switch(map[r][c])
    {
        case '.': row = r; col = c; break;
        case '#': j = dist; break;
        case ' ': 
            if (dir[di][0] != 0)
            {
                ra = r;
                while (map[ra][c] == ' ')
                {
                    ra += dir[di][0];
                    if (ra < 0)           ra = map.size() - 1;
                    if (ra >= map.size()) ra = 0;
                }
            }
            else
            {        
                ca = c;                
                while (map[r][ca] == ' ')
                {
                    ca += dir[di][1];
                    if (ca < 0)              ca = map[r].size() - 1;
                    if (ca >= map[r].size()) ca = 0;
                }
            }
            j--;
            break;
    }
}

The only real difficult part of this was wrapping my head around wrapping around. I had to be extra careful to make sure the wrapping logic was in the correct directions. I had a lot of off-by-one issues, as well as (oddly enough) I kept running into the fact I was comparing a signed int with a size_t which is unsigned. Which kept throwing off comparisons when the signed int was less than zero. Whoops.


Okay I have no idea how to programatically deal with this. I think I'm going to have to hard code some relationships based on my input, as it's a different shape than the sample, and I assume everyone may have a different unfolded cube map.

My basic plan now is, when attempting to move to a spot, check to see if would enter a new 50x50 boundary (or just 4x4 for the sample).

...

Okay that took a WHILE to wrap my head around and figure out what to do. Because it will take too long to enumerate with my input, I'll just show an example I did with the sample data:

int dir[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} }; // Right, Down, Left, Up
int sides[6][2] = { {0,2}, {1,0}, {1,1}, {1,2}, {2,2}, {2,3} }; // Normalized coordinates of sides
int edge[6][4] = // edge[side][dir] == new side
{
    {5,3,2,1},
    {2,4,5,0},
    {3,4,1,0},
    {5,4,2,0},
    {5,1,2,3},
    {0,1,4,3}
};

// ...

tuple<int, int, int> getWarpedCoord(const int r, const int c, const int di)
{
    int dr = r+dir[di][0];
    int dc = c+dir[di][1];
    int ddi = di;
    
    int oldSide = getSide(r, c);
    int newSide = getSide(dr, dc);

    if (oldSide != newSide)
    {
        newSide = edge[oldSide][di];
        cout << "From [" << oldSide << "] to [" << newSide << "]" << endl;

        int x = r%EDGE_SIZE;
        int y = c%EDGE_SIZE;

        // Note: key is RC, or (row*10)+col
        switch ((oldSide*10)+newSide)
        {
            case 03: break;

            case 12: break;

            case 20:
                ddi = D_RIGHT;
                dr = (sides[newSide][0] * EDGE_SIZE) + (y);
                dc = (sides[newSide][1] * EDGE_SIZE);
                break;

            case 35:
                ddi = D_DOWN;
                dr = (sides[newSide][0] * EDGE_SIZE);
                dc = (sides[newSide][1] * EDGE_SIZE) + (y - 1);
                break;

            case 41:
                ddi = D_UP;
                dr = (sides[newSide][0] * EDGE_SIZE) + (EDGE_SIZE - 1);
                dc = (sides[newSide][1] * EDGE_SIZE) + (EDGE_SIZE - y - 1);
                break;

            case 54: break;

            default:
                cout << "FIGURE OUT SIDES" << endl;
                std::_Exit(0);
        }
    }

    return tuple<int, int, int>(dr, dc, ddi);
}

Yes, that's a lot of hard-coded things. Rather than spending hours figuring out each case, I only enumerated the cases in the switch statement that were actually hit, and exited the program with a prompt to figure out the sides. My own input is in a different configuration, so my submission code looks FAR different. If you want to run this code for yourself... you can't, not as-is. You'll need to figure out the edge placement and switch logic yourself unfortunately. (Then again, looking on reddit, everyone had the same unfolded cube configuration)


That one took way longer than any of the others before. Simply because I was hard coding cases, and there was a lot of the cases I got wrong and had to manually debug using my physical references. Ugh. Either way, it's done with.

Paper cube used for reference


I don't think I can finish the rest of AoC by tonight. I'm so close, frustratingly close, and I know day 25 should be easy enough. But 23 and 24 are likely going to take me hours each, and I don't have it in me...


Time taken: 5 hours 40 minutes

My solutions for today's puzzles