Object-Oriented Programming in Python
Dungeon crawling text game using object-oriented python.

Object-Oriented Programming in Python

Python is a versatile and powerful programming language known for its simplicity and readability. One of the key features that make it suitable for a wide range of applications is its support for object-oriented programming. Whether you're a Python novice or have a little more experience, object-oriented programming can help you mature your coding skills.

Object-oriented programming?is a programming method that organizes code around objects rather than functions. The quintessential illustration of object-oriented programming uses a car as a metaphor. A car can be thought of as an object. The car has various attributes associated with it such as color, model, engine, and year. Every single car is going to inherit these same types of attributes due to the nature of all cars having color, model, engine, and year. This is the essence of a programming object.

To provide a real example with code, take a look at the code below. This code defines a class called "Actor". Within the class definition, we see various attributes such as "get_attack_power", and "is_alive", and we see name, level, and hp. Seemingly, these are the attributes of some video game character!

from random import randint


class Actor:
    def __init__(self, name, level):
        self.name = name
        self.level = level
        self.hp = 100 + 3 * level
        self.full_hp = self.hp

    def get_attack_power(self):
        return randint(1, 50) + 5*self.level

    def get_defense(self):
        return randint(1, 25) + self.level*self.level

    def __repr__(self):
        return 'Actor: {}, Level:{}'.format(self.name, self.level)

    def is_alive(self):
        return self.hp > 0

    def attacks(self, other):
        raise NotImplementedError()

    def stats(self):
        print('    {} has {} health.'.format(self.name, self.hp))        

This code illustrates perfectly how a class is given certain attributes and functions that act on these attributes. The benefits of object-oriented programming, however, are not limited to just the organization of ideas. Classes allow for something called?inheritance.

Examine the code below.

class Player(Actor):
    def heal(self):
        self.hp += round((self.full_hp - self.hp) / 3)

    def attacks(self, enemy):
        power = self.get_attack_power()
        enemy_defense = enemy.get_defense()
        damage = power - enemy_defense

        if power > enemy_defense:
            print('{} hit the {} for {} damage!'.format(self.name, enemy.kind, damage))
            enemy.hp -= damage
            if enemy.hp <= 0:
                print('{} slayed the {}!'.format(self.name, enemy.kind))
            return True
        else:
            print('The {} appears unaffected by your attack...'.format(enemy.kind))
            return False        

We have defined another object, this one called "Player". We see similar organization to the "Actor" class before, but careful observation reveals the "Player" class is using variables not explicitly defined within the object! How is it possible that the "Player" class can use attributes like hp when we haven't defined hp for the Player? This is because "Player" is defined as a child class of "Actor". As such, the "Player" inherits all of the attributes and functions defined in the "Actor" class before! Hp, name, and get_attack_power functions are all attributes that all "Player" objects inherit.

To return to our car metaphor, the minivan is a type of car. All minivans share certain characteristics that are not necessarily shared by all cars. For example, minivans are driven by soccer moms while not all cars are driven by soccer moms. However, the minivan inherits all the characteristics of a car. The minivan inherits color, and model, and then defines further attributes unique to just the minivan child class.

Inheritance is a powerful tool that allows for more reusability of code, less code duplication, faster development, consistency, and more efficient code. Together with inheritance, three other principles of object-oriented programming make it such a useful programming style. These other attributes are abstraction, encapsulation, and polymorphism.

Abstraction?provides an interface with the class that allows a programmer to access it without needing to access the inner works of attributes within the class. In the "Actor" code above, functions like "get_attack_power" provide access to the Actor's attack power, but the user does not need to know how the attack power is calculated. The essence of abstraction is like how you do not know how your car engine works but can still turn it on.

Encapsulation?is the idea of wrapping data and the methods that work on data within one object. As you can see in the code above, a class is an example of encapsulation as it encapsulates functions, variables, etc. The goal of information hiding is to ensure that an object’s state is always valid by controlling access to attributes that are hidden from the outside world.

The "Player" class cannot affect the attributes of a separate "Enemy" class. They are hidden from other classes and prevent unwanted changes and wacky behavior in your code.

Lastly,?polymorphism?allows the same function name to have numerous different applications. Take for example the "Enemy" class defined below.

class Enemy(Actor):
    def __init__(self, name, level, kind):
        super().__init__(name, level)
        self.kind = kind

    def attacks(self, player):
        print('The {} attacks!'.format(self.kind))
        e_power = self.get_attack_power()
        player_defense = player.get_defense()
        damage = e_power - player_defense
        if damage < 0:
            damage = 0
            print('The {}\'s attack had no effect.'.format(self.kind, damage))
        else:
            print('The {} attacks the player for {} damage!'.format(self.kind, damage))
            player.hp -= damage        

