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()