;------------------ Tanks Battle ------------------
;   Kill the computer tank before it kills yours
;------------ guillaume.tello@orange.fr -----------


; procedures

#label A  player_move
#label B  bomb
#label C  computer_turn
#label D  think
#label E  init
#label D' informations
#label E' random

; flag

#flag 1 first_turn

; variables

#array field 1 10       ; ten lines of 10 digits

#reg 00 index_Y         ; index for the lines on the grid = Y position
#reg 00 X_temp
#reg 00 index
#reg 11 Y_temp
#reg 11 index_X         ; index for each digit on a line = X position
#reg 12 seed
#reg 16 DIST_player
#reg 13 X_player
#reg 14 Y_player
#reg 15 LIFE_player
#reg 17 X_computer
#reg 18 Y_computer
#reg 19 LIFE_computer
#reg 20 DIST_computer
#reg 21 temp_angle
#reg 21 shoot_distance
#reg 22 max_proba
#reg 23 X_shot
#reg 24 Y_shot
#reg 25 emergency
#reg 26 DIST_wanted
#reg 27 temp
#reg 28 best_X
#reg 29 best_Y

;-----------------
; random generator
;-----------------

LBL random
    seed={ @seed + PI = Y^X 5 = frac }
RTN

;----------------------------------------
; distance x%t angle A to move the player
;----------------------------------------

LBL player_move
    STO temp_angle
    RCL DIST_player
    IF(x<t)                                 ; if remaining dist < dist wanted..
        + + RTN                             ; ..then generates an error
    ENDIF
    DIST_player-{ x%t }                     ; else update remaining distant
    Y_player+{ x%t  RCL temp_angle P/R }    ; P/R returns dy to add to Y..
    X_player+{ X/T }                        ; ..and dx in T to add to X
    RCL LIFE_player X/T                     ; informations for the player
    RCL DIST_player                         ; DIST at X and LIFE in T
RTN

;-----------------------------
; x x%t y B drop a bomb in x,y
;-----------------------------

LBL bomb
    - RCL Y_computer = X/T                  ; y-Y_computer
    - RCL X_computer = X/T                  ; x-X_computer
    INV P/R                                 ; returns angle and shoot distance in T
    VAL LIFE_computer                       ; registers starting at 19=computer
common_bomb:
    STO index
    2 X/T                                   ; T=2 because if dist<=2 -> damages!
    STO shoot_distance                      ; X/T returns the shoot distance
    IF(x<t)
        * 2 - 5 =                           ; damages (from -5 if dist=0 to -1 if dist=2)
        SM* index                           ; in LIFE (either player or computer)
    ENDIF
    0 X/T                                   ; 0 in T for comparison
    RC* index                               ; recall LIFE
    IF(x<t)                                 ; if negative..
        LNX                                 ; ..then generates an error
    ENDIF
    X/T RCL shoot_distance                  ; info for the player
RTN

;--------------------------------
; X0 x%t Y0 E to init the game
; with starting position at X0,Y0
;--------------------------------

