# run this program using Plumb and Animator, like this:
#   plumb "proc lander = python lander.py ; proc anim = animator ; pipe lander anim ; pipe anim lander"

import base64
import zlib
import random
import sys
from time import time, sleep
from math import floor, ceil, pi, cos, sin

RESOLUTION=64
MINPEAKS=3
MAXPEAKS=6
VARIATION=3
MAXHEIGHT=1.0
MINSITE=1
MAXSITE=3
MINSITEW=8
MAXSITEW=14
VIEWPORT=50.0
TERRAINHEIGHT=25.0
LANDERSIZE=5
MAXVARI=0.2
MAXLANDVX=1.0
MAXLANDVY=2.0
STARS=100
MINDELAY=0.01666
GRAVITY=1.6
FUEL=500.0
LATERALSTRENGTH=2.0
VERTICALSTRENGTH=4.0
CONSUMPTION=10.0
ROCKETPARTICLEV=8.0
ROCKETPARTICLEVAR=2.0
PARTICLEGRADIENT=[(0, 1, 1, 1), (0.3, 1, 1, 0.125), (0.7, 1, 0, 0.125), (1.0, 0, 0, 0.125)]
PARTICLEVERTS=7
PARTICLEMINSIZE=0.1
PARTICLEMAXSIZE=0.3
LATPARTICLEPULSE=1
VERTPARTICLEPULSE=2
EXPLODEPARTICLES=50
EXPLODEV=16.0
EXPLODEPARTICLEVAR=10.0
EXPLODEPARTICLEMULT=4.0
BLINKRATE=15
SHOWFPS=False

MOONVERTS=48
MOONR=24
MOONVAR=3
MOONCRATERS=18
MOONCRATERMINSIZE=0.5
MOONCRATERMAXSIZE=2.5
MOONCRATERVERT=16

NUMGAMES=0
NUMVICTORIES=0

DIFGRAVITY=None
DIFFUEL=None
DIFTERRAIN=None





lander='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'

print "macro lander"
print "scale", LANDERSIZE, LANDERSIZE
print "shift 0 0.5"
print zlib.decompress(base64.b64decode(lander))
print "endmacro"

peaks = random.sample(xrange(RESOLUTION), random.randint(MINPEAKS, MAXPEAKS))
peaks.sort()

def genter(peaks):
    ter=[0]*RESOLUTION
    var=float(VARIATION)/RESOLUTION
    hvar=var/2.0
    for i in peaks:
        ter[i] = random.random()
    last=ter[peaks[0]]
    for i in xrange(peaks[0]-1, -1, -1):
        last += random.random()*var-hvar
        ter[i]=last
    last=ter[peaks[-1]]
    for i in xrange(peaks[-1]+1, RESOLUTION):
        last += random.random()*var-hvar
        ter[i]=last
    def filbtwn(peak1, peak2):
        h1=ter[peaks[peak1]]
        h2=ter[peaks[peak2]]
        hd=(h2-h1)/(peaks[peak2]-peaks[peak1])
        last=h1
        for i in xrange(peaks[peak1]+1, peaks[peak2]):
            last += random.random()*var-hvar+hd
            ter[i] = last

    for i in xrange(0,len(peaks)-1):
        filbtwn(i, i+1)

    nsites = random.randint(MINSITE, MAXSITE)
    for s in xrange(nsites):
        p = random.randint(MINSITEW/2, RESOLUTION-MINSITEW/2-1)
        sw = random.randint(MINSITEW, MAXSITEW)
        fromp = max(0, p-sw/2)
        top = min(fromp+sw, RESOLUTION-1)
        ters = ter[fromp:top+1]
        h = sum(ters) / len(ters)
        for i in xrange(fromp, top+1):
            ter[i] = h

    mmin = min(ter)
    mmax = max(ter)
    msiz = mmax - mmin

    smin = 0.03
    smax = min(mmax, MAXHEIGHT)
    ssiz = smax - smin

    return [((t - mmin) / msiz * ssiz + smin) * TERRAINHEIGHT for t in ter]

