zxGammon

net.asm

The neural networks, computed without multiplication: only the inputs that change are added. Download · All the source

; ------------------------------------------------------------------ net; A net scores PA (on roll) against PB from a base position whose; first-layer sums it keeps: only the inputs that differ are added.;; The inputs, as counts: per side and point, one checker, two or more,; three or more and the number beyond three, then the checkers off (202);; the pip lead in buckets of 8 (9); each side's checkers back, 1 to 4 or; more (8); and gnubg's features for each side (50). A net takes the; first 202, 219 or 269.;; The first layer's weights are stored plus 128, as bytes 0 to 255, a row; of H per input; an input counted k more times adds its row k times, and; the 128s come off at the end.;; A net: +0 H, +1 1 if linear, +2 inputs (2), +4 the rows (2), +6 the; biases (2), +8 the output weights (2), +10 the output bias (3), +13 its; base (2), a page:BPOS    equ 0           ; the base position (64)BOFF    equ 64          ; its inputs: the checkers off (2)BBACK   equ 66          ; checkers back (2)BBUCK   equ 68          ; the pip lead's bucket ($ff: none)BSUM    equ 69          ; its checkers on the board (2)BPIPS   equ 71          ; its pips (2 x 2)BFEAT   equ 80          ; gnubg's features (50)BSUMS   equ 130         ; the first-layer sums (2H); NST, from BOFF: the same for PA/PB.; eval: IX -> a net -> RES = its score of PA/PB (and SUMS, NST, FEAT).eval:        ld l,(ix+13)        ld h,(ix+14)        push hl        pop iy        ld a,h        ld (RPAGE),a        ld l,BSUMS        ld de,SUMS        ld c,(ix+0)        ld b,0        sla c        ldir        ld l,BBACK        ld de,NST+2        ld bc,9        ldir        ld hl,0        ld (NETK),hl        ; the points        xor a        ld (SIDE),a        ld hl,PA        call eside        ld a,1        ld (SIDE),a        ld hl,PB        call eside        ; the checkers off        ld a,(NST+5)        neg        add a,15        ld (NST),a        ld c,a        ld b,(iy+BOFF)        ld hl,100        call applyi        ld a,(NST+6)        neg        add a,15        ld (NST+1),a        ld c,a        ld b,(iy+BOFF+1)        ld hl,201        call applyi        ld a,(ix+2)        cp 202        jp z,finish        ; the pip lead, plus four buckets, in buckets of 8        ld hl,(NST+9)        ld de,(NST+7)        or a        sbc hl,de        ld de,32        add hl,de        xor a        bit 7,h        jr nz,.b        ld a,h        or a        ld a,8        jr nz,.b        ld a,l        rrca        rrca        rrca        and $1f        cp 8        jr c,.b        ld a,8.b:     ld (NST+4),a        ld b,(iy+BBUCK)        cp b        jr z,.nb        push af        ld a,b        inc a        jr z,.nob        dec a        ld hl,202        call addhla        ld bc,$100        call applyi.nob:   pop af        ld hl,202        call addhla        ld bc,1        call applyi.nb:    ; checkers back, as thermometers        ld hl,211        ld de,NST+2        call therm        ld hl,215        ld de,NST+3        call therm        ld a,(ix+2)        cp 219        jr z,finish        ; gnubg's features        push ix        ld hl,PA        ld de,PB        ld ix,FEAT        call half        ld hl,PB        ld de,PA        ld ix,FEAT+25        call half        pop ix        ld hl,FEAT.f:     push hl        ld c,(hl)        ld a,(RPAGE)        ld h,a        ld b,(hl)        ld a,l        sub low FEAT        ld l,a        ld h,0        ld de,219        add hl,de        call applyi        pop hl        inc l        ld a,l        cp low FEAT+50        jr nz,.f; finish: RES from SUMS, less the 128 x NETK the stored weights add.finish:        ld hl,(NETK)        add hl,hl        add hl,hl        add hl,hl        add hl,hl        add hl,hl        add hl,hl        add hl,hl        ex de,hl        ld hl,SUMS        ld b,(ix+0).c:     ld a,(hl)        sub e        ld (hl),a        inc l        ld a,(hl)        sbc a,d        ld (hl),a        inc l        djnz .c        bit 0,(ix+1)        jr z,.mlp        ld hl,(SUMS)        ld (RES),hl        ld a,h        rla        sbc a,a        ld (RES+2),a        ret.mlp:   ld a,(ix+10)        ld (RES),a        ld a,(ix+11)        ld (RES+1),a        ld a,(ix+12)        ld (RES+2),a        ld l,(ix+8)        ld h,(ix+9)        ld (W2P),hl        ld hl,SUMS        ld b,(ix+0).h:     push bc        ld e,(hl)        inc l        ld d,(hl)        inc l        push hl        ; the sigmoid table's index: the sum halved, within -128..127        sra d        rr e        ld a,e        rla        ld a,d        adc a,0        jr z,.inr        ld a,d        rla        ld a,255        jr nc,.t        xor a        jr .t.inr:   ld a,e        xor $80.t:     ; the table holds its upper half: below, 255 less the mirror        sub 128        jr nc,.hi        neg        ld hl,SIG        call index        cpl        jr .sg.hi:    ld hl,SIG        call index.sg:    or a        jr z,.nx0        ld e,a        ld d,0        ld hl,(W2P)        ld a,(hl)        inc hl        ld (W2P),hl        or a        push af        jp p,.pos        neg.pos:   call mul        pop af        ld de,RES        jp m,.sub        ld a,(de)        add a,l        ld (de),a        inc de        ld a,(de)        adc a,h        ld (de),a        inc de        ld a,(de)        adc a,0        ld (de),a        jr .nx.sub:   ld a,(de)        sub l        ld (de),a        inc de        ld a,(de)        sbc a,h        ld (de),a        inc de        ld a,(de)        sbc a,0        ld (de),a        jr .nx.nx0:   ld hl,(W2P)        inc hl        ld (W2P),hl.nx:    pop hl        pop bc        djnz .h        ret; rebase: IX -> a net: PA/PB scored (RES), and made its base.rebase:        call eval        ld a,(RPAGE)        ld d,a        ld e,0        ld hl,PA        ld bc,64        ldir        ld hl,NST        ld bc,11        ldir        ld e,BFEAT        ld hl,FEAT        ld bc,50        ldir        ld e,BSUMS        ld hl,SUMS        ld c,(ix+0)        ld b,0        sla c        ldir        ret; therm: HL = the first of 4 inputs, DE -> the new count in NST (the; base's at the same place in its page): checkers back as a thermometer.therm:        ld a,(de)        ld c,a        ld a,(RPAGE)        ld d,a        ld a,(de)        ld b,a        ld e,4.t:     push bc        push de        push hl        ld a,c        call gt0        ld c,a        ld a,b        call gt0        ld b,a        call applyi        pop hl        pop de        pop bc        inc hl        dec b        dec c        dec e        jr nz,.t        retgt0:    or a        ret z        bit 7,a        ld a,0        ret nz        inc a        ret; eside: HL -> PA or PB (SIDE 0 or 1): each point differing from the; base's, its inputs' rows added or taken away, and NST's checkers on the; board, pips and checkers back updated.eside:        ld a,(RPAGE)        ld d,a        ld a,(SIDE)        rrca        rrca        rrca        ld e,a                  ; 0 or 32        ld b,25.l:     ld a,(de)        cp (hl)        call nz,point        inc hl        inc e        djnz .l        ret; point: 25 - B = the point, A = the base's checkers there, (HL) =; PA/PB's.point:        push bc        push de        push hl        ld c,a        ld a,25        sub b        ld b,a        ld a,c        ld (PTOLD),a        ld e,a        ld a,(hl)        ld (PTNEW),a        sub e        ld c,a        ; checkers on the board, and back        ld hl,NST+5        ld a,(SIDE)        call index        ld a,c        add a,(hl)        ld (hl),a        ld a,b        cp 18        jr c,.nb        ld hl,NST+2        ld a,(SIDE)        call index        ld a,c        add a,(hl)        ld (hl),a.nb:    ; pips: the point's, C times        ld a,(SIDE)        add a,a        ld hl,NST+7        call index        push hl        ld e,(hl)        inc hl        ld d,(hl).p:     ld a,c        or a        jr z,.pd        ld a,b        inc a        bit 7,c        jr nz,.pm        dec c        add a,e        ld e,a        jr nc,.p        inc d        jr .p.pm:    inc c        ld l,a        ld a,e        sub l        ld e,a        jr nc,.p        dec d        jr .p.pd:    pop hl        ld (hl),e        inc hl        ld (hl),d        ; its first input's row: 101 x side + 4 x point        ld a,(SIDE)        or a        jr z,.s0        ld a,101.s0:    ld c,a        ld a,b        add a,a        add a,a        add a,c        ld e,a        ld d,0        call mulh        ld e,(ix+4)        ld d,(ix+5)        add hl,de        ld (ROWB),hl        ; a checker at a time, from the base's count to PA/PB's: adding        ; one to a point of n adds the row for one checker (n = 0), for two        ; less that for one (1), for three (2), or beyond three (3 or more).c:     ld a,(PTOLD)        ld hl,PTNEW        cp (hl)        jr z,.done        ld e,1        jr c,.up        dec a        ld e,-1        ld (PTOLD),a        jr .go.up:    inc a        ld (PTOLD),a        dec a.go:    ld hl,(ROWB)        ld b,e        ld e,(ix+0)        ld d,0        or a        jr z,.r        dec a        jr z,.two        add hl,de        add hl,de        dec a        jr z,.r        add hl,de.r:     ld a,b        call rows        jr .c.two:   push hl        push de        push bc        ld a,b        neg        call rows        pop bc        pop de        pop hl        add hl,de        jr .r.done:  pop hl        pop de        pop bc        ret; mulh: HL = DE x the net's H, which is 1, 4, 8 or 48.mulh:   ex de,hl        ld a,(ix+0)        srl a        ret c        add hl,hl        add hl,hl        cp 2        ret z        add hl,hl        cp 4        ret z        add hl,hl        ld d,h        ld e,l        add hl,hl        add hl,de        ret; applyi: HL = an input, B, C = its count in the base and now: its row; added the difference in times.applyi:        ld a,c        sub b        ret z        push af        ex de,hl        call mulh        ld e,(ix+4)        ld d,(ix+5)        add hl,de        pop af; rows: HL -> a row, A = how many times to add it (negative: take away).; The weights are popped two at a time, so interrupts must be off; with H; odd the last pair's second, the next row's first, goes into a spare sum.rows:        ld c,a        push hl        ld l,a        rla        sbc a,a        ld h,a        ld de,(NETK)        add hl,de        ld (NETK),hl        pop hl        ld a,c.r:     push af        push hl        ld (SPSAVE),sp        ld sp,hl        ld hl,SUMS        ld b,(ix+0)        inc b        srl b        or a        jp m,.s.a:     pop de        ld a,e        add a,(hl)        ld (hl),a        inc l        jr nc,.a1        inc (hl).a1:    inc l        ld a,d        add a,(hl)        ld (hl),a        inc l        jr nc,.a2        inc (hl).a2:    inc l        djnz .a        jr .e.s:     pop de        ld a,(hl)        sub e        ld (hl),a        inc l        jr nc,.s1        dec (hl).s1:    inc l        ld a,(hl)        sub d        ld (hl),a        inc l        jr nc,.s2        dec (hl).s2:    inc l        djnz .s.e:     ld sp,(SPSAVE)        pop hl        pop af        or a        jp m,.inc        dec a        ret z        jr .r.inc:   inc a        ret z        jr .r