Snake

A classic arcade game where you guide a snake to eat food, grow longer, and avoid crashing.

This is the classic Snake game, where the goal is simple: eat food to grow the snake while avoiding collisions with the walls and your own body. Each piece of food increases both the snake’s length and speed, making the challenge greater as you progress.

The game features smooth movement on a grid, real-time score and level display, and a Game Over screen showing your final score when the snake crashes. Press the Up button to begin, then use the joystick to steer in four directions. Stay sharp, plan your moves, and see how long you can survive!

Programming Design

Source Code

By default, your device comes with the necessary firmware and libraries preinstalled. If you have modified or replaced the firmware or libraries, make sure the following files are present (download if need by click the link)

  • Assets: board.py, button.py, buzzer_music.py, mma7660.py, st7789.py

  • Fonts: vga_16x32.py, vga2_8x8.py

Below is the main program file along with any additional files required for this specific app.

Github Code

Main.py
import machine
from machine import Timer,PWM,ADC,Pin
import time
import random
import _thread
import st7789_snake as st7789
from test.fonts import vga2_8x8 as font1
from test.fonts import vga1_16x32 as font2
import framebuf
import sys
#from buzzer_music import music
from time import sleep
import utime

dtime=(1,1,1,1,
       1,1,1,1,
       1,1,1,1,
       1.5,0.5,2,
       1,1,1,1,
       1,1,1,1,
       1,1,1,1,
       1.5,0.5,2,
       1,1,1,1,
       1,0.5,0.5,1,1,
       1,0.5,0.5,1,1,
       1,1,1,1,
       1,1,1,1,
       1,1,1,0.5,0.5,
       1,1,1,1,
       1.5,0.5,2)

st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=0, polarity=1, sck=spi_sck, mosi=spi_tx)
print(spi0)
display = st7789.ST7789(spi0, disp_width, disp_height,
                          reset=machine.Pin(st7789_res, machine.Pin.OUT),
                          dc=machine.Pin(st7789_dc, machine.Pin.OUT),
                          xstart=0, ystart=0, rotation=0)

up = Pin(8, Pin.IN, Pin.PULL_UP)    # Up
#down = Pin(6, Pin.IN, Pin.PULL_UP)  # Down
#left = Pin(7, Pin.IN, Pin.PULL_UP)  # Left
start = Pin(5, Pin.IN, Pin.PULL_UP) # Right
a=machine.Pin(28,Pin.PULL_UP)
b=machine.Pin(29,Pin.PULL_UP)
BeepIO= machine.Pin(16,machine.Pin.OUT)
pwm = PWM(machine.Pin(16))

xAxis = ADC(Pin(28))
yAxis = ADC(Pin(29))

direction = 1

pup = 0
pdown = 0
pleft = 0
pright = 0

global highScore
highScore = 0

def reset_game():
    global goal, speedv, lv, direction, pup, pdown, flag, l1, snake, highScore
    snake = []
    goal = 0
    speedv = 0.5
    lv = 1
    direction = 1
    pup = 0
    pdown = 0
    flag = 0
    #display.fill(st7789.BLACK)
    #display.fill_rect(0,0,240,240,st7789.BLACK)
    food()
    l1 = intsnake()
   
    
def waitRestart():
    while True:
        if(start.value() == 0):
            time.sleep(0.3)
            reset_game()
            break
        time.sleep(0.3)
        
        
        
def pushup(Pin):
    global pup
    pup=1

def pushdown(Pin):
    global pdown
    pdown=1
    
def pushleft(Pin):
    global flag
    flag = 2
    

def pushright(Pin):
    global flag
    flag = 1

def displays(snake):
    length=len(snake)
    a=0
    while(a<length):
        display.fill_rect(snake[a],snake[a+1],10,10,st7789.WHITE)
        a+=2

def food(snake=[-1,-1]):
    global x1,y1
    x1=random.randrange(0,230)
    y1=random.randrange(0,180)
    x1=x1-x1%10
    y1=y1-y1%10
    while(x1 in snake and y1 in snake):
        x1=random.randrange(0,230)
        y1=random.randrange(0,180)
        x1=x1-x1%10
        y1=y1-y1%10        
    display.fill_rect(x1,y1,10,10,st7789.RED)
    
def intsnake():
    x2=random.randrange(0,230)
    y2=random.randrange(0,180)
    x2=x2-x2%10
    y2=y2-y2%10
    snake=[x2,y2]
    display.fill_rect(x2,y2,10,10,st7789.WHITE)
    return snake
    
def addlong(x,y,snake):
    head=[x,y]
    head.extend(snake)
    return head

