Today's problem involves a display system whose wiring has been mixed up, and we need to figure out the correct numbers that are being sent to the display.
A full description of the problem can be found here - https://adventofcode.com/2021/day/8
Understanding the problem
Each wire is lettered from a through g, and goes to a single bar in the 7 digit display.
The input to the problem has 2 parts. The first "calibration" part contains a set of unique signals that will be displayed. Each of these signals correspond to the numbers 0 through 9. The second part contains the actual numbers that are sent to the display.
Since the numbers 1,4,7 and 8 are the only numbers that are displayed with a unique number of bars, we can infer the set of wires corresponding to these numbers. We know the set but we cannot infer which wire goes to which yet. This information is enough to devise a solution to the first part of the problem.
If we were to compare the wires of 1 and 7, we can definitely figure out which wire goes to the top bar - a. We can also determine the two wires that should go to c and f. Comparing 1 to 4 also helps us determine the set of wires that should go to b and d. Finally comparing 8, 4 and 7 , lets us determine the set of wires that got to b and e.Based on the data so far, we can compare the wires from 1 and 8 to gives us the "non-three" wires.
Using the newly found information above, in conjunction with what we know from 8 and 4, we can accurately determine which wire goes to b,d,e and g.
For the last set of undiscovered wires we need to figure out the set of wires for 2,3 and 5. Using the information we have just learnt, we can figure out which set of wires corresponds to the number 2, and then use this to determine which wires got to c and f.
Code
The only caveat to the code below is that I use a different lettering scheme for the dictionary key storing the wire. It doesn't affect the actual logic that determines which wire goes to that position
from collections import Counter with open('input.txt') as f: lines = f.readlines() def isUniqueCharSignal(u): return len(Counter(u)) == len(u) def getOneFourSevenEight(signals): # 1 = 2 uniq chars, 4 = 4 unique chars, 7 = 3 unique chars, 8 = 7 unique chars k = { 2 : 1, 3 : 7 , 4 : 4 , 7 : 8 } return { k[len(i)]:i for i in getOneFourSevenEightNoUnique(signals) } def getOneFourSevenEightNoUnique(signals): return [ i for i in signals if len(i) in [2,3,4,7] ] def getTwoThreeFive(signals): return [ set(i) for i in signals if len(i) == 5 ] def getWiring(unique): u = getOneFourSevenEight(unique) # get chars exclusive to one , seven , four and eight oneChars = set(u[1]) sevenChars = set(u[7]).difference(oneChars) fourChars = set(u[4]).difference(oneChars) eightChars = set(u[8]).difference(fourChars).difference(sevenChars).difference(oneChars) # build our intial set of wiring assumptions wiring = { 'a':0 ,'b':0 ,'c':0 ,'d':0 , 'e':0, 'f':0, 'g':0 } wiring['b'] = wiring['c'] = oneChars wiring['a'] = list(sevenChars)[0] wiring['f'] = wiring['g'] = fourChars wiring['d'] = wiring['e'] = eightChars # get chars to two, three and give twoThreeFive = getTwoThreeFive(unique) # we can determine the chars in three threeChars = [ i for i in twoThreeFive if oneChars.issubset(i) ][0] # we can determine the chars NOT in three by removing the chars in three that are also in eight notThreeChars = set(u[8]).difference(threeChars) # knowing what is not in 3 we can solidify what is in positions 3,4,5 and 6 wiring['g'] = list(wiring['g'].difference(notThreeChars))[0] wiring['f'] = list(wiring['f'].difference(wiring['g']))[0] wiring['d'] = list(wiring['d'].difference(notThreeChars))[0] wiring['e'] = list(wiring['e'].difference(wiring['d']))[0] # we can now definitively pick the chars in two and therefore the positions at 1 and 2 twoChars = [ i for i in twoThreeFive if not set(wiring['f']).issubset(i) and set(wiring['e']).issubset(i) ][0] wiring['b'] = list(twoChars.intersection(wiring['b']))[0] wiring['c'] = list(wiring['c'].difference(set(wiring['b'])))[0] # and generate the wiring for each number numbers = {} numbers[0] = {wiring['a'],wiring['b'],wiring['c'],wiring['d'],wiring['e'],wiring['f']} numbers[1] = {wiring['b'],wiring['c']} numbers[2] = {wiring['a'],wiring['b'],wiring['g'],wiring['e'],wiring['d']} numbers[3] = {wiring['a'],wiring['b'],wiring['c'],wiring['d'],wiring['g']} numbers[4] = {wiring['f'],wiring['g'],wiring['b'],wiring['c']} numbers[5] = {wiring['a'],wiring['f'],wiring['g'],wiring['c'],wiring['d']} numbers[6] = {wiring['a'],wiring['f'],wiring['e'],wiring['d'],wiring['c'],wiring['g']} numbers[7] = {wiring['a'],wiring['b'],wiring['c']} numbers[8] = {wiring['a'],wiring['b'],wiring['c'],wiring['d'],wiring['e'],wiring['f'],wiring['g']} numbers[9] = {wiring['a'],wiring['b'],wiring['c'],wiring['d'],wiring['f'],wiring['g']} return wiring, numbers def getNumber(displaySignal,numbers): return [ i for i in numbers if numbers[i] == displaySignal][0] countOfOneFourSevenEight = 0 countOfAllNumbers = 0 for line in lines: (unique, display) = line.rstrip().split("|") (unique, display) = ([i for i in unique.split(" ") if i != ''],[j for j in display.split(" ") if j != '']) displayCharSignals = getOneFourSevenEightNoUnique(display) countOfOneFourSevenEight += len(displayCharSignals) wiring,numbers = getWiring(unique) allnumbers = int("".join([ str(getNumber(set(i),numbers)) for i in display ])) countOfAllNumbers += allnumbers print("Count of One Four Seven Eight = ",countOfOneFourSevenEight) print("Count of All Numbers = ",countOfAllNumbers) # Count of One Four Seven Eight = 349 # Count of All Numbers = 1070957