2 - Snake
Last updated
Last updated
from machine import Pin, PWM
import time
from random import randint
import _thread
class LED_Matrix():
def __init__(self):
# Create a list of pin numbers
self.row_pins = [6,4,7,5,3,8,2,9]
self.row_pins.reverse()
self.col_pins = [10,11,12,13,18,19,20,21]
self.col_pins.reverse()
# Create empty lists to contain the Pin objects
self.rows = []
self.cols = []
# Use the list of pin numbers to create
# Pin objects and add them to the lists
# created above.
for i in self.row_pins:
self.rows.append(Pin(i, Pin.OUT))
for i in self.col_pins:
self.cols.append(Pin(i, Pin.OUT))
# Create empty 8x8 array
self.matrix = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0]
]
# Create a counter for current column
self.cur_col = 0
def clear(self):
self.matrix = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0]
]
def next_row(self):
# Deactivate current row
self.cols[self.cur_col].value(0)
# Increment current row
self.cur_col = (self.cur_col + 1) % 8
# Load next row's columns
for i in range(8):
self.rows[i].value(self.matrix[self.cur_col][i])
# Activate next row
self.cols[self.cur_col].value(1)
def draw(self, tup_list):
for row , col in tup_list:
self.matrix[col][row] = 1
class Snake():
def __init__(self):
self.pos = [(4,4)] # A list of tuples that contains coordinates for each segment
self.len = 2 # Current length of the snake
self.dx = 1 # Change in X position per frame
self.dy = 0 # Change in Y position per frame
self.notes = [262,294,330,349,392,440,495,523,587,659,698,784,880,988,1047,1175,1319,1397,1568,1760,1976,2093]
self.cur_note = 0
self.spkr = PWM(Pin(22)) # Create PWM object for speaker
self.sprk_vol = 2**10
self.spawn_apple() # Call a method to spawn an apple
def spawn_apple(self):
self.apple = [(randint(0,7),randint(0,7))] # Spawn Apple at Random Location
# Retry if it landed on the snake
for tup in self.pos:
if tup == self.apple[0]:
self.spawn_apple()
def ate_apple(self):
print(f'Ate an apple!')
self.len += 1
self.cur_note += 1
self.spkr.freq(self.notes[self.cur_note]) # Set frequency in Hz
self.spkr.duty_u16(self.sprk_vol)
time.sleep_ms(100)
self.spkr.duty_u16(0) # Set duty to 0
self.spawn_apple()
def reset(self):
print('Reset')
for self.i in range (self.cur_note, -1, -1):
print(f'Note{self.i}')
self.spkr.freq(self.notes[self.i])
self.spkr.duty_u16(self.sprk_vol)
time.sleep_ms(200)
self.spkr.duty_u16(0) # Set duty to 0
time.sleep_ms(50)
self.len = 2
self.cur_note = 0
self.spawn_apple()
def up(self):
print('up')
# Prevent Snake from flipping back on itself
if self.dy == -1:
return
# Otherwise set direction to up
else:
self.dx = 0
self.dy = 1
def down(self):
print('down')
# Prevent Snake from flipping back on itself
if self.dy == 1:
return
# Otherwise set direction to down
else:
self.dx = 0
self.dy = -1
def left(self):
print('left')
# Prevent Snake from flipping back on itself
if self.dx == 1:
return
# Otherwise set direction to left
else:
self.dx = -1
self.dy = 0
def right(self):
print('right')
# Prevent Snake from flipping back on itself
if self.dx == -1:
return
# Otherwise set direction to right
else:
self.dx = 1
self.dy = 0
def update(self):
# Get current position of snake head
self.x, self.y = self.pos[0]
# Move the head to the new position
self.x += self.dx
self.y += self.dy
# Ensure the new position stays within bounds
self.x = self.x % 8
self.y = self.y % 8
# Add new position to front of position list
self.pos.insert(0,(self.x,self.y))
# Detect Apple Collision
if self.pos[0] == self.apple[0]:
self.ate_apple()
# Detect Self Collision
for self.i in range(1,len(self.pos)):
if self.pos[0] == self.pos[self.i]:
self.reset()
# Ensure snake only grows when eating apples
while len(self.pos) > self.len:
self.pos.pop()
def update_display():
while True:
global d
d.next_row()
time.sleep_ms(2)
def game_loop():
# Connect to globals
global d
global s
# Create Button Objects
up = Pin(14, Pin.IN, Pin.PULL_UP)
down = Pin(17, Pin.IN, Pin.PULL_UP)
left = Pin(16, Pin.IN, Pin.PULL_UP)
right = Pin(1, Pin.IN, Pin.PULL_UP)
# Main Loop for game, runs at 10 Hz
while True:
# Get button inputs
if not up.value():
s.up()
if not down.value():
s.down()
if not left.value():
s.left()
if not right.value():
s.right()
# Update Snake
s.update()
# Clear Display
d.clear()
# Draw Snake on Display
print(s.pos)
try:
d.draw(s.pos)
except:
print('Could not draw snake, initiating reset.')
s.reset()
# Draw Apple on Display
print(s.apple)
try:
d.draw(s.apple)
except:
print('Could not draw apple, initiating reset.')
s.reset()
# Do nothing for 100ms, (10Hz Frame-Rate)
time.sleep_ms(100)
# Create LED Matrix object
d = LED_Matrix()
# Create Snake Object
s = Snake()
# Use second core to constantly run the display
_thread.start_new_thread(update_display,())
# Use main core to run game loop at 10Hz
game_loop()