Compare commits

...

10 Commits

13 changed files with 1105 additions and 359 deletions

182
d16_old.py Normal file
View File

@ -0,0 +1,182 @@
from collections import deque
from itertools import product
from tools.aoc import AOCDay
from typing import Any
from tools.tools import Cache
class Valve:
def __init__(self, name: str, flowrate: int):
self.name: str = name
self.flowrate: int = flowrate
self.tunnels: set = set()
class Tunnel:
def __init__(self, target: Valve, length: int = 1):
self.target: Valve = target
self.length: int = length
def __str__(self):
return f"Tunnel(target={self.target.name}, length={self.length})"
def __repr__(self):
return str(self)
def get_openable_valve_tunnels(valve: Valve, open_valves: set, time_remaining: int) -> set:
tunnels = set()
queue = deque()
visited = set()
queue.append((0, valve))
while queue:
d, v = queue.popleft()
if v.name in visited:
continue
visited.add(v.name)
if v.name not in open_valves and d + 1 <= time_remaining:
tunnels.add((d, v))
for x in v.tunnels:
queue.append((d + x.length, x.target))
return tunnels
def get_max_flow(valve: Valve, open_valves: list, time_remaining: int = 30, depth: int = 0) -> int:
max_flow = 0
ov = {t for t in valve.tunnels if t.target not in open_valves and t.length < time_remaining - 2}
if time_remaining <= 0 or not ov:
return 0
for tunnel in ov:
this_open_flow = tunnel.target.flowrate * (time_remaining - tunnel.length - 1)
this_flow = get_max_flow(tunnel.target, open_valves + [tunnel.target], time_remaining - tunnel.length - 1, depth + 1)
if this_flow + this_open_flow > max_flow:
max_flow = this_flow + this_open_flow
return max_flow
def get_max_flow_double(valve1: Valve, valve2: Valve, open_valves: list, DP: dict, time_remaining_1: int = 26, time_remaining_2: int = 26, depth: int = 0) -> int:
dp_key = valve1.name + valve2.name + "%02d" % time_remaining_1 + "%02d" % time_remaining_2 + "".join(open_valves)
dp_key2 = valve2.name + valve1.name + "%02d" % time_remaining_1 + "%02d" % time_remaining_2 + "".join(open_valves)
if dp_key in DP:
return DP[dp_key]
if time_remaining_1 <= 0 and time_remaining_2 <= 0:
return 0
ov1 = {t for t in valve1.tunnels if t.target.name not in open_valves and t.length < time_remaining_1 - 2}
ov2 = {t for t in valve2.tunnels if t.target.name not in open_valves and t.length < time_remaining_2 - 2}
if not ov1 and not ov2:
return 0
if not ov1:
ov1 = {Tunnel(valve1, 99)}
if not ov2:
ov2 = {Tunnel(valve2, 99)}
permut = product(ov1, ov2)
max_flow = 0
for v1, v2 in permut:
if v1.target.name == v2.target.name:
continue
this_open_flow = 0
t1 = valve1
if v1.length + 2 <= time_remaining_1:
this_open_flow += v1.target.flowrate * (time_remaining_1 - v1.length - 1)
t1 = v1.target
t2 = valve2
if v2.length + 2 <= time_remaining_2:
this_open_flow += v2.target.flowrate * (time_remaining_2 - v2.length - 1)
t2 = v2.target
this_flow_rate = get_max_flow_double(
t1,
t2,
sorted(open_valves + [v1.target.name, v2.target.name]),
DP,
time_remaining_1 - v1.length - 1,
time_remaining_2 - v2.length - 1,
depth + 1
)
if this_flow_rate + this_open_flow > max_flow:
max_flow = this_flow_rate + this_open_flow
DP[dp_key] = max_flow
DP[dp_key2] = max_flow
return max_flow
class Day(AOCDay):
inputs = [
[
(1651, "input16_test"),
#(1947, "input16_dennis"),
(1850, "input16"),
],
[
(1707, "input16_test"),
(2556, "input16_dennis"),
(2306, "input16"),
]
]
def get_valve_graph(self) -> Valve:
valves = {}
tmp_tunnels = {}
for line in self.getInput():
p = line.split(" ")
valve_name = p[1]
flowrate = int(p[4][5:-1])
tunnels = "".join(p[9:]).split(",")
valves[valve_name] = Valve(valve_name, flowrate)
tmp_tunnels[valve_name] = tunnels
for name, tunnels in tmp_tunnels.items():
valves[name].tunnels = {Tunnel(valves[t]) for t in tunnels}
for valve in valves.values():
tunnels = set()
queue = deque()
visited = set()
queue.append((0, valve))
while queue:
d, v = queue.popleft()
if v in visited:
continue
visited.add(v)
if v != valve and v.flowrate > 0:
tunnels.add(Tunnel(v, d))
for x in v.tunnels:
queue.append((d + 1, x.target))
tmp_tunnels[valve.name] = tunnels
for name, tunnels in tmp_tunnels.items():
valves[name].tunnels = tunnels
return valves["AA"]
def part1(self) -> Any:
return get_max_flow(self.get_valve_graph(), [])
def part2(self) -> Any:
cache = Cache()
root = self.get_valve_graph()
return get_max_flow_double(root, root, [], cache)
if __name__ == '__main__':
day = Day(2022, 16)
day.run(verbose=True)

274
day16.py
View File

