Skip to content

Instantly share code, notes, and snippets.

@jmrnilsson
Last active December 11, 2021 12:04
Show Gist options
  • Save jmrnilsson/233109bdb7212d31013f3eb5772dadb0 to your computer and use it in GitHub Desktop.
Save jmrnilsson/233109bdb7212d31013f3eb5772dadb0 to your computer and use it in GitHub Desktop.
import itertools
import re
import sys
from collections import Counter, defaultdict
from functools import reduce
import numpy as np
from aoc.helpers import timing, loc, Printer, loc_input
# ICE
_default_puzzle_input = "year_2021/sink/day_08.txt"
_default_test_input = "year_2021/sink/day_08_test.txt"
default_puzzle_input = loc_input(__file__, ".txt")
default_test_input = loc_input(__file__, "_test.txt")
default_test_input_2 = loc_input(__file__, "_test_2.txt")
class Translator(object):
def __init__(self):
self.words = []
self.words_per_count = defaultdict(list)
self.seed = {}
self.key = defaultdict(set)
self.known_vector_indices = [(1, 2), (7, 3), (4, 4), (8, 7)]
self.known_vector_indices_map = {v: k for k, v in self.known_vector_indices}
def clear_seed(self):
self.seed.clear()
self.words_per_count.clear()
def _vectorise(self, word):
# Opted for frequency analysis. Vectorisation of character differences is less palatable.
corpus = "".join([word for words in self.words_per_count.values() for word in words])
cumulative_freq = sum(corpus.count(char) for char in list(word))
return cumulative_freq
def vectorise_seed(self):
for word in self.words_per_count[5]:
vector = self._vectorise(word)
self.seed[vector] = word
for word in self.words_per_count[6]:
vector = self._vectorise(word)
self.seed[vector] = word
def solve_vector(self, key_word, solution):
if len(key_word) in {len_ for _, len_ in self.known_vector_indices}:
return
vector = self._vectorise(key_word)
self.key[vector].add(solution)
def solve(self, word):
word_len = len(word)
if known_number := self.known_vector_indices_map.get(word_len):
return known_number
vector = self._vectorise(word)
if number_set := self.key.get(vector):
number, = number_set
return number
return 0
def add_word(self, str_value):
self.words.append(str_value)
self.words_per_count[len(str_value)].append(str_value)
@timing
def solve_2(puzzle_input=None):
"""
Cipher solve of part 2. Works because every answer is listed in test except one (0) in the second part.
"""
translator = Translator()
result_counter = 0
with open(loc(_default_test_input), "r") as fp:
key_lines = [i.strip() for i in fp.readlines()]
with open(loc(_default_puzzle_input), "r") as fp:
lines = [i.strip() for i in fp.readlines()]
for key_line in key_lines:
translator.clear_seed()
input_numbers_text, display_numbers_text = key_line.split(" | ")
diplay_numbers_, solutions_ = display_numbers_text.split(": ")
input_numbers = input_numbers_text.split()
display_numbers = diplay_numbers_.split()
solutions = list(solutions_)
output_solutions = list(zip(display_numbers, solutions))
for number in input_numbers:
translator.add_word(number)
translator.vectorise_seed()
for word, key in output_solutions:
translator.solve_vector(word, int(key))
for line in lines:
translator.clear_seed()
input_numbers_text, display_numbers_text = line.split(" | ")
input_numbers = input_numbers_text.split()
display_numbers = display_numbers_text.split()
for input_number in input_numbers:
translator.add_word(input_number)
translator.vectorise_seed()
result_counter += int("".join(str(translator.solve(display_number)) for display_number in display_numbers))
return result_counter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment