
|
'88 Quickscanner: '94 Quickscanner: Description The Q^1-Scan The Q^2-Scan (I) The Q^2-Scan (II) The Q^2-Scan (III) The Q^3 and Mini-Q^3 The Q^4 and Q^4.5 Qscanner for Tiny Hill Qscanner for Nano Hill Webmaster: fizmo_master@yahoo.com Created by Christian Schmidt, 2002,2003,2004 |
The Q^2 Quickscanner (Part II) To decide, how good a quickscanner is, you should fight against a benchmark with all possible positions. Using the the usual settings there are 15602 possible (pmars -P). That would take a lot of time. That is why I'll use the Tiny Hill settings (coresize: 800, max. cycles: 8000, max. length: 20, max. process: 20). Later I'll show, that there are quite good other methods. Let's take the following enemy:
;redcode-tiny
;name Sitting Duck
;assert CORESIZE == 800
ORG start
start nop # 10, # 11
for 18
nop # 10, # 11
rof
jmp start
END
Sitting Duck has a length of 20 instructions, doesn't change the core,
i.e. places no decoys, bombs, ... and can be killed with one simple
dat-bomb.Now the hero of this part:
;redcode-tiny
;name Killer
;assert CORESIZE == 800
ORG wait
wait jmp 0
for 19
dat.f 0, 0
rof
END
A fight between these two warrior should alway tie. A "pmars -s 800
-c 8000 -l 20 -d 20 -S 20 -b -P Killer.red SittingDuck.red" results in
1522 ties. But why 1522? The size of the core is 800, 760 without our
two warriors. That's why there are (760 + 1) different positions of
your two warriors. Apart from that you have to decide, who starts and
that make 761*2 = 1522.Now we start changing our hero:
...
ORG start
target EQU 20
start mov.i bomb, target
wait jmp 0
bomb dat.f 0, 0
for 17
dat.f 0, 0
rof
END
Now it hits the first possible enemy position with a bomb. Now Killer
wins 2 fights and 1520 ties, because if "Sitting Duck" is at position
20 it is killed regardless of who has executed the first instruction.Using "target EQU 21" results in 4 wins and 1518 ties. If "Sitting Duck" is at position 20 or 21 it gets killed. Using "target EQU 22" results in 6 wins, ..., using "target EQU 25" results in 12 wins, ..., using "target EQU 38" results in 38 wins, using "target EQU 39" results in 40 wins. From now on the value of wins will no longer increase :-( Using "target EQU 781" we have 38 wins and the number of wins starts to decrease. What did we learn? We get the best killing rate, if we throw our bomb somewhere between position 39 and 780. Since "Sittind Duck" dies on being hit by a bomb, we maximize the possibility of finding (!) our enemy with one scan, if the scans somewhere between position 39 and 780.
s - coresize
d - minimal distance between the first instructions of the warriors
L - maximal length of a warrior
v - number of non-"dat 0, 0"-instruction of the enemy warrior (v <= L)
(from now on: number of visible instructions)
Let's assume, that d = L (standard setting), the initial position of
our warrior is randomly chosen from all possible positions, the visible
instructions are equally distributed inside the enemy warrior. Note,
that the last assumption is NOT true for normal warriors :-( All
positions are our from now on relative from the first instruction of our
warrior. Apart from that, let's assume, that the enemy uses the
maximal possible length.Then there are (s-2*d+1) different positions of the enemy warrior. We have seen, that our chances of finding a warrior are suboptimal, if we scan the first (d-1) or the last (d-1) positions. For scan positions sPos with d <= sPos <= 2*(d-1) the probability of finding the enemy is
(sPos - d + 1)/(s - 2 * d + 1) * v/L
v/L is the possibility of finding a visible instruction, IFF (if and
only if) the scan position is already inside (!) the enemy warrior.
Let's call that value "visibility" from now on. (sPos - d + 1) is the
number of scan positions, where we are inside the warrior. That is why
the probability of beeing inside the warrior is
(sPos - d + 1)/(s - 2 * d + 1).
For scan positions sPos with -d + 1 <= sPos <= -1 the probability of
finding the enemy is
(|sPos|)/(s - 2 * d + 1) * v/L
For all other scan positions, i.e. 2*(d-1) < sPos < -d + 1, the
probability of finding the enemy is
L/(s - 2 * d + 1) * v/L = v/(s - 2 * d + 1)
Now we now, where to place the first scan position, but what happens, if
the first scan misses?Let sPos1 be the first scanned position. Then the enemy must be somewhere between (sPos1 + L) and -1. Using the same arguments as in chapter 2, we should scan only the most probable positions, i.e. a position between (sPos1 + d) and (-d + 1). And now for the bad news. We cannot execute enough scans to cover the complete space between (s + 2 * d - 1) and (-d + 1), because there are practical limitations. We have already seen, that making our quickscanner big is a bad idea. For example there 7700 "high-value" position, when using the standard settings. Each scans covers a range of 100 instructions (best case). Then we would need 7700/100 = 77 scans, i.e. about 38 "double-scans" with seq or sne. But we have already seen, that 38 "double-scans" make our warrior to vulnerable to the opponent's scans :-( We can only space our scans among the "high-value" positions.
100/7801 * v/L = 0.0128 * v/L
In a tiny core it is:
20/761 * v/L = 0.0263 * v/L
In a nano core it is:
5/71 * v/L = 0.0704 * v/L
In an experimental core it is:
200/55041 = 0.0036 * v/L
It seems, that a quickscanner can find the opponent far more better
in nano-cores than in normal cores.Apart from that, it is also very probable, that the enemy is inside a radius of L instructions, but hitting an instruction, that is about L instructions away, has a very low chance of killing the enemy. Hitting instructions near to the found instruction has the highest probability of killing the enemy. The further away we hit, the worse the chances of success become.
;redcode-94nop verbose
;name NYAP (Not YAP)
;assert CORESIZE == 8000
ORG qGo
;;
;; quickscanner
;;
start EQU qGo ; first instruction of warrior
qStart EQU (start + 200) ; first scanned position
qSpace EQU 7700 ; space to cover with quickscan
qNum EQU 18 ; number of scans
qStep EQU (qSpace/qNum) ; distance between two scans
qHop EQU (qStep/2) ; distance between two scan positions
qGo sne.i qStart+0*qStep+0*qHop, qStart+0*qStep+1*qHop
seq.i qStart+0*qStep+2*qHop, qStart+0*qStep+3*qHop
jmp attack1, 0
sne.i qStart+2*qStep+0*qHop, qStart+2*qStep+1*qHop
seq.i qStart+2*qStep+2*qHop, qStart+2*qStep+3*qHop
jmp attack1, { attack1
sne.i qStart+4*qStep+0*qHop, qStart+4*qStep+1*qHop
seq.i qStart+4*qStep+2*qHop, qStart+4*qStep+3*qHop
jmp attack1, } attack1
sne.i qStart+6*qStep+0*qHop, qStart+6*qStep+1*qHop
seq.i qStart+6*qStep+2*qHop, qStart+6*qStep+3*qHop
jmp attack1, > attack1
sne.i qStart+8*qStep+0*qHop, qStart+8*qStep+1*qHop
seq.i qStart+8*qStep+2*qHop, qStart+8*qStep+3*qHop
jmp attack1, < attack1
sne.i qStart+10*qStep+0*qHop, qStart+10*qStep+1*qHop
seq.i qStart+10*qStep+2*qHop, qStart+10*qStep+3*qHop
djn.f attack1, attack1
sne.i qStart+12*qStep+0*qHop, qStart+12*qStep+1*qHop
seq.i qStart+12*qStep+2*qHop, qStart+12*qStep+3*qHop
jmp attack2, 0
sne.i qStart+14*qStep+0*qHop, qStart+14*qStep+1*qHop
seq.i qStart+14*qStep+2*qHop, qStart+14*qStep+3*qHop
jmp attack2, { attack1
sne.i qStart+16*qStep+0*qHop, qStart+16*qStep+1*qHop
seq.i qStart+16*qStep+2*qHop, qStart+16*qStep+3*qHop
jmp attack2, } attack1
jmp boot
;; choose target
qTimes EQU 20 ; number of bombs to throw
bDist EQU 80 ; target range
qStep2 EQU (bDist/qTimes + 1)
dat.f 2*qStep, qStart+8*qStep-found
qTab dat.f 0*qStep, qStart+0*qStep-found
dat.f 4*qStep, qStart+6*qStep-found
attack2 add.ab # 12*qStep, found
attack1 add.ab qTab, qTab
found add.b @ attack1, # 0
;; choose between the four possible positions
find seq.i (start - 1), @ found
jmp adjust
add.ab # qHop, found
djn find, # 4
adjust add.ab # (bDist/2), found ; start with bombing from above
;; bombing engine I
throw mov.i qBomb, @ found
sub.ab # qStep2, found
djn throw, # qTimes
jmp boot
qBomb dat.f # 1, # 1
;;
;; waiting to die ;-)
;;
for 55
dat.f 0, 0
rof
boot jmp 0
END
How to benchmark it? The quickscan doesn't take long. Let's say, that
3000 cycles are enough, i.e. we use "pmars -c 3000 -b -P". (I've tested
it with 500, 1000, 2000, 3000 and 4000 cycles. After about 3000 cycles
the number of wins doesn't increase that much any more.)Against Wilkies (quite old warriors) we win in about 4.61052% of all cases, against WilFiz (still quite old warriors ;-) we win in about 3.02467% of all cases. Let's see how to improve these values. Increasing the target range from 80 to 100 instructions (bDist), while using the same number of bombs, results in lower scores against Wilkies (4.399% wins) and WilFiz (2.677% wins). Let's try this variation:
...
adjust sub.ab # (bDist/2), found ; start with bombing from above
;; bombing engine II
throw mov.i qBomb, @ found
add.ab # qStep2, found
djn throw, # qTimes
jmp boot
...
Now we bomb from below the scanned position. Using the old values
(qTimes EQU 20, bDist EQU 80) we have 3.50% wins against Wilkies
and 2.33% wins against WilFiz. Bad idea!We already know, that we should hit the instruction we have found and all instructions near it. Let's bomb forwards and backwards:
...
;; choose between the four possible positions
find seq.i (start - 1), @ found
jmp adjust
add.ab # qHop, found
djn find, # 4
;; bombing engine III
adjust mov.ba found, found
throw mov.i qBomb, @ found
mov.i qBomb, { found
add.f qBomb, found
djn.b throw, # 20
jmp boot
qBomb dat.f # -3, # 4
...
With this engine, we have 4.56565% wins against Wilkies (quite
as good as engine I) and 6.88606% wins against WilFiz :-)And another engine (Tornado?):
...
attack2 add.ab # 12*qStep, found
attack1 add.ab qTab, qTab
add.b @ attack1, found ; <--- CHANGED!
;; choose between the four possible positions
find seq.i (start - 1), @ found
jmp adjust
add.ab # qHop, found
djn find, # 4
;; bombing engine IV
qTimes EQU 20 ; number of bombs to throw
qStep2 EQU 4
adjust add.ba found, found
throw mov.i qBomb, @ found
mov.i qBomb, * found
found mov.i -qStep2, @ found
add.f incr, found
djn.b throw, # 20
jmp boot
qBomb dat.f # 0, # qStep2
incr dat.f # -qStep2, # 2*qStep2
...
Now we have 4.94274% wins against Wilkies and 7.14943% wins
against WilFiz. Yay!
;redcode-94nop verbose
;name Yet Another Paper II
;author Jens Gutzeit
;strategy q^2 -> paper
;strategy Better quickscan and bombing engine
;assert CORESIZE == 8000
ORG qGo
pStep1 EQU 3913
pStep2 EQU 3035
boot spl 1
spl 1
silk1 spl @ silk1, < pStep1
mov.i } silk1, > silk1
mov.i { silk1, < silk2
silk2 djn.f @ silk2, < pStep2
;;
;; quickscanner
;;
start EQU boot ; first instruction of warrior
qStart EQU (start + 200) ; first scanned position
qSpace EQU 7700 ; space to cover with quickscan
qNum EQU 18 ; number of scans
qStep EQU (qSpace/qNum) ; distance between two scans
qHop EQU (qStep/2) ; distance between two scan positions
for 47
dat.f 0, 0
rof
qGo sne.i qStart+0*qStep+0*qHop, qStart+0*qStep+1*qHop
seq.i qStart+0*qStep+2*qHop, qStart+0*qStep+3*qHop
jmp attack1, 0
sne.i qStart+2*qStep+0*qHop, qStart+2*qStep+1*qHop
seq.i qStart+2*qStep+2*qHop, qStart+2*qStep+3*qHop
jmp attack1, { attack1
sne.i qStart+4*qStep+0*qHop, qStart+4*qStep+1*qHop
seq.i qStart+4*qStep+2*qHop, qStart+4*qStep+3*qHop
jmp attack1, } attack1
sne.i qStart+6*qStep+0*qHop, qStart+6*qStep+1*qHop
seq.i qStart+6*qStep+2*qHop, qStart+6*qStep+3*qHop
jmp attack1, > attack1
sne.i qStart+8*qStep+0*qHop, qStart+8*qStep+1*qHop
seq.i qStart+8*qStep+2*qHop, qStart+8*qStep+3*qHop
jmp attack1, < attack1
sne.i qStart+10*qStep+0*qHop, qStart+10*qStep+1*qHop
seq.i qStart+10*qStep+2*qHop, qStart+10*qStep+3*qHop
djn.f attack1, attack1
sne.i qStart+12*qStep+0*qHop, qStart+12*qStep+1*qHop
seq.i qStart+12*qStep+2*qHop, qStart+12*qStep+3*qHop
jmp attack2, 0
sne.i qStart+14*qStep+0*qHop, qStart+14*qStep+1*qHop
seq.i qStart+14*qStep+2*qHop, qStart+14*qStep+3*qHop
jmp attack2, { attack1
sne.i qStart+16*qStep+0*qHop, qStart+16*qStep+1*qHop
seq.i qStart+16*qStep+2*qHop, qStart+16*qStep+3*qHop
jmp attack2, } attack1
jmp boot
;; choose target
dat.f 2*qStep, qStart+8*qStep-found
qTab dat.f 0*qStep, qStart+0*qStep-found
dat.f 4*qStep, qStart+6*qStep-found
attack2 add.ab # 12*qStep, found
attack1 add.ab qTab, qTab
add.b @ attack1, found
;; choose between the four possible positions
find seq.i (start - 1), @ found
jmp adjust
add.ab # qHop, found
djn find, # 4
;; bombing engine IV
qTimes EQU 20 ; number of bombs to throw
qStep2 EQU 4
adjust add.ba found, found
throw mov.i qBomb, @ found
mov.i qBomb, * found
found mov.i -qStep2, @ found
add.f incr, found
djn.b throw, # 20
jmp boot
qBomb dat.f # 0, # qStep2
incr dat.f # -qStep2, # 2*qStep2
END
This version scores 129.52 (W 27.00%, T 48.53%, L 24.47%) against
Wilkies and 118.53 (W 22.75%, T 50.28%, L 26.97%) against WilFiz. |