@ -1,124 +1,151 @@
from collections import deque
from itertools import product
import heapq
import itertools
import re
from tools.aoc import AOCDay
from typing import Any
from tools.tools import Cache
class Valve:
def __init__(self, name: str, flowrate: int):
self.name: str = name
self.flowrate: int = flowrate
self.tunnels: set = set()
def __init__(self, name: str, flowrate: int) -> None:
self.__name = name
self.__flowrate = flowrate
self.neighbours = {}
@property
def flowrate(self) -> int:
return self.__flowrate
@property
def name(self) -> str:
return self.__name
def shortest_path_to(self, other: 'Valve'):
if other in self.neighbours:
return self.neighbours[other]
current = self
v = set()
v.add(current)
q = [(v, k) for k, v in self.neighbours.items()]
heapq.heapify(q)
while q:
dist, current = heapq.heappop(q)
if current == other:
return dist
if current in v:
continue
v.add(current)
for n, d in current.neighbours.items():
heapq.heappush(q, (dist + d, n))
def __lt__(self, other: 'Valve') -> bool:
return self.__name < other.__name
def __repr__(self) -> str:
return "Valve(%s;%s)" % (self.__name, self.__flowrate)
def __str__(self) -> str:
return self.__repr__()
class Tunnel:
def __init__(self, target: Valve, length: int = 1):
self.target: Valve = target
self.length: int = length
def get_most_pressure_release_solo(root: Valve, remaining_minutes: int = 30, visited: set = None) -> int:
if visited is None:
visited = set()
visited.add(root)
def __str__(self):
return f"Tunnel(target={self.target.name}, length={self.length})"
my_flowrate = 0
if root.flowrate > 0:
remaining_minutes -= 1
my_flowrate = root.flowrate * remaining_minutes
def __repr__(self):
return str(self)
def get_openable_valve_tunnels(valve: Valve, open_valves: set, time_remaining: int) -> set:
tunnels = set()
queue = deque()
visited = set()
queue.append((0, valve))
while queue:
d, v = queue.popleft()
if v.name in visited:
max_flowrate = 0
for n, d in root.neighbours.items():
if n in visited:
continue
visited.add(v.name)
if v.name not in open_valves and d + 2 <= time_remaining:
tunnels.add((d, v))
for x in v.tunnels:
queue.append((d + x.length, x.target))
return tunnels
if remaining_minutes <= d + 1:
continue
n_flowrate = get_most_pressure_release_solo(n, remaining_minutes - d, visited.copy())
if n_flowrate > max_flowrate:
max_flowrate = n_flowrate
return max_flowrate + my_flowrate
def get_max_flow(valve: Valve, open_valves: list, time_remaining: int = 30, depth: int = 0) -> int:
max_flow = 0
def get_mode_pressure_release_double(root_me: Valve, root_ele: Valve, r_min_me: int = 26, r_min_ele: int = 26, visited: set = None) -> int:
dp_key = root_me.name + root_ele.name + "%02d" % r_min_me + "%02d" % r_min_ele + "".join(v.name for v in sorted(visited))
dp_key2 = root_ele.name + root_me.name + "%02d" % r_min_me + "%02d" % r_min_ele + "".join(v.name for v in sorted(visited))
ov = {t for t in valve.tunnels if t.target not in open_valves and t.length < time_remaining - 2}
if time_remaining <= 0 or not ov:
return 0
for tunnel in ov:
this_open_flow = tunnel.target.flowrate * (time_remaining - tunnel.length - 1)
this_flow = get_max_flow(tunnel.target, open_valves + [tunnel.target], time_remaining - tunnel.length - 1, depth + 1)
if this_flow + this_open_flow > max_flow:
max_flow = this_flow + this_open_flow
return max_flow
def get_max_flow_double(valve1: Valve, valve2: Valve, open_valves: list, DP: dict, time_remaining_1: int = 26, time_remaining_2: int = 26, depth: int = 0) -> int:
dp_key = valve1.name + valve2.name + "%02d" % time_remaining_1 + "%02d" % time_remaining_2 + "".join(open_valves)
dp_key2 = valve2.name + valve1.name + "%02d" % time_remaining_1 + "%02d" % time_remaining_2 + "".join(open_valves)
if dp_key in DP:
return DP[dp_key]
if time_remaining_1 <= 0 and time_remaining_2 <= 0:
my_flowrate = 0
if r_min_me > 1 and root_me not in visited:
visited.add(root_me)
r_min_me -= 1
my_flowrate += root_me.flowrate * r_min_me
if r_min_ele > 1 and root_ele not in visited:
visited.add(root_ele)
r_min_ele -= 1
my_flowrate += root_ele.flowrate * r_min_ele
if not my_flowrate and root_me.name != 'AA':
return 0
ov1 = {t for t in valve1.tunnels if t.target.name not in open_valves and t.length < time_remaining_1 - 2}
ov2 = {t for t in valve2.tunnels if t.target.name not in open_valves and t.length < time_remaining_2 - 2}
max_flowrate = 0
rem_list = [x for x in root_me.neighbours.keys() if x not in visited]
if len(rem_list) == 1:
if root_me.neighbours[rem_list[0]] < root_ele.neighbours[rem_list[0]]:
max_flowrate = get_mode_pressure_release_double(rem_list[0], root_ele, r_min_me - root_me.neighbours[rem_list[0]], r_min_ele, visited.copy())
else:
max_flowrate = get_mode_pressure_release_double(root_me, rem_list[0], r_min_me, r_min_ele - root_ele.neighbours[rem_list[0]], visited.copy())
else:
max_prod = len(rem_list) ** 2
cur_prod = 0
for v1, v2 in itertools.product(rem_list, repeat=2):
if len(visited) == 1:
cur_prod += 1
print("Iter (%d/%d)" % (cur_prod, max_prod))
if v1 == v2:
continue
if not ov1 and not ov2:
return 0
me, ele = v1, v2
if r_min_me <= root_me.neighbours[me] + 1:
me = root_me
if not ov1:
ov1 = {Tunnel(valve1, 99)}
if r_min_ele <= root_ele.neighbours[ele] + 1:
ele = root_ele
if not ov2:
ov2 = {Tunnel(valve2, 99)}
if me == root_me and ele == root_ele:
continue
permut = product(ov1, ov2)
n_flowrate = get_mode_pressure_release_double(
me, ele,
r_min_me - (root_me.neighbours[me] if me in root_me.neighbours else 1),
r_min_ele - (root_ele.neighbours[ele] if ele in root_ele.neighbours else 1),
visited.copy()
)
if n_flowrate > max_flowrate:
max_flowrate = n_flowrate
max_flow = 0
for v1, v2 in permut:
if v1.target.name == v2.target.name:
continue
if n_flowrate == 1671:
break
this_open_flow = 0
DP[dp_key] = my_flowrate + max_flowrate
DP[dp_key2] = my_flowrate + max_flowrate
return my_flowrate + max_flowrate
t1 = valve1
if v1.length + 2 <= time_remaining_1:
this_open_flow += v1.target.flowrate * (time_remaining_1 - v1.length - 1)
t1 = v1.target
t2 = valve2
if v2.length + 2 <= time_remaining_2:
this_open_flow += v2.target.flowrate * (time_remaining_2 - v2.length - 1)
t2 = v2.target
this_flow_rate = get_max_flow_double(
t1,
t2,
sorted(open_valves + [v1.target.name, v2.target.name]),
DP,
time_remaining_1 - v1.length - 1,
time_remaining_2 - v2.length - 1,
depth + 1
)
if this_flow_rate + this_open_flow > max_flow:
max_flow = this_flow_rate + this_open_flow
DP[dp_key] = max_flow
DP[dp_key2] = max_flow
return max_flow
DP = {}
class Day(AOCDay):
input_regexp = re.compile(r'Valve ([A-Z][A-Z]) has flow rate=([0-9]+); tunnels? leads? to valves? (.*)')
inputs = [
[
(1651, "input16_test"),
@ -132,49 +159,54 @@ class Day(AOCDay):
]
]
def get_valve_graph(self) -> Valve:
def parse_input(self) -> Valve:
n_cache = {}
valves = {}
tmp_tunnels = {}
for line in self.getInput():
p = line.split(" ")
valve_name = p[1]
flowrate = int(p[4][5:-1])
tunnels = "".join(p[9:]).split(",")
valves[valve_name] = Valve(valve_name, flowrate)
tmp_tunnels[valve_name] = tunnels
name, flowrate, neighbours = self.input_regexp.match(line).groups()
valves[name] = Valve(name, int(flowrate))
n_cache[name] = neighbours.split(", ")
for name, tunnels in tmp_tunnels.items():
valves[name].tunnels = {Tunnel(valves[t]) for t in tunnels}
for valve, neighbours in n_cache.items():
for n in neighbours:
valves[valve].neighbours[valves[n]] = 1
for valve in valves.values():
tunnels = set()
queue = deque()
visited = set()
queue.append((0, valve))
while queue:
d, v = queue.popleft()
if v in visited:
if valve.flowrate != 0:
continue
for n_set in valve.neighbours.keys():
del n_set.neighbours[valve]
for n_get in valve.neighbours.keys():
if n_get == n_set:
continue
if n_get in n_set.neighbours:
continue
n_set.neighbours[n_get] = valve.neighbours[n_set] + valve.neighbours[n_get]
for v_set in valves.values():
for v_get in valves.values():
if v_set == v_get or v_get in v_set.neighbours or v_get.flowrate == 0:
continue
visited.add(v)
if v != valve and v.flowrate > 0:
tunnels.add(Tunnel(v, d))
for x in v.tunnels:
queue.append((d + 1, x.target))
tmp_tunnels[valve.name] = tunnels
v_set.neighbours[v_get] = v_set.shortest_path_to(v_get)
for name, tunnels in tmp_tunnels.items():
valves[name].tunnels = tunnels
for n in list(valves['AA'].neighbours.keys()):
if n.flowrate == 0:
del valves['AA'].neighbours[n]
return valves["AA"]
return valves['AA']
def part1(self) -> Any:
return get_max_flow(self.get_valve_graph(), [])
return get_most_pressure_release_solo(self.parse_input())
def part2(self) -> Any:
cache = Cache()
root = self.get_valve_graph()
return get_max_flow_double(root, root, [], cache)
global DP
DP = {}
root_valve = self.parse_input()
return get_mode_pressure_release_double(root_valve, root_valve, visited={root_valve})
if __name__ == '__main__':

