Monowire

      The tale of beginners warrior

During the quest of finding a kind of warrior i would be able to create a good warrior with, i hear for more than couple of times a suggestion of creating a oneshot. It took 3 months from the start to get it good enough to make me happy - I entered Koth '94nop-hill as 9th. I had promised to make an article from this oneshots development once i enter koth, so here is the development of Monowire. (Notice: the code shown here near the beginning is not exactly the code of first monowire, but the idea behind is almost the same.)


While starting, i did know that warriors must be formidable and capable of beating different opponents. Oneshots are on basic scanners, that are counterpart to replicators with their tactic of stunning enemy before eliminating them. So oneshot must clear with SPL's, and because opponents should be also defeated, another clear with DAT's should be incorporated. The scan part was easy to deside; for simplicity and size i chose JMZ-scanner:

add #10, 1 
jmz.f -1, 0 
I had no idea how to make the multipass clear though, so i picked up the corewarrior.pdf and started looking for. Pretty much near beginning, on the improvement of Mutagen, there was one described:
 org a1
ptr  dat a1, end+100
a4   dat 0, end+2+1
a3   dat 1, end+2+2
a2   spl #2, end+2+3
a1   spl #3, end+2+4
     mov *ptr1, >ptr1
     mov *ptr1, >ptr1
     mov *ptr1, >ptr1
     djn.f -3, <4000
I combined them and it became something very similiar to this:
org ad
ptr1  dat a1, 0
a4   dat 0, 15
a3   dat 1, 15
a2   spl #2, 15
ad   add #35, 1
     jmz.f -1, #105
     mov.b -1, ptr1
a1   spl #3, 15
     mov.i *ptr1, >ptr1
     mov.i *ptr1, >ptr1
     djn.f -2, <7500
end  dat 0,0
I was shocked to see over 110 point from Wilkies benchmark gotten from the warrior, and with a bit of fixing (the source few lines earlier included fixes.) i got over 130. I though that this might come up something interesting. It beated both stones and scanners, stones because of the coreclears size and scanners because the step allowed to find other big scanners fast. Papers were simply eradicated.
There i knew that still something could be done to improve it, the first improvement was to remove the mov.b -1, ptr1 since it was completely useless. After the modification i noticed that the djn somehow worked against me. I changed it to jmp -2, <-50 The code looked like this afterwards:
org ad
ptr1  dat a1, 105
a4   dat 0, 15
a3   dat 1, 15
a2   spl #2, 15
ad   add #35, ptr1
     jmz.f -1, @ptr1
a1   spl #3, 15
     mov.i *ptr1, >ptr1
     mov.i *ptr1, >ptr1
     jmp -2, <7500
end  dat 0,0
Now it used the start of clear as the scanning address, and got rid of one instruction. Better against scanners. It still had some problems against imps, and i thinked of a way to get even a bit of protection against them. I changed the jmp-line to <-50 if i remember right. Then i noticed that i could use it as a pointer, changing the add line to sub and the jmp to jmp -2, <-35. A small defence against imps.
org ad
ptr1  dat a1, 105
a4   dat 0, 15
a3   dat 1, 15
a2   spl #2, 15
ad   sub.b 5, ptr1
     jmz.f -1, @ptr1
a1   spl #3, 15
     mov.i *ptr1, >ptr1
     mov.i *ptr1, >ptr1
     jmp -2, <-35
end  dat 0,0
It got few points more, nice. The warrior stayed like that for a while, and then i compressed the code a bit by removing one unneeded dat, and played around a bit with numbers to get the bets result. After that i cut'n pasted a q-scan to this warrior, a few point more. Kept getting better and better, and i posted it to Corewars.sourceforge.net Beginner hill. ( To be called cwsf-b after this.) The warrior got 7th place.
org qGo

qf     equ     qKil
qs     equ     200
qd     equ     4000
qi     equ     7
qr     equ     8

