I'm teaching another course of 'Coding for Absolute Beginners' using the BBC microbit and python to explain what programming is, what it looks like, how to write some simple games, how to debug and rubber-duck, to give delegates a flavour of what developers do for the non-technical person.

Canonical Egg Toy

One of the examples I use when explaining loops and conditionals is working up to a very simple tamagotchi clone, a microbotchi if you will, in which the microbit 'sleeps' until it's woken up by shaking the microbit.


from microbit import *

while True:
    
    if accelerometer.was_gesture("shake"):   
        display.show(Image.HAPPY)
        sleep (5000)
    else:
        display.show(Image.ASLEEP)
        

While we were talking about this example some of the discussion got into how to make this more realistic with some more emotions, activities, feeding etc. and even, if the egg goes neglected for too long, dying. I thought it might be fun to try a worked example of this, step by step, so this, dear reader, is that post.

Microbotchi Begins

So, let's start fresh with a normally happy little egg. It doesn't have much of a life but at least it's happy. And for a morbid touch we'll make provision for it's eventual death when we exit the while loop of it's life.


from microbit import *

is_alive = True

# lifetime
while is_alive:
    display.show(Image.HAPPY)


# dead
display.show(Image.GHOST)

Microbotchi Health

Speaking of death, if the egg gets ill enough, it should probably die and end the game. So we can model that with a simple health score which we set suitably high at birth and let it deplete over time such that if it's left alone long enough it will die on it's own. We don't want it to leak away too soon so I've put a delay (sleep) into the while loop.


from microbit import *

is_alive = True
health = 100

# lifetime
while is_alive:

    health = health - 1

    display.show(Image.HAPPY)
    sleep(1000)

    is_alive = health > 0

# dead
display.show(Image.GHOST)

We start off with a score of 100 and if we leave it alone, it will "die" after 100 seconds. What would keep the egg alive? Maybe feeding it every so often by pressing the "a" button? Every time we get a food pellet we increase our health by a fixed amount.

Food


from microbit import *

is_alive = True
health = 100
happiness = 100

# lifetime
while is_alive:

    health = health - 1
    happiness = happiness - 1

    # play with me
    if accelerometer.was_gesture("shake"):
        happiness = happiness + 50

    # feed me
    if button_a.was_pressed():
        health = health + 50

    if happiness > 0:
        display.show(Image.HAPPY)
    else:
        display.show(Image.SAD)

    sleep(1000)

    is_alive = health > 0

# dead
display.show(Image.GHOST)

Happiness and Play

We can follow a similar approach to modelling emotion, we need to have a quantifiable happiness indicator, say, and a way for that to change over time into ... sadness?

Let's create a happiness score and deplete it each time around the loop. We can also make the egg happier by playing with it. Maybe that can be using gestures to interact.


from microbit import *

is_alive = True
health = 100
happiness = 100

# lifetime
while is_alive:

    health = health - 1
    happiness = happiness - 1

    # play with me
    if accelerometer.was_gesture("shake"):
        happiness = happiness + 50

    # feed me
    if button_a.was_pressed():
        health = health + 50

    if happiness > 0:
        display.show(Image.HAPPY)
    else:
        display.show(Image.SAD)

    sleep(1000)

    is_alive = health > 0

# dead
display.show(Image.GHOST)

Sleep

Finally, we might want to put in something so that if it's left alone for a little while, it will go to sleep. And feeding or playing it will wake it up for a while.


from microbit import *

is_alive = True
health = 100
happiness = 100
awakeness = 50

# lifetime
while is_alive:

    health = health - 1
    happiness = happiness - 1
    awakeness = awakeness - 1

    # play with me
    if accelerometer.was_gesture("shake"):
        happiness = happiness + 50
        awakeness = awakeness + 20

    # feed me
    if button_a.was_pressed():
        health = health + 50
        awakeness = awakeness + 10

    if awakeness > 0:
        if happiness > 0:
            display.show(Image.HAPPY)
        else:
            display.show(Image.SAD)
    else:
        display.show(Image.ASLEEP)

    sleep(1000)

    is_alive = health > 0

# dead
display.show(Image.GHOST)

Tidying Up

Now the only thing left to do, is put in an introduction, where we start with an egg before it hatches and the game starts proper. Also we can do some animation around playing, eating and dying.


from microbit import *
import random

def fade_out(image, delay=250, minimum=0):
    image = image.copy()
    for times in range(0, 10):
        for x in range(0, 5):
            for y in range(0, 5):
                brightness = image.get_pixel(x, y)
                if (brightness > minimum):
                    image.set_pixel(x, y, brightness - 1)
        display.show(image)
        sleep(delay)

        
display.scroll("microbotchi")

# start off as an egg that will hatch in time
egg = Image("09990:"
            "90009:"
            "90009:"
            "90009:"
            "09990:")

display.show(egg)
time_before_hatching = random.randint(1, 5)
sleep(time_before_hatching * 1000)
    
# initial state
is_alive = True
health = 100
happiness = 100
awakeness = 50

# rewards for interaction
food_health = 50
food_awakeness = 10
food_happiness = 5
play_happiness = 50
play_awakeness = 20

# lifetime
while is_alive:

    health = max(health - 1, 0)
    happiness = max(happiness - 1, 0)
    awakeness = max(awakeness - 1, 0)

    # play with me
    if accelerometer.was_gesture("shake"):
        display.show(Image.HEART)
        sleep(1000)
        happiness = happiness + play_happiness
        awakeness = awakeness + play_awakeness
        
    # feed me
    if button_a.was_pressed():
        for x in range(0, 5):
            display.show(Image.SURPRISED)
            sleep(300)
            display.show(Image.MEH)
            sleep(300)
        health = health + food_health
        happiness = happiness + food_happiness
        awakeness = awakeness + food_awakeness
        
    if awakeness > 0:
        if happiness > 50:
            display.show(Image.HAPPY)
        elif happiness > 0:
            display.show(Image.MEH)
        else:
            display.show(Image.SAD)
    else:
        display.show(Image.ASLEEP)

    sleep(500)

    is_alive = health > 0

#dying 
fade_out(Image.SAD)
# dead
display.show(Image.GHOST)
sleep(10000)
fade_out(Image.GHOST)