387
day22.py
View File

@ -1,233 +1,42 @@
import re
from tools.aoc import AOCDay
from tools.coordinate import Coordinate
from tools.grid import Grid
from tools.grid import Grid, GridTransformation
from typing import Any
FACING = [
Coordinate(1, 0),
Coordinate(0, 1),
Coordinate(-1, 0),
Coordinate(0, -1)
Coordinate(1, 0, 0),
Coordinate(0, 1, 0),
Coordinate(-1, 0, 0),
Coordinate(0, -1, 0)
]
CUBE_CONNECTIONS = {
'##./.#./.##/..#': (
((0, 0, 1), (1, 1, 0)),
((0, 0, 2), (1, 2, 0)),
((0, 0, 3), (2, 3, 3)),
((1, 0, 0), (2, 2, 2)),
((1, 0, 3), (2, 3, 2)),
((1, 1, 0), (2, 2, 3)),
((1, 1, 2), (0, 0, 3)),
((1, 2, 2), (0, 0, 0)),
((1, 2, 3), (2, 3, 0)),
((2, 2, 0), (0, 1, 2)),
((2, 2, 3), (1, 1, 2)),
((2, 3, 0), (1, 0, 3)),
((2, 3, 1), (0, 0, 1)),
((2, 3, 2), (1, 2, 3)),
),
'..#./###./..##': (
((2, 0, 0), (3, 2, 2)),
((2, 0, 2), (1, 1, 1)),
((2, 0, 3), (0, 1, 1)),
((0, 1, 1), (2, 2, 3)),
((0, 1, 2), (3, 2, 3)),
((0, 1, 3), (2, 0, 1)),
((1, 1, 1), (2, 2, 0)),
((1, 1, 3), (2, 0, 0)),
((2, 1, 0), (3, 2, 1)),
((2, 2, 1), (0, 1, 3)),
((2, 2, 2), (1, 1, 3)),
((3, 2, 0), (2, 0, 2)),
((3, 2, 1), (0, 1, 0)),
((3, 2, 3), (2, 1, 2)),
),
'.#./.#./###/#..': (
((1, 0, 0), (2, 2, 2)),
((1, 0, 2), (0, 2, 0)),
((1, 0, 3), (0, 3, 0)),
((1, 1, 0), (2, 2, 3)),
((1, 1, 2), (0, 2, 1)),
((0, 2, 2), (1, 0, 0)),
((0, 2, 3), (1, 1, 0)),
((1, 2, 1), (0, 3, 2)),
((2, 2, 0), (1, 0, 2)),
((2, 2, 1), (0, 3, 3)),
((2, 2, 3), (1, 1, 2)),
((0, 3, 0), (1, 2, 3)),
((0, 3, 1), (2, 2, 1)),
((0, 3, 2), (1, 0, 1)),
),
}
def get_password_from_coord(c: Coordinate, face: int) -> int:
return (c.y + 1) * 1000 + (c.x + 1) * 4 + face
def get_cube_conn_dict(cube_conn: tuple, c_size: int) -> dict:
conn_dict = {}
for conn in cube_conn:
cur, tar = conn
cur_x, cur_y, cur_f = cur
tar_x, tar_y, tar_f = tar
match cur_f, tar_f:
case 0, 1:
x = (cur_x + 1) * c_size - 1
ty = tar_y * c_size
for d in range(c_size):
y = cur_y * c_size + d
tx = (tar_x + 1) * c_size - (d + 1)
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 0, 2:
x = (cur_x + 1) * c_size - 1
tx = (tar_x + 1) * c_size - 1
for dy in range(c_size):
y = cur_y * c_size + dy
ty = tar_y * c_size + dy
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 0, 3:
x = (cur_x + 1) * c_size - 1
ty = tar_y * c_size
for dy in range(c_size):
y = cur_y * c_size + dy
tx = tar_x * c_size + dy
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 1, 0:
y = (cur_y + 1) * c_size - 1
tx = tar_x * c_size
for dy in range(c_size):
x = cur_x * c_size + dy
ty = tar_y * c_size + dy
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 1, 1:
y = (cur_y + 1) * c_size - 1
ty = tar_y * c_size
for dx in range(c_size):
x = cur_x * c_size + dx
tx = tar_x * c_size + dx
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 1, 2:
y = (cur_y + 1) * c_size - 1
tx = (tar_x + 1) * c_size - 1
for d in range(c_size):
x = cur_x * c_size + d
ty = tar_y * c_size + d
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 1, 3:
y = (cur_y + 1) * c_size - 1
ty = (tar_y + 1) * c_size - 1
for d in range(c_size):
x = cur_x * c_size + d
tx = tar_x * c_size + d
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 2, 0:
x = cur_x * c_size
tx = tar_x * c_size
for dy in range(c_size):
y = cur_y * c_size + dy
ty = tar_y * c_size + dy
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 2, 1:
x = cur_x * c_size
ty = tar_y * c_size
for d in range(c_size):
y = cur_y * c_size + d
tx = tar_x * c_size + d
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 2, 3:
x = cur_x * c_size
ty = (tar_y + 1) * c_size - 1
for dy in range(c_size):
y = cur_y * c_size + dy
tx = tar_x * c_size + dy
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 3, 0:
y = cur_y * c_size
tx = tar_x * c_size
for d in range(c_size):
x = cur_x * c_size + d
ty = tar_y * c_size + d
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 3, 1:
y = cur_y * c_size
ty = (tar_y + 1) * c_size - 1
for d in range(c_size):
x = cur_x * c_size + d
tx = tar_x * c_size + d
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 3, 2:
y = cur_y * c_size
tx = (tar_x + 1) * c_size - 1
for d in range(c_size):
x = cur_x * c_size + d
ty = (tar_y + 1) * c_size - (d + 1)
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case 3, 3:
y = cur_y * c_size
ty = tar_y * c_size
for d in range(c_size):
x = cur_x * c_size + d
tx = tar_x * c_size + d
conn_dict[(x, y, cur_f)] = (Coordinate(tx, ty), tar_f)
case _:
print("Missing case:", cur_f, tar_f)
return conn_dict
def identify_cube(board: Grid) -> dict:
for i in ((4, 3), (3, 4), (2, 5), (5, 2)):
if (board.maxX + 1) % i[0] != 0 or (board.maxY + 1) % i[1] != 0:
continue
x_size, y_size = (board.maxX + 1) // i[0], (board.maxY + 1) // i[1]
if x_size != y_size:
continue # this cannot be a cube
x_tiles, y_tiles = (board.maxX + 1) // x_size, (board.maxY + 1) // y_size
cube_grid = Grid()
for x in range(x_tiles):
for y in range(y_tiles):
cube_grid.set(Coordinate(x, y), board.get(Coordinate(x * x_size, y * y_size)) is not None)
if cube_grid.getOnCount() != 6:
continue
cube_grid.print(true_char='#')
if str(cube_grid) in CUBE_CONNECTIONS:
return get_cube_conn_dict(CUBE_CONNECTIONS[str(cube_grid)], x_size)
print("Unknown Cube-Shape")
def walk(board: Grid, pos: Coordinate, directions: list, face: int = 0, connections: dict = None) -> (Coordinate, int):
def walk(board: Grid, pos: Coordinate, directions: list) -> (Coordinate, int):
face = 0
for direction in directions:
steps, turn = direction
print("starting at", pos, "moving", steps, "steps, then turning", turn)
for _ in range(steps):
next_pos = pos + FACING[face]
next_face = face
if board.get(next_pos) is None or not board.isWithinBoundaries(next_pos):
if connections is not None:
next_pos, next_face = connections[(pos.x, pos.y, face)]
print("wrapping from", pos, "to", next_pos, "facing", next_face)
else:
match face:
case 0:
next_pos = Coordinate(0, next_pos.y)
case 1:
next_pos = Coordinate(next_pos.x, 0)
case 2:
next_pos = Coordinate(board.maxX, next_pos.y)
case 3:
next_pos = Coordinate(next_pos.x, board.maxY)
while board.get(next_pos) is None:
next_pos += FACING[face]
match face:
case 0:
next_pos = Coordinate(0, next_pos.y, 0)
case 1:
next_pos = Coordinate(next_pos.x, 0, 0)
case 2:
next_pos = Coordinate(board.maxX, next_pos.y, 0)
case 3:
next_pos = Coordinate(next_pos.x, board.maxY, 0)
while board.get(next_pos) is None:
next_pos += FACING[face]
next_val = board.get(next_pos)
if not next_val:
@ -242,29 +51,121 @@ def walk(board: Grid, pos: Coordinate, directions: list, face: int = 0, connecti
return pos, face
def cube_walk(board: Grid, pos: Coordinate, directions: list) -> (Coordinate, int):
face = 0
for direction in directions:
steps, turn = direction
for _ in range(steps):
next_pos = pos + FACING[face]
if board.get(next_pos) is False:
break
elif board.get(next_pos) is None:
match face:
case 0: # right
if board.get(Coordinate(pos.x + 1, pos.y, 1)) is True:
board.transform(GridTransformation.COUNTER_ROTATE_Y)
next_pos = Coordinate(1, pos.y, 0)
else:
break
case 1: # down
if board.get(Coordinate(pos.x, pos.y + 1, 1)) is True:
board.transform(GridTransformation.ROTATE_X)
next_pos = Coordinate(pos.x, 1, 0)
else:
break
case 2: # left
if board.get(Coordinate(0, pos.y, 1)) is True:
board.transform(GridTransformation.ROTATE_Y)
next_pos = Coordinate(board.maxX - 1, pos.y, 0)
else:
break
case 3: # up
if board.get(Coordinate(pos.x, 0, 1)) is True:
board.transform(GridTransformation.COUNTER_ROTATE_X)
next_pos = Coordinate(pos.x, board.maxY - 1, 0)
else:
break
pos = next_pos
if turn != 'S':
face = (face + (1 if turn == 'R' else -1)) % 4
return pos, face
def fold(board: Grid, start_pos: Coordinate):
c_size = 4 if board.maxX < 40 else 50 # account for test case
if board.get(start_pos + Coordinate(-1, 0, 0)) is not None:
for y in board.rangeY():
for x in range(start_pos.x - 1, board.minX - 1, -1):
from_c = Coordinate(x, y, 0)
to_c = Coordinate(start_pos.x - 1, y, start_pos.x - x)
board.set(to_c, board.get(from_c))
board.set(from_c, None)
board.recalcBoundaries()
board.transform(GridTransformation.ROTATE_Y)
board.shift(shift_z=-board.minZ)
fold(board, Coordinate(board.maxX - c_size, 1, 0))
board.transform(GridTransformation.COUNTER_ROTATE_Y)
board.shift_zero()
start_pos = Coordinate(1, 1, 0)
if board.get(start_pos + Coordinate(c_size, 0, 0)) is not None:
for y in range(board.maxY + 1):
for x in range(start_pos.x + c_size, board.maxX + 1):
from_c = Coordinate(x, y, 0)
to_c = Coordinate(start_pos.x + c_size, y, x - start_pos.x - c_size + 1)
board.set(to_c, board.get(from_c))
board.set(from_c, None)
board.recalcBoundaries()
board.transform(GridTransformation.COUNTER_ROTATE_Y)
board.shift(shift_z=-board.minZ)
fold(board, Coordinate(1, 1, 0))
board.transform(GridTransformation.ROTATE_Y)
board.shift_zero()
if board.get(Coordinate(start_pos.x, 0, 0)) is not None:
board.shift(shift_y=1)
if list(board.getActiveCells(x=0, z=0)):
board.shift(shift_x=1)
if board.get(start_pos + Coordinate(0, c_size, 0)) is not None:
for y in range(start_pos.y + c_size, board.maxY + 1):
for x in board.rangeX():
from_c = Coordinate(x, y, 0)
to_c = Coordinate(x, start_pos.y + c_size, y - start_pos.y - c_size + 1)
board.set(to_c, board.get(from_c))
board.set(from_c, None)
board.recalcBoundaries()
board.transform(GridTransformation.ROTATE_X)
fold(board, start_pos)
board.transform(GridTransformation.COUNTER_ROTATE_X)
class Day(AOCDay):
inputs = [
[
(6032, "input22_test"),
(191010, "input22_dennis"),
(1428, "input22"),
],
[
(5031, "input22_test"),
(None, "input22"),
(55364, "input22_dennis"),
(142380, "input22"),
]
]
def get_map_and_directions(self) -> (Grid, list, Coordinate):
board_map = Grid(None)
start_pos = None
map_lines, dir_line = self.getMultiLineInputAsArray()
for y, map_line in enumerate(map_lines):
for x, v in enumerate(map_line):
if v in ['#', '.']:
c = Coordinate(x, y)
if start_pos is None and v == '.':
start_pos = c
board_map.set(c, v == '.')
board = Grid.from_str("/".join(map_lines), default=None, translate={' ': None, '#': False, '.': True}, mode3d=True)
for x in board.rangeX():
if board.get(Coordinate(x, 0, 0)) is not None:
start_pos = Coordinate(x, 0, 0)
break
if dir_line[0][-1] not in ['R', 'L']:
dir_line[0] += 'S'
@ -272,29 +173,43 @@ class Day(AOCDay):
for d in re.findall(r'\d+[RLS]', dir_line[0]):
directions.append((int(d[:-1]), d[-1]))
return board_map, directions, start_pos
return board, directions, start_pos
def part1(self) -> Any:
board_map, directions, start_position = self.get_map_and_directions()
finish, face = walk(board_map, start_position, directions)
board, directions, start_position = self.get_map_and_directions()
finish, face = walk(board, start_position, directions)
return get_password_from_coord(finish, face)
def part2(self) -> Any:
board_map, directions, start_position = self.get_map_and_directions()
conn = identify_cube(board_map)
for x in board_map.rangeX():
c = Coordinate(x, 0)
if board_map.get(c) is not None:
start_position = c
break
print(board_map.minX, board_map.minY, board_map.maxX, board_map.maxY)
print(start_position)
print(board_map.get(Coordinate(4, 0)))
print(conn)
board_map.print(true_char='.')
finish, face = walk(board_map, start_position, directions, 0, conn)
print(finish, face)
print(get_password_from_coord(finish, face))
board, directions, start_position = self.get_map_and_directions()
board.shift(shift_x=1, shift_y=1)
start_position += Coordinate(1, 1, 0)
fold(board, start_position)
finish, face = cube_walk(board, Coordinate(1, 1, 0), directions)
orig_board, _, _ = self.get_map_and_directions()
c_size = 4 if orig_board.maxX < 50 else 50 # account for test case
for x in range(0, orig_board.maxX + 1, c_size):
for y in range(0, orig_board.maxY + 1, c_size):
check_pos = finish - Coordinate(1, 1, 0)
check_face = face
sub_board = orig_board.sub_grid(x, y, x + c_size - 1, y + c_size - 1, 0, 0)
if len(sub_board.getActiveCells()) == 0:
continue
check_board = board.sub_grid(1, 1, c_size, c_size, 0, 0)
for _ in range(2):
for _ in range(4):
check_board.transform(GridTransformation.ROTATE_Z)
check_pos = Coordinate(-check_pos.y + sub_board.maxY, check_pos.x, 0)
check_face = (check_face + 1) % 4
if sub_board == check_board:
check_pos += Coordinate(x, y, 0)
return get_password_from_coord(check_pos, check_face)
check_board.transform(GridTransformation.FLIP_X)
check_pos = Coordinate(abs(check_pos.x - c_size + 1), check_pos.y, 0)
check_face = (check_face + 2) % 4
return ""

View File

@ -52,16 +52,18 @@ class Day(AOCDay):
[
(25, "input23_test_small"),
(110, "input23_test"),
(4070, "input23_dennis"),
(3766, "input23"),
],
[
(20, "input23_test"),
(881, "input23_dennis"),
(954, "input23"),
]
]
def part1(self) -> Any:
map = Grid.from_str("/".join(self.getInput()), true_char='#')
map = Grid.from_str("/".join(self.getInput()), translate={'#': True, '.': False})
for i in range(10):
if not move_elfs(map, i):
@ -71,7 +73,7 @@ class Day(AOCDay):
return (map.maxX - map.minX + 1) * (map.maxY - map.minY + 1) - map.getOnCount()
def part2(self) -> Any:
map = Grid.from_str("/".join(self.getInput()), true_char='#')
map = Grid.from_str("/".join(self.getInput()), translate={'#': True, '.': False})
round = 0
while move_elfs(map, round):

