--- Day 14: Reservoirs ---

December 14

Listening to: PS1 Jungle Mix


I went rock climbing today. Hung out with a friend I hadn't seen in a long time, and their partner who I only met breifly before. It was a nice, active diversion from all of the stress and work I've had lately.


A falling sand puzzle! Some basic physics. Seems kinda fun to try and simulate, and see what kind of fun structures the input might have in store. I'm excited for this one actually.

First thing first, parse it, and figure out the range of values. It'll help a bit figuring out how much of a surface I need to actually simulate.

vector<string> split(string s, string delim)
{
    vector<string> output;
    while (s.find(delim) != string::npos)
    {
        size_t pos = s.find(delim);
        output.push_back(s.substr(0, pos));
        s.erase(0, pos + delim.length());
    }
    return output;
}

So odd that C++ doesn't have its own string split function - nearly every other language has something similar. I've been working around it up to this point, but I'll probably just nab this bit of code for a lot of future.

X: 447 - 515
Y: 13 - 168

That range seems reasonable. 68x155 grid. Not that big of a deal. Now I know the bounds, I can just draw the lines in the bounds.

// Prepare and draw map
for (int i = 0; i <= ymax; i++)
{
    string s = "";
    for (int j = xmin; j <= xmax; j++) s += ".";
    map.push_back(s);
}

for (Line line: lines)
{
    Coord dir, from, to = line[0];
    for (int i = 1; i < line.size(); i++)
    {
        from = to;
        to = line[i];

        if      (from.first  < to.first)  dir = Coord( 1, 0);
        else if (from.first  > to.first)  dir = Coord(-1, 0);
        else if (from.second < to.second) dir = Coord( 0, 1);
        else if (from.second > to.second) dir = Coord( 0,-1);

        map[from.second][from.first-xmin] = '#';
        while (from != to)
        {
            map[from.second][from.first-xmin] = '#';
            from.first += dir.first;
            from.second += dir.second;
        }
    }
}

Map prepared, time for physics... I guess?

// Perform physics
int count = 0;
while(true)
{
    int grain = START_X - xmin;

    // Drop grain
    int i = 0;
    for (; i < map.size(); i++)
    {
        // Check if fallen off map bottom
        if (i+1 >= map.size()) { cout << "Total grains: " << count << endl; return 0; }

        // Check directly below
        if (map[i+1][grain] == '.') continue;

        // Check down-left
        if (map[i+1][grain-1] == '.' ) { grain--; continue; }

        // Check down-right
        if (map[i+1][grain+1] == '.') { grain++; continue; }

        break;
    }
    

    map[i][grain] = 'o';
    count++;
} 

Okay, Part 2 is eazy enough. It's just an extra floor two spaces below the existing map, nothing inbetween. It should be easy enough... eugh, except I just realized the far X and Y are now just going to be existant. So now it's going to be something like a 1000x158 grid. I guess the optimizations I initially did are going away.

// Add extra space and floor
string hardFloor = "";
for (int j = 0; j <= xmax*2; j++) hardFloor += "#";
map.push_back(hardFloor);

Physics is fun


Time taken: 1 hour 30 minutes

My solutions for today's puzzles