Can you cross the road? Simple frogger game.
# Frogger - NumWorks # Created by Alvar Laigna - https://alvarlaigna.com # Arrows:move frog Back:quit from kandinsky import fill_rect as F,draw_string as D from ion import keydown as K from time import sleep as Z,monotonic as M SW,SH=320,222 BK=(0,)*3;WH=(255,)*3 TH=22;RH=20;NC=SW//RH GC=(50,160,50);MC=(40,120,40);RC=(55,55,55) FC=(0,210,0);FE=(255,255,0) okv=1 if K(4)or K(52) else 0 def okd(): return K(4)or K(52) def okp(): global okv d=okd() if d and not okv: okv=1 return True if not d:okv=0 return False def wup(): while okd():Z(0.02) Z(0.12) # Lane defs: dir,speed,car_w,gap,color LD=[ None, (1,0.8,32,110,(210,50,50)), (-1,0.6,26,130,(50,70,210)), (1,1.0,36,95,(210,170,30)), None, (-1,0.7,28,120,(210,90,40)), (1,0.9,34,100,(120,40,190)), (-1,0.5,24,130,(40,170,210)), (1,1.4,40,85,(210,50,110)), None] NR=len(LD) def title(): F(0,0,SW,SH,BK) D("F R O G G E R",88,30,FC,BK) for i in range(5): c=LD[i+1][4]if LD[i+1]else LD[i+2][4] F(60+i*45,60,35,14,c) F(155,82,14,14,FC) F(158,84,3,3,FE);F(165,84,3,3,FE) D("Arrows = move",90,115,(180,)*3,BK) D("Cross all lanes!",75,138,(180,)*3,BK) D("Back = quit",105,165,(120,)*3,BK) D("Press OK",125,200,FC,BK) while True: if okp():wup();return True if K(17):return False Z(0.05) def row_y(r):return TH+r*RH def draw_bg(): F(0,0,SW,TH,(30,)*3) for r in range(NR): y=row_y(r) if r==0:F(0,y,SW,RH,GC) elif r==NR-1:F(0,y,SW,RH,GC) elif LD[r]is None:F(0,y,SW,RH,MC) else: F(0,y,SW,RH,RC) for x in range(0,SW,40): F(x+16,y+RH//2,8,1,(80,80,60)) # Goal flags for x in range(10,SW,40): F(x,row_y(0)+3,14,14,(255,220,50)) def draw_frog(fx,fy,c=None): if c is None:c=FC px,py=fx*RH+2,row_y(fy)+2 F(px,py,RH-4,RH-4,c) if c==FC: F(px+2,py+2,4,4,FE) F(px+RH-10,py+2,4,4,FE) def car_pos(ln,off): d,sp,cw,gap,co=ln stride=cw+gap n=SW//stride+2 ps=[] for i in range(n): if d>0: x=int(off+i*stride)%int(n*stride)-cw else: x=SW-int(off+i*stride)%int(n*stride) ps.append(x) return ps def draw_cars(r,off): ln=LD[r] if ln is None:return y=row_y(r)+3 cw=ln[2];co=ln[4] for x in car_pos(ln,off): if-cw<x<SW: F(max(0,x),y,min(cw,SW-max(0,x)),RH-6,co) # Windshield wx=x+4 if ln[0]>0 else x+cw-10 if 0<=wx<SW-6: F(wx,y+2,6,RH-10,(150,200,220)) def hit(fx,fy,offs): if LD[fy]is None:return False ln=LD[fy] px=fx*RH+2;pw=RH-4 for x in car_pos(ln,offs[fy]): cw=ln[2] if px+pw>x and px<x+cw:return True return False def flash_frog(fx,fy): for _ in range(3): draw_frog(fx,fy,(255,60,60)) Z(0.12) draw_frog(fx,fy,BK) Z(0.1) def frogger(): while True: sc=0;lives=3;lv=1 fx,fy=NC//2,NR-1 offs=[0.0]*NR spd=1.0 draw_bg() D("Score:0",5,3,WH,(30,)*3) h="O "*lives D(h,SW-len(h)*10-5,3,(255,80,80),(30,)*3) D("Lv:"+str(lv),150,3,(100,200,255),(30,)*3) draw_frog(fx,fy) tm=M() while True: if K(17):return now=M() dt=now-tm;tm=now if dt>0.1:dt=0.05 # Erase frog r=fy;y=row_y(r) if LD[r]is None: c=GC if r==0 or r==NR-1 else MC else:c=RC draw_frog(fx,fy,c) mv=False if K(1)and fy>0:fy-=1;mv=True elif K(2)and fy<NR-1:fy+=1;mv=True elif K(0)and fx>0:fx-=1;mv=True elif K(3)and fx<NC-1:fx+=1;mv=True # Update car offsets for r in range(NR): if LD[r]: offs[r]+=LD[r][1]*spd*dt*60 # Redraw lanes that have cars for r in range(NR): if LD[r]: ry=row_y(r) F(0,ry,SW,RH,RC) for x in range(0,SW,40): F(x+16,ry+RH//2,8,1,(80,80,60)) draw_cars(r,offs[r]) # Check collision if hit(fx,fy,offs): flash_frog(fx,fy) lives-=1 F(200,3,120,16,(30,)*3) h="O "*lives D(h,SW-len(h)*10-5,3,(255,80,80),(30,)*3) if lives<=0:break fx,fy=NC//2,NR-1 # Reached goal? if fy==0: sc+=1;lv=1+sc//3;spd=1.0+sc*0.05 F(0,3,150,16,(30,)*3) D("Score:"+str(sc),5,3,WH,(30,)*3) D("Lv:"+str(lv),150,3,(100,200,255),(30,)*3) # Celebrate draw_frog(fx,fy) Z(0.4) draw_frog(fx,fy,GC) fx,fy=NC//2,NR-1 draw_frog(fx,fy) if mv:Z(0.1) Z(0.025) # Game over F(60,70,200,80,BK) F(62,72,196,76,(20,)*3) D("GAME OVER",105,78,(255,60,60),(20,)*3) D("Score: "+str(sc),112,100,WH,(20,)*3) D("OK=again",120,125,(120,)*3,(20,)*3) while True: if K(17):return if okp():wup();break Z(0.05) if title():frogger()