Skip to content

Commit

Permalink
Day 8
Browse files Browse the repository at this point in the history
  • Loading branch information
xoposhiy committed Dec 8, 2021
1 parent d9652c7 commit c005ad6
Show file tree
Hide file tree
Showing 7 changed files with 461 additions and 1 deletion.
4 changes: 4 additions & 0 deletions 2021/07-crabs.py
@@ -1,4 +1,5 @@
import numpy as np
from intcode import run

inp = np.loadtxt('07.txt', delimiter=',', dtype=int)

Expand Down Expand Up @@ -29,3 +30,6 @@
candidates.append((delta * (delta + 1) // 2).sum())

print('Part Two', min(candidates))

p, output = run(inp, [])
print(output)
98 changes: 98 additions & 0 deletions 2021/08-7segment-displays.py
@@ -0,0 +1,98 @@
from aoc import *

inp = read(sep=" \\| ")

entries = [(entry[0].split(' '), entry[1].split(' ')) for entry in inp]
ans = sum(sum(1 for p in entry[1] if len(p) in [2, 3, 4, 7]) for entry in entries)

print("Part One", ans)

digits = {
'abcefg': 0,
'cf': 1,
'acdeg': 2,
'acdfg': 3,
'bcdf': 4,
'abdfg': 5,
'abdefg': 6,
'acf': 7,
'abcdefg': 8,
'abcdfg': 9
}


def solve():
ans2 = 0
for signals, displays in entries:
def find_signal(segments_count, other_digit='', intersection_size=0):
candidates = [
s for s in signals
if len(s) == segments_count
and len(set(other_digit) & set(s)) == intersection_size]
assert len(candidates) == 1
return ''.join(sorted(candidates[0]))

d1 = find_signal(2)
d4 = find_signal(4)
d7 = find_signal(3)
d8 = find_signal(7)
d3 = find_signal(5, d1, 2)
d2 = find_signal(5, d4, 2)
d5 = find_signal(5, d2, 3)
d6 = find_signal(6, d1, 1)
d9 = find_signal(6, d3, 5)
d0 = find_signal(6, d5, 4)
mapping = dict([(d1, 1), (d2, 2), (d3, 3), (d4, 4), (d5, 5), (d6, 6), (d7, 7), (d8, 8), (d9, 9), (d0, 0)])

n = 0
for display in displays:
n = n*10 + mapping[''.join(sorted(display))]
ans2 += n
return ans2


def solve_sets():
ans2 = 0
for signals, displays in entries:

def contains_all_segments(signal, required_segments):
return len(required_segments - set(signal)) == 0

def find_signal_with(segments_count, required_segments=set()):
signal = next(
s for s in signals if len(s) == segments_count and contains_all_segments(s, required_segments))
return set(signal)

d1 = find_signal_with(2)
d4 = find_signal_with(4)
d8 = find_signal_with(7)
d7 = find_signal_with(3)
fc = d1
a = d7 - d1
d3 = find_signal_with(5, a | fc)
dg = d3 - fc - a
d9 = find_signal_with(6, dg | fc)
b = d9 - dg - fc - a
d = d4 - fc - b
g = dg - d
e = d8 - d9
d6 = find_signal_with(6, a | dg | e)
c = d8 - d6
f = fc - c

letters = [list(x)[0] for x in [a, b, c, d, e, f, g]]
mapping = {}
for i in range(7):
mapping[letters[i]] = 'abcdefg'[i]
n = 0

for d in displays:
d2 = ''.join(sorted(map(lambda ch: mapping[ch], d)))
digit = digits[d2]
n = n * 10 + digit
ans2 += n
return ans2


print("Part Two", solve_sets())
print("Part Two", solve())
200 changes: 200 additions & 0 deletions 2021/08.txt

Large diffs are not rendered by default.

106 changes: 106 additions & 0 deletions 2021/DAY08.md
@@ -0,0 +1,106 @@
# Ищем интересное в AoC 2021

## Day 8. 7-segment displays

### itertools.permutations

![permutations](day8.jpg)

```python
from itertools import permutations

*good, = map(set, ['abcefg','cf', # Correct segments for each digit.
'acdeg','acdfg','bcdf','abdfg', # Segments for 0 are at position 0, etc.
'abdefg','acf','abcdefg','abcdfg'])

s = 0
for x,y in [x.split("|") for x in open(0)]:
for p in permutations('abcdefg'): # For each possible wiring permutation,
wires = dict(zip('abcdefg', p)) # create a dictionary to translate them.

def trans(displays):
out = 0
for d in displays.split(): # For each of the segment displays:
t = [wires[s] for s in d] # 1. translate each segment using dict,
digit = good.index(set(t)) # 2. look up to which digit they belong,
out = 10*out + digit # 3. add this digit to the output value.
return out

try: # Try translating using this dictionary.
_ = trans(x) # If we can trans. all signal patterns,
s += trans(y) # it must be correct, so we add output.
except ValueError: # If we hit a translation error, we try
pass # the next wiring permutation.
print(s)
```

## Размер пересечения с известными цифрами

Цифры 1 4 7 8 — определяются по количеству сегментов.
2 3 5 можно отличить друг от друга по количеству пересечений сегментов с уже известными цифрами.
6 9 0 — аналогично.

Например так:

```python
def solve():
ans2 = 0
for signals, displays in entries:
def find_signal(segments_count, other_digit='', intersection_size=0):
candidates = [
s for s in signals
if len(s) == segments_count
and len(set(other_digit) & set(s)) == intersection_size]
assert len(candidates) == 1
return ''.join(sorted(candidates[0]))

d1 = find_signal(2)
d4 = find_signal(4)
d7 = find_signal(3)
d8 = find_signal(7)
d3 = find_signal(5, d1, 2)
d2 = find_signal(5, d4, 2)
d5 = find_signal(5, d2, 3)
d6 = find_signal(6, d1, 1)
d9 = find_signal(6, d3, 5)
d0 = find_signal(6, d5, 4)
mapping = dict([(d1, 1), (d2, 2), (d3, 3), (d4, 4), (d5, 5), (d6, 6), (d7, 7), (d8, 8), (d9, 9), (d0, 0)])

n = 0
for display in displays:
n = n*10 + mapping[''.join(sorted(display))]
ans2 += n
return ans2
```

### Вычитание множеств

```python
def decode_digits(x):
cc = {x.count(c):c for c in 'abcdefg'} # A
sB = {cc[6]}; sE = {cc[4]}; sF = {cc[9]} # B C
ss = {len(d):set(d) for d in x.split()} # D
d1 = ss[2]; d4 = ss[4]; d7 = ss[3]; d8 = ss[7] # E F
sD = d4-d1-sB; sC = d1-sF # sA=d7-d1; sG=d8-d4-d7 - not needed # G
return d8-sD,d1,d8-sB-sF,d8-sB-sE,d4,d8-sC-sE,d8-sC,d7,d8,d8-sE
```

### Ещё короче!

Если отсортировать сигналы по хитрому критерию, все встанет на свои места!

```python
ans1 = ans2 = 0
for line in data.splitlines():
seqs = [frozenset(seq) for seq in re.findall(r'\w+', line)]
_1,_7,_4, *pending,_8 = sorted(set(seqs), key=len)
sorter = lambda x: [len(x &_8), len(x &_4), len(x &_1)]
_2,_5,_3,_6,_0,_9 = sorted(pending, key=sorter)
ns = [_0,_1,_2,_3,_4,_5,_6,_7,_8,_9]
ans1 += sum(x in {_1, _7, _4, _8} for x in seqs[-4:])
ans2 += int(''.join(str(ns.index(x)) for x in seqs[-4:]))
```

---

Автор большинства сниппетов выше не я — они взяты [из реддита](https://www.reddit.com/r/adventofcode/) твиттера или нашего [телеграм чата](https://t.me/konturAoC2021_chat).
2 changes: 1 addition & 1 deletion 2021/README.md
Expand Up @@ -14,7 +14,7 @@

## [Day 7. Crabs! Median! Mean!](DAY07.md)

## [Day 8.](DAY08.md)
## [Day 8. 7-segments displays](DAY08.md)

## [Day 9.](DAY09.md)

Expand Down
Binary file added 2021/day8.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions 2021/intcode.py
@@ -0,0 +1,52 @@
def run(program, inp):
program = program.copy()
ip = 0
inp_index = 0
output = ''

def param(i):
mode = modes // int(10 ** (i - 1)) % 10
if mode == 0:
return program[program[ip + i]]
else:
return program[ip + i]

while ip < len(program):
modes = program[ip] // 100
opcode = program[ip] % 100
if opcode == 99:
break
if opcode == 1:
program[program[ip + 3]] = param(1) + param(2)
ip += 4
elif opcode == 2:
program[program[ip + 3]] = param(1) * param(2)
ip += 4
elif opcode == 3:
program[program[ip + 1]] = inp[inp_index]
inp_index += 1
ip += 2
elif opcode == 4:
v = param(1)
output = output + chr(v)
ip += 2
elif opcode == 5: # jump-if-true
if param(1) != 0:
ip = param(2)
else:
ip += 3
elif opcode == 6: # jump-if-false
if param(1) == 0:
ip = param(2)
else:
ip += 3
elif opcode == 7: # less-than
program[program[ip + 3]] = 1 if param(1) < param(2) else 0
ip += 4
elif opcode == 8: # equals
program[program[ip + 3]] = 1 if param(1) == param(2) else 0
ip += 4
else:
print("Unknown opcode: ", opcode)
return
return program, output

0 comments on commit c005ad6

Please sign in to comment.