#!/usr/bin/python """ This program navigates between cities using the A* algorithm. It takes in a ".geo" file that models cities and roads as a graph. It is then able to recieve requests from the user, planning the best route to take between any two cities in its model. It relies on an AStarGraph object, that you must write. The API is as given in the assignment. """ __author__ = "Adam A. Smith" __version__ = "2023.11.08" from astargraph import AStarGraph import decimal import os # load a file & make an AStarGraph from its lines def make_astar_graph(filename): graph = AStarGraph() with open(filename, "r") as file: addCities = True for line in file: line = line.strip() if len(line) == 0: addCities = False # 1st part: adding cities to the graph elif addCities: tokens = line.split("\t") graph.add_city(tokens[0], float(tokens[1]), float(tokens[2])) # 2nd part: adding roads else: tokens = line.split("\t") graph.add_road(tokens[0], tokens[1], float(tokens[2])) return graph def query_user(graph): print("Please enter your query:\n") while True: query = input("> ").strip() # do nothing on empty string if len(query) == 0: continue # quit on "!quit" or "!exit" elif query == "!quit" or query == "!exit": break # help menu elif query == "!help": print_help_menu() # find path(s) elif "-" in query: cities = query.split("-") cities = [city.strip() for city in cities] # actual path finding for i in range(len(cities) - 1): try: path = graph.find_path(cities[i], cities[i + 1]) # print on failure if path is None: print("I'm sorry. There's not a path from " + cities[i] + " to " + cities[i + 1] + ".") # print on found path else: distance = round(graph.measure_path(path)) print("Path found: " + path[0], end="") for j in range(1, len(path)): print(" - " + path[j], end="") print(" (" + str(distance) + " km)") # catch for bad cities except ValueError as ex: print('I\'m sorry. Either "' + cities[i] + '" or "' + cities[i + 1] + '" is unknown to me.') print() # query 1 city--get info on it else: # if valid, give its location & neighbors if graph.is_valid_city(query): location = graph.get_city_location(query) latitude = location[0] longitude = location[1] print(query + " is located at (", end="") # latitude if latitude > 0: print(str(round(latitude, 2)) + "° N, ", end="") elif latitude < 0: print(str(round(-latitude, 2)) + "° S, ", end="") else: print("0°, ", end="") # longitude if longitude > 0: print(str(round(longitude, 2)) + "° E). ", end="") elif longitude < 0: print(str(round(-longitude, 2)) + "° W). ", end="") else: print("0°). ", end="") # neighbors neighbors = graph.get_neighboring_cities(query) if len(neighbors) == 0: print("It is not connected to any other city.") else: if len(neighbors) == 1: print("It has a road to " + neighbors[0] + ".") elif len(neighbors) == 2: print("It has roads to " + neighbors[0] + " and " + neighbors[1] + ".") else: print("It has roads to ", end="") for i in range(len(neighbors) - 1): print(neighbors[i] + ", ", end="") print("and " + neighbors[-1] + ".") # otherwise, error message else: print('I\'m sorry. There is no city "' + query + '".') print() print("Goodbye!") # just prints a help menu def print_help_menu(): print("\t\t\tprints info on a city") print("\t-\tcalculates a path") print("\t!help\t\tprints this help menu") print("\t!exit\t\texits the program") if __name__ == "__main__": # test command-line args from sys import argv, exit, stderr # make sure we have a file if len(argv) != 2: print("Please enter a file name!", file=stderr) exit(1) # make the graph, and query on it try: graph = make_astar_graph(argv[1]) print('File "' + argv[1] + '" has been loaded with ' + str(len(graph)) + ' cities.') query_user(graph) except FileNotFoundError: print('Couldn\'t open file "' +argv[1]+ '".', file=stderr) exit(1)