Created
January 25, 2012 01:06
-
-
Save sli/1673933 to your computer and use it in GitHub Desktop.
Dijkstra's algo implementation for Arkham Asylum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from __future__ import generators | |
| class priorityDictionary(dict): | |
| def __init__(self): | |
| '''Initialize priorityDictionary by creating binary heap | |
| of pairs (value,key). Note that changing or removing a dict entry will | |
| not remove the old pair from the heap until it is found by smallest() or | |
| until the heap is rebuilt.''' | |
| self.__heap = [] | |
| dict.__init__(self) | |
| def smallest(self): | |
| '''Find smallest item after removing deleted items from heap.''' | |
| if len(self) == 0: | |
| raise IndexError, "smallest of empty priorityDictionary" | |
| heap = self.__heap | |
| while heap[0][1] not in self or self[heap[0][1]] != heap[0][0]: | |
| lastItem = heap.pop() | |
| insertionPoint = 0 | |
| while 1: | |
| smallChild = 2*insertionPoint+1 | |
| if smallChild+1 < len(heap) and \ | |
| heap[smallChild] > heap[smallChild+1]: | |
| smallChild += 1 | |
| if smallChild >= len(heap) or lastItem <= heap[smallChild]: | |
| heap[insertionPoint] = lastItem | |
| break | |
| heap[insertionPoint] = heap[smallChild] | |
| insertionPoint = smallChild | |
| return heap[0][1] | |
| def __iter__(self): | |
| '''Create destructive sorted iterator of priorityDictionary.''' | |
| def iterfn(): | |
| while len(self) > 0: | |
| x = self.smallest() | |
| yield x | |
| del self[x] | |
| return iterfn() | |
| def __setitem__(self,key,val): | |
| '''Change value stored in dictionary and add corresponding | |
| pair to heap. Rebuilds the heap if the number of deleted items grows | |
| too large, to avoid memory leakage.''' | |
| dict.__setitem__(self,key,val) | |
| heap = self.__heap | |
| if len(heap) > 2 * len(self): | |
| self.__heap = [(v,k) for k,v in self.iteritems()] | |
| self.__heap.sort() # builtin sort likely faster than O(n) heapify | |
| else: | |
| newPair = (val,key) | |
| insertionPoint = len(heap) | |
| heap.append(None) | |
| while insertionPoint > 0 and \ | |
| newPair < heap[(insertionPoint-1)//2]: | |
| heap[insertionPoint] = heap[(insertionPoint-1)//2] | |
| insertionPoint = (insertionPoint-1)//2 | |
| heap[insertionPoint] = newPair | |
| def setdefault(self,key,val): | |
| '''Reimplement setdefault to call our customized __setitem__.''' | |
| if key not in self: | |
| self[key] = val | |
| return self[key] | |
| def Dijkstra(G,start,end=None): | |
| D = {} | |
| P = {} | |
| Q = priorityDictionary() | |
| Q[start] = 0 | |
| for v in Q: | |
| D[v] = Q[v] | |
| if v == end: break | |
| for w in G[v]: | |
| #vwLength = D[v] + G[v][w] | |
| vwLength = D[v] + 1 | |
| if w in D: | |
| if vwLength < D[w]: | |
| raise ValueError, "Dijkstra: found better path to already-final vertex" | |
| elif w not in Q or vwLength < Q[w]: | |
| Q[w] = vwLength | |
| P[w] = v | |
| return (D,P) | |
| def shortestPath(G,start,end): | |
| D,P = Dijkstra(G,start,end) | |
| Path = [] | |
| while 1: | |
| Path.append(end) | |
| if end == start: break | |
| end = P[end] | |
| Path.reverse() | |
| return Path | |
| ### TEST ### | |
| if __name__ == '__main__': | |
| import time | |
| graph = { | |
| # Streets | |
| 'Downtown Streets': ['Bank of Arkham', 'Arkham Asylum', 'Independence Square', 'Northside Streets', 'Easttown Streets'], | |
| 'Easttown Streets': ["Hibb's Roadhouse", "Velma's Diner", 'Police Station', 'Downtown Streets', 'Rivertown Streets'], | |
| 'French Hill Streets': ['The Witch House', 'Silver Twilight Lodge', 'Miskatonic University Streets', 'Rivertown Streets', 'Southside Streets'], | |
| 'Merchant District Streets': ['Unvisited Isle', 'River Docks', 'The Unnamable', 'Rivertown Streets', 'Miskatonic University Streets', 'Northside Streets', 'Downtown Streets'], | |
| 'Miskatonic University Streets': ['Science Building', 'Administration', 'Library', 'Merchant District Streets', 'French Hill Streets', 'Uptown Streets'], | |
| 'Northside Streets': ['Train Station', 'Newspaper', 'Curiositie Shoppe', 'Downtown Streets', 'Merchant District Streets'], | |
| 'Rivertown Streets': ['Graveyard', 'Black Cave', 'General Store', 'Easttown Streets', 'Merchant District Streets', 'French Hill Streets'], | |
| 'Southside Streets': ["Ma's Boarding House", 'South Church', 'Historical Society', 'Uptown Streets', 'French Hill Streets'], | |
| 'Uptown Streets': ["St. Mary's Hospital", 'Ye Olde Magick Shoppe', 'Woods', 'Southside Streets', 'Miskatonic University Streets'], | |
| # Locations | |
| 'Administration': ['Miskatonic University Streets'], | |
| 'Arkham Asylum': ['Downtown Streets'], | |
| 'Bank of Arkham': ['Downtown Streets'], | |
| 'Black Cave': ['Rivertown Streets'], | |
| 'Curiositie Shoppe': ['Northside Streets'], | |
| 'General Store': ['Rivertown Streets'], | |
| 'Graveyard': ['Rivertown Streets'], | |
| "Hibb's Roadhouse": ['Easttown Streets'], | |
| 'Historical Society': ['Southside Streets'], | |
| 'Independence Square': ['Downtown Streets'], | |
| 'Library': ['Miskatonic University Streets'], | |
| "Ma's Boarding House": ['Southside Streets'], | |
| 'Newspaper': ['Northside Streets'], | |
| 'Police Station': ['Easttown Streets'], | |
| 'River Docks': ['Merchant District Streets'], | |
| 'Science Building': ['Miskatonic University Streets'], | |
| 'Silver Twilight Lodge': ['French Hill Streets'], | |
| 'South Church': ['Southside Streets'], | |
| "St. Mary's Hospital": ['Uptown Streets'], | |
| 'The Unnamable': ['Merchant District Streets'], | |
| 'The Witch House': ['French Hill Streets'], | |
| 'Train Station': ['Northside Streets'], | |
| 'Unvisited Isle': ['Merchant District Streets'], | |
| "Velma's Diner": ['Easttown Streets'], | |
| 'Woods': ['Uptown Streets'], | |
| 'Ye Olde Magick Shoppe': ['Uptown Streets'] | |
| } | |
| s = time.time() | |
| path = shortestPath(graph, 'Train Station', 'South Church') | |
| e = time.time() | |
| print 'Path: %s' % ' -> '.join(path) | |
| print 'Time taken: %.5fs' % (e-s) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment