4
\$\begingroup\$

I recently started coding and after learning a bit about functions and basics I tried to make a simple text escape room game. My code is working and the game functions as intended but I now there are probably neat ways to reduce the long amount of code using techniques I haven't yet heard about. I would really appreciate it if anyone could offer some improvements I could make.

room1 ="""There's a small, silent creature huddled in the corner chained to a
pipe. It faces the wall and trembles vigorously. Around the room there are many
sharp objects smeared in a thick, inky liquid. It stings to the touch. You want
to leave as soon as possible. In the corner of the room there is a switch on the
wall.\n
The doors are in front of you and to the right.\n"""
room2 ="""There is a body upon a table in the middle of the room, but it doesn't
look like a human. It has huge black eyes and a strangely misshapen head. The
skin is an ugly greyish colour and it's blood smells like perfume.
The doors are behind you, right, and forwards.\n"""
room3 ="""You open the door and the room is completely filled with water, or some
kind of watery substance that somehow doesn't gush out when you open the door,
seemingly encased by an invisible membrane. The only way to get to the other
doors is to swim through the block of water. The liquid has a yellow-green tinge
to it.
The doors are behind you and to the right.\n\n"""
room4 ="""The rancid smell of rotting flesh fills your nose as you glance around
the concrete room. You see...nothing. Until you look up and notice the 7 corpses
dangling from the roof. Instantly repulsed, you think nothing can be worse than
this.
The doors are left, right, and forward.\n"""
room5 ="""The same room you woke up in. You wonder how you ended up in this
nightmarish hell-house.
The doors are on all sides.\n"""
room6 ="""As you open the door there is an ominous choral humming. Apprehensively,
you enter into a room circled by cloaked figures, rehearsing a bone chilling
chant. The longer you listen, the more you want to leave.
The doors behind you, to your left, and to your right.\n"""
room7 ="""All this room is, is yellow hazard writing on the wall reading 'Room 7'
You get the sense this one hasn't been finished yet.
The doors are to your left and forwards.\n"""
room8 ="""Pleasantly, you are surprised by a room seemingly out of a museum, with
beautiful pieces of art lining each of the four walls, and classical music
playing. Only, the art seems to be... bleeding.
The doors are behind you, left, and forward.\n"""
room9 ="""A large, levitating, purple ball sits in the center of the room. All
light seemes to be swallowed up by it and it produces a low frequency sound
that makes your bones shake within you. You try and approach it but it repels
you like a magnet and leaves you skirting around it to get to the other doors.
The doors are behind you and to your left.\n"""
r1 ="""\n
|[ ][ ][ ]|
|[ ][ ][ ]|
|[^][ ][ ]|
"""
r2 ="""\n
|[ ][ ][ ]|
|[^][ ][ ]|
|[ ][ ][ ]|
"""
r3 ="""\n
|[^][ ][ ]|
|[ ][ ][ ]|
|[ ][ ][ ]|
"""
r4 ="""\n
|[ ][ ][ ]|
|[ ][ ][ ]|
|[ ][^][ ]|
"""
r5 ="""\n
|[ ][ ][ ]|
|[ ][^][ ]|
|[ ][ ][ ]|
"""
r6 ="""\n
|[ ][^][ ]|
|[ ][ ][ ]|
|[ ][ ][ ]|
"""
r7 ="""\n
|[ ][ ][ ]|
|[ ][ ][ ]|
|[ ][ ][^]|
"""
r8 ="""\n
|[ ][ ][ ]|
|[ ][ ][^]|
|[ ][ ][ ]|
"""
r9 ="""\n
|[ ][ ][^]|
|[ ][ ][ ]|
|[ ][ ][ ]|
"""


#!/usr/bin/python3
import time
import sys
import random
import pygame
pygame.init()
start_time=time.time()

def stutter(text):
    for c in text:
        print(c, end="")
        sys.stdout.flush()
        time.sleep(.02)

