Python Game for Numworks, Epsilon 20+
By Kevin FEDYNA, Ilyas RAHMOUN & Vincent ROBERT. April 2020, december 2024
https://nsi.xyz/tetris (FR)
Un Tetris en flat design, ludique et prenant. A tester rapidement ! 😍
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 FEDYNA, Ilyas RAHMOUN, & 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()