109
day24.py Normal file
View File

@ -0,0 +1,109 @@
from heapq import heappush, heappop
from tools.aoc import AOCDay
from tools.coordinate import Coordinate
from tools.grid import Grid
from typing import Any
def expand_valley(valley: Grid, to_z: int) -> None:
while valley.maxZ <= to_z:
for blizzard_pos in valley.getActiveCells(z=valley.maxZ):
for blizzard in valley.get(blizzard_pos):
next_pos = blizzard_pos + blizzard
if next_pos.x < 0:
next_pos = Coordinate(valley.maxX, next_pos.y, next_pos.z)
elif next_pos.x > valley.maxX:
next_pos = Coordinate(0, next_pos.y, next_pos.z)
elif next_pos.y < 0:
next_pos = Coordinate(next_pos.x, valley.maxY, next_pos.z)
elif next_pos.y > valley.maxY:
next_pos = Coordinate(next_pos.x, 0, next_pos.z)
if not valley.get(next_pos):
valley.set(next_pos, [blizzard])
else:
valley.get(next_pos).append(blizzard)
def get_min_steps(valley: Grid, pos: Coordinate, target: Coordinate) -> int:
check_list = [
Coordinate(1, 0, 1),
Coordinate(-1, 0, 1),
Coordinate(0, 0, 1),
Coordinate(0, 1, 1),
Coordinate(0, -1, 1)
]
q = []
heappush(q, (0, pos))
v = set()
while q:
_, cur_pos = heappop(q)
if cur_pos in v:
continue
v.add(cur_pos)
if cur_pos.z >= valley.maxZ:
expand_valley(valley, cur_pos.z + 1)
for c in check_list:
next_pos = cur_pos + c
if next_pos.x == target.x and next_pos.y == target.y:
return next_pos.z
if not valley.isWithinBoundaries(next_pos) and (next_pos.x != pos.x or next_pos.y != pos.y):
continue
if valley.get(next_pos):
continue
dist = abs(target.x - next_pos.x) + abs(target.y - next_pos.y)
heappush(q, (dist + next_pos.z, next_pos))
return -1
class Day(AOCDay):
inputs = [
[
(18, "input24_test"),
(297, "input24_dennis"),
(269, "input24"),
],
[
(54, "input24_test"),
(856, "input24_dennis"),
(825, "input24"),
]
]
def get_valley(self) -> Grid:
valley = Grid.from_str(
"/".join(self.getInput()),
translate={
'#': False,
'.': False,
'>': [Coordinate(1, 0, 1)],
'<': [Coordinate(-1, 0, 1)],
'v': [Coordinate(0, 1, 1)],
'^': [Coordinate(0, -1, 1)],
},
default=False,
mode3d=True
)
valley.shift_zero()
return valley
def part1(self) -> Any:
valley = self.get_valley()
return get_min_steps(valley, Coordinate(0, -1, 0), Coordinate(valley.maxX, valley.maxY + 1))
def part2(self) -> Any:
valley = self.get_valley()
start = Coordinate(0, -1, 0)
target = Coordinate(valley.maxX, valley.maxY + 1)
steps = get_min_steps(valley, start, target)
steps = get_min_steps(valley, Coordinate(target.x, target.y, steps), start)
return get_min_steps(valley, Coordinate(start.x, start.y, steps), target)
if __name__ == '__main__':
day = Day(2022, 24)
day.run(verbose=True)

