"""
CyclopeSnake v0.5
by Fime
https://workshop.numworks.com/python/fime/cyclope_snake
"""fromkandinskyimport*fromrandomimportrandintfromionimport*fromtimeimport*LOGO=["011101001001100101101111","110001101010010110001100","001101011011110101101000","111001001010010100101111"]INSTRUCTIONS="""Eat the maximum food you can,but
dont touch the edges or an other
part of the snake !
→ arrows : move
→ if you wait a too long time,
the snake gonna be crazy and
will go in the opposite
direction !
"""#screen config
SCREEN_W=320SCREEN_H=180#game vars
START_SPEED=0.2SIZE=14HALF_SIZE=SIZE//2DIRECTION={"L":[-1,0],"U":[0,-1],"R":[1,0],"D":[0,1]}ANGRY_TIME=5#colors
BG_COLOR=(255,255,255)SDW_COLOR=(150,150,150)EDGE_COLOR=(50,50,50)COLORS=[[205,150,0],[100,175,0],[0,205,100],[0,150,205],[150,0,205],[205,0,50]]#grid config
GRID_W=SCREEN_W//SIZEGRID_H=SCREEN_H//SIZEOFFSET_X=SCREEN_W%SIZEOFFSET_Y=SCREEN_H%SIZELIMIT_X=[OFFSET_X,SCREEN_W-OFFSET_X]LIMIT_Y=[OFFSET_Y,SCREEN_H-OFFSET_Y]START_PO=[GRID_W//2*SIZE+HALF_SIZE+OFFSET_X//2,GRID_H//2*SIZE+HALF_SIZE+OFFSET_Y//2]defgame():"""The game fonction.
snake parts: list of the snake parts ([x],[y],[part color])
snake length: actual limit size of the snake
game score: score
best score: best score. saved on snake.sav
snake position: head's position
snake direction: head's direction
food info: food infos ([x],[y],[color])
food timer: for the limit of the angry
timer: game timer
fps: frame par seconds
"""globals_part,s_len,score,best,po,vec,f_info,f_timer,timer,fps#draw the (n) element of snake
defdrawElement(n):#get element info
inf=list(s_part[n])inf.append((inf[2][0]+50,inf[2][1]+50,inf[2][2]+50))#fill the main square and the detail
fill_rect(inf[0]-HALF_SIZE,inf[1]-HALF_SIZE,SIZE,SIZE,inf[3])fill_rect(inf[0]-HALF_SIZE//2,inf[1]-HALF_SIZE//2,HALF_SIZE//2*2,HALF_SIZE//2*2,inf[2])drawShadow(inf)defdrawEye():inf=list(s_part[-1])fill_rect(inf[0]-HALF_SIZE//2,inf[1]-HALF_SIZE//2,HALF_SIZE//2*2,HALF_SIZE//2*2,BG_COLOR)fill_rect(inf[0]-HALF_SIZE//3+vec[0],inf[1]-HALF_SIZE//3+vec[1],HALF_SIZE//3*2,HALF_SIZE//3*2,EDGE_COLOR)defdrawShadow(inf):#draw shadow
ifget_pixel(inf[0],inf[1]+HALF_SIZE)==(248,252,248):#if nothing below, draw shadow
fill_rect(inf[0]-HALF_SIZE,inf[1]+HALF_SIZE,SIZE,SIZE//2,SDW_COLOR)defhideElement(n):inf=list(s_part[n])#get part info
fill_rect(inf[0]-HALF_SIZE,inf[1]-HALF_SIZE,SIZE,SIZE,BG_COLOR)#hide part
hideShadow(inf)defhideShadow(inf):ifget_pixel(inf[0]-HALF_SIZE,inf[1]+HALF_SIZE)==(144,148,144):#if shadow below
fill_rect(inf[0]-HALF_SIZE,inf[1]+HALF_SIZE,SIZE,SIZE//2,BG_COLOR)if (get_pixel(inf[0],inf[1]-HALF_SIZE-1)!=(248,252,248))andnot(inf[1]-HALF_SIZE-1<OFFSET_Y):#if part above
fill_rect(inf[0]-HALF_SIZE,inf[1]-HALF_SIZE,SIZE,HALF_SIZE,SDW_COLOR)defdrawFood():#get element info
inf=list(f_info)inf.append([inf[2][0]+50,inf[2][1]+50,inf[2][2]+50])#fill the main square and the detail
fill_rect(inf[0]-HALF_SIZE,inf[1]-HALF_SIZE,SIZE,SIZE,inf[3])fill_rect(inf[0]-HALF_SIZE,inf[1]-HALF_SIZE,HALF_SIZE//2,SIZE,inf[2])fill_rect(inf[0],inf[1]-HALF_SIZE,HALF_SIZE//2,SIZE,inf[2])fill_rect(inf[0]-HALF_SIZE//2-1,inf[1]-HALF_SIZE,HALF_SIZE+1,HALF_SIZE//2+1,EDGE_COLOR)fill_rect(inf[0]-HALF_SIZE//2,inf[1]-HALF_SIZE,HALF_SIZE//2,HALF_SIZE//2,(0,200,100))fill_rect(inf[0],inf[1]-HALF_SIZE,HALF_SIZE//2,HALF_SIZE//2,(0,150,75))drawShadow(inf)defhideFood():inf=list(f_info)#get part info
fill_rect(inf[0]-HALF_SIZE,inf[1]-HALF_SIZE,SIZE,SIZE,BG_COLOR)#hide part
hideShadow(inf)defrandPo():x=OFFSET_X//2+HALF_SIZE+randint(1,GRID_W-2)*SIZEy=OFFSET_Y//2+HALF_SIZE+randint(1,GRID_H-2)*SIZEreturnx,ydefdrawScore():fill_rect(0,SCREEN_H,320,20,EDGE_COLOR)draw_string("Time: {}s".format(int(monotonic()-timer)),0,SCREEN_H,BG_COLOR,EDGE_COLOR)draw_string("Score: {} ({})".format(score,best),110,SCREEN_H,BG_COLOR,EDGE_COLOR)defdrawFoodTmr(val):lenght=int(val*300/ANGRY_TIME)ifval<ANGRY_TIMEelse300fill_rect(10,SCREEN_H+20,lenght,20,f_info[2])ifval>=2.5:draw_string("ANGRY",10,SCREEN_H+20,BG_COLOR,f_info[2])defdeath_annimation():forninrange(s_len):#hide the elements from the last to the fist
hideElement(n)#s_part.remove(s_part[n])
sleep(1/s_len)foryinrange(0,222,10):fill_rect(0,y,SCREEN_W,10,EDGE_COLOR)sleep(0.05)dead_msg="GAME OVER"foryinrange(-10,222//2-10,10):draw_string(dead_msg,SCREEN_W//2-5*len(dead_msg),y,BG_COLOR,EDGE_COLOR)sleep(0.05)fill_rect(SCREEN_W//2-5*len(dead_msg),y,10*len(dead_msg),20,EDGE_COLOR)draw_string(dead_msg,SCREEN_W//2-5*len(dead_msg),y,BG_COLOR,EDGE_COLOR)x,y=SCREEN_H//2,SCREEN_H//2-40#init vars
s_part,s_len,s_color,hue,f_hue,po=[],5,COLORS[0],0,0,list(START_PO)f_info,f_timer,angry=[randPo()[0],randPo()[1],COLORS[0]],float(monotonic()),0score,key,frame,frame_count,timer,speed=0,"L",1,0,float(monotonic()),START_SPEEDbest=int(readBestScore())print(str(po))#init screen
fill_rect(0,0,320,222,EDGE_COLOR)fill_rect(OFFSET_X//2,OFFSET_Y//2,SCREEN_W-OFFSET_X,SCREEN_H-OFFSET_Y,(BG_COLOR))drawFood()print("Starting game...")whileTrue:frame_count+=1#frame for move
ifmonotonic()-frame>=speed:#fps
fps=int(frame_count/(monotonic()-timer))#reset second count
frame=monotonic()vec=list(DIRECTION[key])#get direction
po[0]+=vec[0]*SIZE#change position
po[1]+=vec[1]*SIZE#score
drawScore()#dead hitbox
dead=0ifLIMIT_X[0]>po[0]orpo[0]>LIMIT_X[1]:#out of area
dead=1elifLIMIT_Y[0]>po[1]orpo[1]>LIMIT_Y[1]:dead=1ifpo[0:2]in[s_part[n][0:2]forninrange(len(s_part))]:dead=1print("touch")ifdead:print("Game over...\nFrame count : {}\nGame during : {}\nFps : {}\nScore : {}\nSpeed : {}".format(frame_count,monotonic()-timer,fps,score,speed))death_annimation()#game over
saveScore(best)breakelse:#normal move
#actualize position
s_part.append([po[0],po[1],s_color])change_color=0#food hitbox
ifpo[0:2]==f_info[0:2]:hideFood()s_len+=1score+=1000speed=speed/1.02f_timer=monotonic()fill_rect(0,SCREEN_H+20,320,20,EDGE_COLOR)change_color=1loop=0f_hue=0iff_hue==len(COLORS)-1elsef_hue+1f_info[2]=COLORS[f_hue]whileTrue:f_info[0:2]=randPo()[0],randPo()[1]loop+=1ifnotf_info[0:2]in[i[0:2]foriins_part]:breakifloop>GRID_W*GRID_H:breakhue=f_hueforninrange(len(s_part)):s_part[n][2]=COLORS[hue]drawElement(n)drawFood()score+=20ifscore>best:best=scoreifmonotonic()-f_timer>=ANGRY_TIME:angry=1change_color=1hue=0ifhue==len(COLORS)-1elsehue+1draw_string("CRAZY !",10,SCREEN_H+20,BG_COLOR,f_info[2])else:angry=0drawFoodTmr(monotonic()-f_timer)s_color=COLORS[hue]iflen(s_part)>=2:drawElement(-2)drawElement(-1)drawEye()iflen(s_part)>s_len:#len limit
hideElement(0)s_part.remove(s_part[0])#controls
ifkeydown(KEY_LEFT)andvec[0]==0:key="R"ifangryelse"L"elifkeydown(KEY_UP)andvec[1]==0:key="D"ifangryelse"U"elifkeydown(KEY_RIGHT)andvec[0]==0:key="L"ifangryelse"R"elifkeydown(KEY_DOWN)andvec[1]==0:key="U"ifangryelse"D"######game over
text="\t\tScore :{}\n\t\tBest Score :{}".format(score,best)x=320//2-(len(LOGO[0])*10)//2drawLogo(x,10,10,BG_COLOR)draw_string(text,0,150,BG_COLOR,EDGE_COLOR)whileTrue:ifkeydown(KEY_OK):whilekeydown(KEY_OK):passbreakifint(monotonic())%2==1:draw_string("press <OK>",220,200,(255,100,100),EDGE_COLOR)else:fill_rect(220,200,140,20,EDGE_COLOR)game()defmain_menu():"""the main menu"""fill_rect(0,0,320,222,EDGE_COLOR)x=320//2-(len(LOGO[0])*10)//2drawLogo(x,5,10,BG_COLOR)draw_string(INSTRUCTIONS,0,60,(150,150,150),EDGE_COLOR)whileTrue:ifkeydown(KEY_OK):whilekeydown(KEY_OK):passbreakifint(monotonic())%2==1:draw_string("press <OK>",220,200,(255,50,50),EDGE_COLOR)else:fill_rect(220,200,140,20,EDGE_COLOR)game()defdrawLogo(x,y,size,color):"""draw the logo at [x,y]
with the specified size for each pixel
and the specified color
"""foryOfinrange(len(LOGO)):forxOfinrange(len(LOGO[yOf])):ifLOGO[yOf][xOf]=="1":fill_rect(x+xOf*size,y+yOf*size,size,size,color)defreadBestScore():"""
read and return the best score
saved in snake.sav
return 0 if reading failed
"""try:file=open("snake.sav","r")best=file.readline()file.close()returnint(best)except:return0defsaveScore(score):"""
erase the actual best score in snake.sav
then write [score] on it.
"""try:file=open("snake.sav","w")file.truncate(0)file.write(str(score))file.close()except:passmain_menu()
During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:
Ensure the proper functioning of the site (essential cookies); and
Track your browsing to send you personalized communications if you have created a professional account on the site and can be contacted (audience measurement cookies).
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.