#!/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')