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