Day 17 (Python)
Third time lucky! ... it was not worth staying up until 1am for this
This commit is contained in:
parent
cf15aee7f1
commit
aed18d1ac8
6 changed files with 112 additions and 148 deletions
2
.github/README.md
vendored
2
.github/README.md
vendored
|
@ -32,7 +32,7 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
|
|||
| [14](/14-dockingData) | ![Completed][check] | [Link](/14-dockingData/python) | [Link](/14-dockingData/go) |
|
||||
| [15](/15-rambunctiousRecitation) \* | ![Completed][check] | [Link](/15-rambunctiousRecitation/python) | [Link](/15-rambunctiousRecitation/go) |
|
||||
| [16](/16-ticketTranslation) | ![Partially complete][partial] | [Link](/16-ticketTranslation/python) | |
|
||||
| [17](/17-conwayCubes) | ![Incomplete][cross] | | |
|
||||
| [17](/17-conwayCubes) | ![Partially complete][partial] | [Link](/17-conwayCubes/python) | |
|
||||
| 18 | | | |
|
||||
| 19 | | | |
|
||||
| 20 | | | |
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
# [Day 17: Conway Cubes](https://adventofcode.com/2020/day/17)
|
||||
|
||||
Will be re-attempted at a later date.
|
||||
I would not have got this if it wasn't for [this Reddit comment](https://www.reddit.com/r/adventofcode/comments/kf5mzc/2020_day_17_i_am_now_sad/gg6u25j).
|
||||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
```
|
||||
❯ python .\python\
|
||||
AoC 2020: day 17 - Conway Cubes
|
||||
Python 3.8.5
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 232
|
||||
Part 2: 1620
|
||||
```
|
||||
|
||||
</details>
|
|
@ -9,6 +9,11 @@
|
|||
"expected": 112
|
||||
}
|
||||
],
|
||||
"two": []
|
||||
"two": [
|
||||
{
|
||||
"input": ".#.\n..#\n###\n",
|
||||
"expected": 848
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,49 +1,23 @@
|
|||
from typing import List, Tuple
|
||||
import math
|
||||
from typing import Dict, Tuple, Callable
|
||||
import itertools
|
||||
|
||||
|
||||
active = "#"
|
||||
inactive = "."
|
||||
active_marker = "#"
|
||||
inactive_marker = "."
|
||||
|
||||
|
||||
class Matrix3D:
|
||||
master_array: List[List[List]]
|
||||
x_zero: int
|
||||
y_zero: int
|
||||
z_zero: int
|
||||
|
||||
def __init__(self, x, y, z, default_value=None):
|
||||
self.master_array = [[[default_value for _ in range(x)] for _ in range(y)] for _ in range(z)]
|
||||
self.x_zero = math.floor(len(self.master_array[0][0]) / 2)
|
||||
self.y_zero = math.floor(len(self.master_array[0]) / 2)
|
||||
self.z_zero = math.floor(len(self.master_array) / 2)
|
||||
|
||||
def translate(self, x:int, y:int, z:int) -> Tuple[int, int, int]:
|
||||
x += self.x_zero
|
||||
y += self.y_zero
|
||||
z += self.z_zero
|
||||
return x, y, z
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.master_array)
|
||||
|
||||
def __getitem__(self, location_tuple:Tuple[int, int, int]):
|
||||
x, y, z = location_tuple
|
||||
|
||||
if x < 0 or y < 0 or z < 0:
|
||||
raise IndexError("list index out of range")
|
||||
|
||||
return self.master_array[z][y][x]
|
||||
|
||||
def __setitem__(self, location_tuple:Tuple[int, int, int], value):
|
||||
x, y, z = location_tuple
|
||||
|
||||
if x < 0 or y < 0 or z < 0:
|
||||
raise IndexError("list index out of range")
|
||||
|
||||
self.master_array[z][y][x] = value
|
||||
translation_vectors_3d = [p for p in itertools.product([-1, 0, 1], repeat=3) if p != (0, 0, 0)]
|
||||
translation_vectors_4d = [p for p in itertools.product([-1, 0, 1], repeat=4) if p != (0, 0, 0, 0)]
|
||||
|
||||
|
||||
def parse(instr: str) -> int:
|
||||
def parse(instr: str, key:Callable[[int, int], int]) -> Dict[Tuple[int, int, int], str]:
|
||||
input_lists = [[x for x in y] for y in instr.strip().split("\n")]
|
||||
|
||||
return 0
|
||||
rtvl = {}
|
||||
|
||||
for y, row in enumerate(input_lists):
|
||||
for x, col in enumerate(row):
|
||||
if col != inactive_marker:
|
||||
rtvl[key(x, y)] = col
|
||||
|
||||
return rtvl
|
|
@ -1,115 +1,43 @@
|
|||
from common import *
|
||||
import copy
|
||||
from pprint import pprint
|
||||
from typing import Dict, Tuple
|
||||
|
||||
|
||||
iterations = 6
|
||||
|
||||
translation_vectors = [
|
||||
(-1, 1, 1),
|
||||
(0, 1, 1),
|
||||
(1, 1, 1),
|
||||
(-1, 0, 1),
|
||||
(0, 0, 1),
|
||||
(1, 0, 1),
|
||||
(-1, -1, 1),
|
||||
(0, -1, 1),
|
||||
(1, -1, 1),
|
||||
(-1, 1, -1),
|
||||
(0, 1, -1),
|
||||
(1, 1, -1),
|
||||
(-1, 0, -1),
|
||||
(0, 0, -1),
|
||||
(1, 0, -1),
|
||||
(-1, -1, -1),
|
||||
(0, -1, -1),
|
||||
(1, -1, -1),
|
||||
(-1, 1, 0),
|
||||
(0, 1, 0),
|
||||
(1, 1, 0),
|
||||
(-1, 0, 0),
|
||||
(1, 0, 0),
|
||||
(-1, -1, 0),
|
||||
(0, -1, 0),
|
||||
(1, -1, 0)
|
||||
]
|
||||
|
||||
def find_neighbours(matrix:List[List[List[int]]], raw_point:Tuple[int, int, int]) -> int:
|
||||
x, y, z = raw_point
|
||||
def count_neighbours(matrix:Dict[Tuple[int, int, int], str], position:Tuple[int, int, int]) -> int:
|
||||
num_neighbours = 0
|
||||
for (vx, vy, vz) in translation_vectors:
|
||||
vx += x
|
||||
vy += y
|
||||
vz += z
|
||||
|
||||
if vx < 0 or vy < 0 or vz < 0:
|
||||
continue
|
||||
|
||||
try:
|
||||
current_val = matrix[vz][vy][vx]
|
||||
except IndexError:
|
||||
continue
|
||||
|
||||
if current_val == active:
|
||||
x, y, z = position
|
||||
for (x_delta, y_delta, z_delta) in translation_vectors_3d:
|
||||
if matrix.get((x + x_delta, y+y_delta, z+z_delta), inactive_marker) == active_marker:
|
||||
num_neighbours += 1
|
||||
return num_neighbours
|
||||
|
||||
def iterate(matrix:List[List[List[int]]]) -> List[List[List[int]]]:
|
||||
new = copy.deepcopy(matrix)
|
||||
sz = len(matrix)
|
||||
sy = len(matrix[0])
|
||||
sx = len(matrix[0][0])
|
||||
for z in range(sz):
|
||||
for y in range(sy):
|
||||
for x in range(sx):
|
||||
neighbours = find_neighbours(matrix, (x, y, z))
|
||||
current_state = matrix[z][y][x]
|
||||
if (neighbours == 2 or neighbours == 3) and current_state != active:
|
||||
new[z][x][y] = inactive
|
||||
elif neighbours == 3 and current_state == inactive:
|
||||
new[z][x][y] = active
|
||||
|
||||
def iterate(matrix:Dict[Tuple[int, int, int], str]) -> Dict[Tuple[int, int, int], str]:
|
||||
new = {}
|
||||
|
||||
# get min/max for x, y and z values
|
||||
keys = list(matrix)
|
||||
_, _, min_z = min(keys, key=lambda x: x[2])
|
||||
_, _, max_z = max(keys, key=lambda x: x[2])
|
||||
_, min_y, _ = min(keys, key=lambda x: x[1])
|
||||
_, max_y, _ = max(keys, key=lambda x: x[1])
|
||||
min_x, _, _ = min(keys, key=lambda x: x[0])
|
||||
max_x, _, _ = max(keys, key=lambda x: x[0])
|
||||
|
||||
for z in range(min_z - 2, max_z + 2):
|
||||
for y in range(min_y - 2, max_y + 2):
|
||||
for x in range(min_x - 2, max_x + 2):
|
||||
num_neighbours = count_neighbours(matrix, (x, y, z))
|
||||
current_state = matrix.get((x, y, z), inactive_marker)
|
||||
if (num_neighbours == 2 and current_state == active_marker) or num_neighbours == 3:
|
||||
new[(x, y, z)] = active_marker
|
||||
|
||||
return new
|
||||
|
||||
|
||||
def partOne(instr: str) -> int:
|
||||
matrix = parse(instr, lambda x, y: (x, y, 0))
|
||||
|
||||
input_array = [[y for y in x] for x in instr.strip().split("\n")]
|
||||
|
||||
assert len(input_array) == len(input_array[0]), "input array must be square"
|
||||
input_size = len(input_array)
|
||||
|
||||
# determine matrix size and create
|
||||
size = (iterations * 2) + 1 + len(input_array) # 1 extra col/row/whatever around per iteration
|
||||
if size % 2 != len(input_array) % 2:
|
||||
size += 1 # the len and size must both be even or odd
|
||||
matrix = [[[inactive for _ in range(size)] for _ in range(size)] for _ in range(size)]
|
||||
|
||||
# Load input into center of matrix
|
||||
centerpoint = size / 2
|
||||
centerpoint_mod = len(input_array) / 2
|
||||
start_point = int((centerpoint - centerpoint_mod) - 1)
|
||||
|
||||
center_z = int(size / 2) - 1
|
||||
|
||||
for y in range(input_size):
|
||||
for x in range(input_size):
|
||||
matrix[center_z][y + start_point][x + start_point] = input_array[y][x]
|
||||
|
||||
# Iterate
|
||||
for _ in range(iterations):
|
||||
for _ in range(6):
|
||||
matrix = iterate(matrix)
|
||||
|
||||
# Count active
|
||||
active_count = 0
|
||||
|
||||
sz = len(matrix)
|
||||
sy = len(matrix[0])
|
||||
sx = len(matrix[0][0])
|
||||
for z in range(sz):
|
||||
for y in range(sy):
|
||||
for x in range(sx):
|
||||
if matrix[z][y][x] == active:
|
||||
active_count += 1
|
||||
|
||||
return active_count
|
||||
|
||||
return len(matrix)
|
||||
|
|
|
@ -1,6 +1,45 @@
|
|||
from common import *
|
||||
|
||||
|
||||
def count_neighbours(matrix:Dict[Tuple[int, int, int, int], str], position:Tuple[int, int, int, int]) -> int:
|
||||
num_neighbours = 0
|
||||
x, y, z, w = position
|
||||
for (x_delta, y_delta, z_delta, w_delta) in translation_vectors_4d:
|
||||
if matrix.get((x + x_delta, y+y_delta, z+z_delta, w+w_delta), inactive_marker) == active_marker:
|
||||
num_neighbours += 1
|
||||
return num_neighbours
|
||||
|
||||
|
||||
def iterate(matrix:Dict[Tuple[int, int, int], str]) -> Dict[Tuple[int, int, int], str]:
|
||||
new = {}
|
||||
|
||||
# get min/max for x, y and z values
|
||||
keys = list(matrix)
|
||||
_, _, _, min_w = min(keys, key=lambda x: x[3])
|
||||
_, _, _, max_w = max(keys, key=lambda x: x[3])
|
||||
_, _, min_z, _ = min(keys, key=lambda x: x[2])
|
||||
_, _, max_z, _ = max(keys, key=lambda x: x[2])
|
||||
_, min_y, _, _ = min(keys, key=lambda x: x[1])
|
||||
_, max_y, _, _ = max(keys, key=lambda x: x[1])
|
||||
min_x, _, _, _ = min(keys, key=lambda x: x[0])
|
||||
max_x, _, _, _ = max(keys, key=lambda x: x[0])
|
||||
|
||||
for w in range(min_w - 2, max_w + 2):
|
||||
for z in range(min_z - 2, max_z + 2):
|
||||
for y in range(min_y - 2, max_y + 2):
|
||||
for x in range(min_x - 2, max_x + 2):
|
||||
num_neighbours = count_neighbours(matrix, (x, y, z, w))
|
||||
current_state = matrix.get((x, y, z, w), inactive_marker)
|
||||
if (num_neighbours == 2 and current_state == active_marker) or num_neighbours == 3:
|
||||
new[(x, y, z, w)] = active_marker
|
||||
|
||||
return new
|
||||
|
||||
|
||||
def partTwo(instr: str) -> int:
|
||||
input_list = parse(instr)
|
||||
return 0
|
||||
matrix = parse(instr, lambda x, y: (x, y, 0, 0))
|
||||
|
||||
for _ in range(6):
|
||||
matrix = iterate(matrix)
|
||||
|
||||
return len(matrix)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue