0
votes

I am making a small text game, and one of my methods is behaving unexpectedly, and I can't figure out why. If I import the module and run the method in python, it works fine. Some parts of the game aren't complete, but that parts that I need run fine.

With the module pasted below, choose method is changing a list into a string, but only when the module is run. I'm running this on 2.7.3, on a mac.

Edit: I figured it out. The program execution had continued, and I was confused by the choose call in the match method. The options parameter sent in match was a string, instead of the list it should have been, but that was simple to figure out why.

import fighters
import weapons
from random import randint
from sys import exit

class Hero(object):
    weapons = ["spikeglove", "shortsword"]
    hp = {"actual":50, "base":50}
    score = 0

    def attack(self, weapon, method):
        return None

class Scene(object):

    # Returns one or more items from the provided choices    
    def choose(self, options, max_choices, prompt):
        chosen = []
        while len(chosen) < max_choices and len(options) > 0:
            print
            print prompt
            print options, chosen
            for o in options:
                print "- {}".format(o)    
            print type(options)
            choice = raw_input("> ")
            if choice in options:
                chosen.append(choice)
                options.remove(choice)
                print options, chosen
            else:
                print "That is not one of the options!"
        if len(chosen) == 1:
            return chosen[0]
        else:
            return chosen  


class Death(Scene):
    def enter(self):
        print "You are now dead"
        return "menu"

class Exit(Scene):
    def enter(self):
        print "Thanks for playing!"
        return exit(1)

class Menu(Scene):

    def enter(self):
        menu_options = ["play", "train", "exit"]
        choice = self.choose(menu_options, 1, "Welcome to the Arena!")
        return choice

class Level(Scene):

    def __init__(self):
        self.prologue = "Welcome to {}".format(self.__class__.__name__)

    next_scene = "level1"

    # A match is the fight between the Hero and a particular Enemy
    # A Hero must defeat each Enemy via a match to win the tournament/level
    def match(self, hp, weapons, enemy):
        hero_hp = hp
        enemy_hp = enemy.stats["hp"]
        last_attack = ""
        while hero_hp and enemy_hp:
            weapon_choice = self.choose(weapons, 1, "> ")
            attack_choice = self.choose(weapon_choice.available_attacks(last_attack), 1, "> ")
            last_attack = attack_choice
            hero_attack = hero.attack(attack_choice)
            enemy_attack = enemy.attack()
            print "Hero: {}          {}: {}".format(hero_hp, enemy, enemy_hp)
        if hero_hp:
            return "victory", hero_hp
        else:
            return "defeat"

    # The game cycles through the enemies that our hero has to face
    # passing the setup to the "match" function for the fighting   
    def enter(self):
        print
        print
        print self.prologue
        start_hp = hero.hp['actual']
        weapons = self.choose(hero.weapons, 2, "Choose a weapon")
        while self.enemies:
            enemy = fighters.roster[self.enemies.pop()]
            match_outcome, finish_hp = self.match(start_hp, weapons, enemy)            
            if match_outcome == "defeat":
                hero.hp['actual'] = hero.hp['base']
                return "death"
            # The Hero enters the next match with the current HP obtained from the previous match
            start_hp = finish_hp

        # Add our Hero's victory points, and get them some medical attention 
        # before heading back to the Barracks
        points_award = 5
        hero.points += points_award
        hero.hp['actual'] = hero.hp['base']
        new_weapon = "shortsword"
        hero.add_weapon(new_weapon)
        epilogue = """Congratulations! 
                    You have gained {} points for a total score of {}.\n
                     You have unlocked the \"{}\" """.format(
                            points_award, hero.points, new_weapon)
        return next_scene

class Train(Scene):
    pass

class Level1(Level):

    enemies = ["boxer", "boxer"]
    next_scene = "level2"

class Level2(Level):
    pass

class Level3(Level):
    pass

class Level4(Level):
    pass

class Level5(Level):
    pass

class Engine(object):
    def __init__(self, start_scene):
        self.start_scene = start_scene

    scenes = {
        "menu": Menu(),
        "death": Death(),
        "exit": Exit(),
        "play": Level1(),
        "level2": Level2(),
        "level3": Level3(),
        "level4": Level4(),
        "level5": Level5(),       
    }

    def next_scene(self, scene_name):
        return self.scenes[scene_name]

    def play(self):
        current_scene = self.scenes[self.start_scene]
        while True:
            next_scene = current_scene.enter()
            current_scene = self.scenes[next_scene]

if __name__ == "__main__":
    hero = Hero()        
    game = Engine("menu")
    game.play()        

Terminal output:

$ python arena.py
Welcome to the Arena!
['play', 'train', 'exit'] []
- play
- train
- exit
<type 'list'>
> play
['train', 'exit'] ['play']


Welcome to Level1

Choose a weapon
['spikeglove'] []
- spikeglove
<type 'list'>
> spikeglove
[] ['spikeglove']

> 
spikeglove []
- s
- p
- i
- k
- e
- g
- l
- o
- v
- e
<type 'str'>

Yet when I run in python:

>>> import arena
>>> s = arena.Level1()
>>> s.choose(['shortsword', 'spikeglove'], 2, "Choose a weapon")

Choose a weapon
['shortsword', 'spikeglove'] []
- shortsword
- spikeglove
<type 'list'>
> shortsword
['spikeglove'] ['shortsword']

Choose a weapon
['spikeglove'] ['shortsword']
- spikeglove
<type 'list'>
> spikeglove
[] ['shortsword', 'spikeglove']
['shortsword', 'spikeglove']
1
It's not related to your question, but you almost certainly don't want to define weapons, hp and score for Hero at class level: that means they'll be shared by all instances of Hero.Daniel Roseman
Thanks Daniel, I see what you mean. The thing is, there will only ever be one instance of Hero when the game is played, so in the end I might not need to have Hero created as a class. It might be less complicated/more appropriate to set the "Hero" attributes to regular variables in the module: hero_hp, hero_weapons, etc.burmer

1 Answers

2
votes

The if __name__ == "__main__": means that the portion of code indented after that if-statement will be executed only when the script is executed, not when it is imported.