diff --git a/2017/21/21.md b/2017/21/21.md new file mode 100644 index 0000000..bd15a1c --- /dev/null +++ b/2017/21/21.md @@ -0,0 +1,116 @@ +## \-\-- Day 21: Fractal Art \-\-- + +You find a program trying to generate some art. It uses a strange +process that involves [repeatedly +enhancing]{title="This technique is also often used on TV."} the detail +of an image through a set of rules. + +The image consists of a two-dimensional square grid of pixels that are +either on (`#`) or off (`.`). The program always begins with this +pattern: + + .#. + ..# + ### + +Because the pattern is both `3` pixels wide and `3` pixels tall, it is +said to have a *size* of `3`. + +Then, the program repeats the following process: + +- If the size is evenly divisible by `2`, break the pixels up into + `2x2` squares, and convert each `2x2` square into a `3x3` square by + following the corresponding *enhancement rule*. +- Otherwise, the size is evenly divisible by `3`; break the pixels up + into `3x3` squares, and convert each `3x3` square into a `4x4` + square by following the corresponding *enhancement rule*. + +Because each square of pixels is replaced by a larger one, the image +gains pixels and so its *size* increases. + +The artist\'s book of enhancement rules is nearby (your puzzle input); +however, it seems to be missing rules. The artist explains that +sometimes, one must *rotate* or *flip* the input pattern to find a +match. (Never rotate or flip the output pattern, though.) Each pattern +is written concisely: rows are listed as single units, ordered top-down, +and separated by slashes. For example, the following rules correspond to +the adjacent patterns: + + ../.# = .. + .# + + .#. + .#./..#/### = ..# + ### + + #..# + #..#/..../#..#/.##. = .... + #..# + .##. + +When searching for a rule to use, rotate and flip the pattern as +necessary. For example, all of the following patterns match the same +rule: + + .#. .#. #.. ### + ..# #.. #.# ..# + ### ### ##. .#. + +Suppose the book contained the following two rules: + + ../.# => ##./#../... + .#./..#/### => #..#/..../..../#..# + +As before, the program begins with this pattern: + + .#. + ..# + ### + +The size of the grid (`3`) is not divisible by `2`, but it is divisible +by `3`. It divides evenly into a single square; the square matches the +second rule, which produces: + + #..# + .... + .... + #..# + +The size of this enhanced grid (`4`) is evenly divisible by `2`, so that +rule is used. It divides evenly into four squares: + + #.|.# + ..|.. + --+-- + ..|.. + #.|.# + +Each of these squares matches the same rule (`../.# => ##./#../...`), +three of which require some flipping and rotation to line up with the +rule. The output for the rule is the same in all four cases: + + ##.|##. + #..|#.. + ...|... + ---+--- + ##.|##. + #..|#.. + ...|... + +Finally, the squares are joined into a new grid: + + ##.##. + #..#.. + ...... + ##.##. + #..#.. + ...... + +Thus, after `2` iterations, the grid contains `12` pixels that are *on*. + +*How many pixels stay on* after `5` iterations? + +To begin, [get your puzzle input](21/input). + +Answer: + diff --git a/2017/21/solution.py b/2017/21/solution.py new file mode 100644 index 0000000..d743db3 --- /dev/null +++ b/2017/21/solution.py @@ -0,0 +1,145 @@ +#!/bin/python3 +import sys,re, math +from copy import deepcopy +import numpy as np +from pprint import pprint +sys.path.insert(0, '../../') +from fred import list2int, toGrid, nprint,get_re + +input_f = 'test' + +part = 1 +######################################### +# # +# Part 1 # +# # +######################################### + +instructions = {} + +grid = [ + ['.','#','.'], + ['.','.','#'], + ['#','#','#'] +] + +def toSet(input,regex): + set = {} + with open(input) as file: + for line in file: + r = get_re(regex, line.rstrip()) + set[r.group(1).replace('/','')] = r.group(2).replace('/','') + return set + +def need2split(grid): + if len(grid) > 3: + return True + else: + return False + +def grid2line(grid): + line = '' + for i in grid: + line += ''.join(i) + return line + +def line2grid(line): + grid = [] + size = int(math.sqrt(len(line))) + for i in range(size): + grid.append(list(line[i*size:size*(1+i)])) + return grid + +def rotate90(grid): + rotatedGrid = np.array(deepcopy(grid)) + return np.rot90(rotatedGrid) + +def splitGrid(grid): + size = len(grid) + block_size = 0 + if size % 2 == 0: + block_size = 2 + elif size % 3 == 0: + block_size = 3 + else: + print('Grind is wrong at splitGrid()') + + blocks = [] + + for i in range(0, size, block_size): + for j in range(0, size, block_size): + block = [row[j:j+block_size] for row in grid[i:i+block_size]] + #print(block) + for bdx,b in enumerate(block): + block[bdx] = list(b) + #print(block) + #input() + blocks.append(block) + return blocks + +def findInst(grid,instructions): + found = False + new_grid = [] + grid = grid + while not found: + try: + new_grid = instructions[grid2line(grid)] + found = True + except: + grid = rotate90(grid) + return new_grid + +def transform_grid(input_grid): + result = [] + + for half in [input_grid[:2], input_grid[2:]]: + for i in range(3): # Each subgrid has 3 rows + # Merge the rows from the two subgrids in the current half + row = ''.join([''.join(subgrid[i]) for subgrid in half]) + result.append(row) + + return result + +if part == 1: + instructions = toSet(input_f,r"^(.*) => (.*)$") + + print(instructions) + blocks = [] + mixed_grid = [[]] + for i in range(0,5): + size = len(grid) + nprint(grid) + print() + if size % 3 == 0 or size % 2 == 0: + if not need2split(grid): + new_grid = findInst(grid,instructions) + grid = line2grid(new_grid) + #print(grid) + else: + blocks = splitGrid(grid) + #print(blocks) + #print(len(blocks)) + #print(blocks) + print(blocks) + input() + mixed_grid = [] + + + for i in range(0,len(blocks)): + x = line2grid(findInst(blocks[i],instructions)) + + mixed_grid.append(x) + grid = transform_grid(mixed_grid) + #nprint(grid) + #input() + + else: + print('Something is wrong with the grid size of ', size) + #input() +######################################### +# # +# Part 2 # +# # +######################################### +if part == 2: + exit() diff --git a/__pycache__/fred.cpython-311.pyc b/__pycache__/fred.cpython-311.pyc index 55e6bb0..1265de6 100644 Binary files a/__pycache__/fred.cpython-311.pyc and b/__pycache__/fred.cpython-311.pyc differ diff --git a/fred.py b/fred.py index 6d025c3..7c125c4 100644 --- a/fred.py +++ b/fred.py @@ -1,4 +1,22 @@ -import re +import re,sys + +def toGrid(input,parser=None): + grid = [] + if parser: + with open(input) as file: + for line in file: + grid.append(list2int(line.rstrip())) + else: + with open(input) as file: + for line in file: + grid.append(line.rstrip()) + return grid + +def nprint(grid): + for idx,i in enumerate(grid): + for jdx,j in enumerate(i): + print(grid[idx][jdx],end='') + print() def list2int(x): return list(map(int, x))