advent-of-code/2017-python/solutions/day_21.py

90 lines
2.6 KiB
Python
Raw Normal View History

2021-11-01 16:40:46 +01:00
import collections
from solutions import BaseSolution
class Rule:
size = 0
def __init__(self, line):
pattern, output = line.split(' => ')
self.pattern = pattern.replace('/', '')
self.output = output.replace('/', '')
self.size = int(len(self.pattern) ** 0.5)
self.patterns = [
self.pattern,
self._f(self.pattern),
self._r(self.pattern),
self._f(self._r(self.pattern)),
self._r(self._f(self.pattern)),
self._r(self._r(self.pattern)),
]
def __repr__(self):
return '[{}] {} -> {}'.format(self.size, self.pattern, self.output)
def _r(self, b):
return ''.join(map(lambda g: ''.join(g), zip(*[b[s:s + self.size] for s in range(0, len(b), self.size)][::-1])))
def _f(self, b):
return b[-self.size:] + b[self.size:len(b) - self.size] + b[0:self.size]
def matches(self, canvas):
return canvas in self.patterns
def enhance(self, canvas):
return self.output
class Solution(BaseSolution):
input_file = '21.txt'
def __str__(self):
return 'Day 21: Fractal Art'
def _get_block(self, canvas, size, n=0):
s = ''
cl = int(len(canvas) ** 0.5)
x = n % (cl // size)
y = n // (cl // size)
for r in range(size):
start = cl * ((y * size) + r) + (x * size)
end = start + size
s += canvas[start:end]
return s
def _join_blocks(self, blocks):
bl = len(blocks)
c = int(bl ** 0.5)
rl = int(len(blocks[0]) ** 0.5)
canvas = ''
for i in range(0, bl, c):
for j in range(rl):
canvas += ''.join([block[j * rl:(j + 1) * rl] for block in blocks[i:i + c]])
return canvas
def solve(self, puzzle_input, iterations=5):
canvas = '.#...####'
rules = [Rule(l.strip()) for l in puzzle_input.splitlines()]
for _ in range(iterations):
size = 2 if len(canvas) % 2 == 0 else 3
blocks = len(canvas) // (size ** 2)
cb = []
for b in range(blocks):
bc = self._get_block(canvas, size, b)
rule = [r for r in rules if r.matches(bc) and r.size == size]
if len(rule) > 0:
r = rule[0]
cb.append(r.enhance(bc))
canvas = self._join_blocks(cb)
return collections.Counter(canvas)['#']
def solve_again(self, puzzle_input):
return self.solve(puzzle_input, 18)
if __name__ == '__main__':
solution = Solution()
solution.show_results()