def end():
    stutter("\n>>>>><<<<<\nYOU DIED\n>>>>><<<<<\n")
    sound.load("/home/leo/Documents/Python/Sounds/lose.mp3")
    sound.play()
    time.sleep(6)
    start()

def win():
    global start_time
    end_time=time.time()-start_time
    m = end_time / 60
    minutes = round(m,2)
    stutter("\n---------------------------------------------------\n")
    stutter("Well done! You escaped in only {} minutes!\n".format(minutes))
    stutter("\nThank you for playing!")




def direction():
    global x
    global y
    global key
    global gloves
    global intestines
    global battery
    global switch
    global potion
    global chance


    prompt = input("\n\nChoose a direction using AWSD:\n")
    if prompt == "a" or prompt == "A":
        if (x-1) > 0 and (x-1) <= 3:
            x -= 1
        else:
            stutter("You hit a wall")
            sound.load("/home/leo/Documents/Python/Sounds/thud.mp3")
            sound.play()
            direction()
    elif prompt == "w" or prompt == "W":
        if (y+1) > 0 and (y+1) <= 3:
            y += 1
        else:
            stutter("You hit a wall")
            sound.load("/home/leo/Documents/Python/Sounds/thud.mp3")
            sound.play()
            direction()
    elif prompt == "s" or prompt == "S":
        if (y-1) > 0 and (y-1) <= 3:
            y -= 1
        else:
            stutter("You hit a wall")
            sound.load("/home/leo/Documents/Python/Sounds/thud.mp3")
            sound.play()
            direction()
    elif prompt == "d" or prompt == "D":
        if (x+1) > 0 and (x+1) <= 3:
            x += 1
        else:
            stutter("You hit a wall")
            sound.load("/home/leo/Documents/Python/Sounds/thud.mp3")
            sound.play()
            direction()
    else:
        print("That's not a valid input")
        direction()

    if x==1 and y==1:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
        sound.play()
        print(r1)
        stutter(room1)
        if switch == False:
            stutter("The switch on the wall seems to be missing a battery.\n")
            flick_switch = input("Flick the switch?(y or n):\n")
            if flick_switch == "y" or flick_switch == "Y":
                if battery == True:
                    stutter("""Hastily, not wanting to spend any more time with the
unnerving creature in the corner, you insert the
battery into the socket and flick the switch. A
series of mechanical whirrings come from one of
the other rooms.""")
                    sound.load("/home/leo/Documents/Python/Sounds/metal_scrape.mp3")
                    sound.play()
                    time.sleep(2)
                    switch = True
                    sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
                    sound.play()
                    direction()
                elif battery == False:
                    stutter("""
The cowering creature in the corner, seeminly
suddenly agitated, turns to see you flicking the
switch that doesn't have a battery in. Its depressing
face morphs in a flash into a terrify expression of
anger, and, with sudden strength and a terrifying
snarl, it rips it's restraints off and bounds towards
you.""")
                    sound.load("/home/leo/Documents/Python/Sounds/scream2.mp3")
                    sound.play()
                    stutter("""
It pounces on top of you, overpowering
you, and digs its knife-like nails into your eyes.""")
                    sound.play()
                    stutter("""
At once, you are filled with instant regret knowing
that the last thing you see will be the creatures
disgusting face.""")
                    end()
            elif flick_switch == "n" or flick_switch == "N":
                stutter("You leave the switch for the time being.")
                direction()
        elif switch  == True:
            direction()


    elif x==1 and y==2:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        print(r2)
        sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
        sound.play()
        stutter(room2)
        if intestines == False:
            stutter("""\nIt's strange, rope-like intestines lay on another table
bordering the room.""")
            take_intestines = input("\nTake the intestines?(y or n):\n")
            if take_intestines == "y" or take_intestines == "Y":
                if gloves == True:
                    stutter("Using the gloves, you pick up the intestines.\n")
                    stutter("Intestines equipped.")
                    sound.load("/home/leo/Documents/Python/Sounds/ding.mp3")
                    sound.play()
                    time.sleep(2)
                    intestines = True
                    sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
                    sound.play()
                    direction()
                elif gloves == False:
                    sound.load("/home/leo/Documents/Python/Sounds/scream1.mp3")
                    sound.play()
                    stutter("""
You try to take the intestines but as soon as you touch
them, spasms run up and down your arm, then through
your entire body.""")
                    sound.play()
                    stutter("""You begin frothing at the mouth as
you feel the last dregs of life force swiftly exiting
your body.""")
                    end()
            elif take_intestines == "n" or take_intestines == "N":
                stutter("""You decide to leave the intestines for now""")
                direction()
        elif intestines == True:
            direction()

    elif x==1 and y==3:
        sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
        sound.play()
        stutter(room3)
        stutter("""You notice one of the doors has the bright sign saying 'EXIT'
above it.\n""")
        swim = input("Swim through the liquid to the door?(y or n):\n")
        if swim == "y" or swim == "Y":
            if potion == True:
                sound.load("/home/leo/Documents/Python/Sounds/escape.mp3")
                sound.play()
                stutter("""The potion protecting you from the deadly toxicity, you
swim through the thick, cold substance, inching
closer to the door every stroke, hope fills your heart
as you stand in front of the exit door and grasp the
possibility of escape. One shove of the door, sees
it swing open and reveal a wide expanse of forest.
\nYou made it! You escaped! At least for now...""")
                win()
            elif potion == False:
                sound.load("/home/leo/Documents/Python/Sounds/scream3.mp3")
                sound.play()
                stutter("""As soon as you make contact with the liquid your
body begins to slowly disintegrate. Piece by
piece, you break apart. You look down and see
your insides tumbling out your stomach.""")
                sound.load("/home/leo/Documents/Python/Sounds/scream3.mp3")
                sound.play()
                stutter("""Your
eyes bulge and your limps are ripped of by an
invisible force and the bleak world slowly fades away..""")
                end()
        elif swim == "n" or swim == "N":
            stutter("You decide to avoid touching the substance for now.")
            direction()





    elif x==2 and y==1:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
        sound.play()
        print(r4)
        stutter(room4)
        if key == False:
            stutter("\nThere is a key tucked inside one of the body's trouser pocket.\n")
            take_key = input("Take the key?(y or n):\n")
            if take_key == "y" or take_key == "Y":
                stutter("Key equipped.")
                sound.load("/home/leo/Documents/Python/Sounds/ding.mp3")
                sound.play()
                time.sleep(2)
                key = True
                sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
                sound.play()
                direction()
            elif take_key =="n" or take_key =="N":
                stutter("You didn't take the key.")
                sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
                sound.play()
                direction()
        elif key == True:
            direction()

    elif x==2 and y==2:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
        sound.play()
        print(r5)
        stutter(room5)
        direction()

    elif x==2 and y==3:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        print(r6)
        sound.load("/home/leo/Documents/Python/Sounds/scary_chant.mp3")
        sound.play()
        stutter(room6)
        if gloves == False:
            stutter("""\nThere is a small locked glass case in the middle of the room with
a pair of silk gloves inside.\n""")
            take_gloves = input("Take the gloves?(y or n):\n")
            if take_gloves == "y" or take_gloves == "Y":
                if key == True:
                    stutter("Using the key, you open the case and take the gloves.\n")
                    sound.load("/home/leo/Documents/Python/Sounds/unlock.mp3")
                    sound.play()
                    time.sleep(3)
                    stutter("Gloves equipped.")
                    sound.load("/home/leo/Documents/Python/Sounds/ding.mp3")
                    sound.play()
                    time.sleep(2)
                    gloves = True
                    sound.load("/home/leo/Documents/Python/Sounds/scary_chant.mp3")
                    sound.play()
                    direction()
                elif key == False:
                    stutter("The case is locked and you can't get the gloves.")
                    direction()
            elif take_gloves =="n" or take_gloves =="N":
                stutter("You didn't take the gloves.")
                direction()
        elif gloves == True:
            direction()

    elif x==3 and y==1:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        sound.load("/home/leo/Documents/Python/Sounds/ambient.mp3")
        sound.play()
        if switch == False or potion == True:
            print(r7)
            stutter(room7)
            direction()
        elif switch == True:
            print(r7)
            stutter(room7)
            time.sleep(2)
            stutter("\nBut wait...\n")
            time.sleep(2)
            stutter("""Now a small hatch has opened up in the wall. You peek inside
and a small volume of liquid sits in a glass flask. This
must be what the switch opened. You read the label.
'The odds are even. Will you take the chance?'
You ponder what this means as you sense an important
decision approaching...""")
            drink = input("\nWill you drink the potion?(y or n):\n")
            if drink == "n" or drink == "N":
                stutter("You might come back to the potion later.")
            elif drink == "y" or drink == "Y":
                sound.load("/home/leo/Documents/Python/Sounds/glug.mp3")
                sound.play()
                time.sleep(0.6)
                sound.play()
                time.sleep(0.6)
                sound.play()
                time.sleep(0.6)
                sound.play()
                time.sleep(0.6)
                sound.play()
                time.sleep(1)
                if chance == 0 or chance == 1:
                    stutter("""You tip the potion back into your mouth. Nothing goes
wrong so you assume it worked.""")
                    stutter("\nPotion activated.")
                    sound.load("/home/leo/Documents/Python/Sounds/item_consumption.mp3")
                    sound.play()
                    potion = True
                    direction()
                elif chance == 2:
                    sound.load("/home/leo/Documents/Python/Sounds/scream2.mp3")
                    stutter("You gulp the liquid down. Oh no.")
                    sound.play()
                    stutter("""
You bones feel like they're being hammerred at from the inside. You run
your hands through your hair and every strand is
stripped of and falls on the floor.""")
                    sound.play()
                    stutter("""
It feels like all of your nails and toenails are ripped off one
by one. You try and move, but full body paralysis
seems to have overcome your body. 'Fuck'.""")
                    sound.load("/home/leo/Documents/Python/Sounds/scream1.mp3")
                    sound.play()
                    stutter("""
You suffer one last wave of astronomical pain
before swiftly leaving this plane of existance.""")
                    end()



    elif x==3 and y==2:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        print(r8)
        sound.load("/home/leo/Documents/Python/Sounds/classical_music.mp3")
        sound.play()
        stutter(room8)
        if battery == False:
            stutter("""\nYou notice a faint light behind one of the paintings and
so take the hanging art of the wall. It reveals a thin
cylindrical hole in the wall too thin to fit through.
You can see that there is something at the end but
don't know what it is.\n""")
            take_battery = input("Reach for the object?(y or n):\n")
            if take_battery == "y" or take_battery == "Y":
                if intestines == True:
                    stutter("""Using the ropey intesines, you form them into somewhat
of a lasso shape and manage to fish out the the
object. It is a battery.\n""")
                    stutter("Battery equipped.")
                    sound.load("/home/leo/Documents/Python/Sounds/ding.mp3")
                    sound.play()
                    battery = True
                    time.sleep(2)
                    sound.load("/home/leo/Documents/Python/Sounds/classical_music.mp3")
                    sound.play()
                    direction()
                elif intestines == False:
                    stutter("The hole is to small to reach the object through.")
                    direction()

            elif take_battery == "n" or take_battery == "N":
                stutter("You didn't get the object.")
                direction()
        elif battery == True:
            direction()

    elif x==3 and y==3:
        sound.load("/home/leo/Documents/Python/Sounds/walking.mp3")
        sound.play()
        time.sleep(2)
        sound.stop()
        print(r9)
        sound.load("/home/leo/Documents/Python/Sounds/low_hum.mp3")
        sound.play()
        stutter(room9)
        touch = input("\nTouch the levitating ball?(y or n):\n")
        if touch == "y" or touch == "Y":
            sound.load("/home/leo/Documents/Python/Sounds/scream1.mp3")
            sound.play()
            time.sleep(2)
            end()
        elif touch =="n" or touch =="N":
            print("Makes sense")
            direction()
