How to save the minimum path sum in a recursive function? - python

This is my solution to given a matrix m x n, find the minimum path sum. It works fine however, I'm not sure how to modify it to see the path / save it in some list, how can this be done?
def get_path(matrix, x, y, seen):
if (x, y) in seen:
return seen[x, y]
x_end = len(matrix) - 1
y_end = len(matrix[0]) - 1
current = matrix[x][y]
if x == x_end and y == y_end:
return current
possible_moves = []
if x < len(matrix) - 1:
possible_moves.append([x + 1, y])
if y < len(matrix[0]) - 1:
possible_moves.append([x, y + 1])
results = [
current + get_path(matrix, *possible, seen) for possible in possible_moves
]
current_best = min(results)
seen[x, y] = current_best
return current_best

You don't need to.
After get_path returns, start from 0,0 look for a move where seen[x', y'] = seen[x,y] - matrix[x,y].
If you have equality (both moves work) pick whatever you want (equals paths).
Keep going until you reach the end.

Related

Identifying Path in Matrix Game

I am returning the length of the shortest path if there's is one. Otherwise, I return -1.
I'm trying to print the matrix in such a way that all visited nodes that were a part of the shortest path are marked with '$' instead of '1'. However, I'm not able to do so.
def Path(grid):
#print(grid)
start = (0, 0)
queue = collections.deque([[start]])
seen = set([start])
while queue:
path = queue.popleft()
x, y = path[-1]
if y == 7 and x == 7:
#print(path)
for (i, j) in path:
grid[i][j] = '$'
print(grid)
return len(path)
for x2, y2 in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1):
if (grid[y2][x2] != 0) and (x2, y2) not in seen:
queue.append(path + [(x2, y2)])
seen.add((x2, y2))
print(grid)
return -1
The issue is in how you address grid:
When looking for the next available move, you do this test:
grid[y2][x2] != 0
where (x2, y2) is potentially added to the path.
But when you finally assign the $, you write:
grid[i][j] = '$'
where (i, j) is the tuple taken from the path.
This is not consistent. You should swap the coordinate position in one of the two grid[][] expressions to make them consistent.

Array not updating values after function call

I need the array to have all the possible combinations of the (x,y) coordinates that I am generating. The array still prints as an array of 1s.
import numpy as np
coordinates = np.ones([1000, 2])
def translate (x,y):
dx = 5
dy = 5
return x + dx, y + dy
for i in range(0, 100):
for j in range(0, 100):
(x, y) = translate(i, j)
coordinates[i, j] = translate(x, y)
np.append(coordinates, translate(x, y), axis=None)
print(coordinates)
I expect coordinates array to receive the correct values after the translate function is called and not an array of 1s.
If I understand correctly, you want all possible (x,y) coordinates that can be generated by varying x=0..99 and y=0..99 and then adding some dx and dy to x and y, respectively.
One approach, similar to yours, is to initialize an empty list, and then just append a tuple with the translation function you defined:
coordinates = []
def translate (x,y):
dx = 5
dy = 5
return x + dx, y + dy
for x in range(0, 100):
for y in range(0, 100):
coordinates.append(translate(x,y))
print(coordinates)
However, this could be improved. Realize that you are simply adding dx to every x and dy to every y, so you can achieve the same result with simpler code by removing the translate function:
coordinates = []
dx, dy = 5, 5
for x in range(dx, 100+dx):
for y in range(dy, 100+dy):
coordinates.append((x,y))
print(coordinates)
Which will give you the same correct answer.

Finding adjacent cells in a grid without exceptions

