I'm trying to make a function for a minesweeper game I'm making. This function's purpose is to reveal an element given the x and y (where it is located). This is probably not the most elegant way to accomplish it, but I'm making a list of ['-'] for each tile titled newField
. A '-' represents a hidden block (where you don't know if its a bomb or how many bombs are surrounding it). Then, I change one element from the newField
to equal its corresponding block from the listField
(which is a list of lists. Each list within it represents a row). An X represents a bomb and the numbers represent how many bombs surround in.
In minesweeper, when a block with zero bombs surrounding it is revealed, it's surrounding blocks are also revealed. I've made a functioned titled revealSurroundings
that accomplishes this. When I run revealSurroundings
in the function revealElement
as I do below, it freezes my computer. However, if I run revealSurroundings
outside of the function revealElement
it works fine.
If anyone has any advice on how to solve this issue and/or make it more efficient(because I know the method I'm using is very expensive), please let me know.
wl = 10
listField =
[['1', '1', '0', '0', '0', '0', '0', '0', '1', 'X'],
['X', '2', '2', '2', '2', '2', '2', '1', '1', '1'],
['1', '2', 'X', 'X', '2', 'X', 'X', '2', '2', '2'],
['1', '2', '3', '2', '2', '2', '3', '4', 'X', 'X'],
['1', 'X', '1', '0', '0', '1', '3', 'X', 'X', '3'],
['1', '2', '2', '1', '0', '1', 'X', 'X', '4', '2'],
['2', '3', 'X', '1', '0', '1', '2', '2', '2', 'X'],
['X', 'X', '2', '1', '1', '1', '1', '0', '1', '1'],
['4', '5', '4', '3', '3', 'X', '2', '1', '0', '0'],
['X', 'X', 'X', 'X', 'X', '3', 'X', '1', '0', '0']]
hiddenField = ['-' for i in range(wl*wl)]
def removeN(ls, n, iterations):
items = ls
try:
for i in range(iterations):
items.remove(n)
except:
pass
return items
def revealElement(wl, x, y, userField):
yReal = y-1
xReal = x-1
newField = list(userField)
removeN(newField, '\n', wl-1)
newField[yReal*wl + xReal] = listField[yReal][xReal]
if newField[yReal*wl + xReal] == '0':
revealSurroundings(wl, x, y, userField)
for i in range(wl-1, 0, -1): # go backwards
newField.insert(wl*i, '\n')
return "".join(newField) # make it a string
def revealSurroundings(wl, x, y, userField):
yReal = y-1
xReal = x-1
newField = userField
try:
newField = revealElement(wl, x+1, y, newField)
except:
pass
#right
try:
if xReal != 0:
newField = revealElement(wl, x-1, y, newField)
except:
pass
#left
try:
if yReal != 0:
newField = revealElement(wl, x, y-1, newField)
except:
pass
#up
try:
newField = revealElement(wl, x, y+1, newField)
except:
pass
#down
try:
if yReal != 0:
newField = revealElement(wl, x+1, y-1, newField)
except:
pass
#upper-right
try:
if yReal != 0 and xReal != 0:
newField = revealElement(wl, x-1, y-1, newField)
except:
pass
#upper left
try:
newField = revealElement(wl, x+1, y+1, newField)
except:
pass
#bottom-right
try:
if xReal != 0:
newField= revealElement(wl, x-1, y+1, newField)
except:
pass
#bottom-left
return newField
print revealSurroundings(10, 7, 2, hiddenField)
The problem seems to be that when you run the revealSurroundings
within revealElement
, you're creating a never-ending loop.
When you run revealElement
, if the element is 0 the function revealSurroundings
is run. Within revealSurroundings
you run revealElement
. If new element revealed is also a zero, it once again runs revealSurroundings
and detects the zero from the first iteration of revealElement
.
This begins an infinite loop that never ends. I suggest adding another conditional in revealSurroundings
, such as checking to see if you already revealed the characters next to it through a simple if statement. I would also recommend re-writing the code altogether because of what @gorlen stated.
This logic seems like overkill for a basic Minesweeper reveal algorithm. A few thoughts:
__str__
method to print a board and pass the grid into the initializer. There's no need to stringify the grid for algorithmic purposes--leave it as a list internally.Tile
class/recordtype/dict with properties for visible
, status
/ contents
. This lets you store all necessary grid data in one data structure.wl
must be the board size, but this is redundant information since lists already have a len
property that's guaranteed consistent and is semantically meaningful. snake_case
instead of camelCase
for all variables and functions. UpperCamelCase
for class names. See PEP-8 .end
keyword or braces, so anything less than 4 spaces makes it difficult to disambiguate blocks. try
/ except
blocks for logic that's easily converted to conditionals, especially if you're using Pokemon exceptions . You may inadvertently suppress errors other than those you intend to, and it's an abuse of a construct that's not designed for general-purpose control flow.yReal = y-1; xReal = x-1
yReal = y-1; xReal = x-1
is likely causing confusion because it's performed on every frame recursively. If you have to do this, move the logic out of the algorithm and normalize/denormalize as close to the IO interface as possible.Here's a re-write suggestion:
class Minesweeper:
class Tile:
def __init__(self, mark, visible=False):
self.mark = mark
self.visible = visible
def __str__(self):
return self.mark if self.visible else "-"
neighbors = [(x, y) for x in range(-1, 2)
for y in range(-1, 2) if x or y]
def __init__(self, field):
self.field = [[self.Tile(x) for x in row] for row in field]
def in_bounds(self, x, y):
return y >= 0 and y < len(self.field) and \
x >= 0 and x < len(self.field[y])
def reveal(self, x, y):
if self.in_bounds(x, y) and not self.field[y][x].visible and \
self.field[y][x].mark == "0":
self.field[y][x].visible = True
for dx, dy in self.neighbors:
self.reveal(x + dx, y + dy)
def __str__(self):
return "".join("".join(map(str, row)) + "\n" for row in self.field)
if __name__ == "__main__":
field = [
"00000",
"12210",
"1XX10",
]
board = Minesweeper(field)
print board
board.reveal(3, 0)
print board
Output:
-----
-----
-----
00000
----0
----0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.