7
\$\begingroup\$

After posting here before, reading that advice, and doing some research, I re-planned and started over.

I appreciate the comments I get here at Code Review.

The first thing I did was to create a map so I could see what I had to code for. https://sta.sh/01tlcemlvumr

I then finished the code for the first room in the game to see how my new code structure would work. Here are some details:

  1. I was going to use a player object. But, I don't need any methods. I am only storing values. So, I thought a dictionary would be a better choice. I suppose using separate variables could do the same thing; but, I thought the dictionary was a better way to organize things.

    • The location property is a short description of a room/location. It is printed if a player asks where he/she is in the game.
    • The location_name property is used to by the code to call a function associated with the room/location. I will have more on this later.
  2. I created a class for locations in the game. I then created the first room/location object.

    • Each object will have a tuple of valid moves and a tuple of valid actions as properties of the object. I chose tuples because they cannot be changed.
    • Each object will have a keys property which will have a list of settings for that location stored in a dictionary. For instance, I have a light switch that needs to be turned on. If it isn't set to "on", a player cannot see a box in the room. Using a dictionary allows me to have a good descriptive name as a key, and the value can change depending on the situation like the one just described about the light. (* I think I will change the property name to something like "settings" or room_settings".)
    • Each object will have a longer description that lays out the room's/location's features in detail. This can be printed when a player first enters the space.

Getting back to the player's location_name property...

The main game loop function checks the location_name. It then calls a function for that location. That function for the location checks the two tuples. If the player's entry is in the one for a move, then another function is called for moves. If the entry is in the action tuple, then the action function is called for actions.

Since I have the two tuples in the room/location objects, I have all the values/player entry possibilities that I need to code for, and these can be easily found and modified. This also gives me a list of values for testing.

Right now, I only have code for that first room and code that takes a player to the next room. I also have code for actions in the first room.

I think this overall structure will allow me to add to the game in an organized way. I can continue to add elif statements to the play_game() function for each room/location. And, I can add functions for each room with sub functions for moves and actions in those individual rooms.

I coded this using the REPL.it website and the local library's computers. I can't afford my own computer right now. This website is really nice. I have tried PythonAnywhere. But, REPL.it works better for me right now. Maybe if I do a bigger project, PythonAnywhere would be better.

I am not sure if this is relevant. Delete it if it is not. I watched Bryan Tong's YouTube videos on doing a Python Text RPG. I didn't copy what he did. But, I liked a lot of his ideas especially how well-organized he was with his code. He did six videos for this series. https://www.youtube.com/channel/UC5akxkiQHpxCzPZWskdBbQQ

# Since there are no methods needed for a player a dictionary may be a better option since this is only storing data.

player_location = "start_room"

player_data = {
    "name": "none", # This will come from input.
    "location": "You are at the start of the game in a small dining room in a small house.\n",   # The player will always start here.
    "location_name": "start_room",
    "health": 100       
}

# Create locations for the game with directions as to where a player can go in them.
class Location:
    def __init__(self, moves, actions, keys):
        self.moves = moves
        self.actions = actions 
        self.keys = keys
        self.description = "You are in a small dining room in a small house. There is no furniture in this room.\n\nYou are facing a short hallway leading to a staircase.\n\nThere is an open door to your left leading to a small porch.\n\nTo your right is the living room.\n\nThe area of the room back behind you is dark.\n\nThere is a light switch on the wall.\n\n"


# ---------------------------------------------------------
# This will print at the beginning of the game and every time a player enters "help".

def help_file():

    print("\n- - - - - - - - - - - - - - - - - - - - - - - - -\n")

    print("You will be exploring places and interacting with items in the game.\n")

    print("Please use words like 'forward', 'left', 'right' and 'back' for movement inside a structure.\n")

    print("Directions such as 'north' or 'n'; 'south' or 's'; 'east' or 'e'; and 'west' or 'w' will work when you are outside.\n")

    print("When you want to use an item in the game, just enter the name of the item like 'boomerang'. You will then be prompted for what you want to do with that item.\n")

    print("To see a description of where you are in a room or an area, just type 'description'.\n")

    print("To see this introductory list again, type 'help'.\n")

    print("When you are ready to continue, press the ENTER key.\n")
    input()

    print("\n- - - - - - - - - - - - - - - - - - - - - - - - -\n")



# ---------------------------------------------------------
# The starting room:

# This creates a new object based on the Location class.
# The two tuples are the moves list and the actions list for later validation.

start_room_keys = {"light": "off"}

start_room = Location(("stairs", "staircase", "forward", "porch", "left", "living room", "right", "back"),
("look", "light", "light switch", "box", "open"), start_room_keys)


# Functions for a player move or action in this room:
def start_room_moves_actions(player_input):
    if player_input in start_room.moves:
        start_room_moves(player_input)
    elif player_input in start_room.actions:
        start_room_action(player_input)
    else:
        print("\nThat is not a valid request for this situation.\n")
        play_game()


def start_room_moves(player_move):

    print()

    if player_move == "stairs" or player_move == "staircase" or player_move == "forward":
        print("You walk to the bottom of the stairs. There is an old rug at the base of the stairs.")
        player_data["location"] = "At the bottom of the stairs in the small house"
        player_data["location_name"] = "house_stairs"
    elif player_move == "porch" or player_move == "left":
        print("You walk through the open door to the porch.")
        print("The view from here is spectacular. You are looking out over a wooded valley with a river far below.")
        print("There are rolling hills off in the distance.")
        print("You walk to the edge of the porch and see some letters carved in the railing.")
        print()
        print("RWBL")
        print()
        print("Hmm...I wonder what that means?\n")
        player_data["location"] = "On the back porch of a small house."
        player_data["location_name"] = "house_porch"
    elif player_move == "right" or player_move == "living room":
        print("As you enter the living room you notice a large painting of a sunset scene over a wooded valley on one wall.\n")
        player_data["location"] = "You are in the living room in a small house."
        player_data["location_name"] = "house_living_room"
    elif player_move == "back":
        if start_room.keys["light"] == "off":
            print("It is too dark to go in that direction. You should be more careful about where you go.\n")
        else:
            print("There is an old shoe box in the back next to the wall.\n")


