4
\$\begingroup\$

For Learn Python The Hard Way exercise 45 I made a small text game, that took a few hours. Since classes were used and classes were a recently brought up concept in the book, I was wondering how this piece of code could be made better. It should be able to work in terminal as far as I know.

from sys import exit
from random import randint

from Scene import *

class Main(object):

    def __init__(self):
        self.stage = DoorScene()
        self.stage_2 = FightScene()
        self.stage_3 = EndingScene()

    def play(self):
        boss_door = self.stage.enter_boss_room()
        if boss_door == True:
            defeated_boss = self.stage_2.the_fight()
            if defeated_boss == True:
                self.stage_3.ending()
        else:
            exit(0)

game_try = Main()
game_try.play()

second file

from random import randint

class DoorScene(object):

    def enter_boss_room(self):
        print "You walk and come across a door. It requires you to guess the"
        print "right number to enter the room to fight the final boss. You only"
        print "have 5 guesses so make good use of your guesses."

        code = randint(1, 10)
        choice = raw_input("> ")
        attempts = 0

        while int(choice) != code:
            attempts += 1
            if attempts == 5:
                break
            else:
                pass
            print "Wrong number, try again."
            choice = raw_input("> ")

        if int(choice) == code:
            print "That's the correct number! You pass through the door and see"
            print "a huge beast laying in the room. Prepare yourself to fight the beast!\n"
            return True
        else:
            print "You failed more than 5 times. Game Over."
            return False


class FightScene(object):

    def the_fight(self):
        print "Your character will now fight the boss. If your health drops"
        print "below 100, you can use a health potion to restore your"
        print "health by 50. Note that you only have 3 health potions.\n"

        current_boss_health = 200
        current_hero_health = 150
        health_potion = 3

        while True:
            print "It is your turn to perform an action. Would you like"
            print "to attack the boss, use a health potion or run away?"

            choice = raw_input("> ")

            if choice == 'attack':
                damage_hero = randint(25, 35)
                current_boss_health -= damage_hero
                print "You hit the boss for %d damage!" % (damage_hero)
                if current_boss_health <= 0:
                    print "The boss has 0/200 health left!\n"
                    print "Well done, you defeated the boss!\n"
                    break
                print "The boss has %d/200 health left!\n" % (current_boss_health)
            elif choice == 'use health potion':
                if current_hero_health <= 100 and health_potion > 0:
                    print "You restored your health by 50, you now have %d/150 health" % (current_hero_health + 50)
                    current_hero_health = current_hero_health + 50
                    health_potion = health_potion - 1
                    print "You have %d health potion(s) left.\n" % (health_potion)
                    continue
                else:
                    print "Sorry your health is not below 100 or you don't have any"
                    print "health potions left anymore!\n"
                    continue
            elif choice == 'run away':
                print "Coward!"
                exit(0)
            else:
                continue

            damage_boss = randint(30, 50)
            current_hero_health -= damage_boss
            print "The boss hits you for %d damage!" % (damage_boss)
            if current_hero_health <= 0:
                print "You have 0/150 health left!\n"
                print "You got defeated...."
                exit(0)
            print "You have %d/150 health left!\n" % (current_hero_health)

        return True

class EndingScene(object):

    def ending(self):
        print "You manage to escape through an opening you find in the boss' lair"
        print "You return home, lay in your bed and deeply fall asleep...."
        exit(0)
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Code Review! I hope you get some great answers. \$\endgroup\$ – Phrancis Aug 18 '16 at 19:35
1
\$\begingroup\$

You should generalize your room code. Instead of having self.stage.enter_boss_room(), self.stage2.the_fight() and so on in separate classes, it'd be better to have a single Scene() class with methods such as eg entrance_text and main_interaction. Assuming the gameplay is gonna be strictly linear and each room consists of a block of text and a single puzzle, code might look like this:

def Scene():
    def __init__(self, entrance_text, test):
        self.entrance = entrance_text
        self.test = test

    def print_entrance(self):
        print(self.entrance)

    def run_test():
        #1st class functions magic!
        return self.test()

Now to the first room:

def test1():
            code = randint(1, 10)
        choice = raw_input("> ")
        attempts = 0

        while int(choice) != code:
            attempts += 1
            if attempts == 5:
                break
            else:
                pass
            print "Wrong number, try again."
            choice = raw_input("> ")
s = []
s.append(Scene('You walk across the room. It requires you to guess the\nright number', test1))

Add all the other rooms to s, as well. Now your Main() will be way more simple:

for a in s:
    a.print_entrance()
    if not a.run_test():
        print('Game Over')
        quit()

The main advantage here is not the brevity of the code; it's the scalability. In your version, every time you add a scene, you have to manually add some method calls in Main(). This is annoying and leads to barely maintainable code. Imagine all the fun of remembering whether self.bash_goblin() needs to be before or after self.unlock_door_45() when you have a couple hundreds of scenes. Now you have a unified scene API, so your engine doesn't really care how many scenes there are or where. You can add features such as jumping to any random scene, savegames (which are basically a single integer) or rollback at pretty much no cost. Of course, code as written is a pretty primitive prototype I've hacked together as an example, but hopefully it explains the idea.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your reply. I'll definitely take this in account after I add more rooms and bosses in the final mini project! \$\endgroup\$ – user21398 Aug 20 '16 at 1:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.