def color(r, g, b):
    r=max(0.0, min(r, 1.0))
    g=max(0.0, min(g, 1.0))
    b=max(0.0, min(b, 1.0))
    print 'color #%02x%02x%02x' % (r*255.0, g*255.0, b*255.0)

def gradient(g, p):
    for i in xrange(len(g)-1):
        (ap,ar,ag,ab)=g[i]
        (bp,br,bg,bb)=g[i+1]
        if p >= ap and p <= bp:
            p = (p - ap) / (bp - ap)
            color((br-ar)*p+ar, (bg-ag)*p+ag, (bb-ab)*p+ab)
            return
    (bp,br,bg,bb)=g[-1]
    color(br, bg, bb)

def newstars():
    print "macro stars"
    for i in xrange(STARS):
        b = random.random()*0.5 + 0.4
        color(b, b, b)
        print "dot", random.random()*VIEWPORT, random.random()*VIEWPORT
    print "endmacro"

def newterrain():
    global terrain
    terrain=genter(peaks)

    print "macro terrain"
    print "color gray"
    print "poly"
    step=VIEWPORT/(RESOLUTION-1)
    x=0.0
    for i in xrange(RESOLUTION):
        print x, terrain[i]
        x += step
    print VIEWPORT, "0"
    print "0 0"
    print "0", terrain[0]
    print "endmacro"

def genmoon():
    print "macro moon"

    print "color #a0a0a0"
    print "poly"
    step = pi*2/MOONVERTS
    a = 0
    for i in xrange(MOONVERTS):
        r = MOONR + (random.random() - 0.5) * MOONVAR
        x = cos(a) * r
        y = sin(a) * r
        print "%.4f %.4f" % (x, y)
        a += step
    print "color #808080"
    for i in xrange(MOONCRATERS):
        a = random.random() * 2 * pi
        size = random.random() * (MOONCRATERMAXSIZE - MOONCRATERMINSIZE) + MOONCRATERMINSIZE
        r = random.random() * (MOONR - size * 2.5) + size
        x = cos(a) * r
        y = sin(a) * r
        print "fillcircle %.4f %.4f %.4f %s" % (x, y, size, MOONCRATERVERT)

    print "endmacro"

def selterrain(mode):
    global DIFTERRAIN, MINPEAKS, MAXPEAKS, VARIATION, TERRAINHEIGHT, MINSITE, MAXSITE, MINSITEW, MAXSITEW
    MINSITE=1
    MAXSITE=3
    MINSITEW=8
    MAXSITEW=14
    MINPEAKS=3
    MAXPEAKS=6
    TERRAINHEIGHT=25.0
    if mode == 'f':
        DIFTERRAIN="  Flat  "
        TERRAINHEIGHT=16.0
        VARIATION=1
        MINPEAKS=1
        MAXPEAKS=3
    elif mode == 'b':
        DIFTERRAIN=" Bumpy  "
        TERRAINHEIGHT=28.0
        VARIATION=3
        MAXSITE=2
        MAXSITEW=12
    elif mode == 't':
        DIFTERRAIN="Terrible"
        TERRAINHEIGHT=37.0
        VARIATION=5.5
        MINPEAKS=8
        MAXPEAKS=10
        MAXSITE=1
        MINSITEW=7
        MAXSITEW=10

def selfuel(mode):
    global DIFFUEL, FUEL
    if mode == 'l':
        DIFFUEL='Little '
        FUEL=250
    elif mode == 'a':
        DIFFUEL='Average'
        FUEL=400
    elif mode == 'm':
        DIFFUEL=' Much  '
        FUEL=650

def selgravity(mode):
    global DIFGRAVITY, GRAVITY, LATERALSTRENGTH, VERTICALSTRENGTH, CONSUMPTION
    CONSUMPTION=10.0
    LATERALSTRENGTH=2.0
    VERTICALSTRENGTH=4.0

    if mode == 's':
        DIFGRAVITY='Slight'
        GRAVITY=1.5
    elif mode == 'n':
        DIFGRAVITY='Normal'
        GRAVITY=2.5
    elif mode == 'h':
        VERTICALSTRENGTH=5.5
        DIFGRAVITY='Heavy '
        GRAVITY=4.0

