This commit is contained in:
Stefan Harmuth 2021-12-23 18:50:19 +01:00
parent c15534c0aa
commit 7d7aee7c49
3 changed files with 45 additions and 73 deletions

108
day23.py
View File

@ -1,22 +1,18 @@
from tools.aoc import AOCDay from tools.aoc import AOCDay
from typing import Any from typing import Any
import sys
sys.setrecursionlimit(2000)
def getLegalMoves(positions): def getLegalMoves(positions):
movers = [c for c in positions if positions[c]] movers = [c for c in positions if positions[c]]
moves = []
for start in movers: for start in movers:
finalPosition = True finalPosition = True
if start[1] == 0 or start[0] != positions[start] * 2: if start[1] == 0 or start[0] != positions[start] * 2:
finalPosition = False finalPosition = False
else: else:
if start[1] > 0 and start[0] == positions[start] * 2: for y in range(start[1] + 1, 5):
for y in range(start[1] + 1, 5): if (start[0], y) in positions and positions[(start[0], y)] != positions[start]:
if (start[0], y) in positions and positions[(start[0], y)] != positions[start]: finalPosition = False
finalPosition = False
if finalPosition: if finalPosition:
continue continue
@ -31,6 +27,9 @@ def getLegalMoves(positions):
if target not in positions: if target not in positions:
continue continue
if positions[target] and positions[target] != positions[start]:
break
if positions[target] == positions[start]: if positions[target] == positions[start]:
continue continue
@ -57,103 +56,66 @@ def getLegalMoves(positions):
if not wayClear: if not wayClear:
continue continue
#yield start, dest, start[1] + abs(dest[0] - start[0]) + dest[1] yield start, dest, start[1] + abs(dest[0] - start[0]) + dest[1]
moves.append((start, dest, start[1] + abs(dest[0] - start[0]) + dest[1]))
return moves
gMinCost = 1e5 def isFinalPosition(position):
DP = {}
def isFinalPosition(position, cost):
global gMinCost
for x in 2, 4, 6, 8: for x in 2, 4, 6, 8:
for y in 1, 2, 3, 4: for y in 1, 2, 3, 4:
if (x, y) in position and position[(x, y)] != x // 2: if (x, y) in position and position[(x, y)] != x // 2:
return False return False
if gMinCost > cost:
print("Found final position with cost", cost)
gMinCost = cost
return True return True
def play(position, cost): def play(position, depth=0):
if (str(position), cost) in DP: if str(position) in DP:
return DP[str(position), cost] return DP[str(position)]
minCost = 5e4 minCost = 1e9
for move in getLegalMoves(position): for move in getLegalMoves(position):
move_cost = cost + 10 ** (position[move[0]] - 1) * move[2] move_cost = 10 ** (position[move[0]] - 1) * move[2]
this_cost = move_cost
if this_cost > gMinCost:
continue
new_pos = position.copy() new_pos = position.copy()
new_pos[move[1]] = new_pos[move[0]] new_pos[move[1]] = new_pos[move[0]]
new_pos[move[0]] = 0 new_pos[move[0]] = 0
if not isFinalPosition(new_pos, this_cost): if not isFinalPosition(new_pos):
this_cost += play(new_pos, this_cost) move_cost += play(new_pos, depth+1)
if this_cost < minCost: if move_cost < minCost:
minCost = this_cost minCost = move_cost
DP[str(position), cost] = minCost DP[str(position)] = minCost
return minCost return minCost
DP = {}
class Day(AOCDay): class Day(AOCDay):
test_solutions_p1 = [12521] test_solutions_p1 = [12521, 12530]
test_solutions_p2 = [44169] test_solutions_p2 = [44169, 50492]
def getStartingPosition(self, part2=False): def getStartingPosition(self, part2=False):
positions = {} positions = {}
for x in range(11): for x in range(11):
positions[(x, 0)] = 0 positions[(x, 0)] = 0
y1 = self.getInput()[2].split("#") my_input = self.getInput()[2:4]
positions[(2, 1)] = ord(y1[3]) - 64 if part2:
positions[(4, 1)] = ord(y1[4]) - 64 my_input = [my_input[0], " #D#C#B#A#", ' #D#B#A#C#', my_input[1]]
positions[(6, 1)] = ord(y1[5]) - 64
positions[(8, 1)] = ord(y1[6]) - 64 for y, l in enumerate(my_input):
if not part2: for x, c in enumerate(l[2:].split("#")):
y2 = self.getInput()[3].split("#") if not c.strip():
positions[(2, 2)] = ord(y2[1]) - 64 continue
positions[(4, 2)] = ord(y2[2]) - 64
positions[(6, 2)] = ord(y2[3]) - 64 positions[(x * 2, y + 1)] = ord(c) - 64
positions[(8, 2)] = ord(y2[4]) - 64
else:
my1 = "#D#C#B#A#".split("#")
positions[(2, 2)] = ord(my1[1]) - 64
positions[(4, 2)] = ord(my1[2]) - 64
positions[(6, 2)] = ord(my1[3]) - 64
positions[(8, 2)] = ord(my1[4]) - 64
my2 = "#D#B#A#C#".split("#")
positions[(2, 3)] = ord(my2[1]) - 64
positions[(4, 3)] = ord(my2[2]) - 64
positions[(6, 3)] = ord(my2[3]) - 64
positions[(8, 3)] = ord(my2[4]) - 64
y2 = self.getInput()[3].split("#")
positions[(2, 4)] = ord(y2[1]) - 64
positions[(4, 4)] = ord(y2[2]) - 64
positions[(6, 4)] = ord(y2[3]) - 64
positions[(8, 4)] = ord(y2[4]) - 64
return positions return positions
def part1(self) -> Any: def part1(self) -> Any:
global gMinCost
gMinCost = 5e4
initPos = self.getStartingPosition() initPos = self.getStartingPosition()
print(play(initPos, 0)) return play(initPos)
return gMinCost
def part2(self) -> Any: def part2(self) -> Any:
global gMinCost
gMinCost = 5e4
initPos = self.getStartingPosition(part2=True) initPos = self.getStartingPosition(part2=True)
print(initPos) return play(initPos)
print(len(list(getLegalMoves(initPos))), list(getLegalMoves(initPos)))
play(initPos, 0)
return gMinCost

5
inputs/test_input23_1_1 Normal file
View File

@ -0,0 +1,5 @@
#############
#...........#
###C#D#D#A###
#B#A#B#C#
#########

5
inputs/test_input23_2_1 Normal file
View File

@ -0,0 +1,5 @@
#############
#...........#
###C#D#D#A###
#B#A#B#C#
#########