Проблема рекурсивной игры в питоне

Я создаю версию Minesweeper в Python и столкнулся с небольшой проблемой. В этом куске кода:

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

Он снова вызывает функцию тральщика, которая снова начинает игру. Этот код находится внутри некоторого цикла True: вместе с остальным игровым кодом. Единственная проблема состоит в том, что если игра запускается снова, а затем выигрывает и говорит, что вы не хотите играть снова, это не нарушает цикл. Я думаю, что это как-то связано с тем, что я использую рекурсию для повторного вызова функции. Пока единственное, что работает, - это использование sys.exit(), но я бы предпочел иметь более законное решение, если это имеет смысл.

Вот полный код:

#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()

2 ответа

Решение

Если вы хотите использовать рекурсию, верните вызов функции, а не просто вызывайте ее.

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

Таким образом, когда одна из ваших рекурсивных функций заканчивается, она возвращает None на предыдущий, который снова возвращает None к предыдущему и т. д. и т. д., пока не прозвенит последний return который завершает весь цикл рекурсии.

Возможно, это не лучшее решение для этой проблемы (посмотрите на ответ MathieuW, в основном то же самое), но оно работает для любой ситуации и в основном используется в рекурсивных функциях.

Это нарушает цикл, если вы не отвечаете "у".

Но если вы играли в N игр, это только разорвет цикл N-й игры, и вы вернетесь в цикл вызова (N-1) -й функции.

Что касается фактического решения, я согласен с комментарием AshRj, который вы уже реализовали.

Вот еще одно решение, все еще использующее ваш предыдущий дизайн (но менее правильное), просто перемещающее разрыв.

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
Другие вопросы по тегам