selterrain('b')
selfuel('a')
selgravity('n')


print "bg #000020"
print "color #202020"
print "line -1 -1 -1 1"
print "line 1 -1 1 1"

print "color gray"

print "shift -1 -1"
viewportscale = 2.0 / VIEWPORT
print "scale", viewportscale, viewportscale

print "events on"

def drawlander(p):
    (x, y, vx, vy) = p
    print "push"
    print "shift %.4f %.4f" % (x, y)
    vx /= 4.0
    vx=min(1, max(-1, vx))
    print "rotate %.4f" % (-vx*15,)
    print "invoke lander"
    print "pop"

def updatepos(dt, p, fx, fy):
    (x, y, vx, vy) = p
    vx += (fx * dt)
    vy += ((fy-GRAVITY) * dt)
    x += (vx * dt)
    y += (vy * dt)
    if y<0:
        y = 0
    return (x, y, vx, vy)

def tersample(x):
    x = min(VIEWPORT, max(0, x)) / VIEWPORT * (RESOLUTION - 1)
    f = max(0, int(floor(x)))
    c = min(RESOLUTION-1, int(ceil(x)))
    if f == c:
        return terrain[f]
    m = x-floor(x)
    return terrain[f]*(1.0-m) + terrain[c]*m

def mainmenu():
    s = { 'r': 0, 'messagecnt': 0, 'messagestate': 0 }
    centermsg = "     L A N D E R\\n\\n    SELECT TERRAIN\\nF:LAT B:UMPY T:ERRIBLE\\n     SELECT FUEL\\nM:UCH A:VERAGE L:ITTLE\\n    SELECT GRAVITY\\nS:LIGHT N:ORMAL H:EAVY"
    fr1 = "* * * * * * * * * * * * *\\n                         *\\n*\\n                         *\\n*\\n                         *\\n*\\n                         *\\n*\\n                         *\\n*\\n * * * * * * * * * * * * *"
    fr2 = " * * * * * * * * * * * * *\\n*\\n                         *\\n*\\n                         *\\n*\\n                         *\\n*\\n                         *\\n*\\n                         *\\n* * * * * * * * * * * * *"

    def frame():
        print "frame"
        print "color #000080"
        print "line 0 0 0", VIEWPORT
        print "line", VIEWPORT, "0", VIEWPORT, VIEWPORT
        print "invoke stars"
        print "push"
        print "shift", VIEWPORT/2, VIEWPORT/2
        print "rotate %.4f" % (s['r'],)
        print "invoke moon"
        print "pop"

        print "color white"

        if NUMGAMES > 0:
            print "text center top %f %f \"WON %s OF TOTAL %s\"" % (VIEWPORT/2, 0, NUMVICTORIES, NUMGAMES)

        print "text center bottom", VIEWPORT/2, VIEWPORT, "\"     PRESS SPACE TO PLAY\\n%s * %s * %s\"" % (DIFTERRAIN, DIFFUEL, DIFGRAVITY)

        print "color white"
        print "text", VIEWPORT/2, VIEWPORT/2, "\"%s\"" % (centermsg,)
        if s['messagestate'] == 0:
            print "color green"
        else:
            print "color yellow"
        print "text", VIEWPORT/2, VIEWPORT/2, "\"%s\"" % (fr1,)
        if s['messagestate'] == 0:
            print "color yellow"
        else:
            print "color green"
        print "text", VIEWPORT/2, VIEWPORT/2, "\"%s\"" % (fr2,)

        print "flushdelay 0.0166666"

    def update(dt):
        s['r'] += dt * 2.0

    while True:
        l = sys.stdin.readline().strip().split()
        if l[0] == 'KEYDOWN':
            if l[3] == 'space':
                return True
            elif l[3] == 'escape':
                return False
            elif l[3] in ['f', 'b', 't']:
                selterrain(l[3])
            elif l[3] in ['l', 'a', 'm']:
                selfuel(l[3])
            elif l[3] in ['s', 'n', 'h']:
                selgravity(l[3])
        elif l[0] == 'FLUSHDELAY':
            s['messagecnt'] += 1
            if s['messagecnt'] >= BLINKRATE:
                s['messagecnt'] = 0
                s['messagestate'] = 1 - s['messagestate']

            update(float(l[1]))

            frame()
            sys.stdout.flush()