def start():
    global x
    global y
    global key
    global gloves
    global intestines
    global battery
    global switch
    global potion
    global chance
    global sound
    x=2
    y=2
    key = False
    gloves = False
    intestines = False
    battery = False
    switch = False
    potion = False
    chance = random.randint(0,2)
    sound = pygame.mixer.music
    sound.load("/home/leo/Documents/Python/Sounds/slow_music.mp3")
    sound.play()

    stutter("\n\n<<<<<<<<<<<<<<<<<<<<<<<<<< Escape Room >>>>>>>>>>>>>>>>>>>>>>>>>>\n")
    time.sleep(3)
    stutter("A game by Leo Gortzak\n")
    time.sleep(5)
    stutter("""\n\nYou awake in a dark room with a rusty iron door. There is a small
circular window casting a dim light across the room.
There are four doors leading out. One on each wall.\n""")
    print(r5)
    direction()

start()
\$\endgroup\$
3
\$\begingroup\$

To add to @Errorsatz's comment at the bottom of his answer

In terms of the data itself, there's only so far you can compress that, but the map images (r1-r9) could all be generated by a single function.

Any time you find yourself hard coding repetitious, complicated things like with the variables r1-r9, you should take a step back and consider writing code to automate it for you. What if you want to change the size later, or add some other detail? Do you really want to have to edit every room?