58
day25.py Normal file
View File

@ -0,0 +1,58 @@
from tools.aoc import AOCDay
from typing import Any
def int2snafu(dec: int) -> str:
conv = "012=-0"
snafu = ""
power = 1
over = 0
while dec > 0:
c = dec % (5 ** power) + over
dec //= 5
if c > 2:
over = 1
else:
over = 0
snafu = conv[c] + snafu
return snafu
def snafu2int(snafu: str) -> int:
dec = 0
for i, c in enumerate(snafu):
if c == '-':
val = -1
elif c == '=':
val = -2
else:
val = int(c)
dec += 5 ** (len(snafu) - i - 1) * val
return dec
class Day(AOCDay):
inputs = [
[
("2=-1=0", "input25_test"),
("2==221=-002=0-02-000", "input25"),
],
[
(None, "input25"),
]
]
def part1(self) -> Any:
return int2snafu(sum(snafu2int(c) for c in self.getInput()))
def part2(self) -> Any:
return ""
if __name__ == '__main__':
day = Day(2022, 25)
day.run(verbose=True)

202
inputs/input22_dennis Normal file

File diff suppressed because one or more lines are too long

72
inputs/input23_dennis Normal file
View File

@ -0,0 +1,72 @@
#.##......#...#.###......###.........####.##...#.###...####.#....#.#.#.#
..#.###..##.##.#.#.....#.###..###.#..........#..#...##..####.#.#..#..##.
#..#.###...##.....##.#.#####.#..##.....##...#.#.#....##.#..###.###....#.
#.###...###.#.##.#..#..#.##..##...##.#..##..#.##.##....#######...#..#...
....#.#.###...#.#..###.#.#..##....#####.#...##..#.#...##.##.....###..#.#
..###.#.#..#####..##.##....###......##.##..####.#.###....######.#.#.##..
#...###.##.##..###.####.####.#...###..##...#.#..#####.#...##...#..##..##
##.####....###.#####..#.#.###.##.#...#..##.##.###..#...##.#.#..###...#..
####...##..#..####...##.##..##.##..#.##.......#..#.##.#...###..######.##
.#.##.#.###.##.##........####.#...#.##...##..##.....#..##.#.###...######
#.......#...#####.#...#.###...####..####....##..###.##..##..######....#.
.##.###..#....#.#.#####.###..#.##......#...##..##...#..#.##.#...##..#..#
##.###......####.#..#####.....#..##.####.#.#....##...##.#.#.##...#.#.#..
.#.##..###.#.......#..##.##.#.#.........#.##.##.......##....##..#..#....
###..####.##..##..#....#..#..#.#.##..#........#...##.##.#.##...#.#...#.#
..#.#####.#..###.#.##..#..#...#.#...#...#..##.#.#..##..#.#...####..#...#
#...#####..#.####.#.##.##.#...##.#...#.....##.....#..#.###..#.#...#..#..
.##########...#..#..#......#.###.#......#..#.#..#..#.#..#..#.#.###.#...#
.##..#.##.###.#...##.#...#.##.#.##..##...#.#..#...#.....#.######..#.#.##
.#.#.....###......#.#.##.#..#...#....##.#..#.###...#.....###.##.####..##
..#..#.#...#.###..#..####....##.#........##..###..####....###..###.###..
#..##.###.#.#..#..#.##....#...#.#.###..#.#.....###..##..#####...##.#..#.
#.#......##.#.#.#.###.#.#...###..######.###.##.#.#....#####..#.#..###.##
........##.##.##..##.#.###.#..#.########.....#.#.##.##.#......########.#
#..#.#.#...#..#.#....###.....###.###.#.##....##...#...#..#.#..##.###.###
.#...####.#.#....#.####..#...##.#.##...#.#.####.#...#..##.###...#.###..#
......#...#..##.##.###.#..#.....######..##.####.#......#..##.......####.
...###.#..#.....#..#.####...#..#...#...##..#...##.##....####......###..#
#.###...#.##.######.#...#...##..#.#..##.#.#....#####.####.#.#......#..##
##.....#..####.#.#.###...#..#..#..#..#.#.#....###..##..#.#.#....#..#.##.
.#.#.....####.#.#...........#.#.##.####...#.#...#..#.#..####.#..#.#.##.#
...#..#...#.#.###..#.#..##...##.#.#..#.#####.#.##.###.#......#..##.#.###
...#....##########.######...#.....#..#.##...###..#.####.#.####..##..##..
#.##....#..#...####.......##.#..##.#.#..#######.....#.#.#.##..##..#.#...
###..##..#..#.#..###..#.#.#..###....##..#.#.....##..#..#....#....###.#.#
##.#.#..#.#######.......#..#.#.#...#..#.#..######..##..........##....#..
......##..#######.#..#...#.#####.#.#.#..#.####.####..##.##.#.##....#....
...#.###...######.#....#.#...###.##.#.#.###..#.#...####.#....#...#.#..#.
#.#...#.###..#####.###..##.#....#...#.##...#..#...####.#...#.##.#..#.#.#
##.#..##....##..#..######....##.##.....##..##....###....#####.#.##....##
#..#.#..#..###.##..#....#.##.#####.###.#.##.#..#.#..#####..###..###.#.##
.#.##...#.#..#....#.#.##.#.......#.....###.###.#.##.##...###.####......#
#.#####.#.##.#.#.##.#..#####......#...#...##.###.#..#.#.#..#.##.....###.
#....##.##....##.....#..#.#.#.#.#...###.#####....#..#.##.##.#.#.#.#.####
#....##.##....#...####....##..#.#.#.#.##.##.#..##....##....##..#...###..
##.#..##.#...#.##.#.#.##.#.#.#...#...#..##.###....#.##...###.#.#...####.
.############.#.#..#.###.###.######...#####.####.....#.#.###..##.#######
##...#.###..####..##...#...###...##..#.###...###.#.#..#.##..#######.###.
#..#.###..#..##..#..#.##.###..###....##..#.#..#....#.#.##..#.###.....#.#
#.#...#..#.##...###..##.##..###........#...##..#....###..##..#.#.###...#
##....#......##.####..##...###...##..#...#..#.#.##.#...####.#.#.####..#.
..#.#.###..##.##.#..####.###..####.....##.#...#.#.#...#.########.#.#....
#..#.##..#..##......##.##...#..#.#..#####..##.#.##..##.###.#.#..######.#
#..#..###.#..###.##..##....#..##..##...#.#...#..##..#####.###..###.####.
...#..##..##.#...#.....##..........#.##.#..#####..##..###..#...##.##..##
.#.#..##......#...#..#....#.######..#.#..##..#.......#.###.#.###..##....
..#.###.#.#.#.###.###..######..####...#..#.##.###..#....##..#.#.#.#..###
###.##.##.####.....####.##.##..##....###.#....###..###.##########.####..
#.#...#.###....##.#.#.##.#.#.#....#####...#.##..###.#.......#.##.#.###.#
.....##....#..#.....####.#.##..#.#..#....#.....#.######.##..#..###.#..#.
.........#...###..#....#...##.............###..###...#..##..####.###.##.
..#.#..#####.#.#..#.#...######.#.##..#...##.####...#...#.##..#.#.##.#...
#...#.#...##.#..##..#.####.#.#.######...###...#..#...#.##.#.#...#.###.##
.#####..#.#.##.#####...######.#..#.#.#.###...#...#.#.#.#.#..#..##.#...##
###.##.#.#.##...##..###....##.#.#..#..#...#.###.#.#.....#..##...#....#.#
##.#.##..#...###.#..#..###...#.##.#..#..####.#.#.##.#....#.#.#....#..###
.#.#.#...##.#.######.#.##.#.......#.#......#..#..#.#.####...###..#....#.
.#....####...#....#..#.##.######...####..#...#.####.####..#.##.#.#.###..
###.......#.###.##...##..#....#####..##.#...#..###..#......#...#.#.##..#
.#...##.#..##..#..###.##..#....#..#....##..#.##...###.##.#.####.##.#.###
..##.#.#.##.#.###.##.##...#.#....#.#..###..##....#.##...#...#.###.##.##.
#..#..##.##..#..#####..#.#.#.#.##....#####.#.#.....###.##....#.#...##..#

