## Welcome

This blog’s tagline is adapted from the Emacs Org-Mode motto. It seemed appropriate, as I seem to have spent most of my life writing novels and short stories (of which you can find out more at tonyballantyne.com) or teaching computer coding.

I’ve amassed a lot of material over the years, and I wanted to share it with people who may not have had the same access to education as people living in my country are lucky enough to have. If you want to change the world, become a teacher.

As the the teaching of coding seems to be coming back into fashion, I’ve also included my thoughts on the pedagogy of this subject.

## Recursion Explained Using Sandwiches

• If you put a piece of toast between two slices of bread, you have a toast sandwich.
• If you put a piece of bread between two slices of bread, you have a bread sandwich.
• If you put a piece of bread between two pieces of toast you have a toasted bread sandwich.

It would be nice to have a program that identifies what sort of sandwich we have.

If we’re going to do this we’ll need a way to represent the make up of our sandwich. One way would be to use lists, as follows

• [B,T,B] Toast sandwich

We can now represent more complicated sandwiches such as the following:

• [B,T,B,T,B] Toasted bread sandwich sandwich
• [T,T,B,T,T] Toasted toasted bread sandwich sandwich

Now we have a sandwich data structure, we can write a program that will accept a list such as [B,T,B] as input and then output “Toast sandwich”.

… but before we start reaching for a for loop to traverse that list, let’s just to a moment to notice something. Sandwiches have sandwiches inside them.

If you look at [B,T,B,T,B], a toasted bread sandwich sandwich, you’ll notice that it’s really just a [T,B,T] or toasted bread sandwich wrapped in bread. And in fact, a [T,B,T] is just a piece of bread wrapped in toast.

Let’s do the above backwards

• [B] – A piece of bread
• [T,B,T] – A toasted bread sandwich
• [B,T,B,T,B] – A toasted bread sandwich wrapped in bread, in other words, a toasted bread sandwich sandwich

To check you’ve understood this, try deconstructing a [T,B,T,B,T,B,T]. You should get a toasted toasted bread sandwich sandwich sandwich.

The fact that we can repeatedly reduce this problem to simpler sandwich, two slices at a time, tells us that this problem could be solved by recursion. We’re going to write a recursive function that strips away the sandwich, two slices at a time.

Start by defining a function called SNS (sandwich name service). This function will use python slicing to find the base, top and filling of the sandwich.

If the sandwich contains only one item it will simply be a piece of bread or a piece of toast. A one item sandwich will be the base case or escape clause for our recursive function.

If the sandwich contains more than one item, we’ll remove the outer layers and then call the SNS function again with the filling.

Here are a couple of examples

Input [T]

This is a one item sandwich, so SNS outputs “toast”

Input [B,B,T,B,B]

This is not a one item sandwich, so SNS strips the outer bread layers and then calls itself with the filling:

SNS([B,T,B]) + “sandwich”

Here’s the code:

B = "bread"
T = "toast"

def SNS(sandwich):
base = sandwich[0]
top = sandwich[-1]
filling = sandwich[1:-1]

if len(sandwich) == 1:
return sandwich[0]
if base == top:
if base == B:
return SNS(filling) + " sandwich"
else:
return "toasted " + SNS(filling) + " sandwich"

print(SNS([T,B,B,B,T]))


And there we have it. Sandwiches identified recursively.

There are problems with this code. It doesn’t check for incorrect input. It doesn’t identify even numbered lists correctly as open faced sandwiches or things on toast. Perhaps you could fix that…

## Chessboards

Here’s a chessboard. Each square is 4×4 characters

    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX


What’s the most Emacsy way of producing the above?

## First Line

XXXX    XXXX    XXXX    XXXX

You could do the following:

C-4 <space> 4 Spaces
C-4 X       4 Xs
C-k         Kill line
C-y         Yank
C-x z z z   Repeat last command three times


Another way is to use a macro:

F3          Start recording
C-4 <space>
C-4 X
F4          Stop recording
F4 F4 F4    Run the macro three times


Once you have one line, you could copy it and then yank it three times to get the first line of squares.

Here’s another way to get a line of squares, this time using rectangles. See this post to remind yourself about rectangles.

