/aima/driver.py

https://github.com/bmiro/carmageddon
Python | 243 lines | 204 code | 24 blank | 15 comment | 2 complexity | d5d55e5125c1c85fab79d13a860824f5 MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. from copy import deepcopy, copy
  3. from passenger import *
  4. from datetime import datetime
  5. # Macros for easy indexation of coor tuples.
  6. # i.e. a[X] -> xcoor
  7. INTMAX = 3000000000
  8. def distance(src, dst):
  9. return abs(src[0] - dst[0]) + abs(src[1] - dst[1])
  10. def distanceRara(src, dst):
  11. if src[1] == "fi":
  12. src = src[0]
  13. return abs(src[0] - dst[0]) + abs(src[1] - dst[1])
  14. class Driver(Passenger):
  15. t = 0
  16. def __init__(self, name, xo, yo, xd, yd, maxSpace):
  17. Passenger.__init__(self, name, xo, yo, xd, yd)
  18. self.__freespace = maxSpace
  19. self.__maxSpace = maxSpace
  20. self.__passengers = []
  21. self.calculatedRouteWeight = None
  22. def __copy__(self):
  23. newone = Driver(self.getName(),self.getOrigin()[0],self.getOrigin()[1],self.getDestination()[0],self.getDestination()[1],self.__maxSpace)
  24. newone.__dict__.update(self.__dict__)
  25. newone.setPassengers(copy(self.__passengers))
  26. return newone
  27. def isEmpty(self):
  28. return self.__freespace == self.__maxSpace
  29. def getPassengers(self):
  30. return self.__passengers
  31. def setPassengers(self, p):
  32. self.__passengers = p
  33. def getMaxSpace(self):
  34. return self.__maxSpace
  35. """ Recives a passenger name """
  36. def pickupPassenger(self, passenger):
  37. self.__passengers.append(passenger)
  38. self.__freespace -= 1
  39. self.calculatedRouteWeight = None
  40. """ Recives a passenger name """
  41. def leavePassenger(self, passenger):
  42. self.__passengers.remove(passenger)
  43. self.__freespace += 1
  44. self.calculatedRouteWeight = None
  45. def getDestinations(self):
  46. d = []
  47. for p in self.__passsengers:
  48. d.append(p.getDestination())
  49. return d
  50. """ Returns the min route that involves all the passengers
  51. " i.e.
  52. " [[[33, 44], "DriverOrigin", "D-0000"],
  53. " [[34, 45], "PickupPassenger", "P-00001"],
  54. " [[55, 65], "LeavePassenger", "P-00001"],
  55. " [[57, 70], "DriverDestination", "D-0000"]]
  56. """
  57. def getRoute(self, state):
  58. # The optimus one returns a optimus route but it takes too long (NP)...
  59. # So we take a very very got aproach in less time
  60. return self.getRouteHeuristic(state)
  61. def getRouteHeuristic(self, state):
  62. ## Dictionary of tuplas name-originPoint pointing destinations
  63. # i.e. { ("P-0001", [34, 45]) : [22, 56] }
  64. checkpoints = {}
  65. ## Dictionary of carried passengers pointing to their destinations
  66. # i.e { ("P-0001" : [22, 56] }
  67. checkpointsDest = {}
  68. ## List of tuples [point, event, name]
  69. # i.e. [[34, 45], "PickupPassenger", "P-0001"]
  70. route = []
  71. # Inserting all origin points
  72. for p in self.__passengers:
  73. src = state.getPassengers()[p][0].getOrigin()
  74. dst = state.getPassengers()[p][0].getDestination()
  75. checkpoints[(p, src)] = dst
  76. current = (self.getOrigin(), "DriverOrigin", self.getName())
  77. route.append(current)
  78. npass = 0
  79. routeDist = 0
  80. while checkpoints or checkpointsDest:
  81. # Searching nearst point
  82. dmin = INTMAX
  83. nearest = None
  84. for (n, p) in checkpointsDest.iteritems():
  85. d = distance(current[0], p)
  86. if d < dmin:
  87. dmin = d
  88. nearest = p
  89. name = n
  90. if npass < self.__maxSpace:
  91. for (n, p) in checkpoints.keys():
  92. d = distance(current[0], p)
  93. if d < dmin:
  94. dmin = d
  95. nearest = p
  96. name = n
  97. if (name, nearest) in checkpoints:
  98. checkpointsDest[name] = checkpoints[(name, nearest)]
  99. checkpoints.pop((name, nearest))
  100. event = "PickupPassenger"
  101. npass += 1
  102. else:
  103. event = "LeavePassenger"
  104. checkpointsDest.pop(name)
  105. npass -= 1
  106. routeDist += d
  107. current = (nearest, event, name)
  108. route.append(current)
  109. route.append((self.getDestination(), "DriverDestination", self.getName()))
  110. self.calculatedRouteWeight = routeDist + distance(route[-2][0], route[-1][0])
  111. return route
  112. def getRouteOptimus(self, state):
  113. ## Dictionary of point pointing destinations if exist
  114. # i.e. { [34, 45] : [22, 56] --> Point is origin
  115. # [56, 77] : None } --> Point is destination
  116. checkpoints = {}
  117. checkpointsDest = {}
  118. ## List of tuples [point, event]
  119. # i.e. [[34, 45] "PickupPassenger"]
  120. route = []
  121. # Inserting all origin points
  122. lchecks = [(self.getOrigin(),"fi")]
  123. for p in self.__passengers:
  124. checkpoints[state.getPassengers()[p][0].getOrigin()] = state.getPassengers()[p][0].getDestination()
  125. lchecks.append((state.getPassengers()[p][0].getOrigin(),state.getPassengers()[p][0].getDestination()))
  126. current = (self.getOrigin(), "DriverOrigin")
  127. npass = 0
  128. temp = datetime.now()
  129. lmarques = [False]*len(lchecks)
  130. lmarques[0] = True
  131. sol = []
  132. soltmp = []
  133. soltmp.append(lchecks[0])
  134. self.permuta(lchecks,0,lmarques,soltmp,sol,len(lchecks),0,INTMAX,self.getDestination())
  135. sol = sol[-1]
  136. #print sol
  137. sol[0].append((self.getDestination()))
  138. self.calculatedRouteWeight = sol[1]
  139. sol[0][0] = sol[0][0][0]
  140. return sol[0]
  141. def permuta(self,lini,npass,lmarques,soltmp,s,npoints,dist,maxim,dest):
  142. if dist + distanceRara(soltmp[-1],dest) > maxim:
  143. return
  144. if len(lini) == 1:
  145. soltmp.append(lini[0][0])
  146. distFinal = dist + distance(soltmp[-1], dest)
  147. if distFinal < maxim:
  148. s.append((soltmp[:], distFinal))
  149. maxim = distFinal
  150. return
  151. if len(soltmp) == npoints*2 -1:
  152. distFinal = dist + distance(soltmp[-1], dest)
  153. if distFinal < maxim:
  154. s.append((soltmp[:], distFinal))
  155. maxim = distFinal
  156. longitud = len(lini)
  157. for x in xrange(longitud):
  158. if not lmarques[x] :
  159. lmarques[x] = True
  160. if lini[x][1] != "fi" and npass < 2:
  161. soltmp.append(lini[x][0])
  162. lmarques.append(False)
  163. lini.append((lini[x][1],"fi"))
  164. incr = distance(lini[x-1][0],lini[x][0])
  165. self.permuta(lini,npass+1,lmarques,soltmp,s,npoints,dist +incr,maxim,dest )
  166. lmarques.pop()
  167. lini.pop()
  168. soltmp.pop()
  169. else:
  170. soltmp.append(lini[x][0])
  171. self.permuta(lini,npass-1,lmarques,soltmp,s,npoints,dist + distance(lini[x-1][0],lini[x][0]),maxim,dest)
  172. soltmp.pop()
  173. lmarques[x] = False
  174. def getRouteWeight(self,state):
  175. if self.calculatedRouteWeight != None:
  176. return self.calculatedRouteWeight
  177. route = self.getRoute(state)
  178. return self.calculatedRouteWeight
  179. def printRoute(self, state):
  180. s = "Driver %s route:\n" % self.getName()
  181. route = self.getRoute(state)
  182. print route[0]
  183. for (point, event, name) in route:
  184. if "Passenger" in event:
  185. s += "\t\t" + event + " " + name + " at point " + str(point) + "\n"
  186. else:
  187. s += "\t\t" + event + " at point " + str(point) + "\n"
  188. s += "This driver covers %f km\n" % (self.getRouteWeight(state)/1000.0)
  189. return s