def chuli(snake, x, y):

    global x1, y1, speedv, lv, crush, died, goal, highScore
    died = False
    if goal < 5:   
        speedv = 0.1
        lv = 1
    elif goal < 10:
        speedv = 0.09
        lv = 2
    elif goal < 15:
        speedv = 0.0
        lv = 3
    elif goal < 20:
        speedv = 0.1
        lv = 4
    else:
        speedv = 0.09
        lv = 5
    
    crush = 0
    length = len(snake)
    
    # Check collision with body (exclude current head at index 0 and 1)
    a = 2
    while a < length:
        if snake[a] == x and snake[a+1] == y:
            crush = 1
            break
        a += 2
    
    #death
    if crush == 1 or x > 240 or x < 0 or y > 180 or y < 0:
        if goal >= highScore:
            highScore = goal
            
        print(x, y, crush)
        display.fill(st7789.BLACK)
        display.text(font2, "Game Over!", 40, 80, st7789.RED)
        display.text(font2, "Final score:", 10, 110, st7789.BLUE)
        display.text(font2, str(goal), 200, 110, st7789.YELLOW)
        display.text(font1, "Press the B to restart!", 10, 160)
        display.text(font2, "HIGH SCORE:", 5, 190)
        display.text(font2, str(highScore),180, 190)


        #Timer.deinit()
        died = True
        waitRestart()
        reset_game()
        
        
    if died != True:
        newsnake = addlong(x, y, snake)  # Add the new head here once
        if x == x1 and y == y1:
            goal += 1
            
            newsnake = addlong(x1, y1, newsnake)  # Grow longer by adding food pos again
            displays(newsnake)
            food(newsnake)

        # Clear last tail segment
        display.fill_rect(newsnake[-2], newsnake[-1], 10, 10, st7789.BLACK)
        del newsnake[-1]
        del newsnake[-1]
        
        displays(newsnake)
        time.sleep(speedv)
        display.hline(0, 190, 240, st7789.RED)
        display.text(font2, "score:", 0, 200)
        display.text(font2, str(goal), 95, 200, st7789.YELLOW)
        display.text(font2, "level:", 125, 200)
        display.text(font2, str(lv), 215, 200, st7789.YELLOW)

        return newsnake

def read_joystick():
    global direction
    xValue = xAxis.read_u16()
    yValue = yAxis.read_u16()

    # Up
    if xValue >= 50000 and direction != 0:  # prevent reverse
        direction = 2
    # Down
    elif xValue <= 500 and direction != 2:
        direction = 0
    # Right
    elif yValue <= 500 and direction != 1:
        direction = 3
    # Left
    elif yValue >= 50000 and direction != 3:
        direction = 1

def dir(snake):
    global x, y, direction
    print(snake)
    if snake == None:
        display.fill(st7789.BLACK)
        food()
        snake = intsnake()
    x = snake[0]
    y = snake[1]
 
    read_joystick()

    # Move the snake head according to direction
    if direction == 0:  # up
        y -= 10
    elif direction == 1:  # right
        x += 10
    elif direction == 2:  # down
        y += 10
    elif direction == 3:  # left
        x -= 10

    # Pass the new coordinates and old snake to chuli, which handles adding the head
   
    return chuli(snake, x, y)
        
#global flag,r,l,goal,stop,pup,pdown,speedv,lv,fo,sx,lenm,crush
r=l=flag=goal=stop=pup=pdown=fo=sx=crush=0
speedv=0.5
lv=1
tim = Timer()

#button controls

up.irq(handler=pushup,trigger=machine.Pin.IRQ_FALLING)
start.irq(handler=pushup,trigger=machine.Pin.IRQ_FALLING)

display.text(font2, "Greedy Snake", 20, 80,st7789.YELLOW)
display.text(font1, "Press the up key to start!", 15, 120)
display.hline(0,190,240,st7789.RED)
display.text(font2, "score:", 0, 200)
display.text(font2, str(goal), 95, 200,st7789.YELLOW)
display.text(font2, "level:", 125, 200)
display.text(font2, str(lv), 215, 200,st7789.YELLOW)



while(pup==0 and pdown==0 and flag==0):
    continue
pup=0
#tim.init(freq=1, mode=Timer.PERIODIC, callback=tick)
display.fill(st7789.BLACK)
food()

direction =1
l1 = intsnake()

while True:
    if l1 != []:


        l1 = dir(l1)
        if not l1:  # empty list means game restarted
            continue  # just continue the loop with new l1 from reset_game(
  

    
    



    

Demos

Last updated

Was this helpful?