164 lines
5.7 KiB
Python
164 lines
5.7 KiB
Python
from argparse import ArgumentError
|
|
from math import log, ceil
|
|
from operator import itemgetter
|
|
from classes import *
|
|
|
|
class SolvingAlgorithm:
|
|
def __init__(self,space,gMngr:GarageManager):
|
|
self.space:MetricSpace = space
|
|
self.garageManager:GarageManager = gMngr
|
|
self.amountTraveled = 0
|
|
|
|
def getGarageForCar(self,car:Point):
|
|
garages:List[Garage] = list(self.garageManager.garages)
|
|
garages = sorted(garages,key=lambda g: self.space.distancefunction.apply(car,g))
|
|
|
|
for g in garages:
|
|
if self.garageManager.is_full(g):
|
|
continue
|
|
else:
|
|
g.cars_parked.append(g)
|
|
self.amountTraveled += self.space.distancefunction.apply(car,g)
|
|
return g
|
|
|
|
return None
|
|
|
|
|
|
class MST():
|
|
@classmethod
|
|
def _helper_getListInPointset(self, pointesets:List[List[Point]] , point:tuple):
|
|
for li in pointesets:
|
|
if point in li:
|
|
return li
|
|
return None
|
|
|
|
|
|
def __init__(self, points:set, distancefunction: DistanceFunction,space:MetricSpace, powerTWO = False,mst_visualize=True):
|
|
self.points = points
|
|
self.distancefunction = distancefunction
|
|
|
|
all_edges = []
|
|
for i in self.points:
|
|
for j in self.points:
|
|
if not i == j:
|
|
if not (j,i, distancefunction.apply(i,j)) in all_edges:
|
|
all_edges.append((i,j, distancefunction.apply(i,j)))
|
|
|
|
all_edges = sorted(all_edges,key=itemgetter(2))
|
|
|
|
minimal_edges = [] # edge is represented by (i,j, distance/Weight)
|
|
pointSets:List[List[Point]] = []
|
|
for p in self.points:
|
|
pointSets.append([p])
|
|
|
|
visualisations =[]
|
|
for edge in all_edges:
|
|
if len(pointSets) <= 1: break
|
|
li0 = MST._helper_getListInPointset(pointSets,edge[0])
|
|
li1 = MST._helper_getListInPointset(pointSets,edge[1])
|
|
|
|
if not( li0 == li1):
|
|
minimal_edges.append(edge)
|
|
|
|
li_new = li0 + li1
|
|
pointSets.remove(li0)
|
|
pointSets.remove(li1)
|
|
pointSets.append( li_new)
|
|
|
|
if (mst_visualize):
|
|
a= frameGenerator.point_to_pixel_center(space,edge[0])
|
|
b= frameGenerator.point_to_pixel_center(space,edge[1])
|
|
data = [ a[0], a[1], b[0], b [1], (23,64,96,100)]
|
|
visualisations.append(RenderTask(RenderTaskType.LINE,"mst",data))
|
|
RenderTaskStack.add_single_frame_render(RenderTaskFrame(visualisations.copy()))
|
|
|
|
if(powerTWO):
|
|
for x in range(len(minimal_edges)):
|
|
c_edge = minimal_edges[x]
|
|
c_edge = ( c_edge[0], c_edge[1], 2**ceil(log(c_edge[2],2)) )
|
|
minimal_edges[x] = c_edge
|
|
|
|
if (mst_visualize):
|
|
RenderTaskStack.add_single_frame_render(RenderTaskFrame(visualisations.copy(),True))
|
|
|
|
self.minimalEdges: List[tuple[Point,Point,float]] = minimal_edges
|
|
|
|
def _dfs_recursive(self, tree, start, visited =[]):
|
|
# due tue MST property,
|
|
tour = []
|
|
|
|
for edge in tree:# go throug all edges and recursively walk down all that lead to new places, on return add back edge
|
|
if edge[0].get_location() == start.get_location() and edge[1].get_location() not in visited:
|
|
tour.append(edge)
|
|
visited.append(start.get_location()) # visited only needs to be carried in for a node downwards but not upwards, since this is a MST
|
|
data = self._dfs_recursive(tree,edge[1],visited)
|
|
tour+= data # add subtree
|
|
tour.append((edge[1],edge[0],edge[2])) #append reversed edge
|
|
|
|
return tour
|
|
|
|
|
|
|
|
def get_dfs_eulerwalk(self,start:Point, level= 0):
|
|
directionalEdges = []
|
|
for min_edge in self.minimalEdges:
|
|
i,j,dist = min_edge
|
|
if dist > 2**level: continue
|
|
directionalEdges.append((i,j,dist))
|
|
directionalEdges.append((j,i,dist))
|
|
|
|
# create walk with dfs
|
|
walk:List[tuple[Point,Point,float]] = self._dfs_recursive(directionalEdges,start)
|
|
|
|
return walk
|
|
|
|
class AlgorithmA(SolvingAlgorithm):
|
|
def __init__(self, space:MetricSpace, gMngr: GarageManager):
|
|
super().__init__(space, gMngr)
|
|
gar_set = set(gMngr.garages)
|
|
self.mst = MST(gar_set,space.distancefunction,space,True)
|
|
|
|
def getGarageForCar(self, car: Car):
|
|
garagedata= self.garageManager.get_garage_at_location(car.get_location())
|
|
garagefound = garagedata[0]
|
|
garage: Garage = garagedata[1]
|
|
if(not garagefound):
|
|
raise ArgumentError("No garage found INSIDE of ALGO A")
|
|
|
|
if(not self.garageManager.is_full(garage)):
|
|
car.set_walk(0)
|
|
garage.cars_parked.append(car)
|
|
return garage
|
|
|
|
carParked = False
|
|
while not carParked:
|
|
walk = self.mst.get_dfs_eulerwalk(car,car.get_walk()) # implicite, position of car determines where it arrived!
|
|
|
|
if len(walk) <1: continue
|
|
if car.get_walk() >32:
|
|
raise ArgumentError("walk got over power 32, this is likely an error and an infinite loop")
|
|
|
|
currentGarage = self.garageManager.get_garage_at_location(car.get_location())
|
|
for x in walk:
|
|
currentGarage = self.garageManager.get_garage_at_location(
|
|
x[1].get_location()) # second argument of edge
|
|
|
|
##TODO Finish implementation, garage full case and proper start
|
|
|
|
if not self.garageManager.is_full(currentGarage):
|
|
garage.cars_parked.append(car)
|
|
return garage
|
|
|
|
|
|
car.add_to_walk(1)
|
|
|
|
return super().getGarageForCar(car)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|