tetris.py

Created by ilyas-r

Created on December 26, 2024

11.1 KB

Tetris v2.0.
Python Game for Numworks, all models.
By Kevin F., Ilyas R. & Vincent ROBERT. April 2020.

Learn more about Tetris on: nsi.xyz/tetris (FR)

Changelog

Tetris v1.0 - 28/04/2020:
- Initial game

Tetris v2.0 - 25/12/2024:
- Fixed the game on Epsilon 20+
- The interface has been updated
- The [var] key is now used to pause and resume the game


from kandinsky import draw_string as txt, fill_rect as rec, get_pixel
from ion import keydown
from random import randint
from math import sqrt,log
from time import monotonic, sleep

# Tetris 2.0 NumWorks, 25.12.2024
# Par Kevin F., Ilyas R., & Vincent ROBERT
# https://nsi.xyz/tetris <3

dark_c=(42,)*3
light_c=(142,)*3
bright_c=(242,)*3
game_c=(148,113,222)
void_c=(255,)*3

color = ((128,192,224),(224,128,192),(192,224,128),(192,192,192),(224,192,128),(192,128,224),(128,224,192))
formes = ([(1,1,2,1)],[(1,2,1),(0,0,1)],[(0,2,1),(1,1,0)],[(2,2),(2,2)],[(1,2,1),(0,1,0)],[(1,2,1),(1,0,0)],[(1,2,0),(0,1,1)])
os = (148,113,222)

scoreboard=[["Level",1],["Lines",0],["Score",0], [None]]

game_config=(["Level",1],["Vision",3],["Grid", 0])
config_limits=((1,9),(1,4),(0,1))
state="IN_MENU"
ks=0


def reset():
    global scoreboard
    rec(0,0,320,222,void_c)
    scoreboard=[["Level",game_config[0][1]],["Lines",0],["Score",0], [None]]


