Reputation: 23
I'm creating a version of Minesweeper in python and have run into a small issue. In this piece of code:
if winGame(mines):
printWorld(gameMap)
print 'You Win!'
answer = raw_input('Would you like to play again?')
if answer == 'y':
minesweeper()
else:
print 'Thanks for playing!'
break
It calls the minesweeper function again, which starts the game over again. This code is inside of a while True: loop along with the rest of the game code. The only problem is that if the game is started again and then win and say that you don't want to play again, it doesn't break the loop. I'm thinking this has something to do with the fact that I'm using recursion to call the function again. For now the only thing that works is using sys.exit(), but I'd prefer to have a more legitimate solution if that makes sense.
Here is the entirety of the code:
#Minesweeper Game
#difficulty levels
#make it look better text based
from random import *
import sys
gameMap = '''
#123456789#
1?????????1
2?????????2
3?????????3
4?????????4
#123456789#'''
row = 0
col = 0
coord = []
response = ''
numMines = 5
mines = []
answer = ''
#This runs the game
def minesweeper():
global gameMap
global row
global col
global coord
global mines
global response
global answer
#resets the gameboard after replaying.
gameMap = '''
#123456789#
1?????????1
2?????????2
3?????????3
4?????????4
#123456789#'''
#generates the mines
generateMines()
#converts the world into a list of lists. exception is for when playing again since
#it would try to convert it to a list of lists again
try:
initWorld()
except Exception, e:
pass
#main loop of the game.
while True:
#checks to see if you won the game
if winGame(mines):
printWorld(gameMap)
print 'You Win!'
answer = raw_input('Would you like to play again?')
if answer == 'y':
minesweeper()
else:
print 'Thanks for playing!'
break
#joins the list together so it can be printed
printWorld(gameMap)
print mines
#gets user input and converts it to an int, then adds coords to a list
getCoord()
#asks user what they want to do
clearOrFlag()
if response.lower() == 'c':
if isMine(mines):
answer = raw_input('Would you like to play again?')
if answer == 'y':
minesweeper()
else:
print 'Thanks for playing!'
break
else:
clearSpace(mines)
print '\n'
elif response.lower() == 'f':
flagSpace()
print '\n'
#randomly generates the mines and checks for duplicates
def generateMines():
global numMines
global mines
i = 0
mines = []
while i < numMines:
mines.append([randint(1,4),randint(1,9)])
i += 1
if checkDuplicateMines(mines):
generateMines()
#gets coordinates from the user
def getCoord():
global row
global col
global coord
global gameMap
row = 0
col = 0
coord = []
try:
row = raw_input('Enter an Row: ')
row = int(row)
col = raw_input('Enter a Column: ')
col = int(col)
except ValueError:
print 'Invalid Coordinates \n'
getCoord()
coord.append(row)
coord.append(col)
def isMine(mines):
global coord
global gameMap
for x in mines:
if coord == x:
showSolution(mines, gameMap)
return True
#asks user if they want to clear or flag a space
def clearOrFlag():
global response
response = raw_input("Clear (c), Flag/Unflag (f)")
#clears a space. if it's a mine, the player loses. If not it will write the
#number of surrounding mines to the space. Might break this up later.
def clearSpace(mines):
#checks to see if selected square is a ? (playable).
global gameMap
global row
global col
global coord
if gameMap[row][col] == '?' or gameMap[row][col] == 'F':
gameMap[row][col] = str(countMines(mines))
#flags a space, or unflags it if already flagged.
def flagSpace():
global gameMap
global row
global col
try:
if gameMap[row][col] == '?' :
gameMap[row][col] = 'F'
elif gameMap[row][col] == 'F':
gameMap[row][col] = '?'
except Exception, OutOfBounds:
print 'Invalid Coordinates \n'
#Prints the world
def printWorld(gameMap):
#just prints spaces to keep things tidy
print '\n' * 100
for row in gameMap:
print ' '.join(row)
print '\n'
print '\n'
#initializes the world so it can be printed
def initWorld():
global gameMap
# convert the gamemap into a list of lists
gameMap = gameMap.split('\n')
del gameMap[0]
for index in range(0, len(gameMap)):
gameMap[index] = list(gameMap[index])
#prints the gameBoard with all of the mines visible
def showSolution(mines, gameMap):
for x in mines:
gameMap[x[0]][x[1]] = 'M'
printWorld(gameMap)
print 'You Lose'
#counts the number of surrounding mines in a space
def countMines(mines):
global row
global col
count = 0
#theres probably a much better way to do this
for x in mines:
if [row+1,col] == x:
count += 1
if [row-1,col] == x:
count += 1
if [row,col+1] == x:
count += 1
if [row,col-1] == x:
count += 1
if [row+1,col+1] == x:
count += 1
if [row+1,col-1] == x:
count += 1
if [row-1,col+1] == x:
count += 1
if [row-1,col-1] == x:
count += 1
return count
#counts the number of flags on the board
def countFlags(mines):
global gameMap
numFlags = 0
for i in range (0, len(gameMap)):
for j in range (1, len(gameMap[0])-1):
if gameMap[i][j]=='F':
numFlags += 1
if numFlags == len(mines):
return True
else:
return False
#counts the number of mines flagged
def minesFlagged(mines):
global gameMap
count = 0
for x in mines:
if gameMap[x[0]][x[1]] == 'F':
count += 1
if count == numMines:
return True
else:
return False
#checks to see if there were duplicate mines generated
def checkDuplicateMines(mines):
mines.sort()
for x in range(0, len(mines)-1):
if mines[x] == mines[x+1]:
return True
x += 1
return False
#checks to see if player won the game
def winGame(mines):
if countFlags(mines):
if minesFlagged(mines):
return True
else:
return False
minesweeper()
Upvotes: 2
Views: 1399
Reputation:
If you want to use a recursion, return the function call, don't just call it.
if winGame(mines):
printWorld(gameMap)
print 'You Win!'
answer = raw_input('Would you like to play again?')
if answer == 'y':
return minesweeper()
else:
print 'Thanks for playing!'
return
This way, when one of your recursive functions ends, it returns None
to the previous one, which again returns None
to the previous one, etc. etc. until the last one calls return
which ends the whole recursion loop.
It might not be the best solution for this problem (take a look at MathieuW's answer, basically does the same) but it works for any situation, and is mostly used on recursive functions.
Upvotes: 1
Reputation: 2372
It does break the loop if you don't reply 'y'.
But if you have played N games, it will only break the loop of the Nth game, and you will go back in the loop of the (N-1)th function call.
For an actual solution, I agree with AshRj comment you already have implemented.
Here is another solution still using your previous design (but less correct), just moving the break.
if winGame(mines):
printWorld(gameMap)
print 'You Win!'
answer = raw_input('Would you like to play again?')
if answer == 'y':
minesweeper()
else:
print 'Thanks for playing!'
break
Upvotes: 0