2012-12-06 5 views
2

Je crée une version de Minesweeper en python et j'ai rencontré un petit problème. Dans ce morceau de code:Problème de jeu récursif en 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 

Il appelle la fonction de démineur à nouveau, qui commence le jeu encore. Ce code est à l'intérieur d'un certain temps True: boucle avec le reste du code du jeu. Le seul problème est que si le jeu est recommencé et ensuite gagner et dire que vous ne voulez pas rejouer, il ne casse pas la boucle. Je pense que cela a quelque chose à voir avec le fait que j'utilise la récursivité pour rappeler la fonction. Pour l'instant, la seule chose qui fonctionne est d'utiliser sys.exit(), mais je préférerais avoir une solution plus légitime si cela a du sens.

Voici l'intégralité du 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() 
+5

Un appel récursif n'est probablement pas le meilleur moyen d'y parvenir. Vous devriez gérer exit/start/restart depuis une autre fonction. – asheeshr

+0

Merci pour le conseil. Modification de l'état de la boucle while et déplacement de la lecture vers une autre fonction pour que tout fonctionne. – TaylorV

Répondre

0

Si vous souhaitez utiliser une récursivité, renvoyez l'appel de fonction, ne l'appelez pas simplement.

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 

De cette façon, lorsque l'un de vos fonctions récursives se termine, il retourne None au précédent, ce qui revient à nouveau None à la précédente, etc., etc. jusqu'à ce que le dernier appelle return qui se termine toute récursivité boucle.

Ce n'est peut-être pas la meilleure solution pour ce problème (jetez un oeil à la réponse de MathieuW, fait la même chose), mais cela fonctionne pour toutes les situations et est principalement utilisé pour les fonctions récursives.

+0

Merci les gars pour l'aide! – TaylorV

0

Il ne casse la boucle si vous ne répondez pas « y ». Mais si vous avez joué à N jeux, cela ne fera que casser la boucle du Nième jeu, et vous retournerez dans la boucle de l'appel de la fonction (N-1).

Pour une solution réelle, je suis d'accord avec le commentaire AshRj que vous avez déjà implémenté.

Voici une autre solution utilisant encore votre conception précédente (mais moins correcte), juste en déplaçant la coupure.

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 
+0

Merci les gars pour l'aide! – TaylorV