Last updated: February 21th, 2023
Evolve 5.0
VOLVE    5.0

Activity 4: Tank

This first program creates a USER CONTROLLED tank. The second program is a version which can be controlled by an evolving algorithm.



Add this organism to any simulation. It doesn't matter what strain you assign it to. To add to an existing simulation, first add it to a "new universe" as the strain number you want. Then add the tank creature via the Cut and Paste operations to the other simulation file.

; utank.kf
; USER CONTROLLED TANK
;
;   SPACE       - stop                          32
;   w           - start/stop move forard        119
;   s           - start/stop move backward      115
;   a           - rotate left                   97
;   d           - rotate right                  100
;   e           - eat                           101
;   r           - reproduce                     114
;   f           - fire                          102
;   .           - move                          46
;
; trap4 - move          ( -- r)             move in current direction based on thrust
; trap5 - make-spore    (e -- rc)
; trap6 - set thrust    (n -- )             n is: 0 -1 or 1     stopped, backward, forward
; trap7 - shoot         ( -- )
; trap8 - rotate        (n -- r)            n is: 0, -1 or +1
; trap9 - eat           (x y -- rc)         eat
;
; Shape:
; This organism creates a tank like shape. This is
; the morphology:
;
;       JBCD
;        EAFL
;       KGHI
;
;    #### 
;     ####
;    ####  
;
; It can only EAT and SHOOT from the turret cell
; It breeds from the back cell.
; It can generally Omove and rotate as it wants to.
; Organism cannot heal itself.
;
; A
; B     creates J
; C
; D
; E     - reproducer
; F     creates L
; G     creates K
; H
; I
; J
; K
; L     - turret/eater/shooter
;
; Protected Instructions:
;   R9++ --R9 R9!
;   CSHIFT, CMOVE
;   EAT, SEND-ENERGY, SPAWN
;   MAKE-SPORE
;   GROW, GROW.CB
;
; Modes:
;   - Make EAT permissive: Don't kill cell, just nibble
;   - rotate must use center of organism
;   
;
; Principle of operation:
;   * Shoot (trap9) can only happen from L cell
;   * Eating (trap8) can only happen from L cell
;   * Reproduction: (trap7) can only happen from E cell
;   * We use the R9 register to store our cell ID
;   * the cell ID is the code block number we were first redirected to
;
;
;

main:
{
    dnum call directions + call
    2negate
    2dup OMOVE pop
    2dup OMOVE pop
    OMOVE pop

    0 thrust 0 NUMBER!      ; may have been changed by parent reset to initial state
    2 dnum 0 NUMBER!        ; may have been changed by parent reset to initial state

    a_cell call
}

_trap1: { }
_trap2: { }

;
; ( -- thrust)
;
_trap3: { CSLEN 63 <= ?exit thrust call }

;
; Move ( -- rc)
;
;;_trap4:
;;{
;;  DSLEN 60 >= ?exit
;;  CSLEN 60 >= ?exit
;;
;;  dnum call directions + call     ; -- x y
;;  thrust call                     ; -- x y t
;;  swap over                       ; -- x t y t
;;  *                               ; x t y t -- x t y*t
;;  -rot                            ; x t y*t -- y*t x t
;;  *                               ; y*t x t -- y*t x*t
;;  swap                            ; y*t x*t -- x*t y*t
;;  OMOVE
;;}

_trap4:
{
    0 0 OMOVE
}

; make-spore replacement (e -- r)
_trap5:
{
    R9 e_cell <> ?exit
    DSLEN 60 >= ?exit
    CSLEN 60 >= ?exit

    dnum call directions + call 2negate rot MAKE-SPORE
}

; Set Thrust (n -- )
; n is normalized to -1, 0, 1
; -1 means backwards
_trap6:
{
    DSLEN 1 < ?exit
    SIGN thrust 0 NUMBER!
    recompute_move_trap call
}

;
; shoot ( -- )
;
_trap7:
{
    R9 l_cell <> ?exit
    DSLEN 60 >= ?exit
    CSLEN 60 >= ?exit

    dnum call directions + call

    1 5 bullet SPAWN pop
}

;
; rotate (n -- r)
;
_trap8:
{
    DSLEN 60 > ?exit
    CSLEN 60 > ?exit
    DSLEN 1 < ?exit
    do_rotate call
}

;
; eat (x y -- r)
;
_trap9:
{
    R9 l_cell <> ?exit
    EAT
}

