simplified minesweeper recursion in python: why is this code not succeeding? - python

I'm working on developing a minesweeper clone in python and am having trouble getting the reveal function to work. Currently, I get the following infinite error messages:
File "/Users/home/Desktop/minesweeper.py", line 79, in uncover_cells
uncover_cells(i - 1, j, board)
where uncover_cells is defined as follows (EDIT: added simpler example of problem at end of post):
def uncover_cells(i, j, board):
length = len(board)
width = len(board[0])
if i > -1 and j > -1 and i < length and j < width and not board[i][j].visited:
board[i][j].visited = True
# unproblematic code removed
uncover_cells(i + 1, j, board)
uncover_cells(i - 1, j, board)
uncover_cells(i, j + 1, board)
uncover_cells(i, j - 1, board)
uncover_cells(i + 1, j + 1, board)
uncover_cells(i + 1, j - 1, board)
uncover_cells(i - 1, j + 1, board)
uncover_cells(i - 1, j - 1, board)
return
The original call is:
b, locs = setup_game(100, 100, 50)
uncover_cells(0, 0, b)
I don't think that the recursion limit has been reached and fear there might be a logic bug. Any input would be greatly appreciated.
Other code that might be important: each element of board is of type Cell:
class Cell:
def __init__(self, isMine, loc, visited = False, flagged = False):
self.visited = visited # think of visited as 'uncovered'
self.flagged = flagged
self.isMine = isMine
self.x = loc[0]
self.y = loc[1]
self.label = 0
Here's how the board is setup:
def setup_game(length, width, n_mines):
idx = [(i, j) for j in range(width) for i in range(length)]
board = [[None for j in range(width)] for i in range(length)]
mine_locs = random.sample(idx, n_mines)
for i, j in idx:
if (i, j) in mine_locs:
board[i][j] = Cell(isMine = True, loc = (i, j))
else:
board[i][j] = Cell(isMine = False, loc = (i, j))
return board, mine_locs
EDIT: here's the simplest instance of my problem:
def simple_fill(i, j, b):
length = len(b)
width = len(b[0])
if i > -1 and j > -1 and i < length and j < width and b[i][j] != 1:
b[i][j] == 1
simple_fill(i + 1, j, b)
simple_fill(i - 1, j, b)
simple_fill(i, j + 1, b)
simple_fill(i, j - 1, b)
simple_fill(i + 1, j + 1, b)
simple_fill(i + 1, j - 1, b)
simple_fill(i - 1, j + 1, b)
simple_fill(i - 1, j - 1, b)
return
original call:
b = [[0 for j in range(100)] for i in range(100)]
simple_fill(0, 0, b)

In simple_fill():
b[i][j] == 1 # You have.
b[i][j] = 1 # Should be.
Using this code, your uncover_cells() works ... but only for small n. After that, we hit maximum recursion depth.
class Cell(object):
def __init__(self, i, j):
self.i = i
self.j = j
self.visited = False
def main():
n = 30 # Works ... but not, for example, for 40.
board = [[Cell(i,j) for j in range(n)] for i in range(n)]
uncover_cells(0, 0, board)
for row in board:
for cell in row:
assert cell.visited
main()

