Use nuitka for compiling, reorganize py files
This commit is contained in:
parent
8139bf8154
commit
54bce41d50
1528
Tetris2000.py
1528
Tetris2000.py
File diff suppressed because it is too large
Load Diff
BIN
dist/Tetris2000.exe
vendored
BIN
dist/Tetris2000.exe
vendored
Binary file not shown.
@ -1,43 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
|
|
||||||
block_cipher = None
|
|
||||||
|
|
||||||
|
|
||||||
a = Analysis(['Tetris2000.py'],
|
|
||||||
pathex=[],
|
|
||||||
binaries=[],
|
|
||||||
datas=[
|
|
||||||
("backgrounds/*", "backgrounds"),
|
|
||||||
("fonts/*.ttf", "fonts"),
|
|
||||||
("fonts/*.otf", "fonts"),
|
|
||||||
("icons/*.ico", "icons"),
|
|
||||||
("icons/splash_screen.png", "icons"),
|
|
||||||
("locale/*.qm", "locale"),
|
|
||||||
("musics/*.mp3", "musics"),
|
|
||||||
("sfx/*.wav", "sfx")
|
|
||||||
],
|
|
||||||
hiddenimports=[],
|
|
||||||
hookspath=[],
|
|
||||||
runtime_hooks=[],
|
|
||||||
excludes=["PyQt4", "PySide", "PySide2"],
|
|
||||||
win_no_prefer_redirects=False,
|
|
||||||
win_private_assemblies=False,
|
|
||||||
cipher=block_cipher)
|
|
||||||
pyz = PYZ(a.pure, a.zipped_data,
|
|
||||||
cipher=block_cipher)
|
|
||||||
exe = EXE(pyz,
|
|
||||||
a.scripts,
|
|
||||||
exclude_binaries=True,
|
|
||||||
name='Tetris2000',
|
|
||||||
debug=False,
|
|
||||||
strip=False,
|
|
||||||
upx=False,
|
|
||||||
console=False,
|
|
||||||
icon='icons\icon.ico')
|
|
||||||
coll = COLLECT(exe,
|
|
||||||
a.binaries,
|
|
||||||
a.zipfiles,
|
|
||||||
a.datas,
|
|
||||||
strip=False,
|
|
||||||
upx=False,
|
|
||||||
name='Tetris2000')
|
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
__author__ = "Adrien Malingrey"
|
__author__ = "Adrien Malingrey"
|
||||||
__title__ = "Tetris 2000"
|
__title__ = "Tetris 2000"
|
||||||
__version__ = "0.3"
|
__version__ = "0.3"
|
@ -1,107 +1,108 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from qt5 import QtGui
|
from .qt5 import QtGui
|
||||||
|
|
||||||
|
|
||||||
# Paths
|
# Paths
|
||||||
PATH = os.path.dirname(os.path.abspath(__file__))
|
PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
ICON_PATH = os.path.join(PATH, "icons", "icon.ico")
|
PATH = os.path.dirname(PATH)
|
||||||
BG_IMAGE_DIR = os.path.join(PATH, "backgrounds")
|
ICON_PATH = os.path.join(PATH, "icons", "icon.ico")
|
||||||
START_BG_IMAGE_NAME = "01-spacefield_a-000.png"
|
BG_IMAGE_DIR = os.path.join(PATH, "backgrounds")
|
||||||
MUSICS_DIR = os.path.join(PATH, "musics")
|
START_BG_IMAGE_NAME = "01-spacefield_a-000.png"
|
||||||
SFX_DIR = os.path.join(PATH, "sfx")
|
MUSICS_DIR = os.path.join(PATH, "musics")
|
||||||
LINE_CLEAR_SFX_PATH = os.path.join(SFX_DIR, "line_clear.wav")
|
SFX_DIR = os.path.join(PATH, "sfx")
|
||||||
TETRIS_SFX_PATH = os.path.join(SFX_DIR, "tetris.wav")
|
LINE_CLEAR_SFX_PATH = os.path.join(SFX_DIR, "line_clear.wav")
|
||||||
ROTATE_SFX_PATH = os.path.join(SFX_DIR, "rotate.wav")
|
TETRIS_SFX_PATH = os.path.join(SFX_DIR, "tetris.wav")
|
||||||
HARD_DROP_SFX_PATH = os.path.join(SFX_DIR, "hard_drop.wav")
|
ROTATE_SFX_PATH = os.path.join(SFX_DIR, "rotate.wav")
|
||||||
WALL_SFX_PATH = os.path.join(SFX_DIR, "wall.wav")
|
HARD_DROP_SFX_PATH = os.path.join(SFX_DIR, "hard_drop.wav")
|
||||||
LOCALE_PATH = os.path.join(PATH, "locale")
|
WALL_SFX_PATH = os.path.join(SFX_DIR, "wall.wav")
|
||||||
FONTS_DIR = os.path.join(PATH, "fonts")
|
LOCALE_PATH = os.path.join(PATH, "locale")
|
||||||
STATS_FONT_PATH = os.path.join(FONTS_DIR, "PixelCaps!.otf")
|
FONTS_DIR = os.path.join(PATH, "fonts")
|
||||||
STATS_FONT_NAME = "PixelCaps!"
|
STATS_FONT_PATH = os.path.join(FONTS_DIR, "PixelCaps!.otf")
|
||||||
MATRIX_FONT_PATH = os.path.join(FONTS_DIR, "maass slicer Italic.ttf")
|
STATS_FONT_NAME = "PixelCaps!"
|
||||||
MATRIX_FONT_NAME = "Maassslicer"
|
MATRIX_FONT_PATH = os.path.join(FONTS_DIR, "maass slicer Italic.ttf")
|
||||||
|
MATRIX_FONT_NAME = "Maassslicer"
|
||||||
SPLASH_SCREEN_PATH = os.path.join(PATH, "icons", "splash_screen.png")
|
|
||||||
|
SPLASH_SCREEN_PATH = os.path.join(PATH, "icons", "splash_screen.png")
|
||||||
# Coordinates and direction
|
|
||||||
L, R, U, D = -1, 1, -1, 1 # Left, Right, Up, Down
|
# Coordinates and direction
|
||||||
CLOCKWISE, COUNTERCLOCKWISE = 1, -1
|
L, R, U, D = -1, 1, -1, 1 # Left, Right, Up, Down
|
||||||
|
CLOCKWISE, COUNTERCLOCKWISE = 1, -1
|
||||||
# Delays in milliseconds
|
|
||||||
ANIMATION_DELAY = 67
|
# Delays in milliseconds
|
||||||
INITIAL_SPEED = 1000
|
ANIMATION_DELAY = 67
|
||||||
ENTRY_DELAY = 80
|
INITIAL_SPEED = 1000
|
||||||
LINE_CLEAR_DELAY = 80
|
ENTRY_DELAY = 80
|
||||||
LOCK_DELAY = 500
|
LINE_CLEAR_DELAY = 80
|
||||||
TEMPORARY_TEXT_DURATION = 1000
|
LOCK_DELAY = 500
|
||||||
AFTER_LVL_15_ACCELERATION = 0.9
|
TEMPORARY_TEXT_DURATION = 1000
|
||||||
|
AFTER_LVL_15_ACCELERATION = 0.9
|
||||||
# Block Colors
|
|
||||||
BLOCK_BORDER_COLOR = QtGui.QColor(0, 159, 218, 255)
|
# Block Colors
|
||||||
BLOCK_FILL_COLOR = QtGui.QColor(0, 159, 218, 25)
|
BLOCK_BORDER_COLOR = QtGui.QColor(0, 159, 218, 255)
|
||||||
BLOCK_GLOWING_BORDER_COLOR = None
|
BLOCK_FILL_COLOR = QtGui.QColor(0, 159, 218, 25)
|
||||||
BLOCK_GLOWING_FILL_COLOR = QtGui.QColor(186, 211, 255, 70)
|
BLOCK_GLOWING_BORDER_COLOR = None
|
||||||
BLOCK_LIGHT_COLOR = QtGui.QColor(242, 255, 255, 40)
|
BLOCK_GLOWING_FILL_COLOR = QtGui.QColor(186, 211, 255, 70)
|
||||||
BLOCK_TRANSPARENT = QtGui.QColor(255, 255, 255, 0)
|
BLOCK_LIGHT_COLOR = QtGui.QColor(242, 255, 255, 40)
|
||||||
BLOCK_GLOWING = 0
|
BLOCK_TRANSPARENT = QtGui.QColor(255, 255, 255, 0)
|
||||||
BLOCK_INITIAL_SIDE = 20
|
BLOCK_GLOWING = 0
|
||||||
|
BLOCK_INITIAL_SIDE = 20
|
||||||
GHOST_BLOCK_BORDER_COLOR = QtGui.QColor(135, 213, 255, 255)
|
|
||||||
GHOST_BLOCK_FILL_COLOR = None
|
GHOST_BLOCK_BORDER_COLOR = QtGui.QColor(135, 213, 255, 255)
|
||||||
GHOST_BLOCK_GLOWING_FILL_COLOR = QtGui.QColor(201, 149, 205, 255)
|
GHOST_BLOCK_FILL_COLOR = None
|
||||||
GHOST_BLOCK_GLOWING = 1
|
GHOST_BLOCK_GLOWING_FILL_COLOR = QtGui.QColor(201, 149, 205, 255)
|
||||||
|
GHOST_BLOCK_GLOWING = 1
|
||||||
# Grid
|
|
||||||
GRID_INVISIBLE_ROWS = 3
|
# Grid
|
||||||
GRID_DEFAULT_ROWS = 4
|
GRID_INVISIBLE_ROWS = 3
|
||||||
GRID_DEFAULT_COLUMNS = 6
|
GRID_DEFAULT_ROWS = 4
|
||||||
GRID_GRIDLINE_COLOR = QtGui.QColor(255, 255, 255, 60)
|
GRID_DEFAULT_COLUMNS = 6
|
||||||
GRID_HARD_DROP_MOVEMENT = 0.2
|
GRID_GRIDLINE_COLOR = QtGui.QColor(255, 255, 255, 60)
|
||||||
GRID_SPOTLIGHT = 0, 0
|
GRID_HARD_DROP_MOVEMENT = 0.2
|
||||||
|
GRID_SPOTLIGHT = 0, 0
|
||||||
# Matrix
|
|
||||||
MATRIX_ROWS = 20
|
# Matrix
|
||||||
MATRIX_COLUMNS = 10
|
MATRIX_ROWS = 20
|
||||||
MATRIX_TEXT_COLOR = QtGui.QColor(204, 255, 255, 128)
|
MATRIX_COLUMNS = 10
|
||||||
|
MATRIX_TEXT_COLOR = QtGui.QColor(204, 255, 255, 128)
|
||||||
# Next Queue
|
|
||||||
NEXT_QUEUE_ROWS = 16
|
# Next Queue
|
||||||
NEXT_QUEUE_COLUMNS = 6
|
NEXT_QUEUE_ROWS = 16
|
||||||
|
NEXT_QUEUE_COLUMNS = 6
|
||||||
# Stats frame
|
|
||||||
STATS_ROWS = 15
|
# Stats frame
|
||||||
STATS_COLUMNS = 6
|
STATS_ROWS = 15
|
||||||
STATS_TEXT_COLOR = QtGui.QColor(0, 159, 218, 128)
|
STATS_COLUMNS = 6
|
||||||
SCORES = (
|
STATS_TEXT_COLOR = QtGui.QColor(0, 159, 218, 128)
|
||||||
{"name": "", "": 0, "Mini T-Spin": 1, "T-Spin": 4},
|
SCORES = (
|
||||||
{"name": "Single", "": 1, "Mini T-Spin": 2, "T-Spin": 8},
|
{"name": "", "": 0, "Mini T-Spin": 1, "T-Spin": 4},
|
||||||
{"name": "Double", "": 3, "T-Spin": 12},
|
{"name": "Single", "": 1, "Mini T-Spin": 2, "T-Spin": 8},
|
||||||
{"name": "Triple", "": 5, "T-Spin": 16},
|
{"name": "Double", "": 3, "T-Spin": 12},
|
||||||
{"name": "Tetris", "": 8},
|
{"name": "Triple", "": 5, "T-Spin": 16},
|
||||||
)
|
{"name": "Tetris", "": 8},
|
||||||
|
)
|
||||||
# Default settings
|
|
||||||
DEFAULT_WINDOW_SIZE = 839, 807
|
# Default settings
|
||||||
# Key mapping
|
DEFAULT_WINDOW_SIZE = 839, 807
|
||||||
DEFAULT_MOVE_LEFT_KEY = "Left"
|
# Key mapping
|
||||||
DEFAULT_MOVE_RIGHT_KEY = "Right"
|
DEFAULT_MOVE_LEFT_KEY = "Left"
|
||||||
DEFAULT_ROTATE_CLOCKWISE_KEY = "Up"
|
DEFAULT_MOVE_RIGHT_KEY = "Right"
|
||||||
DEFAULT_ROTATE_COUNTERCLOCKWISE_KEY = "Control"
|
DEFAULT_ROTATE_CLOCKWISE_KEY = "Up"
|
||||||
DEFAULT_SOFT_DROP_KEY = "Down"
|
DEFAULT_ROTATE_COUNTERCLOCKWISE_KEY = "Control"
|
||||||
DEFAULT_HARD_DROP_KEY = "Space"
|
DEFAULT_SOFT_DROP_KEY = "Down"
|
||||||
DEFAULT_HOLD_KEY = "Shift"
|
DEFAULT_HARD_DROP_KEY = "Space"
|
||||||
DEFAULT_PAUSE_KEY = "Escape"
|
DEFAULT_HOLD_KEY = "Shift"
|
||||||
# Delays in milliseconds
|
DEFAULT_PAUSE_KEY = "Escape"
|
||||||
DEFAULT_AUTO_SHIFT_DELAY = 170
|
# Delays in milliseconds
|
||||||
DEFAULT_AUTO_REPEAT_RATE = 20
|
DEFAULT_AUTO_SHIFT_DELAY = 170
|
||||||
# Volume in percent
|
DEFAULT_AUTO_REPEAT_RATE = 20
|
||||||
DEFAUT_MUSIC_VOLUME = 25
|
# Volume in percent
|
||||||
DEFAULT_SFX_VOLUME = 50
|
DEFAUT_MUSIC_VOLUME = 25
|
||||||
# Other
|
DEFAULT_SFX_VOLUME = 50
|
||||||
DEFAULT_SHOW_GHOST = True
|
# Other
|
||||||
DEFAULT_SHOW_NEXT_QUEUE = True
|
DEFAULT_SHOW_GHOST = True
|
||||||
DEFAULT_HOLD_ENABLED = True
|
DEFAULT_SHOW_NEXT_QUEUE = True
|
||||||
|
DEFAULT_HOLD_ENABLED = True
|
1520
source/game_gui.py
Normal file
1520
source/game_gui.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,48 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
from consts import CLOCKWISE
|
from .consts import CLOCKWISE
|
||||||
from qt5 import QtCore
|
from .qt5 import QtCore
|
||||||
from propertize import propertize, rename_attributes, snake_case
|
from .propertize import propertize, rename_attributes, snake_case
|
||||||
|
|
||||||
|
|
||||||
@propertize("", "set_")
|
@propertize("", "set_")
|
||||||
@rename_attributes(snake_case)
|
@rename_attributes(snake_case)
|
||||||
class Point(QtCore.QPoint):
|
class Point(QtCore.QPoint):
|
||||||
"""
|
"""
|
||||||
Point of coordinates (x, y)
|
Point of coordinates (x, y)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def rotate(self, center, direction=CLOCKWISE):
|
def rotate(self, center, direction=CLOCKWISE):
|
||||||
""" Returns the Point image of the rotation of self
|
""" Returns the Point image of the rotation of self
|
||||||
through 90° CLOKWISE or COUNTERCLOCKWISE around center"""
|
through 90° CLOKWISE or COUNTERCLOCKWISE around center"""
|
||||||
if self == center:
|
if self == center:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
p = self - center
|
p = self - center
|
||||||
p = Point(-direction * p.y, direction * p.x)
|
p = Point(-direction * p.y, direction * p.x)
|
||||||
p += center
|
p += center
|
||||||
return p
|
return p
|
||||||
|
|
||||||
def __add__(self, o):
|
def __add__(self, o):
|
||||||
return Point(self.x + o.x, self.y + o.y)
|
return Point(self.x + o.x, self.y + o.y)
|
||||||
|
|
||||||
def __sub__(self, o):
|
def __sub__(self, o):
|
||||||
return Point(self.x - o.x, self.y - o.y)
|
return Point(self.x - o.x, self.y - o.y)
|
||||||
|
|
||||||
def __mul__(self, k):
|
def __mul__(self, k):
|
||||||
return Point(k * self.x, k * self.y)
|
return Point(k * self.x, k * self.y)
|
||||||
|
|
||||||
def __truediv__(self, k):
|
def __truediv__(self, k):
|
||||||
return Point(self.x / k, self.y / k)
|
return Point(self.x / k, self.y / k)
|
||||||
|
|
||||||
__radd__ = __add__
|
__radd__ = __add__
|
||||||
__rsub__ = __sub__
|
__rsub__ = __sub__
|
||||||
__rmul__ = __mul__
|
__rmul__ = __mul__
|
||||||
__rtruediv__ = __truediv__
|
__rtruediv__ = __truediv__
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Point({}, {})".format(self.x, self.y)
|
return "Point({}, {})".format(self.x, self.y)
|
||||||
|
|
||||||
__str__ = __repr__
|
__str__ = __repr__
|
@ -1,29 +1,29 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtWidgets, QtCore, QtGui, QtMultimedia
|
from PyQt5 import QtWidgets, QtCore, QtGui, QtMultimedia
|
||||||
except ImportError as pyqt5_error:
|
except ImportError as pyqt5_error:
|
||||||
try:
|
try:
|
||||||
from PySide2 import QtWidgets, QtCore, QtGui, QtMultimedia
|
from PySide2 import QtWidgets, QtCore, QtGui, QtMultimedia
|
||||||
except ImportError as pyside2_error:
|
except ImportError as pyside2_error:
|
||||||
sys.exit(
|
sys.exit(
|
||||||
"This program require a Qt5 library.\n"
|
"This program require a Qt5 library.\n"
|
||||||
"You can install PyQt5 (recommended) :\n"
|
"You can install PyQt5 (recommended) :\n"
|
||||||
" pip3 install --user PyQt5\n"
|
" pip3 install --user PyQt5\n"
|
||||||
" pip3 install --user qdarkstyle\n"
|
" pip3 install --user qdarkstyle\n"
|
||||||
"or PySide2 :\n"
|
"or PySide2 :\n"
|
||||||
" pip3 install --user PySide2\n"
|
" pip3 install --user PySide2\n"
|
||||||
+ pyqt5_error.msg
|
+ pyqt5_error.msg
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ pyside2_error.msg
|
+ pyside2_error.msg
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
os.environ["QT_API"] = "pyside2"
|
os.environ["QT_API"] = "pyside2"
|
||||||
else:
|
else:
|
||||||
os.environ["QT_API"] = "pyqt5"
|
os.environ["QT_API"] = "pyqt5"
|
||||||
QtCore.Signal = QtCore.pyqtSignal
|
QtCore.Signal = QtCore.pyqtSignal
|
||||||
|
|
@ -1,422 +1,422 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import consts
|
from . import consts
|
||||||
from consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE
|
from .consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE
|
||||||
from point import Point
|
from .point import Point
|
||||||
from qt5 import QtCore, QtGui
|
from .qt5 import QtCore, QtGui
|
||||||
|
|
||||||
|
|
||||||
class Block:
|
class Block:
|
||||||
"""
|
"""
|
||||||
Mino or block
|
Mino or block
|
||||||
Mino : A single square-shaped building block of a shape called a Tetrimino.
|
Mino : A single square-shaped building block of a shape called a Tetrimino.
|
||||||
Four Minos arranged into any of their various connected patterns is known as a Tetrimino
|
Four Minos arranged into any of their various connected patterns is known as a Tetrimino
|
||||||
Block : A single block locked in a cell in the Grid
|
Block : A single block locked in a cell in the Grid
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Colors
|
# Colors
|
||||||
BORDER_COLOR = consts.BLOCK_BORDER_COLOR
|
BORDER_COLOR = consts.BLOCK_BORDER_COLOR
|
||||||
FILL_COLOR = consts.BLOCK_FILL_COLOR
|
FILL_COLOR = consts.BLOCK_FILL_COLOR
|
||||||
GLOWING_BORDER_COLOR = consts.BLOCK_GLOWING_BORDER_COLOR
|
GLOWING_BORDER_COLOR = consts.BLOCK_GLOWING_BORDER_COLOR
|
||||||
GLOWING_FILL_COLOR = consts.BLOCK_GLOWING_FILL_COLOR
|
GLOWING_FILL_COLOR = consts.BLOCK_GLOWING_FILL_COLOR
|
||||||
LIGHT_COLOR = consts.BLOCK_LIGHT_COLOR
|
LIGHT_COLOR = consts.BLOCK_LIGHT_COLOR
|
||||||
TRANSPARENT = consts.BLOCK_TRANSPARENT
|
TRANSPARENT = consts.BLOCK_TRANSPARENT
|
||||||
GLOWING = consts.BLOCK_GLOWING
|
GLOWING = consts.BLOCK_GLOWING
|
||||||
|
|
||||||
side = consts.BLOCK_INITIAL_SIDE
|
side = consts.BLOCK_INITIAL_SIDE
|
||||||
|
|
||||||
def __init__(self, coord, trail=0):
|
def __init__(self, coord, trail=0):
|
||||||
self.coord = coord
|
self.coord = coord
|
||||||
self.trail = trail
|
self.trail = trail
|
||||||
self.border_color = self.BORDER_COLOR
|
self.border_color = self.BORDER_COLOR
|
||||||
self.fill_color = self.FILL_COLOR
|
self.fill_color = self.FILL_COLOR
|
||||||
self.glowing = self.GLOWING
|
self.glowing = self.GLOWING
|
||||||
|
|
||||||
def paint(self, painter, top_left_corner, spotlight):
|
def paint(self, painter, top_left_corner, spotlight):
|
||||||
p = top_left_corner + self.coord * Block.side
|
p = top_left_corner + self.coord * Block.side
|
||||||
block_center = Point(Block.side / 2, Block.side / 2)
|
block_center = Point(Block.side / 2, Block.side / 2)
|
||||||
self.center = p + block_center
|
self.center = p + block_center
|
||||||
spotlight = top_left_corner + Block.side * spotlight + block_center
|
spotlight = top_left_corner + Block.side * spotlight + block_center
|
||||||
self.glint = 0.15 * spotlight + 0.85 * self.center
|
self.glint = 0.15 * spotlight + 0.85 * self.center
|
||||||
|
|
||||||
if self.trail:
|
if self.trail:
|
||||||
start = (
|
start = (
|
||||||
top_left_corner + (self.coord + Point(0, self.trail * U)) * Block.side
|
top_left_corner + (self.coord + Point(0, self.trail * U)) * Block.side
|
||||||
)
|
)
|
||||||
stop = top_left_corner + (self.coord + Point(0, 2 * D)) * Block.side
|
stop = top_left_corner + (self.coord + Point(0, 2 * D)) * Block.side
|
||||||
fill = QtGui.QLinearGradient(start, stop)
|
fill = QtGui.QLinearGradient(start, stop)
|
||||||
fill.setColorAt(0, self.LIGHT_COLOR)
|
fill.setColorAt(0, self.LIGHT_COLOR)
|
||||||
fill.setColorAt(1, self.GLOWING_FILL_COLOR)
|
fill.setColorAt(1, self.GLOWING_FILL_COLOR)
|
||||||
painter.setBrush(fill)
|
painter.setBrush(fill)
|
||||||
painter.setPen(QtCore.Qt.NoPen)
|
painter.setPen(QtCore.Qt.NoPen)
|
||||||
painter.drawRoundedRect(
|
painter.drawRoundedRect(
|
||||||
start.x,
|
start.x,
|
||||||
start.y,
|
start.y,
|
||||||
Block.side,
|
Block.side,
|
||||||
Block.side * (1 + self.trail),
|
Block.side * (1 + self.trail),
|
||||||
20,
|
20,
|
||||||
20,
|
20,
|
||||||
QtCore.Qt.RelativeSize,
|
QtCore.Qt.RelativeSize,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.glowing:
|
if self.glowing:
|
||||||
fill = QtGui.QRadialGradient(self.center, self.glowing * Block.side)
|
fill = QtGui.QRadialGradient(self.center, self.glowing * Block.side)
|
||||||
fill.setColorAt(0, self.TRANSPARENT)
|
fill.setColorAt(0, self.TRANSPARENT)
|
||||||
fill.setColorAt(0.5 / self.glowing, self.LIGHT_COLOR)
|
fill.setColorAt(0.5 / self.glowing, self.LIGHT_COLOR)
|
||||||
fill.setColorAt(1, self.TRANSPARENT)
|
fill.setColorAt(1, self.TRANSPARENT)
|
||||||
painter.setBrush(QtGui.QBrush(fill))
|
painter.setBrush(QtGui.QBrush(fill))
|
||||||
painter.setPen(QtCore.Qt.NoPen)
|
painter.setPen(QtCore.Qt.NoPen)
|
||||||
painter.drawEllipse(
|
painter.drawEllipse(
|
||||||
self.center.x - self.glowing * Block.side,
|
self.center.x - self.glowing * Block.side,
|
||||||
self.center.y - self.glowing * Block.side,
|
self.center.y - self.glowing * Block.side,
|
||||||
2 * self.glowing * Block.side,
|
2 * self.glowing * Block.side,
|
||||||
2 * self.glowing * Block.side,
|
2 * self.glowing * Block.side,
|
||||||
)
|
)
|
||||||
|
|
||||||
painter.setBrush(self.brush())
|
painter.setBrush(self.brush())
|
||||||
painter.setPen(self.pen())
|
painter.setPen(self.pen())
|
||||||
painter.drawRoundedRect(
|
painter.drawRoundedRect(
|
||||||
p.x + 1,
|
p.x + 1,
|
||||||
p.y + 1,
|
p.y + 1,
|
||||||
Block.side - 2,
|
Block.side - 2,
|
||||||
Block.side - 2,
|
Block.side - 2,
|
||||||
20,
|
20,
|
||||||
20,
|
20,
|
||||||
QtCore.Qt.RelativeSize,
|
QtCore.Qt.RelativeSize,
|
||||||
)
|
)
|
||||||
|
|
||||||
def brush(self):
|
def brush(self):
|
||||||
if self.fill_color is None:
|
if self.fill_color is None:
|
||||||
return QtCore.Qt.NoBrush
|
return QtCore.Qt.NoBrush
|
||||||
|
|
||||||
fill = QtGui.QRadialGradient(self.glint, 1.5 * Block.side)
|
fill = QtGui.QRadialGradient(self.glint, 1.5 * Block.side)
|
||||||
fill.setColorAt(0, self.fill_color.lighter())
|
fill.setColorAt(0, self.fill_color.lighter())
|
||||||
fill.setColorAt(1, self.fill_color)
|
fill.setColorAt(1, self.fill_color)
|
||||||
return QtGui.QBrush(fill)
|
return QtGui.QBrush(fill)
|
||||||
|
|
||||||
def pen(self):
|
def pen(self):
|
||||||
if self.border_color is None:
|
if self.border_color is None:
|
||||||
return QtCore.Qt.NoPen
|
return QtCore.Qt.NoPen
|
||||||
|
|
||||||
border = QtGui.QRadialGradient(self.glint, Block.side)
|
border = QtGui.QRadialGradient(self.glint, Block.side)
|
||||||
border.setColorAt(0, self.border_color.lighter())
|
border.setColorAt(0, self.border_color.lighter())
|
||||||
border.setColorAt(1, self.border_color.darker())
|
border.setColorAt(1, self.border_color.darker())
|
||||||
return QtGui.QPen(QtGui.QBrush(border), 1, join=QtCore.Qt.RoundJoin)
|
return QtGui.QPen(QtGui.QBrush(border), 1, join=QtCore.Qt.RoundJoin)
|
||||||
|
|
||||||
def shine(self, glowing=2, delay=None):
|
def shine(self, glowing=2, delay=None):
|
||||||
self.border_color = Block.GLOWING_BORDER_COLOR
|
self.border_color = Block.GLOWING_BORDER_COLOR
|
||||||
self.fill_color = Block.GLOWING_FILL_COLOR
|
self.fill_color = Block.GLOWING_FILL_COLOR
|
||||||
self.glowing = glowing
|
self.glowing = glowing
|
||||||
if delay:
|
if delay:
|
||||||
QtCore.QTimer.singleShot(delay, self.fade)
|
QtCore.QTimer.singleShot(delay, self.fade)
|
||||||
|
|
||||||
def fade(self):
|
def fade(self):
|
||||||
self.border_color = Block.BORDER_COLOR
|
self.border_color = Block.BORDER_COLOR
|
||||||
self.fill_color = Block.FILL_COLOR
|
self.fill_color = Block.FILL_COLOR
|
||||||
self.glowing = 0
|
self.glowing = 0
|
||||||
self.trail = 0
|
self.trail = 0
|
||||||
|
|
||||||
|
|
||||||
class GhostBlock(Block):
|
class GhostBlock(Block):
|
||||||
"""
|
"""
|
||||||
Mino of the ghost piece
|
Mino of the ghost piece
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BORDER_COLOR = consts.GHOST_BLOCK_BORDER_COLOR
|
BORDER_COLOR = consts.GHOST_BLOCK_BORDER_COLOR
|
||||||
FILL_COLOR = consts.GHOST_BLOCK_FILL_COLOR
|
FILL_COLOR = consts.GHOST_BLOCK_FILL_COLOR
|
||||||
GLOWING_FILL_COLOR = consts.GHOST_BLOCK_GLOWING_FILL_COLOR
|
GLOWING_FILL_COLOR = consts.GHOST_BLOCK_GLOWING_FILL_COLOR
|
||||||
GLOWING = consts.GHOST_BLOCK_GLOWING
|
GLOWING = consts.GHOST_BLOCK_GLOWING
|
||||||
|
|
||||||
|
|
||||||
class MetaTetro(type):
|
class MetaTetro(type):
|
||||||
"""
|
"""
|
||||||
Save the different shapes of Tetrominoes
|
Save the different shapes of Tetrominoes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(cls, name, bases, dico):
|
def __init__(cls, name, bases, dico):
|
||||||
type.__init__(cls, name, bases, dico)
|
type.__init__(cls, name, bases, dico)
|
||||||
Tetromino.classes.append(cls)
|
Tetromino.classes.append(cls)
|
||||||
Tetromino.nb_classes += 1
|
Tetromino.nb_classes += 1
|
||||||
|
|
||||||
|
|
||||||
class Tetromino:
|
class Tetromino:
|
||||||
"""
|
"""
|
||||||
Geometric Tetris® shape formed by four Minos connected along their sides.
|
Geometric Tetris® shape formed by four Minos connected along their sides.
|
||||||
A total of seven possible Tetriminos can be made using four Minos.
|
A total of seven possible Tetriminos can be made using four Minos.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = NotImplemented
|
COORDS = NotImplemented
|
||||||
SUPER_ROTATION_SYSTEM = (
|
SUPER_ROTATION_SYSTEM = (
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((0, 0), (R, 0), (R, U), (0, 2 * D), (R, 2 * D)),
|
COUNTERCLOCKWISE: ((0, 0), (R, 0), (R, U), (0, 2 * D), (R, 2 * D)),
|
||||||
CLOCKWISE: ((0, 0), (L, 0), (L, U), (0, 2 * D), (L, 2 * D)),
|
CLOCKWISE: ((0, 0), (L, 0), (L, U), (0, 2 * D), (L, 2 * D)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((0, 0), (R, 0), (R, D), (0, 2 * U), (R, 2 * U)),
|
COUNTERCLOCKWISE: ((0, 0), (R, 0), (R, D), (0, 2 * U), (R, 2 * U)),
|
||||||
CLOCKWISE: ((0, 0), (R, 0), (R, D), (0, 2 * U), (R, 2 * U)),
|
CLOCKWISE: ((0, 0), (R, 0), (R, D), (0, 2 * U), (R, 2 * U)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((0, 0), (L, 0), (L, U), (0, 2 * D), (L, 2 * D)),
|
COUNTERCLOCKWISE: ((0, 0), (L, 0), (L, U), (0, 2 * D), (L, 2 * D)),
|
||||||
CLOCKWISE: ((0, 0), (R, 0), (R, U), (0, 2 * D), (R, 2 * D)),
|
CLOCKWISE: ((0, 0), (R, 0), (R, U), (0, 2 * D), (R, 2 * D)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((0, 0), (L, 0), (L, D), (0, 2 * U), (L, 2 * U)),
|
COUNTERCLOCKWISE: ((0, 0), (L, 0), (L, D), (0, 2 * U), (L, 2 * U)),
|
||||||
CLOCKWISE: ((0, 0), (L, 0), (L, D), (0, 2 * D), (L, 2 * U)),
|
CLOCKWISE: ((0, 0), (L, 0), (L, D), (0, 2 * D), (L, 2 * U)),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
classes = []
|
classes = []
|
||||||
nb_classes = 0
|
nb_classes = 0
|
||||||
random_bag = []
|
random_bag = []
|
||||||
|
|
||||||
def __new__(cls):
|
def __new__(cls):
|
||||||
"""
|
"""
|
||||||
Return a Tetromino using the 7-bag Random Generator
|
Return a Tetromino using the 7-bag Random Generator
|
||||||
Tetris uses a “bag” system to determine the sequence of Tetriminos
|
Tetris uses a “bag” system to determine the sequence of Tetriminos
|
||||||
that appear during game play.
|
that appear during game play.
|
||||||
This system allows for equal distribution among the seven Tetriminos.
|
This system allows for equal distribution among the seven Tetriminos.
|
||||||
The seven different Tetriminos are placed into a virtual bag,
|
The seven different Tetriminos are placed into a virtual bag,
|
||||||
then shuffled into a random order.
|
then shuffled into a random order.
|
||||||
This order is the sequence that the bag “feeds” the Next Queue.
|
This order is the sequence that the bag “feeds” the Next Queue.
|
||||||
Every time a new Tetrimino is generated and starts its fall within the Matrix,
|
Every time a new Tetrimino is generated and starts its fall within the Matrix,
|
||||||
the Tetrimino at the front of the line in the bag is placed at the end of the Next Queue,
|
the Tetrimino at the front of the line in the bag is placed at the end of the Next Queue,
|
||||||
pushing all Tetriminos in the Next Queue forward by one.
|
pushing all Tetriminos in the Next Queue forward by one.
|
||||||
The bag is refilled and reshuffled once it is empty.
|
The bag is refilled and reshuffled once it is empty.
|
||||||
"""
|
"""
|
||||||
if not cls.random_bag:
|
if not cls.random_bag:
|
||||||
cls.random_bag = random.sample(cls.classes, cls.nb_classes)
|
cls.random_bag = random.sample(cls.classes, cls.nb_classes)
|
||||||
return super().__new__(cls.random_bag.pop())
|
return super().__new__(cls.random_bag.pop())
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.orientation = 0
|
self.orientation = 0
|
||||||
self.t_spin = ""
|
self.t_spin = ""
|
||||||
|
|
||||||
def insert_into(self, matrix, position):
|
def insert_into(self, matrix, position):
|
||||||
self.matrix = matrix
|
self.matrix = matrix
|
||||||
self.minoes = tuple(Block(Point(*coord) + position) for coord in self.COORDS)
|
self.minoes = tuple(Block(Point(*coord) + position) for coord in self.COORDS)
|
||||||
|
|
||||||
def _try_movement(self, next_coords_generator, trail=0, update=True):
|
def _try_movement(self, next_coords_generator, trail=0, update=True):
|
||||||
"""
|
"""
|
||||||
Test if self can fit in the Grid with new coordinates,
|
Test if self can fit in the Grid with new coordinates,
|
||||||
i.e. all cells are empty.
|
i.e. all cells are empty.
|
||||||
If it can, change self's coordinates and return True.
|
If it can, change self's coordinates and return True.
|
||||||
Else, make no changes and return False
|
Else, make no changes and return False
|
||||||
Update the Grid if there is no drop trail
|
Update the Grid if there is no drop trail
|
||||||
"""
|
"""
|
||||||
futures_coords = []
|
futures_coords = []
|
||||||
for p in next_coords_generator:
|
for p in next_coords_generator:
|
||||||
if not self.matrix.is_empty_cell(p):
|
if not self.matrix.is_empty_cell(p):
|
||||||
return False
|
return False
|
||||||
futures_coords.append(p)
|
futures_coords.append(p)
|
||||||
|
|
||||||
for block, future_coord in zip(self.minoes, futures_coords):
|
for block, future_coord in zip(self.minoes, futures_coords):
|
||||||
block.coord = future_coord
|
block.coord = future_coord
|
||||||
block.trail = trail
|
block.trail = trail
|
||||||
if update:
|
if update:
|
||||||
self.matrix.update()
|
self.matrix.update()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def move(self, horizontally, vertically, trail=0, update=True):
|
def move(self, horizontally, vertically, trail=0, update=True):
|
||||||
"""
|
"""
|
||||||
Try to translate self horizontally or vertically
|
Try to translate self horizontally or vertically
|
||||||
The Tetrimino in play falls from just above the Skyline one cell at a time,
|
The Tetrimino in play falls from just above the Skyline one cell at a time,
|
||||||
and moves left and right one cell at a time.
|
and moves left and right one cell at a time.
|
||||||
Each Mino of a Tetrimino “snaps” to the appropriate cell position at the completion of a move,
|
Each Mino of a Tetrimino “snaps” to the appropriate cell position at the completion of a move,
|
||||||
although intermediate Tetrimino movement appears smooth.
|
although intermediate Tetrimino movement appears smooth.
|
||||||
Only right, left, and downward movement are allowed.
|
Only right, left, and downward movement are allowed.
|
||||||
Movement into occupied cells and Matrix walls and floors is not allowed
|
Movement into occupied cells and Matrix walls and floors is not allowed
|
||||||
Update the Grid if there is no drop trail
|
Update the Grid if there is no drop trail
|
||||||
"""
|
"""
|
||||||
return self._try_movement(
|
return self._try_movement(
|
||||||
(block.coord + Point(horizontally, vertically) for block in self.minoes),
|
(block.coord + Point(horizontally, vertically) for block in self.minoes),
|
||||||
trail,
|
trail,
|
||||||
update
|
update
|
||||||
)
|
)
|
||||||
|
|
||||||
def rotate(self, direction=CLOCKWISE):
|
def rotate(self, direction=CLOCKWISE):
|
||||||
"""
|
"""
|
||||||
Try to rotate self through 90° CLOCKWISE or COUNTERCLOCKWISE around its center
|
Try to rotate self through 90° CLOCKWISE or COUNTERCLOCKWISE around its center
|
||||||
Tetriminos can rotate clockwise and counterclockwise using the Super Rotation System.
|
Tetriminos can rotate clockwise and counterclockwise using the Super Rotation System.
|
||||||
This system allows Tetrimino rotation in situations that
|
This system allows Tetrimino rotation in situations that
|
||||||
the original Classic Rotation System did not allow,
|
the original Classic Rotation System did not allow,
|
||||||
such as rotating against walls.
|
such as rotating against walls.
|
||||||
Each time a rotation button is pressed,
|
Each time a rotation button is pressed,
|
||||||
the Tetrimino in play rotates 90 degrees in the clockwise or counterclockwise direction.
|
the Tetrimino in play rotates 90 degrees in the clockwise or counterclockwise direction.
|
||||||
Rotation can be performed while the Tetrimino is Auto-Repeating left or right.
|
Rotation can be performed while the Tetrimino is Auto-Repeating left or right.
|
||||||
There is no Auto-Repeat for rotation itself.
|
There is no Auto-Repeat for rotation itself.
|
||||||
"""
|
"""
|
||||||
rotated_coords = tuple(
|
rotated_coords = tuple(
|
||||||
mino.coord.rotate(self.minoes[0].coord, direction) for mino in self.minoes
|
mino.coord.rotate(self.minoes[0].coord, direction) for mino in self.minoes
|
||||||
)
|
)
|
||||||
|
|
||||||
for movement in self.SUPER_ROTATION_SYSTEM[self.orientation][direction]:
|
for movement in self.SUPER_ROTATION_SYSTEM[self.orientation][direction]:
|
||||||
if self._try_movement(coord + Point(*movement) for coord in rotated_coords):
|
if self._try_movement(coord + Point(*movement) for coord in rotated_coords):
|
||||||
self.orientation = (self.orientation + direction) % 4
|
self.orientation = (self.orientation + direction) % 4
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def soft_drop(self):
|
def soft_drop(self):
|
||||||
"""
|
"""
|
||||||
Causes the Tetrimino to drop at an accelerated rate (s.AUTO_REPEAT_RATE)
|
Causes the Tetrimino to drop at an accelerated rate (s.AUTO_REPEAT_RATE)
|
||||||
from its current location
|
from its current location
|
||||||
"""
|
"""
|
||||||
return self.move(0, D, trail=1)
|
return self.move(0, D, trail=1)
|
||||||
|
|
||||||
def hard_drop(self, show_trail=True, update=True):
|
def hard_drop(self, show_trail=True, update=True):
|
||||||
"""
|
"""
|
||||||
Causes the Tetrimino in play to drop straight down instantly from its
|
Causes the Tetrimino in play to drop straight down instantly from its
|
||||||
current location and Lock Down on the first Surface it lands on.
|
current location and Lock Down on the first Surface it lands on.
|
||||||
It does not allow for further player manipulation of the Tetrimino in play.
|
It does not allow for further player manipulation of the Tetrimino in play.
|
||||||
"""
|
"""
|
||||||
trail = 0
|
trail = 0
|
||||||
while self.move(0, D, trail=trail, update=update):
|
while self.move(0, D, trail=trail, update=update):
|
||||||
if show_trail:
|
if show_trail:
|
||||||
trail += 1
|
trail += 1
|
||||||
return trail
|
return trail
|
||||||
|
|
||||||
|
|
||||||
class TetroI(Tetromino, metaclass=MetaTetro):
|
class TetroI(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Tetromino shaped like a capital I
|
Tetromino shaped like a capital I
|
||||||
four minoes in a straight line
|
four minoes in a straight line
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (L, 0), (2 * L, 0), (0, 0), (R, 0)
|
COORDS = (L, 0), (2 * L, 0), (0, 0), (R, 0)
|
||||||
SUPER_ROTATION_SYSTEM = (
|
SUPER_ROTATION_SYSTEM = (
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((0, D), (L, D), (2 * R, D), (L, U), (2 * R, 2 * D)),
|
COUNTERCLOCKWISE: ((0, D), (L, D), (2 * R, D), (L, U), (2 * R, 2 * D)),
|
||||||
CLOCKWISE: ((R, 0), (L, 0), (2 * R, 0), (L, D), (2 * R, 2 * U)),
|
CLOCKWISE: ((R, 0), (L, 0), (2 * R, 0), (L, D), (2 * R, 2 * U)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((L, 0), (R, 0), (2 * L, 0), (R, U), (2 * L, 2 * D)),
|
COUNTERCLOCKWISE: ((L, 0), (R, 0), (2 * L, 0), (R, U), (2 * L, 2 * D)),
|
||||||
CLOCKWISE: ((0, D), (L, D), (2 * R, D), (L, U), (2 * R, 2 * D)),
|
CLOCKWISE: ((0, D), (L, D), (2 * R, D), (L, U), (2 * R, 2 * D)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((0, U), (R, U), (2 * L, U), (R, D), (2 * L, 2 * U)),
|
COUNTERCLOCKWISE: ((0, U), (R, U), (2 * L, U), (R, D), (2 * L, 2 * U)),
|
||||||
CLOCKWISE: ((L, 0), (R, 0), (2 * L, 0), (R, U), (2 * L, 2 * D)),
|
CLOCKWISE: ((L, 0), (R, 0), (2 * L, 0), (R, U), (2 * L, 2 * D)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
COUNTERCLOCKWISE: ((R, 0), (L, 0), (2 * R, 0), (L, D), (2 * R, 2 * U)),
|
COUNTERCLOCKWISE: ((R, 0), (L, 0), (2 * R, 0), (L, D), (2 * R, 2 * U)),
|
||||||
CLOCKWISE: ((0, U), (R, U), (2 * L, U), (R, D), (2 * L, 2 * U)),
|
CLOCKWISE: ((0, U), (R, U), (2 * L, U), (R, D), (2 * L, 2 * U)),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TetroT(Tetromino, metaclass=MetaTetro):
|
class TetroT(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Tetromino shaped like a capital T
|
Tetromino shaped like a capital T
|
||||||
a row of three minoes with one added above the center
|
a row of three minoes with one added above the center
|
||||||
Can perform a T-Spin
|
Can perform a T-Spin
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (0, 0), (L, 0), (0, U), (R, 0)
|
COORDS = (0, 0), (L, 0), (0, U), (R, 0)
|
||||||
T_SLOT_A = ((L, U), (R, U), (R, D), (L, D))
|
T_SLOT_A = ((L, U), (R, U), (R, D), (L, D))
|
||||||
T_SLOT_B = ((R, U), (R, D), (L, D), (L, U))
|
T_SLOT_B = ((R, U), (R, D), (L, D), (L, U))
|
||||||
T_SLOT_C = ((L, D), (L, U), (R, U), (R, D))
|
T_SLOT_C = ((L, D), (L, U), (R, U), (R, D))
|
||||||
T_SLOT_D = ((R, D), (L, D), (L, U), (R, U))
|
T_SLOT_D = ((R, D), (L, D), (L, U), (R, U))
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def rotate(self, direction=CLOCKWISE):
|
def rotate(self, direction=CLOCKWISE):
|
||||||
"""
|
"""
|
||||||
Detects T-Spins:
|
Detects T-Spins:
|
||||||
this action can be achieved by first landing a T-Tetrimino,
|
this action can be achieved by first landing a T-Tetrimino,
|
||||||
and before it Locks Down, rotating it in a T-Slot
|
and before it Locks Down, rotating it in a T-Slot
|
||||||
(any Block formation such that when the T-Tetrimino is spun into it,
|
(any Block formation such that when the T-Tetrimino is spun into it,
|
||||||
any three of the four cells diagonally adjacent to the center of self
|
any three of the four cells diagonally adjacent to the center of self
|
||||||
are occupied by existing Blocks.)
|
are occupied by existing Blocks.)
|
||||||
"""
|
"""
|
||||||
rotated = super().rotate(direction)
|
rotated = super().rotate(direction)
|
||||||
if rotated:
|
if rotated:
|
||||||
center = self.minoes[0].coord
|
center = self.minoes[0].coord
|
||||||
pa = center + Point(*self.T_SLOT_A[self.orientation])
|
pa = center + Point(*self.T_SLOT_A[self.orientation])
|
||||||
pb = center + Point(*self.T_SLOT_B[self.orientation])
|
pb = center + Point(*self.T_SLOT_B[self.orientation])
|
||||||
pc = center + Point(*self.T_SLOT_C[self.orientation])
|
pc = center + Point(*self.T_SLOT_C[self.orientation])
|
||||||
pd = center + Point(*self.T_SLOT_D[self.orientation])
|
pd = center + Point(*self.T_SLOT_D[self.orientation])
|
||||||
|
|
||||||
a = not self.matrix.is_empty_cell(pa)
|
a = not self.matrix.is_empty_cell(pa)
|
||||||
b = not self.matrix.is_empty_cell(pb)
|
b = not self.matrix.is_empty_cell(pb)
|
||||||
c = not self.matrix.is_empty_cell(pc)
|
c = not self.matrix.is_empty_cell(pc)
|
||||||
d = not self.matrix.is_empty_cell(pd)
|
d = not self.matrix.is_empty_cell(pd)
|
||||||
|
|
||||||
if (a and b) and (c or d):
|
if (a and b) and (c or d):
|
||||||
if c:
|
if c:
|
||||||
pe = (pa + pc) / 2
|
pe = (pa + pc) / 2
|
||||||
elif d:
|
elif d:
|
||||||
pe = (pb + pd) / 2
|
pe = (pb + pd) / 2
|
||||||
if not self.matrix.is_empty_cell(pe):
|
if not self.matrix.is_empty_cell(pe):
|
||||||
self.t_spin = "T-Spin"
|
self.t_spin = "T-Spin"
|
||||||
elif (a or b) and (c and d):
|
elif (a or b) and (c and d):
|
||||||
self.t_spin = "Mini T-Spin"
|
self.t_spin = "Mini T-Spin"
|
||||||
return rotated
|
return rotated
|
||||||
|
|
||||||
|
|
||||||
class TetroZ(Tetromino, metaclass=MetaTetro):
|
class TetroZ(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Tetromino shaped like a capital Z
|
Tetromino shaped like a capital Z
|
||||||
two stacked horizontal dominoes with the top one offset to the left
|
two stacked horizontal dominoes with the top one offset to the left
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (0, 0), (L, U), (0, U), (R, 0)
|
COORDS = (0, 0), (L, U), (0, U), (R, 0)
|
||||||
|
|
||||||
|
|
||||||
class TetroS(Tetromino, metaclass=MetaTetro):
|
class TetroS(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Tetromino shaped like a capital S
|
Tetromino shaped like a capital S
|
||||||
two stacked horizontal dominoes with the top one offset to the right
|
two stacked horizontal dominoes with the top one offset to the right
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (0, 0), (0, U), (L, 0), (R, U)
|
COORDS = (0, 0), (0, U), (L, 0), (R, U)
|
||||||
|
|
||||||
|
|
||||||
class TetroL(Tetromino, metaclass=MetaTetro):
|
class TetroL(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Tetromino shaped like a capital L
|
Tetromino shaped like a capital L
|
||||||
a row of three minoes with one added above the right side
|
a row of three minoes with one added above the right side
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (0, 0), (L, 0), (R, 0), (R, U)
|
COORDS = (0, 0), (L, 0), (R, 0), (R, U)
|
||||||
|
|
||||||
|
|
||||||
class TetroJ(Tetromino, metaclass=MetaTetro):
|
class TetroJ(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Tetromino shaped like a capital J
|
Tetromino shaped like a capital J
|
||||||
a row of three minoes with one added above the left side
|
a row of three minoes with one added above the left side
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (0, 0), (L, U), (L, 0), (R, 0)
|
COORDS = (0, 0), (L, U), (L, 0), (R, 0)
|
||||||
|
|
||||||
|
|
||||||
class TetroO(Tetromino, metaclass=MetaTetro):
|
class TetroO(Tetromino, metaclass=MetaTetro):
|
||||||
"""
|
"""
|
||||||
Square shape
|
Square shape
|
||||||
four minoes in a 2×2 square.
|
four minoes in a 2×2 square.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COORDS = (0, 0), (L, 0), (0, U), (L, U)
|
COORDS = (0, 0), (L, 0), (0, U), (L, U)
|
||||||
|
|
||||||
def rotate(self, direction=1):
|
def rotate(self, direction=1):
|
||||||
""" irrelevant """
|
""" irrelevant """
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class GhostPiece(Tetromino):
|
class GhostPiece(Tetromino):
|
||||||
"""
|
"""
|
||||||
A graphical representation of where the Tetrimino in play will come to rest
|
A graphical representation of where the Tetrimino in play will come to rest
|
||||||
if it is dropped from its current position.
|
if it is dropped from its current position.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, piece):
|
def __new__(cls, piece):
|
||||||
return object.__new__(cls)
|
return object.__new__(cls)
|
||||||
|
|
||||||
def __init__(self, piece):
|
def __init__(self, piece):
|
||||||
self.matrix = piece.matrix
|
self.matrix = piece.matrix
|
||||||
self.minoes = tuple(
|
self.minoes = tuple(
|
||||||
GhostBlock(Point(mino.coord.x, mino.coord.y)) for mino in piece.minoes
|
GhostBlock(Point(mino.coord.x, mino.coord.y)) for mino in piece.minoes
|
||||||
)
|
)
|
||||||
self.hard_drop(show_trail=False, update=False)
|
self.hard_drop(show_trail=False, update=False)
|
Loading…
x
Reference in New Issue
Block a user