Part 3

Picking things up

Do you remember we said back in Part 1 that there was a torch in the first room? Let’s make it possible for the player to pick this up.

At the moment the player can only state a dirction to go in, by typing N, E, S, or W. So we need to expand the vocabulary that the player can use to make it possible to pick things up, go in directions and for any other actions we think of in the future.

So instead of just a direction let’s ask the player for a command, so that they can enter things like this:

  • go west

  • take torch

  • eat apple

Verbs and nouns

Each command will be a verb followed by a noun. Let’s explore in the console on the right side of your screen. Add these lines one at a time – don’t enter the lines that start with a hash (#).

c = input("What do you want to do? ")

# You'll ender something here like: go east

c
c.split(" ")

# You'll see the first line just returns what you typed, but
# the second returns a list of [noun, verb], that's just
# what we need!

(verb, verb) = c.split(" ")
if verb == "go": print("Going", noun)

# Assuming you entered "go ..." then you should see Python
# spot this.

So hopefully you can see from the examples above that we can ask the player for instructions and understand them.

Let’s add a new function so that we can add this to our adventure!

Add this code to the top of your program:

def player_action(directions, objects):
  c = input("What do you want to do? ")
  (verb, noun) = c.lower().split(" ")
  return verb, noun

You might notice that we’ve stopped checking what the player types in. We’ll come to that soon, but let’s first see how we call this function.

Now change your entrance function like so:

def entrance():
  print()
  print("You are standing in the entrance to a huge cave network.")
  print("You can see a torch on the ground, and can see two tunnels")
  print("One to the North, one on the South")

  (verb, noun) = player_action(['n', 's'], ['torch'])

  if verb == "go":
    if noun[0] == 'n':
      room2()
    if noun[0] == 's':
      room3_death()

  if verb == "take":
    if noun == "torch":
      print("You take the torch")

Test it and see if that works. It is quite likely that if you go north or south you’ll get an error because we’ve not changed the rooms to use this new function yet.

Fixing the errors

Let’s do some testing to see what errors we can find. Have a play and write down everything that doesn’t work – there’s quite a list!

When you’ve done that, scroll down and see if your list matches ours…

Bug list

  1. If you enter nothing, you get an error: ValueError: not enough values to unpack (expected 2, got 1)

  2. If you enter too many words, e.g. take the apple, you get an error: ValueError: too many values to unpack (expected 2)

  3. You can use any verb, e.g. eat apple

  4. You can ask to go in any direction, not just those available, e.g. go west

  5. You can try taking things that don’t exist: take apple

Let’s fix these one at a time.

Not the right number of words

In the first two errors, ValueError is Python’s way of saying that when we try and split the player’s input it won’t match our two variables: verb and noun.

We can catch this error and ask the player to try again. Let’s change your player_action function to do this:

def player_action(directions, objects):

  while True:
    c = input("What do you want to do? ")
    try:
      (verb, noun) = c.lower().split(" ")
      break
    except ValueError:
      print("I don't understand")

  return verb, noun

So, what does that all do?

  1. You’ll have seen while True before, it means keep trying until something works and we break out of the loop.

  2. try tells Python that if anything goes wrong, look for a matching except for the error.

  3. And that’s what we see on line 8: except ValueError, if this happens we say we don’t understand and round we go again.

Only two commands

OK, so the player should only be able to use two commands: go in a direction and take things. Let’s fix this.

Make the following changes to your function:

def player_action(directions, objects):

  while True:
    c = input("What do you want to do? ")
    try:
      (verb, noun) = c.lower().split(" ")
      # no break here now
    except ValueError:
      print("I don't understand")
      continue

    if verb == "go":
      break
    elif verb == "take":
      break
    else:
      print("I only understand two commands: go, take")

  return verb, noun

We’ve swapped out the break and added a continue. Continue means go back to the start of the loop, which means the player is asked again for their command.

We’ll expand those if-statements in a tick to check for directions and things being taken.

If you haven’t tested your new code, go ahead and do this. You should find that errors 1,2 and 3 have been fixed.

Checking the nouns

Finally let’s check the directions and objects to squash the last two bugs.

Change your code like so:

def player_action(directions, objects):

  while True:
    c = input("What do you want to do? ")
    try:
      (verb, noun) = c.lower().split(" ")
    except ValueError:
      print("I don't understand")
      continue

    if verb == "go":
      if noun[0] in directions: break
      else: print("You can't go in direction", noun)
    elif verb == "take":
      if noun in objects: break
      else: print("There is no", noun, "to take")
    else:
      print("I only understand two commands: go, take")

  return verb, noun

Updating our room functions

Great, so now we have a function to discover the next player action, so we can update all of our room functions to use this.

We’ve already changed the entrance function, so we can use this as a guide for the other functions.

Here’s what entrance looks like now:

def entrance():
  print()
  print("You are standing in the entrance to a huge cave network.")
  print("You can see a torch on the ground, and can see two tunnels")
  print("One to the North, one on the South")

  (verb, noun) = player_action(['n', 's'], ['torch'])

  if verb == "go":
    if noun[0] == 'n':
      room2()
    if noun[0] == 's':
      room3_death()

  if verb == "take":
    if noun == "torch":
      print("You take the torch")

And if we look at one of our other room functions we’ll see something like this:

def room2():
  print()
  print("You crawl through into a small space, it is quite dark")
  print("You can just make out a hole to the east leading to a space below, and to the south you can see a tunnel.")

  go = what_to_do(['e', 's'])

  if go == 'e':
    room5()
  if go == 's':
    entrance()

Do you see what lines we need to change? Here’s an updated function with the new lines in yellow:

def room2():
  print()
  print("You crawl through into a small space, it is quite dark")
  print("You can just make out a hole to the east leading to a space below, and to the south you can see a tunnel.")

  (verb, noun) = player_action(['e', 's'], [])

  if verb == "go":
    if noun[0] == 'e':
      room5()
    if noun[0] == 's':
      entrance()

Next up

In the next part, coming soon, we’ll allow our player to pick things up and use them in our world.