I reimplemented simple_fill with a stack:
def simple_fill(x, y, b):
length = len(b)
width = len(b[0])
stack = [(x,y)]
while len(stack) > 0:
i, j = stack.pop()
if i > -1 and j > -1 and i < length and j < width :
if b[i][j] != 1:
b[i][j] = 1
stack.append((i + 1, j))
stack.append((i - 1, j))
stack.append((i, j + 1))
stack.append((i, j - 1))
stack.append((i + 1, j + 1))
stack.append((i + 1, j - 1))
stack.append((i - 1, j + 1))
stack.append((i - 1, j - 1))
Hopefully this is helpful for someone in the future (https://xkcd.com/979/)

Related

My Conway's game of life is not properly updating colors on the board and working correctly

I've been trying to figure out why when I run the GUI of the board, all the colors slowly start turning into one color over time such as green, brown, pink, etc. Also, when I put 3 cells in a row they disappear instead of looping infinitely. This is the board class responsible for updating and checking everything on the board. I've tried many different ways but still end in the same result. I'm relatively new to coding so any help would be appreciated!
class Board:
def __init__(self, size=20):
self._board = [[(0, 0, 0) for _ in range(size)] for _ in range(size)]
self._prior = copy.deepcopy(self._board)
def get_board(self):
return self._board
def change_color(self, i, j):
r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
self._board[i][j] = (r, g, b)
def count_neighbors(self, i, j):
num_neighbors = 0
total_r = 0
total_g = 0
total_b = 0
for x in range(i - 1, i + 2):
for y in range(j - 1, j + 2):
if 0 <= x < len(self._board) and 0 <= y < len(self._board[i]):
if (x, y) != (i, j) and self._board[x][y] != (0, 0, 0):
num_neighbors += 1
total_r += self._board[x][y][0]
total_g += self._board[x][y][1]
total_b += self._board[x][y][2]
if num_neighbors > 0:
average_color = (total_r // num_neighbors, total_g // num_neighbors, total_b // num_neighbors)
else:
num_neighbors = 0
average_color = (0, 0, 0)
return num_neighbors, average_color
def update(self):
self._prior = copy.deepcopy(self._board)
for i in range(len(self._prior)):
for j in range(len(self._prior[i])):
num_neighbors, average_color = self.count_neighbors(i, j)
if self._board[i][j] != (0, 0, 0):
if num_neighbors < 2 or num_neighbors > 3:
self._board[i][j] = (0, 0, 0)
elif num_neighbors == 3:
self._board[i][j] = average_color
if random.randint(1, 100) == 42:
x = random.randint(0, len(self._board) - 1)
y = random.randint(0, len(self._board) - 1)
self.change_color(x, y)

Python: How can I reduce the number of 'if' statements down to a reasonable amount for my game?

Im making a chess game in python and was trying to generate the legal moves of each piece using 'if' statements to see if the space the player wants to move to is free and if the move is actually within the borders of the board. The problem is that there are too many 'if' statements as well as nested 'if' statements. This really makes my file look like spaghetti code and over-complicates the process.
Here is an example:
def valid_moves(self, board):
i = self.row
j = self.col
moves = []
if i > 0:
# TOP LEFT
if j > 0:
p = board[i - 1][j - 1]
if p == 0: # checks if space empty
moves.append((j - 1, i - 1,))
elif p.color != self.color:
moves.append((j - 1, i - 1,))
# TOP MIDDLE
p = board[i - 1][j]
if p == 0: # checks if space empty
moves.append((j, i - 1))
elif p.color != self.color:
moves.append((j, i - 1))
# TOP RIGHT
if j < 7:
p = board[i - 1][j + 1]
if p == 0: # checks if space empty
moves.append((j + 1, i - 1,))
elif p.color != self.color:
moves.append((j + 1, i - 1,))
if i < 7:
# BOTTOM LEFT
if j > 0:
p = board[i + 1][j - 1]
if p == 0: # checks if space empty
moves.append((j - 1, i + 1,))
elif p.color != self.color:
moves.append((j - 1, i + 1,))
# BOTTOM MIDDLE
p = board[i + 1][j]
if p == 0: # checks if space empty
moves.append((j, i + 1))
elif p.color != self.color:
moves.append((j, i + 1))
# BOTTOM RIGHT
if j < 7:
p = board[i + 1][j + 1]
if p == 0: # checks if space empty
moves.append((j + 1, i + 1))
elif p.color != self.color:
moves.append((j + 1, i + 1))
# MIDDLE LEFT
if j > 0:
p = board[i][j - 1]
if p == 0: # checks if space empty
moves.append((j - 1, i))
elif p.color != self.color:
moves.append((j - 1, i))
# MIDDLE RIGHT
if j < 7:
p = board[i][j + 1]
if p == 0: # checks if space empty
moves.append((j + 1, i))
elif p.color != self.color:
moves.append((j + 1, i))
return moves
This example is for just 1 piece out of 6 and so there is a lot of occurring 'if' statements. How can I refractor this to where I don't need to use as many 'if' statements?
A local function helps to avoid code duplicates:
def valid_moves(self, board):
i = self.row
j = self.col
moves = []
def move(a: int, b: int) -> None:
p = board[a][b]
if p == 0 or p.color != self.color:
moves.append((b, a))
if i > 0:
# TOP LEFT
if j > 0:
move(i - 1, j - 1)
# TOP MIDDLE
move(i - 1, j)
# TOP RIGHT
if j < 7:
move(i - 1, j + 1)
if i < 7:
# BOTTOM LEFT
if j > 0:
move(i + 1, j - 1)
# BOTTOM MIDDLE
move(i + 1, j)
# BOTTOM RIGHT
if j < 7:
move(i + 1, j + 1)
# MIDDLE LEFT
if j > 0:
move(i, j - 1)
# MIDDLE RIGHT
if j < 7:
move(i, j + 1)
return moves
First generate all possible moves, including illegal ones. Then filter the illegal ones. Also you check whether i > 0 or i < 7, I think you meant i >= 0 and i < 8 if you're using zero-based indexing for an 8x8 chess board.
def valid_moves(self, board):
i = self.row
j = self.col
destinations = [
(j + dj, i + di)
for di [-1, 0, 1] for dj in [-1, 0, 1]
# Disallow staying in place - not a move.
if not (di == 0 and dj == 0)
]
legal_moves = [
(mj, mi)
for mj, mi in destinations
# In bounds.
if 0 <= mi < 8 and 0 <= mj < 8
# And empty or enemy occupied.
and (board[mi][mj] == 0 or board[mi][mj].color != self.color)
]
return legal_moves
You seem to only be looking for a one space move so it could be simplified by looping on the vertical and horizontal deltas of each direction:
def valid_moves(self, board):
moves = []
for v,h in [(-1,-1),(0,-1),(0,1),(-1,0),(1,0),(1,1)]: # directions
r,c = self.row+v,self.col+h # advance by 1
if r not in range(8): continue # vertical bounds
if c not in range(8): continue # horizontal bounds
p = board[r][c]
if p==0 or p.color != self.color: # playable position
moves.append((r,c))
return moves
This isn't going to cover multi-step moves and non-linear moves. There is a strategy for all types of moves here.

Bubble sort a dictionary

I am having problem to implement the bubble, insertion and selection sort. I have no idea how to make the whole thing works. Any kind soul pleaseee
Here below are the object added into the dictionary
items = {}
items[1] = Item(1,'Juicy',2,99,'New Zealand','Orange')
items[2] = Item(4,'Sweet',2,99,'Thailand','Mango')
items[3] = Item(6,'Tasty & Sweet',4,99,'Malaysia','Bananas')
items[4] = Item(2,'Juicy',5,99,'Australia','Watermelons')
Here below are the sort function but are unable to sort
def bubble(theSeq):
n = len(theSeq)
for i in range(1, n):
for j in range(n - i):
if theSeq[j] > theSeq[j + 1]:
tmp = theSeq[j]
theSeq[j] = theSeq[j + 1]
theSeq[j + 1] = tmp
def selection(theSeq):
n = len(theSeq)
for i in range(n - 1):
smallNdx = i # 0
for j in range(i + 1, n):
if theSeq[j] > theSeq[smallNdx]:
smallNdx = j
if smallNdx != i:
tmp = theSeq[i]
theSeq[i] = theSeq[smallNdx]
theSeq[smallNdx] = tmp
def insertion(theSeq):
n = len(theSeq)
for i in range(0, n):
value = theSeq[i]
pos = i
while pos > 0 and value < theSeq[pos - 1]:
theSeq[pos] = theSeq[pos - 1]
pos -= 1
theSeq[pos] = value
If "Item" is a class, firstly, you should make sure, that you enabled comparison of class instances, using method: __le__, __ge__ and so on, secondly, I think you have some problems with first index in your dictionary, which is equal to 1, but in sorting you start counting from 0, in your place I would write this code for insertion sort:
def insertion(theSeq):
n = len(theSeq)
for i in range(1, n + 1):
pos = i
while pos > 1 and theSeq[pos] < theSeq[pos - 1]:
theSeq[pos], theSeq[pos - 1] = theSeq[pos - 1], theSeq[pos]
pos -= 1
But I think, that the main problem is that you can't compare instances of "Item" class, I've run your code on list's with parameters and it went successfully:
items = {}
items[1] = [1,'Juicy',2,99,'New Zealand','Orange']
items[2] = [4,'Sweet',2,99,'Thailand','Mango']
items[3] = [6,'Tasty & Sweet',4,99,'Malaysia','Bananas']
items[4] = [2,'Juicy',5,99,'Australia','Watermelons']
insertion(items)
for x in items.items():
print(x)

Python recursion - max lenght of a subsequence in a matrix is not updated

I am trying to find the longest sequence of a character in a matrix. I am realively new to python, and I think the problem is that python's recursive methods are not the same as C/C++/Java etc. here is my code, now... Do you know another way to do this, if reccursion is not a thing in Python, or can you fix my code to work in pythonic recusion? ( the problem is that the lenght and the visited matrix is not updated during recursion ).
def get_current_score(self, i, j, char, viz, leng):
leng = 0
self.viz[i][j] = True
if (self.out_of_span(i - 1, j) == False and self.viz[i-1][j] == False and self.matrix[i - 1][j] == char):
self.viz[i - 1][j] = True
return leng + self.get_current_score(i - 1, j, char, self.viz, leng)
if (self.out_of_span(i - 1, j +1) == False and self.viz[i-1][j+1] == False and self.matrix[i - 1][j + 1] == char):
self.viz[i - 1][j + 1] = True
return leng + self.get_current_score(i - 1, j + 1, char, self.viz, leng)
if (self.out_of_span(i - 1, j - 1) == False and self.viz[i-1][j-1] == False and self.matrix[i - 1][j - 1] == char):
self.viz[i - 1][j - 1] = True
return leng + self.get_current_score(i - 1, j - 1, char, self.viz, leng)
if (self.out_of_span(i, j - 1) == False and self.viz[i][j-1] == False and self.matrix[i][j - 1] == char):
self.viz[i][j - 1] = True
return leng + self.get_current_score(i, j - 1, char, self.viz, leng)
if ( self.out_of_span(i, j + 1) == False and self.viz[i][j+1] == False and self.matrix[i][j + 1] == char):
self.viz[i][j + 1] = True
return leng + self.get_current_score(i, j + 1, char, self.viz, leng)
if ( self.out_of_span(i + 1, j) == False and self.viz[i+1][j] == False and self.matrix[i + 1][j] == char):
self.viz[i + 1][j] = True
return leng + self.get_current_score(i + 1, j, char, self.viz, leng)
if (self.out_of_span(i + 1, j - 1) == False and self.viz[i+1][j-1] == False and self.matrix[i + 1][j - 1] == char):
self.viz[i + 1][j - 1] = True
return leng + self.get_current_score(i + 1, j - 1, char, self.viz, leng)
if (self.out_of_span(i + 1, j + 1) == False and self.viz[i+1][j+1] == False and self.matrix[i + 1][j + 1] == char):
self.viz[i + 1][j + 1] = True
return leng + self.get_current_score(i + 1, j + 1, char, self.viz, leng)
return 1 + leng
def add(self, index):
[...]
# scor
print('\n --------------\n')
for i in range(self.maxh, self.nr):
for j in range(self.span[0], self.span[1]+1):
if(self.player1 == False and self.matrix[i][j] == 'X'):
self.score1 = max(self.score1, self.get_current_score(i, j, 'X', self.viz, self.score1))
self.viz[i][j] = True
#self.score1 -= 1
else:
if(self.player1 == True and self.matrix[i][j] == 'O'):
self.score2 = max(self.score2, self.get_current_score(i, j, 'O', self.viz, self.score1))
self.viz[i][j] = True
self.reset_viz()
self.print_matrix()
i think this will do
def get_current_score(self, i, j, char, leng):
# leng = 0 <- don't
self.viz[i][j] = True # you set it twice, let's keep that one
def test_cell(a, b): # keep it DRY
return self.out_of_span(a, b) == False \
and self.viz[a][b] == False \
and self.matrix[a][b] == char
cells = [(i - 1, j), (i - 1, j + 1), (i - 1, j - 1), (i, j - 1),
(i, j + 1), (i + 1, j), (i + 1, j - 1), (i + 1, j + 1)]
for a, b in cells:
if test_cell(a, b):
# you don't need to set that cell to true since that's the
# first thing you do in the function
# self.viz[a][b] = True
return leng + self.get_current_score(a, b, char, leng)
return 1 + leng
def add(self, index):
[...]
# scor
print('\n --------------\n')
for i in range(self.maxh, self.nr):
for j in range(self.span[0], self.span[1]+1):
if(self.player1 == False and self.matrix[i][j] == 'X'):
# no need to send self.viz here. same for score2
# if you need to set self.score1 to 0 do it here. not in the recursion
self.score1 = max(self.score1, self.get_current_score(i, j, 'X', self.score1))
self.viz[i][j] = True
#self.score1 -= 1
else:
if(self.player1 == True and self.matrix[i][j] == 'O'):
self.score2 = max(self.score2, self.get_current_score(i, j, 'O', self.score1))
self.viz[i][j] = True
self.reset_viz()
self.print_matrix()

Hanoi sort algirithm

How to implement Hanoi sort in python? Rules of Hanoi sort: http://www.dangermouse.net/esoteric/hanoisort.html
My code:
def hanoy_sorted(arr, x, y):
if len(arr) == 1:
print(arr[0], x, y)
elif len(arr) > 1:
hanoy_sorted(arr[1:], x, 6 - x - y)
print(arr[0], x, y)
hanoy_sorted(arr[1:], 6 - x - y, y)
def merge(arr1, x, arr2, y):
if len(arr2) == 0:
hanoy(arr1, x, y)
elif len(arr1) > 0:
n = arr1[-1]
j = len(arr2) - 1
if n < arr2[-1]:
print(arr1[-1], x, y)
j = len(arr2)
else:
for i in range(0, len(arr2)):
if n > arr2[i]:
j = i + 1
break
hanoy_sorted(arr2[j - 1:], y, x)
hanoy_sorted([n] + arr2[j - 1:], x, y)
arr2.insert(j, n)
merge(arr1[:len(arr1) - 1], x, sorted(arr2)[::-1], y)
def hanoy(arr, x, y):
if len(arr) == 1:
print(arr[0], x, y)
if len(arr) > 1:
mi = arr.index(max(arr))
up = arr[mi + 1:]
z.append(up[:])
hanoy(z[-1], x, 6 - x - y)
print(arr[mi], x, y)
merge(arr[:mi], x, sorted(up)[::-1], 6 - x - y)
arr.remove(arr[mi])
hanoy_sorted(sorted(arr)[::-1], 6 - x - y, y)
del z[-1]
n = int(input())
arr = list(map(int, input().split()))[::-1]
z = []
hanoy(arr, 1, 3)
There is an error in function merge: It sometimes puts bigger disk on smaller. How to fix that?
This programme prints what disk to move from rod1, to rod2.
Updated:
So I rewrote all my code and now I have that:
from sys import setrecursionlimit
setrecursionlimit(10000000)
def gen_moves(pos, prev_move):
moves = []
not_to_go = [prev_move[0], prev_move[2], prev_move[1]]
not_to_go2 = [prev_move[0], prev_move[2], 6 - prev_move[2] - prev_move[1]]
first, second, third = pos
if first != []:
if second != []:
if second[-1] > first[-1]:
moves.append([first[-1], 1, 2])
else:
moves.append([second[-1], 2, 1])
else:
moves.append([first[-1], 1, 2])
if third != []:
if third[-1] > first[-1]:
moves.append([first[-1], 1, 3])
else:
moves.append([third[-1], 3, 1])
else:
moves.append([first[-1], 1, 3])
else:
if second != []:
moves.append([second[-1], 2, 1])
if third != []:
moves.append([third[-1], 3, 1])
if second != []:
if third != []:
if second[-1] > third[-1]:
moves.append([third[-1], 3, 2])
else:
moves.append([second[-1], 2, 3])
else:
moves.append([second[-1], 2, 3])
else:
if third != []:
moves.append([third[-1], 3, 2])
if not_to_go in moves:
moves.remove(not_to_go)
if not_to_go2 in moves:
moves.remove(not_to_go2)
return moves
def do_move(arr, move):
pos = arr[:]
disk, from_rod, to_rod = move
pos[from_rod - 1] = pos[from_rod - 1][:-1]
pos[to_rod - 1] = pos[to_rod - 1] + [disk]
return pos
def hanoi(arr, solved, prev_move):
if not solved:
moves = gen_moves(arr, prev_move)
for move in moves:
pos = arr[:]
pos = do_move(pos, move)
sorted_arr = sorted(arr[0] + arr[1] + arr[2])[::-1]
for i in range(3):
if pos[i] == sorted_arr:
solved = True
solved = solved or hanoi(pos, solved, move)
if solved:
moves_to_solve.append(move)
break
return solved
n = int(input())
arr = [list(map(int, input().split()))[::-1], [], []]
solved = False
moves_to_solve = []
sorted_arr = sorted(arr[0] + arr[1] + arr[2])[::-1]
for i in range(3):
if arr[i] == sorted_arr:
solved = True
if n > 1 and not solved:
solved = hanoi(arr, solved, [0, 0, 0])
moves_to_solve = moves_to_solve[::-1]
for move in moves_to_solve:
print(*move)
It works right but if there are eleven disks programme prints segmentation fault. How to fix that?
You can simply use a recursive approach with a helper function to implement the tower of hanoi. Something like this;
def moveTower(height,fromPole, toPole, withPole):
if height >= 1:
moveTower(height-1,fromPole,withPole,toPole)
moveDisk(fromPole,toPole)
moveTower(height-1,withPole,toPole,fromPole)
def moveDisk(fp,tp):
print("moving disk from",fp,"to",tp)

Categories

Resources