C-16 X
Kill and yank to get the following:

XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX


Now insert the white squares:

Go to start of the pattern

Set the region to cover the first square
C-x r o to insert blank space to fill the space of the region-rectangle

XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX

Now move the point forward 8 so its at the correct position to open the next square

C-8 C-f

You can record a macro of the above and then run it 3 times. Don’t forget to add the C-8 C-f at the end to move the point to the correct starting position.

## 2 The Second Line

Once you have the first line of squares, the second is quite easy. Copy one line of squares beneath itself to get the following:

    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX

And then use C-x r k to kill the white square at the start of the second line.

    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX


Now you can just kill and yank four times to get the complete chessboard.

Of course, you could just do it in LISP:

(defun one-line(pattern)
"Insert PATTERN 4 times"
(dotimes (count 4)
(insert pattern)))

(defun four-lines(pattern)
"Insert 4 lines of PATTERN"
(dotimes (count 4)
(one-line pattern)
(insert "\n")))

(defun chess-board()
(interactive)
(dotimes (count 4)
(four-lines "    XXXX")
(four-lines "XXXX    ")))

M-x chess-board

Can you think of a more efficient method than the ones above? Why not post it below?

## Emacs Characters 3

I never thought I would write three posts about entering characters in Emacs.

Emacs Characters demonstrates the quickest way to insert characters such as è and ä by using the C-x 8 key combination. So, for example:

C-x 8 ' e prints é
C-x 8 e prints è
C-x 8 ^ e prints ê
C-x 8 " u prints ü
C-x 8 / / prints ÷
C-x 8 C prints © copyright

Emacs Characters 2 shows how C-x 8 [return] allows you to type in the description of a character, so C-x 8 [return] LEFT ARROW gives ←

It’s time for another way. This post demonstrates toggle-input-method. Emacs has a number of input methods, used for entering such things as Arabic characters. You can see the full list using

 M-x list-input-methods 

Use C-\ to enable the input method. The first time you do this you’ll be prompted for a method. For the purposes of this post, enter TeX. If you don’t know TeX, this post gives you a flavour.

You can now enter characters using TeX. Here are some examples

\pir^2 → πr²
Z\"urich → Zürich
Caf\'e  → café

I used \rightarrow to get the → used above, by the way.

When you’re done using TeX, use C-\ to disable the current input method

That’s three different methods for entering text. Which one is best? For me, it’s whichever is the most convenient. If I want to type the acute accent in café I’d probably use C-x 8 ‘e. When I was writing my novel Dream Paris I used TeX input for typing in the French dialogue.

As this is the Emacs workout, why not think of the ways you could type the following in Emacs?

Einstein wrote E=mc² on the table whilst eating a rösti in a café in Zürich. As easy as πr², he thought.

If you get stuck

M-x describe-input-method 

will give a list of key sequences.

## Common Lisp Loops

I can’t think why you wouldn’t use the Common Lisp loop macro in Emacs. Don’t forget to (require ‘cl-lib)

### Simple Loops

;; keywords: to, upto, below, downto, above, by
;; keywords: collect, append, nconc, count, sum, maximize, minimize

(cl-loop
do (princ 1))
=> 111111... infinite loop

(cl-loop repeat 5
do (princ 1)
(princ 2))
=> 1212121212

(cl-loop for i from 1 below 10
maximize i)
=> 9

(cl-loop for x from 9 downto 1
collect x)
=> (9 8 7 6 5 4 3 2 1)

(cl-loop for i from 10 above 1 by 2
collect i)
=> (10 8 6 4 2)

### Looping over Sets and Arrays

;; keywords: in, on, across, by
;; Remember in for lists
;; across for vectors

(cl-loop for l in '(1 2 3 4 5)
do (princ l))
=> 12345

(cl-loop for l in '(1 2 3 4 5) by #'cddr
collect l)
=> (1 3 5)

(cl-loop for l on '(1 2 3 4 5)
collect l)
=> ((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5))

(cl-loop for l on '(1 2 3 4 5) by #'cddr
collect l)
=> ((1 2 3 4 5) (3 4 5) (5))