LBL init

    STO Y_player                            ; stores Y0
    X/T STO X_player                        ; and X0
    X_computer={ random }                   ; computer position at random [0;1[
    Y_computer={ random }
                                            ; init everything to 10
                                            ; and multiplies computer position by 10
                                            ; to get in into [0;10[
                                            
    index_Y,LIFE_player,DIST_player,LIFE_computer,DIST_computer={
                X_computer,Y_computer*{ $10 }
                                                                }
    0
    FOR index_Y                             ; clears the grid (reg 10 down to 1)
        STO field(index_Y)                  ; stores 0 on every line
    LOOP
    
    STF first_turn                          ; it's the first turn
    emergency={ 2 }                         ; emergency for a computer move to low
RTN

;--------------------------------------------
; C for computer move and shoot at the player
;--------------------------------------------

LBL computer_turn

    INV IFF first_turn
            normal_turn                     ; if not first turn, then X,Y shot yet..
                                            ; ..in memory (with procedure D)
    X_shot={ random }                       ; else, first shot at random
    Y_shot={ random }
    X_shot,Y_shot*{ $10 }
    
    X/T                                     ; 10 in T for comparison
    RCL LIFE_computer                       ; with LIFE
    
    IF(x<>t)                                ; only at first time, if LIFE<>10 then move!
    normal_turn:
        4 X/T                               ; 4 limit value for one move 
        { random Y^X @emergency 
            * @DIST_computer =  }           ; distance to move
        IF(x>=t)
            X/T                             ; if too high, then recalls 4
        ENDIF
        STO DIST_wanted
        DO
        
            DO
                RCL DIST_wanted X/T         ; distance in T
                random * $360 =             ; random angle in X
                P/R                         ; returns dy (and dx in T)
                + RCL Y_computer =
                    STO Y_temp              ; new possible Y_computer
                    * ( CE - $10 ) =        ; this expression <0 if Y_temp in [0,10]
                X/T                         ; expression in T and recalls dx
                + RCL X_computer =
                    STO X_temp              ; new possible X_computer
                0 X/T
            UNTIL(x<t)                      ; until Y is in [0;10]
            
            RCL X_temp * ( CE - $10 ) =     ; this expression <0 if X_temp in [0,10]
        UNTIL(x<t)                          ; until X is in [0;10] too
        
        X_computer={ @X_temp }              ; accept new coordinates
        Y_computer={ @Y_temp }
        DIST_computer-{ @DIST_wanted }      ; updates remaining distance
        X/T 2                               ; compares move with 2
        IF(x>=t)                            ; if little move (<2)
            INV                             ; then emergency increases (factor /2)
        ENDIF
        PRD emergency                       ; else emergency decreases (factor *2)
    ENDIF
    @X_player - @X_shot = X/T               ; dx in T
    @Y_player - @Y_shot =                   ; dy
    INV P/R                                 ; distance from bomb to the player in T
    INV STF first_turn                      ; now, not first turn anymore
    VAL LIFE_player                         ; work with registers starting at 15 (player)
    GTO common_bomb                         ; treat bombing damages

;-------------------------------------
; D to make the computer "think" about
; its next shot
;-------------------------------------

LBL think
    index_Y={ TOP field }                       ; to loop from line 10 to line 1
    Y_shot+{ $.5 }                              ; to calculate with the middle point
    max_proba={ 0 }                             ; best probability of presence found
    
    FOR index_Y                                 ; loop through grid lines
    
        index_X={ $9.5 }                        ; to loop from 9,5 to 0,5
        DIST_wanted={ @Y_shot - @index_Y = X } ; first part of distance (y-y')
        
        FOR index_X                             ; loop through digits of a line
        
            $.1 PRD field(index_Y)              ; shift line right
                RCL field(index_Y) frac         ; takes rightmost digit 0,n (0,0 to 0,8)
            INV SUM field(index_Y)              ; removes it from the line
            * 4 = STO temp                      ; value from 0 to 3,2 = previous probability
            
            $.7 X/T                             ; for comparison
            
            { @X_shot - @index_X = X           ; second part of distance (x-x')
              + @DIST_wanted = } SQR            ; distance SQR( (x-x')+(y-y'))                
            - @shoot_distance = abs             ; compared to shoot distance
            
            IF(x<t)                             ; if close (d-d'<0,7), then a possible point
            
                temp+{ 5 }                      ; add 5 to probability of presence
                RCL max_proba
                X/T RCL temp                    ; compares current proba with max
                
                IF(x>=t)                        ; if better or equal probability than max
                
                    IF(x=t)                     ; if probs are equal, then change..
                        $.6 X/T random          ; ..only if random>=0,6, else keep previous
                        x>=t dont_change
                    ENDIF
                    
                    max_proba={ @temp }         ; new best point
                    best_Y={ @index_Y }
                    best_X={ @index_X }
                    
                ENDIF
                
            ENDIF
         dont_change:
            { @temp INT * $1e9 = }              ; the new digit in 10th position
            SUM field(index_Y)                  ; and back on its line but on the left!
        LOOP
    LOOP
    X_shot={ @best_X }                          ; finally we have our next shot point
    Y_shot={ @best_Y - $.5 = }
    INV EE 0                                    ; clears everything
RTN

;--------------------------------
; D' to get informations 
; Only here for debugging reasons
; or at the end of the game,
; else, it's cheating!
;--------------------------------

LBL informations
    RCL Y_computer X/T
    RCL X_computer                           ; computer position
        R/S
    RCL LIFE_computer X/T
    RCL DIST_computer                        ; computer Dist and Life
RTN
