Advent Of Code 2021 - Day 8

Photo by pparnxoxo on Unsplash

Advent Of Code 2021 - Day 8

Day 8 was a very word-y task, so I'll try to sum it up. If it seems confusing, it's because I was quite confused by the original description.

After escaping the giant whale from Day 7, we find ourselves in an underwater cave. It seems that some of our displays are malfunctioning, so we need to fix them. These are seven-segments displays, the kind you might have seen on digital watches that make up the numbers by lighting up seven segments in different combinations.

It might look something like this, with segments named from a through g:

  0:      1:      2:      3:      4:
 aaaa    ....    aaaa    aaaa    ....
b    c  .    c  .    c  .    c  b    c
b    c  .    c  .    c  .    c  b    c
 ....    ....    dddd    dddd    dddd
e    f  .    f  e    .  .    f  .    f
e    f  .    f  e    .  .    f  .    f
 gggg    ....    gggg    gggg    ....

  5:      6:      7:      8:      9:
 aaaa    aaaa    aaaa    aaaa    aaaa
b    .  b    .  .    c  b    c  b    c
b    .  b    .  .    c  b    c  b    c
 dddd    dddd    ....    dddd    dddd
.    f  e    f  .    f  e    f  .    f
.    f  e    f  .    f  e    f  .    f
 gggg    gggg    ....    gggg    gggg

So, in order to be able to understand our displays, we need to decode some input. It seems like the wires have been mixed up. We're still getting signals, but they don't make sense. A line in our input looks like this:

acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf

The section before | is the signal pattern, and the section after | is the four digit output. Using the input signal, we need to figure out the output value. We're starting with the easy stuff in Part 1.

There are a few digits that use a unique amount of segments to display, and therefore are easy to recognize. These digits are 1, 4, 7 and 8. For Part 1 we just need to count how many times any of these digits appear in the output values. This could be a oneliner, I've spread it out a little for readbility:

var uniqueLengths = new[] { 2, 3, 4, 7 };

var part1 = input.Select(x =>
    x.Split(new[] {'|', ' '}, StringSplitOptions.RemoveEmptyEntries)[10..]
        .Count(x => uniqueLengths.Contains(x.Length))).Sum();

We define our unique lengths, split our input so we're only looking at the output values and count the number of outputs that matches any of the unique lengths. Quite simple.

Part 2 requires us to figure out the remaining digits for each input line, get the four digits output and sum all the outputs together.

private static void Part2(IEnumerable<string> entries)
{
    long sum = 0;

    foreach (var line in entries)
    {
        var mapping = new Dictionary<int, List<char>>();
        var tmp = line.Split(new char[] { '|', ' ' }, StringSplitOptions.RemoveEmptyEntries);

        var wires = tmp[..10].Select(x => x.OrderBy(c => c).ToList()).ToList();
        var outputs = tmp[10..].Select(x => x.OrderBy(c => c).ToList());

        mapping[1] = wires.Single(x => x.Count == 2);
        mapping[4] = wires.Single(x => x.Count == 4);
        mapping[7] = wires.Single(x => x.Count == 3);
        mapping[8] = wires.Single(x => x.Count == 7);

        mapping[9] = wires.Single(x => x.Count == 6 && x.Intersect(mapping[4]).Count() == 4);
        mapping[6] = wires.Single(x => x.Count == 6 && !mapping[1].All(x.Contains));
        mapping[0] = wires.Single(x => x.Count == 6 && !mapping.ContainsValue(x));

        mapping[5] = wires.Single(x => x.Count == 5 && x.Intersect(mapping[6]).Count() == 5);
        mapping[3] = wires.Single(x => x.Count == 5 && x.Intersect(mapping[7]).Count() == 3 && !mapping.ContainsValue(x));
        mapping[2] = wires.Single(x => x.Count == 5 && !mapping.ContainsValue(x));

        var ans = string.Empty;
        foreach (var output in outputs)
        {
            var number = mapping.Single(x => x.Value.SequenceEqual(output)).Key;
            ans += number;
        }

        sum += long.Parse(ans);
    }

    Console.WriteLine($"Part 2: {sum}");
}

We create a dictionary to hold our mapping for each line. Then we have to parse our input and separate wire signals from outputs. Finally, we can start figuring out which wire signal belings to what number.

The first four are easy, the unique ones that we talked about in Part 1. Now we have 6 digits left to figure out, 3 of them uses 6 segments and 3 of them uses 5 segments.

  • 9 is the only digit that uses 6 segments, and use all of the segments from digit 4.
  • 6 is the only digit that uses 6 segments, but does not use all of the segments from digit 1.
  • 0 is the remaining digit that uses 6 segments, but isn't 9 or 6.

  • 5 is the only digit that uses 5 segments, where all 5 is also used in digit 6.

  • 3 also uses 5 segments, where 3 of them is also used in digit 7, and it isn't a 5.
  • 2 is the remaining digit that uses 5 segments, but isn't 5 or 3.

Once we've figured out the mapping, we convert our individual digits to a 4 digit number and add that to the sum. When we've gone through all our lines, we have our answer.

This wasn't actually that difficult to code, but it did take me some time to understand the question properly.