Related
I have to make this small recursion exercise where, given a matrix and a number I have to return the position of the number in the matrix. For example:
matrix = [[2,0,1],[3,5,3],[5,1,4,9],[0,5]]
numberToFind = 5
The expected result would be this one:
[(1,1),(2,0),(3,1)]
Could anyone pint me on how to start or what I have to do to create the code?
Here is one approach using a recursive generator:
matrix = [[2,0,1],[3,5,3],[5,1,4,9],[0,5]]
numberToFind = 5
def find(m, n, prev=tuple()):
for i,x in enumerate(m):
if isinstance(x, list):
yield from find(x, n, prev=prev+(i,))
elif x==n:
yield prev+(i,)
list(find(matrix, numberToFind))
output: [(1, 1), (2, 0), (3, 1)]
other example:
matrix = [[2,0,1],[3,5,3],[5,1,4,5],[0,5],[[[2,5,[1,5]]]]]
list(find(matrix, numberToFind))
# [(1, 1), (2, 0), (2, 3), (3, 1), (4, 0, 0, 1), (4, 0, 0, 2, 1)]
you can use just a single for loop as below. Way more efficient than a recursion
matrix = [[2,0,1],[3,5,3],[5,1,4,9],[0,5]]
my_list = []
for x in range(0,len(matrix)):
try:
a = matrix[x].index(5)
my_list.append((x,a))
except ValueError:
pass
As the title says, I've been running into issues with my code not running properly. It reaches maximum recursion depth, and after some debugging with print statements, it seems like it runs through the pawns possible moves, but then gets stuck on Rooks moves, repeating this set of values (included 1 repeat):
pos: 0 0
count 1
<chessPieces.Rook object at 0x115cc5610>
[]
pos: 7 0
[]
pos: 7 1
[]
pos: 3 4
[(0, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
pos: 1 0
count 1
<chessPieces.Rook object at 0x115cc5610>
[]
pos: 7 0
[]
pos: 7 1
[]
pos: 3 4
[(1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
pos: 0 0
count 1
<chessPieces.Rook object at 0x115cc5610>
[]
pos: 7 0
[]
pos: 7 1
[]
pos: 3 4
[(0, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
The current legal moves for each piece is the list of tuples that is printed (which for some reason is sometimes an empty list even though it seems to make a move). Here is my code below:
def makeMinimaxMove(app,isMax,depth):
score, pieceMoved, move = minimax(app,isMax,depth,None,None,0)
newLoc = findPiece(app,move[0],move[1])
app.pieceSelected = pieceMoved
moveToSelection(app,newLoc,move[0],move[1])
def minimax(app,isMax,depth,pieceMoved,move,count): #board just pieces so can be found w app
#print(depth)
curBoard = copy.copy(app.pieces)
score = evaluate(app)
if score >= 900: #if maximizer captured opponents King
return score, pieceMoved, move #not sure how to pass move and piece thru
elif score <= -900: #if minimizer captured opponents King
return score, pieceMoved, move
elif depth <= 0:
print('depth exceeded')
return score, pieceMoved, move
if isMax:
team = 'white'
best = [-10000,None,None]
for piece in app.pieces:
if piece.team == team:
findPossibleMoves(app,piece)
for (row,col) in app.currentLegalMoves:
count += 1
print('count',count)
curBoard = copy.deepcopy(app.pieces)
move = (row,col)
newLoc = findPiece(app,row,col)
app.pieceSelected = piece
moveToSelection(app,newLoc,row,col)
score, pieceMoved, move = minimax(app,not isMax,depth-1,piece,move,count)
if score >= best[0]:
best = [score,pieceMoved,move] #update all characteristics of best
app.pieces = curBoard #undo move
else:
team = 'black'
best = [10000,None,None]
for piece in app.pieces:
if piece.team == team:
findPossibleMoves(app,piece)
print(app.currentLegalMoves)
print('pos:',piece.row,piece.col)
for (row,col) in app.currentLegalMoves:
curBoard = copy.deepcopy(app.pieces)
count += 1
print('count',count)
move = (row,col)
newLoc = findPiece(app,row,col)
print(piece)
app.pieceSelected = piece
moveToSelection(app,newLoc,row,col)
score, pieceMoved, move = minimax(app,not isMax,depth-1,piece,move)
print('made it')
if score >= best[0]:
best = [score,pieceMoved,move] #update all characteristics of best
app.pieces = curBoard #undo move
#reset all other app instances too
How can I order a list of orthogonal polygon points?
For example, I have a list of orthorgonal polygon points
data = [(2, 0), (5, 0), (5, 7), (4, 7), (4, 5), (3, 5),(3, 3), (2, 3), (2, 2), (3, 2), (3, 7), (2, 7)]
Not in order.
I want to order it in a counter-clockwise way like this:
out = [(2,0),(5,0),(5,7),(4,7),(4,5),(3,5),(3,7),(2,7),(2,3),(3,3),(3,2),(2,2)]
I had tried to use deflate _hull already but it did not correct.
Is there any algorithm to solve this problem ?
I get this:
But expected :
You can use the following recursive function:
def sort_ortho_poly(points, current=None, start=None, go_x=True):
# initialize the starting point at the bottom left, which should have the least sum of x and y
if not current:
start = current = min(points, key=sum)
# if we're going x-wards, v would be the y index (1), h would be the x index (0), and vice versa
v, h = go_x, not go_x
# remove the current point from the list of points so the next recursion would be processing the remaining points
remaining = points[:]
remaining.remove(current)
# if there is no more remaining point
if not remaining:
# we've found a path if we are able to connect back to the starting point, or else we don't
return [current] if start[v] == current[v] else []
# try each point in the remaining points that goes in the right direction from the current point
for next in [p for p in remaining if p[v] == current[v]]:
# recursively find a valid path from the remaining points after flipping the direction
path = sort_ortho_poly(remaining, next, start, not go_x)
# if we get a path that does go back to the starting point, we have to make sure the path is valid
if path:
# the current edge (e1, e2)
e1, e2 = current, next
# make sure e1 is lower than or left of e2
if e1[h] > e2[h]:
e1, e2 = e2, e1
# for each edge (p1, p2) in the path, including the final edge connecting to the starting point
for p1, p2 in zip(path, path[1:] + [start]):
# make sure p1 is lower than or left of p2
if p1[0] == p2[0] and p1[1] > p2[1] or p1[1] == p2[1] and p1[0] > p2[0]:
p1, p2 = p2, p1
# if the edge is in the same line as the current edge
if p1[v] == p2[v] == e1[v]:
# make sure the two edges don't overlap
if e1[h] < p1[h] < e2[h] or e1[h] < p2[h] < e2[h] or p1[h] < e1[h] < p2[h] or p1[h] < e2[h] < p2[h]:
break
# if the edge is perpendicular to the current edge, make sure they don't cross over
elif p1[h] == p2[h] and e1[h] < p1[h] < e2[h] and p1[v] < e1[v] < p2[v]:
break
else:
# the path is valid! we append the path to the current point and return
return [current, *path]
# return empty if it's a dead end
return []
so that:
data = [(2, 0), (5, 0), (5, 7), (4, 7), (4, 5), (3, 5),(3, 3), (2, 3), (2, 2), (3, 2), (3, 7), (2, 7)]
print(sort_ortho_poly(data))
would output:
[(2, 0), (5, 0), (5, 7), (4, 7), (4, 5), (3, 5), (3, 7), (2, 7), (2, 3), (3, 3), (3, 2), (2, 2)]
inp[0][0] = shadow[3][0]
inp[0][3] = shadow[0][0]
inp[3][3] = shadow[0][3]
inp[3][0] = shadow[3][3]
I want to turn this code into a for loop, because this is disgusting! I can't figure out how though.
You are basically picking two sets of coordinates from the series (0, 0), (0, 3), (3, 3), (3, 0), in a ring fashion. You can do so by iteration over that series with an index to use for the second point:
points = [(0, 0), (0, 3), (3, 3), (3, 0)]
for index, (x, y) in enumerate(points, -1):
shadow_x, shadow_y = points[index]
inp[x][y] = shadow[shadow_x][shadow_y]
By giving the enumerate() function a starting point of -1 we create an offset that'll find the right matching point in points.
You could also use the zip() function:
points = [(0, 0), (0, 3), (3, 3), (3, 0)]
for (x, y), (shadow_x, shadow_y) in zip(points, [points[-1]] + points):
inp[x][y] = shadow[shadow_x][shadow_y]
Pick whichever you feel fits your usecase best.
Demo (replacing the actual assignment with a print() statement to show what would be executed):
>>> points = [(0, 0), (0, 3), (3, 3), (3, 0)]
>>> for index, (x, y) in enumerate(points, -1):
... shadow_x, shadow_y = points[index]
... print(f"inp[{x}][{y}] = shadow[{shadow_x}][{shadow_y}]")
...
inp[0][0] = shadow[3][0]
inp[0][3] = shadow[0][0]
inp[3][3] = shadow[0][3]
inp[3][0] = shadow[3][3]
>>> for (x, y), (shadow_x, shadow_y) in zip(points, [points[-1]] + points):
... print(f"inp[{x}][{y}] = shadow[{shadow_x}][{shadow_y}]")
...
inp[0][0] = shadow[3][0]
inp[0][3] = shadow[0][0]
inp[3][3] = shadow[0][3]
inp[3][0] = shadow[3][3]
I got an array of consisting of 0 and 1. The 1s form continuous clusters as show in the image.
The number of clusters are not known beforehand.
Is there some way to create a list with the positions of all the clusters, or a list for each cluster which contain the position of all its members. For example:
cluster_list = continuous_cluster_finder(data_array)
cluster_list[0] = [(pixel1_x, pixel1_y), (pixel2_x, pixel2_y),...]
It is not clear from the description what are the exact constraints of the problem.
Assuming you can distinguish a cluster by zeros on left, right,above,below then the following solves the problem...
#!/usr/bin/env python
data = [ #top-left
[0,0,1,1,0,0],
[0,0,1,1,0,0],
[1,1,0,0,1,1],
[1,1,0,0,1,1],
[0,0,1,1,0,0],
[0,0,1,1,0,0],
[1,1,0,0,1,1],
[1,1,0,0,1,1],
] # bottom-right
d = {} # point --> clid
dcl = {} # clid --> [point1,point2,...]
def process_point(t):
global clid # cluster id
val = data[t[0]][t[1]]
above = (t[0]-1, t[1])
abovevalid = 0 <= above[0] < maxX and 0 <= above[1] < maxY
#below = (t[0]+1, t[1]) # We do not need that because we scan from top-left to bottom-right
left = (t[0], t[1]-1)
leftvalid = 0 <= left[0] < maxX and 0 <= left[1] < maxY
#right = (t[0], t[1]+1) # We do not need that because we scan from top-left to bottom-right
if not val: # for zero return
return
if left in d and above in d and d[above] != d[left]:
# left and above on different clusters, merge them
prevclid = d[left]
dcl[d[above]].extend(dcl[prevclid]) # update dcl
for l in dcl[d[left]]:
d[l] = d[above] # update d
del dcl[prevclid]
dcl[d[above]].append(t)
d[t] = d[above]
elif above in d and abovevalid:
dcl[d[above]].append(t)
d[t] = d[above]
elif left in d and leftvalid:
dcl[d[left]].append(t)
d[t] = d[left]
else: # First saw this one
dcl[clid] = [t]
d[t] = clid
clid += 1
def print_output():
for k in dcl: # Print output
print k, dcl[k]
def main():
global clid
global maxX
global maxY
maxX = len(data)
maxY = len(data[0])
clid = 0
for i in xrange(maxX):
for j in xrange(maxY):
process_point((i,j))
print_output()
if __name__ == "__main__":
main()
It prints ...
0 [(0, 2), (0, 3), (1, 2), (1, 3)]
1 [(2, 0), (2, 1), (3, 0), (3, 1)]
2 [(2, 4), (2, 5), (3, 4), (3, 5)]
3 [(4, 2), (4, 3), (5, 2), (5, 3)]
4 [(6, 0), (6, 1), (7, 0), (7, 1)]
5 [(6, 4), (6, 5), (7, 4), (7, 5)]
You can look a well known 'blob' finding algorithms which are used in image processing to isolate regions of same color. You can also brew your own flavors by finding the islands and marking them visited (while all of them are unvisited at start); all connected ( in a 3x3 grid the center pixel as 8 connected-ness ) and visited pixels form one region; you need to find all such regions in the map.
Blob finding is what you need to look for.