mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2025-01-22 05:06:23 +00:00
08
This commit is contained in:
parent
d3427a2651
commit
a4f671a6cc
27
2021/08/README.md
Normal file
27
2021/08/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# 08
|
||||
|
||||
This was super fun and another episode of "I should have gotten my paper out sooner".
|
||||
|
||||
As soon as I realized you can take the statistical approach to decode the numbers.
|
||||
|
||||
1. Count all characters
|
||||
|
||||
This will reveal the mapping for the letters `b`, `e` and `f`, as they appear a unique amount of times.
|
||||
|
||||
2. `a` & `c`
|
||||
|
||||
Both appear 8 times. We find `a` by looking at the `1` and `7`. If we identify `1` (cf) and `7` (afc) we can simply calculate what `a` is by difference. With `a` identified `c` is also determined.
|
||||
|
||||
3. `d` & `g`
|
||||
|
||||
Both appear 7 times. We take the similar approach as in 2.
|
||||
|
||||
This ensures a linear time execution.
|
||||
|
||||
<details>
|
||||
<summary>Solutions</summary>
|
||||
<ol>
|
||||
<li>449</li>
|
||||
<li>968175</li>
|
||||
</ol>
|
||||
</details>
|
169
2021/08/python/main.py
Normal file
169
2021/08/python/main.py
Normal file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from os.path import join, dirname
|
||||
from typing import Dict, List, Set
|
||||
|
||||
# Day 08
|
||||
|
||||
# Common
|
||||
|
||||
|
||||
def read_input(filename):
|
||||
data = join(dirname(__file__), '..', filename)
|
||||
with open(data) as f:
|
||||
return f.read().strip()
|
||||
|
||||
|
||||
test = read_input('test.txt')
|
||||
data = read_input('input.txt')
|
||||
|
||||
|
||||
class Utils:
|
||||
@staticmethod
|
||||
def count_chars(items: List[str]) -> Dict[str, int]:
|
||||
count = {}
|
||||
for item in items:
|
||||
for char in item:
|
||||
if char not in count:
|
||||
count[char] = 0
|
||||
count[char] += 1
|
||||
return count
|
||||
|
||||
@staticmethod
|
||||
def group_by_length(items: List[str]) -> Dict[int, List[str]]:
|
||||
groups = {}
|
||||
for item in items:
|
||||
l = len(item)
|
||||
if l not in groups:
|
||||
groups[l] = []
|
||||
groups[l].append(item)
|
||||
return groups
|
||||
|
||||
|
||||
class SevenSegment:
|
||||
mappings = {
|
||||
0: 'abcefg',
|
||||
1: 'cf',
|
||||
2: 'acdeg',
|
||||
3: 'acdfg',
|
||||
4: 'bcdf',
|
||||
5: 'abdfg',
|
||||
6: 'abdefg',
|
||||
7: 'acf',
|
||||
8: 'abcdefg',
|
||||
9: 'abcdfg'
|
||||
}
|
||||
reverse = {v: k for k, v in mappings.items()}
|
||||
count: Dict[str, int] = Utils.count_chars(mappings.values())
|
||||
|
||||
@staticmethod
|
||||
def encode(number: int) -> str:
|
||||
return SevenSegment.mappings[number]
|
||||
|
||||
@staticmethod
|
||||
def decode(segment: str) -> int:
|
||||
normalized: str = ''.join(sorted(list(segment)))
|
||||
return SevenSegment.reverse[normalized]
|
||||
|
||||
|
||||
class Reading:
|
||||
def __init__(self, input: List[str], output: List[str]) -> None:
|
||||
self.input = input
|
||||
self.output = output
|
||||
self.transformations: Dict[str, str] = {}
|
||||
|
||||
def translate(self, segment: str) -> str:
|
||||
return ''.join([self.transformations[char] for char in segment])
|
||||
|
||||
def analyse(self):
|
||||
count = Utils.count_chars(self.input)
|
||||
by_length = Utils.group_by_length(self.input)
|
||||
|
||||
# Find a & c
|
||||
# 1 and 7 have the same chars with the only difference of the 'a'
|
||||
one = set(by_length[2][0])
|
||||
seven = set(by_length[3][0])
|
||||
a = seven.difference(one).pop()
|
||||
|
||||
dg: Set[str] = set()
|
||||
|
||||
# Find b, e & f by statistical analysis
|
||||
for k, v in count.items():
|
||||
if v == 6:
|
||||
b = k
|
||||
self.transformations[k] = 'b'
|
||||
elif v == 4:
|
||||
self.transformations[k] = 'e'
|
||||
elif v == 9:
|
||||
self.transformations[k] = 'f'
|
||||
elif v == 8:
|
||||
if k == a:
|
||||
self.transformations[k] = 'a'
|
||||
else:
|
||||
self.transformations[k] = 'c'
|
||||
elif v == 7:
|
||||
dg.add(k)
|
||||
|
||||
# Find d by looking at the 1 and 4
|
||||
# We already know b so, we subtract cf (1) from bcdf (4) and are left with bd.
|
||||
four = set(by_length[4][0])
|
||||
bd = four.difference(one)
|
||||
d = bd.difference(b).pop()
|
||||
self.transformations[d] = 'd'
|
||||
g = dg.difference(d).pop()
|
||||
self.transformations[g] = 'g'
|
||||
|
||||
def read(self) -> List[int]:
|
||||
return [SevenSegment.decode(self.translate(segment)) for segment in self.output]
|
||||
|
||||
@staticmethod
|
||||
def parse(data: str):
|
||||
input, output = data.split('|')
|
||||
i = input.strip().split(' ')
|
||||
o = output.strip().split(' ')
|
||||
return Reading(i, o)
|
||||
|
||||
|
||||
class Log:
|
||||
def __init__(self, readings: List[Reading]) -> None:
|
||||
self.readings = readings
|
||||
|
||||
def flag(self, alt=False):
|
||||
count = 0
|
||||
for reading in self.readings:
|
||||
reading.analyse()
|
||||
numbers = reading.read()
|
||||
if alt:
|
||||
count += int(''.join([str(n) for n in numbers]))
|
||||
else:
|
||||
for number in numbers:
|
||||
if number == 1 or number == 4 or number == 7 or number == 8:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
@staticmethod
|
||||
def parse(data: str):
|
||||
return Log([Reading.parse(line) for line in data.split('\n')])
|
||||
|
||||
|
||||
# 1
|
||||
print('1.')
|
||||
|
||||
log = Log.parse(test)
|
||||
result = log.flag()
|
||||
print(f"Test: {result}")
|
||||
|
||||
log = Log.parse(data)
|
||||
result = log.flag()
|
||||
print(f"Result: {result}")
|
||||
|
||||
# 2
|
||||
print('\n2.')
|
||||
|
||||
log = Log.parse(test)
|
||||
result = log.flag(True)
|
||||
print(f"Test: {result}")
|
||||
|
||||
log = Log.parse(data)
|
||||
result = log.flag(True)
|
||||
print(f"Result: {result}")
|
Loading…
Reference in New Issue
Block a user