Advent Of Code - Day 8

If yesterday was a bit of a respite from adventuring, today was the boss fight for which we geared up for. The wall of text that hit us in the face, nearly depleted all of our HP. Let’s hope tomorrow brings some potions.

Day 8 - Part 1

We start off relatively easy… We have to deal with old school number displays that use segments to display numbers. Luckily, for part one, all we are interested about is to find numbers in the output which are a definitive match against numbers which are displayed using the segmented display system.

That’s easy, we just gather all numbers which correspond to a certain length.

	out := 0
	for _, line := range strings.Split(string(content), "\n") {
		input := strings.Split(string(line), " | ")
		// signalPatterns := input[0]
		outputValue := input[1]
		for _, v := range strings.Split(outputValue, " ") {
			if _, ok := digitsToSegments[len(v)]; ok {
				out++
			}
		}
	}

	fmt.Println("out: ", out)

Where digitsToSegments is just a map of length -> number.

That’s it. This is part 1. Super easy. Barely an inconvenience.

Day 8 - Part 2

Okay, now comes the hard part. There are several solutions out there for this one. Some used bit logic, some used brute force, some used backtracking, some used set logic, some used permutations, and I used a lot of frigging Contains.

There is a lot I don’t like about the code, but I had my booster, I’m tired, and I “logiced” it out on paper. I actually saw a person doing the same and posting their logic on it on reddit. I did the same thing. Cool, I’m not insane.

First step was to sort all of the values, since, I need to match them up later. This was just easier to do than creating a set and doing some intersection logic.

Once I had my sorted items, I isolated 1, 4, 7, 8 like above. Created a map for segmentToNumber and numberToSegment for easy parsing.

And then, I started to find the rest of the numbers. The paper logic translated to this monstrosity.

func findNumberMappings(s []string) {
	// find 6 and 9
	var (
		ninezero                          []string
		six, three, five, two, nine, zero string
		topOne, bottomOne                 string
	)

	// find out which one of 1's "ab" is in 6 and 9
	// determine which of ones lines is top and bottom
	// find 2, 3, 5 and determine which is 2 and which is 5
	// by checking which one it contains.
	// the rest is 3.
	for _, v := range s {
		// 9, 6, 0
		if len(v) == 6 && strings.Contains(v, string(numberToSegment["1"][0])) && strings.Contains(v, string(numberToSegment["1"][1])) {
			ninezero = append(ninezero, v)
		} else if len(v) == 6 && (strings.Contains(v, string(numberToSegment["1"][0])) || strings.Contains(v, string(numberToSegment["1"][1]))) {
			six = v
		}
		// 3
		if len(v) == 5 && strings.Contains(v, string(numberToSegment["1"][0])) && strings.Contains(v, string(numberToSegment["1"][1])) {
			three = v
		}
	}

	if strings.Contains(six, string(numberToSegment["1"][0])) {
		topOne = string(numberToSegment["1"][1])
		bottomOne = string(numberToSegment["1"][0])
	} else {
		topOne = string(numberToSegment["1"][0])
		bottomOne = string(numberToSegment["1"][1])
	}

	// find 2, 5
	for _, v := range s {
		if len(v) == 5 && v != three {
			if strings.Contains(v, topOne) {
				two = v
			} else if strings.Contains(v, bottomOne) {
				five = v
			}
		}
	}

	// 9 contains all segments of 4
	nine = ninezero[0]
	zero = ninezero[1]
	isNine := true
	for _, c := range numberToSegment["4"] {
		if !strings.Contains(nine, string(c)) {
			isNine = false
			break
		}
	}
	if !isNine {
		nine, zero = zero, nine
	}

	segmentToNumber[nine] = "9"
	segmentToNumber[six] = "6"
	segmentToNumber[two] = "2"
	segmentToNumber[three] = "3"
	segmentToNumber[five] = "5"
	segmentToNumber[zero] = "0"
}

Obviously, here, I need to replace the strings.Contains with some maps that I can than use more efficiently.

I started working on something like:

type digit struct {
	value string
	chars map[rune]struct{}
}

And then use this instead of strings. The map than can be used for quick checking of segments. This should yield some better benchmark results. Overall it’s not that shabby.

Conclusion

Today we learned to read again. And we also learned that drawing things on paper gives a better perspective and playground on working out some details about the problem.

The repository for all my solutions for AOC 2021 can be found here.

Thank you for reading!

Gergely.