python cannot use break

Asked

Viewed 448 times

1

This is a little game that simulates a race. However, when a player reaches level 3 I want him to stop loop and reset all data, but I can’t use the break so that when the level of one of the players is 3, stop the game and end.

import random
class Jogador:
    def __init__(self, nome):
        self.nome = nome
        self.nivel=0
        self.passos= 0
        self.passos_parcial=0

    def mostra_tudo(self):
        print 'nivel',self.nivel
        print 'passos', self.passos
        print 'bonus', self.bonus

    def andar(self):
            self.passos_parcial = random.randint(1,60)
            self.passos+=self.passos_parcial
            self.checknivel()
            self.victory()
            print self.nome, "Andou mais", self.passos_parcial, "e está a", (120 - self.passos), "do próximo nível"

    def checknivel(self):
        if self.passos>=120:
              self.nivel+=1
              self.passos= self.passos-120
              print self.nome, 'está no nível', self.nivel

    def victory(self):
            if self.nivel == 3:
                print self.nome, 'ganhou'
                self.nivel=0
                self.passos= 0
                self.passos_parcial=0
                break



a=Jogador('Jogador 1')
b=Jogador('Jogador 2')
while True:
    a.andar()
    b.andar()
  • When you call the method andar, the player will walk an amount less than 60 steps and after is called the method victory, which has an infinite loop: the while will be running forever as the player has not walked 60 steps and continues to level 0. What is the function of this while?

  • Actually I tried to put this 'while' because there is no way to break the 'if' loop. But the real question is this... do when the 'self.nivel == 3' stop the loop. I tried to do this in the 'Victory'

  • 1

    That’s the point: you don’t need the tie, so you don’t need the break. Try to leave only the if. In advance, the method names are a bit strange. It is not a good practice to mix names in Portuguese and English.

  • But when I call the class downstairs, it will happen that the only one will call downstairs. Being that it is to call until the level is equal to 3. Ai then it is to zero the dice pq finished the game.

  • who downvoted this question? is perfectly responsive and good.

1 answer

2

The break has limited utility for cases like these: it comes out of a single loop in the same function.

You are creating the game with a good separation of what does what, but apparently the desperation to do break work messed up your code.

Every game will have an excerpt that is what we call the main loop - "mainloop": the excerpt that has to be repeated each frame, or with each interaction with the player, for the game to work. In this code it is easy to notice that the part that does this is in its function andar, updating positions, calling update and verification functions, and printing the current status of the game. For this code to make sense, it is the walking function that is the main loop, which needs to be executed every interaction of the game.

Updating - I only realized after I wrote that you will actually have several "players". In case, you will get a "main loop" at another point of the program, which calls the function andar in every interaction: that’s where the block should be try...except which I describe at the end. If you choose the variable, it has to be a global variable, not an attribute then.

So the while True which ended up in function victory should be covering the whole block that is on andar. And yes, hence, we need a mechanism for that function victory can break that bond, and that is your doubt.

There are two ways: you can keep a variable with the overall state of the game (in this case, simply an attribute of the Player class): while in andar checks this variable, and the function victory updates the same:

...
def __init__(...):
    ...
    self.vitoria_aconteceu = False
    ...
    self.andar()
...
    def andar(self):
        while not self.vitoria_aconteceu:
            self.passos_parcial = random.randint(1,60)
            self.passos+=self.passos_parcial
            self.checknivel()
            self.victory()
            print self.nome, "Andou mais", self.passos_parcial, "e está a", (120 - self.passos), "do próximo nível"

...
    def victory(self):
        if self.nivel == 3:
            ...
            vitoria_aconteceu = True

Now, imagine that this is a complex game, with several instances of Jogador, and several tests to stop the game: a player may die, or find the treasure, or even reach a point where there is a phase shift to another map.

The functions could have more levels - in another type of game, the death of a player can happen in the position update of a class object Tiro, in his method atualizar (and this method would not have access to the attribute in the main class of the game).

So a common way to treat the problem is to create custom exceptions, and put the main loop block inside a try...except.

Creating a custom exception may sound complicated, but it’s the simplest thing in the world: it’s empty classes that inherit from Exception.

You can even create an exception for each type of event that would result in an exit from loop main, and there, a block of except appropriate to each:

class GameException(Exception): pass

class VicrotyException(GameException): pass

class LostException(GameException): pass

...

    def andar(self):
        try:
            while True:
                self.passos_parcial = random.randint(1,60)
                self.passos+=self.passos_parcial
                self.checknivel()
                self.victory()
                print self.nome, "Andou mais", self.passos_parcial, "e está a", (120 - self.passos), "do próximo nível"
         except VictoryException:
                print(self.nome, "ganhou")
                ...
...
    def victory(self):
        if self.nivel == 3:
            # Levanta uma excelççao de vitória,
            # que dsvia o código para o except correspondente:
            raise VitctoryException

The exceptions are by no means something bad, as it may seem - for more information see my reply on exceptions:

Why make use of Python exceptions using raise?

Two more general tips for your code:

  • Why are you sweating Python 2? It’s a language from last millennium, with less and less support - try to use Python 3.6

  • Try to maintain a consistency of nomenclature: you are using variables and methods with names in Portuguese and English half at random. Ideally use in English: you never know when your project will be cool, and you’ll want to put it on github and have international contributors.

  • I found it a bit like overpower use exception in this specific case. Particularly I would do in the main game loop the check of the match status (win/draw/defeat/the show must go on). But it feels like me, I’m used to try to follow a flow more similar to what Unity does

  • 1

    You may find "overpower", but in many cases it is less complex, and it is a quite used Pattern. It is not something like a "hack" - it is used for flow control in same programming.

  • I know, the end of the iteration of for is indicated by the release of an exception. But I think due to my (little) custom I think overpower. Feeling like shooting flies with bazookas.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.