Files
minimal_tetris_py/tetris_gui/gpu.py
T
2026-06-10 21:58:50 +02:00

183 lines
5.7 KiB
Python
Executable File

#!/home/honney/Projects/tetris_gui/.venv/bin/python3
import sys, json, select, os
import pygame
WIDTH, HEIGHT = 1280, 720
CELL = 32
BOARD_H, BOARD_W = 20, 10
NEXT_H, NEXT_W = 4, 4
B1 = (304, 40, 320, 640)
B2 = (656, 40, 320, 640)
N1 = (88, 96, 128, 128)
N2 = (1064, 96, 128, 128)
S1 = (84, 454, 136, 32)
S2 = (1060, 454, 136, 32)
SCORE_FONT = [
[ # S
[0,1,1,1,1,0],[1,1,0,0,1,1],[1,1,0,0,0,0],
[0,1,1,1,0,0],[0,0,1,1,1,0],[0,0,0,0,1,1],
[1,1,0,0,1,1],[0,1,1,1,1,0],
],
[ # C
[0,1,1,1,1,0],[1,1,1,0,1,1],[1,1,0,0,0,0],
[1,1,0,0,0,0],[1,1,0,0,0,0],[1,1,0,0,0,0],
[1,1,1,0,1,1],[0,1,1,1,1,0],
],
[ # O
[0,1,1,1,1,0],[1,1,0,0,1,1],[1,1,0,0,1,1],
[1,1,0,0,1,1],[1,1,0,0,1,1],[1,1,0,0,1,1],
[1,1,0,0,1,1],[0,1,1,1,1,0],
],
[ # R
[1,1,1,1,1,0],[1,1,0,0,1,1],[1,1,0,0,1,1],
[1,1,1,1,1,0],[1,1,0,1,1,1],[1,1,0,0,1,1],
[1,1,0,0,1,1],[1,1,0,0,1,1],
],
[ # E
[1,1,1,1,1,1],[1,1,0,0,0,0],[1,1,0,0,0,0],
[1,1,1,1,1,1],[1,1,0,0,0,0],[1,1,0,0,0,0],
[1,1,0,0,0,0],[1,1,1,1,1,1],
],
]
PALETTE = [
(0,0,0),(0,255,255),(0,0,255),(255,128,0),
(255,242,0),(0,255,0),(159,0,255),(255,0,0),
]
PALETTE_ALT = [
(0,0,0),(0,134,243),(61,79,220),(253,171,1),
(171,203,4),(2,189,205),(210,15,99),(254,75,15),
]
def bevel_color(r, g, b, x, y, style):
if style == 0:
if 8 <= x < 24 and 8 <= y < 24:
return (r, g, b)
if 6 <= x < 26 and 6 <= y < 26:
return (r & 0xB0, g & 0xB0, b & 0xB0)
if x + y < 31:
return (r, g, b) if x > y else (r & 0xEF, g & 0xEF, b & 0xEF)
return (r & 0xD7, g & 0xD7, b & 0xD7) if x > y else (r & 0xC0, g & 0xC0, b & 0xC0)
if x == 31 or y == 31:
return (r >> 1, g >> 1, b >> 1) if (x == 0 or y == 0) else (r >> 2, g >> 2, b >> 2)
if x == 0 or y == 0:
return (r, g, b)
return (r & 0xC0, g & 0xC0, b & 0xC0)
def build_blocks(palette, style):
tex = []
for clr in palette:
surf = pygame.Surface((CELL, CELL))
for y in range(CELL):
for x in range(CELL):
surf.set_at((x, y), bevel_color(*clr, x, y, style))
tex.append(surf)
return tex
def build_background():
surf = pygame.Surface((WIDTH, HEIGHT))
for y in range(HEIGHT):
for x in range(WIDTH):
if (x + y) & 1:
surf.set_at((x, y), (0, 0, 255))
else:
v = (x + y) >> 3
surf.set_at((x, y), (v, 250 - v, 0))
return surf
def build_score():
surf = pygame.Surface((136, 32))
surf.fill((0, 0, 0))
x_off = 0
for glyph in SCORE_FONT:
for fy, row in enumerate(glyph):
for fx, px in enumerate(row):
if px:
pygame.draw.rect(surf, (255, 255, 255), (x_off + fx * 4, fy * 4, 4, 4))
x_off += 28
return surf
class Display:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tetris")
self.bg = build_background()
self.score = build_score()
self.b1_tex = build_blocks(PALETTE, 0)
self.b2_tex = build_blocks(PALETTE_ALT, 0)
self.n1_tex = build_blocks(PALETTE, 1)
self.n2_tex = build_blocks(PALETTE_ALT, 1)
self.board1 = [[0] * BOARD_W for _ in range(BOARD_H)]
self.board2 = [[0] * BOARD_W for _ in range(BOARD_H)]
self.next1 = [[0] * NEXT_W for _ in range(NEXT_H)]
self.next2 = [[0] * NEXT_W for _ in range(NEXT_H)]
def draw_grid(self, board, rect, textures):
x, y, w, h = rect
for row in range(h // CELL):
for col in range(w // CELL):
v = board[row][col]
self.screen.blit(textures[v if 0 <= v <= 7 else 0], (x + col * CELL, y + row * CELL))
def render(self):
self.screen.blit(self.bg, (0, 0))
self.draw_grid(self.board1, B1, self.b1_tex)
self.draw_grid(self.board2, B2, self.b2_tex)
self.draw_grid(self.next1, N1, self.n1_tex)
self.draw_grid(self.next2, N2, self.n2_tex)
self.screen.blit(self.score, (S1[0], S1[1]))
self.screen.blit(self.score, (S2[0], S2[1]))
pygame.display.flip()
def close(self):
pygame.quit()
def main():
disp = Display()
buf = ""
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if not sys.stdin.isatty():
r, _, _ = select.select([sys.stdin], [], [], 0)
if r:
chunk = os.read(sys.stdin.fileno(), 65536)
if not chunk:
running = False
else:
buf += chunk.decode("utf-8")
while "\n" in buf:
line, buf = buf.split("\n", 1)
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
if "b1" in data:
disp.board1 = data["b1"]
if "b2" in data:
disp.board2 = data["b2"]
if "n1" in data:
disp.next1 = data["n1"]
if "n2" in data:
disp.next2 = data["n2"]
except json.JSONDecodeError:
pass
disp.render()
clock.tick(60)
disp.close()
sys.exit()
if __name__ == "__main__":
main()