2021-12-13
Created on Monday, December 13, 2021.
Day 13 - Folding like a pro
Right, I've missed about 5 days in a row due to log4j so the explanations are going to be shorter.
We've got a series of fold along instructions. At that point what we're going to have to do is take all the marked dots that are beyond the x or y foldline, and duplicate them below the line.
We're going to use a set of coordinates to indicate each of the (x,y) coords.
When we fold, we'll go through each coordinate and if it's beynd the fold, we create a new coordinate at the equivalent new location. If we hold all the coords in a set (because order doesn't matter), then it will automatically deduplicate the coordinates.
Make sense? Let's describe that with code
## Import ipytest and get it setup for use in Python Notebook
import pytest
import ipytest
ipytest.autoconfig()
from collections import namedtuple
Coord = namedtuple('Coord', ['x', 'y'])
def foldAt(axis, value, coords):
newcoords = set()
for coord in coords:
x = coord.x
y = coord.y
if axis == "x" and x > value:
x = value-(x-value)
if axis == "y" and y > value:
y = value-(y-value)
newcoords.add(Coord(x,y))
return newcoords
def render(coords):
maxy = max(coords, key=lambda a: a.y).y
maxx = max(coords, key=lambda a: a.x).x
s=""
for y in range(maxy+1):
for x in range(maxx+1):
if Coord(x,y) in coords: s+="#"
else: s+="."
s+="\n"
print(s)
# Map a coordinate based on a fold line
coords = {Coord(6,10), Coord(6,12), Coord(6,0)}
assert foldAt("y", 7, coords) == {Coord(6,2), Coord(6,4), Coord(6,0) }
test_coords = {Coord(6,10), Coord(0,14), Coord(9,10), Coord(0,3), Coord(10,4), Coord(4,11), Coord(6,0), Coord(6,12), Coord(4,1), Coord(0,13), Coord(10,12), Coord(3,4), Coord(3,0), Coord(8,4), Coord(1,10), Coord(2,14), Coord(8,10), Coord(9,0)}
render(test_coords)
newtest_coords = foldAt("y", 7, test_coords)
render(newtest_coords)
assert len(newtest_coords) == 17
newtest_coords = foldAt("x", 5, newtest_coords)
render(newtest_coords)
assert len(newtest_coords) == 16
...#..#..#. ....#...... ........... #.......... ...#....#.# ........... ........... ........... ........... ........... .#....#.##. ....#...... ......#...# #.......... #.#........
#.##..#..#. #...#...... ......#...# #...#...... .#.#..#.###
##### #...# #...# #...# #####
Ok, let's try that on test data, remembering that in this case, we only want to apply the first fold instruction
(We're going to need to parse the instructions anyway I suspect)
test_lines = """6,10
0,14
9,10
0,3
10,4
4,11
6,0
6,12
4,1
0,13
10,12
3,4
3,0
8,4
1,10
2,14
8,10
9,0
fold along y=7
fold along x=5""".split("\n")
def parse(lines):
coords = set()
instructions = []
i = 0
while lines[i] != "":
coords.add(Coord(*[int(n) for n in lines[i].split(",")]))
i+=1
i+=1
while i < len(lines):
axis, num = lines[i].split("=")
instructions.append((axis[-1], int(num)))
i+=1
return coords, instructions
coords, instructions = parse(test_lines)
assert coords == test_coords
assert [("y", 7), ("x", 5)] == instructions
assert 17 == len(foldAt(instructions[0][0], instructions[0][1], coords))
Ok, that works, lets try on prod data
lines = [line.strip() for line in open("day13.txt").readlines()]
coords, instructions = parse(lines)
instruction = instructions[0]
print(len(foldAt(instruction[0], instruction[1], coords)))
653
Part 2 Render the Code
Somewhat as expected, do all the folds and then render
lines = [line.strip() for line in open("day13.txt").readlines()]
coords, instructions = parse(lines)
for instruction in instructions:
coords = foldAt(instruction[0], instruction[1], coords)
render(coords)
#....#..#.###..####.###..###..###..#..# #....#.#..#..#.#....#..#.#..#.#..#.#.#. #....##...#..#.###..###..#..#.#..#.##.. #....#.#..###..#....#..#.###..###..#.#. #....#.#..#.#..#....#..#.#....#.#..#.#. ####.#..#.#..#.####.###..#....#..#.#..#
Next
Previous