Compare commits

..

No commits in common. "1d5bec6bde7c626ec3e677848dee3ea89c753da8" and "a82057d89c33400cedb91bb9e4dfd92afde5a059" have entirely different histories.

13 changed files with 359 additions and 1105 deletions

View File

@ -1,182 +0,0 @@
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)

276
day16.py
View File

@ -1,151 +1,124 @@
import heapq from collections import deque
import itertools from itertools import product
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) -> None: def __init__(self, name: str, flowrate: int):
self.__name = name self.name: str = name
self.__flowrate = flowrate self.flowrate: int = flowrate
self.neighbours = {} self.tunnels: set = set()
@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__()
def get_most_pressure_release_solo(root: Valve, remaining_minutes: int = 30, visited: set = None) -> int: class Tunnel:
if visited is None: 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() visited = set()
visited.add(root) queue.append((0, valve))
while queue:
my_flowrate = 0 d, v = queue.popleft()
if root.flowrate > 0: if v.name in visited:
remaining_minutes -= 1
my_flowrate = root.flowrate * remaining_minutes
max_flowrate = 0
for n, d in root.neighbours.items():
if n 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))
if remaining_minutes <= d + 1: return tunnels
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_mode_pressure_release_double(root_me: Valve, root_ele: Valve, r_min_me: int = 26, r_min_ele: int = 26, visited: set = None) -> int: def get_max_flow(valve: Valve, open_valves: list, time_remaining: int = 30, depth: int = 0) -> 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)) max_flow = 0
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: if dp_key in DP:
return DP[dp_key] return DP[dp_key]
my_flowrate = 0 if time_remaining_1 <= 0 and time_remaining_2 <= 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
max_flowrate = 0 ov1 = {t for t in valve1.tunnels if t.target.name not in open_valves and t.length < time_remaining_1 - 2}
rem_list = [x for x in root_me.neighbours.keys() if x not in visited] ov2 = {t for t in valve2.tunnels if t.target.name not in open_valves and t.length < time_remaining_2 - 2}
if len(rem_list) == 1:
if root_me.neighbours[rem_list[0]] < root_ele.neighbours[rem_list[0]]: if not ov1 and not ov2:
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()) return 0
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()) if not ov1:
else: ov1 = {Tunnel(valve1, 99)}
max_prod = len(rem_list) ** 2
cur_prod = 0 if not ov2:
for v1, v2 in itertools.product(rem_list, repeat=2): ov2 = {Tunnel(valve2, 99)}
if len(visited) == 1:
cur_prod += 1 permut = product(ov1, ov2)
print("Iter (%d/%d)" % (cur_prod, max_prod))
if v1 == v2: max_flow = 0
for v1, v2 in permut:
if v1.target.name == v2.target.name:
continue continue
me, ele = v1, v2 this_open_flow = 0
if r_min_me <= root_me.neighbours[me] + 1:
me = root_me
if r_min_ele <= root_ele.neighbours[ele] + 1: t1 = valve1
ele = root_ele if v1.length + 2 <= time_remaining_1:
this_open_flow += v1.target.flowrate * (time_remaining_1 - v1.length - 1)
t1 = v1.target
if me == root_me and ele == root_ele: t2 = valve2
continue if v2.length + 2 <= time_remaining_2:
this_open_flow += v2.target.flowrate * (time_remaining_2 - v2.length - 1)
t2 = v2.target
n_flowrate = get_mode_pressure_release_double( this_flow_rate = get_max_flow_double(
me, ele, t1,
r_min_me - (root_me.neighbours[me] if me in root_me.neighbours else 1), t2,
r_min_ele - (root_ele.neighbours[ele] if ele in root_ele.neighbours else 1), sorted(open_valves + [v1.target.name, v2.target.name]),
visited.copy() DP,
time_remaining_1 - v1.length - 1,
time_remaining_2 - v2.length - 1,
depth + 1
) )
if n_flowrate > max_flowrate:
max_flowrate = n_flowrate
if n_flowrate == 1671: if this_flow_rate + this_open_flow > max_flow:
break max_flow = this_flow_rate + this_open_flow
DP[dp_key] = my_flowrate + max_flowrate DP[dp_key] = max_flow
DP[dp_key2] = my_flowrate + max_flowrate DP[dp_key2] = max_flow
return my_flowrate + max_flowrate return max_flow
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"),
@ -159,54 +132,49 @@ class Day(AOCDay):
] ]
] ]
def parse_input(self) -> Valve: def get_valve_graph(self) -> Valve:
n_cache = {}
valves = {} valves = {}
tmp_tunnels = {}
for line in self.getInput(): for line in self.getInput():
name, flowrate, neighbours = self.input_regexp.match(line).groups() p = line.split(" ")
valves[name] = Valve(name, int(flowrate)) valve_name = p[1]
n_cache[name] = neighbours.split(", ") flowrate = int(p[4][5:-1])
tunnels = "".join(p[9:]).split(",")
valves[valve_name] = Valve(valve_name, flowrate)
tmp_tunnels[valve_name] = tunnels
for valve, neighbours in n_cache.items(): for name, tunnels in tmp_tunnels.items():
for n in neighbours: valves[name].tunnels = {Tunnel(valves[t]) for t in tunnels}
valves[valve].neighbours[valves[n]] = 1
for valve in valves.values(): for valve in valves.values():
if valve.flowrate != 0: tunnels = set()
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))
for n_set in valve.neighbours.keys(): tmp_tunnels[valve.name] = tunnels
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: for name, tunnels in tmp_tunnels.items():
continue valves[name].tunnels = tunnels
n_set.neighbours[n_get] = valve.neighbours[n_set] + valve.neighbours[n_get] return valves["AA"]
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_most_pressure_release_solo(self.parse_input()) return get_max_flow(self.get_valve_graph(), [])
def part2(self) -> Any: def part2(self) -> Any:
global DP cache = Cache()
DP = {} root = self.get_valve_graph()
root_valve = self.parse_input() return get_max_flow_double(root, root, [], cache)
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,40 +1,231 @@
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, GridTransformation from tools.grid import Grid
from typing import Any from typing import Any
FACING = [ FACING = [
Coordinate(1, 0, 0), Coordinate(1, 0),
Coordinate(0, 1, 0), Coordinate(0, 1),
Coordinate(-1, 0, 0), Coordinate(-1, 0),
Coordinate(0, -1, 0) Coordinate(0, -1)
] ]
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 walk(board: Grid, pos: Coordinate, directions: list) -> (Coordinate, int): def get_cube_conn_dict(cube_conn: tuple, c_size: int) -> dict:
face = 0 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):
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, 0) next_pos = Coordinate(0, next_pos.y)
case 1: case 1:
next_pos = Coordinate(next_pos.x, 0, 0) next_pos = Coordinate(next_pos.x, 0)
case 2: case 2:
next_pos = Coordinate(board.maxX, next_pos.y, 0) next_pos = Coordinate(board.maxX, next_pos.y)
case 3: case 3:
next_pos = Coordinate(next_pos.x, board.maxY, 0) next_pos = Coordinate(next_pos.x, board.maxY)
while board.get(next_pos) is None: while board.get(next_pos) is None:
next_pos += FACING[face] next_pos += FACING[face]
@ -51,121 +242,29 @@ def walk(board: Grid, pos: Coordinate, directions: list) -> (Coordinate, int):
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"),
(55364, "input22_dennis"), (None, "input22"),
(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()
board = Grid.from_str("/".join(map_lines), default=None, translate={' ': None, '#': False, '.': True}, mode3d=True) for y, map_line in enumerate(map_lines):
for x in board.rangeX(): for x, v in enumerate(map_line):
if board.get(Coordinate(x, 0, 0)) is not None: if v in ['#', '.']:
start_pos = Coordinate(x, 0, 0) c = Coordinate(x, y)
break if start_pos is None and v == '.':
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'
@ -173,43 +272,29 @@ 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, directions, start_pos return board_map, directions, start_pos
def part1(self) -> Any: def part1(self) -> Any:
board, directions, start_position = self.get_map_and_directions() board_map, directions, start_position = self.get_map_and_directions()
finish, face = walk(board, start_position, directions) finish, face = walk(board_map, 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, directions, start_position = self.get_map_and_directions() board_map, directions, start_position = self.get_map_and_directions()
board.shift(shift_x=1, shift_y=1) conn = identify_cube(board_map)
start_position += Coordinate(1, 1, 0) for x in board_map.rangeX():
fold(board, start_position) c = Coordinate(x, 0)
finish, face = cube_walk(board, Coordinate(1, 1, 0), directions) if board_map.get(c) is not None:
start_position = c
orig_board, _, _ = self.get_map_and_directions() break
c_size = 4 if orig_board.maxX < 50 else 50 # account for test case print(board_map.minX, board_map.minY, board_map.maxX, board_map.maxY)
for x in range(0, orig_board.maxX + 1, c_size): print(start_position)
for y in range(0, orig_board.maxY + 1, c_size): print(board_map.get(Coordinate(4, 0)))
check_pos = finish - Coordinate(1, 1, 0) print(conn)
check_face = face board_map.print(true_char='.')
sub_board = orig_board.sub_grid(x, y, x + c_size - 1, y + c_size - 1, 0, 0) finish, face = walk(board_map, start_position, directions, 0, conn)
if len(sub_board.getActiveCells()) == 0: print(finish, face)
continue print(get_password_from_coord(finish, face))
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,18 +52,16 @@ 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()), translate={'#': True, '.': False}) map = Grid.from_str("/".join(self.getInput()), true_char='#')
for i in range(10): for i in range(10):
if not move_elfs(map, i): if not move_elfs(map, i):
@ -73,7 +71,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()), translate={'#': True, '.': False}) map = Grid.from_str("/".join(self.getInput()), true_char='#')
round = 0 round = 0
while move_elfs(map, round): while move_elfs(map, round):

109
day24.py
View File

@ -1,109 +0,0 @@
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)

View File

@ -1,58 +0,0 @@
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)

File diff suppressed because one or more lines are too long

View File

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

View File

@ -1,27 +0,0 @@
#.########################################################################################################################
#.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..>^^<^^.><>^><#
########################################################################################################################.#

View File

@ -1,27 +0,0 @@
#.########################################################################################################################
#>^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>#
########################################################################################################################.#

View File

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

View File

@ -1,101 +0,0 @@
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=

View File

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