Conway’s Game of Life for micro:bit using MicroPython
Conway’s Game of Life has been challenging programmers for many years. I treat it as a more advanced form of “Hello World” as it requires a reasonable knowledge of a programming language to complete.
This version is for the BBC micro:bit and uses MicroPython. The main restriction here is the limit of a 5 x 5 grid of LEDs as the display but this can be scaled up, perhaps to work on an external LED matrix.
Conway’s Game of Life
# Conway's Game of Life
# Richard Zealley
# 9th May 2016
from microbit import *
from random import randint
# Number of lives to start out with (12 seems to work pretty well)
numbugs = 12
# Whether to treat the sides as boundaries or wrap round to the other side
wrap = True
# We're stuck with a 5x5 array but may be useful on another platform
cols = 5
rows = 5
# Define 5x5 array full of 0s
bugs = [[0 for x in range(cols)] for y in range(rows)]
def clear_bugs():
# Clears the array though this is not actually used as the definition above does this anyway but could be useful at some point'
global bugs
# Set all array elements to 0
for x in range(5):
for y in range(5):
bugs[x][y] = 0
return
def random_bugs(n):
# Generate a set number of cells as populated (with 1)'
global bugs
i = 0
while i < n:
x = randint(0, 4)
y = randint(0, 4)
# Check not already populated
if bugs[x][y] != 1:
# Populate it
bugs[x][y] = 1
# Count it
i += 1
return
def show_bugs():
# Clear the display and then set any led which is populated'
global bugs
display.clear()
for x in range(5):
for y in range(5):
if bugs[x][y] == 1:
display.set_pixel(x, y, 9)
return
def check_position(pos):
# For wrapping - check if a position is in the 5x5 grid,
# and shift to opposite side if necessary
if pos < 0:
pos = 5 + pos
if pos>4:
pos = pos - 5
return pos
def process_bug(x, y):
# Check a position by counting each of its 8 surrounding neighbours and return the number populated'
global bugs
n = 0
# Count each of 8 neighbours
for i in (-1, 0, 1): # col
for j in (-1, 0, 1): # row
if not (i == 0 and j == 0): #don't count the current bug
if wrap:
col = check_position(x+i)
row = check_position(y+j)
if bugs[col][row] == 1:
n += 1
else:
if i in (0, 1, 2, 3, 4) and j in (0, 1, 2, 3, 4):
if bugs[i][j] == 1:
n += 1
return n
def generate_bugs():
# Check each position in grid, count neighbours and die or birth if needed
global bugs
# Track changes - if none then no point continuing
changes = 0
# Clone current bug positions - need to work from original before changing
new_bugs = [list(row) for row in bugs]
# Check each bug for neighbours
for x in range(5):
for y in range(5):
n = process_bug(x, y)
# Live cell
if bugs[x][y] == 1:
if n < 2 or n > 3: # dies (under or over population)
new_bugs[x][y] = 0
changes += 1
elif n == 3: # dead cell with 3 neighbours
# New birth
new_bugs[x][y] = 1
changes += 1
# Copy new population back to bugs
bugs = [list(row) for row in new_bugs]
return changes
def main():
# Count the number of generations
goes = 0
# Create the game and show the initials LEDs
random_bugs(numbugs)
show_bugs()
sleep(1000)
# Continue until button B is pressed
while not button_b.is_pressed():
goes += 1
# Process bugs and stop if no longer any changes
changes = generate_bugs()
show_bugs()
# Slow things down
sleep(1000)
# If nothing changed, that's it
if changes == 0:
break
display.scroll(str(goes)+" generations")
display.scroll("The End")
# Run it 8-)
if __name__ == "__main__":
main()