qBmb     dat       {qi*qr-10, {1
qGo      seq       qd+qf+qs, qf+qs
         jmp       qSki, {qd+qf+qs+qi+2
         sne       qd+qf+5*qs, qf+5*qs
         seq       qf+4*qs, {qTab
         jmp       qFas, }qTab
         sne       qd+qf+8*qs, qf+8*qs
         seq       qf+7*qs, {qTab-1
         jmp       qFas, {qFas
         sne       qd+qf+10*qs, qf+10*qs
         seq       qf+9*qs, {qTab+1
         jmp       qFas, }qFas
         seq       qd+qf+2*qs, qf+2*qs
         jmp       qFas, {qTab
         seq       qd+qf+6*qs, qf+6*qs
         djn.a     qFas, {qFas
         seq       qd+qf+3*qs, qf+3*qs
         jmp       qFas, {qd+qf+3*qs+qi+2
         sne       qd+qf+14*qs, qf+14*qs
         seq       qf+13*qs, <qTab
         jmp       qSlo, >qTab
         sne       qd+qf+17*qs, qf+17*qs
         seq       qf+16*qs, <qTab-1
         jmp       qSlo, {qSlo
         seq       qd+qf+11*qs, qf+11*qs
         jmp       qSlo, <qTab
         seq       qd+qf+15*qs, qf+15*qs
         djn.b     qSlo, {qSlo
         sne       qd+qf+12*qs, qf+12*qs
         jmz       update, qd+qf+12*qs-qi   
qSlo     mov.ba    qTab, qTab
qFas     mul.ab    qTab, qKil
qSki     sne     qBmb-1, @qKil
         add        #qd, qKil
qLoo     mov.i     qBmb, @qKil
qKil     mov.i     qBmb, *qs
         sub.ab     #qi, qKil
         djn       qLoo, #qr
         jmp     update, <-4000
         dat       5408, 7217
qTab     dat       4804, 6613
dSrc     dat       5810, qBmb-5
for 10
dat 0,0
rof
ptr1    dat    a1,   100
a3      dat     0,    15
a2      spl    #1,    10
update  sub.b   5,  ptr1
scan    jmz    -1, @ptr1
a1      spl    #2,    15
        mov *ptr1, >ptr1
        mov *ptr1, >ptr1 
        jmp    -2,  <-35
for 2
for 9
dat 0,0
rof
for 9
dat 1,1
rof
rof
This is the warrior straight from the cwsf archives, stripped of headers. It is still on the archive by name of Simple oneshot. Eight spot was not quite enough, so still more optimizing was needed. As you can see in the archive, newer "Simple oneshot" got quite a lot closer to the top by 3rd place. Also in the headers you can see "Version 2.0 Misusing professionals advices (Metcalf)". Metcalf suggested that i would use Djn instead of Jmp. I had changed to Jmp instead of Djn for some weird problems, but after some testing turned out that that the problems were gone. The plain change to Djn gave me notable addition to scores. Also, for safety of the program the oneshot was changed on the front of qscan. Cwsf-b had forward-scanning oneshots that would find the huge q-scan and clear forward, until finding the oneshot and killing it, but oneshot on behind of the qscan the was a chance that other scans wouldnt have noticed to oneshot, but they wouldve started their clear on qscan. It was really a jump on the scores, to 3rd place from 8th. Later, after few experiments i had also changed the amount of bombs thrown by the oneshot to 6 insted of 8. It was worth few more points, though not enough to rise me up immediately. I had also sent more warriors later, hoping that they would be better optimized.

They were'nt. By talks with other corewar-people, we came to conclusion that Jmz-scan had come to the end of its road so i had to create a cmp-scanner. "So lets see what i would come up with"
Add.f 3, 1
sne.i 0, -6
Djn -2, <7500
Spl #const, #const..
Now what kind of clear im go-
<Metcalf> Check out Janeck's S774++
<Mizcu> Wha? Huh?
Oh my god, just like the code of what i was thinking of but with a different clear. I though twice on morality of copying code, and since is was still in the beginner-hill; Cut'n'paste. I played around a lot with numbers and the result at last was: (Qscan not included, look at Cwsf archive for full warrior, look at the version with best rank of them.)
const  equ     145

up add.f      3,   1
sc sne.i  const, const-6
   djn.f     -2, <7500
   spl   #const, #const
   mov.i     @2, >sc
   mov.i     @1, >sc
   djn.f     -2, {2
   dat     2500,  7
   spl   #-2500,  8
   
It did a bit better than the Jmz-one. After posting this version, i stopped developing the warrior for a month or so. It bounced in the hill as The Boss, Silk4 and Monowire changed places at Top-3 depending on current structure of other warriors on the hill. At last, it got a Joint 1st with silk4. I though it would be the time to optimize the warrior for Koth-hills.
When the modification started, i asked some questions about what should i do with this code. Grabun told me to scrap the Qscan after the warrior. Points gotten from Wilfiz-benchmark:
Original: 113,67
No Qscan, using a decoymaker: 109,6
Hmm.. what if i scrap the decoymaker and get a good constant instead? I runned MOPT to get a better constant and then i removed te decoymaker. Consted: 112,5 Fizzies
Better. There is a problem though, the constant MOPT gave me was better than it was before, but it was mod-2 and it spreaded very well so there would've been a huge battle of making it not hit any decoys. Then there was a small evaluation: Should i use a decoy or boot away? At last we chose to boot the warrior away from start, that was filled with many lines of trash. With a quick search for good boot distance: Boot: 117,7
With some more number searching i got 120,4. Roy started begging (a bit strong word, maybe) for me to send the version to Koth. I sent a test version; missed by 3 points. Damn. Using Djn to modify the already scanned addresses didnt help. I didnt really know what to do to the numbers, so i used Metcalf's help. He tried for better numbers, and the version was a bit better. I changed the const a bit and returned the djn to its original state: More modification: ~124 Fizzies.
Now this version might be better. I sent it to Koth '94nop - 9th place!
My mission had come to its fullfillment and i got a warrior on koth-hill. Here is the latest version of Monowire:
;redcode-94nop
;name Monowire
;author Miz
;strategy Oneshot
;strategy First Koth-ready version
;assert 1

n equ 5
const equ  24

up add.f      3,   1
sc sne.i  -6833, -6840
   djn.f     -2, <-300
   spl   #const, #const
   mov.i     @2, >sc
   mov.i     @1, >sc
   djn.f     -2, {2
   dat      -20,  7
   spl    #-500,  8

for 12
spl #n*356,>n*653
spl }3653+n,@3566-n
spl >253*n,3656+n
spl #35*n, *n*355
spl <256+n,>64*n-5*n
rof
boot mov <src, <dst
for 8
     mov <src, <dst
rof
src spl @dst, up+9
dst dat #1, -1100+9
end boot