Skip to content

Instantly share code, notes, and snippets.

@SimonKocurek
Last active July 18, 2023 11:05
Show Gist options
  • Save SimonKocurek/85ff49d41208fbdccd65d3dac5968b42 to your computer and use it in GitHub Desktop.
Save SimonKocurek/85ff49d41208fbdccd65d3dac5968b42 to your computer and use it in GitHub Desktop.
Snake game on a Micro:bit controller
from microbit import *
from random import randrange
class State:
def __init__(self):
self.last_frame_time = 0
self.speed = 500
self.snake_pos = [(2, 2)]
self.food_pos = (0, 0)
self.directions = ((1, 0), (0, 1), (-1, 0), (0, -1))
self.direction = 0
self.board_max_x = 5
self.board_max_y = 5
self.game_lost = False
def main():
state = State()
spawn_food(state)
while not state.game_lost:
wait_for_next_step(state)
handle_input(state)
move_snake(state)
render(state)
display.scroll('Score: ' + str(len(state.snake_pos)))
restart_on_button_press()
def handle_input(state):
if button_a.was_pressed():
if state.direction == 0:
state.direction = len(state.directions)
state.direction -= 1
elif button_b.was_pressed():
state.direction = (state.direction + 1) % len(state.directions)
def wait_for_next_step(state):
current_time = running_time()
time_to_next_step = state.speed - (current_time - state.last_frame_time)
while time_to_next_step > 0:
# we cannot trust sleep to work with 100ms precision
# but it's still better than going in while loop over and over again
if time_to_next_step > 100:
sleep(time_to_next_step - 100)
current_time = running_time()
time_to_next_step = state.speed - (current_time - state.last_frame_time)
state.last_frame_time = current_time
def move_snake(state):
# Add new head and remove last tail
state.snake_pos.insert(0, get_next_snake_point(state))
state.snake_pos.pop()
# Head ate part of tail
if state.snake_pos[0] in state.snake_pos[1:]:
state.game_lost = True
# Ate food
if state.food_pos == state.snake_pos[0]:
state.snake_pos.append(state.snake_pos[0])
spawn_food(state)
def get_next_snake_point(state):
old_x, old_y = state.snake_pos[0]
change_x, change_y = state.directions[state.direction]
new_x = (old_x + change_x) % state.board_max_x
if new_x < 0:
new_x = state.board_max_x - 1
new_y = (old_y + change_y) % state.board_max_y
if new_y < 0:
new_y = state.board_max_y - 1
return (new_x, new_y)
def spawn_food(state):
# Just doing state.food_pos = (random.randrange(5), random.randrange(5)) would be problematic,
# when there are no longer many free spaces. So instead we create a set of all free spaces and
# choose random one from those
all_places = set([(x, y) for x in range(state.board_max_x) for y in range(state.board_max_y)])
snake_places = set(state.snake_pos)
free_places = list(all_places.difference(snake_places))
chosen_place_idx = randrange(len(free_places))
state.food_pos = free_places[chosen_place_idx]
def render(state):
# we don't use display.clear() and display.set_pixel() since that would cause
# flickering (lights would turn off for a brief moment)
board = ['0' * state.board_max_x] * state.board_max_y
image = Image(':'.join(board))
image.set_pixel(state.food_pos[0], state.food_pos[1], 4)
render_snake(state, image)
display.show(image)
def render_snake(state, image):
# We first render tail with lower brightness so that we can tell what is head
# and what is tail in case the snake goes in a straight line... habing head
# exactly before it's tail
snake_tail = state.snake_pos[-1]
image.set_pixel(snake_tail[0], snake_tail[1], 6)
for snake_part in state.snake_pos[1:]:
image.set_pixel(snake_part[0], snake_part[1], 8)
# In case of len(state.snake_pos) == 1, lower brightness of tail gets overriden by
# higher brightness of head
snake_head = state.snake_pos[0]
image.set_pixel(snake_head[0], snake_head[1], 9)
def restart_on_button_press():
# Reset button presses
button_a.was_pressed()
button_b.was_pressed()
# We have no support for interrupts unfortunately, so waiting it is...
while not (button_a.was_pressed() or button_b.was_pressed()):
sleep(1000)
reset()
main()
@SimonKocurek
Copy link
Author

SimonKocurek commented Nov 7, 2020

Demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment