## 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 = {"n": 0, "e":5}
print("You've opened up a tunnel, leading east...")

def Main():
ans = ""
global location
print(places)
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 # e.g. Take or Drop
noun = words # 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 (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 = {"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)
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 # e.g. Take or Drop
noun = words # 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)
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 # e.g. Take or Drop
noun = words # 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)
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 # e.g. Take or Drop
noun = words # 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?

Now we have the locations sorted, we need to add objects to the game. These will be things such as keys and chests. Later on we’ll add code so that the player can use these objects

Note how I’m only using 3 locations while I write this game. It’s always a good idea to keep things simple. Get the mechanics of the game working first, and then expand it.

Copy and paste the code below 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)
print_objects()

while ans != "bye":
ans = input("What now?")
if ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
print_objects()
else:
print("I can't move that way")

Main()``````

## Exercise

1. Look at the objects dictionary `objects = {“spanner”:0, “lockpick”:0, “spade”:2}`. What do the keys in the dictionary represent? (hint: the key is the part before the colon:)
2. What do the values in the dictionary represent?
3. Add “rope” to the list of objects. Place it in the cave.
4. Add “torch” to the list of objects. Place it in the cabin.
5. Run the code and check the objects are where you think they should be.
6. Look at the print_objects() function. Explain how it works

### Extension

1. Draw your own map for a game. Implement it. Modify the code so that you are using your map.
3. Add code so that if the user types “l” (for look) the game prints out the current location and a list of objects.

## Coin Change Problem

Famously (or at least famously in maths puzzle circles) there are 293 ways to make a US dollar using the following coins:

Penny (1 cent) | Nickel (5 cents) | Dime (10 cents) | Quarter (25 cents) | Half Dollar (50 cents) | Dollar (100 cents)

You could make a dollar with, for example, 4 quarters or 10 dimes.

How many ways are there of making a Brtish pound?

At the time of writing GB currency has the following coins

1p, 2p, 5p, 10p, 20p, 50p and £1 or 100p.

It’s usually a good idea to start problems like this by looking at simpler cases.

If we only have 1p coins, the answer is easy. There’s only 1 way to make any value: 1p = 1, 2p = 1 + 1, 3p = 1 + 1 + 1 etc

How about if we have 1p and 2p coins?

ValuePossibleWays
1p1p1
2p2 x 1p, 2p2
3p3 x 1p, 2p + 1p2
4p4 x 1p, 2p + 2p, 2p + 1p + 1p3
5p5 x 1p, 2 x 2p +1p, 2p + 3 x 1p3

Extend the table and you quickly see a pattern

ValueWays
1p1
2p2
3p2
4p3
5p3
6p4
7p4
8p5
9p5
10p6

We could write the following python code to work out the number of ways of making values with only 1 or 2p coins:

`def coin12(n):     if n%2 == 0:         return int(n/2 +1)     else:         return int((n + 1)/2)`

What about if we have 1p, 2p and 5p coins?

It turns out we can use our previous function to help us work this out.

For example, we could make 8p entirely of 2s and 1s. But this is just coin12(8) ways using the above function

We could make 8p using a 5p coin and 3p made of 2s and 1s: this is coin12(3) ways

This lets us write out the following table.

ValuePossibleWays
1pcoin12(1)1
2pcoin12(2)2
3pcoin12(3)2
4pcoin12(4)3
5p5p, coin12(5)4
6p5p + 1p, coin12(6)5
7p5p + coin12(2), coin12(7)6
8p5p + coin12(3), coin12(8)7
9p5p + coin12(4), coin12(9)8
10p5p + 5p, 5p + coin12(5), coin12(10)10

We can use this to help us write a new function

`def coin125(n):     total =0     while n >= 5:         total += coin12(n)         n -= 5     return total + coin12(n)`

When the function is tested, the results match the table above.

`for i in range (1,11):     print(i ,": " ,coin125(i))`

Now we can look at using the 1p, 2p, 5p and 10p coins. Our coin125 function suggests a way this can be done:

`def coin12510(n):     total =0     while n >= 10:         total += coin125(n)         n -= 10     return total + coin125(n)`

Similarly we could make functions for coins up to 20p, 50p and 100p

I’ve missed out some of the steps below, but working through all the coins I finished up with the following function:

` def coin125102050100(n):     total =0     while n >= 100:         total += coin125102050(n)         n -= 100     return total + coin125102050(n) print(coin125102050100(100))`

Which gave me the correct answer: 4563. In other words, there are 4,563 ways to make £1 using 1p, 2p, 5p, 10p, 20p, 50p and £1 coins.

However.

This isn’t very elegant. Looking at the code we can see we’re doing the same thing over and over again. Also, what if we had a currency that used 100 coins? Or 1000? It would take a lot of copying and pasting to work those problems out.

There has to be a better way.

Let’s look at the functions again. It’s easy to spot a pattern to them. Using pseudocode, they can be written out something like this:

`define coinVALUES(n): total =0 while n >= VALUE:     total += coinVALUES-1(n)     n -= VALUE end while return total + coinVALUES-1(n) end define`

Here’s a first attempt at writing the above in Python

`values = [100, 50, 20, 10, 5, 2, 1] def coin(n, val):     total = 0     while n> values[val]:         total += coin(n, val+1)         n -= values[val]     return total + coin(n, val+1)`

You might notice I’ve written a recursive function, but there’s a problem. There’s no escape clause, there’s nothing to stop the function calling itself forever.

That’s quite easy to fix though

All we have to do is realise that coin1(n) = 1. If you want to make 5p using only 1p coins, there’s only one way to do it: 1p + 1p + 1p + 1p + 1p.

We can use that to add a clause to make a proper recursive function.
It also sorts out an irritating niggle: why should coin12 be different to all the other coin functions?

`values = [100, 50, 20, 10, 5, 2, 1] def coin(n, val):     if values[val] == 1:         return 1     total = 0     while n>= values[val]:         total += coin(n, val+1)         n -= values[val]     return total + coin(n, val+1) print(coin(100,0))`

This works but it’s a little bit messy. I have to call the function with an extra argument, 0, telling it to start at the beginning of the values list.

It would be better to treat coin as a “helper” function and to write another function to call it. This would make the function a lot more user friendly.

I’ve wrapped the coin function in a one called makechange. To show the flexibility of my function, I’ve used makechange to work out how many ways there are to make change from a dollar.

` values = [100, 50, 25, 10, 5, 1] def coin(n, val):     if values[val] == 1:         return 1     total = 0     while n>= values[val]:         total += coin(n, val+1)         n -= values[val]     return total + coin(n, val+1) def makechange(n):     return coin(n,0) print(makechange(100))`

## The Best Programming Language

As Andrew Hunt and David Thomas say in the Pragmatic Programmer, there’s no such thing as the best programming language, just the best programming language for the job in hand.

However, if I had to choose the best language it would be Lisp. Here’s why:

The following code is written in Emacs Lisp. It prints out all the elements of a list

`(cl-loop for element in mylist do (print element))`

In the code below I’ve set mylist to equal the numbers one to five. Evaluating the loop will, unsurprisingly, print the numbers one to five.

`(setq mylist '(1 2 3 4 5))(cl-loop for element in mylist do (print element))=> 1 234 5`

You’re probably thinking you can do the same in Python or Java or whatever your preferred language is, and you’d be right.

But can your preferred language do this?

`(setq mylist '(cl-loop for element in mylist do (print element)))mylist=>   (cl-loop for element in mylist do (print element))`

In the above code I’ve set mylist to be the loop itself.
That means I can set the loop code to loop across itself and print itself out one word at a time.

` (cl-loop for element in mylist do (print element))=> cl-oop for elementin... etc `

In Lisp, code is data. So mylist is data; it’s a list of symbols: cl-loop for element etc. But I can also evaluate mylist in which case mylist will be a set of instructions to loop across itself and print itself out.

`(eval mylist) => cl-oop for elementin... etc   `

Or to put it another way, I’ve just written a list that can read itself!

The thing that makes this possible is the fact that Lisp is a homoiconic language: programs written in such a language can be manipulated as data using the language.

Things like this give me a warm glow inside. They remind me why I love coding so much.

• Moving around three locations

Copy the following code into your IDE and run it.

```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 Main():
ans = ""
global location
print(places)

while ans != "bye":
ans = input("What now?")
if ans in moves[location]:
location = moves[location].get(ans)
print(places[location])
else:
print("I can't move that way")

Main()
```

## Exercise

1. How do you exit the game?
2. What sort of data structure has been used to store the places?
3. What sort of data structure has been used to store the moves?
4. What does the variable location do?
5. Give some valid moves.
6. How does the code check if a move is valid?
7. Which line of code sets the new location?
8. Look at the map below. Add the extra locations to the game.
9. Run the code and check that it works.

## Writing Better Code 1

The number 28 has 6 divisors:

1,2,4,7,14,28

The number 5 only has 2 divisors:

1,5

Write a program to find all the divisors of a number.

The mod operator is useful here. Remember that the mod operator gives the remainder when two numbers are divided, so

```28 % 14 = 0
28 % 5  = 3
```

We can use the mod function to write code as follows

```def divisors(n):
divs = []
for i in range(1,n+1):
if n%i == 0:
divs.append(i)
return divs

print(divisors(28))
```

The above code is inefficient. To find the divisors of 28, you have to go through the for loop 28 times. To find the divisors of n, we have to go through the for loop n times. We say the code has time complexity O(n).

Try running the code to find the divisors of a large number such as 1347663998. You’ll notice it takes a long time to find the answer. We need a way to make the code more efficient.

You should notice that the divisors come in pairs. (1,28, 2,14 4,7). This suggests a way of saving loops. Rather than looking at all the numbers, we could look at just half of them.

```import math

def divisors(n):
divs = []
for i in range(1,int(n/2)):
if n%i == 0:
divs.append(i)
divs.append(int(n/i))
return divs

print(divisors(28))

```

That seems better, but testing we get repeated divisors

[1, 28, 2, 14, 4, 7, 7, 4]

Thinking about it further we see that we only need to count as far as the square root of n (because root n * root n = n)

```import math

def divisors(n):
divs = []
for i in range(1,int(math.sqrt(n))):
if n%i == 0:
divs.append(i)
divs.append(int(n/i))
return divs

print(divisors(28))
```

There’s still a problem though.

Run the above code with divisors(9) and you just get

[1, 9]

Isn’t 3 a divisor of 9? The problem lies in our range. We’re counting up to one less then root 9. Let’s tweak the code to take this case into account.

```import math

def divisors(n):
divs = []
for i in range(1, int(math.sqrt(n))):
if n%i == 0:
divs.append(i)
divs.append(int(n/i))
if math.sqrt(n).is_integer():
divs.append(int(math.sqrt(n)))
return divs

print(divisors(9))
```

We’ve now got working code that runs a lot faster than the original code.

There are a couple of further tweaks we can make.

Firstly, all numbers are divisible by 1 and themselves, so we can just append them without checking.

Odd numbers are never divisible by even numbers.  So, if n is odd, we only need to check if n is divisible by 3, 5, 7 …

If n is even we need to check all numbers from 2 onwards.

```import mathdef divisors(n):    divs = []    step = 1    start = 2    if n%2 == 1:        step = 2        start = 3    for i in range(start, int(math.sqrt(n)), step):        if n%i == 0:            divs.append(i)            divs.append(int(n/i))    if math.sqrt(n).is_integer():        divs.append(int(math.sqrt(n)))    divs.append(1)    divs.append(n)    return divs
```

One last thing. In the new code the following calculation appears three times: math.sqrt(n)

It takes the computer a lot longer to work out square roots than to do other calculations. Now, a good compiler should notice this. It will perform optimisation on your code and will store repeated calculations to stop them having to be worked out over and over again.

However, it might be more elegant to adjust your code as follows.  I’ve also added a line to sort the divisors into order.

```import math
def divisors(n):    divs = []    rootn = math.sqrt(n)    step = 1    start = 2    if n%2 == 1:        step = 2        start = 3    for i in range(start, int(rootn), step):        if n%i == 0:            divs.append(i)            divs.append(int(n/i))    if rootn.is_integer():        divs.append(int(rootn))    divs.append(1)    divs.append(n)    divs.sort()    return divs```

## Code is Poetry

Brian Bilston has written a History of Modern Art in Poetry.  I  wondered what it would be like to do something similar in various programming languages.

Here’s the original poem:

Roses are red
Violets are blue
Sugar is sweet
And so are you

Here’s the poem constructed using a zip statement in Haskell

```Prelude> zip ["roses","violets","sugar","you"]["red","blue","sweet","sweet"]
[("roses","red"),("violets","blue"),("sugar","sweet"),("you","sweet")]```

The list produced holds the relationship that sugar is sweet and you are sweet. The comparison between “you” and sugar is not made clear.

### Lisp

Here’s the poem stored as an alist in Lisp

```(setq poem '(("roses" . "red") ("violets" . "blue") ("sugar" . "sweet")("you" . "sweet")))
(mapcar (lambda (x) (concat (car x) " are " (cdr x))) poem)```

I’ve gone one stage further here, using a mapcar function to produce something that looks a little bit more like the original poem, however we’re still missing the connection between “you” and sugar.

`("roses are red" "violets are blue" "sugar are sweet" "you are sweet")`

### Python

Of course, sugar are sweet isn’t right.   Let’s try some Python.

```poem = {"roses":"red","violets":"blue","sugar":"sweet","you":"sweet"}

for key, value in poem.items():
if key == "sugar":
print(key, "is" ,value)
else:
print(key, "are", value)
```

This output is at least grammatically correct.

```roses are red
violets are blue
sugar is sweet
you are sweet
```

### Java

Java can do something similar using a HashMap

```Map<String, String> poem = new HashMap<String, String>();

poem.put("roses", "red");
poem.put("violets", "blue");
poem.put("sugar", "sweet");
poem.put("you", "sweet");

for (Map.Entry<String, String> entry : poem.entrySet()) {
if(entry.getKey().equals("sugar")){
System.out.println(entry.getKey() + " is " + entry.getValue());
} else{
System.out.println(entry.getKey() + " are " + entry.getValue());
}

}
```

But we’re still no closer to conveying the connection between “you” being sweet, just like sugar is sweet.

Fortunately, Java allows us to use some object oriented design to better convey the meaning of the poem.

In the example below I’ve used an interface to allow sweetness to be applied to both sugar and to the special one to whom the poem refers.  The comparison is at last made clear.  As there can only be one true love, it seemed reasonable to make a singleton class for TheOne, inherited from a regular person.

Run the code and the poem is printed out properly, just like the original.  More importantly though, the concepts to which the poem refers are properly encapsulated and related.

The original poem was only 4 lines long.  My implementation takes 80 lines, but I think you’ll agree I’ve done a rather better job, providing clarity and removing any ambiguity.

```public class Love {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Flower [] rose = new Flower; // 12 roses in a bunch
Flower [] violet = new Flower; // more violets in bunch
Sugar sugar = new Sugar();
TheOne myLove = TheOne.getInstance();  // Singleton class
// There can only be one true love

rose = new Flower();
rose.setColour("red");  // colour is static so only need
// to instantiate one here

violet = new Flower();
violet.setColour("blue");

System.out.println("Roses are " + rose.getColour());
System.out.println("Violets are " + violet.getColour());
System.out.println(sugar.sweet());
System.out.println(myLove.sweet());
}

}

class Flower {
private static String colour;

public void setColour(String colour){
this.colour = colour;
}

public String getColour (){
return colour;
}
}

class Sugar implements Sweetness {

@Override
public String sweet() {
return "Sugar is sweet";
}

}

class Person {
public String sweet()
{
return "Not sweet";
}
}

class TheOne extends Person implements Sweetness{
private static TheOne instance = null;

private TheOne()
{

}

public static TheOne getInstance()
{
if(instance == null)
instance = new TheOne();

return instance;
}

@Override
public String sweet() {
return "And so are you";
}
}

interface Sweetness {
String sweet();
}
```