There are times when I have an area in a 2D array, and I need to check for adjacent cells. Normally I would do the following:
adjacentCells = (world[y+1][x]==1)+(world[y-1]==1)+(world[y][x+1]==1)+(world[y][x-1]==1)
This would calculate how many orthogonally adjacent cells to the point (x,y) are equal to 1. The issue is, doing things this way wraps around the matrix if my x or y coordinates are 0 (the top or left edge), and it causes an exception if the point (x,y) is on a different edge. This makes the code look like this:
def adjacentCells(x,y):
total=0
if x==0:
total += 1
else:
total += world[y][x-1]
if y==0:
total += 1
else:
total += world[y-1][x]
try:
total += world[y][x+1]
except:
total += 1
try:
total += world[y+1][x]
except:
total += 1
return total
Is there a way to fix this issue, in a way about as simple as the uppermost example?
I would do it something like this:
def adjacentCells(x, y):
neighbours = [(x-1, y), (x, y-1), (x+1, y), (x, y+1)]
return sum(
world[b][a] if 0 <= b < len(world) and 0 <= a < len(world[b])
else 1
for (a,b) in neighbours)
So get a list of potential neighbours but check each one is valid before you use it.
If the neighbours of border cells counted as 0 instead of 1 it would be simpler, then you would simply filter the list of neighbours before using it.
For doing something as trivial as adding up the values of up to 4 cells, I'd just write the code for each caseā€”it only requires one line per cell location. It may be longer than using a loop construct, but avoids looping overhead and it's all pretty much boilerplate.
It's also relatively easy to read and understand, and would make it easier to special-case one of the locations should doing that be needed for some reason.
Here's what I mean:
world = [[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]
MIN_X, MAX_X = 0, len(world[0])-1
MIN_Y, MAX_Y = 0, len(world)-1
def adjacentCells(x, y):
return((world[ y][x-1] if MIN_Y <= y <= MAX_Y and MIN_X <= x-1 <= MAX_X else 1)
+ (world[ y][x+1] if MIN_Y <= y <= MAX_Y and MIN_X <= x+1 <= MAX_X else 1)
+ (world[y-1][ x] if MIN_Y <= y-1 <= MAX_Y and MIN_X <= x <= MAX_X else 1)
+ (world[y+1][ x] if MIN_Y <= y+1 <= MAX_Y and MIN_X <= x <= MAX_X else 1))
print(adjacentCells(0, 0)) # -> 4
print(adjacentCells(1, 1)) # -> 4

python ProjectEuler task 4 Using while loop

i wanted to do the project euler problems by using python.
but i am having problems with the following task:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 x 99.
Find the largest palindrome made from the product of two 3-digit numbers.
my code for the given task:
def palindrome_number():
n=0
lower_range = 100
upper_range = 999
while x >= lower_range or x <= upper_range and y >= lower_range or y <= upper_range:
z = x * y
while z > n:
s = str(x * y)
if s == s[::-1]:
n = x * y
print(n)
now i dont know how to check for all the x and y numbers varying from 100-999.
i thought it has to be like in my code, but it doesnt work
Solution 1: using a generator expression
Actually the problem can be solved in one line :)
max(x*y for x in range(100, 1000) for y in range(100, 1000) if str(x*y)==str(x*y)[::-1])
Solution 2: using a for loop
for loops are better suited for this kind of operation than while loops. Below is the solution (I have only replaced your while with two for loops. The first loop tells the variable x to run from 100 to 999 and the second one tells y to do the same. With these two loops you will try out all combinations for x and y.)
def palindrome_number():
n = 0
lower_range = 100
upper_range = 999
for x in range(lower_range, upper_range+1):
for y in range(lower_range, upper_range+1):
z = x * y
if z > n: # an *if* suffices ;)
s = str(x * y)
if s == s[::-1]:
n = x * y
print(n)
Solution 3: using a while loop
To get the same thing with while loops you would have to take care of changing x and y to get all combinations:
x = y = lower_range
while x >= lower_range and x <= upper_range: # (*and* instead of *or*)
while y >= lower_range and y <= upper_range: # (again you want the >= *and* the <= to be fulfilled)
z = x * y
if z > n:
s = str(x * y)
if s == s[::-1]:
n = x * y
y += 1 # change y to get all combinations
y = lower_range
x += 1 # change x to get all combinations

Python 3.4.3 Diamond-Square Algorithm is producing odd results

