Skip to main content
edited body
Source Link
from collections import OrderedDict
move_choices = OrderedDict({(('1':, 'punch'), ('2':, 'kick'), ('3':, 'heal'})))

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())
 
    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(Marco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)

In addition to what was mentioned above, I also made a lot of small style changes for readability. Let me know if you have any questions or curiosities. At the end, my updated version of your code looks like:

def hp_check(function):
    def decorator(self, *args, **kwargs):
        if self.hp > 0:
            function(self, *args, **kwargs)
        else:
            print(self.name, "is dead and cannot perform actions")
    return decorator

class Fighter:
    def __init__(self, name, hp=100, attack=75, defense=50, speed=60):
        self.name = name
        self.hp = hp
        self.attack = attack
        self.defense = defense
        self.speed = speed

    @hp_check
    def punch(self, target, modifier=1.00):
        base = 50/100.0
        damage = (self.attack - target.defense) * base
        target.hp = target.hp - damage
        print(self.name, "punched", target.name, "for %d HP" % damage)
    punch.priority = 1

    @hp_check
    def heal(self, target, modifier=1.00):
        self.hp += 15
        if self.hp > 100:
            self.hp = 100
        print(self.name, "healed 15 HP")
    heal.priority = 2

    @hp_check
    def kick(self, target, modifier=1.00):
        base = 100/100.0
        damage = (self.attack - target.defense) * base
        target.hp = target.hp - damage
        self.hp = self.hp - 10
        print(self.name, "kicked", target.name, "for %d HP" % damage)
    kick.priority = 2


def play(Player1,Player2):
    # First - Check Options Priority
    if Player1.next_move is None and Player2.next_move is None:
        pass

    elif Player1.next_move is None:
        Player2.next_move(Player1)

    elif Player2.next_move is None:
        Player1.next_move(Player2)

    elif Player1.next_move.priority > Player2.next_move.priority:
        Player1.next_move(Player2)
        Player2.next_move(Player1)

    elif Player1.next_move.priority < Player2.next_move.priority:
        Player2.next_move(Player1)
        Player1.next_move(Player2)

    # Second - Check Player's Speed
    elif Player1.speed > Player2.speed:
        Player1.next_move(Player2)
        Player2.next_move(Player1)

    elif Player1.speed < Player2.speed:
        Player2.next_move(Player1)
        Player1.next_move(Player2)

    # Third - Randomly Choose
    else:
        if random.choice(range(2)) == 0:
            Player1.next_move(Player2)
            Player2.next_move(Player1)
        else: 
            Player2.next_move(Player1)
            Player1.next_move(Player2)


Player = Fighter("you")
Marco = Fighter("Marco")

from collections import OrderedDict
move_choices = OrderedDict((('1', 'punch'), ('2', 'kick'), ('3', 'heal')))

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())
    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(Marco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)
from collections import OrderedDict
move_choices = OrderedDict({'1': 'punch', '2': 'kick', '3': 'heal'})

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())
 
    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(Marco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)

In addition to what was mentioned above, I also made a lot of small style changes for readability. Let me know if you have any questions or curiosities.

from collections import OrderedDict
move_choices = OrderedDict((('1', 'punch'), ('2', 'kick'), ('3', 'heal')))

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())
    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(Marco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)

In addition to what was mentioned above, I also made a lot of small style changes for readability. Let me know if you have any questions or curiosities. At the end, my updated version of your code looks like:

def hp_check(function):
    def decorator(self, *args, **kwargs):
        if self.hp > 0:
            function(self, *args, **kwargs)
        else:
            print(self.name, "is dead and cannot perform actions")
    return decorator

class Fighter:
    def __init__(self, name, hp=100, attack=75, defense=50, speed=60):
        self.name = name
        self.hp = hp
        self.attack = attack
        self.defense = defense
        self.speed = speed

    @hp_check
    def punch(self, target, modifier=1.00):
        base = 50/100.0
        damage = (self.attack - target.defense) * base
        target.hp = target.hp - damage
        print(self.name, "punched", target.name, "for %d HP" % damage)
    punch.priority = 1

    @hp_check
    def heal(self, target, modifier=1.00):
        self.hp += 15
        if self.hp > 100:
            self.hp = 100
        print(self.name, "healed 15 HP")
    heal.priority = 2

    @hp_check
    def kick(self, target, modifier=1.00):
        base = 100/100.0
        damage = (self.attack - target.defense) * base
        target.hp = target.hp - damage
        self.hp = self.hp - 10
        print(self.name, "kicked", target.name, "for %d HP" % damage)
    kick.priority = 2


def play(Player1,Player2):
    # First - Check Options Priority
    if Player1.next_move is None and Player2.next_move is None:
        pass

    elif Player1.next_move is None:
        Player2.next_move(Player1)

    elif Player2.next_move is None:
        Player1.next_move(Player2)

    elif Player1.next_move.priority > Player2.next_move.priority:
        Player1.next_move(Player2)
        Player2.next_move(Player1)

    elif Player1.next_move.priority < Player2.next_move.priority:
        Player2.next_move(Player1)
        Player1.next_move(Player2)

    # Second - Check Player's Speed
    elif Player1.speed > Player2.speed:
        Player1.next_move(Player2)
        Player2.next_move(Player1)

    elif Player1.speed < Player2.speed:
        Player2.next_move(Player1)
        Player1.next_move(Player2)

    # Third - Randomly Choose
    else:
        if random.choice(range(2)) == 0:
            Player1.next_move(Player2)
            Player2.next_move(Player1)
        else: 
            Player2.next_move(Player1)
            Player1.next_move(Player2)


Player = Fighter("you")
Marco = Fighter("Marco")

