Search code examples
pythonvariablessubroutine

local variable assigned in enclosing line referenced before assignment


I have this bit of code

health = 12

manager_health = 10 

def manager_boss_fight_used_for_backup():

    sleep(1)
    print("manager health is ",manager_health)
    print("your health is ",health)
    
    sleep(1)

    print("the boss gets first attack")
    manager_boss_damage = random.randint(1,8)
    print(manager_boss_damage)
    print(health)
    health = health - manager_boss_damage
    sleep(1)
    print("the boss did",manager_boss_damage,"damage")
    sleep(1)
    print("your health is now",health)

    if health <= 0:
        sleep(1)
        print("you have died")
        sleep(1)
        print("better luck next time")
        exit()
    sleep(1)
    print("your turn to attack")
    sleep(1)
    heal_or_attack = input("Do you wish to heal or attack?(1/2)")
    if heal_or_attack == "1":
        healing = random.randint(1,7)
        print("you have healed by",healing)
        health = health + healing
        manager_boss_fight_used_for_backup()
    if heal_or_attack == "2":
        print("you attack the boss")
        sleep(1)
        attack_damage = random.randint(1,6)
        print("You did",attack_damage,"damage")
        manager_health = manager_health - attack_damage
        if manager_health <= 0:
            sleep(1)
            print("You have killed the boss")
            sleep(1)

        if manager_health > 0:
            manager_boss_fight_used_for_backup()

and in the parts of code where for example health = health - manager_boss_damage it will error out. I have fiddled with global variables and all that but I cant get it to work so I came here. Any answers appreciated!


Solution

  • As probably everyone will tell you, using global variables is pretty bad. Why don't you use OOP instead? You can create a class Manager: and a class Player: with health as property and damage and take_damage as a method of the class, for example:

    class Manager:
    def __init__(self):
        self.health = 10
        
    def attack(self):
        damage = ramdom.randint(1,8)
        return damage
    def take_damage(self, damage):
        self.health -= damage
        if (self.health <= 0):
            self.health = 0
        return self.health
    

    then the Player class would be more or less the same:

    class Player:
    def __init__(self):
        self.health = 12
        
    def attack(self):
        damage = ramdom.randint(1,8)
        return damage
    def take_damage(self, damage):
        self.health -= damage
        if (self.health <= 0):
            self.health = 0
        return self.health
    def heal(self, amount):
        self.health += amount
        return self.health
    

    Ideally of course, you can create one class called "Actor" or "Enemy" and derive those from there, but let's stick with this for now:

    # Instantiate the classes like this:
    manager = Manager()
    player = Player()
    # and then just invoke the methods from the classes:
    sleep(1)
    print("manager health is ",manager.health)
    print("your health is ",player.health)
    
    sleep(1)
    
    print("the boss gets first attack")
    damage = manager.Attack()
    print("You were hit by {} points".format(damage))
    player.take_damage(damage)
    print("Your Health is {}".format(player.health))
    

    Etc.