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)

262
day16.py
View File

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

373
day22.py
View File

@ -1,231 +1,40 @@
import re import re
from tools.aoc import AOCDay from tools.aoc import AOCDay
from tools.coordinate import Coordinate from tools.coordinate import Coordinate
from tools.grid import Grid from tools.grid import Grid, GridTransformation
from typing import Any from typing import Any
FACING = [ FACING = [
Coordinate(1, 0), Coordinate(1, 0, 0),
Coordinate(0, 1), Coordinate(0, 1, 0),
Coordinate(-1, 0), Coordinate(-1, 0, 0),
Coordinate(0, -1) 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: def get_password_from_coord(c: Coordinate, face: int) -> int:
return (c.y + 1) * 1000 + (c.x + 1) * 4 + face return (c.y + 1) * 1000 + (c.x + 1) * 4 + face
def get_cube_conn_dict(cube_conn: tuple, c_size: int) -> dict: def walk(board: Grid, pos: Coordinate, directions: list) -> (Coordinate, int):
conn_dict = {} face = 0
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):
for direction in directions: for direction in directions:
steps, turn = direction steps, turn = direction
print("starting at", pos, "moving", steps, "steps, then turning", turn)
for _ in range(steps): for _ in range(steps):
next_pos = pos + FACING[face] next_pos = pos + FACING[face]
next_face = face next_face = face
if board.get(next_pos) is None or not board.isWithinBoundaries(next_pos): 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: match face:
case 0: case 0:
next_pos = Coordinate(0, next_pos.y) next_pos = Coordinate(0, next_pos.y, 0)
case 1: case 1:
next_pos = Coordinate(next_pos.x, 0) next_pos = Coordinate(next_pos.x, 0, 0)
case 2: case 2:
next_pos = Coordinate(board.maxX, next_pos.y) next_pos = Coordinate(board.maxX, next_pos.y, 0)
case 3: case 3:
next_pos = Coordinate(next_pos.x, board.maxY) next_pos = Coordinate(next_pos.x, board.maxY, 0)
while board.get(next_pos) is None: while board.get(next_pos) is None:
next_pos += FACING[face] next_pos += FACING[face]
@ -242,29 +51,121 @@ def walk(board: Grid, pos: Coordinate, directions: list, face: int = 0, connecti
return pos, face 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): class Day(AOCDay):
inputs = [ inputs = [
[ [
(6032, "input22_test"), (6032, "input22_test"),
(191010, "input22_dennis"),
(1428, "input22"), (1428, "input22"),
], ],
[ [
(5031, "input22_test"), (5031, "input22_test"),
(None, "input22"), (55364, "input22_dennis"),
(142380, "input22"),
] ]
] ]
def get_map_and_directions(self) -> (Grid, list, Coordinate): def get_map_and_directions(self) -> (Grid, list, Coordinate):
board_map = Grid(None)
start_pos = None start_pos = None
map_lines, dir_line = self.getMultiLineInputAsArray() map_lines, dir_line = self.getMultiLineInputAsArray()
for y, map_line in enumerate(map_lines): board = Grid.from_str("/".join(map_lines), default=None, translate={' ': None, '#': False, '.': True}, mode3d=True)
for x, v in enumerate(map_line): for x in board.rangeX():
if v in ['#', '.']: if board.get(Coordinate(x, 0, 0)) is not None:
c = Coordinate(x, y) start_pos = Coordinate(x, 0, 0)
if start_pos is None and v == '.': break
start_pos = c
board_map.set(c, v == '.')
if dir_line[0][-1] not in ['R', 'L']: if dir_line[0][-1] not in ['R', 'L']:
dir_line[0] += 'S' dir_line[0] += 'S'
@ -272,29 +173,43 @@ class Day(AOCDay):
for d in re.findall(r'\d+[RLS]', dir_line[0]): for d in re.findall(r'\d+[RLS]', dir_line[0]):
directions.append((int(d[:-1]), d[-1])) directions.append((int(d[:-1]), d[-1]))
return board_map, directions, start_pos return board, directions, start_pos
def part1(self) -> Any: def part1(self) -> Any:
board_map, directions, start_position = self.get_map_and_directions() board, directions, start_position = self.get_map_and_directions()
finish, face = walk(board_map, start_position, directions) finish, face = walk(board, start_position, directions)
return get_password_from_coord(finish, face) return get_password_from_coord(finish, face)
def part2(self) -> Any: def part2(self) -> Any:
board_map, directions, start_position = self.get_map_and_directions() board, directions, start_position = self.get_map_and_directions()
conn = identify_cube(board_map) board.shift(shift_x=1, shift_y=1)
for x in board_map.rangeX(): start_position += Coordinate(1, 1, 0)
c = Coordinate(x, 0) fold(board, start_position)
if board_map.get(c) is not None: finish, face = cube_walk(board, Coordinate(1, 1, 0), directions)
start_position = c
break orig_board, _, _ = self.get_map_and_directions()
print(board_map.minX, board_map.minY, board_map.maxX, board_map.maxY) c_size = 4 if orig_board.maxX < 50 else 50 # account for test case
print(start_position) for x in range(0, orig_board.maxX + 1, c_size):
print(board_map.get(Coordinate(4, 0))) for y in range(0, orig_board.maxY + 1, c_size):
print(conn) check_pos = finish - Coordinate(1, 1, 0)
board_map.print(true_char='.') check_face = face
finish, face = walk(board_map, start_position, directions, 0, conn) sub_board = orig_board.sub_grid(x, y, x + c_size - 1, y + c_size - 1, 0, 0)
print(finish, face) if len(sub_board.getActiveCells()) == 0:
print(get_password_from_coord(finish, face)) 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 "" return ""

View File

@ -52,16 +52,18 @@ class Day(AOCDay):
[ [
(25, "input23_test_small"), (25, "input23_test_small"),
(110, "input23_test"), (110, "input23_test"),
(4070, "input23_dennis"),
(3766, "input23"), (3766, "input23"),
], ],
[ [
(20, "input23_test"), (20, "input23_test"),
(881, "input23_dennis"),
(954, "input23"), (954, "input23"),
] ]
] ]
def part1(self) -> Any: 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): for i in range(10):
if not move_elfs(map, i): 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() return (map.maxX - map.minX + 1) * (map.maxY - map.minY + 1) - map.getOnCount()
def part2(self) -> Any: 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 round = 0
while move_elfs(map, round): 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