183 lines
5.7 KiB
Python
Executable File
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()
|