; ------------------------------------------------------------- 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 ret addhla: 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 ret blk: add a,c ld l,a ld a,(hl) or a ret esub: 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 ret pairdist: 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) ret maxnp: 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 dsteps bar1_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 blotoffs shout: 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