Here's some code that does just that. I chose to break it down quite far and opt for a verbose version, but I feel that will help readability and understanding. Don't worry, we'll walk through the code in detail after.

room_wall = "|"
spot_template = "[ ]"
position_indicator = "^"

def room_template(width, height):
    row = [room_wall + spot_template * width + room_wall]

    return "\n".join(row * height)

def generate_room(width, height, pos_x, pos_y):
    template = room_template(width, height)

    spot_width = len(spot_template)
    wall_width = len(room_wall)
    row_width = spot_width * width + wall_width * 2 + 1 # + 1 to account for newline
    replace_index = 1 + wall_width + pos_y * row_width + pos_x * spot_width

    return template[:replace_index] \
               + position_indicator \
               + template[replace_index + 1:] 

def generate_rooms(room_width, room_height):
    return [generate_room(room_width, room_height, x, y)
            for x in range(room_width)
            for y in range(room_height - 1, -1, -1)]

And an example of its use:

>>> for r in generate_rooms(3, 3):
        print(r + "\n")

|[ ][ ][ ]|
|[ ][ ][ ]|
|[^][ ][ ]|

|[ ][ ][ ]|
|[^][ ][ ]|
|[ ][ ][ ]|

|[^][ ][ ]|
|[ ][ ][ ]|
|[ ][ ][ ]|