27
inputs/input24 Normal file
View File

@ -0,0 +1,27 @@
#.########################################################################################################################
#.v^<>^^.<^^<v>v>>>.<^<<v.^>vv>>^<<<v>.v<^v^<v<<^<^^<^<^v><^vv.v^^.>^><vv><^<.<^v<>.v<v..^>><v>.vvv.v>^^<^>.<<^<^<^>v.^^<#
#.^^<v>><<v><vv<>..<>v<^v><<>><>v.>v.^^<<.v.^<^<vv><v<<v><<^<>^v>v>><>v..v^<^.v><>^>><v<<>v^<<v<v>v.v<v>><<v>^v<v^...<<<>#
#><vv>>v>v<^>^^^^vv^<v^<<v<>^<^.^^>^<^vv>^v>><<^^<.>^>v<^v<.v.^<^^v.<.>.<^>v^>.v>>^vv^v.>>>v<<<<v.^^v<^^<^><<<<.^>.>vvv>>#
#<.vv>.><<.<^v.>v^v>><v>><<^vv>^v^>.><v>>><^><v<v^^vv>.v^^<v>vv<>v>^v.>>v^>..v<>^v.^>><.vv><^...<>^^>v>vvv>^<^<><v>v<^^^<#
#>^.^>vvv>vv>^^vv>v^^v>vv>v^v>^<v>>vvvv^>.v^<v^><^>vvv<>vv<^v<.<^v^>^vv^<><>.^.^>><<^^>^<v^>>>>v><<v^^>^^>>v^v.<^vv^<^v<>#
#><^>><vv^vvv.v><v<>^v>^<<<^^<><^<<v<>^<<v><<<v>><v<^^<vv<.>^v>^<v>.>v>>^^>^>><>.<<v<^><>>>^.<vv>.^^<.^^>>v.><<v<>><>v^><#
#>>^.<<v.^v>^^v.>v.vv^<<.v<v<..<<v^^>^v.><>v<^^<<.>v>v>v>^v>.<>v<><<^v><^>><^v>v^v>^vvv>>>..>^>>.><v><>.^^v.><<vv<.v>^^<.#
#>vv>^^.<>^v<^<<v^>v<^^v><>>>>v^vv>v<^v^><><^.<v^>.<^.v^>><vv>>vvv>^v<<<><vv<v^<<>v>>^v>^^^>^v><^^>^^^<<^^<v<<v<v>^^^<^>>#
#>.v^<<.vv<^v>^>>v<>v^v^^v^v<^^<<..<<^v<<<<^<v>^>.<>v<v<v<.<.v>vv^>><^.<.v<^<^v><v<v>.v.><<^>>v^.^vv.vv^.>^^>vv<>^..v>^v<#
#..v.>^><<>..<>.<^<<v>^^^^><<><<vv><^>v>^v<vv>v><vv.^<.<<<<v^v<>^^^vv>.>>>v^v<v<^.<v<<^.v<><<>>v<<<.>>v.^^>^^.>.<.>vv>^>>#
#>^^vv<<><<v<^.v>>v>^^^v^<v.^><<<<<v^v>v<<^v..^<.vv.^v>vvv>^v<..v<><<^<<vv<>>>>^>^^<>^<^<^^.vv>>^>^>^v^>.<^.<<.>v^>vv<.^<#
#<v^vv>^^v>vv>^.^>v>v^v>vv.>>.>v^v^>.^v<^.>^<<<v.>^>^^<>vv<.<^^<^v<^><v^v^.^<><v^^v^>.<vv^>v^v<v^><>^<vv>v<><^v<v.<<^.>^>#
#<>^<^<v><^^.^^>..^^>v>>>>^v<.<>>.<^v^>vvvvv>^<<.><^<v<.v<^><^^>vv<^<^<>v>v<>^^v>>^^>>v<^^<v>v^^^vvv<<<<<>>>v>^v.<^^>^>^<#
#>.<^v<.<^v.v>^.>>><^<<^^<<.<>><>>>^vvv<v<v<<^^vv<<<^v^v^vv<^v>>^^vv.^>^.v^^^>>v^>.<>.^^>v^^^^><^^>^>>.v<v^<^>^v^>^<<<v<<#
#>><><.>v^<>^^>.^>^v>^.^<v><><>.<v<^v>>>>v.<>>.^vv>v.vv.><vv^v>^<>>v>vv.v>v>v<><>>>^..^v>^^><..^..^..^vvv>><>v<>v<^<<>v<<#
#<vv^vvv><>v^v.<^v^^v<.<>v<>.^v^<<^<><.^vv<>^>>.v<<><vv<^^<>>v^.^v><v^^<>v.v<.>^^v^<<<^^<<v<^^^<<<<>^^v>><><<><>v>v<v.>^>#
#.<.^>^>^>^v..v>^.<v<^<<<^vvv>vv><^^v^<.>>.^<.^^<<>>^><<>>^^.^<<^^><^v<.><>.<<<.vvv>>vv^v<^v<>vv<<^v^^<v.v^<<^>v^>v<><vv<#
#.vvvv>>^>^<..^>>^>vv^.^>^<<v>^^v>v>^<>.>vv<v^>>>^.^<<^>>^>^>vvv><vv^^<^.^^.<^^v.<v<>^<<<v^>><<.^^^^>^>>>v<<>>v>v<>v<v><.#
#<<vv.<v>^^v<.>>^>^<>^><.<v^><>>.^<v^v<<.v>>.<>.v>^>^v><><^<><<<v^<><<v^..^v^v>^.><>>>v^.^>vv<<^>v<><.^^v<>vv>v^v<><^>>><#
#><>^v>v<>><vv>>v<>^<v>v^^>^v^>^^<v>v>^^v><<^v>>vv<^><>^>^^>>v^^<^<v>.^>v^vv^<.v>^v^.v^><><>>v.v^vv^<v>^>^><v>^>^>v>^v..<#
#>v<^^<^>.<>v<v<.^vv^>>v><^^v<^^>>^>^<^^>>>^<v<^v<>v<^>v>^>v^v>^.<<v^>vv<^<.><^><<^>v><^<v>^<^v>v^>><^vvv^>>v>>vv>v^>^><<#
#<vvv<><^.>v.^><v<^^<v><^<vvv.^..v^>...v^><<^^><^>^^vv>^v>v^<v<<>^>^^..<^<<v><<>.><<>^vvvv>v^><.^^>>v>>>^>>^<^<^<v^>vvv>>#
#><<<^^.^<.^.^^<>^.vv^^^<v^<<<vv<<>^<v<^>>v^>>v<<v^^.v^<.vv<v<><<.v><<^>>v><.v><v>v^^v^v<^><vvvvv<^.<<>v^.<>^.^><>^v><>^<#
#<.<>.>v^><<>^^<<vv>^>^v>>>v>v><^v><v.>>^<>>.<vv<<<v<v^<<vv^<.v^^>vv>>^<^<v<v<<>vv.><v..>>>.>^v<<vv><v^^^vv^^<>^>v<^^>v.>#
#<>^^<>>^v>v<<>^.>>^^^<<v>^vv^<^<.<<<vv>>v>^^<^v><><>.<>.^><<^^^>^vv><>v.<>v<.<v>>><v.^>^>vv<v>^<v^<<v^v>v..>^^<^^.><>^><#
########################################################################################################################.#

