zxGammon

choose.asm

Choosing a move: the filter, the contact (or race) net, and a look a ply ahead over the opponent's 21 rolls; and the same look ahead for the cube. Download · All the source

; --------------------------------------------------------------- choose; decide: the play from ROOT with dice DHI >= DLO -> RESULT, and A = 0; if there is none (RESULT = ROOT).;; The filter keeps the best 12 plays, the contact net (or the race net); the best 2 of those; for each, over the opponent's 21 rolls, their; reply is chosen by the filter (best 5) and the reply net (or race), and; the position after it scored by the contact (or race) net. A play; bearing off the last checker is taken at once.;; Plays are kept in lists, best first: a count, a capacity, and from +16,; 16 bytes each: a key of 5 (the score from the opponent's side, lower; better, then the place in generation order, big-endian) and the play's; steps (4 points, $ff after the last, and their 4 dice).decide:        di        ld hl,ROOT        ld de,RESULT        call copy64        ld hl,ROOT        ld de,TOP12        call plays        ret z        ld de,WINSTEPS        ld a,(WIN)        or a        jr nz,.done        dec hl        ld a,h        or l        ld de,TOP12+21        jr z,.done        ; the best 12 to the best 2, from the opponent's side        ld hl,ROOT        ld de,PA        call turn        call setbase        ld hl,TOP12        ld de,TOP2        ld bc,s_last        call restage        ; each against the opponent's rolls        ld de,TOP2+21        call look        ld hl,TOTAL        ld de,BEST        ld bc,4        ldir        ld de,TOP2+37        call look        ld hl,(BEST)        ld de,(TOTAL)        or a        sbc hl,de        ld hl,(BEST+2)        ld de,(TOTAL+2)        sbc hl,de        ld de,TOP2+21        jp p,.done        ld de,TOP2+37.done:  call fromroot        ld hl,W        ld de,RESULT        call copy64        ld a,1        ret; look: DE -> a candidate play's steps: TOTAL = the sum over the; opponent's rolls (non-doubles twice) of its value after their reply.look:        call fromroot; lookw: the same for the position in W.lookw:        ld hl,W        ld de,CAND        call copy64        ld hl,CAND        ld de,PA        call copy64        call setbase        ld hl,CAND        ld de,ROOT2        call turn        ld hl,0        ld (TOTAL),hl        ld (TOTAL+2),hl        inc l        ld h,l.roll:  ld (RA),hl        call TICK               ; the caller's, each roll (any registers)        call reply        call addtot        ld hl,(RA)        ld a,l        cp h        call nz,addtot        ld hl,(RA)        ld a,h        cp l        inc h        jr c,.roll        ld h,1        inc l        ld a,l        cp 7        jr c,.roll        ret; ply1: the side on roll's equity in ROOT a ply deeper, for the cube:; over its 21 rolls, its play chosen by the filter and the reply net and; the position after scored by the contact (or race) net, as `look` scores; a candidate against the replies. RES = the mean, rounded toward 0.ply1:        di        ld hl,ROOT        ld de,W        call turn        call lookw        ; RES = -TOTAL / 36 (TOTAL is within 24 bits)        ld hl,(TOTAL)        ld a,(TOTAL+2)        ld c,a        ld a,(TOTAL+3)        or a        push af        call m,neg24            ; |TOTAL|        xor a        ld b,24.d:     add hl,hl        rl c        rla        cp 36        jr c,.n        sub 36        inc l.n:     djnz .d        pop af        call p,neg24            ; TOTAL is the other side's: ours negated        ld (RES),hl        ld a,c        ld (RES+2),a        ret; ply1c: ply1 with the side on roll's plays chosen by the contact (or; race) net rather than the reply net: better, and slower.ply1c:  ld a,1        ld (PLYBY),a        call ply1        xor a        ld (PLYBY),a        ret; neg24: CHL = -CHL.neg24:  xor a        sub l        ld l,a        ld a,0        sbc a,h        ld h,a        ld a,0        sbc a,c        ld c,a        ret; reply: RES = the value to us (CAND) of the opponent's roll RA, RB.reply:        ld hl,(RA)        ld (DHI),hl        ld hl,ROOT2        ld de,TOP5        call plays        jr nz,.some        ; they cannot move: our position as it is        ld hl,CAND        ld de,PA        call copy64        jp s_last.some:  ld a,(WIN)        or a        jr z,.pick        ; they bear off their last checker: 1, 2 or 3 points to them        ld hl,WINSTEPS        call replay        ld hl,W+OPPOFF        call total        cp 15        ld b,$e0        jr nz,.pts        ld hl,W+OPPOFF+18        ld b,7        xor a.bk:    or (hl)        inc hl        djnz .bk        ld b,$a0        jr nz,.pts        ld b,$c0.pts:   ld hl,RES        ld (hl),0        inc hl        ld (hl),b        inc hl        ld (hl),$ff        ret.pick:  dec hl        ld a,h        or l        ld hl,TOP5+21        jr z,.one        ld hl,TOP5        ld de,TOP1        ld bc,s_reply        ld a,(PLYBY)        or a        jr z,.by        ld bc,s_last.by:    call restage        ld hl,TOP1+21.one:   call replay        call fromopp        jp s_last; plays: HL -> a board, DE -> a list: its plays, scored by the filter; from the other side, the best in the list. HL = GCOUNT, Z if none. The; filter scores the board turned; the move generator adds each step's; change to that.plays:        ld (CURLIST),de        xor a        ld (de),a        ld (WIN),a        push hl        call total        sub 5        sbc a,a        ld (WINPOSS),a        pop hl        push hl        ld de,PA        call turn        ld ix,NET_FILTER        call eval        ld hl,(RES)        ld (FSCORE),hl        ld hl,leafs        ld (USERFN),hl        pop hl        call gen        ld hl,(GCOUNT)        ld a,h        or l        ret; restage: HL -> a list, DE -> another, BC -> a scorer: the first's plays; scored from the other side, the best in the second.restage:        ld (SCORER),bc        ld (CURLIST),de        xor a        ld (de),a        ld b,(hl)        ld de,16        add hl,de.e:     push bc        push hl        push hl        ld de,5        add hl,de        call replay        call fromopp        ld hl,.r        push hl        ld hl,(SCORER)        jp (hl).r:     pop hl        push hl        ld de,5        add hl,de        ld de,NEWSTEPS        ld bc,8        ldir        pop hl        inc hl        inc hl        inc hl        ld d,(hl)        inc hl        ld e,(hl)        ld (CURIDX),de        call mkkey        call linsert        pop hl        ld de,16        add hl,de        pop bc        djnz .e        ret; addtot: TOTAL += RES.addtot:        ld a,(RES+2)        rla        sbc a,a        ld c,a        ld hl,RES        ld de,TOTAL        ld b,3        or a.l:     ld a,(de)        adc a,(hl)        ld (de),a        inc hl        inc de        djnz .l        ld a,(de)        adc a,c        ld (de),a        ret; leafs: a generated play: taken at once if it bears off the last; checker, else into the list by its filter score.leafs:        ld a,(WIN)        or a        ret nz        ld a,(WINPOSS)        or a        jr z,.nowin        ld hl,W        call total        or a        jr nz,.nowin        inc a        ld (WIN),a        call mksteps        ld hl,NEWSTEPS        ld de,WINSTEPS        ld bc,8        ldir        ret.nowin: ld hl,(FSCORE)        ld (RES),hl        ld a,h        rla        sbc a,a        ld (RES+2),a        ld hl,(GCOUNT)        ld (CURIDX),hl        call mkkey        ; a full list: no better than its last, no further        ld iy,(CURLIST)        ld a,(iy+0)        cp (iy+1)        jr c,.in        ld l,a        ld h,0        add hl,hl        add hl,hl        add hl,hl        add hl,hl        ld de,(CURLIST)        add hl,de        ld de,NEWKEY        ld b,3.q:     ld a,(de)        cp (hl)        jr c,.in        ret nz        inc hl        inc de        djnz .q        ret.in:    call mksteps        jr linsert; mksteps: NEWSTEPS = the play's steps, $ff for those not taken, and; their dice.mksteps:        ld hl,NEWSTEPS        ld b,4.c:     ld (hl),$ff        inc hl        djnz .c        ld a,(GTARGET)        ld b,a        ld de,STEPS        ld hl,NEWSTEPS.s:     ld a,(de)        ld (hl),a        inc e        inc e        inc hl        djnz .s        ld hl,GDIE        ld de,NEWSTEPS+4        ld bc,4        ldir        ret; linsert: NEWKEY and NEWSTEPS into the list at CURLIST, in their place; if among the best.linsert:        ld iy,(CURLIST)        push iy        pop hl        ld de,16        add hl,de        ld b,0.f:     ld a,b        cp (iy+0)        jr z,.at        push hl        ld de,NEWKEY        ld c,5.cmp:   ld a,(de)        cp (hl)        jr c,.lt        jr nz,.gt        inc hl        inc de        dec c        jr nz,.cmp.gt:    pop hl        ld de,16        add hl,de        inc b        jr .f.lt:    pop hl.at:    ld a,b        cp (iy+1)        ret nc        push hl        ld a,(iy+0)        cp (iy+1)        jr c,.room        dec a                   ; full: the last falls off        jr .mv.room:  inc (iy+0).mv:    sub b                   ; entries to move down        jr z,.put        ld l,a        ld h,0        add hl,hl        add hl,hl        add hl,hl        add hl,hl        ld b,h        ld c,l        pop hl        push hl        add hl,bc        dec hl        ld d,h        ld e,l        ld a,16        call addea        lddr.put:   pop de        ld hl,NEWKEY        ld bc,13        ldir        ret; mkkey: NEWKEY from RES and CURIDX.mkkey:        ld hl,NEWKEY        ld a,(RES+2)        xor $80        ld (hl),a        inc hl        ld a,(RES+1)        ld (hl),a        inc hl        ld a,(RES)        ld (hl),a        inc hl        ld de,(CURIDX)        ld (hl),d        inc hl        ld (hl),e        retaddea:  add a,e        ld e,a        ret nc        inc d        ret; fromroot: DE -> a play's steps: W = ROOT after it.fromroot:        ld hl,ROOT        ld (GROOT),hl        ex de,hl; replay: HL -> a play's steps: W = the board at GROOT after it.replay:        push hl        ld hl,(GROOT)        ld de,W        call copy64        pop hl        ld b,4.s:     ld a,(hl)        cp $ff        ret z        push bc        push hl        ld b,a        ld de,4        add hl,de        ld e,(hl)        call step        pop hl        pop bc        inc hl        djnz .s        ret; fromopp: PA/PB = W from the other side.fromopp:        ld hl,W        ld de,PA; turn: HL -> a board, DE -> 64 bytes: the board from the other side.turn:   push hl        ld bc,OPPOFF        add hl,bc        ld c,32        ldir        pop hl        ld c,32        ldir        retcopy64: ld bc,64        ldir        ret; The scores of PA/PB, into RES: the contact net, or the race net; the; reply net, or the race net.s_last:        call contact        jr nc,s_race        ld ix,NET_CONTACT        jp evals_race:        ld ix,NET_RACE        jp evals_reply:        call contact        jr nc,s_race        ld ix,NET_REPLY        jp eval; setbase: PA/PB as the nets' base (the contact net's only in contact).setbase:        ld ix,NET_RACE        call rebase        ld ix,NET_REPLY        call rebase        call contact        ret nc        ld ix,NET_CONTACT        jp rebase; init: the work area cleared, the hash values made, the lists' sizes,; and the nets' bases set to no inputs at all.init:        ld hl,WORK        ld de,WORK+1        ld bc,WORKEND-WORK-1        ld (hl),0        ldir        ld hl,1        ld de,RTAB        ld b,102.r:     ld a,h        rra        ld a,l        rra        xor h        ld h,a        ld a,l        rra        ld a,h        rra        xor l        ld l,a        xor h        ld h,a        ex de,hl        ld (hl),e        inc hl        ld (hl),d        inc hl        ex de,hl        djnz .r        ld a,$ff        ld (ECACHE),a        ld (ECACHE+34),a        ld hl,TOP12+1        ld (hl),12        inc h        ld (hl),2        inc h        ld (hl),5        inc h        ld (hl),1        ld hl,NETS        ld b,4.n:     push bc        ld e,(hl)        inc hl        ld d,(hl)        inc hl        push hl        push de        pop ix        ld l,(ix+6)        ld h,(ix+7)        ld d,(ix+14)        ld e,BSUMS        ld c,(ix+0)        ld b,0        sla c        ldir        ld e,BBUCK        ld a,$ff        ld (de),a        pop hl        pop bc        djnz .n        ret