;; Remember that a string is an array in lisp, so...
;; Add up the digits in 90125
(cl-loop for d across "90125"
sum (- d 48))
=> 17

### Destructuring

(cl-loop for (a nil) in '((1 2) (2 3) (3 4))
collect a)
=> (1 2 3)

(cl-loop for (a b) in '((1 2) (2 3) (3 4))
collect (* a b))
=> (2 6 12)

(cl-loop for (a b) on '(1 2 3 4 5) while b
collect (+ a b))
=> (3 5 7 9)

(cl-loop for (a b) on '(1 2 3 4 5) by #'cddr while b
collect (+ a b))
=> (3 7)

### Hashtables

(cl-loop for key being the hash-keys of myhashtable
using (hash-value value)
do (princ value))

### Parallel fors

(cl-loop for i from 1 to 5
for l in '(a b c d)
collect (list i l))
=> ((1 a) (2 b) (3 c) (4 d))

(cl-loop for i from 1 to 5
for j from 2 to 10 by 2
collect (* i j))
=> (2 8 18 32 50)

### Nested fors

(cl-loop for i from 1 to 5
collect (cl-loop for j from 1 to 5
collect (* i j)))
=> ((1 2 3 4 5) (2 4 6 8 10) (3 6 9 12 15) (4 8 12 16 20) (5 10 15 20 25))

(cl-loop for i from 1 to 5
append (cl-loop for j from 1 to 5
collect (* i j)))
=> (1 2 3 4 5 2 4 6 8 10 3 6 ...)

(cl-loop for i from 1 to 5
collect (cl-loop for j from 1 to 5
sum (* i j)))
=> (15 30 45 60 75)

(cl-loop for i from 1 to 5
sum (cl-loop for j from 1 to 5
sum (* i j)))
=> 225

### Selection

;; if, when, unless

(cl-loop for i from 1 to 20
unless (cl-evenp i) collect i)
=> (1 3 5 7 9 11 13 15 17 19)

(cl-loop for i from 1 to 20
when (= (% i 3) 0) collect i into fizz
when (= (% i 5) 0) collect i into buzz
finally return (list fizz buzz))
=> ((3 6 9 12 15 18) (5 10 15 20))

(cl-loop for i from 1 to 20
if (and (= (% i 3) 0) (= (% i 5) 0)) collect i into fizzbuzz
else if (= (% i 3) 0) collect i into fizz
else if (= (% i 5) 0) collect i into buzz
finally return (list fizz buzz fizzbuzz))
=> ((3 6 9 12 18) (5 10 20) (15))

(cl-loop for i from 1 to 10
if (cl-evenp i)
collect i into evens
and sum i into evensum
else
collect i into odds
and sum i into oddsum
finally return (list evens evensum odds oddsum))
=> ((2 4 6 8 10) 30 (1 3 5 7 9) 25)

Find c from comp where diff is never a member of squares
(cl-loop for c in comp
if  (cl-loop for p in pri
for diff = (/ (- c p) 2)
never (member diff squares))
collect c)

### Then Iteration

(cl-loop for i from 1 to 5
for square = (* i i)
collect square)

;; Though you'd be better with
(cl-loop for i from 1 to 5
collect (* i i))

;; However, this leads to Triangle Numbers
(cl-loop for n from 1 to 10
for triangle = 1 then (+ triangle n)
collect triangle)
=> (1 3 6 10 15 21 28 36 45 55)

(cl-loop for x = 0 then y
for y = 1 then (+ x y)
while (< y 30)
collect y)
=> (1 2 4 8 16)

;; Fibonacci Sequence (note the and)
(cl-loop for x = 0 then y
and y = 1 then (+ x y)
while (< y 30)
collect y)
=> (1 1 2 3 5 8 13 21)

### Termination

;; while, until, always, never, and thereis

while and until are straightforward

(cl-loop for n from 1
for tri = 1 then (+ tri n)
until (> (divs tri) 500)
finally return tri)

never, thereis and always are shorthand for a combination of when-return

(defun isprime(n)
(cond
((< n 2) nil)
((= n 2) t)
((cl-evenp n) nil)
(t
(cl-loop for i from 3 to (sqrt n) by 2
never (= (% n i) 0)))))