def start_room_action(player_action):
    if player_action == "look":
        print("There is no furniture in this room. There is an old hanging light fixture that has a bulb in the middle of the ceiling. There is a light switch to your right on the wall. The room back behind you is dark and you cannot see what is there.\n")
    elif player_action == "light" or player_action == "light switch":
        print("\nThe hanging light in the middle of the ceiling illuminates the room. There appears to be a box back of the room where it was previously dark.\n")
        start_room.keys["light"] = "on"
    elif player_action == "box" or player_action == "open":
        if start_room.keys["light"] == "off":
            print("What are you trying to do? You need to lighten up.\n")
        else:
            print("\nThere is a brand new pair of running shoes in the box.\n")
            print("As you take them out, you see...SOMETHING.\n")


# ---------------------------------------------------------
# The porch:


# ---------------------------------------------------------
# The stairs:


# ---------------------------------------------------------
# The living room:


# -------------------------------------------------------------
# End of code/functions for individual rooms/locations.
# -------------------------------------------------------------

# Get a name from player and update player object.
print("Welcome to the game.")

def get_player_name():
    name_input = input("What is your name?")

    if len(name_input) > 10 or len(name_input) < 1:
        print("Please enter a name with 0 - 10 letters.")
        get_player_name()
    else:
        player_data["name"] = name_input


get_player_name()


# Print welcome to player using name.
print("\nWelcome, " + str(player_data["name"]) + "!")

# Print the starting story text.
# Print a description of the game with examples of valid entries.
help_file()

# Print a description of the starting room.
print(start_room.description)

# ---------------------------------------------------------
# Main game loop

def play_game():
    # Get input from player for move or interaction.
    player_input = input("What would you like to do now?\n")

    # If 'description', then print the current location's description, and then prompt again for input.
    if player_input == "description":
        current_location = player_data["location"]
        print("\n" +  str(current_location))
    elif player_input == "help":
        help_file()
    elif player_input == "":
        print("Please try again.")
    else:
        # Get the name of the player's current location.
        current_location_name = player_data["location_name"]        
        if current_location_name == "start_room":
            start_room_moves_actions(player_input)

        # Add elif statements here checking for rooms.


    # Check to see if the game is over at this point.
    if player_data["health"] < 1:
        print("You are dead! Too bad. You seemed like a nice person.")
    else:
        play_game()


play_game()  
\$\endgroup\$
  • \$\begingroup\$ You can replace e.g. if player_move == "stairs" or player_move == "staircase" or player_move == "forward" with if player_move in {'stairs', 'staircase', 'forward'} which is a bit more terse and still readable \$\endgroup\$ – James Hiew May 24 '18 at 9:00
1
\$\begingroup\$

Reviewing your design, you mention I was going to use a player object. But, I don't need any methods , however you have:
- "name": "none",
- "health": 100
These lend themselves to player actions and multiple players in a game. The health, for instance, where do you manage the "drink potion" and "being attacked" functionality? It seems like you need a class for the player and two methods, heal(amount) and damage(amount) - which means we also need a property for player().is_dead when (not real code):

if damage(amount)>= self.health:
    self.is_dead = True

Also, for your locations, having functionality and properties separated into tuples doesn't make sense, you'd need to create hundreds of tuples and track them all (how do you link them for the adventure? how does the user move between them?). It would be easier to create a base class of Location and Room(Location) or Outside(Location) to inherit. The Location class would contain the logic of the user moving into and out of the location, Rooms would have additional functionality like light switches (and if they're on or off by default). For this, I'd use a feature map (a matrix containing a Location's default properties) and make the process of loading them responsible for creating the objects (and adding certain items to a room).
As this design is quite complex, I would suggest separating the location data from the code, possibly by using ConfigParser and storing the data into an .ini file.

Something like:

[room_x1_y1]
name = Dining Room
contains_physical = dining_table,chairs,plates
contains_npc = npc_butler

[npc_butler]
name = Butler
contains_physical = building_key

When the program runs, it will load the player data and location data (knowing x and y from each section definition) and start the game.
Finally, it sounds like you might want a decent IDE, I'd recommend starting with the community version of PyCharm from JetBrains.

Hope this helps with your design and code. Good luck!

\$\endgroup\$
  • \$\begingroup\$ The main reason I used the two tuples was because I was thinking that listing and separating the valid moves and valid actions like this would help with verifying a player's input. Yes - I did realize that I would have to create new functions for those for every room/location. Moving from simple tutorials where I am only writing small functions to writing actual programs is going to involve thinking about the over-all design as to how the code fits together and interacts. I will read your suggestions, do some research/reading (especially about classes/objects) and try again. \$\endgroup\$ – user109140 May 29 '18 at 13:32
  • \$\begingroup\$ Unfortunately, I cannot use PyCharm or any other IDE since I only have the library computers (Windows) to use which don't have Python installed. So, I am glad I at least have REPL.it and Python Anywhere. \$\endgroup\$ – user109140 May 29 '18 at 18:03

Your Answer

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