Skip to content

Commit a64ad6e

Browse files
committed
Added day 2021-20
1 parent 619c852 commit a64ad6e

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

2021/20-Trench Map.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# -------------------------------- Input data ---------------------------------------- #
2+
import os, grid, graph, dot, assembly, re, itertools, copy, functools
3+
from collections import Counter, deque, defaultdict
4+
5+
from compass import *
6+
7+
8+
# This functions come from https://github.com/mcpower/adventofcode - Thanks!
9+
def lmap(func, *iterables):
10+
return list(map(func, *iterables))
11+
12+
13+
def ints(s: str):
14+
return lmap(int, re.findall(r"-?\d+", s)) # thanks mserrano!
15+
16+
17+
def positive_ints(s: str):
18+
return lmap(int, re.findall(r"\d+", s)) # thanks mserrano!
19+
20+
21+
def floats(s: str):
22+
return lmap(float, re.findall(r"-?\d+(?:\.\d+)?", s))
23+
24+
25+
def positive_floats(s: str):
26+
return lmap(float, re.findall(r"\d+(?:\.\d+)?", s))
27+
28+
29+
def words(s: str):
30+
return re.findall(r"[a-zA-Z]+", s)
31+
32+
33+
test_data = {}
34+
35+
test = 1
36+
test_data[test] = {
37+
"input": """..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..#
38+
39+
#..#.
40+
#....
41+
##..#
42+
..#..
43+
..###""",
44+
"expected": ["35", "Unknown"],
45+
}
46+
47+
test = "real"
48+
input_file = os.path.join(
49+
os.path.dirname(__file__),
50+
"Inputs",
51+
os.path.basename(__file__).replace(".py", ".txt"),
52+
)
53+
test_data[test] = {
54+
"input": open(input_file, "r+").read(),
55+
"expected": ["5044", "18074"],
56+
}
57+
58+
59+
# -------------------------------- Control program execution ------------------------- #
60+
61+
case_to_test = "real"
62+
part_to_test = 2
63+
64+
# -------------------------------- Initialize some variables ------------------------- #
65+
66+
puzzle_input = test_data[case_to_test]["input"]
67+
puzzle_expected_result = test_data[case_to_test]["expected"][part_to_test - 1]
68+
puzzle_actual_result = "Unknown"
69+
70+
71+
# -------------------------------- Actual code execution ----------------------------- #
72+
73+
dot.Dot.all_directions = directions_diagonals
74+
all_directions = directions_diagonals
75+
dot.Dot.allowed_direction_map = {
76+
".": {dir: all_directions for dir in all_directions},
77+
"#": {dir: all_directions for dir in all_directions},
78+
}
79+
dot.Dot.terrain_map = {
80+
".": [True, False],
81+
"#": [True, False],
82+
"X": [True, False],
83+
}
84+
85+
86+
def get_neighbors(self):
87+
if self.neighbors_obsolete:
88+
self.neighbors = {}
89+
for direction in self.allowed_directions:
90+
if (self + direction) and (self + direction).is_walkable:
91+
self.neighbors[self + direction] = 1
92+
else:
93+
new_dot = self.__class__(self.grid, self.position + direction, ".")
94+
self.grid.dots[self.position + direction] = new_dot
95+
self.neighbors[self + direction] = 1
96+
97+
self.neighbors_obsolete = False
98+
return self.neighbors
99+
100+
101+
dot.Dot.get_neighbors = get_neighbors
102+
103+
grid.Grid.all_directions = directions_diagonals
104+
105+
dot.Dot.sort_value = dot.Dot.sorting_map["reading"]
106+
107+
if part_to_test == 1:
108+
generations = 2
109+
else:
110+
generations = 50
111+
112+
113+
algorithm = puzzle_input.split("\n")[0]
114+
115+
image = grid.Grid()
116+
image.all_directions = directions_diagonals
117+
image.text_to_dots("\n".join(puzzle_input.split("\n")[2:]))
118+
119+
# print (image.dots_to_text())
120+
121+
for i in range(generations + 5):
122+
dots = image.dots.copy()
123+
[image.dots[x].get_neighbors() for x in dots]
124+
125+
126+
for i in range(generations):
127+
# print ('Generation', i)
128+
new_image = grid.Grid()
129+
new_image.dots = {
130+
x: dot.Dot(new_image, image.dots[x].position, image.dots[x].terrain)
131+
for x in image.dots
132+
}
133+
new_image.all_directions = directions_diagonals
134+
135+
for x in image.dots.copy():
136+
neighbors = [neighbor for neighbor in image.dots[x].get_neighbors()] + [
137+
image.dots[x]
138+
]
139+
text = "".join([neighbor.terrain for neighbor in sorted(neighbors)])
140+
binary = int(text.replace(".", "0").replace("#", "1"), 2)
141+
new_image.dots[x].set_terrain(algorithm[binary])
142+
# print (new_image.dots_to_text())
143+
144+
# Empty borders so they're not counted later
145+
# They use surrounding data (out of image) that default to . and this messes up the rest
146+
# This is done only for odd generations because that's enough (all non-borders get blanked out due to the "." at the end of the algorithm)
147+
if i % 2 == 1:
148+
borders, _ = new_image.get_borders()
149+
borders = functools.reduce(lambda a, b: a + b, borders)
150+
[dot.set_terrain(".") for dot in borders]
151+
152+
image.dots = {
153+
x: dot.Dot(image, new_image.dots[x].position, new_image.dots[x].terrain)
154+
for x in new_image.dots
155+
}
156+
157+
# print ('Lit dots', sum([1 for dot in image.dots if image.dots[dot].terrain == '#']))
158+
159+
# Remove the borders that were added (they shouldn't count because they take into account elements outside the image)
160+
borders, _ = image.get_borders()
161+
borders = functools.reduce(lambda a, b: a + b, borders)
162+
image.dots = {
163+
dot: image.dots[dot] for dot in image.dots if image.dots[dot] not in borders
164+
}
165+
166+
puzzle_actual_result = sum([1 for dot in image.dots if image.dots[dot].terrain == "#"])
167+
168+
169+
# -------------------------------- Outputs / results --------------------------------- #
170+
171+
print("Case :", case_to_test, "- Part", part_to_test)
172+
print("Expected result : " + str(puzzle_expected_result))
173+
print("Actual result : " + str(puzzle_actual_result))
174+
# Date created: 2021-12-20 08:30:35.363096
175+
# Part 1: 2021-12-20 10:19:36
176+
# Part 2: 2021-12-20 10:35:25

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy