Micro:bit Challenges
- Author: Dr. Jim Marquardson (jimarqua@nmu.edu)
- Updated 2024-06-19
This exercise assumes that you have had some introduction to Python programming using the Micro:bit platform. Several sample projects are included. Choose projects that you find interesting and challenging. The goal is to have you explore the platform in a semi-structured way.
Learning Objectives
In this exercise, you will learn to:
- add missing code to complete programs,
- develop new functions, and
- investigate the documentation.
Editing Code
- Go to https://python.microbit.org/ to edit the code.
- Remove the sample code.
- Write your Python code.
- Preview your code using the simulator.
- Download the code to the micro:bit device to run your program on the micro:bit hardware.
Project Index
- Foundations
- Data Type Intro: Learn about Python data types
- Functions Intro: Learn about Python functions
- Loops Intro: Learn about Python loops
- Novice
- Hello World 2: Practice calling functions
- Simple Calculator: Do some math and show the result
- Indentation Matters: Practice indenting code
- Data Types: Create variables with different data types and show the results
- Countdown: Make the micro:bit count from 9 to 0 and print "Go!"
- Greet Loop: Greet people using lists and loops
- Out of Bounds: Fix code that goes outside of a list
- Intermediate
- Button Events: Run functions when buttons are pressed
- Guessing Game Mod: Make a guessing game better
- Fix the Mine Game: A mine-finding game needs its logic fixed
- Artist Struggle: A simple program for making art, but it can be tricky to use
- Expert
- Atbash Cipher: Implement the Atbash cipher
- Vigenere Cipher: Implement the Vigenere cipher
- Free Play: Explore your ideas
Data Type Intro
The following code shows a complete, working program. Follow the instructions to change the values of different variables. You do not need to modify any of the code that displays the variables. This sample code can help you remember the syntax for creating and working with variables in different challenges.
from microbit import *
# Integer variables hold whole numbers (1, 2, 3, etc.).
# Integer variables do not need quotation marks around the values.
# Change the age variable below to your age.
age = 50
# The print() function shows the contents in the
# serial output of the simulator.
print("Age: " + str(age))
# The display.show() function displays the value
# in the LED lights.
display.show(age)
display.clear()
sleep(500)
# Decimal numbers are known as "floats."
# Change the the ideal_temperature variable
# below to you ideal weather temperature.
ideal_temperature = 55.3
# The value will be displayed.
print("Ideal temperature: " + str(ideal_temperature))
display.show(ideal_temperature)
display.clear()
sleep(500)
# String variables store text.
# Use quotation marks around the text
# when setting the value of string variables.
# Change the birth_month variable below to
# the month you were born.
birth_month="December"
# The value will be displayed.
print("Birth month: " + birth_month)
display.scroll(birth_month)
display.clear()
sleep(500)
# List variables store multiple values.
# The values are separated by commas inside
# of square brackets.
# Change the numbers in the list variable lucky
# to your 3 luckiest numbers.
lucky = [3, 42, 111]
# You can access elements in the list using their
# indices, starting with 0.
print("Lucky #1: " + str(lucky[0]))
display.show(lucky[0])
print("Lucky #2: " + str(lucky[1]))
display.show(lucky[1])
print("Lucky #3: " + str(lucky[2]))
display.show(lucky[2])
display.clear()
sleep(500)
# Dictionaries store values in key/value pairs.
# The key is always a string.
# The value can be any Python variable type.
# The 'about' variable blow has 3 keys:
# 1) 'city': a string
# 2) 'heigh_cm': an integer
# 3) 'foods': a list of strings
# Change the values to the city where you are
# from, your height in centimeters, and three
# of your favorite foods.
about = {
'city': "New York",
'height_cm': 140,
'foods': ["burgers", "fries", "tortilla chips"]
}
# Access dictionary elements using square brackets
# and the the key, with quotation marks around the key.
print("City: " + about['city'])
display.show(about['city'])
print("Height: " + str(about['height_cm']))
display.show(about['height_cm'])
# Because the value of about['foods'] is a list,
# the items in the list must be access with their indices.
print("Food 1: " + str(about['foods'][0]))
display.show(about['foods'][0])
print("Food 2: " + str(about['foods'][1]))
display.show(about['foods'][1])
print("Food 3: " + str(about['foods'][2]))
display.show(about['foods'][2])
display.clear()
Functions Intro
Functions help organize code. Instead of repeating code several times, it can be helpful to put blocks of code in functions. Read the code below, and modify the function calls at the bottom of the code to test different function inputs.
from microbit import *
# Begin a line with 'def' to define a function.
# The fuction's name follows 'def'.
# Function inputs can be put in parentheses.
# After the paretheses, add a colon.
# The rest of the lines in the function need
# to be indented.
def show_big(text):
print("UPPER CASE: " + text.upper())
display.scroll(text.upper())
sleep(100)
def show_small(text):
print("lower case: " + text.lower())
display.scroll(text.lower())
sleep(100)
# Not all functions need inputs.
# The show_error() function below adoes not
# accept any inputs.
def show_error():
print("Error")
display.scroll("Error")
sleep(100)
# Call functions by providing the function name
# and providing values for the function's inputs.
# Change the function inputs below and run the code.
show_big("hElLo")
show_small("hElLo")
show_error()
show_big("world")
show_small("WORLD")
Loops Intro
Loops let you run code multiple times. Loops are helpful when working with lists or ranges of numbers.
from microbit import *
# The following `for` loop goes from
# 0 to 4 and displays the number.
# The variable `i` takes the value
# of the current integer.
# Change the paramters of the range() function
# to edit the start and end of the `for` loop.
for i in range(0, 5):
display.show(i)
sleep(500)
# This `for` loop goes through a list of
# values. The variable `n` takes the value
# of each element in the list as Python
# goes through the loop.
# Add or remove elements from the list.
# Be sure the list elements are separated
# by commas.
for n in ["a", "b", "c"]:
display.show(n)
sleep(500)
# A while loop continues until the condition
# is false.
# Change the values for `end` and `i` to see
# how the loop changes.
end = 9
i = 5
while i <= end:
display.show(i)
i = i + 1
sleep(500)
# Creating a `while True` loop will continue forver.
# Notice that the code will never reach the
# `display.clear() code below the loop.
# Add the `break` keyword after the sleep()
# function to force the while loop to exit,
# then re-run the code.
while True:
display.show(".X")
sleep(500)
display.clear()
Hello World 2
This simple project will display "Hello name" as many times as you call the function.
from microbit import *
def greet_name(name):
display.scroll("Hello " + name)
# Write the code here to call the greet_name()
# function two separate times.
Simple Calculator
The Python code below performs basic math operations and shows the results. Run the code to make sure it works. Then, modify the code to find the answers to these questions:
- What happens if the result is a number with more than 1 digit?
- What happens if a number is not evenly divisible (e.g., 7/2)?
- What happens if you raise a number to a very large power (e.g., 2**800)?
from microbit import *
added = 5 + 2
display.scroll(added)
divided = 9 / 3
display.scroll(divided)
multiplied = 2 * 3
display.scroll(multiplied)
squared = 3**2
display.scroll(squared)
Indentation Matters
Python code must be indented properly to work. Fix the code by indenting the lines properly. The code creates a list of lists, has a function to print letters (skipping the letter '2'), and creates an infinite loop to cycle through the data.
from microbit import *
data = [['a', 'b', 'c'],
['1', '2', '3']]
# Show letters, but skips the text '2'
def show_letter_but_not_two(letter):
if letter=='2':
pass
else:
display.show(letter)
# Indent the code properly.
# The program should pause the same
# amount for each letter displayed.
while True:
for i in data:
for n in i:
show_letter_but_not_two(n)
sleep(200)
Data Types
This exercise asks you to create variables using different data types. After you create the variables, you will show the variable values. Replace the question marks with the appropriate code.
from microbit import *
################################
# Create the variables
################################
# Make name a string variable with your first name
name = ?
# Make age an integer variable with your age.
age = ?
# Make exact_age decimal number with your age .
# If it has been 6 months since your birthday,
# your exact age would be 20.5
exact_age = ?
# Make the friends a list variable with the
# names of 2 or more friends
friends = ?
# Make the favorites variable a dictionary
# with 3 key-value pairs:
# 1) "team" containing your favorite team
# 2) "color" containintg your favorite color
# 3) "food" containing your favorite food
favorites = ?
################################
# Show the variables
################################
# Show the value of the name variable
display.scroll(?)
# Show the value of the age variable
display.scroll(?)
# Show the value of the exact_age variable
display.scroll(?)
# Show the first element of the friend list
display.scroll(?)
# Show the second element of the friend list
display.scroll(?)
# Show the value of team from the favorites dictionary
display.scroll(?)
# Show the value of color from the favorites dictionary
display.scroll(?)
# Show the value of food from the favorites dictionary
display.scroll(?)
Countdown
from microbit import *
countdown = 9
# Create a while loop that goes down to zero
while ????: # Complete the while loop condition so that it continues until countdown is 0
display.scroll(countdown)
countdown = ???? # Edit the countdown variable to subtract 1
display.scroll("Go!")
Greet Loop
This challenge requires you to create a list of names. Then, you will loop through those names to call the greet_name
function.
from microbit import *
def greet_name(name):
display.scroll("Hi " + name)
print("Hello " + name)
# Create a list with 3 names
names = ???? # Finish this line of code
# Loop through each name and call the greet_name() function
for ???? # Finish this line of code
greet_name(name)
Out of Bounds
The following code creates a list named items
. The code will print the current index
of the list. The A
button goes to the next item in the index. The B
button goes to the previous item. But the code will crash if the index goes outside of the items
list. Fix the code. There are several ways to fix this program. Two options are below.
- Option 1: Prevent the
index
from going below zero or higher than two. Essentially, theA
button is rendered useless ifindex
is zero. TheB
button becomes useless ifindex
is two. - Option 2: If
index
goes lower than zero, set it to two. Setindex
to zero if the index is changed to something greater than two. Essentially, theA
andB
buttons will loop forever in either direction.
from microbit import *
items = ['a', 'b', 'c']
index = 0
while True:
if button_a.was_pressed():
index = index - 1
if button_b.was_pressed():
index = index + 1
# The following line can crash the program
display.show(items[index])
Button Events
This challenge requires you to run functions when buttons are pressed. The code already works when pressing the A and B buttons separately. Your task is to add the code to handle when both A and B are pressed at the same time.
from microbit import *
while True:
# Add code at the beginning to check if A and B are both pressed.
# If so, show the North arrow.
if button_a.is_pressed():
display.show(Image.ARROW_W)
elif button_b.is_pressed():
display.show(Image.ARROW_E)
sleep(100)
Guessing Game Mod
The following code works okay. It's a simple guessing game. The starting guess is 5. When the A button is pressed, the program reduces the guess by 1 and checks if it matches the secret number. When the B button is pressed, the guess is increased by one and checked to see if it matches the secret. Make the game better. Here are a few suggestions:
- Reduce duplicate code. For example, the logic to check whether the guess is correct could be extracted into a separate function.
- Instead of checking the guess each time, only check guesses when A and B are pressed simultaneously.
- Set the minimum and maximum guess. For example, the lowest guess could be 0, and the maximum guess could be 20. Enforce these minimums and maximums in the code.
- Randomly generate the secret integer.
from microbit import *
guess = 5
secret = 7
print(secret)
display.show(guess)
while True:
if button_a.was_pressed():
guess = guess - 1
display.show(guess)
sleep(500)
if guess == secret:
display.scroll("Yes!")
else:
display.scroll("No")
display.show(guess)
elif button_b.was_pressed():
guess = guess + 1
display.show(guess)
sleep(500)
if guess == secret:
display.scroll("Yes!")
else:
display.scroll("No")
display.show(guess)
sleep(100)
Fix the Mine Game
The code below implements a simple mine-finding game. The A and B buttons move the current position. Pressing A and B together checks for a mine. The movement logic needs to be improved. If the position gets to the end of a line and B is pressed, the position should move to the following row in the first column. Likewise, if the current position is in the first column and A is pressed, the position should move up a row to the last column. Basically, the current position should never leave the grid.
- The grid is 5 by 5. The top-left coordinate is 0, 0. The bottom-right coordinate is 4, 4.
- If the current position is 0, 0 and the A button is pressed, the current position should not change.
- If the current position is 4, 4 and the B button is pressed, the current position should not change.
- If the current position is 0, 4, and the A button is pressed, the position should change to 4, 3.
from microbit import *
# Game Start Conditions
mine_x = 3
mine_y = 2
current_x = 2
current_y = 2
display.set_pixel(current_x, current_y, 9)
while True:
if button_a.is_pressed() and button_b.is_pressed():
if current_x == mine_x and current_y == mine_y:
display.show(Image.HEART)
elif button_b.was_pressed():
display.set_pixel(current_x, current_y, 0)
current_x = current_x + 1
# Add logic here to move rows
display.set_pixel(current_x, current_y, 9)
elif button_a.was_pressed():
display.set_pixel(current_x, current_y, 0)
current_x = current_x - 1
# Add logic here to move rows
display.set_pixel(current_x, current_y, 9)
sleep(200)
Artist Struggle
In this program, the A and B buttons move the current position left and right. When A and B are pressed together, the current pixel is toggled (i.e., if it's off, it will be turned on and vice versa). The program works, but it can be a bit frustrating to use. Sometimes, the position does not change the amount you think it should and so the wrong pixel is toggled. Can you improve the program? Here are some ideas:
- Try changing the
sleep()
function. - Should the current pixel be changed to a different brightness?
- Is there a different way to access the button codes?
The goal of this exercise is to make the program more friendly for our artist friends.
from microbit import *
position = [0,0]
pixels = [[0,0,0,0,0],
[0,0,0,0,0],
[0,0,0,0,0],
[0,0,0,0,0],
[0,0,0,0,0]]
def toggle_current_pixel():
# Toggle the pixel of the current position
if pixels[position[0]][position[1]] == 0:
pixels[position[0]][position[1]] = 9
else:
pixels[position[0]][position[1]] = 0
display.clear()
for x in range(0, len(pixels)):
for y in range(0, len(pixels)):
display.set_pixel(x, y, pixels[x][y])
while True:
if button_a.is_pressed() and button_b.is_pressed():
print("A and B pressed")
print(position)
toggle_current_pixel()
elif button_b.was_pressed():
print("B pressed")
position[0] = position[0] + 1
if position[0] > 4 and position[1] == 4:
position[0] = 4
elif position[0] > 4:
position[0] = 0;
position[1] = position[1] + 1
elif position[0] < 0:
position[0] = 0
position[1] = position[1] - 1
print(position)
elif button_a.was_pressed():
print("Button A pressed")
position[0] = position[0] - 1
if position[0] < 0 and position[1]==0:
position[0] = 0
elif position[0] < 0:
position[0] = 4;
position[1] = position[1] - 1
print(position)
sleep(200)
Atbash Cipher
The Atbash cipher is a monoalphabetic substitution cipher. See Wikipedia for an overview. You can experiment with the Atbash cipher using the Cyber Chef. A basic outline of a sample program is included, but you must develop the logic.
from microbit import *
def atbash_encrypt(input):
ciphertext = ''
# Complete this function
return ciphertext
cleartext = "hello"
ciphertext = atbash_encrypt(cleartext)
display.scroll(ciphertext)
# 'hello' should produce 'svool'
Vigenere Cipher
The Vigenere cipher is a polyalphabetic substitution cipher. It is similar to the Caesar cipher except that the letters are rotated different amounts based on a multi-character key. Read about the Vigenere Cipher on Wikipedia. Experiment with the Vigenere cipher using the Cyber Chef. In the Cyber Chef, try making the key 'aaa' or 'bbb' and look at the results on the output.
from microbit import *
def vigenere_encrypt(input, key):
ciphertext = ''
# Complete this function
return ciphertext
cleartext = "hello"
key = "abc"
ciphertext = vigenere_encrypt(cleartext, key)
display.scroll(ciphertext)
# 'hello' with the key 'abc' should produce 'hfnlp'
Free Play
Develop your own idea! Push yourself to see what you can do with the micro:bit.
Reflection
- What were the most challenging parts of writing the code?
- Think of projects that you could do if the micro:bit had GPS, a microphone, or other modules. What programs would you write?