
SGB_10.net      CORE WARS

Steve's Guide for Beginners Iss 10 (v2)

Issue 7 looked at one (inefficient) way of copying
blocks of code/data around.

Issue 8 looked at another variation of copying and
at the SPL command.

Issue 9 looked at imp-rings and bombers and
replicators (by proxy).

======

The first six issues took a week to produce. The
next two took another week. The ninth took another
week. As I get into it, it all slows down
enormously.

However I now reckon I have enough knowledge to
analyse one of the warriors supplied with PMARS08
- RAVE.RED .

======

The source:

;redcode-94
;name Rave
;author Stefan Strack
;strategy Carpet-bombing scanner based on Agony and Medusa's
;strategy (written in ICWS'94)
;strategy Submitted: @date@
;assert CORESIZE==8000

CDIST   equ 12
IVAL    equ 42
FIRST   equ scan+OFFSET+IVAL
OFFSET  equ (2*IVAL)
DJNOFF  equ -431
BOMBLEN equ CDIST+2

        org comp

scan    sub.f  incr,comp
comp    cmp.i  FIRST,FIRST-CDIST        ;larger number is A
        slt.a  #incr-comp+BOMBLEN,comp  ;compare to A-number
        djn.f  scan,<FIRST+DJNOFF       ;decrement A- and B-number
        mov.ab #BOMBLEN,count
split   mov.i  bomb,>comp               ;post-increment
count   djn.b  split,#0
        sub.ab #BOMBLEN,comp
        jmn.b  scan,scan
bomb    spl.a  0,0
        mov.i  incr,<count
incr    dat.f  <0-IVAL,<0-IVAL
 end

======

Which assembles as:

Program "Rave" (length 12) by "Stefan Strack"

       ORG      START
       SUB.F  $    11, $     1
START  CMP.I  $   125, $   113
       SLT.A  #    24, $    -1
       DJN.F  $    -3, <  -308
       MOV.AB #    14, $     2
       MOV.I  $     4, >    -4
       DJN.B  $    -1, #     0
       SUB.AB #    14, $    -6
       JMN.B  $    -8, $    -8
       SPL.A  $     0, $     0
       MOV.I  $     1, <    -4
       DAT.F  <   -42, <   -42

======

First note that RAVE works with only ONE process
until the last parts of its operation.

======

Rave starts by comparing two locations 100+ locns
further on. Assuming that there is no opposing
warrior there, the CMP (SkipifEQual) will find a
matched pair of "empty" (DAT 0,0) instructions.
Therefore CMP will skip to the DJN.

The DJN pre-decrements a BNumber and uses that as
a pointer to another locn where it decrements both
A and B Numbers. I'll come back to exactly what
gets decremented later. Just assume that it
doesn't decrement to both zero, so the DJN jumps
to "scan"

At "scan", the CMP instruction at "comp" is
modified, by subtracting -42 from both A & B
Numbers (IE adding 42 to each).

The loop of three instructions now repeats but
inspecting locations 42 further on.

What happens when the two locations aren't the
same (IE it has found something - either code or
bombs dropped by the enemy)? In that case it
executes the SLT (SkipifLessThan) which skips if
the immediate ANumber is less than the ANumber in
the "comp" instruction.
The immediate ANumber is a complicated expression
that boils down to 24. This is a means of testing
if the "enemy warrior" just detected is actually
"yourself". (It is presumably 24 due to the length
of RAVE (12) + the comparison separation
(also 12).
If it has detected itself, it rolls into the DJN
and scans round core again, slightly offset as 42
is not a factor of 8000.
If it has detected something else, it changes
mode.

See the appendix to this issue for a list of SLT
visits (aka boming runs).

======

Before looking at what it does after the mode
change, lets look in more detail at the DJN
BOperand. This pre-decrements location "-308".

Often this will be "empty" (DAT 0,0), in which
case the pre-decrement will change it to DAT 0,-1
so the DJN will decrement the A & B Numbers of
locn -309. Again assuming it was empty, this will
go from DAT 0,0 to DAT -1,-1.

Next time round the loop it will predecrement -308
to DAT 0,-2 and hence decrement and test locn
-310. Then -311, then -312 etc.

What does this achieve? Well it will usually jump
unless enemy code / data is at that locn. If it is
there then the code will be corrupted by the
decrements. Additionally the pre-decrement acts as
a sort of inefficient imp-gate.

It is at -308 to stop it being too close to the
main body of code as it will easily be found by
scanners and bombers. (Note that the CMP will
start comparing the decremented (DAT -1,-1)
locations after a while. It is phased so that they
are equal and we don't compare a decremented
DAT -1,-1 with an undecremented DAT 0,0 too
often.) (Without being presumptious, I wonder if
perhaps this could be improved given the list in
the appendix.)

======

Having scanned core and found something what does
RAVE do now?

It goes into a tight loop bombing 14 locations
from the smaller of the two locns which differed.
(MOV.AB sets up the loop count, MOV.I bombs, DJN.B
loops.)
(After the bombing run, the pointer COMP is
repaired using SUB.AB .)

It then tests the BNumber in "scan" which is a
(nearly) constant "1", so it always jumps to
"scan" and starts again, stepping on from where it
got to looking for more code to attack.

Note that the bomb is "SPL 0,0" which will cause
the bombed location to malfunction and slow the
enemy down by spliting lots of processes off. It
won't actually kill the enemy.

======

This is the bit I missed in v1 of this issue.
Thanks to those who explained what I was missing.

The test of the BNumber in "scan" is not *always*
1. After some number of loops round the code, the
ANumber in "comp" is "scan" ("comp-1"). This is
interpreted as being enemy code rather than
"myself", so the bombing run commences. The
bombing run overwrites "scan" with the SPL bomb.

When this happen, the JMN doesn't jump back to
scan but switches into its final modes.

======

It executes SPL 0 which queues one process to the
next instruction and one at SPL again. Thus there
is a steady stream of processes being generated by
this SPL.

The process reaching the next instruction executes
a MOV which puts a killing DAT at "count-1" and
all locations before that, working backwards round
core, clearing it. (This is a core clear.)
The process then falls through to the DAT where is
dies.

However, as it dies, it decrements location
"incr"-IVAL (about -30 absolute) twice as part of
the Operand address evaluation. This is an imp
gate.

When the coreclear has gone round memory once, the
MOV will be zapped by the DAT, so the coreclear
stops and the SPL just feeds the newly moved imp-
gate.

======

To summarise:

RAVE has a sort-of imp-gate 308 locations before
it.

RAVE corrupts core, one location at a time
backwards.

RAVE scans core in jumps of 42 looking for enemies
and bomb 14 locations there.

RAVE eventually bombs itself and switches to a
coreclear and imp-gate.

RAVE then sits being an imp-gate till the end of
the round.

======

APPENDIX

List of values of "comp" at each execution of SLT:

It is a worthwhile exercise to understand why each
bombing run occurs in a single warrior (rave)
environment.

The ones with * are "the enemy is me" situations.
The one with # is "the enemy is me, but I have
left myself exposed".

00001   CMP.I  $    21, $     9     *
00001   CMP.I  $     1, $   -11     *
00001   CMP.I  $     3, $    -9     *
00001   CMP.I  $     5, $    -7     *
00001   CMP.I  $     7, $    -5     *
00001   CMP.I  $     9, $    -3     *
00001   CMP.I  $  -305, $  -317
00001   CMP.I  $ -2383, $ -2395
00001   CMP.I  $    11, $    -1     *
00001   CMP.I  $  -303, $  -315
00001   CMP.I  $ -2381, $ -2393
00001   CMP.I  $    13, $     1     *
00001   CMP.I  $  -679, $  -691
00001   CMP.I  $  -301, $  -313
00001   CMP.I  $ -2379, $ -2391
00001   CMP.I  $  -489, $  -501
00001   CMP.I  $    15, $     3     *
00001   CMP.I  $  -677, $  -689
00001   CMP.I  $  -299, $  -311
00001   CMP.I  $ -2377, $ -2389
00001   CMP.I  $  -487, $  -499
00001   CMP.I  $    17, $     5     *
00001   CMP.I  $  -675, $  -687
00001   CMP.I  $  -297, $  -309
00001   CMP.I  $ -2375, $ -2387
00001   CMP.I  $  -485, $  -497
00001   CMP.I  $  -317, $  -329
00001   CMP.I  $    19, $     7     *
00001   CMP.I  $ -2395, $ -2407
00001   CMP.I  $  -673, $  -685
00001   CMP.I  $  -295, $  -307
00001   CMP.I  $    -1, $   -13     *#
End of round 1

This data was obtained using:
PM RAVE -e
write rave.dbg
trace 2
g~l 1
>>>lots of repeats using ENTER<<<
q
EDIT RAVE.DBG

======

Sorry about the length of this issue, but RAVE has
turned out to be more complex than I expected when
I started this!

=== Steve Bailey 101374.624@compuserve.com
sgb@zed-inst.demon.co.uk
http://ourworld.compuserve.com/homepages/SGBailey
Work: Electronics Play: Go 2kyu.
