5
\$\begingroup\$

I am semi new to coding and have been following a tutorial on making a "text based RPG" on CodeClub.

Here is the full code:

#!/bin/python3

# Replace RPG starter project with this code when new instructions are live

def showInstructions():
  #print a main menu and the commands
  print('''
RPG Game
========

Get to the Garden with a key, a knife and a matchbox
But beware of the monsters!

Commands:
  go [direction]
  get [item]
''')

def showStatus():
  #print the player's current status
  print('---------------------------')
  print('You are in the ' + currentRoom)
  #print the current inventory
  print('Inventory : ' + str(inventory))
  #print an item if there is one
  if "item" in rooms[currentRoom]:
    print('You see a ' + rooms[currentRoom]['item'])
  print("---------------------------")

#an inventory, which is initially empty
inventory = []

#a dictionary linking a room to other rooms
rooms = {

            'Hall' : { 
                  'south' : 'Kitchen',
                  'east'  : 'Dining Room',
                  'item'  : 'key'
                },

            'Kitchen' : {
                  'north' : 'Hall',
                  'east'  : 'Living Room',
                  'item'  : 'knife'
                },
            'Dining Room' : {
                  'west'  : 'Hall',
                  'south' : 'Living Room',
                  'east'  : 'Garden',
                  'item'  : 'matchbox'
                },
            'Living Room' : {
                  'north' : 'Dining Room',
                  'west'  : 'Kitchen',
                  'item'  : 'monster'
                },
            'Garden' : {
                  'west'  : 'Dining Room'
            }

         }

# Displays a map of all the accesable rooms from the current room.
def room_map():

  # Makes sure that a variable defaults to an empty string...
  # ...if the current room doesnt link to another room in that direction.
  try:
    north = rooms[currentRoom]['north']
  except:
    north = ""
  try:
    south = rooms[currentRoom]['south']
  except:
    south = ""
  try:
    east = rooms[currentRoom]['east']
  except:
    east = ""
  try:
    west = rooms[currentRoom]['west']
  except:
    west = ""

  # Prints the map
  n = "N"
  s = "S"
  vert_line = "|"
  hzt_line = "-- W -- X -- E --"
  print(north.center(30))
  print("")
  print(vert_line.center(30))
  print(n.center(30))
  print(vert_line.center(30))
  print(west + hzt_line.center(30 - len(west) * 2) + east)
  print(vert_line.center(30))
  print(s.center(30))
  print(vert_line.center(30))
  print("")
  print(south.center(30))
  print("")

#start the player in the Hall
currentRoom = 'Hall'

showInstructions()

#loop forever
while True:
  room_map()
  showStatus()

  #get the player's next 'move'
  #.split() breaks it up into an list array
  #eg typing 'go east' would give the list:
  #['go','east']
  move = ''
  while move == '':  
    move = input('>')

  move = move.lower().split()

  #if they type 'go' first
  if move[0] == 'go':
    #check that they are allowed wherever they want to go
    if move[1] in rooms[currentRoom]:
      #set the current room to the new room
      currentRoom = rooms[currentRoom][move[1]]
    #there is no door (link) to the new room
    else:
        print('You can\'t go that way!')

  #if they type 'get' first
  if move[0] == 'get' :
    #if the room contains an item, and the item is the one they want to get
    if "item" in rooms[currentRoom] and move[1] in rooms[currentRoom]['item']:
      #add the item to their inventory
      inventory += [move[1]]
      #display a helpful message
      print(move[1] + ' got!')
      #delete the item from the room
      del rooms[currentRoom]['item']
    #otherwise, if the item isn't there to get
    else:
      #tell them they can't get it
      print('Can\'t get ' + move[1] + '!')
  # player loses if they enter a room with a monster
  if 'item' in rooms[currentRoom] and 'monster' in rooms[currentRoom]['item']:
    print('A monster has got you....GAME OVER!')
    break

  # player wins if they get to the garden with a key, a matchbox and a knife
  if currentRoom == 'Garden' and 'key' in inventory and 'matchbox' in inventory and 'knife' in inventory:
    print('You escaped the house... YOU WIN!')
    break

I have tried to implement my own map/compass to display the players current location in relationship to the accesable rooms. My code works but is very repetitive and not very efficient.

I am interested in simplifying the room_map() function.

I will eventually go about creating a real map with rooms and walls that can be updated in terms of player location, enemies etc.

The map looks like this and updates when I go to another room: enter image description here

\$\endgroup\$
3
\$\begingroup\$
#!/bin/python3

This is rarely where Python lives. Typically you should instead write

#!/usr/bin/env python3

Your rooms dict shouldn't really be a dict. Dicts are good for serialization and web APIs, but in Python they're often abused. You should use a namedtuple, if not an actual class.

Here:

# Displays a map of all the accesable rooms from the current room.
def room_map():

The convention for function documentation is to use the following format:

def room_map():
"""
Displays a map of all the accessible rooms from the current room.
"""

When you do this:

try:
    north = rooms[currentRoom]['north']
except:
    north = ""

There are several problems. First, your except clause is way, way too broad. You probably want to catch KeyError. However, the saner thing to do is:

north = rooms.get(currentRoom, {}).get('north', '')

You also have a bunch of code in global scope. This should be reduced - you should move that code into one or more functions.

'You can\'t go that way!'

should simply be

"You can't go that way!"
\$\endgroup\$
0
\$\begingroup\$

Since “Dining Room” (11 characters long) is west of the garden, you probably want

west.rjust(11) + hzt_line + east

for your room map. (You’ll have to increase your centering values to accommodate the additional characters.)


Since ['item'] is often in a room dictionary, the player can type “go item”, moving to the “item” room, crashing the game. You should validate the move directions. One way: instead of move directions stored as keys of the room, store them in a 'exits' dictionary in the room.

'Kitchen' : {
    'exits' : { 'north': 'Hall', 'east': 'Living Room'},
    ...

You can test for many similar conditions using all(...) and list comprehension.

if currentRoom == 'Garden'  and  all(item in inventory for item in ('key', 'matchbox', 'knife')):
    ...

But really you want inventory to be a set. Then you can test:

if currentRoom == 'Garden'  and  inventory >= {'key', 'matchbox', 'knife'}:
    ...
\$\endgroup\$
0
\$\begingroup\$

I'm going to assume that you borrowed code from this page on usingpython.com in order to make this because of the dictionary and the move = input("").lower().split(). No shame in that, it's a useful site. I use it too. Try instead of if item in room and if enemy in room, try if a enemy is in the room. So if a enemy is in the room, then it would display game over if a enemy is in the room, meaning you dont have to add extra items into a room

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Code Review! This answer is a little in the brief side, which isn’t bad but could you expand it a little? Specifically you stated “Try instead of if item in room and if enemy in room, try if a enemy is in the room.” can you explain to the OP what advantages this would have? \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Apr 5 at 23:39
  • \$\begingroup\$ (The diction differs between Axel Sorensen's qustion and the site/code linked: pleas use the terms (monster) from the question.) \$\endgroup\$ – greybeard Apr 6 at 9:29

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.