Wednesday, 11 May 2016

Conway's Game of Life on the BBC micro:bit

Conway's Game of Life is a great way to test out a new programming platform and the 5x5 LED display of the micro:bit seemed to be a great fit. If you're not aware of Game of Life you can find out more here: https://en.wikipedia.org/wiki/Conway's_Game_of_Life.

The no-player game uses a two-dimensional grid of cells, each of which can be 'alive' or 'dead'. These are then processed through generations where they live or die according to rules about the cells' immediate neighbours:

  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by over-population.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
Typically the initial population is generated randomly, so that's what I've done here.

My initial code is below. I know this can be improved, possibly by using the LEDs and their brightness level in place of the arrays. Anyway here it is...
  
# Conway's Game of Life
# Richard Zealley
# 9th May 2016

from microbit import *
from random import *

#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 accordingly'
    global bugs
    
    #track changes - if none then no point continuing
    changes=0
    
    #clone current bug positions because need to work from riginal before changing any
    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()




Sunday, 8 May 2016

BBC micro:bit - an introduction

I can't resist the challenge of a new (or ancient) piece of programmable kit and have been keen to try out the new BBC micro:bit - a small computer reminiscent of the Raspberry Pi and currently being handed out to all year 7 pupils in UK secondary schools.

It's a far cry from the original BBC Micro (of which I'm a great fan) but the purpose is the same - to introduce children to coding at an early age. School-based computing in the intervening years has been reduced to learning to use apps like word processing, spreadsheets and PowerPoint so this is potentially a great step forward. I'm particularly interested at the moment as I'm running a Code Club at a local primary school, helping kids learn programming using Scratch and Python.

I found my micro:bit for sale on eBay. I'm not sure these should be for sale at all yet as they haven't been released to the general public but it seemed a good opportunity to try one out. Here are some picture of the complete kit:



To get started I went to the BBC micro:bit website where you can create code online and download it onto the micro:bit. The whole process is really simple and I had a Hello World app running in a few minutes using MicroPython, for which there's a guide here: https://www.microbit.co.uk/python-guide, with further documentation here: http://microbit-micropython.readthedocs.io/en/latest/.