I am working on an assignment where I have managed the main problem and am looking into the extension exercises. Currently a map is given and all of the possible solutions to the maze are identified on a grid which is printed as follows:
1 1 3 1 0 2
3 3 3 3 1 3
3 3 1 3 3 3
3 3 3 1 3 0
3 1 3 1 3 1
3 1 3 3 3 0
Where a 0 is an empty spaces, 1 is a wall, 2 is the goal, and 3 is a visited space. The extension task is to give the shortest possible solution to the maze with any given starting point. If the starting point is a wall, then the maze can’t be solved. This is fine as well. It should be able to work for any maze given.
I don't really know where to get started with this problem. One idea was to take the sum of all the paths and finding the smallest of them, but I'm not sure how to implement this.
Currently this is my code:
EMPTY = 0
WALL = 1
GOAL = 2
VISITED = 3
def solve(grid, x, y):
if grid[x][y] == GOAL:
show_grid(grid)
return True
elif grid[x][y] == WALL:
return False
elif grid[x][y] == VISITED:
return False
else:
# mark as visited
grid[x][y] = VISITED
# explore neighbors clockwise starting by going up
if ((x < len(grid)-1 and solve(grid, x + 1, y))
or (y > 0 and solve(grid, x, y-1))
or (x > 0 and solve(grid, x-1, y))
or (y < len(grid)-1 and solve(grid, x, y+1))):
return True
else:
return False
def show_grid (grid):
for i in range(len(grid), 0, -1):
# print("i: ", i)
for element in grid[i-1]:
print (element, end=" ")
print()
def main ():
grid = [[EMPTY, WALL, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, WALL, EMPTY, WALL, EMPTY, WALL],
[EMPTY, EMPTY, EMPTY, WALL, EMPTY, EMPTY],
[EMPTY, EMPTY, WALL, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, WALL, EMPTY],
[WALL, WALL, EMPTY, WALL, EMPTY, GOAL]]
solve(grid, 0, 0)
The extension asks to print the length of the shortest path, where traversing 1 square is 1 movement. Any help with this problem is appreciated.
I agree with #wwii's answer, if you are exploring all the solutions, simply return the length of each successful path and then find the shortest one. This can be achieved with the following changes:
changing your solved function to return the path instead of true or false.
at each node instead of putting 3 for visited, you can put the minimum length from that node to the solution (or the origin), put -1 for wall and nodes that can't reach the solution. Nodes that can't reach the solution are essentially walls.
For example,
GOAL = 'G'
WALL = 'W'
EMPTY = 'E'
def solve(grid, x, y):
if grid[x][y] == WALL or grid[x][y].endswith(GOAL):
return grid[x][y]
candidates = []
# explore neighbors clockwise starting by going down
if x < len(grid)-1:
candidates.append('d' + solve(grid, x + 1, y))
if y > 0:
candidates.append('l' + solve(grid, x, y - 1))
if x > 0:
candidates.append('u' + solve(grid, x - 1, y))
if y < len(grid)-1:
candidates.append('r' + solve(grid, x, y + 1))
# get rid of none solutions from candidates
candidates = [x for x in candidates if not x.endswith(GOAL)]
if not candidates: # if no solution, it's essentially a wall
grid[x][y] = 'W'
else:
# getting shortest path
grid[x][y] = sorted(candidates, key=lambda x: len(x))[0]
# for longest path use code below instead of above
# grid[x][y] = sorted(candidates, key=lambda x: len(x))[-1]
return grid[x][y]
If a node is visited and it goes to the goal, the value at that node can be something like 'drrurG'. This means the shortest path is going down, right*2, up, right, Goal. The direction convention is down meaning going down a row, i.e. x+1.
Granted you may have to change some other parts of the code for this to work.
Food for thought
The above code goes over all the possible paths. But you may not need to. There may be faster ways to get to the shortest path, as this problem is not as complicated as other general pathfinding problems.
For example, the absolutely shortest path is obviously the straight line from start to goal. Check that first. If that's not a solution, then start checking the next shortest paths. See if those work. If not, keep going until you find it.
You are exploring the grid using recursion where the base case is that the GOAL is found. Each instance of solve only returns a boolean so you have lost information - the path that instance took.
Refactor so that the function returns the grid location if it is viable and the return values from an instance's decendents are accumulated.
Your conditionals will need to be rethought and you want to ensure that all paths are explored (up,down,left,right). It might be helpful to use the fact that a tuple is evaluated True in a conditional, bool((0,0)) -> True.
Finally you can either:
accumulate all the successful paths then determine the min and max lengths when the process is done or
evaluate successful path lengths in process and use placeholder(?) variables to keep the current max and min - this option discards path information but if you don't need that, it doesn't matter.
I tried to formulate that based on your current code because I presumed that you understood how your current process works and it might be easier to start from there.
You could also view the grid as a graph, each point is a node with edges to the nodes around it. You could parse the grid into a graph first then use any number of well defined algorithms to traverse the graph and find your answers. For a tree solution the root would be the starting point for the search. I don't have a lot of experience using graphs so I don't feel I can give a detailed answer for this - maybe someone will answer with a better explanation.
Related
So the code is about finding the least amount of rounds a knight in chess would take to move from start to goal. And also the code must be recursive.
I have a problem with this code. . My problem is that it's not runing through all stacks but only through one "path" of possible moves and then deliveres the amount of rounds needed in that path.
For example with print(knight([1,1], [5,2], [])) it returns 17 instead of 3
moves = ([1,2],[2,1],[-1,2],[-1,-2],[1,-2],[2,-1],[-2,1],[-2,-1])
def knight(start, goal, visited):
if start == goal:
return 0
else:
visited.append(start)
possibles =[]
makeable= []
for x in range(8):
possibles.append([start[0] + moves[x][0],start[1] + moves[x][1]])
for i in range(8):
if possibles[i] not in visited and possibles[i][0]<9 and possibles[i][1]<9 and possibles[i][0]>0 and possibles[i][1]>0:
makeable.append(knight(possibles[i],goal,visited))
if makeable:
return min(makeable)+1
else:
return 99
print(knight([1,1], [5,2], []))
I assume your besucht is storing the path. I don't understand the use of it, as it is not used anywhere in the code. Anyways, I will stop pretending I am on CodeReview and answer your question.
The reason of the bug is because you're passing the list besucht around. When you pass lists as function arguments, it is passed as a reference/pointer instead of a copy of the list. As a result, the later function calls will modify the original besucht, causing bugs in if possibles[i] in besucht.
To fix this, instead pass in a copy of the path. (Obviously it's not the most efficient way, but it works here). See code.
# python
moves = ([1,2],[2,1],[-1,2],[-1,-2],[1,-2],[2,-1],[-2,1],[-2,-1])
def springerzug(start, end, path, sofar = 0):
if start == end:
return 0
# Terminate if path is too long
if len(path) > 9:
return 999
# omit the else
possibles = []
ergebnisse = [98] # default value
for x in range(8):
possibles.append([start[0] + moves[x][0], start[1] + moves[x][1]])
for i in range(8):
if 0 < possibles[i][0] < 9 and 0 < possibles[i][1] < 9 \
and possibles[i] not in path:
ergebnisse.append(springerzug(possibles[i], end, path.copy() + [possibles[i]]))
return min(ergebnisse)+1
print(springerzug([1,1], [5,2], []))
(Note: Your code using DFS for a shortest path is extremely inefficient. Please search up Breath-First Search so other people on stackoverflow don't flame you for your inefficient code.)
this is famous path counting problem , i am trying to solve it using memoization.
Enlighten me!
def pathCounter(a,b):
matrix = [[0 for i in xrange(a)] for i in xrange(b)]
if a==0 or b==0:
return 1
if matrix[a][b]:
return matrix[a][b]
print matrix[a][b]
matrix[a][b]=pathCounter(a,b-1)+pathCounter(a-1,b)
return matrix[2][2]
if __name__=='__main__':
k=pathCounter(2,2)
print k
I believe your trying to solve this problem.
If that is the case, then you are correct that it would be sensible to solve with recursion.
If you imagine each corner of the grid as a node, then you want to a recursive function that simply takes a parameter of the node it is at (x, y). In the function, it first needs to check if the position that it was called at is the bottom right vertex of the grid. If it is, the function adds one to the path count (as a path is finished when it reaches this corner) and then returns. Otherwise, this function just calls two more of itself (this is the recursion), one to its right (so y+1) and one to its left (x+1). An added step is to check that the coordinates are in the grid before calling them as a node in the middle of the bottom row for instance shouldn't call a node below it as that would be off the grid.
Now you have the recursive function defined, all you need to do now is declare a variable to store the path count. And call the recursive function from the coordinate (0,0).
However, as I am sure you have seen, this solution does not complete in reasonable time so it is necessary that you use memoization - speeding it up by caching the nodes so that the same sections of paths aren't calculated twice.
It also makes coding it more simple if as you have done, we work from the bottom right corner up to the top left corner. One last thing is that if you use a dictionary then the code becomes clearer.
The final code should look something like:
cache = {}
def pathCounter(x, y):
if x == 0 or y == 0:
return 1
if (x,y) in cache:
return cache[(x,y)]
cache[(x,y)] = pathCounter(x, y-1) + pathCounter(x-1, y)
return cache[(x,y)]
print(pathCounter(2,2))
this gives the expected result of 6.
I'll leave you to do the 20x20 grid. Hope this helps!
You made a few errors in your implementation of the algorithm. If your using a recursive approach you do not have to use the grid because you want require any of the stored data, actually. You only need to return the two possible sub-paths from your current position - that's it! Therefore, you need to make some changes in the main idea of your code.
I tried to keep as much of your original code as possible, but still make it working:
def pathCounterNaive(width, height, startX = 0, startY = 0):
if startX >= width or startY >= height:
return 0
if startX == width-1 and startY == height-1:
return 1
return pathCounter(width,height, startX+1, startY) + pathCounter(width,height, startX, startY+1)
slowK=pathCounterNaive(3,3)
print(slowK)
Please keep in mind, that the parameters width and height represent the number of vertices, and are therefore not 2 but 3 for a 2x2 grid. As this code is using pure recursion it is very slow. If you want to use your memorization approach, you have to modify your code like this:
import numpy as np
def pathCounter(width, height):
grid = np.zeros((height+1, width+1))
def pathCounterInternal(x, y):
if x==0 or y==0:
return 1
grid[x, y] = pathCounterInternal(x,y-1)+pathCounterInternal(x-1,y)
return grid[x, y]
grid[width, height] = pathCounterInternal(width, height)
return grid[width, height]
k=pathCounter(2,2)
print(k)
Here you have to call it with 2 as the parameter for a 2x2 grid. This code is much faster due to the caching of already calculated paths.
EDIT: I asked a friend and he found a way, generate a list of possible squares the convoy can move to from the original square and choose the one closes to the end coordinates, then generate a list for that square and again choose the closest ect.
I am making a game where among other things you move a convoy. The map is basically a Cartesian coordinate system, the coordinates are a tuple (X, Y).
What i need is to find a way to determine the sectors that the convoy passes through, since one only has the start point and chosen end point, to later be able to change the corresponding values of those sectors to simulate fog of war.
I tried creating a square around the two points and then a list for all possible Y and X coordinates (X/Y_movement_coords_loc).
Now the problem is finding the shortest possible route through this square, but i cant figure out a formula, since there are quiet a lot of possibilities and what i tried includes a division which often leads to fractions or division by 0. Neither of which i can use.
y_per_x_coord = len(y_movement_coords_loc) / len(x_movement_coords_loc)
Also the code as is now, for some inexplicable reason hangs at the
for x_index in range(len(x_movement_coords_loc)):
loop, it enters the if clause, appends to the list but 3 out of 5 times doesn't reach the res_index_list, i checked with prints.
Anyone out there who can help me with my problem?
Thanks in advance.
x_movement_loc = old_coord_loc[0] - new_coord_loc[0]
y_movement_loc = old_coord_loc[1] - new_coord_loc[1]
x_movement_coords_loc = []
y_movement_coords_loc = []
moved_tiles_coords = []
negative_movement = 1
if x_movement_loc < 0:
x_movement_loc *= -1
negative_movement = -1
if y_movement_loc < 0:
y_movement_loc *= -1
negative_movement = -1
for u in range(x_movement_loc):
x_movement_coords_loc.append(old_coord_loc[0] + (u * negative_movement))
for u in range(y_movement_loc):
y_movement_coords_loc.append(old_coord_loc[1] + (u * negative_movement))
counter = 0
y_per_x_coord = len(y_movement_coords_loc) / len(x_movement_coords_loc)
for x_index in range(len(x_movement_coords_loc)):
for y_index in range(y_per_x_coord):
moved_tiles_coords.append((x_movement_coords_loc[x_index], y_movement_coords_loc[y_index + counter]))
counter += y_per_x_coord
if (x_movement_coords_loc[x_index], y_movement_coords_loc[counter]) != new_coord_loc:
moved_tiles_coords.append((x_movement_coords_loc[x_index], y_movement_coords_loc[counter]))
res_index_list = [1, 3, 5, 7, 9]
I have a 2D array in Python (version 3.2) that looks like this:
...AAA....
...AAABB..
..BBBBBCC.
.....CCCC.
.DDD..CC..
.DDD......
It represents a kind of map with areas painted different colors. The above example shows four distinct regions, A, B, C, and D.
Here's an example of indexing the array:
map[1][5] == 'A' would return True.
I'm trying to write a function that takes in an array like this, and a row/col index, and returns the number of adjoining spaces that are of the same "color". So using that example above, here are some return values (the arguments are the array, row, and column number respectively:
6 <-- countArea(map, 5, 2)
8 <-- countArea(map, 2, 8)
I'd like to implement this as a recursive function, but I can't figure it out. Here's what I have so far:
def countArea(map, row, col):
key = map[row][col]
if (map[row-1][col] == key):
return 1 + countArea(map, row-1, col)
elif (map[row+1][col] == key):
return 1 + countArea(map, row+1, col)
elif (map[row][col+1] == key):
return 1 + countArea(map, row, col+1)
elif (map[row][col-1] == key):
return 1 + countArea(map, row, col-1)
else:
return 1
I know I'm missing something basic here. I'm basically saying "here is the current character, now look in each direction to see if it has the same character."
My question is, what am I missing in this recursive definition?
Thanks for your help.
My question is, what am I missing in this recursive definition?
Once a grid square has been counted, it must not be counted again (this includes counting by recursive invocations of countArea()!)
Your current algorithm goes as far north as it can, and then keeps taking one step to the south followed by one step to the north. This two-step sequence repeats until you run out of stack space.
If you like, you could read up on algorithms for this problem in Wikipedia.
In your code the algorithm would look one field left of a given input field and in the recursive call would again call the function on the initial field. (What you obviously don't want since it would lead to an infinite recursion)
Approach 1
A method to overcome this problem while still using recursion would be to specify a direction where the recursion should look for more fields of the same type. For example the call to the field directly north (or above) of the initial one could look recursively farer to the north or east (or right), the one to the east go south (below) and east and so on.
By intelligently choosing the first step you can ensure, that there is no overlap in the scanned regions. However it needs some adaptions to specify the directions the recursive call should scan. BUT: Note that this algorithm would not work if the area is overhanging so if not every field northeast of the starting point can be reached by just moving right and up.
There exist more algorithms like this that are also capable to solve the the mentioned problem. Have a look at Flood Filling on wikipedia.
Approach 2
You can also save the already visited fields in some way and directly return from the recursive call if the field was already visited.
The following implementation should work:
def countArea(map, row, col, key=None, seen=None):
if key is None:
key = map[row][col]
if seen is None:
seen = set()
seen.add((row, col)) # mark this location as visited
n = 1
for dy, dx in [(0, 1), (1, 0), (-1, 0), (0, -1)]:
r, c = row + dy, col + dx
if r < 0 or r >= len(map) or c < 0 or c >= len(map[0]): # check boundaries
continue
# only increment and recurse if key matches and we haven't already visited
if map[r][c] == key and (r, c) not in seen:
n += countArea(map, r, c, key, seen)
return n
Example:
>>> print '\n'.join(''.join(row) for row in map)
...AAA....
...AAABB..
..BBBBBCC.
.....CCCC.
.DDD..CC..
.DDD......
>>> countArea(map, 5, 2)
6
>>> countArea(map, 2, 8)
8
Note that this assumes that areas with the same key that are only touching at a diagonal should be considered separate, for example for the following map countArea(map, 0, 0) and countArea(map, 1, 1) would both return 1:
A.
.A
As a side note, you should not use map as a variable name, as it will mask the builtin map() function.
Goal: Trying to convert some of the lines of an algorithm written in python to pseudocode.
Goal of the given algorithm: Find all cycles in a directed graph with cycles.
Where I stand: I well understand the theory behind the algorithm, I have also coded different versions on my own, however I cannot write an algorithm that small, efficient and correct on my own.
Source: stackoverflow
What I have done so far: I cannot describe enough how many weeks spent on it, have coded Tarjan, various versions DFS, Flloyd etc in php but unfortunately they are partial solutions only and one have to extend them more.
In addition: I have run this algorithm online and it worked, I need it for a school project that I am stack and cannot proceed further.
This is the algorithm:
def paths_rec(path,edges):
if len(path) > 0 and path[0][0] == path[-1][1]:
print "cycle", path
return #cut processing when find a cycle
if len(edges) == 0:
return
if len(path) == 0:
#path is empty so all edges are candidates for next step
next_edges = edges
else:
#only edges starting where the last one finishes are candidates
next_edges = filter(lambda x: path[-1][1] == x[0], edges)
for edge in next_edges:
edges_recursive = list(edges)
edges_recursive.remove(edge)
#recursive call to keep on permuting possible path combinations
paths_rec(list(path) + [edge], edges_recursive)
def all_paths(edges):
paths_rec(list(),edges)
if __name__ == "__main__":
#edges are represented as (node,node)
# so (1,2) represents 1->2 the edge from node 1 to node 2.
edges = [(1,2),(2,3),(3,4),(4,2),(2,1)]
all_paths(edges)
This is what I have managed to write in pseudocode from it, I have marked with #? the lines I do not understand. Once I have them in pseudocode I can code them in php with which I am a lot familiar.
procedure paths_rec (path, edges)
if size(path) > 0 and path[0][0] equals path[-1][1]
print "cycle"
for each element in path
print element
end of for
return
end of if
if size(edges) equals 0
return
end of if
if size(path) equals 0
next_edges equals edges
else
next edges equals filter(lambda x: path[-1][1] == x[0], edges) #?
end of else
for each edge in next_edges
edges_recursive = list(edges) #?
edges_recursive.remove(edge)#?
#recursive call to keep on permuting possible path combinations
paths_rec(list(path) + [edge], edges_recursive)#?
The line next_edges = filter(lambda x: path[-1][1] == x[0], edges) creates a new list containing those edges in edges whose first point is the same as the second point of the last element of the current path, and is equivalent to
next_edges = []
for x in edges:
if path[len(path) - 1][1] == x[0]
next_edges.append[x]
The lines create a new copy of the list of edges edges, so that when edge is removed from this copy, it doesn't change the list edges
edges_recursive = list(edges)
edges_recursive.remove(edge)
paths_rec(list(path) + [edge], edges_recursive) is just the recursive call with the path with edge added to the end and the new list of edges that has edge removed from it.