Вопрос

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()
Это было полезно?

Решение

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.

Другие советы

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top