frogger.py

Created by laigna

Created on March 14, 2026

4.25 KB

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()

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.