;redcode-94
;name Rand-Man
;author Randy Graham
;contact hp715!rgraham@peridot.spawar.navy.mil
;NSFCWT round 5
;assert 1
;strategy Fight in a random core size. Move weak stone away from decoy
;strategy and launch gate-crashing imp spiral. Use pspace to save time
;strategy on later boots (but protect against brainwashing).
IMPOFF equ (imp+500)
IMPSIZE equ #3 ;what step size we think we need
PDATPTR equ #2 ;save # of points to verify step size
STONESAVE equ #1 ;what stone step we want
STONESTEP equ 36 ;what to start check at
STONEMAX equ 50 ;what to stop at
imp mov.i #3044, -1
imp2 mov.i #1143, 1
launch3 spl.a adder3, <-330
jmpto3 jmp.a IMPOFF+6, <-91
adder3 add.ba imp2, jmpto3
datptr dat.f 13, getptr
dat.f 11, 0
dat.f 7, 0
dat.f 5, 0
getsize ldp.ab IMPSIZE, #0 ;these 2 lines double as data
getptr ldp.ab PDATPTR, datptr ;statements
mul.ab @datptr, getsize
seq.ab #1, getsize
counter jmp.a starter-1, 0
getstone ldp.a STONESAVE, setstone
ldp.ab IMPSIZE, imp ;restore location
jmp.a postsave, <-431
mov.ab #(getptr-datptr), datptr
starter div.ab #2, imp
add.ab #1, imp ;set imp.b to CORESIZE/2
moder mod.ba #-1, #2
jmz.a psave, moder ;make 2-point imp if odd core
check mov.a R=m%p
; I can't do Coresize % Points, but I can do (Coresize-1)%points
; Then, add one to make up for the one we subtracted. Finally, mod
; that with points again to make sure we have the real mod.
setup mod.ab @datptr, skipper
add.ab #1, skipper
skipper mod.ab @datptr, #0 ;after this, we have our mod
;The next part is a hybrid of Brant D. Thomsen's Imp-Spiral Finder in
; the May 4, 1994 issue of The 94 Warrior and Jay Han's routine in
; makeimp.c. This calculates the N value for Jay's
; ImpStep = (CoreSize * N + 1) / ImpSize ---> x=(m*n+1)/p
;The idea for only looping through ImpSize-1 times and checking is
; from Brant's program's data lines (get the program and see it)
;Now, to actually check if our attempted point size is an impstep, we
; use Jay's lines
; Counter = 0
; if (Counter+R) % Points == Points - 1 --> if ((c=(c+r)%p) == p-1)
; until we have checked Points-1 times or we get the match
mov.ab gotit, loop
check2 mov.ab #0, gotit
setN add.ab #1, counter
add.b skipper, gotit
mod.ab @datptr, gotit
gotit sne.ab #0, #0
jmp.a sizer, <-100
loop djn.b setN, #loop
jmn.b check, datptr ;in case this fails, at least stone
;Here was the hard part. Given the number of points we can theoretically
; run in this core size, and knowing Coresize/2, figure out the correct
; step size. In Jay's program, he used
; ImpStep = (CoreSize * N + 1) / ImpSize ---> x=(m*n+1)/p
; as noted above. We have the N now, but how to do the math in a
; modular world. Well, I finally decided to give up on getting it right,
; and just get close. Then I can find the exact amount. So, throw
; away the +1, combine the terms, and remember that you know CoreSize/2
; Use the above ImpStep equation, modified for what you have
; ImpStep = (CoreSize / 2 / ImpSize * N) * 2 (approximately)
;By doing the division first, then multiplying, we don't have the
; wraparound effect of the Modular world mess us up. And, we get
; pretty close to the correct value. Also, since we are using integer
; division and we ignored the +1 above, we know we will be slightly
; BELOW the correct value. So, add one, multiply it by the number of
; points. If it is equals 1 (in a modular world), then it is correct.
; If not, loop back, add one more, multiply again, and go until you get
; a 1. Then, you have what you need, so move your imp out and launch
; it (using a jmp/add launch which let's you add in your step as you go)
;As for why this works, I don't exactly know. You have to ask Jay for
; details. I just converted his C code to Redcode. ;-)
sizer div.ab @datptr, imp ;approximate the step size
mul.ab #2, imp
mul.b counter, imp
exact mov.b imp, #0
mul.ab @datptr, -1
seq.ab #1, -2
jmp.a exact, >imp
psave stp.b datptr, PDATPTR
stp.b imp, IMPSIZE
;Ffrom Jay Han's corestep, find a number from mod-4 to mod-7. If no
;number is usable, then use 7 (per moonstone). C code was:
; uint modsize (uint s)
; {
; uint r, b=s, a=coresize;
; if (s == 0 || s == 1) return s;
; while (r=a%b)
; {
; a=b;
; b=r;
; }
; return b;
; }
;
;where uint is an unsigned integer, and s is the number to find the
; modsize for
;I used from 36 to 51 as my s.
;I only stopped on s == 0 (save 2 instructions, waste 5 cycles - but
; those two instructions would be executed every time otherwise).
;When I found a modsize between 4 and 7 (inclusive) I used it
;Man I like Jay's code. Helped a lot on this round
;I just hope I do OK. I am REALLLLLY slow launching because of finding
; my stone step size - especially in prime size cores
setstone mov.a #STONESTEP, findstone
mov.ab #-1, findstone
mod.ab setstone, findstone
add.ab #1, findstone
findstone mod.ab #0, #-1
jmz.b keepstone, findstone
mov.b findstone, a
mov.ab findstone, findstone
mov.ba a, findstone
a jmp.a findstone, 0
;man I wish I had used the following for findstone:
; findstone mod.ab #0, #-1
; mov.x findstone, findstone
; jmn.a findstone, findstone
;then used .b instead of .a below
keepstone slt.ab findstone, #8 ;want at most mod-7
jmp.a keepstone+4,0
slt.ab findstone, #4 ;keep it if mod4-mod7
jmp.a psave2, 0
slt.a #STONEMAX, setstone ;found nothing, work with what we
jmp.a setstone, }setstone ;have
mov.a #7, setstone ;use some small step
psave2 stp.ab setstone, STONESAVE
postsave add.b imp, imp2
mov.a @datptr, build ;build up processes
add.a build, build
mul.ab #2, enough
build slt.ab #0, enough
jmp.a -2, <-300
mov.i imp, IMPOFF
spl.a l_stone, launch1 ;set up gate crashing imps
threeway spl.a launch1, <-190
spl.a launch3, <-150
launch2 spl.a adder2, <-135
jmpto2 jmp.a IMPOFF+4,