optimize lock
This commit is contained in:
parent
cc0e8f10e8
commit
6866d63a32
122
tetrarcade.py
122
tetrarcade.py
@ -3,6 +3,7 @@ import sys
|
||||
import locale
|
||||
import time
|
||||
import os
|
||||
import itertools
|
||||
|
||||
try:
|
||||
import arcade
|
||||
@ -14,7 +15,7 @@ python -m pip install --user arcade
|
||||
"""
|
||||
)
|
||||
|
||||
from tetrislogic import TetrisLogic, State, AbstractScheduler
|
||||
from tetrislogic import TetrisLogic, State, AbstractScheduler, NB_LINES
|
||||
|
||||
|
||||
# Constants
|
||||
@ -34,7 +35,7 @@ TEXT_MARGIN = 40
|
||||
FONT_SIZE = 16
|
||||
TEXT_HEIGHT = 20.8
|
||||
HIGHLIGHT_TEXT_FONT_SIZE = 20
|
||||
START_TEXT = """TETRARCADE
|
||||
TITLE_AND_CONTROL_TEXT = """TETRARCADE
|
||||
|
||||
CONTROLS
|
||||
MOVE LEFT ←
|
||||
@ -42,11 +43,11 @@ MOVE RIGHT →
|
||||
SOFT DROP ↓
|
||||
HARD DROP SPACE
|
||||
ROTATE CLOCKWISE ↑
|
||||
ROTATE COUNTERCLOCKWISE Z
|
||||
ROTATE COUNTER Z
|
||||
HOLD C
|
||||
PAUSE ESC
|
||||
|
||||
PRESS [ENTER] TO START"""
|
||||
PAUSE ESC"""
|
||||
START_TEXT = TITLE_AND_CONTROL_TEXT + "\n\nPRESS [ENTER] TO START"
|
||||
PAUSE_TEXT = TITLE_AND_CONTROL_TEXT + "\n\nPRESS [ESC] TO RESUME"
|
||||
STATS_TEXT = """SCORE
|
||||
|
||||
HIGH SCORE
|
||||
@ -59,19 +60,6 @@ LINES
|
||||
|
||||
TIME
|
||||
"""
|
||||
PAUSE_TEXT = """TETRARCADE
|
||||
|
||||
CONTROLS
|
||||
MOVE LEFT ←
|
||||
MOVE RIGHT →
|
||||
SOFT DROP ↓
|
||||
HARD DROP SPACE
|
||||
ROTATE CLOCKWISE ↑
|
||||
ROTATE COUNTERCLOCKWISE Z
|
||||
HOLD C
|
||||
RESUME ESC
|
||||
|
||||
PRESS [ESC] TO RESUME"""
|
||||
GAME_OVER_TEXT = """GAME
|
||||
OVER
|
||||
|
||||
@ -125,6 +113,16 @@ class ArcadeScheduler(AbstractScheduler):
|
||||
arcade.unschedule(_task)
|
||||
del self._tasks[task]
|
||||
|
||||
def restart(self, task, period):
|
||||
try:
|
||||
_task = self._tasks[task]
|
||||
except KeyError:
|
||||
_task = lambda _: task()
|
||||
self._tasks[task] = _task
|
||||
else:
|
||||
arcade.unschedule(_task)
|
||||
arcade.schedule(_task, period)
|
||||
|
||||
|
||||
class TetrArcade(TetrisLogic, arcade.Window):
|
||||
|
||||
@ -182,15 +180,22 @@ class TetrArcade(TetrisLogic, arcade.Window):
|
||||
antialiasing = False
|
||||
)
|
||||
|
||||
center_x = self.width / 2
|
||||
center_y = self.height / 2
|
||||
self.bg_sprite = arcade.Sprite(WINDOW_BG)
|
||||
self.matrix_minoes_sprites = arcade.SpriteList()
|
||||
self.bg_sprite.center_x = center_x
|
||||
self.bg_sprite.center_y = center_y
|
||||
self.matrix_minoes_sprites = []
|
||||
self.held_piece_sprites = arcade.SpriteList()
|
||||
self.current_piece_sprites = arcade.SpriteList()
|
||||
self.ghost_piece_sprites = arcade.SpriteList()
|
||||
self.next_pieces_sprites = arcade.SpriteList()
|
||||
self.matrix_sprite = arcade.Sprite(MATRIX_SPRITE_PATH)
|
||||
self.matrix_sprite.alpha = MATRIX_SRITE_ALPHA
|
||||
self.on_resize(self.width, self.height)
|
||||
self.matrix_sprite.center_x = center_x
|
||||
self.matrix_sprite.center_y = center_y
|
||||
self.matrix_sprite.left = int(self.matrix_sprite.left)
|
||||
self.matrix_sprite.top = int(self.matrix_sprite.top)
|
||||
self.general_text = arcade.create_text(
|
||||
text = STATS_TEXT,
|
||||
color = TEXT_COLOR,
|
||||
@ -201,17 +206,40 @@ class TetrArcade(TetrisLogic, arcade.Window):
|
||||
|
||||
def new_game(self):
|
||||
self.highlight_texts = []
|
||||
self.matrix_minoes_sprites = []
|
||||
super().new_game()
|
||||
|
||||
def new_current_piece(self):
|
||||
super().new_current_piece()
|
||||
self.reload_next_pieces()
|
||||
self.reload_current_piece()
|
||||
self.reload_matrix()
|
||||
|
||||
def lock(self):
|
||||
super().lock()
|
||||
|
||||
def enter_the_matrix(self):
|
||||
super().enter_the_matrix()
|
||||
self.update_current_piece()
|
||||
for mino_coord, mino_sprite in zip(
|
||||
self.current_piece.minoes_coords,
|
||||
self.current_piece_sprites
|
||||
):
|
||||
mino_coord += self.current_piece.coord
|
||||
self.matrix_minoes_sprites[
|
||||
mino_coord.y
|
||||
].append(mino_sprite)
|
||||
|
||||
def append_new_line_to_matrix(self):
|
||||
super().append_new_line_to_matrix()
|
||||
self.matrix_minoes_sprites.append(arcade.SpriteList())
|
||||
|
||||
def remove_line_of_matrix(self, line):
|
||||
super().remove_line_of_matrix(line)
|
||||
self.matrix_minoes_sprites.pop(line)
|
||||
for line_sprites in self.matrix_minoes_sprites[line:NB_LINES+2]:
|
||||
for mino_sprite in line_sprites:
|
||||
mino_sprite.center_y -= mino_sprite.height-1
|
||||
|
||||
def swap(self):
|
||||
super().swap()
|
||||
self.reload_held_piece()
|
||||
@ -272,19 +300,6 @@ class TetrArcade(TetrisLogic, arcade.Window):
|
||||
self.current_piece_sprites = self.reload_piece(self.current_piece)
|
||||
self.ghost_piece_sprites = self.reload_piece(self.ghost_piece)
|
||||
|
||||
def reload_matrix(self):
|
||||
if self.matrix:
|
||||
self.matrix_minoes_sprites = arcade.SpriteList()
|
||||
for y, line in enumerate(self.matrix):
|
||||
for x, mino_color in enumerate(line):
|
||||
if mino_color:
|
||||
mino_sprite_path = MINOES_SPRITES_PATHS[mino_color]
|
||||
mino_sprite = arcade.Sprite(mino_sprite_path)
|
||||
mino_sprite.left = self.matrix_sprite.left + x*(mino_sprite.width-1)
|
||||
mino_sprite.bottom = self.matrix_sprite.bottom + y*(mino_sprite.height-1)
|
||||
mino_sprite.alpha = 200
|
||||
self.matrix_minoes_sprites.append(mino_sprite)
|
||||
|
||||
def update_piece(self, piece, piece_sprites):
|
||||
if piece:
|
||||
for mino_sprite, mino_coord in zip(
|
||||
@ -294,17 +309,7 @@ class TetrArcade(TetrisLogic, arcade.Window):
|
||||
mino_sprite.left = self.matrix_sprite.left + mino_coord.x*(mino_sprite.width-1)
|
||||
mino_sprite.bottom = self.matrix_sprite.bottom + mino_coord.y*(mino_sprite.height-1)
|
||||
|
||||
def on_draw(self):
|
||||
arcade.start_render()
|
||||
self.bg_sprite.draw()
|
||||
|
||||
if self.state in (State.PLAYING, State.OVER):
|
||||
self.matrix_sprite.draw()
|
||||
self.matrix_minoes_sprites.draw()
|
||||
|
||||
self.update_piece(self.held_piece, self.held_piece_sprites)
|
||||
self.held_piece_sprites.draw()
|
||||
|
||||
def update_current_piece(self):
|
||||
self.update_piece(self.current_piece, self.current_piece_sprites)
|
||||
if self.current_piece.prelocked:
|
||||
alpha = (
|
||||
@ -314,6 +319,20 @@ class TetrArcade(TetrisLogic, arcade.Window):
|
||||
)
|
||||
for mino_sprite in self.current_piece_sprites:
|
||||
mino_sprite.alpha = alpha
|
||||
|
||||
def on_draw(self):
|
||||
arcade.start_render()
|
||||
self.bg_sprite.draw()
|
||||
|
||||
if self.state in (State.PLAYING, State.OVER):
|
||||
self.matrix_sprite.draw()
|
||||
for line in self.matrix_minoes_sprites:
|
||||
line.draw()
|
||||
|
||||
self.update_piece(self.held_piece, self.held_piece_sprites)
|
||||
self.held_piece_sprites.draw()
|
||||
|
||||
self.update_current_piece()
|
||||
self.current_piece_sprites.draw()
|
||||
|
||||
self.update_piece(self.ghost_piece, self.ghost_piece_sprites)
|
||||
@ -379,17 +398,6 @@ class TetrArcade(TetrisLogic, arcade.Window):
|
||||
anchor_y = 'center'
|
||||
)
|
||||
|
||||
def on_resize(self, width, height):
|
||||
center_x = self.width / 2
|
||||
center_y = self.height / 2
|
||||
self.bg_sprite.center_x = center_x
|
||||
self.bg_sprite.center_y = center_y
|
||||
self.matrix_sprite.center_x = center_x
|
||||
self.matrix_sprite.center_y = center_y
|
||||
self.matrix_sprite.left = int(self.matrix_sprite.left)
|
||||
self.matrix_sprite.top = int(self.matrix_sprite.top)
|
||||
self.reload_matrix()
|
||||
|
||||
def load_high_score(self):
|
||||
try:
|
||||
with open(HIGH_SCORE_PATH, "r") as f:
|
||||
|
@ -76,8 +76,18 @@ class AbstractScheduler:
|
||||
|
||||
class Tetromino:
|
||||
|
||||
random_bag = []
|
||||
|
||||
|
||||
class MetaTetromino(type):
|
||||
|
||||
def __init__(cls, name, bases, dico):
|
||||
super().__init__(name, bases, dico)
|
||||
cls.classes.append(cls)
|
||||
|
||||
|
||||
class AbstractTetromino:
|
||||
|
||||
# Super rotation system
|
||||
SRS = {
|
||||
Rotation.COUNTERCLOCKWISE: (
|
||||
@ -94,6 +104,7 @@ class Tetromino:
|
||||
)
|
||||
}
|
||||
CAN_SPIN = False
|
||||
classes = []
|
||||
|
||||
def __init__(self):
|
||||
self.coord = NEXT_PIECES_COORDS[-1]
|
||||
@ -107,7 +118,7 @@ class Tetromino:
|
||||
return self.__class__()
|
||||
|
||||
|
||||
class O(AbstractTetromino):
|
||||
class O(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
SRS = {
|
||||
Rotation.COUNTERCLOCKWISE: (tuple(), tuple(), tuple(), tuple()),
|
||||
@ -120,7 +131,7 @@ class Tetromino:
|
||||
return False
|
||||
|
||||
|
||||
class I(AbstractTetromino):
|
||||
class I(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
SRS = {
|
||||
Rotation.COUNTERCLOCKWISE: (
|
||||
@ -140,43 +151,40 @@ class Tetromino:
|
||||
MINOES_COLOR = "cyan"
|
||||
|
||||
|
||||
class T(AbstractTetromino):
|
||||
class T(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
MINOES_COORDS = (Coord(-1, 0), Coord(0, 0), Coord(0, 1), Coord(1, 0))
|
||||
MINOES_COLOR = "magenta"
|
||||
CAN_SPIN = True
|
||||
|
||||
|
||||
class L(AbstractTetromino):
|
||||
class L(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
MINOES_COORDS = (Coord(-1, 0), Coord(0, 0), Coord(1, 0), Coord(1, 1))
|
||||
MINOES_COLOR = "orange"
|
||||
|
||||
|
||||
class J(AbstractTetromino):
|
||||
class J(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
MINOES_COORDS = (Coord(-1, 1), Coord(-1, 0), Coord(0, 0), Coord(1, 0))
|
||||
MINOES_COLOR = "blue"
|
||||
|
||||
|
||||
class S(AbstractTetromino):
|
||||
class S(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
MINOES_COORDS = (Coord(-1, 0), Coord(0, 0), Coord(0, 1), Coord(1, 1))
|
||||
MINOES_COLOR = "green"
|
||||
|
||||
|
||||
class Z(AbstractTetromino):
|
||||
class Z(AbstractTetromino, metaclass=MetaTetromino):
|
||||
|
||||
MINOES_COORDS = (Coord(-1, 1), Coord(0, 1), Coord(0, 0), Coord(1, 0))
|
||||
MINOES_COLOR = "red"
|
||||
|
||||
|
||||
TETROMINOES = (O, I, T, L, J, S, Z)
|
||||
random_bag = []
|
||||
|
||||
def __new__(cls):
|
||||
if not cls.random_bag:
|
||||
cls.random_bag = list(cls.TETROMINOES)
|
||||
cls.random_bag = list(Tetromino.AbstractTetromino.classes)
|
||||
random.shuffle(cls.random_bag)
|
||||
return cls.random_bag.pop()()
|
||||
|
||||
@ -209,10 +217,9 @@ class TetrisLogic():
|
||||
self.lock_delay = LOCK_DELAY
|
||||
self.fall_delay = FALL_DELAY
|
||||
|
||||
self.matrix = [
|
||||
[None for x in range(NB_COLS)]
|
||||
for y in range(NB_LINES+3)
|
||||
]
|
||||
self.matrix = []
|
||||
for y in range(NB_LINES+3):
|
||||
self.append_new_line_to_matrix()
|
||||
self.next_pieces = [Tetromino() for i in range(NB_NEXT_PIECES)]
|
||||
self.current_piece = None
|
||||
self.held_piece = None
|
||||
@ -341,8 +348,8 @@ class TetrisLogic():
|
||||
self.current_piece.prelocked = False
|
||||
self.scheduler.stop(self.lock)
|
||||
if self.pressed_actions:
|
||||
self.stop_autorepeat()
|
||||
self.scheduler.start(self.repeat_action, AUTOREPEAT_DELAY)
|
||||
self.auto_repeat = False
|
||||
self.scheduler.restart(self.repeat_action, AUTOREPEAT_DELAY)
|
||||
|
||||
# Game over
|
||||
if all(
|
||||
@ -352,19 +359,15 @@ class TetrisLogic():
|
||||
self.game_over()
|
||||
return
|
||||
|
||||
# Insert tetromino in the matrix
|
||||
for mino_coord in self.current_piece.minoes_coords:
|
||||
coord = mino_coord + self.current_piece.coord
|
||||
if coord.y <= NB_LINES+3:
|
||||
self.matrix[coord.y][coord.x] = self.current_piece.MINOES_COLOR
|
||||
self.enter_the_matrix()
|
||||
|
||||
# Clear complete lines
|
||||
nb_lines_cleared = 0
|
||||
for y, line in reversed(list(enumerate(self.matrix))):
|
||||
if all(mino for mino in line):
|
||||
nb_lines_cleared += 1
|
||||
self.matrix.pop(y)
|
||||
self.matrix.append([None for x in range(NB_COLS)])
|
||||
self.remove_line_of_matrix(y)
|
||||
self.append_new_line_to_matrix()
|
||||
if nb_lines_cleared:
|
||||
self.nb_lines += nb_lines_cleared
|
||||
|
||||
@ -423,6 +426,19 @@ class TetrisLogic():
|
||||
else:
|
||||
self.new_current_piece()
|
||||
|
||||
def enter_the_matrix(self):
|
||||
for mino_coord in self.current_piece.minoes_coords:
|
||||
coord = mino_coord + self.current_piece.coord
|
||||
if coord.y <= NB_LINES+3:
|
||||
self.matrix[coord.y][coord.x] = self.current_piece.MINOES_COLOR
|
||||
|
||||
|
||||
def append_new_line_to_matrix(self):
|
||||
self.matrix.append([None for x in range(NB_COLS)])
|
||||
|
||||
def remove_line_of_matrix(self, line):
|
||||
self.matrix.pop(line)
|
||||
|
||||
def can_move(self, potential_coord, minoes_coords):
|
||||
return all(
|
||||
self.cell_is_free(potential_coord+mino_coord)
|
||||
@ -478,7 +494,8 @@ class TetrisLogic():
|
||||
self.scheduler.stop(self.lock)
|
||||
self.scheduler.stop(self.update_time)
|
||||
self.pressed_actions = []
|
||||
self.stop_autorepeat()
|
||||
self.auto_repeat = False
|
||||
self.scheduler.stop(self.repeat_action)
|
||||
|
||||
def resume(self):
|
||||
self.state = State.PLAYING
|
||||
@ -494,15 +511,15 @@ class TetrisLogic():
|
||||
self.scheduler.stop(self.repeat_action)
|
||||
self.save_high_score()
|
||||
|
||||
def update_time(self, delta_time=1):
|
||||
self.time += delta_time
|
||||
def update_time(self):
|
||||
self.time += 1
|
||||
|
||||
def do_action(self, action):
|
||||
action()
|
||||
if action in self.autorepeatable_actions:
|
||||
self.stop_autorepeat()
|
||||
self.auto_repeat = False
|
||||
self.pressed_actions.append(action)
|
||||
self.scheduler.start(self.repeat_action, AUTOREPEAT_DELAY)
|
||||
self.scheduler.restart(self.repeat_action, AUTOREPEAT_DELAY)
|
||||
|
||||
def repeat_action(self):
|
||||
if self.pressed_actions:
|
||||
@ -511,7 +528,8 @@ class TetrisLogic():
|
||||
self.auto_repeat = True
|
||||
self.scheduler.restart(self.repeat_action, AUTOREPEAT_PERIOD)
|
||||
else:
|
||||
self.stop_autorepeat()
|
||||
self.auto_repeat = False
|
||||
self.scheduler.stop(self.repeat_action)
|
||||
|
||||
def remove_action(self, action):
|
||||
if action in self.autorepeatable_actions:
|
||||
@ -520,10 +538,6 @@ class TetrisLogic():
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def stop_autorepeat(self):
|
||||
self.auto_repeat = False
|
||||
self.scheduler.stop(self.repeat_action)
|
||||
|
||||
def show_text(self, text):
|
||||
print(text)
|
||||
raise Warning("TetrisLogic.show_text not implemented.")
|
||||
|
Loading…
x
Reference in New Issue
Block a user