## Adventure Game 8: Making a Playable Game

Now we have a working game engine, we need to make the game more interesting.

We can do this in a number of ways.

1. Think of an interesting setting: in a castle, on a spaceship, in a school for witches and wizards…
2. What quest are we setting the player? To find the gold? Escape from the space station before it explodes? To find the spy?
4. What sort of objects could we use? Magic wands, rayguns, teleporters?
5. What sort of puzzles and riddles could we add?

## Exercise

1. Think of the setting for your game. What does the player have to do (what’s their quest?)
2. Draw a map for your game (see lesson 1 for an example) Don’t add too many locations – 16 is more then enough.
3. Think of the objects the player will have to use and add them to the map.
4. Make a note of the game play. What will the player have to do to complete the game.
5. Now modify the code of the game engine to write your own game.
6. Get your partner to play the game and feedback.
7. Make any improvements to the game.

## Adventure Game 7: Robust Code

We now have a working game, however the code isn’t very robust. Robust code continues to function when errors occur.

Here’s an example of the start of a game:

A clearing in a forest
spanner
lockpick
What now?use spoon
Traceback (most recent call last):
Main()
if (objects[noun]==99): # check holding object
KeyError: 'spoon'

Process finished with exit code 1

There are two problems here, one minor, one major.

The minor problem occurs when the user types use spade. Nothing happens as the user isn’t holding a spade, but the program doesn’t alert the user to that fact.

The major problem occurs when the user tries to use spoon. At that point the program throws an exception and terminates.

An exception is an error that occurs when the program is running and causes the program to terminate. In this case, the program is trying to look up an object that doesn’t exist. We need to handle this exception.

The following code deals with both the above problems.

elif verb == "use":
try:
if (objects[noun]==99): # check holding object
use_object(noun)
else:
print("I don't have a", noun)
except:
print("I don't know what a", noun, "is")

You will see try except in many pieces of python code. It’s the professional way to write robust code

Here’s the complete code. Copy and paste it into your IDE

places = ["A clearing in a forest", "An old wooden cabin", "A dark cave", "The top of a Hill", "Deep in the Forest", "An Underground Lake", "Caught in the Brambles"]
moves = [{"n": 1, "s": 2, "e":4},     {"s": 0, "e":3},       {"n": 0} ,     {"w": 1, "s":4},    {"n":3,"w":1, "e":6}, {"w": 2},             {"w": 4}]
location = 0

def print_objects():
for key, val in objects.items():
if val == location:
print(key)

def items():
print("You are carrying: ")
for key, val in objects.items():
if val == 99:
print(key)

def take_object(noun):
for key, val in objects.items():
if key == noun and val == location:
print("Got it!")
objects[noun] = 99

def drop_object(noun):
for key, val in objects.items():
if key ==noun and val == 99:
print("Dropped ", noun)
objects[noun] = location

def use_object(noun):
if noun == "spade" and location == 0:
objects["gold"] = 0 # create the gold
print("You dug up some gold!")
if noun == "spade" and location == 2:
moves[2] = {"n": 0, "e":5}
print("You've opened up a tunnel, leading east...")

def Main():
ans = ""
global location
print(places[0])
print_objects()

while ans != "bye":
ans = input("What now?")
words = ans.split()

# Check if it's a move
if len(words) == 1:
if ans == "items":
items()
elif ans == "look":
print(places[location])
print_objects()

elif ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
print_objects()
else:
print("I can't move that way")
else:
verb = words[0] # e.g. Take or Drop
noun = words[1] # e.g. hammer or spanner

if verb == "take":
take_object(noun)

elif verb == "drop":
drop_object(noun)

elif verb == "use":
try:
if (objects[noun]==99): # check holding object
use_object(noun)
else:
print("I don't have a", noun)
except:
print("I don't know what a", noun, "is")

else:
print("I don't understand what you mean")

Main()

## Exercise

1. Copy the above code into your IDE and test it.
2. Run the code. What happens if you try to take the spade in the clearing in the forest?
3. Is the behaviour of the code here an error or an exception?
4. Fix the code.
5. What errors can occur when a user tries to drop an object? Fix those errors.
6. What other errors can you find in the code?
7. Are there any other exceptions you can find in the code?

