AdventOfCode/2024/16/solution.py

87 lines
3.0 KiB
Python

#!/bin/python3
import sys,time,re
from pprint import pprint
sys.path.insert(0, '../../')
from fred import list2int,get_re,nprint,lprint,loadFile,dijkstra,toGrid,dfs,bfs,findInGrid,get_value_in_direction,addTuples,subTuples,create_graph_from_grid,manhattan_distance
start_time = time.time()
input_f = 'input'
#########################################
# #
# Part 1 #
# #
#########################################
def part1():
grid = toGrid(input_f)
start = findInGrid(grid,'S')
end = findInGrid(grid,'E')
print(start,end)
def a_star(graph, start, end, heuristic):
import heapq
# Priority queue stores (f_score, current_node, current_direction)
priority_queue = [(0, start, None)]
g_scores = {node: float('inf') for node in graph} # Cost from start to each node
g_scores[start] = 0
f_scores = {node: float('inf') for node in graph}
f_scores[start] = heuristic(start, end)
previous_nodes = {node: None for node in graph}
while priority_queue:
current_f_score, current_node, previous_direction = heapq.heappop(priority_queue)
if current_node == end:
break
for neighbor, weight in graph[current_node]:
current_direction = (
neighbor[0] - current_node[0], # Row direction (-1, 0, 1)
neighbor[1] - current_node[1] # Col direction (-1, 0, 1)
)
turn_cost = 1000 if previous_direction and current_direction != previous_direction else 0
tentative_g_score = g_scores[current_node] + weight + turn_cost
if tentative_g_score < g_scores[neighbor]:
g_scores[neighbor] = tentative_g_score
f_scores[neighbor] = tentative_g_score + heuristic(neighbor, end)
previous_nodes[neighbor] = current_node
heapq.heappush(priority_queue, (f_scores[neighbor], neighbor, current_direction))
path = []
while end is not None:
path.append(end)
end = previous_nodes[end]
path.reverse()
return path, g_scores[path[-1]]
graph = create_graph_from_grid(grid,start,end,'#')
path, score = a_star(graph,start,end,manhattan_distance)
#print(path)
return score #Instead of implementing edge cases, just try with turning (adding 1000) to the result, if that's wrong, just don't add it. I got it right by not turning right away.
start_time = time.time()
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
#########################################
# #
# Part 2 #
# #
#########################################
def part2():
return
start_time = time.time()
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')