-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.py
More file actions
95 lines (83 loc) · 3.75 KB
/
util.py
File metadata and controls
95 lines (83 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import heapq, collections, re, sys, time, os, random
###
### All code in this file is from the Stanford CS 221
### "Text Reconstruction" assignment starter code
###
############################################################
# Uniform cost search algorithm (Dijkstra's algorithm).
class UniformCostSearch:
def __init__(self, verbose=0):
self.verbose = verbose
def solve(self, problem):
# If a path exists, set |actions| and |totalCost| accordingly.
# Otherwise, leave them as None.
self.actions = None
self.totalCost = None
self.numStatesExplored = 0
# Initialize data structures
frontier = PriorityQueue() # Explored states are maintained by the frontier.
backpointers = {} # map state to (action, previous state)
# Add the start state
startState = problem.startState()
frontier.update(startState, 0)
while True:
# Remove the state from the queue with the lowest pastCost
# (priority).
state, pastCost = frontier.removeMin()
if state == None: break
self.numStatesExplored += 1
if self.verbose >= 1:
sys.stdout.write("\rTrying %d turns..." % (self.numStatesExplored - 1))
sys.stdout.flush()
if self.verbose >= 2:
print "Exploring %s with pastCost %s" % (state.faces, pastCost)
# Check if we've reached an end state; if so, extract solution.
if problem.isEnd(state):
self.actions = []
while state != startState:
action, prevState = backpointers[state]
self.actions.append(action)
state = prevState
self.actions.reverse()
self.totalCost = pastCost
if self.verbose >= 1:
sys.stdout.write("\rSolved in %d turns" % (self.numStatesExplored - 1))
sys.stdout.flush()
print
return
# Expand from |state| to new successor states,
# updating the frontier with each newState.
for action, newState, cost in problem.succAndCost(state):
if self.verbose >= 3:
print " Action %s => %s with cost %s + %s" % (action, newState.faces, pastCost, cost)
if frontier.update(newState, pastCost + cost):
# Found better way to go to |newState|, update backpointer.
backpointers[newState] = (action, state)
if self.verbose >= 1:
print "No path found"
# Data structure for supporting uniform cost search.
class PriorityQueue:
def __init__(self):
self.DONE = -100000
self.heap = []
self.priorities = {} # Map from state to priority
# Insert |state| into the heap with priority |newPriority| if
# |state| isn't in the heap or |newPriority| is smaller than the existing
# priority.
# Return whether the priority queue was updated.
def update(self, state, newPriority):
oldPriority = self.priorities.get(state)
if oldPriority == None or newPriority < oldPriority:
self.priorities[state] = newPriority
heapq.heappush(self.heap, (newPriority, state))
return True
return False
# Returns (state with minimum priority, priority)
# or (None, None) if the priority queue is empty.
def removeMin(self):
while len(self.heap) > 0:
priority, state = heapq.heappop(self.heap)
if self.priorities[state] == self.DONE: continue # Outdated priority, skip
self.priorities[state] = self.DONE
return (state, priority)
return (None, None) # Nothing left...