## Adventure Game 6: Using Objects

We’ve set up the basics of the game, but it’s not much fun. All you can do is wander round picking up and dropping objects. We need to allow the user to use the objects. We’re going to add two ways of using objects.

• If the player uses the spade in the clearing in the forest they will dig up gold.
• If the player uses the spade in the cave they will open a path to an underground lake.

Note that I’ve added new locations to the map, the same ones we added in Exercise 1

places = ["A clearing in a forest", "An old wooden cabin", "A dark cave", "The top of a Hill", "Deep in the Forest", "An Underground Lake", "Caught in the Brambles"]
moves = [{"n": 1, "s": 2, "e":4},     {"s": 0, "e":3},       {"n": 0} ,     {"w": 1, "s":4},    {"n":3,"w":1, "e":6}, {"w": 2},             {"w": 4}]
location = 0

def print_objects():
for key, val in objects.items():
if val == location:
print(key)

def items():
print("You are carrying: ")
for key, val in objects.items():
if val == 99:
print(key)

def take_object(noun):
for key, val in objects.items():
if key == noun and val == location:
print("Got it!")
objects[noun] = 99

def drop_object(noun):
for key, val in objects.items():
if key ==noun and val == 99:
print("Dropped ", noun)
objects[noun] = location

def use_object(noun):
if noun == "spade" and location == 0:
objects["gold"] = 0 # create the gold
print("You dug up some gold!")
if noun == "spade" and location == 2:
moves[2] = {"n": 0, "e":5}
print("You've opened up a tunnel, leading east...")

def Main():
ans = ""
global location
print(places[0])
print_objects()

while ans != "bye":
ans = input("What now?")
words = ans.split()

# Check if it's a move
if len(words) == 1:
if ans == "items":
items()
elif ans == "look":
print(places[location])
print_objects()

elif ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
print_objects()
else:
print("I can't move that way")
else:
verb = words[0] # e.g. Take or Drop
noun = words[1] # e.g. hammer or spanner

if verb == "take":
take_object(noun)

elif verb == "drop":
drop_object(noun)

elif verb == "use":
if (objects[noun]==99): # check holding object
use_object(noun)

else:
print("I don't understand what you mean")

Main()

## Exercise

1. Copy the code into your IDE. Move around the map to see the new locations
2. Find the spade and use it to dig up gold in the forest
3. Now dig in the cave and check to see the path to the lake opens up.
4. Look at the function use_object(noun). What’s the purpose of the statement objects["gold"] = 0
5. Look at the moves list (line 2). What has been added to the first dictionary in the list?
6. Look at moves[2] (remember, this is the third item in the list). At the moment this is {“n”: 0}. What does that mean?
7. Look at the function use_object(noun). What is the purpose of the line moves[2] = {"n": 0, "e":5} (hint, this is only called if the noun is a spade)
8. Add the following objects to the map: telescope in the wooden cabin, cutters deep in the forest.
9. Add code so if the user uses the telescope on top of the hill they see a message written on a sign saying “There is treasure in the forest”
10. Add code so if the user uses the cutters when caught in the brambles, treasure appears.

We’re going to add two new commands, Look and Items

• Look will show your current location and objects
• Items will show the items you’re currently carrying
places = ["A clearing in a forest", "An old wooden cabin", "A dark cave"]
moves = [{"n": 1, "s": 2},           {"s": 0},              {"n": 0}]
location = 0

def print_objects():
for key, val in objects.items():
if val == location:
print(key)

def items():
print("You are carrying: ")
for key, val in objects.items():
if val == 99:
print(key)

def take_object(noun):
for key, val in objects.items():
if key == noun and val == location:
print("Got it!")
objects[noun] = 99

def drop_object(noun):
for key, val in objects.items():
if key ==noun and val == 99:
print("Dropped ", noun)
objects[noun] = location

def Main():
ans = ""
global location
print(places[0])
print_objects()

while ans != "bye":
ans = input("What now?")
words = ans.split()