recompute_move_trap:
{
    dnum 0 NUMBER
    directions + call
    thrust call
    swap over                       ; -- x t y t
    *                               ; x t y t -- x t y*t
    -rot                            ; x t y*t -- y*t x t
    *                               ; y*t x t -- y*t x*t
    swap                            ; y*t x*t -- x*t y*t
    _trap4 1 NUMBER!
    _trap4 0 NUMBER!
}

do_rotate:
{
    SIGN            ; n
    dup ROTATE
    {
        dnum 0 NUMBER   ; n dnum
        +
        dup 0 <
            { pop 7 }
            {
                dup 7 > { pop 0 } if
            } ifelse
        dnum 0 NUMBER!
        recompute_move_trap call
        1
    } { 0 } ifelse
}

; 0 = stopped, -1 = backwards, 1 = forwards
thrust: { 0 }

; this is the current direction will always be a number
; between 0 and 7.
; (Initial direction corresponds to pointing right)
dnum: { 2 }

;
; Direcetion table for 'dnum'
;
directions:
    { 0 1 }
    { 1 1 }
    { 1 0 }
    { 1 -1 }
    { 0 -1 }
    { -1 -1 }
    { -1 0 }
    { -1 1 }

;
; Create the tank shape
;       JBCD
;        EAFL
;       KGHI
;
a_cell: {
    {
        0
        -1 1    b_cell      GROW.CB not +
        0 1     c_cell      GROW.CB not +
        1 1     d_cell      GROW.CB not +
        -1 0    e_cell      GROW.CB not +
        1 0     f_cell      GROW.CB not +
        -1 -1   g_cell      GROW.CB not +
        0 -1    h_cell      GROW.CB not +
        1 -1    i_cell      GROW.CB not +
        { HALT } if
    } call
    evolve_a_cell call
}

b_cell:
{
    CB R9!
     -1 0 j_cell GROW.CB not { HALT } if
    evolve_b_cell call
}

c_cell: { CB R9! evolve_c_cell call }
d_cell: { CB R9! evolve_d_cell call }
e_cell: { CB R9! evolve_e_cell call }

f_cell:
{
    CB R9!
    1 0 l_cell GROW.CB not { HALT } if
    evolve_f_cell call
}

g_cell:
{
    CB R9!
    -1 0 k_cell GROW.CB not { HALT } if
    evolve_g_cell call
}

h_cell: { CB R9! evolve_h_cell call }
i_cell: { CB R9! evolve_i_cell call }
j_cell: { CB R9! evolve_j_cell call }
k_cell: { CB R9! evolve_k_cell call }
l_cell: { CB R9! evolve_l_cell call }

; move forward and eat
; When the bullet is spawn'd its kforth program contains  the vector the tank
; was moving, we just use that info to derive the direction of the bullet
bullet:
{
    dnum call directions + call
    
    2dup        ; (x y x y -- )

    { 2dup OMOVE ?loop } call       ; bullet move

    {
        2dup EAT pop
        2dup OMOVE pop      ; ( x y -- x y rc)
        255 NEAREST EAT
        ?loop
    } call

    HALT
}


; ---- protected / unprotected ----

evolve:
evolve_a_cell: { 1 ?loop }
evolve_b_cell: { check_thrust call }
evolve_c_cell: { 1 ?loop }
evolve_d_cell: { 1 ?loop }
evolve_e_cell: { check_reproduce call }
evolve_f_cell: { check_steering call }
evolve_g_cell: { check_fire call }
evolve_h_cell: { 1 ?loop }
evolve_i_cell: { 1 ?loop }
evolve_j_cell: { 1 ?loop }
evolve_k_cell: { TRAP4 pop 1 ?loop }        ; move
evolve_l_cell: { check_fire call }

check_thrust:
{
    KEY-PRESS
    dup 119 = { 1 TRAP6 } if
    dup 115 = { -1 TRAP6 } if
    32 = { 0 TRAP6 } if
    1 ?loop
}

check_steering:
{
    KEY-PRESS
    dup 97 = { -1 TRAP8 pop delay call } if
    100 = { 1 TRAP8 pop delay call } if
    1 ?loop
}

delay: { 50 {1- dup ?loop} call pop }

check_fire:
{
    KEY-PRESS
    dup 102 = { TRAP7 } if
    101 = { 7 NEAREST TRAP9 pop } if
    1 ?loop 
}

check_reproduce:
{
    KEY-PRESS
    dup 114 = { ENERGY 5 / TRAP5 pop } if
    46 = { TRAP4 pop } if
    1 ?loop
}