play.asm
The title and menu, games and matches, the player's and Gnubby's turns, the doubling cube, the scores. Download · All the source
; ----------------------------------------------------------------- play; The games: the title and menu, a match or money session, and each; game's turns, the cube, and the scores.start: di ld sp,0 xor a out ($fe),a call init ld hl,1 ld (SEED),hl ; the loading screen a while longer, or until a key xor a ; K_ANY ld (KSET),a inc a ld (KWAIT),a ld b,200.hold: push bc call scan pop bc or a jr nz,title push bc ld b,1 call pause pop bc djnz .hold; The title, and a choice of game.title: ld sp,0 xor a ld (KWAIT),a ld (SAID),a ld (UP),a ; the board to be set up again call cls ld a,$42 ld (TATTR),a ld hl,S_TITLE ld bc,2*256+8 call bigtext ld a,1 ld (MOOD),a ld bc,6*256+14 call mascot ld a,$45 ld (TATTR),a ld hl,S_WITH ld bc,11*256+9 call print ld a,$46 ld (TATTR),a ld hl,S_MENU ld bc,13*256+8 call print ld a,$05 ld (TATTR),a ld hl,S_FOOT ld bc,23*256+4 call print.k: ld a,K_TITLE ; M for money, else the match's length call getk ld b,0 cp 'M' jr z,.len sub '0' ld b,a cp 8 jr nc,.k and 1 ; 1, 3, 5 or 7 jr z,.k.len: ld a,b ld (MLEN),a ld hl,0 ld (SCH),hl ld (SCC),hl xor a ld (CRAW),a; A game.newgame: ld sp,0 call lgame ld hl,START ld de,GB call copy64 ld a,1 ld (CUBE),a xor a ld (OWNER),a ld (SHOWN),a ld (MOOD),a ld (PLAYED),a ld (U1),a ld (U2),a ld (NDONE),a ld a,25 ld (CURS),a ld hl,S_HELLO call say call drawall call getkey ; the opening roll: one die each, the higher starts with both.open: ld a,3 ld (SHOWN),a call roll call tsay ld hl,S_YOUROLL call tstr ld a,(DIE1) call tdig ld hl,S_IROLL call tstr ld a,(DIE2) call tdig ld a,(DIE1) ld b,a ld a,(DIE2) cp b jr nz,.go ld hl,S_TIE call tstr call tdone call getkey jr .open.go: ld hl,S_YOUSTART jr c,.h ld hl,S_ISTART.h: push af call tstr call tdone call getkey pop af ld a,1 jr c,.hum inc a.hum: ld (SHOWN),a dec a ld (TURN),a jp nz,cturn1 jp hturn1; The player's turn: first the cube, then the dice.hturn: xor a ld (SHOWN),a ld (U1),a ld (U2),a ld (NDONE),a ld a,25 ld (CURS),a xor a ld (TURN),a call candbl ld hl,S_ROLL jr nc,.nd ld hl,S_ROLLDBL.nd: call sayplay ld a,0 ld (MOOD),a call drawall.k: call candbl ; D only if the player may double ld a,K_ROLL jr nc,.kr ld a,K_ROLLD.kr: call getk cp 'R' jr z,.roll cp ' ' jr z,.roll cp 13 jr z,.roll cp 'D' jr nz,.k call candbl jr nc,.k call hdouble ret c ; Gnubby passed: the game is over.roll: ld a,1 ld (SHOWN),a call rollhturn1: call hmove ld hl,GB call total or a jr nz,cturn ; the player bore off the last checker ld a,1 jp won; Gnubby's turn.cturn: xor a ld (U1),a ld (U2),a ld (NDONE),a ld (SHOWN),a ld a,25 ld (CURS),a ld a,1 ld (TURN),a call drawall ; the player's cursor gone call cdouble ret c ; the player passed ld a,2 ld (SHOWN),a call rollcturn1: ld a,25 ld (CURS),a call cmove ld hl,GB+32 call total or a jp nz,hturn ld a,2 jp won; won: A = 1 if the player won, 2 Gnubby: its points, and the next game.won: ld (WINNER),a ; 1 point, 2 for a gammon (the loser has none off), 3 for a ; backgammon (and a checker on the bar or in the winner's home) ld hl,GB+32 cp 1 jr z,.l ld hl,GB.l: push hl call total pop hl ld c,1 cp 15 jr nz,.pts inc c ld de,18 add hl,de ld b,7 xor a.bg: or (hl) inc hl djnz .bg jr z,.pts inc c.pts: ld a,c ld (GAMMON),a ld a,(CUBE) ld b,a xor a.m: add a,c djnz .m jp score; score: A points to WINNER; the score, and a new game, or the match's end.score: ld (POINTS),a call lwin ld a,(POINTS) ld e,a ld d,0 ld a,(WINNER) dec a ld hl,SCH jr z,.h ld hl,SCC.h: ld a,(hl) add a,e ld (hl),a inc hl ld a,(hl) adc a,d ld (hl),a ; the Crawford game is the one after a player first needs one point ld a,(MLEN) or a jr z,.said ld a,(CRAW) cp 1 jr nz,.nc inc a ld (CRAW),a jr .said.nc: or a jr nz,.said ld a,(MLEN) dec a ld hl,SCH cp (hl) jr z,.cr ld hl,SCC cp (hl) jr nz,.said.cr: ld a,1 ld (CRAW),a.said: call tsay ld a,(WINNER) dec a ld hl,S_YOUWIN jr z,.w ld hl,S_IWIN.w: call tstr ld a,(POINTS) call tnum ld hl,S_POINT call tstr ld a,(POINTS) dec a jr z,.one ld a,'S' call tchr.one: ld a,(GAMMON) dec a jr z,.plain ld hl,S_GAMMON dec a jr z,.g ld hl,S_BACKG.g: call tstr.plain: ld a,(WINNER) dec a ld hl,S_YAY ld a,2 ; Gnubby sad, but a good sport jr z,.m ld hl,S_HEHE ld a,1.m: ld (MOOD),a push hl ; the second line, unless the match is over ; the match over? ld a,(MLEN) or a jr z,.money ld e,a ld d,0 ld hl,(SCH) or a sbc hl,de ld hl,S_MATCHYOU jr nc,.over ld hl,(SCC) or a sbc hl,de ld hl,S_MATCHME jr nc,.over pop hl call tstr call tdone call drawall call cheer call getkey jp newgame.over: pop de push hl ld hl,S_NL call tstr pop hl call tstr call tdone call drawall call cheer call getkey jp title.money: pop hl call tstr ld hl,S_AGAIN call tstr call tdone call drawall call cheer ld a,K_AGAIN call yesno jp c,newgame jp title; cheer: a tune for the winner.cheer: ld a,(WINNER) dec a ld hl,T_WIN jr z,.t ld hl,T_LOSE.t: jp tune; ----------------------------------------------------------------- cube; candbl: carry if the side on roll (TURN) may double: the cube theirs or; in the middle, not the Crawford game, and more points in it than they; need, in a match.candbl: ld a,(OWNER) ld hl,TURN or a jr z,.mine dec a cp (hl) jr nz,.no.mine: ld a,(MLEN) or a jr z,.yes ld a,(CRAW) dec a jr z,.no call need ld hl,CUBE cp (hl) jr c,.no jr z,.no.yes: scf ret.no: or a ret; need: A = the points the side on roll needs to win the match.need: ld a,(TURN) or a ld hl,(SCH) jr z,.h ld hl,(SCC).h: ld a,(MLEN) sub l ret; hdouble: the player doubles: Gnubby takes (carry clear) or passes (the; game over, carry set).hdouble: xor a ; the player call ldbl ld hl,S_DBLYOU call say ld a,3 ld (MOOD),a call drawall ; take if passing loses the match ld a,(MLEN) or a jr z,.eq ld hl,CUBE ld a,(SCH) add a,(hl) ld hl,MLEN cp (hl) jr nc,.take ; else if the player's equity is under the take threshold.eq: ld hl,GB ld de,ROOT call copy64 ld a,1 ld (TAKEQ),a xor a ld (OWNED),a call cubeq ld de,(CT1) call scmp jr c,.take.pass: ld a,$41 ; Gnubby passes call lone ld hl,S_IPASS call say ld a,2 ld (MOOD),a call drawall call getkey ld a,1 ld (WINNER),a ld (GAMMON),a ld a,(CUBE) call score scf ret.take: ld a,$31 ; Gnubby takes call lone ld hl,CUBE sla (hl) ld a,2 ld (OWNER),a ld hl,S_ITAKE call say xor a ld (MOOD),a call drawall ld hl,T_DBL call tune call getkey or a ret; cdouble: Gnubby's turn: it may double; the player takes (carry clear) or; passes (the game over, carry set).cdouble: call candbl ret nc ; after the Crawford game, double at once when the player needs ; a point and Gnubby more ld a,(CRAW) cp 2 jr nz,.eq ld a,(MLEN) dec a ld hl,SCH cp (hl) jr z,.dbl.eq: ld hl,GB ld de,ROOT call turn xor a ld (TAKEQ),a ld a,(OWNER) cp 2 ld a,0 jr nz,.o inc a.o: ld (OWNED),a ld a,1 call cubeq ; from the lower threshold, and short of too good push hl ld de,(CT1) call scmp pop hl jr c,.no ld de,(CT2) call scmp jr c,.dbl.no: or a ret.dbl: ld a,1 ; Gnubby doubles call ldbl ld hl,T_DBL call tune call tsay ld hl,S_IDOUBLE call tstr ld a,(CUBE) add a,a call tnum ld hl,S_TAKEQ call tstr call tdone ld a,1 ld (MOOD),a call drawall ld a,K_TAKE call yesno jr nc,.pass ld a,$30 ; the player takes call lone ld hl,CUBE sla (hl) ld a,1 ld (OWNER),a ld hl,S_YOUTAKE call say xor a ld (MOOD),a call drawall ld b,40 call pause or a ret.pass: ld a,$40 ; the player passes call lone ld a,2 ld (WINNER),a ld a,1 ld (GAMMON),a ld a,(CUBE) call score scf ret; ------------------------------------------------------- the cube's rules; Gnubby judges the cube by an equity for the doubler against three; thresholds: double from, too good from, and take below. In a match they; come from a table (METTAB) made from gnubg's cubeful match equity at the; score and cube, taking the equity for chances with a fixed share of; gammons; in money play (MONEYREC) they follow gnubg's money-play cube; decisions. Each is by who owns the cube and by race or contact. The; equity is the nets' (0-ply); within C_W of a threshold, a ply deeper; (the engine's ply1, up to 6 s); and within C_W2, a ply deeper with; Gnubby's plays chosen by the contact net instead (ply1c, about 14 s).; All in the nets' units, 8192 a point.C_W equ 2458 ; a ply deeper within 0.3 of a thresholdC_W2 equ 1229 ; with the plays chosen better within 0.15; cubeq: ROOT = a board, the doubler (A: 0 the player, 1 Gnubby) on roll,; OWNED whether they own the cube, TAKEQ whether it is a take -> HL = the; doubler's equity, and the thresholds: CT1 (double from, or take below); and CT2 (too good from).cubeq: call crec ld hl,ROOT call equity call contact sbc a,a and 2 ld (CFLAG),a ; 0 race, 2 contact ld hl,(RECP) ld a,(TAKEQ) or a jr z,.dbl ld a,(CFLAG) rrca add a,8 call thr ld (CT1),hl ld hl,16383 ld (CT2),hl jr .e.dbl: ld a,(OWNED) add a,a add a,a ld b,a ld a,(CFLAG) add a,b push af call thr ld (CT1),hl pop af inc a ld hl,(RECP) call thr ld (CT2),hl.e: call res16 ld bc,C_W2 call close ld de,ply1c ; very close: the plays chosen better jr c,.deep ld bc,C_W call close ret nc ld de,ply1.deep: push de ld a,3 ; thinking ld (MOOD),a call drawmasc ld a,(TAKEQ) ; his own double: he says he is thinking or a ; (a take follows "YOU DOUBLE? HMM") ld hl,S_CUBEQ call z,say pop hl call jphl jp res16jphl: jp (hl); close: carry if HL is within BC of a threshold: CT1, or for a double; CT2 too. Keeps HL.close: ld de,(CT1) call near ret c ld a,(TAKEQ) or a ret nz ld de,(CT2) jr near; near: carry if HL is within BC of DE. Keeps HL, BC.near: push hl or a sbc hl,de jp p,.pos xor a sub l ld l,a sbc a,a sub h ld h,a.pos: or a sbc hl,bc pop hl ret; thr: HL -> a record, A = an entry -> HL = its threshold: 80 x the byte,; less 8192; 0 for always, 255 for never.thr: add a,l ld l,a jr nc,.n inc h.n: ld a,(hl) cp 255 ld hl,16383 ret z or a ld hl,-16384 ret z ld l,a ld h,0 add hl,hl add hl,hl add hl,hl add hl,hl ld d,h ld e,l add hl,hl add hl,hl add hl,de ; 80 x ld de,-8192 add hl,de ret; crec: A = the doubler (0 the player, 1 Gnubby) -> RECP = the record for; the game, score and cube: money's, or METTAB's for the doubler 2 to 7; away, the other 1 to 7, and the cube 1, 2 or 4.crec: ld b,a ld hl,MONEYREC ld (RECP),hl ld a,(MLEN) or a ret z ld c,a ld a,(SCH) ld d,a ld a,(SCC) ld e,a ld a,b or a jr z,.p ld a,d ld d,e ld e,a.p: ld a,c sub d ld d,a ; the doubler's away ld a,c sub e ld e,a ; the other's ld a,(CUBE) ld b,-1.k: inc b rra jr nc,.k ; B = log2 of the cube ld a,b cp 3 jr c,.kk ld b,2.kk: ld a,d sub 2 ld l,a add a,a add a,a add a,a sub l ; 7 (a - 2) add a,e dec a ld l,a add a,a add a,l add a,b ; 3 (7 (a - 2) + b - 1) + k ld l,a ld h,0 add hl,hl ld d,h ld e,l add hl,hl add hl,hl add hl,de ; 10 bytes a record ld de,METTAB add hl,de ld (RECP),hl ret; res16: HL = RES, within -16384 to 16383 (two points).res16: ld hl,(RES) ld a,(RES+2) ld de,16383 or a jp m,.neg jr nz,.hi ld a,h cp $40 ret c.hi: ex de,hl ret.neg: inc a jr nz,.lo ld a,h cp $c0 ret nc.lo: ld hl,-16384 ret; scmp: carry if HL < DE, signed. Loses HL.scmp: ld a,h xor d jp m,.diff or a sbc hl,de ret.diff: ld a,h rla ret; equity: HL -> a board -> RES = the side on roll's equity, by the; contact or race net (8192 a point).equity: ld de,PA call copy64 jp s_last; ----------------------------------------------------------- the player; hmove: the player plays DIE1, DIE2 (DHI, DLO), a checker at a time.hmove: ld hl,GB ld de,TB0 call copy64 xor a ld (NDONE),a ld (U1),a ld (U2),a ld hl,GB call mx ld (NMAX),a or a jr nz,.can ld hl,S_NOMOVE call say ld a,2 ld (MOOD),a call drawall ld hl,0 ; the player's turn, no play xor a call lmove jp getkey.can: call first.loop: xor a ld (MOOD),a ld a,(NDONE) ld hl,NMAX cp (hl) jr nz,.more ld hl,S_DONE call say call drawall.dk: ld a,K_DONE call getk cp 13 jr z,.fin cp ' ' jr z,.fin cp 'U' jr nz,.dk call undo jr .loop.fin: ld hl,TSTEPS ; the player's turn, as played xor a jp lmove.more: ld hl,S_MOVE call say call drawall.k: ld a,K_MOVE call getk cp 'D' jr z,.swap cp 'Q' ; up, towards 24 jr z,.up cp '7' ; (the cursor keys' up) jr z,.up cp 'A' ; down, towards 1 jr z,.down cp '6' jr z,.down cp 'U' jr z,.undo cp 'H' jr z,.hint cp '1' ld hl,DIE1 jr z,.die cp '2' ld hl,DIE2 jr z,.die cp 13 jr z,.any cp ' ' jr nz,.k.any: ; the current die, the left unless it is played ld a,(U1) or a jr nz,.rt ld a,(DIE1) call tryd jp nc,.loop ; it cannot be: the right, if it can, swapped to the left ld a,(U2) or a jr nz,.no call swapd ld a,(DIE1) call tryd jp nc,.loop call swapd jr .no.rt: ld a,(DIE2).try: call tryd jp nc,.loop.no: ld hl,T_LOSE+4 call tune jp .k.die: ld a,(hl) jr .try.swap: call swapd call drawall jp .k.up: ld e,1 jr .mv.down: ld e,-1.mv: call cursor call drawall jp .k.undo: call undo jp .loop.hint: ld hl,S_HINT call say ld a,3 ld (MOOD),a ld a,25 ; no cursor while he thinks ld (CURS),a call drawall ld hl,TB0 ld de,ROOT call copy64 call think ; its steps, for the log: the play generated again, as Gnubby's ld hl,match ld (USERFN),hl ld hl,ROOT call gen ld hl,CSTEPS ld de,TSTEPS ld bc,8 ldir ld hl,RESULT ld de,GB call copy64 ld a,(NMAX) ld (NDONE),a ld a,1 ld (U1),a ld (U2),a ld a,25 ld (CURS),a jp .loop; swapd: the dice (and whether each is played) the other way round.swapd: ld hl,(DIE1) ld a,l ld l,h ld h,a ld (DIE1),hl ld hl,(U1) ld a,l ld l,h ld h,a ld (U1),hl ret; undo: the turn's start again.undo: ld hl,TB0 ld de,GB call copy64 xor a ld (NDONE),a ld (U1),a ld (U2),a; first: the cursor on the bar, or the highest point with a checker.first: ld a,$ff ; no steps yet this turn ld (TSTEPS),a ld a,26 ld (CURS),a ld e,0; cursor: to the next point in direction E (1 up, -1 down) with one of the; player's checkers, or (E = 0) kept if it has one; on the bar while; there are checkers there; none (25) when all are borne off.cursor: ld hl,GB call total or a jr nz,.some ld a,25 ld (CURS),a ret.some: ld a,(GB+24) or a ld a,24 jr nz,.set ld a,e or a jr nz,.go dec e ld a,(CURS) cp 24 jr c,.chk ld a,23 jr .chk.go: ld a,(CURS) cp 24 jr c,.l ld a,24.l: add a,e cp 24 jr c,.chk ld a,e or a ld a,23 jp m,.chk xor a.chk: push af ld hl,GB call index or a pop bc ld a,b jr z,.l.set: ld (CURS),a ret; tryd: A = a die: its step from the cursor, if legal and the rest of the; roll can still be played as it must; carry if not.tryd: ld e,a ; the die unplayed? ld a,(DIE1) ld b,a ld a,(DIE2) cp b jr z,.ok ld a,e cp b jr nz,.d2 ld a,(U1) or a jr z,.ok.d2: ld a,(DIE2) cp e scf ret nz ld a,(U2) or a scf ret nz.ok: ; with only one die to play, the larger if it can be ld a,(NMAX) dec a jr nz,.st ld a,(MUSTHI) or a jr z,.st ld a,(DHI) cp e scf ret nz.st: push de ld hl,GB ld de,W call copy64 pop de ld a,(CURS) ld b,a push de call step pop de ret c ; the rest: as many dice as the roll must play ld hl,W push de ld de,ANIM call copy64 pop de ld a,(NDONE) ld b,a ld a,(NMAX) sub b dec a jr z,.yes ld (NEED),a ld hl,GDIE ld (hl),e ld a,(DIE1) ld b,a ld a,(DIE2) cp b jr z,.dbl cp e jr nz,.oth ld a,b.oth: ld (hl),a.dbl: inc l ld (hl),e inc l ld (hl),e inc l ld (hl),e ld (GDOUBLE),a ld hl,ANIM ld (GROOT),hl xor a ld (GKEYED),a ld (GPRUNE),a push de ld a,(NEED) call measure pop de ld hl,NEED cp (hl) ret c.yes: call lstep ld hl,ANIM push de ld de,GB call copy64 pop de ld hl,NDONE inc (hl) ; which die ld a,(DIE1) cp e jr nz,.u2 ld hl,U1 ld a,(hl) or a jr z,.set.u2: ld hl,U2.set: ld (hl),1 ld e,0 call cursor ld bc,$0430 call tone or a ret; mx: HL -> a board, DHI/DLO the dice -> A = how many can be played, and; MUSTHI: only one can, and the larger can.mx: ld (GROOT),hl ld de,W call copy64 xor a ld (GKEYED),a ld (GPRUNE),a ld (MUSTHI),a ld a,(DHI) ld b,a ld a,(DLO) cp b jr nz,.nd ld hl,GDIE ld (hl),a inc l ld (hl),a inc l ld (hl),a inc l ld (hl),a ld (GDOUBLE),a ld a,4 jp measure.nd: xor a ld (GDOUBLE),a call order_a call measure2 ld (MXA),a cp 2 ret z call order_b call measure2 ld b,a ld a,(MXA) cp b jr nc,.a ld a,b ret.a: or a ret z ld (MUSTHI),a ret; ---------------------------------------------------------------- Gnubby; cmove: Gnubby plays DHI, DLO, shown a checker at a time.cmove: ld hl,S_THINK call say ld a,3 ld (MOOD),a call drawall ld hl,GB ld de,ROOT call turn call think or a jr nz,.can ld hl,0 ; Gnubby's turn, no play ld a,1 call lmove call tsay ld hl,S_ICANT call tstr call tdone ld a,1 ld (PLAYED),a ld a,2 ld (MOOD),a call drawall ld b,100 jp pause.can: ; its steps: the play generated again, the one giving RESULT ld hl,match ld (USERFN),hl ld hl,ROOT call gen ld hl,CSTEPS ; Gnubby's turn, as played ld a,1 call lmove ld hl,ROOT ld de,ANIM call copy64 call tsay ld hl,S_IPLAY call tstr ld a,4 ld (CNT),a ld hl,CSTEPS.s: ld a,(hl) cp $ff jr z,.done push hl ld b,a ld de,4 add hl,de ld e,(hl) push de push bc ; its notation: from/to, * for a hit ld a,b cp 24 jr nz,.pt ld hl,S_BAR call tstr jr .to.pt: inc a call tnum.to: ld a,'/' call tchr pop bc pop de push bc push de ld hl,ANIM ld de,W call copy64 pop de pop bc call step push af ld a,b sub e jr nc,.on ld hl,S_OFF call tstr jr .hit.on: inc a call tnum.hit: pop af or a jr z,.nh ld a,'*' call tchr.nh: ld a,' ' call tchr ld hl,W ld de,ANIM call copy64 ld hl,ANIM ld de,GB call turn call drawall ld bc,$0440 call tone ld b,25 call pause pop hl inc hl ld a,(CNT) dec a ld (CNT),a jr nz,.s.done: call tdone ld a,1 ld (PLAYED),a ld (MOOD),a call drawall ld b,50 jp pause; sayplay: says HL, after Gnubby's play if he has just played (without; its "I PLAY" if it would not fit on a line).sayplay: ld a,(PLAYED) or a jp z,say xor a ld (PLAYED),a push hl ld hl,TXT xor a ld bc,0 cpir ld a,c add a,33 ; the length with its 0 is -C: carry if ld hl,TXT ; 32 or less jr c,.fit ld hl,TXT+7.fit: ld de,TXT2.c: ld a,(hl) ld (de),a inc hl inc de or a jr nz,.c call tsay ld hl,TXT2 call tstr ld a,'|' call tchr pop hl call tstr jp tdone; think: decide, keeping the dice (it leaves DHI, DLO at the last reply; it looked at).think: call decide push af call setdice pop af ret; match: a generated play: its steps kept if it is the chosen one.match: ld hl,W ld de,RESULT ld b,64.c: ld a,(de) cp (hl) ret nz inc hl inc de djnz .c call mksteps ld hl,NEWSTEPS ld de,CSTEPS ld bc,8 ldir ret; ----------------------------------------------------------------- text; Building what Gnubby says: tsay starts, tstr/tnum/tdig/tchr add, tdone; says it.tsay: ld hl,TXT ld (TXP),hl rettstr: ld de,(TXP).l: ld a,(hl) or a jr z,.e ld (de),a inc hl inc de jr .l.e: ld (TXP),de rettdig: add a,'0'tchr: ld hl,(TXP) ld (hl),a inc hl ld (TXP),hl rettnum: ld l,a ld h,0 ld de,(TXP) call utoa ld (TXP),de rettdone: xor a call tchr ld hl,TXT jp say