I am currently stumped by an artefact in my code. It appears to produce very sharp points in a grid pattern that have a noticeable difference in value to their neighbours.
I am following the blog post at http://www.bluh.org/code-the-diamond-square-algorithm/ and converting from whichever language they are using (assuming either C# or Java), and have double-checked that what I am doing should match.
Is there any chance that someone could have a browse over this, and see what I'm doing wrong? I've stepped through it at smaller levels, and stopped it on specific iterations of the algorithm (by unrolling the top loop, and explicitly calling the algorithm a set number of times) and everything seems to work until we get to the very last set of points/pixels.
I use a class (called Matrix) to access the list, and wrap any out of bounds values.
The code for the algorithm is as follows:
class World :
def genWorld (self, numcells, cellsize, seed):
random.seed(seed)
self.dims = numcells*cellsize
self.seed = seed
self.cells = Matrix(self.dims, self.dims)
# set the cells at cellsize intervals
half = cellsize/2
for y in range(0, self.dims, cellsize):
for x in range(0, self.dims, cellsize):
self.cells[x,y] = random.random()
scale = 1.0
samplesize = cellsize
while samplesize > 1:
self._diamondSquare(samplesize, scale)
scale *= 0.8
samplesize = int(samplesize/2)
# I need to sort out the problem with the diamond-square algo that causes it to make the weird gridding pattern
def _sampleSquare(self, x, y, size, value):
half = size/2
a = self.cells[x-half, y-half]
b = self.cells[x+half, y-half]
c = self.cells[x-half, y+half]
d = self.cells[x+half, y+half]
res = min(((a+b+c+d+value)/5.0), 1.0)
self.cells[x, y] = res
def _sampleDiamond(self, x, y, size, value):
half = size/2
a = self.cells[x+half, y]
b = self.cells[x-half, y]
c = self.cells[x, y+half]
d = self.cells[x, y-half]
res = min(((a+b+c+d+value)/5.0), 1.0)
self.cells[x, y] = res
def _diamondSquare(self, stepsize, scale):
half = int(stepsize/2)
for y in range(half, self.dims+half, stepsize):
for x in range(half, self.dims+half, stepsize):
self._sampleSquare(x, y, stepsize, random.random()*scale)
for y in range(0, self.dims, stepsize):
for x in range(0, self.dims, stepsize):
self._sampleDiamond(x+half, y, stepsize, random.random()*scale)
self._sampleDiamond(x, y+half, stepsize, random.random()*scale)
and is called with:
w = World()
w.genWorld(16, 16, 1) # a 256x256 square world, since the numcells is multiplied by the cellsize to give us the length of ONE side of the resulting grid
then I save to file to check the result:
file = io.open("sample.raw",'wb')
arr = [int(i * 255) for i in w.cells.cells] # w.cells.cells should not have a value >= 1.0, so what's going on?
ind = 0
for a in arr:
if a > 255:
print ("arr["+str(ind)+"] ::= "+str(a))
ind += 1
file.write(bytearray(arr))
file.close()
which gives the result:
EDIT: Okay, so it appears that I managed to get it working. I swapped from using functions for working out the diamond and square steps to doing it all in the _diamondSquare() function, but this wasn't the only thing. I also found out that random.random() provides values in the range [0.0 ->1.0), when I was expecting values in the range [-1.0 -> 1.0). After I corrected this, everything started working properly, which was a relief.
Thanks for the advice everyone, here's the working code in case anyone else is struggling with something similar:
Random Function
# since random.random() gives a value in the range [0.0 -> 1.0), I need to change it to [-1.0 -> 1.0)
def rand():
mag = random.random()
sign = random.random()
if sign >=0.5:
return mag
return mag * -1.0
Matrix class
class Matrix:
def __init__(self, width, height):
self.cells = [0 for i in range(width*height)]
self.width = width
self.height = height
self.max_elems = width*height
def _getsingleindex(self, ind):
if ind < 0:
ind *= -1
while ind >= self.max_elems:
ind -= self.max_elems
return ind
def _getmultiindex(self, xind, yind):
if xind < 0:
xind *= -1
if yind < 0:
yind *= -1
while xind >= self.width:
xind -= self.width
while yind >= self.height:
yind -= self.height
return xind + (yind*self.height)
def __getitem__(self, inds):
# test that index is an integer, or two integers, and throw an indexException if not
if hasattr(inds, "__len__"):
if len(inds) > 1:
return self.cells[self._getmultiindex(int(inds[0]), int(inds[1]))]
return self.cells[self._getsingleindex(int(inds))]
def __setitem__(self, inds, object):
# test that index is an integer, or two integers, and throw an indexException if not
if hasattr(inds, "__len__"):
if len(inds) > 1:
self.cells[self._getmultiindex(int(inds[0]),int(inds[1]))] = object
return self.cells[self._getmultiindex(int(inds[0]),int(inds[1]))]
self.cells[self._getsingleindex(int(inds))] = object
return self.cells[self._getsingleindex(int(inds))]
def __len__(self):
return len(self.cells)
The Actual Diamond-Square Generation
# performs the actual 2D generation
class World:
def genWorld (self, numcells, cellsize, seed, scale = 1.0):
random.seed(seed)
self.dims = numcells*cellsize
self.seed = seed
self.cells = Matrix(self.dims, self.dims)
mountains = Matrix(self.dims, self.dims)
# set the cells at cellsize intervals
for y in range(0, self.dims, cellsize):
for x in range(0, self.dims, cellsize):
# this is the default, sets the heights randomly
self.cells[x,y] = random.random()
while cellsize > 1:
self._diamondSquare(cellsize, scale)
scale *= 0.5
cellsize = int(cellsize/2)
for i in range(len(mountains)):
self.cells[i] = self.cells[i]*0.4 + (mountains[i]*mountains[i])*0.6
def _diamondSquare(self, stepsize, scale):
half = int(stepsize/2)
# diamond part
for y in range(half, self.dims+half, stepsize):
for x in range(half, self.dims+half, stepsize):
self.cells[x, y] = ((self.cells[x-half, y-half] + self.cells[x+half, y-half] + self.cells[x-half, y+half] + self.cells[x+half, y+half])/4.0) + (rand()*scale)
# square part
for y in range(0, self.dims, stepsize):
for x in range(0, self.dims, stepsize):
self.cells[x+half,y] = ((self.cells[x+half+half, y] + self.cells[x+half-half, y] + self.cells[x+half, y+half] + self.cells[x+half, y-half])/4.0)+(rand()*scale)
self.cells[x,y+half] = ((self.cells[x+half, y+half] + self.cells[x-half, y+half] + self.cells[x, y+half+half] + self.cells[x, y+half-half])/4.0)+(rand()*scale)
Main Function (added for completeness)
# a simple main function that uses World to create a 2D array of diamond-square values, then writes it to a file
def main():
w = World()
w.genWorld(20, 16, 1)
mi = min(w.cells.cells)
ma = max(w.cells.cells) - mi
# save the resulting matrix to an image file
file = io.open("sample.raw",'wb')
maxed = [(i-mi)/ma for i in w.cells.cells]
arr = [int(i * 255) for i in maxed]
file.write(bytearray(arr))
file.close()

Categories

Resources