# Check if it's a one word input
if len(words) == 1:
if ans == "items":
items()
elif ans == "look":
print(places[location])
print_objects()
elif ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
print_objects()
else:
print("I can't move that way")
else:
verb = words[0] # e.g. Take or Drop
noun = words[1] # e.g. hammer or spanner

if verb == "take":
take_object(noun)

elif verb == "drop":
drop_object(noun)

else:
print("I don't understand what you mean")

Main()

## Exercise

1. Look at the Main() function. Why is location a global variable?
2. List the one word commands that are permitted in this program
3. What does the printobjects() function do?
4. Look at the items() function. Why does it only print items where val =99?

You’re going to add a help function. If the user enters “help” the program will print the following instructions: “Type n,s,e,w to move north, south, east and west.”

1. Add an elif statment under the elif ans == “look”: statement to check if the user has entered “help”
2. Add code to print the help instructions

## Adventure Game 4: Structured Programming

The program is becoming very complicated. We need to apply structured programming techniques to make it easier to follow. According to the specification this means:

“Using modularised programming, clear, well documented interfaces (local variables, parameters) and return values.”

Copy the following code into your IDE

places = ["A clearing in a forest", "An old wooden cabin", "A dark cave"]
moves = [{"n": 1, "s": 2},           {"s": 0},              {"n": 0}]
location = 0

def print_objects():
for key, val in objects.items():
if val == location:
print(key)

def take_object(noun):
for key, val in objects.items():
if key == noun and val == location:
print("Got it!")
objects[noun] = 99

def drop_object(noun):
for key, val in objects.items():
if key ==noun and val == 99:
print("Dropped ", noun)
objects[noun] = location

def Main():
ans = ""
global location
print(places[0])
print_objects()

while ans != "bye":
ans = input("What now?")
words = ans.split()

# Check if it's a move
if len(words) == 1:
if ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
print_objects()
else:
print("I can't move that way")
else:
verb = words[0] # e.g. Take or Drop
noun = words[1] # e.g. hammer or spanner

if verb == "take":
take_object(noun)

elif verb == "drop":
drop_object(noun)

else:
print("I don't understand what you mean")

Main()


## Exercise

1. Copy the code into an IDE and run it. Check that it works
2. Give an example of a local variable in the code.
3. Give an example of a global variable.
4. Give an example of a parameter.
5. How many functions have parameters passed to them?
6. What are the advantages of the modular approach?
7. Add a function eat_object(noun). The function will print “I can’t eat” + noun.
8. Add code to the Main method to call the eat_object() function

## Adventure Game 3: Take and Drop Objects

We added objects to the game in the last lesson. Now we’re going to add code to allow the user to take and drop objects

Copy and paste the following code into your IDE

places = ["A clearing in a forest", "An old wooden cabin", "A dark cave"]
moves = [{"n": 1, "s": 2},           {"s": 0},              {"n": 0}]
location = 0

def print_objects():
for key, val in objects.items():
if val == location:
print(key)

def Main():
ans = ""
global location
print(places[0])
print_objects()

while ans != "bye":
ans = input("What now?")
words = ans.split()

# Check if it's a move
if len(words) == 1:
if ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
print_objects()
else:
print("I can't move that way")
else:
verb = words[0] # e.g. Take or Drop
noun = words[1] # e.g. hammer or spanner
if verb == "take":
for key, val in objects.items():
if key == noun and val == location:
print("Got it!")
objects[noun] = 99
if verb == "drop":
for key, val in objects.items():
if key ==noun and val == 99:
print("Dropped ", noun)
objects[noun] = location

Main()

## Exercise

1. Run the game. Take the spanner and drop it in the cave. Check that everything is working correctly.
2. Add a spoon to the list of objects. Place the spoon in the cave. Check that you can Take it and Drop it.
3. What happens if you enter “take elephant?”
4. Look at the line words = ans.split() in the Main() function. What does it do? (try experimenting with the code in IDLE if you’re unsure)
5. Look at the if statement in the Main() function: if len(words) == 1: Why was that code included?
6. Look at the statement if verb == "take": What do key and val mean in the for loop?
7. What is the purpose of the for loop?
8. What is the purpose of the line 'objects[noun] == 99'
9. Look at the if verb = "drop" `statement. Why does the for loop check if key = noun and val == 99?