def gui(e=0):
    rec(74,0,2,222,light_c)
    rec(246,0,2,222,light_c)
    rec(0,200,320,22,game_c)
    txt("Developed by nsi.xyz/tetris",25,202,bright_c,game_c)
    for i in range(len(game_config)):
        txt(game_config[i][0],37 -5*len(game_config[i][0]),200//(len(game_config)+1)*(i + 1)-18,light_c)
        rec((74-18)//2,200//(len(game_config)+1)*(i+1),18,18,light_c)
        txt(str(game_config[i][1]),(74-18)//2+4,200//(len(game_config)+1)*(i+1),bright_c,light_c)
    config_displayer(0,1)
    arrows_displayer(0,1*(e!=0))
    txt("TETRIS",254,155,light_c)
    if game_config[2][1]:
        grid(1)
    for i in range(7):
        rec(250+10*i,178,8,8,color[i])
    if e:
        rec(0, 0, 74, 200, void_c)


def grid(e):
    for i in range(13):
        rec(76+i*14,0,2,200,bright_c*(e==1)+void_c*(e==0))

def config_displayer(conf,stt):
    c=game_c if stt else light_c
    txt(game_config[conf][0],37-5*len(game_config[conf][0]),200//(len(game_config)+1)*(conf+1)-18,c)
    rec((74-18)//2,200//(len(game_config)+1)*(conf+1),18,18,c)
    txt(str(game_config[conf][1]),(74-18)//2+4,200//(len(game_config)+1)*(conf+1),bright_c,c)


def config_updater(conf,incr,f=0):
    global game_config
    c=light_c if f else game_c
    game_config[conf][1]+=incr
    txt(str(game_config[conf][1]),(74-18)//2+4,200//(len(game_config)+1)*(conf+1),bright_c,c)
    arrows_displayer(conf)
    if conf==2:
        grid(game_config[2][1])
    elif conf==0:
        scoreboard[0][1] = game_config[0][1]
        scoreboard_displayer()


def arrows_displayer(conf,leave=0):
    if leave:
        for i in range(len(game_config)):
            for j in range(2):
                rec((74-18)//2+(25 if j else -17),200//(len(game_config)+1)*(i+1)+3,10,10,void_c)
    else:
        if game_config[conf][1]>config_limits[conf][0]:
            txt("<",(74-18)//2-17,200//(len(game_config)+1)*(conf+1),game_c)
        else:
            txt("<",(74-18)//2-17,200//(len(game_config)+1)*(conf+1),void_c)
        if game_config[conf][1]<config_limits[conf][1]:
            txt(">",(74-18)//2+25,200//(len(game_config)+1)*(conf+1),game_c)
        else:
            txt(">",(74-18)//2+25,200//(len(game_config)+1)*(conf+1),void_c)


def arrow(x,y,d=0,c=game_c):
    for i in range(6):
        rec(x+(23+i)*(d==3)-(5+i)*(d==0)+(3+i)*(d%3!=0),y+(3+i)*(d%3==0)-(7+i)*(d==1)+(22+i)*(d==2),1,2,c)
        rec(x+(23+i)*(d==3)-(5+i)*(d==0)+(13-i)*(d%3!=0),y+(13-i)*(d%3==0)-(7+i)*(d==1)+(22+i)*(d==2),1,2,c)


def config_manager(conf,i):
    config_displayer(conf,0)
    arrows_displayer(conf,1)
    conf+=i
    config_displayer(conf,1)
    arrows_displayer(conf)


def menu():
    global game,ks
    config=0
    last_key=None
    while not (keydown(4) or keydown(52)) or not ks:
        if keydown(1) and config>0 and last_key!=1:
            config_manager(config,-1)
            config-=1
            last_key=1
        if keydown(2) and config<len(game_config)-1 and last_key!=2:
            config_manager(config,1)
            config+=1
            last_key=2
        if keydown(0) and game_config[config][1]>config_limits[config][0] and last_key!=0:
            config_updater(config,-1)
            last_key = 0
        if keydown(3) and game_config[config][1]<config_limits[config][1] and last_key!=3:
            config_updater(config,1)
            last_key=3
        if not (keydown(0) or keydown(1) or keydown(2) or keydown(3) or keydown(4) or keydown(52)):
            last_key,ks = None,1
    gui(1)


def scoreboard_displayer():
    for i in range(len(scoreboard)-1):
        txt(scoreboard[i][0],284-5*len(scoreboard[i][0]),200//(len(scoreboard)+1)*(i+1)-18,dark_c)
        rec(250,200//(len(scoreboard)+1)*(i+1),60,18,void_c)
        txt(str(scoreboard[i][1]),284-5*len(str(scoreboard[i][1])),200//(len(scoreboard)+1)*(i+1),light_c)

def score(li=0, i=0):
    scoreboard[1][1] += li
    scoreboard[2][1] += scoreboard[0][1]*(25*li+25*2**max(li-1,0))*(li!=0)+scoreboard[0][1]*i
    scoreboard[0][1] = max(round(sqrt(scoreboard[2][1] + (10 * game_config[0][1]) ** 2 ) / 10), game_config[0][1])
    scoreboard_displayer()

def rlen(l):
    return range(len(l))

def ancr(piece):
    for i in rlen(piece[1]):
        for j in rlen(piece[1][i]):
            if piece[1][i][j] == 2:
                return piece[0][0]-14*j, piece[0][1]-14*i

def draw_tetro(piece,clr=-1):
    if clr == -1:
        clr = piece[2]
    x,y = ancr(piece)
    for i in rlen(piece[1]):
        for j in rlen(piece[1][i]):
            if piece[1][i][j]:
                rec(x+14*j+1,y+14*i+1,12,12,clr)

def tourner(piece,s,t=0):
    if not t:
        draw_tetro(piece,(255,255,255))
    if s == "h":
        piece[1] = list(zip(*piece[1][::-1]))
    if s == "a":
        piece[1] = list(zip(*(list(i)[::-1] for i in piece[1])))
    if not t:
        draw_tetro(piece)

def move(piece,x=0,y=0):
    draw_tetro(piece, (248, 252, 248))
    piece[0][0] += x*14
    piece[0][1] += y*14
    draw_tetro(piece)

def test_rot(piece,s):
    x,y = ancr(piece)
    blocs = []
    for i in rlen(piece[1]):
        for j in rlen(piece[1][i]):
            if piece[1][i][j]:
                blocs += [[x+14*j,y+14*i]]
    tourner(piece,s,1)
    x,y = ancr(piece)
    for i in rlen(piece[1]):
        for j in rlen(piece[1][i]):
            if not [j*14+x,i*14+y] in blocs:
                if not(77<=x+14*j<=231) or not(3<=y+14*i<=207) or get_pixel(x+7+14*j,y+7+14*i) != (255,255,255):
                    tourner(piece,"a"*(s=="h")+"h"*(s=="a"),1)
                    return 1
    tourner(piece,"a"*(s=="h")+"h"*(s=="a"),1)
    return 0


def collision(d,piece):
    x,y = ancr(piece)
    for i in rlen(piece[1]):
        for j in rlen(piece[1][i]):
            if piece[1][i][j]:
                if d in (0,3) and ((0<=j+(d==3)-(d==0)<=len(piece[1][i])-1 and not piece[1][i][j+(d==3)-(d==0)]) or (j,d) in ((0,0),(len(piece[1][i])-1,3))):
                    if get_pixel(x+7+14*(j+(d==3)-(d==0)),y+7+14*i) != (255,255,255) or x+((j+1)*14)*(d!=0) in [77,245]:
                        return 1
                if d == 2 and ((i != len(piece[1])-1 and not piece[1][i+1][j]) or (i == len(piece[1])-1 and piece[1][i][j])):
                    if get_pixel(x+7+14*j,y+7+14*(i+1)) != (255,255,255) or y+i*14 == 207:
                        return 1
    return 0


def engine():
    global state
    x_n,y_n=17,200//(game_config[1][1]+1)-32
    if game_config[1][1]:
        tetrominos = []
        for i in range(game_config[1][1]):
            chx = randint(0,6)
            tetrominos += [[[37-14*(chx == 3)-6*(chx in (1,2,4,5,6)), 200//(len(tetrominos)+1)*(i)], formes[chx], color[chx]]]
    while get_pixel(154,10) == (255,255,255):
        chx = randint(0,6)
        if game_config[1][1]:
            for tet in tetrominos:
                draw_tetro(tet,(255,255,255))
            tetromino = [[147, 3],tetrominos[0][1],tetrominos[0][2]]
            tetrominos = [tetrominos[i+1] for i in range(game_config[1][1]-1)] + [[[0, 0], formes[chx], color[chx]]]
            for i in range(game_config[1][1]):
                tetrominos[i][0] = [37-14*(tetrominos[i][1] == formes[3])-6*(tetrominos[i][1] in (formes[1],formes[2],formes[4],formes[5],formes[6])), 200//(len(tetrominos)+1)*(i+1)]
            for tet in tetrominos:
                draw_tetro(tet)
        else:
            tetromino = [[147, 3], formes[chx], color[chx]]
        draw_tetro(tetromino)
        chute = 0.120
        while 1:
            txt("Next", x_n, y_n)
            depart = monotonic()
            while monotonic() < depart+round(-0.1945871*log(scoreboard[0][1])+1.01122,3):
                if keydown(0) and not collision(0, tetromino):
                    move(tetromino, x=-1)
                    sleep(0.120)
                if keydown(3) and not collision(3,tetromino):
                    move(tetromino,x=1)
                    sleep(0.120)
                if keydown(2):
                    sleep(chute)
                    chute /= 2
                    score(i=1)
                    break
                chute = 0.120
                if keydown(16) and not test_rot(tetromino,"h"):
                    sleep(0.160)
                    tourner(tetromino,"h")
                if (keydown(17) or keydown(1)) and not test_rot(tetromino,"a"):
                    sleep(0.160)
                    tourner(tetromino,"a")
                if (keydown(15) or keydown(52)) and state != "IN_PAUSE":
                    state = "IN_PAUSE"
                    rec(x_n-10,y_n-6,60,30,game_c)
                    txt("PAUSE",x_n-5,y_n,bright_c,game_c)
                    sleep(0.160)
                if state == "IN_PAUSE":
                    while not (keydown(15) or keydown(52)):
                        pass
                    state = "IN_GAME"
                    rec(x_n-10,y_n-6,60,30,void_c)
                    txt("Next", x_n, y_n)
                    sleep(0.160)
            if collision(2,tetromino):
                break
            score(i=1)
            move(tetromino,y=1)
        lignes = []
        for i in range(192,4,-14):
            verif = 0
            for j in range(84,252,14):
                verif += (get_pixel(j,i) != (255,255,255)) + 2*(get_pixel(j,i) == (255,255,255))
            if verif == 12:
                lignes += [i-7]
            if verif == 24:
                stop = i-7
                break
        if lignes:
            score(li=len(lignes))
            for c in range(7):
                for i in lignes:
                    for j in range(77,245,14):
                        rec(j+1,i+1,12,12,not c%2 and (255,255,255) or os)
                sleep(0.2*round(-0.1945871*log(scoreboard[0][1])+1.01122,3))
            lignes = [lignes[i]+i*14 for i in rlen(lignes)]
            for i in lignes:
                for y in range(i,stop-14,-14):
                    for x in range(77,245,14):
                        rec(x+1,y+1,12,12,get_pixel(x+7,y-7))
    rec(130,94,60,34,game_c)
    txt("LOST",140,102,bright_c,game_c)
    state = "END"

def start():
    global state
    gui()
    scoreboard_displayer()
    menu()
    state = "IN_GAME"
    sleep(0.160)
    engine()


def tetris():
    global ks
    while not keydown(51):
        if state == "IN_MENU":
            start()
        if state == "END" and (keydown(4) or keydown(52)) and not ks:
            reset()
            start()
        if not (keydown(4) or keydown(52)):
            ks = 0

tetris()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.