ca65 V2.17 - Git 582aa41 Main file : bulls_and_cows.ca65 Current file: bulls_and_cows.ca65 000000r 1 ; 000000r 1 ; ACORN System 1 Applications: Bulls and Cows (Mastermind) 000000r 1 ; 000000r 1 ; From the Liverpool Software Gazette 000000r 1 ; 000000r 1 ; (Chris Oddy January 2022) 000000r 1 ; 000000r 1 ; entry point $0200 000000r 1 ; 000000r 1 .setcpu "6502" 000000r 1 .listbytes unlimited 000000r 1 ; 000000r 1 KEY := $0D 000000r 1 REPEAT := $0E 000000r 1 D := $10 000000r 1 DISPLAY := $FE0C ; scan the display 000000r 1 RDHEXTD := $FE60 ; right double hex to display 000000r 1 HEXTD := $FE7A ; hex to display 000000r 1 START := $FEDF ; 000000r 1 ; 000000r 1 .org $0200 000200 1 ; 000200 1 MESSPO := $0020 ; pointer to messages 000200 1 RAN := $0022 ; random numbers here 000200 1 MYNO := $0025 ; hidden Acorn's number 000200 1 YGU := $0027 ; humans guess 000200 1 NUMA := $0029 ; number to be matched 000200 1 NUMB := $002D ; number to be matched with 000200 1 BULLS := $0031 000200 1 COWS := $0032 000200 1 LIST := $0033 ; used to calculate cows 000200 1 MYGU := $003B ; my new guess 000200 1 STRT := $003D ; start of guesses 000200 1 ANSWER := $003F ; answer from piran 000200 1 GSEND := $0040 ; end of guess stack 000200 1 GUNO := $0041 ; present guess on stack 000200 1 TEMPA := $0042 ; two temporary locatiosn for ROR 000200 1 TEMPB := $0043 000200 1 ; 000200 1 A9 00 MATCH: lda #$00 000202 1 A2 09 ldx #$09 ; clear bulls, cows 000204 1 95 31 CLEAR: sta BULLS,X ; and list 000206 1 CA dex 000207 1 10 FB bpl CLEAR 000209 1 A0 03 ldy #$03 00020B 1 B9 29 00 CMPARE: lda NUMA,Y ; digit from NUMA 00020E 1 D9 2D 00 cmp NUMB,Y ; is it a bull ? 000211 1 D0 04 bne NOBULL ; no 000213 1 E6 31 inc BULLS ; count a bull 000215 1 10 11 bpl NOCOWS ; it can't be a cow 000217 1 AA NOBULL: tax ; is it a cow then ? 000218 1 F6 33 inc LIST,X ; increment via digit 00021A 1 F0 02 beq COWCNT ; it is a cow 00021C 1 10 02 bpl NOCOW ; it is not a cow 00021E 1 E6 32 COWCNT: inc COWS ; count a cow 000220 1 B6 2D NOCOW: ldx NUMB,Y ; try other way 000222 1 D6 33 dec LIST,X ; decrement via digit 000224 1 30 02 bmi NOCOWS ; it is not a cow 000226 1 E6 32 inc COWS ; count a cow 000228 1 88 NOCOWS: dey ; next digit 000229 1 10 E0 bpl CMPARE ; round again 00022B 1 A5 31 lda BULLS ; now assemble answer 00022D 1 0A asl A 00022E 1 0A asl A 00022F 1 0A asl A 000230 1 0A asl A 000231 1 05 32 ora COWS 000233 1 60 rts ; and return 000234 1 B9 00 00 UNPACK: lda $0000,Y ; put number 000237 1 85 42 sta TEMPA ; to be unpacked 000239 1 B9 01 00 lda $0001,Y ; in TEMPA 00023C 1 A0 04 ldy #$04 ; (4 digits to unpack) 00023E 1 85 43 UNLOOP: sta TEMPB ; and TEMPB 000240 1 29 07 and #$07 ; extract digit 000242 1 95 00 sta $00,X ; save unpacked form 000244 1 A5 43 lda TEMPB ; reload lower byte 000246 1 66 42 ror TEMPA ; 2-byte 3-bit rotate 000248 1 6A ror A 000249 1 66 42 ror TEMPA 00024B 1 6A ror A 00024C 1 66 42 ror TEMPA 00024E 1 6A ror A 00024F 1 E8 inx ; next digit 000250 1 88 dey ; Y is a counter 000251 1 D0 EB bne UNLOOP ; round again 000253 1 60 rts ; and return 000254 1 A9 1F DISRAN: lda #$1F ; set single scan 000256 1 85 0E sta REPEAT 000258 1 20 0C FE DESCAN: jsr DISPLAY ; monitor scan call 00025B 1 49 1F eor #$1F ; key ? 00025D 1 D0 11 bne KEYFO ; yes 00025F 1 A5 24 lda RAN+2 ; generate random 000261 1 29 42 and #TEMPA ; numbers, next bit in 000263 1 69 3E adc #STRT+1 ; bit six of A 000265 1 0A asl A ; and put in carry 000266 1 0A asl A 000267 1 26 22 rol RAN ; now rotate the bits 000269 1 26 23 rol RAN+1 ; round the 3 bytes 00026B 1 26 24 rol RAN+2 00026D 1 4C 58 02 jmp DESCAN ; and round again 000270 1 90 01 KEYFO: bcc NORET ; cont or key ? 000272 1 60 rts ; yes so return 000273 1 A5 3F NORET: lda ANSWER ; digit key so 000275 1 0A asl A ; assemble new answer 000276 1 0A asl A ; last digit up 4 bits 000277 1 0A asl A 000278 1 0A asl A 000279 1 05 0D ora KEY ; put in new digit 00027B 1 85 3F sta ANSWER ; store in ANSWER 00027D 1 20 60 FE jsr RDHEXTD ; A to display 000280 1 4C 58 02 jmp DESCAN ; and round again 000283 1 A9 FF MSSAGE: lda #$FF ; message to display 000285 1 85 0E sta REPEAT ; set scan mode for QOCTFE 000287 1 86 20 stx MESSPO ; setup pointer 000289 1 A0 07 ldy #$07 ; 8 digits to fetch 00028B 1 B1 20 MLOOP: lda (MESSPO),Y ; post index fetch 00028D 1 99 10 00 sta D,Y ; put in display buffer 000290 1 88 dey ; next digit 000291 1 10 F8 bpl MLOOP ; round again 000293 1 60 SUBRET: rts ; or return 000294 1 20 AE 02 QOCTFE: jsr QOCTTD ; display old 000297 1 20 0C FE jsr DISPLAY ; MONITOR scan call 00029A 1 B0 F7 bcs SUBRET ; control key return 00029C 1 A0 03 ldy #$03 ; 3 bits to shift 00029E 1 29 07 and #$07 ; keys range 0 to 7 0002A0 1 16 01 SHIFT: asl $01,X ; this is the 3 0002A2 1 36 00 rol $00,X ; bit shift 0002A4 1 88 dey 0002A5 1 D0 F9 bne SHIFT 0002A7 1 15 01 ora $01,X ; put new key in 0002A9 1 95 01 sta $01,X ; store new entry 0002AB 1 4C 94 02 jmp QOCTFE ; and round again 0002AE 1 A0 04 QOCTTD: ldy #$04 ; 4 octal 0002B0 1 B5 00 lda $00,X ; digits to display 0002B2 1 85 42 sta TEMPA ; use TEMPA and TEMPB 0002B4 1 B5 01 lda $01,X 0002B6 1 85 43 DISLOP: sta TEMPB ; save lower byte 0002B8 1 29 07 and #$07 ; mask digit 0002BA 1 20 7A FE jsr HEXTD ; digit to display buffer 0002BD 1 A5 43 lda TEMPB ; reload lower byte 0002BF 1 66 42 ror TEMPA ; now 3-bit 2-byte 0002C1 1 6A ror A ; rotate 0002C2 1 66 42 ror TEMPA 0002C4 1 6A ror A 0002C5 1 66 42 ror TEMPA 0002C7 1 6A ror A 0002C8 1 88 dey ; next digit 0002C9 1 D0 EB bne DISLOP ; and round again 0002CB 1 60 rts ; or return 0002CC 1 A9 FF MBEGIN: lda #$FF 0002CE 1 85 22 sta RAN 0002D0 1 A9 44 MSTART: lda #$44 ; reset stack end 0002D2 1 85 40 sta GSEND 0002D4 1 A9 03 lda #$03 ; set mess pointer 0002D6 1 85 21 sta MESSPO+1 0002D8 1 A2 A7 ldx #$A7 ; message ready 0002DA 1 20 83 02 jsr MSSAGE 0002DD 1 20 54 02 jsr DISRAN ; display ready 0002E0 1 A5 23 lda RAN+1 ; put random number 0002E2 1 85 26 sta MYNO+1 ; as my number 0002E4 1 A5 22 lda RAN 0002E6 1 29 0F and #$0F 0002E8 1 85 25 sta MYNO 0002EA 1 A2 C2 YOUGO: ldx #$C2 ; clear display 0002EC 1 20 83 02 jsr MSSAGE 0002EF 1 A9 FF lda #$FF ; set scan mode 0002F1 1 85 0E sta REPEAT 0002F3 1 A2 27 ldx #YGU ; fetch your guess 0002F5 1 20 94 02 jsr QOCTFE 0002F8 1 A2 29 ldx #NUMA ; num number to NUMA 0002FA 1 A0 25 ldy #MYNO 0002FC 1 20 34 02 jsr UNPACK 0002FF 1 A2 2D ldx #NUMB ; your number to NUMB 000301 1 A0 27 ldy #YGU 000303 1 20 34 02 jsr UNPACK 000306 1 20 00 02 jsr MATCH ; and compare them 000309 1 C9 40 cmp #GSEND ; four bulls !!? 00030B 1 D0 18 bne NOWIN ; phew !! 00030D 1 A2 B4 ldx #$B4 ; drat you 00030F 1 20 83 02 ENDOUT: jsr MSSAGE ; end of game 000312 1 20 54 02 jsr DISRAN ; display message 000315 1 A2 C2 ldx #$C2 ; clear display 000317 1 20 83 02 jsr MSSAGE 00031A 1 A2 25 ldx #MYNO 00031C 1 20 AE 02 jsr QOCTTD 00031F 1 20 54 02 jsr DISRAN 000322 1 4C DF FE jmp START ; ready to play again 000325 1 20 60 FE NOWIN: jsr RDHEXTD ; MONITOR A to display 000328 1 20 54 02 jsr DISRAN ; display bulls/cows 00032B 1 A5 22 lda RAN ; random number is my guess 00032D 1 29 0F and #$0F ; and rememeber where we are 00032F 1 85 3B sta MYGU ; start 000331 1 85 3D sta STRT 000333 1 A5 23 lda RAN+1 000335 1 85 3C sta MYGU+1 000337 1 85 3E sta STRT+1 000339 1 A0 3B NEWGU: ldy #MYGU 00033B 1 A2 2D ldx #NUMB ; unpacked to NUMB 00033D 1 20 34 02 jsr UNPACK 000340 1 A0 44 ldy #$44 ; reset guess pointer 000342 1 C4 40 NEWINF: cpy GSEND ; end of stack ? 000344 1 84 41 sty GUNO ; store guess pointer 000346 1 F0 30 beq FOUND ; yes stack finished 000348 1 A2 29 ldx #NUMA ; stacked guess 00034A 1 20 34 02 jsr UNPACK ; unpacked to NUMA 00034D 1 20 00 02 jsr MATCH ; compare new answer 000350 1 A4 41 ldy GUNO ; with old answers 000352 1 D9 02 00 cmp $0002,Y 000355 1 D0 05 bne NOGOOD ; does not fit 000357 1 C8 iny ; next stack entry 000358 1 C8 iny 000359 1 C8 iny 00035A 1 D0 E6 bne NEWINF ; try this entry 00035C 1 E6 3C NOGOOD: inc MYGU+1 ; increment 00035E 1 D0 08 bne NOTUP ; my guess as the last 000360 1 E6 3B inc MYGU ; one was no good 000362 1 A5 3B lda MYGU 000364 1 29 0F and #$0F 000366 1 85 3B sta MYGU 000368 1 A5 3C NOTUP: lda MYGU+1 ; if we count 00036A 1 C5 3E cmp STRT+1 ; round to the start 00036C 1 D0 CB bne NEWGU ; then somebody is 00036E 1 A5 3B lda MYGU ; cheating otherwise 000370 1 C5 3D cmp STRT ; try this new guess 000372 1 D0 C5 bne NEWGU 000374 1 A2 BC ldx #$BC ; you rotter 000376 1 D0 97 bne ENDOUT ; end of game 000378 1 A5 3B FOUND: lda MYGU ; put this good 00037A 1 99 00 00 sta $0000,Y ; on the stack 00037D 1 A5 3C lda MYGU+1 00037F 1 99 01 00 sta $0001,Y 000382 1 A2 C4 ldx #$C4 ;"......__“ to display 000384 1 20 83 02 jsr MSSAGE 000387 1 A2 3B ldx #MYGU ; my guess to display 000389 1 20 AE 02 jsr QOCTTD 00038C 1 20 54 02 jsr DISRAN ; use DISRAN to get answer 00038F 1 A5 3F lda ANSWER 000391 1 C9 40 cmp #GSEND ; 4 bulls ? I win 000393 1 D0 05 bne NOIWIN ; no not yet I don't 000395 1 A2 AD ldx #$AD ; message and end game 000397 1 4C 0F 03 jmp ENDOUT 00039A 1 A4 41 NOIWIN: ldy GUNO ; put answer on stack 00039C 1 99 02 00 sta $0002,Y 00039F 1 C8 iny ; update stack end 0003A0 1 C8 iny 0003A1 1 C8 iny 0003A2 1 84 40 sty GSEND 0003A4 1 4C EA 02 jmp YOUGO ; and round again 0003A7 1 ; 0003A7 1 00 50 79 77 READY: .byte $00,$50,$79,$77,$5E,$6E 0003AB 1 5E 6E 0003AD 1 00 00 06 00 IWIN: .byte $00,$00,$06,$00,$1C,$04,$54 0003B1 1 1C 04 54 0003B4 1 00 6E 3F 3E YOUWIN: .byte $00,$6E,$3F,$3E,$00,$1C,$04,$54 0003B8 1 00 1C 04 54 0003BC 1 00 39 76 79 MCHEAT: .byte $00,$39,$76,$79,$77,$78 0003C0 1 77 78 0003C2 1 00 00 BLANK: .byte $00,$00 0003C4 1 00 00 00 00 PROMPT: .byte $00,$00,$00,$00,$00,$00,$08,$08 0003C8 1 00 00 08 08 0003CB 1