27
inputs/input24_dennis Normal file
View File

@ -0,0 +1,27 @@
#.########################################################################################################################
#>^v<.<<^v^<><>>>^<vv>^>><<<^^.^v^<<v^v<v>^^>^^<^><^>.^>v<v<v.v<>vv<^^^vvv<.^v^<v^.^.>.<^<^>v^.v^v<>^vv^<<>>v^<<.<vvv^.<<#
#><^>><<vvv.v>^<..<v><v^^>>>v>>vv^^^<^^<><<>v>v<><><<^<<v>v.>.v>vv<>^>.^vv^^.<v<vv.<v<>>^>>><v<.>v>v^<v<>^<<<^v^<.v..v<^>#
#<v^.^>vv.^<^<>v^<^^^<^^>v<<>v><><^v^<v.v<^><<<^^^.>vv<.^<v<v<v^<v>^<v^<.><^^<>^v>..<v..>v^><>>^<.>.vv<<<.v.^^^^^>.<<.<v<#
#>.<<^>^v>>v<v<>>^v^>><>>v.^>.<>>^v<>.^<>^^^<vv<vv^^^v^^<<><v^^>>.v<v^v<.>^^.^>^v><vv<^^<^>>^v>^>^^v^v.<<^.vv<v..^^v.>>v>#
#>v^^>^^.>.^^<>><>v^^^<v>>>v^v^v^^<^<<^<<>><<^<<vv<<^>>>.<^v^><v<v>>v^>><vv..<v><vv^.>.v^vv>^><v.<vv>^vv^^>><v>v>v<v>>^><#
#>^<vvv^><^vvv>><^^vv^^>v<.v^<^<vv<><v<>^^^^<>^>v<^vv><v.<>>..>^^v<><>v.>>vv<><^^><>v<v<>vv^^>v><>>.v<v<>>>^^^v^v<<<^><^<#
#>^><v>>^.^><.^^^^<v>v<.v^>^^^<<<^<<v><><v>>>>v<v>vv<v><>.^><<^v<>^^v<.^^v<^>v<>v^.>.<<.>vv.^^vvv.<.v^>^><v^<^^^^>.^vv^^<#
#><v^vvv>^<v<>^>^<.><v<<<><v<<<^v^>^<v>>v<^<vv<v>v^..^>^^^^<.><<<>vvv>^vv^>v^<<>vv<<v^>^.v>.^<^^..>v<^<v<^>^^<><vv<.^v^.>#
#<^<><v.>.<<^>>v<^..<<.>>v<<^^>v.<v.<.v<.vv<^>^vvv>^>>v<.<>v^<<<<^<v>^<vv>v<<<^^>^^<<<>^>vv>>^.><>^^v^^><v.>v^^<>^^^^<v>>#
#<v.>^><^>>vv^vvvv^<>vv<<v<<v^v^v<><<^.^<><v^^<><.v<^>^v>^<^v^><^>v>^<<<v><v<<^^>v><v<<<<^.v^.<^<v<<>^>>><>vv<.^^..v>v<<>#
#<v<^>v<<^^>>v<^>^^>v>^>v.v<<<>v>><v<vv.v^<<.v<v>v<<^v<<.>^<v>^^>^..<>^^v.^><^vv><v<<>>vvv^^vv<<>^>^v^<^><<^v<.>^>><^^<^<#
#<<>>v^^>>^.<^^<^^^>^^>vv>>>>>v^vv><.v>v>v<^>><^<<v><^>^>^vv^vv^<v<<<v>><v.v>^^<<.^vvv<>vv<><^^^vv>v^.><^<^vv><<.vv^^^.v<#
#<.<v><vv>^<>>^>.^<<v>..^vvv^^v>^<>>v<<<..^vv>^<...^<<>.<^>^<.v><v.>^^.vv<<^<v.>v^v^^>.^^vv.^v^><<>^^^^.v<..>v^<>^<>>vvv>#
#<^<<v^v<^<.^v^>v^<^<.>^^v^<^>.<v>v>^^^.v><v><vv<<v<>v.<^><>.><vv><<^^.vv<.<^.vvvvvv^^^^<vvv.^<.>v.^v>^v>><v^v.>v^^v.<.^<#
#.<<^.<v<<^^<>v.<.>v.^^^<<^v>.v<>v<...>^<v.<v<<><>.v<^^^>.^v>vv^<^.>.^>>^>v.>v>.^^<v><v^<><^^v<v^^<<<>^.>v><<v<<v>.<^v<v>#
#>>><<^v<^>v^>><^^.<v<^<<<^.<v^>v<<^^^>>^^.^v^>v^<>^v.>^><^>.^^v>><<>v<v><^vv<><^v>.v><^><<v>.^>v^^<<^<>.>v<v^^v<v.>v..>>#
#.v>^^.<v.^^>><^v<vv>v<^<>><v>^^v<<v>>.<<v^v<^.v.<^>^vvv<vv^v>><>^v<^><v..<^<vv<<v<.<^^^<<>v^^v>v>>^^^>vvvv<^^<>.<^^^><^.#
#<^^<v<^<>>vv>v<<vv^v<^.<>><<v<<v>^^^^>^<^>>^vv^^<^vv^>vvv>v>^v.><^>^^>.^^v.<<v.v<^<<^v><vv^^^v^>><.^<>v><v<vv^^>>v^>>..>#
#<^>v^^vv>^><^^^^^^>>.v<^.<^<>^><^.v<v<>>v.^.v^<vv^^<<<><..>>><.v<vv>^v^.<>>v^v.<vv><v^<vv<<v<><.<<^^v><.>v<<>v<<^^>>vvv>#
#.><<>>><^vv^v.>.>.^.<>>^^^v^^><>v<><>>>><v<<v^<>^v^v>>^^v^.<>v>vvv>v>>.<>>^>>>>^>^>v<.><vv>>.>>v<>><<^><v.^<<..>.vvv^v<<#
#>^>^<^^v>^^^>v>.v><>^>^v^^.v.>>v>>v^^^>>>v><>.<vv.<<<.<^^<^>^>v<v>^<^v<><>><>.^vv>^>.^>>>^><<^>^v<<^<vv<vv^.^^<vv>>v.<>>#
#><<><v<<vv>^>.^.<<.>.<.v>^>><^>v<>v^.<><^v^>>v<^^<.<^<>.<vv<<>vvvv>vv>v.<<^v<.>v>^^<v><>.>v>^<^<^^..>v<v>v.^<^<^<vv<v><>#
#>>^^<^<v^<v<vv^>..^v.^<^>^.v><^vv^..v.<>v<<.<v..v>v>vvv^>^<v>vv.^.>^.^^>v<^>v>v><>>^^>.v^<<.<^>v^vv><.v..<.><<v<.<<.<vv>#
#><<>^<>><^.^^><v<<^<^^>>v><v.vv><v<<<<.<^<v>v><>v<<^<<>>^>^vv>v<v.vv>v>v>>>><..v^^vv>><<>>vv><>>.>v<<>v<v^vv<v<<v^>>v<^.#
#>.<<><<vv<^.v<v<v<^>>v><v.^>^v.<^v.^^^<<<<.<<v^v>^<.>^vv^<<^^>.v>>>.v^v<v<v><^>v.>>^^>^v>vv<>vv^^<.<.v>^^v>.^^v<^v^>^^v>#
########################################################################################################################.#

