buba/buba/animations/snake.py
Stefan Bethke 70334603cb
All checks were successful
docker-image / docker (push) Successful in 10m7s
Give display more time to update the LCD panels
2025-06-06 19:14:15 +02:00

107 lines
3.5 KiB
Python

import random
from time import sleep
from buba.bubaanimator import BubaAnimation
class SnakeAnimation(BubaAnimation):
def __init__(self, buba):
super().__init__(buba)
# characters to render the grid and the snake
# Because of Python's limited codec, instead of using the correct Unicode
# codepoints, we're using the CP437 codepoints directly.
self.width = 20
self.height = 4
self.grid = []
self.prev_grid = []
self.body = []
# 0:Space
self.charset = " "
# 1:up 2:right 3:down 4:left
self.charset += "\u001e\u0010\u001f\u0011"
# 5:vertical 6:horizontal
self.charset += "\u2551\u2550"
# 7:up-right 8:down-right 9:down-left 10:up-left
self.charset += "\u255a\u2554\u2557\u255d"
# 11:tail
self.charset += "\u25a0"
self.turn = [
[5, 8, 5, 9], # have been going up, so coming from down
[10, 6, 9, 6], # have been going right, so coming from left
[5, 7, 5, 10], # have been going down, so coming from up
[7, 6, 8, 6], # have been going left, so coming from right
]
random.seed()
def run(self):
self.grid = [list([0] * self.width) for i in range(self.height)]
self.prev_grid = [list([0] * self.width) for i in range(self.height)]
x = random.randrange(self.width)
y = random.randrange(self.height)
d = random.randrange(4)
for r in range(self.height):
self.buba.simple_text(0, r, 0, "") # clear display
self.grid[y][x] = 1 + d
self.body = [(x, y)]
self.render()
iterations = 0
while True:
if self.is_blocked(x, y, d):
end = True
prev_d = d
for n in self.shift(list(range(4))):
if not self.is_blocked(x, y, n):
end = False
d = n
break
if end:
self.grid[y][x] = 11
self.render()
break
self.grid[y][x] = self.turn[prev_d][d]
else:
self.grid[y][x] = 5 + (d % 2)
(x, y) = self.next(x, y, d)
self.grid[y][x] = 1 + d
iterations += 1
self.body.append((x, y))
if iterations % 3 == 0:
(tx, ty) = self.body.pop(0)
self.grid[ty][tx] = 0
(tx, ty) = self.body[0]
self.grid[ty][tx] = 11
self.render()
sleep(1)
sleep(5)
@staticmethod
def shift(a):
i = random.randrange(1, len(a))
return a[i:] + a[:i]
def next(self, x, y, d):
match d:
case 0:
y -= 1
case 1:
x += 1
case 2:
y += 1
case 3:
x -= 1
return (x, y)
def is_blocked(self, x, y, d):
(x, y) = self.next(x, y, d)
return (y < 0 or y >= self.height or
x < 0 or x >= self.width or
self.grid[y][x] != 0)
def render(self):
for x in range(self.width):
for y in range(self.height):
if self.grid[y][x] != self.prev_grid[y][x]:
c = x*6
self.buba.text(0, y, c, c+5, self.charset[self.grid[y][x]])
self.prev_grid[y][x] = self.grid[y][x]