--- Day 19: Towels ---

December 19

Listening to: 🎮Low Poly DnB🎮 Another Ambient Jungle Mix, 90s Style


I think I'm just going to do part 1 naievely; a simple DFS of avaliable towels along with the remaining pattern.

private bool IsAnyPatternPossible(string pattern)
{
    if (pattern.Length == 0) return true;

    foreach (var towel in towels)
    {
        if (pattern.StartsWith(towel) && IsAnyPatternPossible(pattern.Substring(towel.Length)))
        {
            return true;
        }
    }

    return false;
}

Easy.


My first though it to enumerate every bit of the list, with some memoization to help speed things along...

public Dictionary<string, ImmutableList<ImmutableList<string>>> knownPatterns = new Dictionary<string, ImmutableList<ImmutableList<string>>>();

private ImmutableList<ImmutableList<string>> GetAllArrangements(string pattern)
{
    if (knownPatterns.TryGetValue(pattern, out var cachedResult)) return cachedResult;
    if (pattern.Length == 0) return ImmutableList.Create<ImmutableList<string>>();

    var results = new List<ImmutableList<string>>();

    foreach (var towel in towels)
    {
        if (pattern == towel)
        {
            results.Add(ImmutableList.Create(towel));
        }
        else if (pattern.StartsWith(towel))
        {
            foreach (var subList in GetAllArrangements(pattern.Substring(towel.Length)))
            {
                results.Add(subList.Prepend(towel).ToImmutableList());
            }
        }
    }

    knownPatterns[pattern] = results.ToImmutableList();
    return knownPatterns[pattern];
}

... but this is running incredibly slow on the real input.

Actually on second thought this is reminding me a lot of Day 11. I don't need to keep track of the actual pattern lengths, just the actual valid patterns. Much easier just to keep count.

public Dictionary<string, long> knownPatternCounts = new Dictionary<string, long>();
private long GetArrangementCount(string pattern)
{
    if (knownPatternCounts.TryGetValue(pattern, out var cachedResult)) return cachedResult;

    long sum = 0;
    foreach (var towel in towels)
    {
        if (pattern == towel) sum++;
        else if (pattern.StartsWith(towel)) sum += GetArrangementCount(pattern[towel.Length..]);
    }

    knownPatternCounts[pattern] = sum;
    return sum;
}

Shorter, simpler, and runs in 200ms!


Time taken: 45 minutes

My solutions for today's puzzles