Skip to content

Commit a981770

Browse files
committed
Added v2 of 2021-20
1 parent 3420f26 commit a981770

File tree

2 files changed

+193
-78
lines changed

2 files changed

+193
-78
lines changed

2021/20-Trench Map.py

Lines changed: 17 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -70,100 +70,39 @@ def words(s: str):
7070

7171
# -------------------------------- Actual code execution ----------------------------- #
7272

73-
dot.Dot.all_directions = directions_diagonals
7473
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
10274

103-
grid.Grid.all_directions = directions_diagonals
104-
105-
dot.Dot.sort_value = dot.Dot.sorting_map["reading"]
10675

10776
if part_to_test == 1:
10877
generations = 2
10978
else:
11079
generations = 50
11180

112-
81+
# Parsing algorithm
11382
algorithm = puzzle_input.split("\n")[0]
11483

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())
84+
rules = {}
85+
for i in range(2 ** 9):
86+
binary = "{0:>09b}".format(i)
87+
text = binary.replace("0", ".").replace("1", "#")
88+
rules[text] = algorithm[i]
12089

121-
for i in range(generations + 5):
122-
dots = image.dots.copy()
123-
[image.dots[x].get_neighbors() for x in dots]
90+
image = grid.GameOfLife(True)
91+
image.set_rules(rules)
92+
image.text_to_dots("\n".join(puzzle_input.split("\n")[2:]))
12493

94+
# Add some margin to make it 'infinite'
95+
image.extend_grid(2)
12596

12697
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)
98+
image.evolve(1)
14799
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-
}
100+
image.reduce_grid(2)
101+
image.extend_grid(2)
102+
103+
image.reduce_grid(2)
165104

166-
puzzle_actual_result = sum([1 for dot in image.dots if image.dots[dot].terrain == "#"])
105+
puzzle_actual_result = image.dots_to_text().count("#")
167106

168107

169108
# -------------------------------- Outputs / results --------------------------------- #

2021/20-Trench Map.v1.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)