# Choose Your Own Pyventure/Wandering Grue

**Functions Case Study: Wandering Grue**

Let's say you'd like to have a wandering Grue in your Mysterious House that randomly pops up in a room (or rooms).

One way to do this is to make a function that decides whether the Grue is in the room or not:

** Test Frameowrk **

Later in our complete code, we will see code similar to:

```
eaten=grue()
if eaten:
print "Sadly, you were torn limb-from-limb by the Grue and suffered a slow, painful death."
else:
print "Congratulations, you have not been eaten by the Grue! May you have a long happy life."
```

Here we introduce a new python data type: `boolean`

. Python **booleans** can take two values `True`

and `False`

. These code fragments are
equivalent:

if x > 3: print "yep!" if x > 3 is True: print "yep!" if bool(x>3) is True: print "yep!"

The "if" syntax *implies* **if predicate is True**. In Python, most things
evaluate to `True`

, **except**: None, False, 0 (0.0, etc.),
empty strings, zero-length lists, dicts, and few other oddities ^{[1]}.

**Variation 1: not very random **

```
def grue_always():
''' this grue always appears. returns true'''
return True
```

Our not very random grue *always* appears.

*Exercise*: Make the reverse -- a grue that *never* appears. The signature
of the function should be `grue_never() -> False`

**Variation 2: the 50/50 Grue **

```
import random
## random is a Python module, as mentioned above.
## We need to import it to access the random() function.
## now to begin the function definition
## Everything inside the function definition is indented! Remember, white space matters!
def random_grue():
''' boolean. a grue that appears 50% of the time '''
## we want something that will return True 50% of the time.
## one method: get a random float between (0,1), and return True if it's over .5
## now we need a random number. random() will give us one between 0 and 1
n=random.random() ## the random before the dot tells Python what module to look in for the function, which is the one we imported above
if n > 0.5:
grue=1 ## 1 == True
else:
grue=0 ## 0 == False
return grue ## returning allows us to capture the value
```

So what does the random_grue() function do? Let's try it. In the Python interpreter:

>>> import random >>> def random_grue(): n=random.random() if n>0/5: grue = 1 else: grue = 0 return grue >>> random_grue() 1

The first command is to import the random module, the second is to define the function and the third is to actually call the function. The 1 is the return of the function. You may get a 1 or a 0 depending on the number random() generated. (Hint: try running it several times)

> A digression on pseudorandom numbers, and tips for getting the same ones every time!

**Variation 2: the Moody Grue **

```
import random
def grue_moody(cutoff=.5):
''' boolean. a grue that appears (100*cutoff)% of the time '''
n=random.random()
above_cutoff = n < cutoff
return above_cutoff
def grue_moody2(cutoff=.5):
''' boolean. a grue that appears (100*cutoff)% of the time '''
return random.random() < cutoff
```

Note that we simplified down the function quite a bit by returning the boolean
value directly (especially in 'grue_moody2'), rather than doing any conditional logic
to get a 1 or 0. Also notices that we specified a **default value** for
the argument `cutoff`

.

*Exercises*

- Predict the behaviour of these functions calls. Then try them.
- grue_moody()
- grue_moody(-1)
- grue_moody(1)
- grue_moody("a")
- grue_moody([1,2,3])

**Fix**the code so that it prints an angry message and returns`None`

if n is outside the interval (0,1).- try
`help(grue_moody)`

. What do you see? - what are the types of
`random`

,`random.random`

,`random.random()`

**Variation 3: the location, location, location Grue **

In our final variation, we want a grue that:

- has different percentages of appearing based on which page
- should have zero chance of appearing in the main room "foyer"
- should have a default chance of appearing of 5% in rooms that aren't otherwise described

```
import random
grue_fractions = { 'foyer':0, 'thedark': 1.0, 'nocake': .2 }
def location_grue(room=None, base=.05, cutoffs=dict()):
''' (boolean), does a grue appear in the room?
room : str room name
base : 'cutoff', float between (0,1), for base (room not found)
cutoffs: dict of room_name: cutoff (float between 0,1)
'''
cutoff = cutoffs[room]
return random.random() < cutoff
```

*Exercises*

- as written,
`location_grue`

has some bugs, and doesn't meet spec. Identify and fix them.- try: location_grue('foyer', cutoffs=grue_fractions)
- what happens if 'room' isn't in 'cutoffs'?
- research the 'get' method of dictionarys...
`help({}.get)`

. Use this method to fix the code.