def game():
    keystate = { 'u':False, 'l':False, 'r':False }
    keymap = {
            'up': 'u', 'left': 'l', 'right': 'r',
            'w': 'u', 'a': 'l', 'd': 'r',
            '[8]': 'u', '[4]': 'l', '[6]': 'r'
            }

    s = {
            'lander': (VIEWPORT/2, VIEWPORT-LANDERSIZE, 0, 0),
            'fuel': FUEL,
            'parts': [],
            'drawlander': True,
            'alive': True,
            'message': None,
            'messagecolor1': None,
            'messagecolor2': None,
            'messagestate': 0,
            'messagecnt': 0,
            'win': False,
            'fps': None
            }

    def shoot(x, y, vx, vy, varx, vary, sizemult):
        vx = vx + (random.random() - 0.5) * varx
        vy = vy + (random.random() - 0.5) * vary
        size = sizemult * (random.random() * (PARTICLEMAXSIZE - PARTICLEMINSIZE) + PARTICLEMINSIZE)
        return ((x, y, vx, vy), 0.0, size)

    def rocketpulse(vx, vy, n):
        (lx, ly, lvx, lvy) = s['lander']
        vx *= ROCKETPARTICLEV
        vy *= ROCKETPARTICLEV
        s['parts'] += [shoot(lx, ly+LANDERSIZE/4, lvx+vx, lvy+vy, ROCKETPARTICLEVAR, ROCKETPARTICLEVAR, 1.0) for i in xrange(n)]

    def kill(reason):
        s['alive'] = False
        s['drawlander'] = False
        (lx, ly, lvx, lvy) = s['lander']
        ly += LANDERSIZE/3
        for i in xrange(EXPLODEPARTICLES):
            a = (float(i) / EXPLODEPARTICLES) * pi * 2
            vx = lvx + cos(a) * EXPLODEV
            vy = lvy + sin(a) * EXPLODEV
            s['parts'].append(shoot(lx, ly, vx, vy, EXPLODEPARTICLEVAR, EXPLODEPARTICLEVAR, EXPLODEPARTICLEMULT))
        s['message'] = reason
        s['messagecolor1'] = '#ff0000'
        s['messagecolor2'] = None
        s['messagecnt'] = 0
        s['messagestate'] = 0

    def victory():
        s['alive'] = False
        s['win'] = True
        s['message'] = "WHO IS AWESOME?\\nYOU'RE AWESOME!"
        s['messagecolor1'] = '#ffff00'
        s['messagecolor2'] = '#00ff00'
        s['messagecnt'] = 0
        s['messagestate'] = 0

    def frame():
        print "frame"
        print "color #000080"
        print "line 0 0 0", VIEWPORT
        print "line", VIEWPORT, "0", VIEWPORT, VIEWPORT
        print "invoke stars"

        for ((px, py, pvx, pvy), t, size) in s['parts']:
            gradient(PARTICLEGRADIENT, t)
            print "alpha %.2f" % ((1.0 - t/2.0),)
            print "fillcircle %.4f %.4f %.4f %s" % (px, py, size, PARTICLEVERTS)
        print "alpha 255"

        print "invoke terrain"
        if s['alive']:
            print "color white"
            print "text right bottom 0", VIEWPORT, "\"%.2f\"" % (s['fuel'],)
            if abs(s['lander'][2]) > MAXLANDVX or abs(s['lander'][3]) > MAXLANDVY:
                print "color red"
            else:
                print "color green"
            print "text left bottom", VIEWPORT, VIEWPORT, "\"%+5.2f %+5.2f\"" % (s['lander'][2], s['lander'][3])
        if s['drawlander']:
            drawlander(s['lander'])

        if s['message']:
            clr = s['messagecolor1'] if s['messagestate'] == 0 else s['messagecolor2']
            if clr is not None:
                print "color", clr
                print "text", VIEWPORT/2, VIEWPORT/2, "\"%s\"" % (s['message'],)

        if not s['alive']:
            print "color white"
            print "text center bottom", VIEWPORT/2, VIEWPORT, "\"PRESS SPACE\""

        if SHOWFPS and s['fps'] is not None:
            print "color red"
            print "text right top 0 0 \"%.2f\"" % (s['fps'],)

        print "flushdelay 0.0166666"

    def update(dt):
        s['fps'] = 1.0/dt
        if s['alive']:
            fx=0.0
            fy=0.0
            if keystate['l'] and s['fuel']>0:
                fx -= LATERALSTRENGTH
                s['fuel'] -= (LATERALSTRENGTH * CONSUMPTION * dt)
                rocketpulse(1, 0, LATPARTICLEPULSE)
            if keystate['r'] and s['fuel']>0:
                fx += LATERALSTRENGTH
                s['fuel'] -= (LATERALSTRENGTH * CONSUMPTION * dt)
                rocketpulse(-1, 0, LATPARTICLEPULSE)
            if keystate['u'] and s['fuel']>0:
                fy += VERTICALSTRENGTH
                s['fuel'] -= (VERTICALSTRENGTH * CONSUMPTION * dt)
                rocketpulse(0, -1, VERTPARTICLEPULSE)
            s['fuel'] = max(0, s['fuel'])
            s['lander'] = updatepos(dt, s['lander'], fx, fy)
            (lx, ly, lvx, lvy) = s['lander']
            if lx < LANDERSIZE/2:
                kill("THINK INSIDE THE BOX")
            elif lx > VIEWPORT - LANDERSIZE/2:
                kill("THINK INSIDE THE BOX")
            else:
                sampleleft=lx-LANDERSIZE/2.8
                sampleright=lx+LANDERSIZE/2.8
                nsamples=LANDERSIZE*3
                step=(sampleright-sampleleft)/nsamples
                sam=[tersample(sampleleft+i*step) for i in xrange(nsamples+1)]
                maxs = max(sam)
                if ly <= maxs:
                    mins = min(sam)
                    vari = maxs - mins
                    if vari > MAXVARI:
                        kill("AREA TOO BUMPY")
                    elif abs(lvx) > MAXLANDVX:
                        kill("TOO FAST SIDEWAYS")
                    elif abs(lvy) > MAXLANDVY:
                        kill("CRATERED")
                    else:
                        s['lander'] = (lx, mins+vari/2, 0, 0)
                        victory()

        np = []
        for (pos, t, size) in s['parts']:
            pos = updatepos(dt, pos, 0, 0)
            (px, py, vx, vy) = pos
            t += dt

            ty = tersample(px)

            if t < 1.0 and px > size and px < VIEWPORT - size and py > ty:
                np.append((pos, t, size))
        s['parts'] = np

    while True:
        l = sys.stdin.readline().strip().split()
        if l[0] == 'KEYDOWN':
            if l[3] in keymap:
                keystate[keymap[l[3]]] = True
            elif l[3] == 'escape':
                return s['win']
            elif l[3] == 'space' and not s['alive']:
                return s['win']
        elif l[0] == 'KEYUP':
            if l[2] in keymap:
                keystate[keymap[l[2]]] = False
        elif l[0] == 'FLUSHDELAY':
            s['messagecnt'] += 1
            if s['messagecnt'] >= BLINKRATE:
                s['messagecnt'] = 0
                s['messagestate'] = 1 - s['messagestate']

            update(float(l[1]))

            frame()
            sys.stdout.flush()

print "flushdelay 0"
sys.stdout.flush()

while True:
    newstars()
    genmoon()
    if not mainmenu():
        exit()
    newstars()
    newterrain()
    if game():
        NUMVICTORIES += 1
    NUMGAMES += 1
