Created
October 6, 2024 14:16
-
-
Save villares/321c087b517cffee026ab828aabc35f0 to your computer and use it in GitHub Desktop.
Porting my tetris from py5 to pyp5js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This is quick adaptation from my py5 imported mode sketch at: | |
https://abav.lugaralgum.com/sketch-a-day/#sketch_2024_07_09 | |
Use arrows to play - up to rotate, space bar to restart. | |
What changed: py5pjs didn't have random_choice, so I had to import it, and | |
in pyp5js the arrow key constants are different ARROW_LEFT and not LEFT, etc. | |
""" | |
from random import choice as random_choice | |
well = {} # a dictionary for the walls and already fallen pieces | |
falling_piece = [] # will contain ((x,y), color) tuples, the component blocks of a piece | |
pieces = ( | |
[((x, y), color(0, 200, 0)) for x, y in ((6, 0), (7, 0), (6, 1), (7, 1))], # O | |
[((x, y), color(0, 0, 200)) for x, y in ((4, 0), (5, 0), (6, 0), (6, 1))], # J | |
[((x, y), color(200, 200, 0)) for x, y in ((4, 1), (5, 1), (6, 1), (6, 0))], # L | |
[((x, y), color(200, 0, 0)) for x, y in ((4, 0), (5, 0), (6, 0), (7, 0))], # I | |
[((x, y), color(0, 200, 200)) for x, y in ((5, 0), (5, 1), (6, 1), (6, 2))], # S | |
[((x, y), color(200, 0, 200)) for x, y in ((6, 0), (6, 1), (5, 1), (5, 2))], # N | |
[((x, y), color(200)) for x, y in ((4, 0), (5, 0), (6, 0), (5, 1))], # T | |
) | |
W, H, s = 11, 20, 25 # Well Width, Well Height, single block size | |
frame_sample = 12 # a smaller number makes it faster, a bigger number makes it slower | |
def setup(): | |
size(525, 525) | |
text_align(CENTER, CENTER) | |
text_size(80) | |
start() | |
def start(): | |
global game_over, score | |
game_over, score = False, 0 | |
well.clear() | |
for y in range(H): # Set vertical well walls | |
well[0, y] = color(128) | |
well[W, y] = color(128) | |
for x in range(W + 1): # Set bottom of well | |
well[x, H] = color(128) | |
new_falling_piece() | |
loop() # reactivates draw if it is paused | |
def draw(): | |
global score | |
background(0) | |
for (x, y), block_color in list(well.items()) + falling_piece: | |
fill(block_color) | |
square(x * s, y * s, s) | |
fill(200) | |
text(score, W * s + (width - W * s) / 2, s * 2) | |
if game_over: | |
fill(255) | |
text('GAME OVER', | |
width / 2, height / 2) | |
no_loop() # pause draw | |
elif frame_count % frame_sample == 0: | |
if check_move(falling_piece, 0, 1): | |
move_falling_piece(0, 1) | |
else: | |
add_to_well() | |
new_falling_piece() | |
r = check_filled_row() | |
if r != -1: | |
collapse_on_row(r) | |
score += 1 | |
def new_falling_piece(): | |
global game_over | |
falling_piece[:] = random_choice(pieces) | |
if not check_move(falling_piece): | |
game_over = True | |
def add_to_well(): | |
for (x, y), b in falling_piece: | |
well[x, y] = b | |
def check_move(p, h=0, v=0): | |
for (x, y), _ in p: | |
if well.get((x + h, y + v)): | |
return False | |
return True | |
def move_falling_piece(h, v): | |
falling_piece[:] = (((x + h, y + v), b) for (x, y), b in falling_piece) | |
def check_filled_row(): | |
for r in range(H): | |
filled_blocks = 0 | |
for c in range(W): | |
if well.get((c, r)): | |
filled_blocks += 1 | |
if filled_blocks == W: | |
return r # return first filled row found | |
return -1 # no filled row | |
def clear_row(r): | |
for c in range(1, W): | |
if (c, r) in well: | |
del well[c, r] | |
def collapse_on_row(row): | |
# clear passed row and move blocks down to it | |
for r in range(row, -1, -1): # moving upwards, starting from passed row | |
clear_row(r) | |
for c in range(1, W): | |
if b := well.get((c, r - 1)): # get block from 1 row up | |
well[c, r] = b | |
def rounded_falling_piece_centroid(): | |
positions = ((x, y) for (x, y), _ in falling_piece) | |
coords = tuple(zip(*positions)) | |
max_x, max_y = map(max, coords) | |
min_x, min_y = map(min, coords) | |
return (max_x + min_x) // 2, (max_y + min_y) // 2 | |
def rotated_falling_piece(): | |
cx, cy = rounded_falling_piece_centroid() # causes y displacement of -1 offset later... | |
# translated to origin falling piece copy | |
ttofpc = (((x - cx, y - cy), b) for (x, y), b in falling_piece) | |
return tuple(((y + cx, -x + cy + 1), b) for (x, y), b in ttofpc) # note y + 1 offset | |
def key_pressed(): | |
if key == ' ': | |
start() | |
elif key_code == LEFT_ARROW and check_move(falling_piece, -1, 0): | |
move_falling_piece(-1, 0) | |
elif key_code == RIGHT_ARROW and check_move(falling_piece, 1, 0): | |
move_falling_piece(1, 0); | |
elif key_code == DOWN_ARROW and check_move(falling_piece, 0, 1): | |
move_falling_piece(0, 1); | |
elif key_code == UP_ARROW and check_move(rp := rotated_falling_piece()): | |
falling_piece[:] = rp | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Versão minified: https://abav.lugaralgum.com/pyp5js/py5mode/?sketch=TiUzREZhbHNlJTBBTSUzRHR1cGxlJTBBRCUzRHJhbmdlJTBBZnJvbSUyMHJhbmRvbSUyMGltcG9ydCUyMGNob2ljZSUyMGFzJTIwTyUwQUIlM0QlN0IlN0QlMEFBJTNEJTVCJTVEJTBBUCUzRCU1QigoQSUyQ0IpJTJDY29sb3IoMCUyQzIwMCUyQzApKWZvcihBJTJDQilpbigoNiUyQzApJTJDKDclMkMwKSUyQyg2JTJDMSklMkMoNyUyQzEpKSU1RCUyQyU1QigoQSUyQ0IpJTJDY29sb3IoMCUyQzAlMkMyMDApKWZvcihBJTJDQilpbigoNCUyQzApJTJDKDUlMkMwKSUyQyg2JTJDMCklMkMoNiUyQzEpKSU1RCUyQyU1QigoQSUyQ0IpJTJDY29sb3IoMjAwJTJDMjAwJTJDMCkpZm9yKEElMkNCKWluKCg0JTJDMSklMkMoNSUyQzEpJTJDKDYlMkMxKSUyQyg2JTJDMCkpJTVEJTJDJTVCKChBJTJDQiklMkNjb2xvcigyMDAlMkMwJTJDMCkpZm9yKEElMkNCKWluKCg0JTJDMCklMkMoNSUyQzApJTJDKDYlMkMwKSUyQyg3JTJDMCkpJTVEJTJDJTVCKChBJTJDQiklMkNjb2xvcigwJTJDMjAwJTJDMjAwKSlmb3IoQSUyQ0IpaW4oKDUlMkMwKSUyQyg1JTJDMSklMkMoNiUyQzEpJTJDKDYlMkMyKSklNUQlMkMlNUIoKEElMkNCKSUyQ2NvbG9yKDIwMCUyQzAlMkMyMDApKWZvcihBJTJDQilpbigoNiUyQzApJTJDKDYlMkMxKSUyQyg1JTJDMSklMkMoNSUyQzIpKSU1RCUyQyU1QigoQSUyQ0IpJTJDY29sb3IoMjAwKSlmb3IoQSUyQ0IpaW4oKDQlMkMwKSUyQyg1JTJDMCklMkMoNiUyQzApJTJDKDUlMkMxKSklNUQlMEFDJTJDSiUyQ0UlM0QxMSUyQzIwJTJDMjUlMEFRJTNEMTIlMEFkZWYlMjBzZXR1cCgpJTNBc2l6ZSg1MjUlMkM1MjUpJTNCdGV4dF9hbGlnbihDRU5URVIlMkNDRU5URVIpJTNCdGV4dF9zaXplKDgwKSUzQksoKSUwQWRlZiUyMEsoKSUzQSUwQSUwOWdsb2JhbCUyMEclMkNIJTNCRyUyQ0glM0ROJTJDMCUzQkIuY2xlYXIoKSUwQSUwOWZvciUyMEElMjBpbiUyMEQoSiklM0FCJTVCMCUyQ0ElNUQlM0Rjb2xvcigxMjgpJTNCQiU1QkMlMkNBJTVEJTNEY29sb3IoMTI4KSUwQSUwOWZvciUyMEUlMjBpbiUyMEQoQyUyQjEpJTNBQiU1QkUlMkNKJTVEJTNEY29sb3IoMTI4KSUwQSUwOUwoKSUzQmxvb3AoKSUwQWRlZiUyMGRyYXcoKSUzQSUwQSUwOWdsb2JhbCUyMEglM0JiYWNrZ3JvdW5kKDApJTBBJTA5Zm9yKChKJTJDSyklMkNNKWluJTIwbGlzdChCLml0ZW1zKCkpJTJCQSUzQWZpbGwoTSklM0JzcXVhcmUoSipFJTJDSypFJTJDRSklMEElMDlmaWxsKDIwMCklM0J0ZXh0KEglMkNDKkUlMkIod2lkdGgtQypFKSUyRjIlMkNFKjIpJTBBJTA5aWYlMjBHJTNBZmlsbCgyNTUpJTNCdGV4dCgnR0FNRSUyME9WRVInJTJDd2lkdGglMkYyJTJDaGVpZ2h0JTJGMiklM0Jub19sb29wKCklMEElMDllbGlmJTIwZnJhbWVfY291bnQlMjVRJTNEJTNEMCUzQSUwQSUwOSUwOWlmJTIwRihBJTJDMCUyQzEpJTNBSSgwJTJDMSklMEElMDklMDllbHNlJTNBUigpJTNCTCgpJTBBJTA5JTA5RCUzRFMoKSUwQSUwOSUwOWlmJTIwRCElM0QtMSUzQVUoRCklM0JIJTJCJTNEMSUwQWRlZiUyMEwoKSUzQSUwQSUwOWdsb2JhbCUyMEclM0JBJTVCJTNBJTVEJTNETyhQKSUwQSUwOWlmJTIwbm90JTIwRihBKSUzQUclM0RUcnVlJTBBZGVmJTIwUigpJTNBJTBBJTA5Zm9yKChDJTJDRCklMkNFKWluJTIwQSUzQUIlNUJDJTJDRCU1RCUzREUlMEFkZWYlMjBGKHAlMkNoJTNEMCUyQ3YlM0QwKSUzQSUwQSUwOWZvcigoQSUyQ0MpJTJDRClpbiUyMHAlM0ElMEElMDklMDlpZiUyMEIuZ2V0KChBJTJCaCUyQ0MlMkJ2KSklM0FyZXR1cm4lMjBOJTBBJTA5cmV0dXJuJTIwVHJ1ZSUwQWRlZiUyMEkoaCUyQ3YpJTNBQSU1QiUzQSU1RCUzRCgoKEElMkJoJTJDQiUyQnYpJTJDQylmb3IoKEElMkNCKSUyQ0MpaW4lMjBBKSUwQWRlZiUyMFMoKSUzQSUwQSUwOWZvciUyMEElMjBpbiUyMEQoSiklM0ElMEElMDklMDlFJTNEMCUwQSUwOSUwOWZvciUyMEYlMjBpbiUyMEQoQyklM0ElMEElMDklMDklMDlpZiUyMEIuZ2V0KChGJTJDQSkpJTNBRSUyQiUzRDElMEElMDklMDlpZiUyMEUlM0QlM0RDJTNBcmV0dXJuJTIwQSUwQSUwOXJldHVybi0xJTBBZGVmJTIwVChyKSUzQSUwQSUwOWZvciUyMEElMjBpbiUyMEQoMSUyQ0MpJTNBJTBBJTA5JTA5aWYoQSUyQ3IpaW4lMjBCJTNBZGVsJTIwQiU1QkElMkNyJTVEJTBBZGVmJTIwVShyb3cpJTNBJTBBJTA5Zm9yJTIwQSUyMGluJTIwRChyb3clMkMtMSUyQy0xKSUzQSUwQSUwOSUwOVQoQSklMEElMDklMDlmb3IlMjBFJTIwaW4lMjBEKDElMkNDKSUzQSUwQSUwOSUwOSUwOWlmKEYlM0ElM0RCLmdldCgoRSUyQ0EtMSkpKSUzQUIlNUJFJTJDQSU1RCUzREYlMEFkZWYlMjBWKCklM0FDJTNEKChBJTJDQilmb3IoKEElMkNCKSUyQ0MpaW4lMjBBKSUzQkIlM0RNKHppcCgqQykpJTNCRCUyQ0UlM0RtYXAobWF4JTJDQiklM0JGJTJDRyUzRG1hcChtaW4lMkNCKSUzQnJldHVybihEJTJCRiklMkYlMkYyJTJDKEUlMkJHKSUyRiUyRjIlMEFkZWYlMjBXKCklM0FCJTJDQyUzRFYoKSUzQkQlM0QoKChBLUIlMkNELUMpJTJDRSlmb3IoKEElMkNEKSUyQ0UpaW4lMjBBKSUzQnJldHVybiUyME0oKChEJTJCQiUyQy1BJTJCQyUyQjEpJTJDRSlmb3IoKEElMkNEKSUyQ0UpaW4lMjBEKSUwQWRlZiUyMGtleV9wcmVzc2VkKCklM0ElMEElMDlpZiUyMGtleSUzRCUzRCclMjAnJTNBSygpJTBBJTA5ZWxpZiUyMGtleV9jb2RlJTNEJTNETEVGVF9BUlJPVyUyMGFuZCUyMEYoQSUyQy0xJTJDMCklM0FJKC0xJTJDMCklMEElMDllbGlmJTIwa2V5X2NvZGUlM0QlM0RSSUdIVF9BUlJPVyUyMGFuZCUyMEYoQSUyQzElMkMwKSUzQUkoMSUyQzApJTBBJTA5ZWxpZiUyMGtleV9jb2RlJTNEJTNERE9XTl9BUlJPVyUyMGFuZCUyMEYoQSUyQzAlMkMxKSUzQUkoMCUyQzEpJTBBJTA5ZWxpZiUyMGtleV9jb2RlJTNEJTNEVVBfQVJST1clMjBhbmQlMjBGKChCJTNBJTNEVygpKSklM0FBJTVCJTNBJTVEJTNEQg%3D%3D