from collections import OrderedDict
move_choices = OrderedDict((('1', 'punch'), ('2', 'kick'), ('3', 'heal')))

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())
    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(Marco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)
edited body
Source Link
from collections import OrderedDict
move_choices = OrderedDict({'1': 'punch', '2': 'kick', '3': 'heal'})

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())

    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(MArcoMarco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)
from collections import OrderedDict
move_choices = OrderedDict({'1': 'punch', '2': 'kick', '3': 'heal'})

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())

    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(MArco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)
from collections import OrderedDict
move_choices = OrderedDict({'1': 'punch', '2': 'kick', '3': 'heal'})

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())

    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(Marco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)
Source Link

So, I'm no Pythonista, but it's not often that you see nested classes. That's not to say there aren't uses that I don't know of. To change your class into what I would think is a more Pythonic layout, I might do something like:

class Fighter:
    def __init__(self, name, hp=100, attack=75, defense=50, speed=60):
        self.name = name
        self.hp = hp
        self.attack = attack
        self.defense = defense
        self.speed = speed

    def punch(self, target, modifier=1.00):
        base = 50/100.0
        damage = (self.attack - target.defense) * base
        target.hp = target.hp - damage
        print(self.name, "punched", target.name, "for %d HP" % damage)
    punch.priority = 1

    def heal(self, target, modifier=1.00):
        self.hp += 15
        if self.hp > 100:
            self.hp = 100
        print(self.name, "healed 15 HP")
    heal.priority = 2

    def kick(self, target, modifier=1.00):
        base = 100/100.0
        damage = (self.attack - target.defense) * base
        target.hp = target.hp - damage
        self.hp = self.hp - 10
        print(self.name, "kicked", target.name, "for %d HP" % damage)
    kick.priority = 2

Note that this uses the fact that, in Python, a function can have member data. The line punch.priority = 1 works perfectly fine. I also expanded your variable names like atk into attack as it's more readable and you won't have to remember "how did I abbreviate that" later on. Also, I added a "name" attribute. Finally, I changed the use of print to use comma-separated arguments. The default delimiter is a space, so this will work in the same way and reads better.

Next, we need to update the following few lines based on the previous changes. This is now more concise.

# Declare Marco & Player                
Player = Fighter("you")
Marco = Fighter("Marco")

Now, for you function play, we're going to need to make some structural changes. Manually binding the Turn class attribute, when it hasn't been defined, makes the book-keeping here more complicated than it needs to be. Maybe, we could add a class attribute like next_move to keep track of this.

class Fighter:
    def __init__(...):
        # ...
        self.next_move = None

Then, to also help things out, let's embed the hp check into the move definition. We can do this to all of the moves with minimal code using a construct called a decorator. Let's add a function called hp_check, which takes a function and returns a function, outside of our class. Then, let's update our class methods using @hp_check right before the def line.

def hp_check(function):
    def decorator(self, *args, **kwargs):
        if self.hp > 0:
            function(self, *args, **kwargs)
        else:
            print(self.name, "is dead and cannot perform actions")
    return decorator

class Fighter:
    def __init__(...):
        # method body

    @hp_check
    def punch(...):
        # method body

    @hp_check
    def heal(...):
        # method body

    @hp_check
    def kick(...):
        # method body

With this work done, we can make the play function easier to read.

def play(Player1,Player2):
    # First - Check Options Priority
    if Player1.next_move is None and Player2.next_move is None:
        pass

    elif Player1.next_move is None:
        Player2.next_move(Player1)

    elif Player2.next_move is None:
        Player1.next_move(Player2)

    elif Player1.next_move.priority > Player2.next_move.priority:
        Player1.next_move(Player2)
        Player2.next_move(Player1)

    elif Player1.next_move.priority < Player2.next_move.priority:
        Player2.next_move(Player1)
        Player1.next_move(Player2)

    # Second - Check Player's Speed
    elif Player1.speed > Player2.speed:
        Player1.next_move(Player2)
        Player2.next_move(Player1)

    elif Player1.speed < Player2.speed:
        Player2.next_move(Player1)
        Player1.next_move(Player2)

    # Third - Randomly Choose
    else:
        if random.choice(range(2)) == 0:
            Player1.next_move(Player2)
            Player2.next_move(Player1)
        else: 
            Player2.next_move(Player1)
            Player1.next_move(Player2)

Finally, we can do make the main fight sequence more concise by using an OrderedDict.

from collections import OrderedDict
move_choices = OrderedDict({'1': 'punch', '2': 'kick', '3': 'heal'})

while Player.hp > 0 and Marco.hp > 0:
    player_choice = 'place holder'
    while player_choice not in move_choices:
        player_choice = input('')
    player_method = getattr(Player, player_choice)       
    setattr(Player, 'next_move', player_method)

    if Marco.hp < random.choice(range(80,100)):
        marco_choice = random.choice(move_choices.values())

    else:
        marco_choice = random.choice(move_choices.values()[:-1])

    marco_method = getattr(MArco, marco_choice)
    setattr(Marco, 'next_move', marco_method)

    play(Player, Marco)

Now, this last snippet ramps things up a bit. Instead of referencing __dict__, which I would try to avoid, it uses the built-in functions getattr and setattr which can be used to get and set object attributes. It also uses an OrderDict in order to simplify the input process. I can comment further on anything you want, but hopefully you're at the point where you can go through line by line and figure out what's going on. It's usually helpful to open up an interpreter to test things out. I removed the comments and input lines for brevity, but the functionality should be the same.

In addition to what was mentioned above, I also made a lot of small style changes for readability. Let me know if you have any questions or curiosities.