zxGammon

features.asm

GNU Backgammon's 25 contact features of a position, in integer arithmetic. Download · All the source

; ------------------------------------------------------------- features; gnubg's 25 contact features of side X against Y (from X's side), each; as a count 0 to 7 (its value in eighths of its range, which is 1 or 2):; computed in integers, the divisions by repeated subtraction as no count; exceeds 7.; half: HL -> X, DE -> Y, IX -> 25 counts.half:        push de        ld de,SIDEX        ld bc,25        ldir        pop hl        ld de,SIDEY        ld bc,25        ldir        ld hl,SIDEX        ld de,BX        call mkblk        ld hl,SIDEY        ld de,BY        call mkblk        ; 0-2: Y's checkers off (gnubg's quirk), in threes: 0, 2, 5, 7        ld hl,SIDEY        call total        neg        add a,15        ld c,a        ld b,3        push ix.off:   ld a,c        bit 7,a        jr z,.o1        xor a.o1:    cp 3        jr c,.o2        ld a,3.o2:    ld hl,MENOFF        call index        ld (ix+0),a        inc ix        ld a,c        sub 3        ld c,a        djnz .off        pop ix        ; Y's rearmost checker, in X's indices        ld hl,SIDEY        call highest        ld (HYI),a        ld b,a        ld a,23        sub b        ld (NOB),a        ; 3, 23: pips beyond it (from it) and before it        ld hl,0        ld (T1),hl        ld (T2),hl        ld c,0.bc:    ld hl,SIDEX        ld a,c        call index        or a        jr z,.bn        ld b,a        ld a,(NOB)        sub c        jr z,.bn        ld hl,T2        jp p,.free        neg        inc a                   ; i + 1 - nob        ld hl,T1        jr .acc.free:  ld a,c        inc a.acc:   call addn.bn:    inc c        ld a,c        cp 25        jr nz,.bc        ld hl,(T1)        ld de,167        call r4        ld (ix+3),a        ld hl,(T2)        ld de,100        call r4        ld (ix+23),a        ; 19: timing        ld a,(NOB)        bit 7,a        jr nz,.m11        cp 11        jr nc,.mok.m11:   ld a,11.mok:   ld (TM),a        ld hl,0        ld (T3),hl        ld a,(SIDEX+24)        ld (T4),a        or a        jr z,.t0        ld b,a        ld a,24        ld hl,T3        call addn.t0:    ld c,6.tl:    ld hl,SIDEX        ld a,c        call index        ld b,a        ld a,(TM)        cp c        ld a,b        jr nc,.all        cp 1        jr z,.all        sub 2        jr nc,.all        xor a.all:   or a        jr z,.tn        ld b,a        ld hl,T4        add a,(hl)        ld (hl),a        ld a,c        ld hl,T3        call addn.tn:    inc c        ld a,c        cp 24        jr nz,.tl        ld c,5.th:    ld hl,SIDEX        ld a,c        call index        cp 2        jr z,.hn        jr c,.fill        sub 2        ld b,a        ld hl,T4        add a,(hl)        ld (hl),a        ld a,c        ld hl,T3        call addn        jr .hn.fill:  neg        add a,2        ld b,a        ld a,(T4)        sub b        jr c,.hn        ld (T4),a        ld a,c        neg        ld hl,T3        call addn.hn:    dec c        jp p,.th        ld hl,(T3)        ld de,100        call r4        ld (ix+19),a        ; 16: the second moment of the checkers above their average point        ld hl,SIDEX        call total        ld (T5),a        ld hl,0        ld (T1),hl        ld c,1.ms:    ld hl,SIDEX        ld a,c        call index        or a        jr z,.mn        ld b,a        ld a,c        ld hl,T1        call addn.mn:    inc c        ld a,c        cp 25        jr nz,.ms        ld a,(T5)        ld e,a        ld d,0        ld b,d        or a        jr z,.avg        ld hl,(T1)        add hl,de        dec hl.dv:    or a        sbc hl,de        jr c,.avg        inc b        jr .dv.avg:   ld hl,0        ld (T2),hl              ; the sum of squares        ld (T7),hl              ; the square        xor a        ld (T5),a               ; checkers above        ld c,b        ld e,1.mo:    inc c        ld a,c        cp 25        jr nc,.md        ld hl,(T7)        ld d,0        add hl,de        ld (T7),hl        inc e        inc e        push de        ld hl,SIDEX        ld a,c        call index        or a        jr z,.mz        ld b,a        ld hl,T5        add a,(hl)        ld (hl),a        ld a,b        ld de,(T7)        call mul        ld de,(T2)        add hl,de        ld (T2),hl.mz:    pop de        jr .mo.md:    ; count k while sum > (100k - 1) x checkers, k up to 7        ld a,(T5)        ld e,a        ld d,0        ld a,100        call mul        push hl        or a        sbc hl,de        ex de,hl        pop bc        ld hl,(T2)        xor a.mk:    push hl        scf        sbc hl,de        pop hl        jr c,.me        ex de,hl        add hl,bc        ex de,hl        inc a        cp 7        jr nz,.mk.me:    ld (ix+16),a        ; 4: the rearmost checker; 5, 6: the rearmost and forward anchors        ld hl,SIDEX        call highest        bit 7,a        jr z,.bk        xor a.bk:    ld l,a        ld h,0        ld de,3        call ratio        ld (ix+4),a        ld hl,BX+23        ld b,24.ba:    ld a,(hl)        or a        jr nz,.bf        dec hl        djnz .ba.bf:    ld a,b        dec a        ld (TA),a        ld l,a        rla        sbc a,a        ld h,a        ld de,3        call ratio        ld (ix+5),a        ld a,(TA)        bit 7,a        jr nz,.low        cp 18        jr c,.low        ld hl,BX+18        ld b,18.fl:    ld a,(hl)        or a        jr nz,.ff        inc hl        inc b        jr .fl.low:   ld hl,BX+17        ld b,17.fh:    ld a,(hl)        or a        jr nz,.ff        dec hl        dec b        ld a,b        cp 11        jr nz,.fh        ld a,7        jr .fw.ff:    ld a,24        sub b        add a,a        ld l,a        ld h,0        ld de,3        call ratio.fw:    ld (ix+6),a        ; 7-9: shots        call shots        ; 10, 24: Y's rearmost checker escaping (past X's first point held)        ld a,(HYI)        cpl        add a,25+low BX        ld c,a        push bc        xor a        call esc        call r8_36        ld (ix+10),a        pop bc        ld a,1        call esc        call r8_36        ld (ix+24),a        ; 11-14: containment, the fewest escapes from Y's points 15 to 24        ld a,(NOB)        ld b,a        ld a,9        sub b        jp p,.pa        xor a.pa:    ld (TP),a        ; the escapes, kept for each half while X's points held are the same        push ix        pop hl        ld a,l        cp low FEAT        ld hl,ECACHE        jr z,.c0        ld hl,ECACHE+34.c0:    push hl        ld de,BX        ld b,24.cc:    ld a,(de)        cp (hl)        jr nz,.miss        inc de        inc hl        djnz .cc        jr .hit.miss:  pop de        push de        ld hl,BX        ld bc,24        ldir        ld c,9+low BX.ce:    push bc        push de        xor a        call esc        pop de        ld (de),a        inc de        pop bc        dec c        ld a,c        cp low BX-1        jr nz,.ce.hit:   pop hl        ld de,24        add hl,de        ld a,36        ld (MINA),a        ld (MINC),a        ld c,0.cl:    ld b,(hl)        inc hl        push hl        ld a,c        ld hl,TP        cp (hl)        jr nc,.na        ld hl,MINA        call minb.na:    ld a,c        cp 9        jr nc,.nc        ld hl,MINC        call minb.nc:    pop hl        inc c        ld a,c        cp 10        jr nz,.cl        ld a,(MINA)        call cont        ld (ix+11),b        ld (ix+12),a        ld a,(MINC)        call cont        ld (ix+13),b        ld (ix+14),a        ; 15: mobility, X's checkers from point 7 up by the rolls escaping Y        ld hl,0        ld (T1),hl        ld c,6.mb:    ld a,c        ld (TI),a        ld hl,SIDEX        call index        or a        jr z,.mbn        ld (TX),a        ld a,24+low BY        sub c        ld c,a        xor a        call esc        ld e,a        ld d,0        ld a,(TX)        call mul        ex de,hl        ld a,(TI)        sub 5        call mul        ld de,(T1)        add hl,de        ld (T1),hl.mbn:   ld a,(TI)        inc a        ld c,a        cp 25        jr nz,.mb        ld hl,(T1)        ld de,900        call ratio        ld (ix+15),a        ; 17: entering from the bar        xor a        ld hl,0        ld d,high BY        ld c,a        ld a,(SIDEX+24)        or a        jr z,.e0.e1:    call yclosed        jr z,.e1o        ld a,c        inc a        add a,a        add a,a        call addhla        ld b,c.e2:    inc b        ld a,b        cp 6        jr nc,.en        push bc        ld c,b        call yclosed        pop bc        jr z,.e2o        ld a,c        add a,b        add a,2        add a,a        call addhla        jr .e2.e2o:   ld a,(SIDEX+24)        cp 2        jr c,.e2        ld a,c        inc a        add a,a        call addhla        jr .e2.e1o:   ld a,(SIDEX+24)        cp 2        jr c,.en        ld b,c.e3:    inc b        ld a,b        cp 6        jr nc,.en        push bc        ld c,b        call yclosed        pop bc        jr z,.e3        ld a,b        inc a        add a,a        call addhla        jr .e3.en:    inc c        ld a,c        cp 6        jr nz,.e1        add hl,hl        add hl,hl        add hl,hl        ld de,294        call ratio.e0:    ld (ix+17),a        ; 18: Y's home points held        ld hl,BY        ld b,6        xor a.e2c:   add a,(hl)        inc hl        djnz .e2c        ld hl,ENTER2        call index        ld (ix+18),a        ; 20: backbone, X's highest point held (not the ace) against the        ; others below it, by distance        ld hl,BX+23        ld b,23.bb:    ld a,(hl)        or a        jr nz,.bbf        dec hl        djnz .bb        xor a        jr .bbo.bbf:   ld c,0        ld e,c        ld a,b        ld (TP),a.bbl:   dec hl        dec b        jr z,.bbe        ld a,(hl)        or a        jr z,.bbl        inc c        push hl        ld a,(TP)        sub b        ld hl,AC        call index        add a,e        ld e,a        pop hl        jr .bbl.bbe:   ld a,c        or a        jr z,.bbo        push de        ld e,c        ld d,0        ld a,11        call mul        pop bc        push hl        ld b,0        or a        sbc hl,bc        add hl,hl        add hl,hl        add hl,hl        pop de        call ratio.bbo:   ld (ix+20),a        ; 21, 22: backgames: checkers back with two anchors or more, or one        ld hl,BX+18        ld b,6        xor a.ga:    add a,(hl)        inc hl        djnz .ga        ld c,a        ld hl,SIDEX+18        ld b,7        xor a.gb:    add a,(hl)        inc hl        djnz .gb        ld b,a        xor a        ld (ix+21),a        ld (ix+22),a        or c        ret z        dec a        jr z,.g1        ld a,b        sub 3        jr nc,.gc        xor a.gc:    cp 8        jr c,.gs        ld a,7.gs:    ld (ix+21),a        ret.g1:    ld a,b        srl a        cp 8        jr c,.g1s        ld a,7.g1s:   ld (ix+22),a        ret; mkblk: DE[i] = 1 where HL[i] >= 2, for i = 0 to 23.mkblk:        ld b,24.l:     ld a,(hl)        inc hl        cp 2        ccf        sbc a,a        and 1        ld (de),a        inc de        djnz .l        ret; addn: the word at HL += A x B (A signed, B >= 1).addn:        ld e,a        rla        sbc a,a        ld d,a        push hl        ld a,(hl)        inc hl        ld h,(hl)        ld l,a.l:     add hl,de        djnz .l        ex de,hl        pop hl        ld (hl),e        inc hl        ld (hl),d        retaddhla:        add a,l        ld l,a        ret nc        inc h        ret; r4: A = ratio(4 HL, DE).r4:     add hl,hl        add hl,hl        jp ratio; r8_36: A = ratio(8 A, 36) = ratio(2 A, 9).r8_36:  ld l,a        ld h,0        add hl,hl        ld de,9        jp ratio; minb: (HL) = min((HL), B).minb:   ld a,(hl)        cp b        ret c        ld (hl),b        ret; cont: A = the fewest escapes -> B = ratio(8a, 36), A = ratio(a^2, 162); for a = 36 - A.cont:   neg        add a,36        push af        call r8_36        ld b,a        pop af        push bc        ld e,a        ld d,0        call mul        ld de,162        call ratio        pop bc        ret; yclosed: NZ if Y holds its point C (0 to 5). HL kept.yclosed:        ld a,low BY        add a,c        ld e,a        ld a,(de)        or a        ret; esc: C = the low byte of &BX[s] or &BY[s], A = 1 for gnubg's Escapes1; -> A = the rolls escaping a checker whose points at distances 1, 2, ...; are s, s + 1, ...: the open sums' rolls, less those whose two die points; are both held.esc:        ld h,high BX        ld e,0        or a        jr z,.go        ld l,c        ld b,12.f:     ld a,(hl)        or a        jr nz,.low        inc l        djnz .f        xor a        ret.low:   ld a,l        sub c        ld e,a                  ; only sums beyond the first point held.go:    ld d,0        ld b,11.s:     ld a,b        cp e        jr z,.pairs        add a,c        ld l,a        ld a,(hl)        or a        jr nz,.sn        ; the sum's rolls: 1 to 6 up to 6, then 5 down to 1        ld a,b        cp 7        jr c,.t        neg        add a,12.t:     add a,d        ld d,a.sn:    djnz .s.pairs: ld b,0.pa:    ld a,b        call blk        jr z,.pan        ld a,b        add a,a        inc a        call esub        ld a,b        ld (ESCA),a        push bc.pb:    dec b        jp m,.pbe        ld a,b        call blk        jr z,.pb        ld a,(ESCA)        add a,b        inc a        call esub        call esub        jr .pb.pbe:   pop bc.pan:   inc b        ld a,b        cp 6        jr nz,.pa        ld a,d        retblk:    add a,c        ld l,a        ld a,(hl)        or a        retesub:   cp e        ret c        ret z        push af        call blk        jr nz,.x        dec d.x:     pop af        ret; ---------------------------------------------------------------- shots; gnubg's I_PIPLOSS, I_P1 and I_P2: X hitting Y's blots, over the 21; rolls, the pips they would lose and the rolls hitting one or two.shots:        ld hl,0        ld (SNP),hl        ld (SN1),hl        ; blots to hit: Y's, up to its point 22 (24 with three home        ; points of X's made), by X's index        ld hl,SIDEX        ld b,6        ld c,0.nb:    ld a,(hl)        or a        jr z,.nb1        inc c.nb1:   inc hl        djnz .nb        ld a,c        cp 3        ld a,23        jr nc,.st        ld a,21.st:    ld (SSTART),a        ld hl,TB        ld c,0        ld d,0.tb:    ld a,23        sub c        ld e,a        ld a,(SSTART)        cp e        ld a,0        jr c,.tbw        push hl        ld hl,SIDEY        ld a,e        call index        pop hl        dec a        ld a,0        jr nz,.tbw        inc a        ld d,a.tbw:   ld (hl),a        inc l        inc c        ld a,c        cp 24        jr nz,.tb        ld a,d        or a        jp z,shout        ; and as a list, highest first        ld de,BLIST        ld hl,TB+23        ld b,24.bl:    ld a,(hl)        or a        jr z,.bn        ld a,b        dec a        ld (de),a        inc de.bn:    dec hl        djnz .bl        ld a,$ff        ld (de),a        ; hitters: X's points but for home points of exactly two; with two        ; or more on the bar, only the bar        ld a,(SIDEX+24)        cp 2        sbc a,a        ld (BARM),a        ld hl,EL        ld de,SIDEX        ld c,0        ld b,0.el:    ld a,(de)        or a        jr z,.elw        ld a,(BARM)        or a        jr nz,.el0        ld a,c        cp 24        ld a,0        jr nz,.elw.el0:   ld a,(de)        cp 2        jr nz,.el1        ld a,c        cp 6        ld a,0        jr c,.elw.el1:   ld a,1        ld b,a.elw:   ld (hl),a        inc l        inc de        inc c        ld a,c        cp 25        jr nz,.el        ld a,b        or a        jp z,shout        ld hl,YB        ld de,BY+23        ld b,24.yb:    ld a,(de)        ld (hl),a        inc l        dec de        djnz .yb        ; direct shots, per die: the highest hitter, and how many        xor a        ld (OFFN),a        ld b,1.dk:    push bc        call find        pop bc        ld h,high DK        ld l,b        set 7,l        set 6,l        ld (hl),a        set 3,l        ld (hl),e        inc b        ld a,b        cp 7        jr nz,.dk        ld a,(SIDEX+24)        or a        ld hl,nob_d        ld de,nob_p        jr z,.go        ld hl,bar1_d        ld de,bar1_p.go:    push de        call eachdie        pop hl        call eachpair        jp shout; eachdie: the handler at HL for each double (RD the die), tallied once.eachdie:        ld (PHAND),hl        ld b,1.l:     push bc        ld a,b        ld (RD),a        call clr        ld hl,.r        push hl        ld hl,(PHAND)        jp (hl).r:     ld c,1        call tally        pop bc        inc b        ld a,b        cp 7        jr nz,.l        ret; eachpair: the handler at HL for each non-double (RD, RD1 the dice, the; offsets set by `dpair`), tallied twice.eachpair:        ld (PHAND),hl        ld hl,PAIRS        ld b,15.l:     push bc        push hl        call dpair        call clr        ld hl,.r        push hl        ld hl,(PHAND)        jp (hl).r:     ld c,2        call tally        pop hl        inc hl        inc hl        pop bc        djnz .l        ret; No checker on the bar: a double's direct shot, then by 2, 3, 4 times.nob_d:        ld a,(RD)        ld b,a        call getdk        cp $ff        jr z,.x        sub b        inc a        ld (RNP),a        ld a,e        ld (RNCH),a.x:     call doffs        ld hl,ind        jp dsteps; A non-double's direct shots (a second checker if another point, or two; there), then the indirect one.nob_p:        ld a,(RD)        ld b,a        call getdk        ld (RK0),a        ld c,0        ld d,c        cp $ff        jr z,.n0        sub b        inc a        ld d,a        inc c.n0:    ld a,(RD1)        ld b,a        call getdk        cp $ff        jr z,.n1        ld e,a        ld a,(RK0)        cp e        jr nz,.inc        ld a,e        ld hl,BX        call index        or a        jr z,.nop.inc:   inc c.nop:   ld a,e        sub b        inc a        cp d        jr c,.n1        ld d,a.n1:    ld a,c        ld (RNCH),a        ld a,d        ld (RNP),a        call pairdist        jp ind; The pair of dice at HL: RD, RD1, and as the offsets, either open.dpair:        ld a,(hl)        ld (RD),a        ld (OFFS),a        inc hl        ld a,(hl)        ld (RD1),a        ld (OFFS+1),a        ld a,2        ld (OFFN),a        ld a,1        ld (OFFANY),a        retpairdist:        ld a,(RD)        ld b,a        ld a,(RD1)        add a,b        ld b,a        ret; doffs: the offsets d, 2d, 3d of die RD, all to be open.doffs:        ld a,(RD)        ld b,a        ld (OFFS),a        add a,b        ld (OFFS+1),a        add a,b        ld (OFFS+2),a        xor a        ld (OFFANY),a        ret; dsteps: a double's shots by 2, 3 and 4 times its die, each by the; routine at HL.dsteps:        ld (DHAND),hl        ld c,1.s:     ld a,c        ld (OFFN),a        push bc        ld a,(RD)        ld b,a        xor a.m:     add a,b        dec c        jp p,.m        ld b,a        ld hl,.r        push hl        ld hl,(DHAND)        jp (hl).r:     pop bc        inc c        ld a,c        cp 4        jr nz,.s        ret; getdk: B = a die -> A = its highest direct hitter ($ff: none), E = how; many (1, 2). Keeps B, C, D.getdk:        ld h,high DK        ld a,b        or $c8        ld l,a        ld e,(hl)        res 3,l        ld a,(hl)        ret; find: B = a distance -> A = the highest hitter that far from a blot,; the points between passing the offsets' test, or $ff; E = how many; (up to 2).find:        ld e,0        ld d,$ff        ld hl,BLIST.l:     ld a,(hl)        inc hl        cp $ff        jr z,.done        ld c,a        push hl        add a,b        add a,low EL        ld l,a        ld h,high EL        ld a,(hl)        or a        jr z,.n        call open        jr z,.n        inc e        ld a,d        inc a        jr nz,.two        ld a,c        add a,b        ld d,a.n:     pop hl        jr .l.two:   pop hl.done:  ld a,d        ret; open: C = a blot's index: NZ if the points at the offsets from it are; open, all of them or (OFFANY) any. Keeps B, C, D, E.open:        ld a,(OFFN)        or a        jr z,.yes        push bc        ld b,a        ld hl,OFFS.o:     ld a,(hl)        add a,c        add a,low YB        push hl        ld l,a        ld h,high YB        ld a,(hl)        pop hl        or a        ld a,(OFFANY)        jr z,.op        or a        jr z,.no        jr .nx.op:    or a        jr nz,.yes2.nx:    inc hl        djnz .o        ld a,(OFFANY)        or a        jr z,.yes2.no:    pop bc        xor a        ret.yes2:  pop bc.yes:   or 1        ret; ind: B = a distance: the indirect shot that far.ind:        push bc        call find        pop bc        cp $ff        ret z        ld c,a        call one        ld a,c        sub b        inc a        call maxnp        ld a,c        cp 24        ret nc        ld a,23        sub c        ld c,a; blotoffs: RNCH += 1 if Y has a blot at C plus an offset.blotoffs:        ld a,(OFFN)        ld b,a        ld de,OFFS.b:     ld a,(de)        add a,c        ld hl,SIDEY        call index        dec a        jr z,.hit        inc de        djnz .b        ret.hit:   ld hl,RNCH        inc (hl)        ret; one: RNCH = max(RNCH, 1).one:    ld hl,RNCH        ld a,(hl)        or a        ret nz        inc (hl)        retmaxnp:  ld hl,RNP        cp (hl)        ret c        ld (hl),a        ret; tally: C = the roll's weight: its pips, and whether it hits one or two.tally:        ld b,c.t:     ld a,(RNP)        ld hl,(SNP)        call addhla        ld (SNP),hl        ld hl,SN1        ld a,(RNCH)        or a        jr z,.n        inc (hl)        dec a        jr z,.n        inc hl        inc (hl).n:     djnz .t        ret; A checker on the bar: it hits entering, or (only one on the bar) enters; and another hits.bar1_d:        ld a,(RD)        ld b,a        add a,a        ld c,a        call process        call barm        call doffs        ld hl,fbar        jp dstepsbar1_p:        ld a,(RD)        ld b,a        ld a,(RD1)        ld c,a        call process        ld a,(RD1)        ld b,a        ld a,(RD)        ld c,a        call process        call barm        call pairdist        jp fbar; barm: with more than one on the bar, no indirect shots: out of the; caller.barm:   ld a,(BARM)        or a        ret nz        pop hl        ret; clr: a roll's tallies cleared; A = RD.clr:    xor a        ld (RNCH),a        ld (RNP),a        ld (RNEED),a        ld a,(RD)        ret; process: B = a die, C = the die the bar checker enters with first:; direct shots with B, from the bar or (once) from the board.process:        ld hl,BLIST.k:     ld a,(hl)        inc hl        cp $ff        ret z        add a,b        ld e,a                  ; the hitter's point        push hl        add a,low EL        ld l,a        ld h,high EL        ld a,(hl)        or a        jr z,.n        ld a,e        cp 24        jr z,.c        ld a,(RNEED)        or a        jr nz,.x        ld a,c        dec a        ld hl,SIDEY        call index        cp 2        jr nc,.x        ld a,1        ld (RNEED),a.c:     ld hl,RNCH        inc (hl)        ld a,e        sub b        inc a        call maxnp.n:     pop hl        jr .k.x:     pop hl        ret; fbar: B = a distance: the bar checker's indirect shot that far.fbar:        push bc        call find        pop bc        cp 24        ret nz        call one        ld a,25        sub b        call maxnp        ld c,1        jp blotoffsshout:        ld hl,(SNP)        ld de,432        call r4        ld (ix+7),a        ld a,(SN1)        call r8_36        ld (ix+8),a        ld a,(SN2)        call r8_36        ld (ix+9),a        ret