initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__
|
||||
85
classes.py
Normal file
85
classes.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from enum import Enum
|
||||
import math
|
||||
|
||||
|
||||
class ParsingMode(Enum):
|
||||
LOCATIONS = 1
|
||||
FLIGHTSCHEDULE = 2
|
||||
FINDCONNECTION = 3
|
||||
|
||||
|
||||
class LocationType(Enum):
|
||||
LOCATION = 1
|
||||
HALTESTELLE = 2
|
||||
FLUGHAFEN = 3
|
||||
|
||||
|
||||
class TransportData():
|
||||
def __init__(self, co2: float, speed: float, distance_penalty: float):
|
||||
self.co2 = co2
|
||||
self.speed = speed
|
||||
self.distance_penalty = distance_penalty
|
||||
|
||||
|
||||
class TransportMethod(Enum):
|
||||
"""
|
||||
(co2 emission, speed, distance_penalty)
|
||||
"""
|
||||
WALK = TransportData(0, 4, 0.2)
|
||||
CITY = TransportData(0.189, 30, 0.2)
|
||||
AUTOBAHN = TransportData(0.189, 100, 0.2)
|
||||
OEPNV = TransportData(0.055, 30, 0.1)
|
||||
ICE = TransportData(0.055, 100, 0.1)
|
||||
AIRPLANE = TransportData(0.2113, 900, 0.02)
|
||||
|
||||
|
||||
class Coordinate:
|
||||
def __init__(self, lat: float, long: float):
|
||||
self.lat = lat
|
||||
self.long = long
|
||||
|
||||
def __str__(self):
|
||||
return f"Lat: {self.lat}, Long: {self.long}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
class Location:
|
||||
def __init__(self, coord: Coordinate, continent: int, name: str, type: LocationType):
|
||||
self.coord = coord
|
||||
self.continent = continent
|
||||
self.name = name
|
||||
self.type = type
|
||||
|
||||
def __str__(self):
|
||||
return f"{{Location: {self.coord}, continent: {self.continent}, name: {self.name}, type: {self.type}}}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def distance(self, loc2) -> float:
|
||||
"""
|
||||
Calculate the distance im km between two locations with the help of the
|
||||
Seitenkosinussatz
|
||||
"""
|
||||
rErde = 6378.388
|
||||
lat1 = float(self.coord.lat)
|
||||
long1 = float(self.coord.long)
|
||||
lat2 = float(loc2.coord.lat)
|
||||
long2 = float(loc2.coord.long)
|
||||
inner = math.sin(lat1) * math.sin(lat2) + math.cos(lat1) * math.cos(lat2) * math.cos(long2 - long1)
|
||||
return rErde * math.acos(inner)
|
||||
|
||||
|
||||
class DataSet:
|
||||
def __init__(self, locations: dict, flights: dict, connection: tuple):
|
||||
self.locations = locations
|
||||
self.flights = flights
|
||||
self.connection = connection
|
||||
|
||||
def __str__(self):
|
||||
return f"locations: {self.locations}, flights: {self.flights}, connection: {self.connection}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
77
dijkstra.py
Normal file
77
dijkstra.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Module, which holds the logic for the solving algorithms
|
||||
"""
|
||||
|
||||
from classes import DataSet, LocationType, Location, TransportMethod
|
||||
|
||||
|
||||
def calc_co2(distance: float, method: TransportMethod) -> float:
|
||||
"""
|
||||
Return co2 emission in kg
|
||||
"""
|
||||
return (distance * method.value.distance_penalty) * method.value.co2
|
||||
|
||||
|
||||
def calc_time(distance: float, method: TransportMethod) -> float:
|
||||
"""
|
||||
Return time taking in h
|
||||
"""
|
||||
return (distance * method.value.distance_penalty) / method.value.speed
|
||||
|
||||
|
||||
def add_node(graph: dict, frm: str, to: str, locs: dict, method: TransportMethod):
|
||||
"""
|
||||
Add a node into the graph
|
||||
"""
|
||||
distance = locs[frm].distance(locs[to])
|
||||
co2 = calc_co2(distance, method)
|
||||
time = calc_time(distance, method)
|
||||
new_connection: dict = {to: {"type": method, "co2": co2, "time": time}}
|
||||
graph[frm].append(new_connection)
|
||||
print(f"Added node from {frm} to {to} with type {method}.")
|
||||
|
||||
|
||||
def create_graph(dataset: DataSet) -> dict:
|
||||
"""
|
||||
Creates the initial graph, with all edges
|
||||
"""
|
||||
locations = dataset.locations
|
||||
graph: dict = {}
|
||||
|
||||
# add nodes with no edges
|
||||
for start in locations:
|
||||
graph.update({start: []})
|
||||
|
||||
# add edges
|
||||
for start in locations:
|
||||
for dest in locations:
|
||||
# skip, if we wouldnt go anywhere
|
||||
if start == dest:
|
||||
continue
|
||||
print(f"Searching for nodes from {start} to {dest}...")
|
||||
distance = locations[start].distance(locations[dest])
|
||||
|
||||
# Individualtransport
|
||||
if distance <= 1:
|
||||
add_node(graph, start, dest, locations, TransportMethod.WALK)
|
||||
if distance <= 10 + 1:
|
||||
add_node(graph, start, dest, locations, TransportMethod.CITY)
|
||||
if distance <= 2000 + 10 + 1:
|
||||
add_node(graph, start, dest, locations, TransportMethod.AUTOBAHN)
|
||||
|
||||
# Train
|
||||
if locations[start].type == LocationType.HALTESTELLE:
|
||||
dest_type = locations[dest].type
|
||||
# there are only trains between haltestellen or airports
|
||||
if dest_type == LocationType.HALTESTELLE or dest_type == LocationType.FLUGHAFEN:
|
||||
if distance <= 25:
|
||||
add_node(graph, start, dest, locations, TransportMethod.OEPNV)
|
||||
else:
|
||||
add_node(graph, start, dest, locations, TransportMethod.ICE)
|
||||
|
||||
# Flying
|
||||
flights = dataset.flights
|
||||
for flight in flights:
|
||||
add_node(graph, start, dest, locations, TransportMethod.AIRPLANE)
|
||||
|
||||
return graph
|
||||
13
file.txt
Normal file
13
file.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Locations:
|
||||
csu_zen ; Location; 48.176971; 11.5895754; 1; CSU-Zentrale
|
||||
mun_hbf ; PublicTransportStop; 48.140235; 11.559417; 1; Muenchen Hbf.
|
||||
mun_flugh; Airport; 48.140235; 11.770723; 1; Muenchen Flughafen
|
||||
reichstag; Location; 52.518191; 13.3751725; 1; Reichstags Gebaeude
|
||||
ber_flugh; Airport; 52.553625; 13.2901544; 1; Berlin Flughafen Tegel
|
||||
ber_hbf ; PublicTransportStop; 52.524195; 13.3693013; 1; Berlin Hbf
|
||||
|
||||
FlightSchedule:
|
||||
mun_flugh; ber_flugh; 0; True
|
||||
|
||||
FindBestConnections:
|
||||
csu_zen; muc
|
||||
21
main.py
Normal file
21
main.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
Run program from here.
|
||||
Requires: python > 3.10.x
|
||||
"""
|
||||
|
||||
from parser import parse
|
||||
from dijkstra import create_graph
|
||||
|
||||
|
||||
INPUTFILE = "file.txt"
|
||||
|
||||
|
||||
def main():
|
||||
dataset: dict = parse(INPUTFILE)
|
||||
print(dataset)
|
||||
graph: dict = create_graph(dataset)
|
||||
print(graph)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
78
parser.py
Normal file
78
parser.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Parse the input file
|
||||
"""
|
||||
|
||||
from classes import ParsingMode, Coordinate, LocationType, Location, DataSet
|
||||
|
||||
|
||||
def parse(filename: str) -> DataSet:
|
||||
"""
|
||||
Parse a given file with given format and return a DataSet containing the
|
||||
parsed locations, flightschedules and wanted connection
|
||||
"""
|
||||
locations: dict = {}
|
||||
flights: dict = {}
|
||||
connection: tuple = ()
|
||||
with open(filename, "r") as file:
|
||||
for line in file.readlines():
|
||||
line = line.replace("\n", "") # strip newline
|
||||
line = line.replace(" ", "") # strip whitespaces
|
||||
|
||||
# skip empty lines
|
||||
if line == "":
|
||||
continue
|
||||
|
||||
# meta parsing
|
||||
match line:
|
||||
case "Locations:":
|
||||
print("Parsing `Locations`...")
|
||||
current_parsing = ParsingMode.LOCATIONS
|
||||
continue
|
||||
case "FlightSchedule:":
|
||||
print("Parsing `FlightSchedule`...")
|
||||
current_parsing = ParsingMode.FLIGHTSCHEDULE
|
||||
continue
|
||||
case "FindBestConnections:":
|
||||
print("Parsing `FindBestConnections`...")
|
||||
current_parsing = ParsingMode.FINDCONNECTION
|
||||
continue
|
||||
|
||||
match current_parsing:
|
||||
case ParsingMode.LOCATIONS:
|
||||
print("Parsing location...")
|
||||
splitted = line.split(";")
|
||||
assert(len(splitted) == 6) # make sure we have a location
|
||||
id = splitted[0]
|
||||
type = splitted[1]
|
||||
match type:
|
||||
case "Location":
|
||||
type = LocationType.LOCATION
|
||||
case "PublicTransportStop":
|
||||
type = LocationType.HALTESTELLE
|
||||
case "Airport":
|
||||
type = LocationType.FLUGHAFEN
|
||||
lat = splitted[2]
|
||||
long = splitted[3]
|
||||
continent = splitted[4]
|
||||
name = splitted[5]
|
||||
coord = Coordinate(lat, long)
|
||||
location = Location(coord, continent, name, type)
|
||||
locations.update({id: location})
|
||||
case ParsingMode.FLIGHTSCHEDULE:
|
||||
print("Parsing flight schedule...")
|
||||
splitted = line.split(";")
|
||||
assert(len(splitted) >= 2)
|
||||
id1 = splitted[0]
|
||||
id2 = splitted[1]
|
||||
if len(splitted) == 3:
|
||||
stops = splitted[2]
|
||||
else:
|
||||
stops = 0
|
||||
flights.update({id1: {"to": id2, "stops": stops}})
|
||||
continue
|
||||
case ParsingMode.FINDCONNECTION:
|
||||
print("Parsing connection...")
|
||||
splitted = line.split(";")
|
||||
assert(len(splitted) == 2)
|
||||
connection = (splitted[0], splitted[1])
|
||||
return DataSet(locations, flights, connection)
|
||||
Reference in New Issue
Block a user