I'm a newbee to python and computing. This is the problem that I want to implement by using Python:Three couples want to cross a river, from east to west. A boat found there can take only two persons. How to cross the river if a wife can't stay with other men without her husband?
First I created all the possible states.
def genStates():
"""
A function to generate all the possible states.
Input: None
Output: all the possible states
"""
states = []
side = ("E","W")
for a in side:
for b in side:
for c in side:
for d in side:
for e in side:
for f in side:
z = a+b+c+d+e+f
states.append(z)
return states
Then I created a graph to put legal states and their possible moves.
def genGraph(S):
"""
A function to generate a graph that contains all the legal states and their next possible states to move
Input: All the possible states
Output: A graph of all the legal states and their next possible states to move
"""
G = []
graph = {}
for i in range(len(S)):
if isLegal(S[i]) == True:
G.append(S[i])
for i in range(len(G)):
result1 = nextStates(G[i], G)
graph.update({G[i]: result1[1:]}) # add possible states to each legal states, put it in graph
return graph
I created two functions that are used in genGraph.
def isLegal(S):
"""
A function to check if a state is legal or not.
Input: None
Output: Return True if a state is legal, else return False.
"""
if S[0] != S[1]:
if S[1] == S[2] or S[1] == S[4]:
return False
elif S[2] != S[3]:
if S[3] == S[0] or S[3] == S[4]:
return False
elif S[4] != S[5]:
if S[5] == S[0] or S[5] == S[2]:
return False
return True
and
def nextStates(startnode, allstates):
"""
A function to return a set of states that a state can move to.
Input: A state and all the possible states
Output: a set of states that a state can move to
"""
possible = [startnode]
count1 = startnode.count("E")
count2 = startnode.count("W")
for i in range(1, len(allstates)):
if allstates[i].count("E") - count1 <= 2 and allstates[i].count("E") - count1 >= -2 and allstates[i].count(
"W") - count2 <= 2 and allstates[i].count("W") - count2 >= -2:
count = 0
for j in range(0,len(startnode)):
if allstates[i][j] == startnode[j]:
count += 1
if count >= 4: # Unlike MCGW problem, single unit's journey is unnecessary
possible.append(allstates[i])
return possible
and finally, I used a function from a python website to get the shortest path to implement this problem.
def genShortestPath(graph, start, end, path=[]):
"""
A function to find the shortest path in a graph, from the start to the destination.
Input: A graph of all the legal states and their states next possible states to move, the starting point and the destination
Output: the shortest path of the graph
"""
path = path + [start]
if start == end:
return path
if not (start in graph):
return None
shortestPath = None
for node in graph[start]:
if node not in path:
newpath = genShortestPath(graph, node, end, path)
if newpath:
if not shortestPath or len(newpath) < len(shortestPath):
shortestPath = newpath
return shortestPath
And finally, when I implement this problem, it can't find the shortest solution for some reasons. I printed out the graph, and next states functions to check if there's any problems for these, but it was working pretty well. What is the problem here? This is the implementing code:
def Solver():
S = genStates()
G = genGraph(S)
s = "EEEEEE" # source node
d = "WWWWWW" # destination node
result = genShortestPath(G, s, d)
print(result)
Related
Im trying to implement dfs on a matrix but inside my while loop in cases the goal is unreachable it never exists the loop.
Any ideas how to tackle that?
Some pointers for the code:
RowCol and RowNum have indices of reachable neighbours(i.e right, down,right diagonal down)I am adding that to the indices of the current node to get the neighbours indices. If it's not visited or an obstacle(equal to 1) add it to stack and repeat.
while stack:
curr = stack.get() # Dequeue the front cell
path.append(curr.pt)
# If we have reached the destination cell,
# we are done
pt = curr.pt
if pt == goal:
print("Sequence : ")
print(path)
print("Path : ")
print(curr.path+" to "+str(pt))
return curr.dist
# Otherwise enqueue its adjacent cells
for i in range(3):
if i == 0 or i == 1:
cost = 2
elif i == 2:
cost = 3
row = pt[0] + rowNum[i]
col = pt[1] + colNum[i]
# if adjacent cell is valid, has path
# and not visited yet, enqueue it.
if isValid(row, col):
if matrix[row][col] == "0" and not visited[row][col]:
visited[row][col] = True
Adjcell = queueNode([row, col], curr.dist + cost,curr.path+" to "+str(curr.pt))
stack.put(Adjcell)
# Return -1 if destination cannot be reached
print(matrix[start[0]][start[1]])
print(matrix[goal[0]][goal[1]])
print("Can't reach goal")
return -1
If you want to make loop use
while True :
I am trying to write Dijkstra's Algorithm, however I am struggling on how to 'say' certain things in code.
To visualize, here are the columns I want represented using arrays:
max_nodes
A B C Length Predecessor Visited/Unvisited
A 0 1 2 -1 U
B 1 0 1 -1 U
C 2 1 0 -1 U
So, there will be several arrays, as seen in my code below:
def dijkstra (graph, start, end)
network[max_nodes][max_nodes]
state [max_nodes][length]
state2 [max_nodes][predecessor]
state3 [max_nodes][visited]
initialNode = 0
for nodes in graph:
D[max_nodes][length] = -1
P[max_nodes][predecessor] = ""
V[max_nodes][visited] = false
for l in graph:
length = lengthFromSource[node] + graph[node][l]
if length < lengthFromSourceNode[w]:
state[l][length] = x
state2[l][predecessor]
state3[l][visited] = true
x +=1
The part in bold is where I am stuck on - I am trying to implement this section of the algorithm:
3. For current node, consider all its unvisited neighbors and calculate their tentative distance. For example, if current node (A) has distance of 6, and an edge connecting it with another node (B) is 2, the distance to B through A will be 6+2=8. If this distance is less than the previously recorded distance, overwrite the distance
4. When we are done considering all neighbors of the current node, mark it as visited. A visited node will not be checked ever again; its distance recorded now is final and minimal
I think I am on the right track, i'm just stuck on how to say 'start at a node, get the length from source to a node, if length is smaller, overwrite previous value, then move to next node
I also used a dictionary to store the network.
Data is in the following format:
source: {destination: cost}
create a network dictionary (user provided)
net = {'0':{'1':100, '2':300},
'1':{'3':500, '4':500, '5':100},
'2':{'4':100, '5':100},
'3':{'5':20},
'4':{'5':20},
'5':{}
}
shortest path algorithm (user needs to specify start and terminal nodes)
def dijkstra(net, s, t):
# sanity check
if s == t:
return "The start and terminal nodes are the same. Minimum distance is 0."
if s not in net: # python2: if net.has_key(s)==False:
return "There is no start node called " + str(s) + "."
if t not in net: # python2: if net.has_key(t)==False:
return "There is no terminal node called " + str(t) + "."
# create a labels dictionary
labels={}
# record whether a label was updated
order={}
# populate an initial labels dictionary
for i in net.keys():
if i == s: labels[i] = 0 # shortest distance form s to s is 0
else: labels[i] = float("inf") # initial labels are infinity
from copy import copy
drop1 = copy(labels) # used for looping
## begin algorithm
while len(drop1) > 0:
# find the key with the lowest label
minNode = min(drop1, key = drop1.get) #minNode is the node with the smallest label
# update labels for nodes that are connected to minNode
for i in net[minNode]:
if labels[i] > (labels[minNode] + net[minNode][i]):
labels[i] = labels[minNode] + net[minNode][i]
drop1[i] = labels[minNode] + net[minNode][i]
order[i] = minNode
del drop1[minNode] # once a node has been visited, it's excluded from drop1
## end algorithm
# print shortest path
temp = copy(t)
rpath = []
path = []
while 1:
rpath.append(temp)
if temp in order: temp = order[temp] #if order.has_key(temp): temp = order[temp]
else: return "There is no path from " + str(s) + " to " + str(t) + "."
if temp == s:
rpath.append(temp)
break
for j in range(len(rpath)-1,-1,-1):
path.append(rpath[j])
return "The shortest path from " + s + " to " + t + " is " + str(path) + ". Minimum distance is " + str(labels[t]) + "."
# Given a large random network find the shortest path from '0' to '5'
print dijkstra(net, s='0', t='5')
First, I assume this is a homework problem, as the best suggest is to not bother writing it yourself, but to find an existing implementation on the web. Here's one that looks pretty good, for example.
Assuming you do need to reinvent the wheel, the code referenced there uses dictionaries to store the node data. So you feed it something like:
{
's': {'u' : 10, 'x' : 5},
'u': {'v' : 1, 'x' : 2},
'v': {'y' : 4},
'x': {'u' : 3, 'v' : 9, 'y' : 2},
'y': {'s' : 7, 'v' : 6}
}
This seems a more intuitive way of presenting your graph information. Visited nodes and distances can be kept in dictionaries as well.
Dear computer science enthusiasts,
I have stumbled upon an issue when trying to implement the Dijkstra-algorithm to determine the shortest path between a starting node and all other nodes in a graph.
To be precise I will provide you with as many code snippets and information as I consider useful to the case. However, should you miss anything, please let me know.
I implemented a PQueue class to handle Priority Queues of each individual node and it looks like this:
class PQueue:
def __init__(self):
self.items = []
def push(self, u, value):
self.items.append((u, value))
# insertion sort
j = len(self.items) - 1
while j > 0 and self.items[j - 1][1] > value:
self.items[j] = self.items[j - 1] # Move element 1 position backwards
j -= 1
# node u now belongs to position j
self.items[j] = (u, value)
def decrease_key(self, u, value):
for i in range(len(self.items)):
if self.items[i][0] == u:
self.items[i][1] = value
j = i
break
# insertion sort
while j > 0 and self.items[j - 1][1] > value:
self.items[j] = self.items[j - 1] # Move element 1 position backwards
j -= 1
# node u now belongs to position j
self.items[j] = (u, value)
def pop_min(self):
if len(self.items) == 0:
return None
self.items.__delitem__(0)
return self.items.index(min(self.items))
In case you're not too sure about what the Dijkstra-algorithm is, you can refresh your knowledge here.
Now to get to the actual problem, I declared a function dijkstra:
def dijkstra(self, start):
# init
totalCosts = {} # {"node"= cost,...}
prevNodes = {} # {"node"= prevNode,...}
minPQ = PQueue() # [[node, cost],...]
visited = set()
# start init
totalCosts[str(start)] = 0
prevNodes[str(start)] = start
minPQ.push(start, 0)
# set for all other nodes cost to inf
for node in range(self.graph.length): # #nodes
if node != start:
totalCosts[str(node)] = np.inf
while len(minPQ.items) != 0: # Main loop
# remove smallest item
curr_node = minPQ.items[0][0] # get index/number of curr_node
minPQ.pop_min()
visited.add(curr_node)
# check neighbors
for neighbor in self.graph.adj_list[curr_node]:
# check if visited
if neighbor not in visited:
# check cost and put it in totalCost and update prev node
cost = self.graph.val_edges[curr_node][neighbor] # update cost of curr_node -> neighbor
minPQ.push(neighbor, cost)
totalCosts[str(neighbor)] = cost # update cost
prevNodes[str(neighbor)] = curr_node # update prev
# calc alternate path
altpath = totalCosts[str(curr_node)] + self.graph.val_edges[curr_node][neighbor]
# val_edges is a adj_matrix with values for the connecting edges
if altpath < totalCosts[str(neighbor)]: # check if new path is better
totalCosts[str(neighbor)] = altpath
prevNodes[str(neighbor)] = curr_node
minPQ.decrease_key(neighbor, altpath)
Which in my eyes should solve the problem mentioned above (optimal path for a starting node to every other node). But it does not. Can someone help me clean up this mess that I have been trying to debug for a while now. Thank you in advance!
Assumption:
In fact I realized that my dictionaries used to store the previously visited nodes (prevNodes) and the one where I save the corresponding total cost of visiting a node (totalCosts) are unequally long. And I do not understand why.
I can't seem to figure out why I keep getting this error. The command line error traceback looks like this:
The point of the following code is to essentially give artificial intelligence to Pacman; keep him away from unscared ghosts, while eating all the food and capsules on a map. Most of code for this was given by the prof for an AI class, which can be found here.
The evaluationFunction method returns a very simple heuristic value that takes into consideration the distances to ghosts, food and capsules. The getAction function is found within my ExpectimaxAgent class (passed arg is MulitAgentSearchAgent), and it gathers all relevant information together, iterates through all possible actions and passes the info along to expectimax. The expectimax function is supposed to calculate a heuristic value which when returned to getAction is compared to the other action-heuristic values, and the one with the highest heuristic is chosen as the best action.
This should be all the relevant code for this error (if not I'll add more, also a quick apology for the noob mistakes in this question, I'm first time poster):
class ReflexAgent(Agent):
def getAction(self, gameState):
# Collect legal moves and successor states
legalMoves = gameState.getLegalActions()
# Choose one of the best actions
scores = [self.evaluationFunction(gameState, action) for action in legalMoves]
bestScore = max(scores)
bestIndices = [index for index in range(len(scores)) if scores[index] == bestScore]
chosenIndex = random.choice(bestIndices) # Pick randomly among the best
return legalMoves[chosenIndex]
def evaluationFunction(self, currentGameState, action):
successorGameState = currentGameState.generatePacmanSuccessor(action)
oldPos = currentGameState.getPacmanPosition()
newPos = successorGameState.getPacmanPosition()
newFood = successorGameState.getFood()
newGhostStates = successorGameState.getGhostStates()
# heuristic baseline
heuristic = 0.0
# ghost heuristic
for ghost in newGhostStates:
ghostDist = manhattanDistance(ghost.getPosition(), newPos)
if ghostDist <= 1:
if ghost.scaredTimer != 0:
heuristic += 2000
else:
heuristic -= 200
# capsule heuristic
for capsule in currentGameState.getCapsules():
capsuleDist = manhattanDistance(capsule, newPos)
if capsuleDist == 0:
heuristic += 100
else:
heuristic += 10.0/capsuleDist
# food heuristic
for x in xrange(newFood.width):
for y in xrange(newFood.height):
if (newFood[x][y]):
foodDist = manhattanDistance(newPos, (x,y))
if foodDist == 0:
heuristic += 100
else:
heuristic += 1.0/(foodDist ** 2)
if currentGameState.getNumFood() > successorGameState.getNumFood():
heuristic += 100
if action == Directions.STOP:
heuristic -= 5
return heuristic
def scoreEvaluationFunction(currentGameState):
return currentGameState.getScore()
class MultiAgentSearchAgent(Agent):
def __init__(self, evalFn = 'scoreEvaluationFunction', depth = '2'):
self.index = 0 # Pacman is always agent index 0
self.evaluationFunction = util.lookup(evalFn, globals())
self.depth = int(depth)
class ExpectimaxAgent(MultiAgentSearchAgent):
def getAction(self, gameState):
# Set v to smallest float value (-infinity)
v = float("-inf")
bestAction = []
# Pacman is agent == 0
agent = 0
# All legal actions which Pacman can make from his current location
actions = gameState.getLegalActions(agent)
# All successors determined from all the legal actions
successors = [(action, gameState.generateSuccessor(agent, action)) for action in actions]
# Iterate through all successors
for successor in successors:
# Expectimax function call (actor = 1, agentList = total number of agents, state = successor[1], depth = self.depth, evalFunct = self.evaluationFunction)
temp = expectimax(1, range(gameState.getNumAgents()), successor[1], self.depth, self.evaluationFunction)
# temp is greater than -infinity (or previously set value)
if temp > v:
# Set v to the new value of temp
v = temp
# Make the best action equal to successor[0]
bestAction = successor[0]
return bestAction
def expectimax(agent, agentList, state, depth, evalFunct):
# Check if won, lost or depth is less than/equal to 0
if depth <= 0 or state.isWin() == True or state.isLose() == True:
# return evalFunct
return evalFunct
# Check to see if agent is Pacman
if agent == 0:
# Set v to smallest float value (-infinity)
v = float("-inf")
# Otherwise, agent is ghost
else:
# Set v to 0
v = 0
# All possible legal actions for Pacman/Ghost(s)
actions = state.getLegalActions(agent)
# All successors determined from all the legal actions for the passed actor (either Pacman or Ghost(s))
successors = [state.generateSuccessor(agent, action) for action in actions]
# Find the inverse of the length of successors
p = 1.0/len(successors)
# Iterate through the length of successors
for j in range(len(successors)):
# Temp var to store the current successor at location j
successor = successors[j]
# Check if agent is Pacman
if agent == 0:
# Set v to the max of its previous value or recursive call to expectimax
v = max(v, expectimax(agentList[agent + 1], agentList, successor, depth, evalFunct))
# Check if agent is equal to ghost 2
elif agent == agentList[-1]:
# Increment v by the recursive call to p times expectimax (with agent=agentlist[0], agentList, state=successor, depth-=1, evalFunct)
v += expectimax(agentList[0], agentList, successor, depth - 1, evalFunct) * p
# Otherwise
else:
# Increment v by p times the recursive call to expectimax (with agent=agentList[agent+1], agentList, state=successor, depth, evalFunct)
v += expectimax(agentList[agent + 1], agentList, successor, depth, evalFunct) * p
return v
I've looked at a few other posts on here, and around the inter-webs, but have found nothing that seems to be similar to my issue. I've tried to pass the value to a temp variable, even tried to move the multiplication before the function call, but those changes have given me the exact same error, on the exact same line.
The error was the first return inside of the expectimax function. Instead of:
def expectimax(agent, agentList, state, depth, evalFunct):
# Check if won, lost or depth is less than/equal to 0
if depth <= 0 or state.isWin() == True or state.isLose() == True:
# return evalFunct
return evalFunct <--- cause of the error
It should have been:
return evalFunct(state)
This is because (as was pointed out) evalFunct only points to the evaluation function the user chose (from the command line arguments).
I am working on implementing an iterative deepening depth first search to find solutions for the 8 puzzle problem. I am not interested in finding the actual search paths themselves, but rather just to time how long it takes for the program to run. (I have not yet implemented the timing function).
However, I am having some issues trying to implement the actual search function (scroll down to see). I pasted all the code I have so far, so if you copy and paste this, you can run it as well. That may be the best way to describe the problems I'm having...I'm just not understanding why I'm getting infinite loops during the recursion, e.g. in the test for puzzle 2 (p2), where the first expansion should yield a solution. I thought it may have something to do with not adding a "Return" in front of one of the lines of code (it's commented below). When I add the return, I can pass the test for puzzle 2, but something more complex like puzzle 3 fails, since it appears that the now the code is only expanding the left most branch...
Been at this for hours, and giving up hope. I would really appreciate another set of eyes on this, and if you could point out my error(s). Thank you!
#Classic 8 puzzle game
#Data Structure: [0,1,2,3,4,5,6,7,8], which is the goal state. 0 represents the blank
#We also want to ignore "backward" moves (reversing the previous action)
p1 = [0,1,2,3,4,5,6,7,8]
p2 = [3,1,2,0,4,5,6,7,8]
p3 = [3,1,2,4,5,8,6,0,7]
def z(p): #returns the location of the blank cell, which is represented by 0
return p.index(0)
def left(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc-1]
p[zeroLoc-1] = 0
return p
def up(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc-3]
p[zeroLoc-3] = 0
return p
def right(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc+1]
p[zeroLoc+1] = 0
return p
def down(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc+3]
p[zeroLoc+3] = 0
return p
def expand1(p): #version 1, which generates all successors at once by copying parent
x = z(p)
#p[:] will make a copy of parent puzzle
s = [] #set s of successors
if x == 0:
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 1:
s.append(left(p[:]))
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 2:
s.append(left(p[:]))
s.append(down(p[:]))
elif x == 3:
s.append(up(p[:]))
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 4:
s.append(left(p[:]))
s.append(up(p[:]))
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 5:
s.append(left(p[:]))
s.append(up(p[:]))
s.append(down(p[:]))
elif x == 6:
s.append(up(p[:]))
s.append(right(p[:]))
elif x == 7:
s.append(left(p[:]))
s.append(up(p[:]))
s.append(right(p[:]))
else: #x == 8
s.append(left(p[:]))
s.append(up(p[:]))
#returns set of all possible successors
return s
goal = [0,1,2,3,4,5,6,7,8]
def DFS(root, goal): #iterative deepening DFS
limit = 0
while True:
result = DLS(root, goal, limit)
if result == goal:
return result
limit = limit + 1
visited = []
def DLS(node, goal, limit): #limited DFS
if limit == 0 and node == goal:
print "hi"
return node
elif limit > 0:
visited.append(node)
children = [x for x in expand1(node) if x not in visited]
print "\n limit =", limit, "---",children #for testing purposes only
for child in children:
DLS(child, goal, limit - 1) #if I add "return" in front of this line, p2 passes the test below, but p3 will fail (only the leftmost branch of the tree is getting expanded...)
else:
return "No Solution"
#Below are tests
print "\ninput: ",p1
print "output: ",DFS(p1, goal)
print "\ninput: ",p2
print "output: ",DLS(p2, goal, 1)
#print "output: ",DFS(p2, goal)
print "\ninput: ",p3
print "output: ",DLS(p3, goal, 2)
#print "output: ",DFS(p2, goal)
The immediate issue you're having with your recursion is that you're not returning anything when you hit your recursive step. However, unconditionally returning the value from the first recursive call won't work either, since the first child isn't guaranteed to be the one that finds the solution. Instead, you need to test to see which (if any) of the recursive searches you're doing on your child states is successful. Here's how I'd change the end of your DLS function:
for child in children:
child_result = DLS(child, goal, limit - 1)
if child_result != "No Solution":
return child_result
# note, "else" removed here, so you can fall through to the return from above
return "No Solution"
A slightly more "pythonic" (and faster) way of doing this would be to use None as the sentinel value rather than the "No Solution" string. Then your test would simply be if child_result: return child_result and you could optionally leave off the return statement for the failed searches (since None is the default return value of a function).
There are some other issues going on with your code that you'll run into once this recursion issue is fixed. For instance, using a global visited variable is problematic, unless you reset it each time you restart another recursive search. But I'll leave those to you!
Use classes for your states! This should make things much easier. To get you started. Don't want to post the whole solution right now, but this makes things much easier.
#example usage
cur = initialPuzzle
for k in range(0,5): # for 5 iterations. this will cycle through, so there is some coding to do
allsucc = cur.succ() # get all successors as puzzle instances
cur = allsucc[0] # expand first
print 'expand ',cur
import copy
class puzzle:
'''
orientation
[0, 1, 2
3, 4, 5
6, 7, 8]
'''
def __init__(self,p):
self.p = p
def z(self):
''' returns the location of the blank cell, which is represented by 0 '''
return self.p.index(0)
def swap(self,a,b):
self.p[a] = self.p[b]
self.p[b] = 0
def left(self):
self.swap(self.z(),self.z()+1) #FIXME: raise exception if not allowed
def up(self):
self.swap(self.z(),self.z()+3)
def right(self):
self.swap(self.z(),self.z()-1)
def down(self):
self.swap(self.z(),self.z()-3)
def __str__(self):
return str(self.p)
def copyApply(self,func):
cpy = self.copy()
func(cpy)
return cpy
def makeCopies(self,s):
''' some bookkeeping '''
flist = list()
if 'U' in s:
flist.append(self.copyApply(puzzle.up))
if 'L' in s:
flist.append(self.copyApply(puzzle.left))
if 'R' in s:
flist.append(self.copyApply(puzzle.right))
if 'D' in s:
flist.append(self.copyApply(puzzle.down))
return flist
def succ(self):
# return all successor states for this puzzle state
# short hand of allowed success states
m = ['UL','ULR','UR','UDR','ULRD','UDL','DL','LRD','DR']
ss= self.makeCopies(m[self.z()]) # map them to copies of puzzles
return ss
def copy(self):
return copy.deepcopy(self)
# some initial state
p1 = [0,1,2,3,4,5,6,7,8]
print '*'*20
pz = puzzle(p1)
print pz
a,b = pz.succ()
print a,b