6
inputs/input24_test Normal file
View File

@ -0,0 +1,6 @@
#.######
#>>.<^<#
#.<..<<#
#>v.><>#
#<^v^^>#
######.#

101
inputs/input25 Normal file
View File

@ -0,0 +1,101 @@
22-00====1
1210=012020-1=
2=-221
1=020
1=2=0==12----=-
1===-22-=
101120212112-
2022-==20-=-12===2
1=20-200=22-1-1-2=
1-20021=21-
11--0-==0-1-22
2--0=---2=-
21=--=-01=-0=112-21
2=0200
1011021--0-=-10010
2=1=122-22=1---2
110-0--0
200
1=2
1==11=101-=-000=0==2
1200-022-=
1--0=02-2=21220022
10--
10===202=22=00=1
11022
1--222--
100
2-0
1=221==
1==21=22
2==0-=2
1==1=21=201-
12-0=1110-1=02-022
2-12=21=--0020=
10-1-0=0=01=0--=2--
2=1==-001=0=12
212=10002
10-=02200202=2==
1-21-0=-10
1-=12222112
1=1--12220=1
10-
1=-02
1=210
21==1=
1--==--11
1--21212-=--200-0-
1000010
202=012-11-100200
2=-21202200-=
11=1112=1020111
12=1002022-0
1122
1=-0-
1=1=20=0010-
12=2-0000---
1-
2-2=
12001==---1
2---=--=0012121100
10-10-11=1
1=112-2=0-0=0--=0
2=0=212122
102==21101=-==1
102
1=2-2-0000211
10-120-=00
2=-02112010111-0-
1-0=
112
1=2=
11=20
10-2-01-210
1-02122-2=-
1-22==0===0-0
10=--=011-
2101-=1-12
1==0=0=01
22110-=0=111
12---1-10-0-=1
2-2-=
1-=101--11=12=
2-0--02-01=1-10==
2=--=200=12=110
12=
2--=
20212
2102-2
2=202102
2=1=
1101011-=1222-
11
202
102=10001=
101001
1====11=0=12
2211001
11-2-
1-00
11=1-1--
2=

13
inputs/input25_test Normal file
View File

@ -0,0 +1,13 @@
1=-0-2
12111
2=0=
21
2=01
111
20012
112
1=-1=
1-12
12
1=
122