# Snake on the BBC micro:bit

The BBC, in their first digital literacy project since the 1980's, recently gave Year 7 students (aged 11-12) in the UK a tiny single-board computer called the micro:bit. It has a 5x5 grid of LEDs, two buttons, plenty of sensors, and not much memory (16K) or processing power (16 MHz). Thankfully, that's still plenty enough computer to have some fun with.

Playing snake on the micro:bit To me, the 5x5 LEDs looked like they might display a small game of Snake. All I had to do was figure out the input. I originally used the accelerometer to control the snake by tilting the device, but it lacked the speed and precision of a good Snake game. What I really wanted was a way to move the snake in four directions using the two A/B buttons. If you know binary, you'll know that two on/off values gives us four possible combinations. Of course, one of the combinations is off/off meaning no buttons are pressed. For this case, I decided it was most natural to have the snake constantly move 'down' until a button is pressed: A goes left, B right, and A+B up.

### Video

Despite a slightly odd control layout and tiny display, I found Snake on the micro:bit to be surprisingly playable. As proof, here's a video of me playing a full game. It's converted from a GIF so the timing looks a bit odd. In reality the movement is nice and smooth. https://www.youtube.com/watch?v=ALzcqnZaM9w&feature=youtu.be

### Source code

The game clocks in at around 120 lines of Python. To read, I suggest you start with the 'main game loop' at the end of the file.   [cceN_cpp theme="dawn"]

``from microbit import * from random import randrange class Snake(): from microbit import * from random import randrange class Snake(): def __init__(self): self.length = 2 self.direction = "down" self.head = (2, 2) self.tail = [] def move(self): # extend tail self.tail.append(self.head) # check snake size if len(self.tail) > self.length - 1: self.tail = self.tail[-(self.length - 1):] if self.direction == "left": self.head = ((self.head[0] - 1) % 5, self.head[1]) elif self.direction == "right": self.head = ((self.head[0] + 1) % 5, self.head[1]) elif self.direction == "up": self.head = (self.head[0], (self.head[1] - 1) % 5) elif self.direction == "down": self.head = (self.head[0], (self.head[1] + 1) % 5) def grow(self): self.length += 1 def collides_with(self, position): return position == self.head or position in self.tail def draw(self): # draw head display.set_pixel(self.head[0], self.head[1], 9) # draw tail brightness = 8 for dot in reversed(self.tail): display.set_pixel(dot[0], dot[1], brightness) brightness = max(brightness - 1, 5) class Fruit(): def __init__(self): # place in a random position on the screen self.position = (randrange(0, 5), randrange(0, 5)) def draw(self): display.set_pixel(self.position[0], self.position[1], 9) class Game(): def __init__(self): self.player = Snake() self.place_fruit() def place_fruit(self): while True: self.fruit = Fruit() # check it's in a free space on the screen if not self.player.collides_with(self.fruit.position): break def handle_input(self): # change direction? (no reversing) if button_a.is_pressed() and button_b.is_pressed(): if self.player.direction != "down": self.player.direction = "up" elif button_a.is_pressed(): if self.player.direction != "right": self.player.direction = "left" elif button_b.is_pressed(): if self.player.direction != "left": self.player.direction = "right" else: if self.player.direction != "up": self.player.direction = "down" def update(self): # move snake self.player.move() # game over? if self.player.head in self.player.tail: self.game_over() # nom nom nom elif self.player.head == self.fruit.position: self.player.grow() # space for more fruit? if self.player.length < 5 * 5: self.place_fruit() else: self.game_over() def score(self): return self.player.length - 2 def game_over(self): display.scroll("Score: %s" % self.score()) reset() def draw(self): display.clear() self.player.draw() self.fruit.draw() game = Game() # main game loop while True: game.handle_input() game.update() game.draw() sleep(500) [/cceN_cpp] ``