In this "Enemy" class, we see similar attributes as were defined in the "Player" class. For example, both classes contain an "attacks" function. However, notice that the code for the "attacks" functions are very different. This is because each is defined locally within its class and the name can be reused in a different manner for adjacent classes. Using polymorphism, classes can edit attributes inherited by parent classes without editing the parent class itself.

Object-oriented programming constructs useful building blocks that allow for greater usability and transparency in code. It is a staple of programming and is used in areas from software development to modeling and statistics. Below, I have included the complete code for a game called "Monster Slash" inspired by ITPro.TV's Python tutorials. Check out their videos for more in-depth discussion on how to implement object-oriented programming in Python.

This code is a dungeon crawler game complete with level progression, unique path generation, monster difficulty scaling, and more. One could adjust the classes to add an inventory system and items, add more types of enemies, etc. There is a game.py file and an actors.py file each with separate information for the game. Run this code in Python to enjoy a short game experience that illustrates the usefulness of object-oriented programming.

###actors.py###
from random import randint


class Actor:
    def __init__(self, name, level):
        self.name = name
        self.level = level
        self.hp = 100 + 3 * level
        self.full_hp = self.hp

    def get_attack_power(self):
        return randint(1, 50) + 5*self.level

    def get_defense(self):
        return randint(1, 25) + self.level*self.level

    def __repr__(self):
        return 'Actor: {}, Level:{}'.format(self.name, self.level)

    def is_alive(self):
        return self.hp > 0

    def attacks(self, other):
        raise NotImplementedError()

    def stats(self):
        print('    {} has {} health.'.format(self.name, self.hp))




class Player(Actor):
    def heal(self):
        self.hp += round((self.full_hp - self.hp) / 3)

    def attacks(self, enemy):
        power = self.get_attack_power()
        enemy_defense = enemy.get_defense()
        damage = power - enemy_defense

        if power > enemy_defense:
            print('{} hit the {} for {} damage!'.format(self.name, enemy.kind, damage))
            enemy.hp -= damage
            if enemy.hp <= 0:
                print('{} slayed the {}!'.format(self.name, enemy.kind))
            return True
        else:
            print('The {} appears unaffected by your attack...'.format(enemy.kind))
            return False


class Enemy(Actor):
    def __init__(self, name, level, kind):
        super().__init__(name, level)
        self.kind = kind

    def attacks(self, player):
        print('The {} attacks!'.format(self.kind))
        e_power = self.get_attack_power()
        player_defense = player.get_defense()
        damage = e_power - player_defense
        if damage < 0:
            damage = 0
            print('The {}\'s attack had no effect.'.format(self.kind, damage))
        else:
            print('The {} attacks the player for {} damage!'.format(self.kind, damage))
            player.hp -= damage

class Ogre(Enemy):
    def __init__(self, name, level, size):
        super().__init__(name, level, 'Ogre')
        self.size = size
        self.hp = 125 + 5 * level * size
        full_hp = self.hp

    def get_attack_power(self):
        return randint(1, 50)*(self.size + self.level)

    def get_defense(self):
        return randint(1, 15) + self.level*self.level*self.size


class Imp(Enemy):
    def __init__(self, name, level):
        super().__init__(name, level, 'imp')

    def get_attack_power(self):
        return randint(1, 20)

    def get_defense(self):
        return randint(1, 10)        
###game.py###
from actors import Player, Enemy, Ogre
import random
from random import randint