|[ ][ ][ ]|
|[ ][ ][ ]|
|[ ][^][ ]|

|[ ][ ][ ]|
|[ ][^][ ]|
|[ ][ ][ ]|

|[ ][^][ ]|
|[ ][ ][ ]|
|[ ][ ][ ]|

|[ ][ ][ ]|
|[ ][ ][ ]|
|[ ][ ][^]|

|[ ][ ][ ]|
|[ ][ ][^]|
|[ ][ ][ ]|

|[ ][ ][^]|
|[ ][ ][ ]|
|[ ][ ][ ]|

So, how does it work?

room_wall = "|"
spot_template = "[ ]"
position_indicator = "^"

First, at the top I defined several variables holding the bare-bones of what's going to be generated. This makes it easier to change things later, and makes it clearer what the characters actually represent. spot_template represents the basic structure of an empty "cell" in a room. The ^ will be plugged in later when necessary.


def room_template(width, height):
    row = [room_wall + spot_template * width + room_wall]

    return "\n".join(row * height)

room_template returns a simple, empty-celled room. row ends up being, with dimensions of 3x3, ["|[ ][ ][ ]|"]; a string representing a row enclosed in a list. I put a list around it because later on I need row * height to multiply lists, not strings directly. I need each row separate so I can join them with a newline before it's all returned:

>>> room_template(3, 3)
'|[ ][ ][ ]|\n|[ ][ ][ ]|\n|[ ][ ][ ]|'

>>> print(room_template(3, 3))
|[ ][ ][ ]|
|[ ][ ][ ]|
|[ ][ ][ ]|

generate_room's math got a little messy unfortunately. There's a few nit-picky details that need to be taken into consideration though.

Here's the idea of how it works: take the returned template room, figure out the index of the empty space character in the selected "[ ]" that needs to be replaced, then replace it with a "^".

spot_width = len(spot_template)
wall_width = len(room_wall)
row_width = spot_width * width + wall_width * 2 + 1 # + 1 to account for newline
replace_index = 1 + wall_width + pos_y * row_width + pos_x * spot_width

This whole chunk is figuring out the exact index in the template string that needs to be replaced. Basically, I just sat down with a pen and paper and figured the math out by manually finding the indices for a 3x3 room, and thinking out what math would lead to that. Then I expanded it to other dimensions, and fixed a couple bugs. I originally figured it out without the "|" walls for simplicity, then accounted for them after.

Here are the major parts:

row_width = spot_width * width + wall_width * 2 + 1 # + 1 to account for newline

This is how many characters long each "row" of the string is. Each "[ ]" cell is 3 characters long, so the whole row is the length of "[ ]" * the width of the room + the length of "|" * 2. Then + 1 to account for the newline at the end of each row.

replace_index = 1 + wall_width + pos_y * row_width + pos_x * spot_width

This is based on an old equation that's useful in many scenarios. If you have a 2D list/matrix being represented by a normal, 1D list (like [1, 2, 3, 4, 5, 6, 7, 8, 9] representing a 2D array of [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), and you wanted to figure out the index of the cell at position (1, 2), what's the equation? It's simply

i = row_width * y + x
i = 3 * 2 + 1
i = 7

The element at index 7 is 8, which if this were a 2D array, would be the element at (1, 2).

This is the basic idea here. If you squint a bit, you can see row_width * y + x in there. The + 1 is to account for the first "[", and I have to + wall_width to account for the walls on each end.

return template[:replace_index] \
           + position_indicator \
           + template[replace_index + 1:]

This is just "replacing" the character at index replace_index of the template string. See @Willem's answer here for an in-depth explanation of what's going on. It basically just cuts the string in two pieces at the calculated index, puts the "^" in there, then glues it all back together.

>>> generate_room(3, 3, 1, 2)
'|[ ][ ][ ]|\n|[ ][ ][ ]|\n|[ ][^][ ]|'

>>> print(generate_room(3, 3, 1, 2))
|[ ][ ][ ]|
|[ ][ ][ ]|
|[ ][^][ ]|

Finally, generate_rooms goes through each x,y position, in the order you had before, and creates a room with an indicator at the given position.

The whole thing is just a list comprehension split over a few lines.

for x in range(room_width)
for y in range(room_height - 1, -1, -1)

This generates each x,y position starting from the bottom left. It then passes the generated x,y values to generate_room, generates a room, and adds it to the list. The list is then returned. This function is basically a more succinct version of:

def generate_rooms_verbose(room_width, room_height):
    rooms = []

    for x in range(room_width):
        for y in range(room_height - 1, -1, -1):
            rooms.append(generate_room(room_width, room_height, x, y))

    return rooms

Which may make more sense.


Hopefully this helps. This code certainly isn't very short, but it shows how this problem can be approached, and that it can be automated.

Now, you can create rooms of any dimensions:

>>> print(generate_room(4, 10, 2, 7))
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][^][ ]|
|[ ][ ][ ][ ]|
|[ ][ ][ ][ ]|

Without ever needing to manually write each of the possible 40 rooms of that size.



Looking back, I could/should have broken generate_room down further. The math calculating the index could go in its own function, and I could have also created a function to return a string with the character at a given i replaced with a replacement character. Something like:

def spot_index_in_template(template_width, x, y):
    spot_width = len(spot_template)
    wall_width = len(room_wall)
    row_width = spot_width * template_width + wall_width * 2 + 1

    return 1 + wall_width + y * row_width + x * spot_width

def replace_at_index(s, i, replacement):
    return s[:i] + replacement + s[i + 1:]

def generate_room(width, height, pos_x, pos_y):
    template = room_template(width, height)
    i = spot_index_in_template(width, pos_x, pos_y)

    return replace_at_index(template, i, position_indicator)
\$\endgroup\$
  • \$\begingroup\$ This is very clever thank you for taking the time. May I ask how long you've been coding for? \$\endgroup\$ – Leo Gortz Feb 28 at 13:22
  • \$\begingroup\$ @LeoGortz You're welcome. And about 5 - 10 years depending on what you consider "coding". I've been writing code daily for about 5 years now. \$\endgroup\$ – Carcigenicate Feb 28 at 14:59
3
\$\begingroup\$

Organizationally, something that might help in this type of game is classes: https://jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/

For example, you could store all the relevant data for a single room together in a Room class, and you could store the state of various flags like gloves/battery/switch in a GameState class.

In addition to that, try to reduce global variables and instead just pass each function the data it needs. This will make it much easier to grow your game further - at nine rooms, you already have ten global variables, and that number will keep going up until it becomes unmanageable.

For example:

 def promptMovement(gameState):
     prompt = input("\n\nChoose a direction using AWSD:\n")
     if prompt.lower() == "a":
         attemptMovement(gameState, -1, 0)
     else if prompt.lower() == "w":
         attemptMovement(gameState, 0, 1)
     else if prompt.lower() == "s":
         attemptMovement(gameState, 0, -1)
     else if prompt.lower() == "d":
         attemptMovement(gameState, 1, 0)
     else
         print("That's not a valid input")

def attemptMovement(gameState, dx, dy):
    tx = gameState.x + dx
    ty = gameState.y + dy
    if tx < 1 or tx > 3 or ty < 1 or ty > 3:
        stutter("You hit a wall")
        sound.load("/home/leo/Documents/Python/Sounds/thud.mp3")
        sound.play()
    else:
        gameState.x = tx
        gameState.y = ty

By splitting the logic into multiple functions, you can avoid repetition and also make the code clearer to read. This is just a starting point; you could also:

  • Use a dynamic size for the play area rather than hard-coded 3.
  • Put some of this logic inside GameState as a member function.

There are other parts of the code that can be made into functions as well. For example:

def playSoundFor(sfx, seconds):
    sound.load(sfx)
    sound.play()
    time.sleep(seconds)
    sound.stop()

In terms of the data itself, there's only so far you can compress that, but the map images (r1-r9) could all be generated by a single function.

\$\endgroup\$
1
\$\begingroup\$

You could possibly store the rooms in a text file to reduce the code, like this:

if rooms == 1:
    N=10
    f=open("test.txt")
    for i in range(5):
        line=f.read().strip()
        print(line)
    f.close()

This will print what is inside the file and for the range you put the number of lines that are in the file.

\$\endgroup\$
  • \$\begingroup\$ Not just the rooms either, the texts, stutters and everything else could be in there too. Or in different files, if you're so inclined. To keep things neat. \$\endgroup\$ – Mast Dec 18 '18 at 19:17
  • 1
    \$\begingroup\$ Of-course, once you go this route, you can simply read the entire file and parse it in a loader. This loader can put all the texts in lists or dictionaries. \$\endgroup\$ – Mast Dec 18 '18 at 19:19

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.