diff --git a/demos/tetris.py b/demos/tetris.py new file mode 100644 --- /dev/null +++ b/demos/tetris.py @@ -0,0 +1,257 @@ +### tetris.py +### Author: Matthew Reed +### Game of tetris, uses the D-Pad +### Adapted from https://gist.github.com/silvasur/565419/d9de6a84e7da000797ac681976442073045c74a4 + +import sys +import time +import signal +import logging +import configparser +from enum import Enum + +import math +from random import randrange as rand +import matrix + +class Tetris: + + # Define the shapes of the single parts + tetris_shapes = [ + [[1, 1, 1], + [0, 1, 0]], + + [[0, 2, 2], + [2, 2, 0]], + + [[3, 3, 0], + [0, 3, 3]], + + [[4, 0, 0], + [4, 4, 4]], + + [[0, 0, 5], + [5, 5, 5]], + + [[6, 6, 6, 6]], + + [[7, 7], + [7, 7]] + ] + + colors = [ + matrix.Colors.OFF.value, + matrix.Colors.RED.value, + matrix.Colors.GREEN.value, + matrix.Colors.BLUE.value, + matrix.Colors.ORANGE.value, + matrix.Colors.YELLOW.value, + matrix.Colors.MAGENTA.value, + matrix.Colors.LIGHT_BLUE.value + ] + + def rotate_clockwise(self, shape): + return [[ shape[y][x] for y in range(len(shape)) ] for x in range(len(shape[0]) - 1, -1, -1)] + + def check_collision(self, board, shape, offset): + off_x, off_y = offset + for cy, row in enumerate(shape): + for cx, cell in enumerate(row): + try: + if cell and board[ cy + off_y ][ cx + off_x ]: + return True + except IndexError: + return True + return False + + def remove_row(self, board, row): + del board[row] + self.score += 1 + return [[0 for i in range(self.width)]] + board + + def join_matrixes(self, mat1, mat2, mat2_off): + off_x, off_y = mat2_off + for cy, row in enumerate(mat2): + for cx, val in enumerate(row): + mat1[cy+off_y-1 ][cx+off_x] += val + return mat1 + + def new_board(self): + board = [[0 for x in range(self.width)] for y in range(self.height)] + board += [[1 for x in range(self.width)]] + return board + + def new_stone(self): + self.stone = self.tetris_shapes[rand(len(self.tetris_shapes))] + self.stone_x = int(self.width / 2 - len(self.stone[0])/2) + self.stone_y = 0 + + if self.check_collision(self.board, self.stone, (self.stone_x, self.stone_y)): + self.gameover = True + + def draw(self, matrix, board, offset): + off_x, off_y = offset + for y, row in enumerate(board): + for x, val in enumerate(row): + if val and y < self.height: + matrix.set_pixel(off_x + x, off_y + y, self.colors[val]) + + def move(self, delta_x): + if not self.gameover and not self.paused: + new_x = self.stone_x + delta_x + if new_x < 0: + new_x = 0 + if new_x > self.width - len(self.stone[0]): + new_x = self.width - len(self.stone[0]) + if not self.check_collision(self.board, self.stone, (new_x, self.stone_y)): + self.stone_x = new_x + + def drop(self): + if not self.gameover and not self.paused: + self.stone_y += 1 + if self.check_collision(self.board, self.stone, (self.stone_x, self.stone_y)): + self.board = self.join_matrixes(self.board, self.stone, (self.stone_x, self.stone_y)) + self.new_stone() + while True: + for i, row in enumerate(self.board[:-1]): + if 0 not in row: + self.board = self.remove_row(self.board, i) + break + else: + break + + def rotate_stone(self): + if not self.gameover and not self.paused: + new_stone = self.rotate_clockwise(self.stone) + if not self.check_collision(self.board, new_stone, (self.stone_x, self.stone_y)): + self.stone = new_stone + + def toggle_pause(self): + self.paused = not self.paused + + def __init__(self, config, parent, matrix, controller): + self.logger = logging.getLogger('snake') + self.config = config + self.parent = parent + self.matrix = matrix + self.controller = controller + + def reset(self): + pass + + def splash(self): + + w = matrix.Colors.WHITE.value + r = matrix.Colors.RED.value + g = matrix.Colors.GREEN.value + b = matrix.Colors.BLUE.value + l = matrix.Colors.LIGHT_BLUE.value + m = matrix.Colors.MAGENTA.value + O = matrix.Colors.ORANGE.value + y = matrix.Colors.YELLOW.value + o = matrix.Colors.OFF.value + + splash = [ + [o, o, o, o, o, o, y, y], + [o, g, g, g, g, g, o, y], + [o, g, o, g, o, g, o, y], + [o, o, o, g, o, o, l, l], + [o, o, o, g, o, o, l, l], + [r, o, o, g, o, o, b, O], + [r, r, g, g, g, b, b, O], + [r, m, m, m, m, b, O, O], + ] + + for x in range(0, self.matrix.WIDTH): + for y in range(0, self.matrix.HEIGHT): + self.matrix.set_pixel(x, y, splash[y][x]) + + self.matrix.update() + + def run(self): + + self.width = 8 + self.height = 8 + + self.board = self.new_board() + self.new_stone() + + #start timers and counters + self.start_time = time.time() + last_time = time.time() + delay_time = 0.1 + + led_iteration_count = 0 + frame_count = 0 + + self.updateCountMax = 15 + self.updateCount = 0 + + self.score = 0 + + self.gameover = False + self.paused = False + + while not self.gameover: + + for event in self.controller.read_input(): + if event.code == 313 and event.value == 1: + #start button + self.gameover = True + if event.code == 305 and event.value == 1: + #A button + self.toggle_pause() + elif event.code == 16: + if event.value == 1: + #dpad right + self.move(+1) + if event.value == 0: + #dpad none + pass + if event.value == -1: + #dpad left + self.move(-1) + elif event.code == 17: + if event.value == 1: + #dpad down + self.drop() + if event.value == 0: + #dpad none + pass + if event.value == -1: + #dpad up + self.rotate_stone() + + if time.time() > last_time + delay_time: + last_time = time.time() + + self.updateCount = self.updateCount + 1 + if self.updateCount >= self.updateCountMax: + self.drop() + self.updateCount = 0 + + #update display + self.matrix.set_matrix(matrix.Colors.OFF.value) + self.draw(self.matrix, self.board, (0,0)) + self.draw(self.matrix, self.stone, (self.stone_x, self.stone_y)) + self.matrix.update() + + led_iteration_count = (led_iteration_count + 1) % self.matrix.NUM_LEDS + frame_count = frame_count + 1 + + time.sleep(0.01) + + #display score before exiting + self.matrix.set_matrix(matrix.Colors.OFF.value) + if self.score > 750: + for i in range(0, 64): + self.matrix.set_pixel(i % self.matrix.WIDTH, math.floor(i / self.matrix.HEIGHT), matrix.Colors.YELLOW.value) + else: + multiples = math.floor(self.score / 50) + self.score = self.score % 50 + for i in range(0, multiples): + self.matrix.set_pixel(i % self.matrix.WIDTH, math.floor(i / self.matrix.HEIGHT), matrix.Colors.YELLOW.value) + for i in range(multiples, self.score): + self.matrix.set_pixel(i % self.matrix.WIDTH, math.floor(i / self.matrix.HEIGHT), matrix.Colors.WHITE.value) + self.matrix.update() + time.sleep(2) \ No newline at end of file