# Smashy Road: Wanted - 3D voxel edition for NumWorks
# ARROWS: drive in that direction  OK/EXE: restart
from kandinsky import fill_rect as F, draw_string as S
from ion import keydown as K
import ion
from math import sin,cos,atan2,pi
from time import sleep,monotonic
from random import random as R
W,H,C,KY=320,222,40,0.7
GR=(104,190,80);RD=(78,80,92);LN=(240,230,140)
BT=(70,170,70);BS=(40,110,45);BB=((230,120,90),(160,70,55),14),((120,160,230),(70,100,170),20),((235,215,150),(180,150,90),26)
SW=(190,190,195)
PT=(255,190,40);PS=(200,110,20)
CT=(250,250,255);CS=(25,25,35);RE=(240,40,40);BL=(40,90,255)
def blk(a,b):
  if a%5==0 or b%5==0:return 0
  h=(a*92821+b*68917)&255
  return 2+h%3 if h<100 else(1 if h<140 else 0)
def hit(x,y):
  a=int(x//C);b=int(y//C)
  return blk(a,b) and abs(x-a*C-20)<15 and abs(y-b*C-20)<15
def box(sx,y,s,h,t,f,oy):
  t0=int((y-s-oy)*KY)-h;t1=int((y+s-oy)*KY)-h
  F(int(sx-s),t1,2*s,h,f);F(int(sx-s),t0,2*s,t1-t0,t)
  return t0,t1
def car(x,y,a,ox,oy,cop,f):
  sx=x-ox
  if cop:
    t0,t1=box(sx,y,6,5,CT,CS,oy)
    F(int(sx)-4,t0+3,8,3,CS)
    F(int(sx)-3,t0-3,3,3,RE if f%6<3 else BL)
    F(int(sx),t0-3,3,3,BL if f%6<3 else RE)
  else:
    box(sx,y,8,7,(0,0,0),(0,0,0),oy)
    t0,t1=box(sx,y,6,5,PT,PS,oy)
  cy=(t0+t1)//2
  F(int(sx+cos(a)*5)-2,int(cy+sin(a)*5*KY)-2,4,4,(30,30,30))
def game():
  x,y,a=20.0,20.0,0.0;cops=[];f=0;sc=0
  while 1:
    t=monotonic();f+=1
    dx=K(ion.KEY_RIGHT)-K(ion.KEY_LEFT);dy=K(ion.KEY_DOWN)-K(ion.KEY_UP)
    if dx or dy:
      d=(atan2(dy,dx)-a+pi)%(2*pi)-pi
      a+=max(-0.35,min(0.35,d))
    x+=cos(a)*3;y+=sin(a)*3
    wl=min(5,1+f//250)
    if (f==15 or f%50==0) and len(cops)<wl+1:
      r=a+pi+(R()-0.5)*1.5
      cops.append([x+cos(r)*150,y+sin(r)*150,r+pi])
    for c in cops:
      tx=x+cos(a)*20;ty=y+sin(a)*20
      d=atan2(ty-c[1],tx-c[0])-c[2]
      d=(d+pi)%(2*pi)-pi
      c[2]+=max(-0.08,min(0.08,d))
      v=2.8+wl*0.15
      c[0]+=cos(c[2])*v;c[1]+=sin(c[2])*v
    dead=[]
    n=len(cops)
    for i in range(n):
      c=cops[i]
      if hit(c[0],c[1]):dead.append(i)
      for j in range(i+1,n):
        e=cops[j]
        if abs(c[0]-e[0])<10 and abs(c[1]-e[1])<10:dead+=[i,j]
    if dead:
      sc+=50*len(set(dead))
      cops=[cops[i] for i in range(n) if i not in dead]
    ox=x-W/2;oy=y-(H/2+15)/KY
    F(0,0,W,H,GR)
    a0=int(ox//C);b0=int(oy//C)
    for i in range(a0,a0+10):
      if i%5==0:
        sx=int(i*C-ox);F(sx-3,0,C+6,H,SW);F(sx,0,C,H,RD)
    for j in range(b0,b0+12):
      if j%5==0:
        sy=int((j*C-oy)*KY);F(0,sy-3,W,34,SW);F(0,sy,W,28,RD)
    for i in range(a0,a0+10):
      if i%5==0:
        sx=int(i*C-ox)+19
        for q in range(-(int(oy*KY)%24),H,24):F(sx,q,2,12,LN)
    for j in range(b0,b0+12):
      if j%5==0:
        sy=int((j*C-oy)*KY)+13
        for q in range(-(int(ox)%24),W,24):F(q,sy,12,2,LN)
    L=[]
    for j in range(b0,b0+12):
      for i in range(a0,a0+10):
        k=blk(i,j)
        if k:L.append((j*C+20,0,i,k))
    L.sort(key=lambda o:o[0])
    for o in L:
      if o[1]==0:
        if o[3]==1:box(o[2]*C+20-ox,o[0],12,10,BT,BS,oy)
        else:
          b=BB[o[3]-2];box(o[2]*C+20-ox,o[0],15,b[2],b[0],b[1],oy)
    for c in cops:car(c[0],c[1],c[2],ox,oy,1,f)
    car(x,y,a,ox,oy,0,f)
    sc+=1
    F(0,0,W,20,(20,20,30))
    S("SMASHY ROAD",105,1,PT,(20,20,30))
    S("*"*wl,4,1,(255,220,0),(20,20,30))
    S(str(sc),316-10*len(str(sc)),1,(255,255,255),(20,20,30))
    if hit(x,y) or any(abs(c[0]-x)<10 and abs(c[1]-y)<10 for c in cops):
      S(" BUSTED! "+str(sc)+" ",90,100,(255,255,255),RE)
      S(" OK to retry ",95,124,(0,0,0),PT)
      return
    dt=0.04-(monotonic()-t)
    if dt>0:sleep(dt)
while 1:
  game()
  while not(K(ion.KEY_OK) or K(ion.KEY_EXE)):sleep(0.05)
