--- Day 5: Fertilizer ---

December 5

Listening to: Rain beating against the window


Hey. Lethal company. Get some friends and play it. Spent quite a few hours on it tonight.


Oh boy. This one looks complicated. It's likely very simple, a mapping funciton repeated multiple times, but there's a lot of words in this input. Also, looking at the real input file, the individual numbers have a LOT of digits. So it wouldn't be as simple as just making a few arrays of the length of the biggest input. It would be better to do actual math.

So my idea is, starting with the initial seed value, use the transformation steps while there's still lines in the file. I'm going to try and not hard-code anything, and... probably just parse through it all one at a time? Then just map things based off of the odd logic encoded in the line.

// Convert seed values
vector<int64_t> mappedSeeds;
for (int64_t seed: seeds)
{
    bool mapped = false;
    for (AlmMap almMap : almanac)
    {
        if (seed >= almMap.source && seed <= (almMap.source + almMap.range))
        {
            int64_t delta = almMap.destination - almMap.source;
            mappedSeeds.push_back(seed + delta);
            mapped = true;
            break;
        }
    }

    if (!mapped) mappedSeeds.push_back(seed);
}

This is the first time I got hung up on large numbers. Just had to replace int with int64_t, and stoi with stoll. But once it ran successfully with large numbers, it worked!


Ugh... this needs to be done over a RANGE now. Lovely. Naieve approach - just populate the seed values with the initial ranges? But even the first pair will populate it with almost 100 million values. There's got to be a trick with how this mapping is done.

Okay, new trick - since everything is overlapping ranges, the trick should be to simply split ranges as need be! For each iteration, check if there is an overlap between the seed and almanac ranges, and if there are - split and handle that!


This actually took significant refactoring to make sense of this. I basically changed the structs to be start/end pairs (with a delta for the almanac mapping too). If there was an overlap between seed ranges and an almanac, I would split the seed up, and queue the un-mapped portion to be processed again in case it overlapped with a different mapping.

queue<SeedRange> mappedSeeds;
while (!seeds.empty())
{
    SeedRange seed = seeds.front(); seeds.pop();
    bool overlapped = false;
    for (AlmMap almMap : almanac)
    {
        // Check if any overlap
        if ((seed.start <= almMap.end) && (almMap.start <= seed.end))
        {
            overlapped = true;
            // Remove before overlap
            if (seed.start < almMap.start)
            {
                seeds.push(SeedRange{ seed.start, almMap.start-1 });
                seed.start = almMap.start;
            }

            // Remove after overlap
            if (seed.end > almMap.end)
            {
                seeds.push(SeedRange{ almMap.end+1, seed.end });
                seed.end = almMap.end;
            }

            // Map the remaining
            mappedSeeds.push(SeedRange{seed.start+almMap.delta, seed.end+almMap.delta });
        }
    }

    if (!overlapped) mappedSeeds.push(SeedRange{ seed.start, seed.end });
}

Shockingly (to me), it got the right answer nearly instantly, and the first time too!

Aferwards, I took a look at the AoC subreddit and quite a few people just let their part 1 solutions brute-force it. Maybe I could have just done that? I didn't even want to try.


Time taken: 2 hours

My solutions for today's puzzles