def __init__(self, ipcon): self.okay = False self.ipcon = ipcon if not config.UID_LED_STRIP_BRICKLET: print("Not Configured: LED Strip (required)") return self.led_strip = LEDStrip(config.UID_LED_STRIP_BRICKLET, self.ipcon) try: self.led_strip.get_frame_duration() print("Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) except: print("Not Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) return self.kp = KeyPress(self.ipcon) self.display = TetrisSegmentDisplay(self.ipcon) self.speaker = TetrisSpeaker(self.ipcon) self.okay = True self.led_strip.set_frame_duration(40) self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_RENDERED, self.frame_rendered) self.init_game()
def __init__(self, ipcon): self.okay = False self.ipcon = ipcon if not config.UID_LED_STRIP_BRICKLET: print("Not Configured: LED Strip or LED Strip V2 (required)") return if not config.IS_LED_STRIP_V2: self.led_strip = LEDStrip(config.UID_LED_STRIP_BRICKLET, self.ipcon) else: self.led_strip = LEDStripV2(config.UID_LED_STRIP_BRICKLET, self.ipcon) try: self.led_strip.get_frame_duration() if not config.IS_LED_STRIP_V2: print("Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) else: print("Found: LED Strip V2 ({0})".format(config.UID_LED_STRIP_BRICKLET)) except: if not config.IS_LED_STRIP_V2: print("Not Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) else: print("Not Found: LED Strip V2({0})".format(config.UID_LED_STRIP_BRICKLET)) return self.kp = KeyPress(self.ipcon) self.speaker = PongSpeaker(self.ipcon) self.okay = True self.led_strip.set_frame_duration(40) if not config.IS_LED_STRIP_V2: self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_RENDERED, self.frame_rendered) else: self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_STARTED, self.frame_rendered) self.led_strip.set_channel_mapping(config.CHANNEL_MAPPING) self.init_game()
class Tetris: FIELD_ROWS = config.LED_ROWS+4 # 22 rows in playfield, with only 20 columns visible and 2 coloms border FIELD_COLS = config.LED_COLS+2 # 10 columns in playfield, 2 column border FIELD_ROW_START = 2 FIELD_COL_START = 4 COLORS = [ ( 10, 10, 10), # grey (255, 0, 0), # red (255, 80, 0), # orange (255, 255, 0), # yellow ( 0, 255, 0), # green ( 0, 0, 255), # blue (255, 0, 150), # violet (255, 0, 40), # purple ] TETROMINOS = { None: [[[0], [0], [0], [0]]], 'I': [[[0,0,0,0], [0,0,2,0], [0,0,0,0], [0,2,0,0]], [[2,2,2,2], [0,0,2,0], [0,0,0,0], [0,2,0,0]], [[0,0,0,0], [0,0,2,0], [2,2,2,2], [0,2,0,0]], [[0,0,0,0], [0,0,2,0], [0,0,0,0], [0,2,0,0]]], 'J': [[[6,0,0], [0,6,6], [0,0,0], [0,6,0]], [[6,6,6], [0,6,0], [6,6,6], [0,6,0]], [[0,0,0], [0,6,0], [0,0,6], [6,6,0]]], 'L': [[[0,0,5], [0,5,0], [0,0,0], [5,5,0]], [[5,5,5], [0,5,0], [5,5,5], [0,5,0]], [[0,0,0], [0,5,5], [5,0,0], [0,5,0]]], 'O': [[[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]], [[0,1,1,0], [0,1,1,0], [0,1,1,0], [0,1,1,0]], [[0,1,1,0], [0,1,1,0], [0,1,1,0], [0,1,1,0]]], 'S': [[[0,3,3], [0,3,0], [0,0,0], [3,0,0]], [[3,3,0], [0,3,3], [0,3,3], [3,3,0]], [[0,0,0], [0,0,3], [3,3,0], [0,3,0]]], 'T': [[[0,7,0], [0,7,0], [0,0,0], [0,7,0]], [[7,7,7], [0,7,7], [7,7,7], [7,7,0]], [[0,0,0], [0,7,0], [0,7,0], [0,7,0]]], 'Z': [[[4,4,0], [0,0,4], [0,0,0], [0,4,0]], [[0,4,4], [0,4,4], [4,4,0], [4,4,0]], [[0,0,0], [0,4,0], [0,4,4], [4,0,0]]] } GAME_OVER_TEXT = [ "GameOverGameOverGameOverGameOverGameOverGameOverGameOve", " ", " GGGG OO ", " G GG O O ", " G aaa mmm mm ee O O v v ee rr ", " G GG a m m m e e O O v v e e r r ", " G G aaaa m m m eeee O O v v eeee r ", " G G a a m m m e O O v v e r ", " GGGG aaaa m m m eee OO v eee r ", " ", " ", "GameOverGameOverGameOverGameOverGameOverGameOverGameOve" ] GAME_OVER_COLORS = { ' ': 0, 'G': 1, 'a': 2, 'm': 3, 'e': 4, 'O': 5, 'v': 6, 'r': 7 } drop_timer = None tetromino_current = 'O' tetromino_form = 0 tetromino_pos_row = FIELD_ROW_START tetromino_pos_col = FIELD_COL_START playfield = [x[:] for x in [[0]*FIELD_COLS]*FIELD_ROWS] random_bag = ['O', 'I', 'S', 'Z', 'L', 'J', 'T'] random_bag_index = len(random_bag)-1 game_over_position = 0 is_game_over = False loop = True def __init__(self, ipcon): self.okay = False self.ipcon = ipcon if not config.UID_LED_STRIP_BRICKLET: print("Not Configured: LED Strip (required)") return self.led_strip = LEDStrip(config.UID_LED_STRIP_BRICKLET, self.ipcon) try: self.led_strip.get_frame_duration() print("Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) except: print("Not Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) return self.kp = KeyPress(self.ipcon) self.display = TetrisSegmentDisplay(self.ipcon) self.speaker = TetrisSpeaker(self.ipcon) self.okay = True self.led_strip.set_frame_duration(40) self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_RENDERED, self.frame_rendered) self.init_game() def init_game(self): self.tetromino_current = 'O' self.tetromino_form = 0 self.tetromino_pos_row = self.FIELD_ROW_START self.tetromino_pos_col = self.FIELD_COL_START # Add border to playfield self.playfield = [x[:] for x in [[0]*self.FIELD_COLS]*self.FIELD_ROWS] self.playfield[0] = [255]*self.FIELD_COLS self.playfield[-1] = [255]*self.FIELD_COLS for col in self.playfield[1:-1]: col[0] = 255 col[-1] = 255 # initialize current tetronimo randomly self.tetromino_current = self.get_random_tetromino() self.is_game_over = False if self.drop_timer: self.drop_timer.interval = 1 def frame_rendered(self, length): self.write_playfield() # See http://tetris.wikia.com/wiki/Random_Generator for # details of random bag implementation according to tetris specification def get_random_tetromino(self): self.random_bag_index += 1 if self.random_bag_index >= len(self.random_bag): self.random_bag_index = 0 random.shuffle(self.random_bag) return self.random_bag[self.random_bag_index] def add_tetromino_to_field(self, field, pos_row, pos_col, tetromino, form): for index_col, col in enumerate(self.TETROMINOS[tetromino]): for index_row, color in enumerate(col[form]): if color != 0: row = pos_row + index_row col = pos_col + index_col if row >= 0 and row < self.FIELD_ROWS and col >= 0 and col < self.FIELD_COLS: field[row][col] = color def tetromino_fits(self, field, pos_row, pos_col, tetromino, form): for index_col, col in enumerate(self.TETROMINOS[tetromino]): for index_row, color in enumerate(col[form]): if color != 0: row = pos_row + index_row col = pos_col + index_col if row >= 0 and row < self.FIELD_ROWS and col >= 0 and col < self.FIELD_COLS: if field[row][col] != 0: return False return True def write_playfield(self): if not self.okay: return field = copy.deepcopy(self.playfield) if not self.is_game_over: self.add_tetromino_to_field(field, self.tetromino_pos_row, self.tetromino_pos_col, self.tetromino_current, self.tetromino_form) # Reorder LED data into R, G and B channel r = [] g = [] b = [] for row in reversed(range(3, self.FIELD_ROWS-1)): col_range = range(1, self.FIELD_COLS-1) if row % 2 == 0: col_range = reversed(col_range) for col in col_range: r.append(self.COLORS[field[row][col]][config.R_INDEX]) g.append(self.COLORS[field[row][col]][config.G_INDEX]) b.append(self.COLORS[field[row][col]][config.B_INDEX]) # Make chunks of size 16 r_chunk = [r[i:i+16] for i in range(0, len(r), 16)] g_chunk = [g[i:i+16] for i in range(0, len(g), 16)] b_chunk = [b[i:i+16] for i in range(0, len(b), 16)] for i in range(len(r_chunk)): length = len(r_chunk[i]) # Fill up chunks with zeros r_chunk[i].extend([0]*(16-len(r_chunk[i]))) g_chunk[i].extend([0]*(16-len(g_chunk[i]))) b_chunk[i].extend([0]*(16-len(b_chunk[i]))) try: self.led_strip.set_rgb_values(i*16, length, r_chunk[i], g_chunk[i], b_chunk[i]) except: break def clear_lines(self, rows_to_clear): if not self.okay: return self.drop_timer.stop() rows_save = {} for to_clear in rows_to_clear: rows_save[to_clear] = self.playfield[to_clear] self.display.increase_line_count(len(rows_to_clear)) self.speaker.beep_delete_line(len(rows_to_clear)) for i in range(6): if i % 2 == 0: for to_clear in rows_to_clear: self.playfield[to_clear] = [255] + [0]*(self.FIELD_COLS-2) + [255] else: for to_clear in rows_to_clear: self.playfield[to_clear] = rows_save[to_clear] time.sleep(0.1) for to_clear in rows_to_clear: for row in reversed(range(1, to_clear+1)): self.playfield[row] = self.playfield[row-1] self.playfield[1] = [255] + [0]*(self.FIELD_COLS-2) + [255] self.drop_timer.start() def check_for_lines_to_clear(self): rows_to_clear = [] for row_index, col in enumerate(self.playfield[1:-1]): to_clear = True for color in col[1:-1]: if color == 0: to_clear = False break if to_clear: rows_to_clear.append(row_index+1) if len(rows_to_clear) > 0: self.clear_lines(rows_to_clear) def new_tetromino(self): self.add_tetromino_to_field(self.playfield, self.tetromino_pos_row, self.tetromino_pos_col, self.tetromino_current, self.tetromino_form) self.tetromino_current = None self.check_for_lines_to_clear() self.tetromino_current = self.get_random_tetromino() self.tetromino_pos_row = self.FIELD_ROW_START self.tetromino_pos_col = self.FIELD_COL_START self.tetromino_form = 0 if not self.tetromino_fits(self.playfield, self.tetromino_pos_row, self.tetromino_pos_col, self.tetromino_current, self.tetromino_form): self.is_game_over = True self.game_over_position = 0 self.drop_timer.interval = 0.15 def next_game_over_step(self): for row in range(len(self.GAME_OVER_TEXT)): for col in range(config.LED_COLS): k = (self.game_over_position+col) % len(self.GAME_OVER_TEXT[0]) self.playfield[7+row][1+col] = self.GAME_OVER_COLORS[self.GAME_OVER_TEXT[row][k]] self.game_over_position += 1 def drop_tetromino(self): if self.is_game_over: self.next_game_over_step() return if self.tetromino_fits(self.playfield, self.tetromino_pos_row+1, self.tetromino_pos_col, self.tetromino_current, self.tetromino_form): self.tetromino_pos_row += 1 else: self.new_tetromino() def move_tetromino(self, row, col, form): if self.is_game_over: return if self.tetromino_fits(self.playfield, self.tetromino_pos_row+row, self.tetromino_pos_col+col, self.tetromino_current, form): self.tetromino_pos_row += row self.tetromino_pos_col += col self.tetromino_form = form if row > 0: # restart drop timer, so we don't drop two tetrominos in a row self.drop_timer.stop() self.drop_timer.start() elif row == 1: # user is at bottom and hits button to go down again self.new_tetromino() def run_game_loop(self): self.frame_rendered(0) self.drop_timer = RepeatedTimer(1.0, self.drop_tetromino) while self.loop: key = self.kp.read_single_keypress() if key == 'a': self.speaker.beep_input() self.move_tetromino(0, -1, self.tetromino_form) elif key == 'd': self.speaker.beep_input() self.move_tetromino(0, 1, self.tetromino_form) elif key == 's': self.speaker.beep_input() self.move_tetromino(1, 0, self.tetromino_form) elif key == 'k': self.speaker.beep_input() self.move_tetromino(0, 0, (self.tetromino_form-1) % 4) elif key == 'l': self.speaker.beep_input() self.move_tetromino(0, 0, (self.tetromino_form+1) % 4) elif key == 'r': self.init_game() elif not config.HAS_GUI and key == 'q': break self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_RENDERED, None) self.drop_timer.stop() self.kp.stop()
class Pong: PADDLE_SIZE = 3 # Antialased ball? # PONG_COLOR_INDEX_BALL_TOP = 8 # PONG_COLOR_INDEX_BALL_LEFT = 9 # PONG_COLOR_INDEX_BALL_RIGHT = 10 # PONG_COLOR_INDEX_BALL_BOTTOM = 11 COLORS = [ ( 0, 0, 0), # off # ( 10, 10, 10), # grey (255, 0, 0), # red (255, 80, 0), # orange (255, 255, 0), # yellow ( 0, 255, 0), # green ( 0, 0, 255), # blue (255, 0, 150), # violet (255, 0, 40), # purple ( 0, 0, 0), # ball top ( 0, 0, 0), # ball left ( 0, 0, 0), # ball right ( 0, 0, 0) # ball bottom ] SCORE_FONT = { 0: ["222", "202", "202", "202", "222"], 1: ["020", "020", "020", "020", "020"], 2: ["222", "002", "222", "200", "222"], 3: ["222", "002", "222", "002", "222"], 4: ["202", "202", "222", "002", "002"], 5: ["222", "200", "222", "002", "222"], 6: ["222", "200", "222", "202", "222"], 7: ["222", "002", "002", "002", "002"], 8: ["222", "202", "222", "202", "222"], 9: ["222", "202", "222", "002", "002"], } playfield = [x[:] for x in [[0]*config.LED_COLS]*config.LED_ROWS] score = [0, 0] paddle_position_x = [4, 15] paddle_position_y = [3, 3] ball_position = [10, 5] ball_direction = [0.1, 0.2] timer = None loop = True def __init__(self, ipcon): self.okay = False self.ipcon = ipcon if not config.UID_LED_STRIP_BRICKLET: print("Not Configured: LED Strip or LED Strip V2 (required)") return if not config.IS_LED_STRIP_V2: self.led_strip = LEDStrip(config.UID_LED_STRIP_BRICKLET, self.ipcon) else: self.led_strip = LEDStripV2(config.UID_LED_STRIP_BRICKLET, self.ipcon) try: self.led_strip.get_frame_duration() if not config.IS_LED_STRIP_V2: print("Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) else: print("Found: LED Strip V2 ({0})".format(config.UID_LED_STRIP_BRICKLET)) except: if not config.IS_LED_STRIP_V2: print("Not Found: LED Strip ({0})".format(config.UID_LED_STRIP_BRICKLET)) else: print("Not Found: LED Strip V2({0})".format(config.UID_LED_STRIP_BRICKLET)) return self.kp = KeyPress(self.ipcon) self.speaker = PongSpeaker(self.ipcon) self.okay = True self.led_strip.set_frame_duration(40) if not config.IS_LED_STRIP_V2: self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_RENDERED, self.frame_rendered) else: self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_STARTED, self.frame_rendered) self.led_strip.set_channel_mapping(config.CHANNEL_MAPPING) self.init_game() def init_game(self): self.new_ball() self.paddle_position_y = [3, 3] self.score = [0, 0] def frame_rendered(self, length): self.write_playfield() def write_playfield(self): if not self.okay: return field = copy.deepcopy(self.playfield) self.add_score_to_playfield(field) self.add_paddles_to_playfield(field) self.add_ball_to_playfield(field) # Reorder LED data into R, G and B channel r = [] g = [] b = [] frame = [] for row in range(config.LED_ROWS): col_range = range(config.LED_COLS) if row % 2 == 0: col_range = reversed(col_range) for col in col_range: r.append(self.COLORS[field[row][col]][0]) g.append(self.COLORS[field[row][col]][1]) b.append(self.COLORS[field[row][col]][2]) frame.append(self.COLORS[field[row][col]][0]) frame.append(self.COLORS[field[row][col]][1]) frame.append(self.COLORS[field[row][col]][2]) if not config.IS_LED_STRIP_V2: # Make chunks of size 16 r_chunk = [r[i:i+16] for i in range(0, len(r), 16)] g_chunk = [g[i:i+16] for i in range(0, len(g), 16)] b_chunk = [b[i:i+16] for i in range(0, len(b), 16)] for i in range(len(r_chunk)): length = len(r_chunk[i]) # Fill up chunks with zeros r_chunk[i].extend([0]*(16-len(r_chunk[i]))) g_chunk[i].extend([0]*(16-len(g_chunk[i]))) b_chunk[i].extend([0]*(16-len(b_chunk[i]))) try: self.led_strip.set_rgb_values(i*16, length, r_chunk[i], g_chunk[i], b_chunk[i]) except: break else: try: self.led_strip.set_led_values(0, frame) except: return def add_score_to_playfield(self, field): for row in range(3): for col in range(5): field[row][col+1] = int(self.SCORE_FONT[self.score[0]][col][row]) field[row+17][col+1] = int(self.SCORE_FONT[self.score[1]][col][row]) def add_ball_to_playfield(self, field): x = max(0, min(19, int(self.ball_position[0]))) y = max(0, min(9, int(self.ball_position[1]))) field[x][y] = config.PONG_COLOR_INDEX_BALL # Antialased ball? # x = max(0, min(19, self.ball_position[0])) # y = max(0, min(9, self.ball_position[1])) # ix = int(x) # iy = int(y) # field[ix][iy] = config.PONG_COLOR_INDEX_BALL # if ix + 1 < config.LED_ROWS: # field[ix+1][iy] = PONG_COLOR_INDEX_BALL_RIGHT # if ix - 1 > 0: # field[ix-1][iy] = PONG_COLOR_INDEX_BALL_LEFT # if iy + 1 < config.LED_COLS: # field[ix][iy+1] = PONG_COLOR_INDEX_BALL_TOP # if iy - 1 > 0: # field[ix][iy-1] = PONG_COLOR_INDEX_BALL_BOTTOM # # dx = x - int(x) # dy = x - int(x) # self.COLORS[PONG_COLOR_INDEX_BALL_RIGHT] = (0, 255*dx/64, 0) # self.COLORS[PONG_COLOR_INDEX_BALL_LEFT] = (0, 255*(1-dx)/64, 0) # self.COLORS[PONG_COLOR_INDEX_BALL_TOP] = (0, 255*dy/64, 0) # self.COLORS[PONG_COLOR_INDEX_BALL_BOTTOM] = (0, 255*(1-dy)/64, 0) def add_paddles_to_playfield(self, field): for player in range(2): for i in range(self.PADDLE_SIZE): field[self.paddle_position_x[player]][self.paddle_position_y[player]+i] = config.PONG_COLOR_INDEX_PLAYER[player] def move_paddle(self, player, change): new_pos = self.paddle_position_y[player] + change if new_pos >= 0 and new_pos <= config.LED_COLS - self.PADDLE_SIZE: self.paddle_position_y[player] = new_pos def new_ball(self): self.ball_position = [(config.LED_ROWS - 1.0) / 2.0, (config.LED_COLS - 1.0) / 2.0] self.ball_direction = [random.choice([-0.2, 0.2]), random.choice([random.randrange(1, 9)/10.0, random.randrange(-9, -1)/10.0])] def tick(self): # Move ball for i in range(2): self.ball_position[i] += self.ball_direction[i] # Wall collision top/bottom if self.ball_position[1] < 0 or self.ball_position[1] >= config.LED_COLS: self.ball_direction[1] = -self.ball_direction[1] # Wall collision left/right def hit_left_right(player): self.speaker.beep_sirene() self.new_ball() self.score[player] += 1 if self.score[player] > 9: self.score[player] = 0 if self.ball_position[0] < 0: hit_left_right(1) if self.ball_position[0] >= config.LED_ROWS: hit_left_right(0) # Paddle collision def hit_paddle(skew): self.speaker.beep_paddle_hit() self.ball_direction[0] = -self.ball_direction[0] self.ball_direction[1] -= skew for i in range(2): self.ball_direction[i] *= 1.1 # Increase speed if self.ball_direction[0] < 0: if self.paddle_position_x[0] + 0.5 <= self.ball_position[0] <= self.paddle_position_x[0] + 1.5: if self.paddle_position_y[0] - 0.5 <= self.ball_position[1] <= self.paddle_position_y[0] + self.PADDLE_SIZE + 0.5: paddle_skew = (self.paddle_position_y[0] + self.PADDLE_SIZE/2.0 - self.ball_position[1])/10.0 hit_paddle(paddle_skew) if self.ball_direction[0] > 0: if self.paddle_position_x[1] - 0.5 <= self.ball_position[0] <= self.paddle_position_x[1] + 0.5: if self.paddle_position_y[1] - 0.5 <= self.ball_position[1] <= self.paddle_position_y[1] + self.PADDLE_SIZE + 0.5: paddle_skew = (self.paddle_position_y[1] + self.PADDLE_SIZE/2.0 - self.ball_position[1])/10.0 hit_paddle(paddle_skew) def run_game_loop(self): self.frame_rendered(0) self.timer = RepeatedTimer(0.1, self.tick) while self.loop: key = self.kp.read_single_keypress().lower() if key == 'a': self.move_paddle(0, -1) elif key == 's': self.move_paddle(0, 1) elif key == 'k': self.move_paddle(1, -1) elif key == 'l': self.move_paddle(1, 1) elif key == 'r': self.init_game() elif not config.HAS_GUI and key == 'q': break if not config.IS_LED_STRIP_V2: self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_RENDERED, None) else: self.led_strip.register_callback(self.led_strip.CALLBACK_FRAME_STARTED, None) self.timer.stop() self.kp.stop()