class Game:
    def __init__(self, player, enemies):
        self.player = player
        self.enemies = enemies

    def main(self):
        self.print_intro()
        self.wander()
        #self.encounter()

    def print_intro(self):
        print('''
            Monster Slash!!!
            
            Ready Player One?
            [Press Enter to Continue]
            ''')
        input()

    def wander(self):
        print('{} enters the dark and mysterious dungeon...'.format(self.player.name))
        print('{} is faced with two choices. [l]eft or [r]ight?'.format(self.player.name))
        input()
        ending_counter = 100
        difficulty_counter = 1
        numb_paths = 0
        while True:
            if numb_paths == 0:
                numb_paths = randint(1, 3)
            if numb_paths == 1:
                print('{} reached a dead end and retraced his steps.'.format(self.player.name))
                numb_paths = 0
            elif numb_paths == 2:
                if randint(1, ending_counter) == 1 and ending_counter <= 85:
                    print('''There is a faint light ahead.
                            {} escaped the dungeon!'''.format(self.player.name))
                    print()
                    print('*'*40)
                    print()
                    print('       CONGRATULATIONS! YOU WIN!')
                    print()
                    print('*'*40)
                    break
                cmd = input('Continue [s]traight or [g]o back?')
                if cmd == 's':
                    print('{} continued onward into the darkness...'.format(self.player.name))
                    numb_paths = 0
                elif cmd == 'g':
                    print('{} retraced his steps.')
                    numb_paths = 0
                    lost = randint(1, 2)
                    if lost == 2:
                        print('Riley has become even more lost...')
                else:
                    print('{} must make a decision.'.format(self.player.name))
            elif numb_paths == 3:
                if randint(1, ending_counter) == 1 and ending_counter <= 85:
                    print('''There is a faint light ahead.
                            {} escaped the dungeon!'''.format(self.player.name))
                    print()
                    print('*'*40)
                    print()
                    print('          CONGRATULATIONS! YOU WIN!')
                    print()
                    print('*'*40)
                    print()
                    break
                cmd = input('Continue [l]eft, [r]ight, or [g]o back?')
                if cmd == 'l':
                    print('{} continued left...'.format(self.player.name))
                    numb_paths = 0
                elif cmd == 'r':
                    print('{} continued right...'.format(self.player.name))
                    numb_paths = 0
                elif cmd == 'g':
                    print('{} retraced his steps.'.format(self.player.name))
                    numb_paths = 0
                    lost = randint(1, 2)
                    if lost == 2:
                        print('Riley has become even more lost...')
                else:
                    print('{} must make a decision.'.format(self.player.name))
            if randint(1, ending_counter) <= (ending_counter + difficulty_counter/ending_counter) / 3  :
                defeat_or_survive = self.encounter()
                if defeat_or_survive == 0:
                    break

            ending_counter -= 1
            difficulty_counter += 1


            print()
            print('*'*40)
            print()

    def encounter(self):
        while True:
            next_enemy = random.choice(self.enemies)
            continuer = 0
            print('{} encountered a {}!'.format(self.player.name, next_enemy.kind))
            while continuer == 0:
                # print('You see a {}'.format(next_enemy.kind))
                self.player.stats()
                next_enemy.stats()
                print()
                cmd = input('[a]ttack, [i]nventory, [r]un? \n')

                if cmd == 'r':
                    print(self.player.name + ' ran away. {} healed slightly'.format(self.player.name))
                    self.player.heal()
                    next_enemy.hp = next_enemy.full_hp
                    continuer = 0
                    break
                elif cmd == 'a':
                    print(self.player.name + ' attacks the ' + next_enemy.kind + '!')
                    self.player.attacks(next_enemy)
                    if next_enemy.hp <= 0:
                        next_enemy.hp = next_enemy.full_hp
                        #self.enemies.remove(next_enemy)
                        break
                    next_enemy.attacks(player)
                    if self.player.hp <= 0:
                        break

                elif cmd == 'i':
                    print(self.player.name + ' awaits the {}\'s next move...'.format(next_enemy.kind))
                    continuer = 1
                else:
                    print('Choose a valid option')

                print()
                print('*'*40)
                print()
            if self.player.hp <= 0:
                print()
                print('You have been slain by the {}.'.format(next_enemy.kind))
                print()
                print('*'*40)
                print('''               GAME OVER            ''')
                print('*'*40)
                #break
                return 0

            print()
            print('*'*40)
            print()

            if cmd == 'r':
                #break
                next_enemy.hp = next_enemy.full_hp
                return 1



if __name__ == '__main__':
    # enemies = [
    #     Enemy('Ogre', 1),
    #     Enemy('Imp', 1)
    # ]
    character_name = input('What is your name, adventurer?\n')
    player = Player(character_name, 1)
    cnt = 'y'
    while cnt == 'y':
        enemies = [
            Ogre('Ogre', 1, randint(1, 4)),
            Enemy('Imp', 1, 'Imp')
        ]
        Game(player, enemies).main()
        print()
        print('*'*40)
        print()
        cnt = input('Would you like to play again? (\'y\' for yes)\n')        

要查看或添加评论,请登录

Riley Dunnaway的更多文章

  • Python In Excel

    Python In Excel

    Nearly a year ago, Microsoft revealed the planned integration of Python programming language into Excel workbooks. To…

  • Boost Your Productivity: How to Automate Excel Macros

    Boost Your Productivity: How to Automate Excel Macros

    Automation is the name of the game, and in the world of Excel, VBA is the master key. With VBA, you can run Macros…

    1 条评论

社区洞察

其他会员也浏览了