diff --git a/MINESWEEPER.s b/MINESWEEPER.s new file mode 100644 index 0000000..2fe5464 --- /dev/null +++ b/MINESWEEPER.s @@ -0,0 +1,978 @@ + DSK MS + +************************************************** +* minesweeper +* +* test board +* +* 0 0 0 0 0 0 0 0 +* 0 0 0 0 0 0 0 0 +* 0 0 0 0 0 0 0 0 +* 0 0 0 1 0 0 0 0 = 0x10 +* 0 0 0 0 1 0 0 0 = 0x08 +* 0 0 0 0 0 0 0 0 +* 0 0 0 0 0 0 0 0 +* 0 0 0 0 0 0 0 0 +* +* solve result: +* +* 0 0 0 0 0 0 0 0 +* 0 0 0 0 0 0 0 0 +* 0 0 1 1 1 0 0 0 +* 0 0 1 X 2 1 0 0 +* 0 0 1 2 X 1 0 0 +* 0 0 0 1 1 1 0 0 +* 0 0 0 0 0 0 0 0 +* 0 0 0 0 0 0 0 0 +* +************************************************** + +************************************************** +* +* TO DO: win message when progress = 64 and all bombs marked +* lose message when clearing a cell with bomb +* sounds? +* +************************************************** + + + +************************************************** +* Variables +************************************************** + +SOLVEORIGIN EQU $9100 ; 'solved' board to reveal +PROGRESSORIGIN EQU $9200 ; revealed squares +BOMBLOC EQU $FC +ROWBYTE EQU $FD +ROW EQU $FA ; row/col in board +COLUMN EQU $FB +PLOTROW EQU $FE ; row/col in text page +PLOTCOLUMN EQU $FF +]ROWS = #$8 +]COLUMNS = #$8 +CHAR EQU $FC ; char to plot +STRLO EQU $EB ; string lo/hi for printing +STRHI EQU $EC +SCORE EQU $ED ; bombs found +PROGRESS EQU $EE ; cells cleared +BOMBS EQU $EF ; total bombs + +************************************************** +* Apple Standard Memory Locations +************************************************** +CLRLORES EQU $F832 +LORES EQU $C050 +TXTSET EQU $C051 +MIXCLR EQU $C052 +MIXSET EQU $C053 +TXTPAGE1 EQU $C054 +TXTPAGE2 EQU $C055 +KEY EQU $C000 +C80STOREOFF EQU $C000 +C80STOREON EQU $C001 +STROBE EQU $C010 +SPEAKER EQU $C030 +VBL EQU $C02E +RDVBLBAR EQU $C019 ;not VBL (VBL signal low + +RAMWRTAUX EQU $C005 +RAMWRTMAIN EQU $C004 +SETAN3 EQU $C05E ;Set annunciator-3 output to 0 +SET80VID EQU $C00D ;enable 80-column display mode (WR-only) +HOME EQU $FC58 ; clear the text screen + +CH EQU $24 ; cursor Horiz +CV EQU $25 ; cursor Vert +VTAB EQU $FC22 ; Sets the cursor vertical position (from CV) +COUT EQU $FDED ; Calls the output routine whose address is stored in CSW, + ; normally COUTI +STROUT EQU $DB3A ;Y=String ptr high, A=String ptr low + + +************************************************** +* START +************************************************** + + ORG $1000 ; PROGRAM DATA STARTS AT $1000 + +************************************************** +* Draws the blank board borders, corners, borders +************************************************** +DRAWBOARD JSR HOME + +CORNERS LDA #$01 + STA PLOTROW + STA PLOTCOLUMN + LDA #$2E ; . + STA CHAR + JSR PLOTCHAR + + LDA #$11 + STA PLOTCOLUMN + JSR PLOTCHAR + + LDA #$27 + STA CHAR ; ' + LDA #$11 + STA PLOTROW + STA PLOTCOLUMN + JSR PLOTCHAR + + LDA #$01 + STA PLOTCOLUMN + JSR PLOTCHAR +;/CORNERS + +HLINES LDA #$02 ; start at column 2 + STA PLOTCOLUMN + LDA #$2D ; - + STA CHAR + +HLINESLOOP LDA #$01 ; row 1 + STA PLOTROW + JSR PLOTCHAR + +HROWSLOOP INC PLOTROW + INC PLOTROW ; row 3, 5, ... + JSR PLOTCHAR + LDA PLOTROW + CMP #$10 ; goes to 17 + BMI HROWSLOOP +;/HROWSLOOP + INC PLOTCOLUMN + LDA PLOTCOLUMN + CMP #$11 ; goes to 16 + BMI HLINESLOOP +;/HLINES + +VLINES LDA #$02 ; start at column 2 + STA PLOTROW + LDA #$3A ; : + STA CHAR + +VLINESLOOP LDA #$01 ; row 1 + STA PLOTCOLUMN + JSR PLOTCHAR + +VCOLUMNSLOOP INC PLOTCOLUMN ; row 2, 4, ... + INC PLOTCOLUMN ; row 3, 5, ... + JSR PLOTCHAR + LDA PLOTCOLUMN + CMP #$11 ; goes to 16 + BMI VCOLUMNSLOOP +;/VCOLUMNSLOOP + + INC PLOTROW + LDA PLOTROW + CMP #$11 ; goes to 16 + BMI VLINESLOOP +;/VLINES + +* + ROW*2 + 1, COLUMN*2 + 1 + +PLUSES + + LDA #$03 ; starts at 3,3 + STA PLOTROW + LDA #$2B ; + + STA CHAR + +PLUSLOOP + LDA #$03 ; starts at 3,3 + STA PLOTCOLUMN +PLUSCOLS + JSR PLOTCHAR + INC PLOTCOLUMN + INC PLOTCOLUMN + LDA PLOTCOLUMN + CMP #$10 + BMI PLUSCOLS +;/PLUSCOLS + INC PLOTROW + INC PLOTROW + LDA PLOTROW + CMP #$10 + BMI PLUSLOOP +;/PLUSLOOP + +************************************************** +* sets up solving matrix, resets scoreboard +* each cell = 1 byte +************************************************** +SETUP LDX #$0 + STX BOMBS + STX PROGRESS + STX SCORE +SETUPLOOP LDA #$0 + STA SOLVEORIGIN,X ; set byte at origin + x = 0 + LDA #$FF + STA PROGRESSORIGIN,X ; progress reset - FF = unsolved + INX + CPX ]ROWS*]COLUMNS ; $#40 = hex 64 = 8x8 + BNE SETUPLOOP +;/setuploop + +SETUPBOARD + LDX #$8 ; X = 8 +ROWLOOP3 ; (ROW 7 to 0) + DEX + STX ROW + LDA #$0 + STA BOARDORIGIN,X ; set byte at BOARDORIGIN,x 0 + + LDY #$8 ; start columnloop (COLUMN 0 to 7) +COLUMNLOOP3 CLC ; clear CARRY to 0 + DEY + STY COLUMN ; store column for later retrieval + + LDA $C030 ; get byte, pseudorandom source? + ROL ; random bit into Carry + ROL ; random bit into Carry + ROL BOARDORIGIN,X ; random bit into row byte + + TYA ; last COLUMN? + BNE COLUMNLOOP3 ; loop +; /columnloop3 + + TXA ; current row into Accumulator + ; last ROW? + BNE ROWLOOP3 ; loop + +;/rowloop3 +;/SETUPBOARD + + + +************************************************** +* solves the board +************************************************** +SOLVEBOARD + LDX #$8 ; X = 8 +ROWLOOP ; (ROW 8 to 0) + DEX + STX ROW + LDA BOARDORIGIN,X ; puts byte at ROW into accumulator + STA ROWBYTE ; byte is in ROWBYTE + +; start columnloop (COLUMN 0 to 7) + LDY #$8 +COLUMNLOOP CLC ; clear CARRY to 0 + DEY + STY COLUMN ; store column for later retrieval + ROL ROWBYTE ; rotate accumulator bit into CARRY + BCC NOBOMB ; if CARRY = 0 + JSR FOUNDBOMB ; if CARRY > 0 + +NOBOMB ; do nothing. + + TYA ; last COLUMN? + BNE COLUMNLOOP ; loop +; /columnloop + + TXA ; current row into Accumulator + ; last ROW? + BNE ROWLOOP ; loop + +;/rowloop + + +************************************************** +* draws the blank squares to be solved +* +************************************************** +; FOR EACH ROW/COLUMN + + LDA #$8 ; X = 8 + STA ROW +ROWLOOP2 ; (ROW 8 to 0) + DEC ROW + +; start columnloop (COLUMN 0 to 7) + LDA #$8 + STA COLUMN +COLUMNLOOP2 DEC COLUMN + + JSR DRAWSQUARE + + LDA COLUMN ; last COLUMN? + BNE COLUMNLOOP2 ; loop +; /columnloop2 + + LDA ROW ; last ROW? + BNE ROWLOOP2 ; loop + +;/rowloop2 + + +************************************************** +* writes instructions, scoreboard +************************************************** + + JSR INSTRUCTIONS + JSR PRINTSCORE + JSR PRINTBOMBS + JSR PRINTPROGRESS + + +************************************************** +* MAIN LOOP +* waits for keyboard input, moves cursor, etc +************************************************** + +MAIN LDA #$0 ; highlight 0,0 to start with + STA ROW + STA COLUMN ; set row/column + JSR HILITESQUARE ; + +MAINLOOP LDA KEY ; check for keydown + CMP #$A0 ; space bar + BEQ GOTSPACE + CMP #$C9 ; I + BEQ GOTUP + CMP #$CB ; K + BEQ GOTDOWN + CMP #$CA ; J + BEQ GOTLEFT + CMP #$CC ; L + BEQ GOTRIGHT + CMP #$CD ; M + BEQ GOTMINE + CMP #$D2 ; R + BEQ GOTRESET + CMP #$9B ; ESC + BEQ END ; exit on ESC? + + BNE MAINLOOP ; loop until a key + + +GOTSPACE JSR SPACE + JMP MAINLOOP ; back to waiting for a key +GOTUP JSR UP + JMP MAINLOOP ; back to waiting for a key +GOTDOWN JSR DOWN + JMP MAINLOOP ; back to waiting for a key +GOTLEFT JSR LEFT + JMP MAINLOOP ; back to waiting for a key +GOTRIGHT JSR RIGHT + JMP MAINLOOP ; back to waiting for a key +GOTMINE JSR MARKMINE + JMP MAINLOOP +GOTRESET STA STROBE + JSR RESET + JMP MAINLOOP +END JSR HOME + RTS ; END + + + +MARKMINE STA STROBE ; solve current square and move to next space + + JSR DRAWMINE ; solve square + + JMP NEXTSQUARE +;/MARKMINE + + +SPACE STA STROBE ; solve current square and move to next space + + JSR DRAWSOLVEDSQUARE ; solve square if not already solved + ; highlight next square +NEXTSQUARE INC COLUMN ; increment column + LDA COLUMN + CMP #$8 + BMI HILITENEXTSQUARE + INC ROW ; if column = 8, column = 0, row ++ + LDA #$0 + STA COLUMN + + LDA ROW ; if row = 8, row = 0 + CMP #$8 + BMI HILITENEXTSQUARE + LDA #$0 + STA ROW + +HILITENEXTSQUARE + JSR HILITESQUARE ; + RTS +;/GOTSPACE + +UP STA STROBE ; + JSR DESELECTSQUARE ; resolve current square from progress + + LDA ROW ; if row = 0, then row = 7 + BNE GOTUPROW + LDA #$08 + STA ROW + +GOTUPROW DEC ROW ; else, DEC ROW + ; highlight current square + JSR HILITESQUARE ; + RTS +;/GOTUP + +DOWN STA STROBE ; + JSR DESELECTSQUARE ; resolve current square from progress + + LDA ROW ; if row = 7, then row = 0 + CMP #$07 + BMI GOTDOWNROW + LDA #$FF + STA ROW + +GOTDOWNROW INC ROW ; else, INC ROW + ; highlight current square + JSR HILITESQUARE ; + RTS +;/GOTDOWN + +LEFT STA STROBE ; solve current square and move to previous space + JSR DESELECTSQUARE ; resolve current square from progress + ; highlight prev square + DEC COLUMN ; decrement column + LDA COLUMN + CMP #$FF + BNE LEFTNEXTSQUARE + DEC ROW ; if column = 0, column = 7, row ++ + LDA #$7 + STA COLUMN + + LDA ROW ; if row = 0, row = 8 + CMP #$FF + BNE LEFTNEXTSQUARE + LDA #$7 + STA ROW + +LEFTNEXTSQUARE + JSR HILITESQUARE ; + RTS +;/GOTLEFT + +RIGHT STA STROBE ; solve current square and move to next space + JSR DESELECTSQUARE ; resolve current square from progress + ; highlight next square + INC COLUMN ; increment column + LDA COLUMN + CMP #$8 + BMI RIGHTNEXTSQUARE + INC ROW ; if column = 8, column = 0, row ++ + LDA #$0 + STA COLUMN + + LDA ROW ; if row = 8, row = 0 + CMP #$8 + BMI RIGHTNEXTSQUARE + LDA #$0 + STA ROW + +RIGHTNEXTSQUARE + JSR HILITESQUARE ; + RTS +;/GOTRIGHT + +************************************************** +* subroutines +* +************************************************** + +************************************************** +* writes number of bombs to find, etc +************************************************** +PRINTBOMBS ; move cursor to 0x14,0x15, VTAB, LDA BOMBS, JSR FDDA + LDA #$14 + STA CV + LDA #$15 + STA CH + JSR VTAB + LDA BOMBS + JSR $FDDA ; prints HEX of Accumulator + RTS + + +PRINTSCORE ; prints number of bombs marked + LDA #$14 + STA CV + LDA #$0F + STA CH + JSR VTAB + LDA SCORE + JSR $FDDA ; prints HEX of Accumulator + RTS + +PRINTPROGRESS ; prints number of bombs marked + LDA #$15 + STA CV + LDA #$11 + STA CH + JSR VTAB + LDA PROGRESS + JSR $FDDA ; prints HEX of Accumulator + RTS + +************************************************** +* writes instructions and scoreboard +************************************************** +HELLOWORLD ASC "MINESWEEPER",00 ; set to ascii for message +LINE1 ASC "By Charles Mangin", 00 +LINE2 ASC "I, J, K, L to move",00 +LINE3 ASC "SPC to clear cell",00 +LINE4 ASC "M to mark a mine",00 +LINE5 ASC "ESC=QUIT R=RESET",00 +LINE6 ASC "Mines found: 0 of",00 +LINE7 ASC "Cells cleared: 0 of 64",00 + +INSTRUCTIONS LDA #$1 + STA CV ; get screen address at row 2, column 20 + + JSR RIGHTCOLUMN + LDY #>HELLOWORLD + LDA #LINE1 + LDA #LINE2 + LDA #LINE3 + LDA #LINE4 + LDA #LINE5 + LDA #LINE6 + LDA #LINE7 + LDA #= F0, found a bomb + BMI SOLVENOBOMB + LDA #$52 ; FOUND BOMB. YOU LOSE. + +SOLVENOBOMB CLC + ADC #$30 ; add #$30 (becomes #) + STA CHAR ; store as CHAR + LDA ROW + CLC + ADC #$01 ; zero-based to 1-based + ROL ; ROW * 2, COLUMN * 2 + STA PLOTROW + LDA COLUMN + CLC + ADC #$01 ; zero-based to 1-based + ROL ; ROW * 2, COLUMN * 2 + STA PLOTCOLUMN + JSR PLOTCHAR + RTS + +SOLVEBOMB LDA #$FF ; unmark as bomb + STA PROGRESSORIGIN,X ; + ; decrement bombs found + LDA SCORE ; inc as decimal for printy printy. + SED + SEC + SBC #1 + CLD + STA SCORE + JSR PRINTSCORE + + JMP DRAWSOLVEDSQUARE ; go back and solve it as normal + + +;/DRAWSOLVEDSQUARE + + + +************************************************** +* solves squares for adjacent bombs, updates solved map, increments bomb count +************************************************** +FOUNDBOMB ; how many have we found? + LDA BOMBS ; inc as decimal for printy printy. + SED + CLC + ADC #1 + CLD + STA BOMBS + + CLC ; clear the carry in case we found a bomb + TXA ; accum = ROW + ROL ; + ROL ; + ROL ; accum = ROW * 8 + CLC + STY BOMBLOC ; BOMBLOC = COLUMN + ADC BOMBLOC ; accum += COLUMN + STA BOMBLOC ; BOMBLOC = (row*8) + column = offset from origin + + LDA #$0F ; F0 doesn't want to work? + LDX BOMBLOC ; X = bomb offset + STA SOLVEORIGIN,X ; + + DEX + + TYA ; Does Y = 0 + CLC + BEQ MINUSSONE ; if == 0, then skip the - 1 + + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE - 1) + +MINUSSONE INX + INX + + SEC + SBC #$7 ; does y = 8 + BEQ PLUSONE + + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE + 1) + +PLUSONE TXA ; accumulator holds offset + 1 + SEC + SBC #$A ; subtract 10 from offset + TAX ; back to X + + TYA ; Does Y = 0 + CLC + BEQ MINUSNINE ; if == 0, then skip the - 9 + + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE - 9) +MINUSNINE INX + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE - 8) + INX + + SEC + SBC #$7 ; does y = 8 + BEQ MINUSSEVEN + + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE - 7) + +MINUSSEVEN TXA ; accumulator holds offset - 7 + CLC + ADC #$E ; add 15 + TAX ; back to X + + TYA ; Does Y = 0 + CLC + BEQ PLUSSEVEN ; if == 0, then skip the + 7 + + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE + 7) +PLUSSEVEN INX + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE + 8) + + TYA + SEC + SBC #$7 ; does y = 8 + BEQ PLUSNINE + + INX + INC SOLVEORIGIN,X ; INC (byte at BOMBBYTE + 9) + +PLUSNINE LDY COLUMN + LDX ROW + RTS + +;/FOUNDBOMB + + +************************************************** +* prints one CHAR at PLOTROW,PLOTCOLUMN +************************************************** +PLOTCHAR + LDY PLOTROW + LDA LoLineTableL,Y + STA $0 + LDA LoLineTableH,Y + STA $1 ; now word/pointer at $0+$1 points to line + LDY PLOTCOLUMN + LDA CHAR ; this would be a byte with two pixels + STA ($0),Y + RTS +;/PLOTCHAR + + +RESET JMP DRAWBOARD + + + +************************************************** +* Data Tables +* +************************************************** + +BOARDORIGIN HEX 80,00,00,10,08,00,00,01 ; sets up the board + + + +************************************************** +* Lores/Text lines +************************************************** +Lo01 equ $400 +Lo02 equ $480 +Lo03 equ $500 +Lo04 equ $580 +Lo05 equ $600 +Lo06 equ $680 +Lo07 equ $700 +Lo08 equ $780 +Lo09 equ $428 +Lo10 equ $4a8 +Lo11 equ $528 +Lo12 equ $5a8 +Lo13 equ $628 +Lo14 equ $6a8 +Lo15 equ $728 +Lo16 equ $7a8 +Lo17 equ $450 +Lo18 equ $4d0 +Lo19 equ $550 +Lo20 equ $5d0 +* the "plus four" lines +Lo21 equ $650 +Lo22 equ $6d0 +Lo23 equ $750 +Lo24 equ $7d0 + +LoLineTable da Lo01,Lo02,Lo03,Lo04 + da Lo05,Lo06,Lo07,Lo08 + da Lo09,Lo10,Lo11,Lo12 + da Lo13,Lo14,Lo15,Lo16 + da Lo17,Lo18,Lo19,Lo20 + da Lo21,Lo22,Lo23,Lo24 +** Here we split the table for an optimization +** We can directly get our line numbers now +** Without using ASL +LoLineTableH db >Lo01,>Lo02,>Lo03 + db >Lo04,>Lo05,>Lo06 + db >Lo07,>Lo08,>Lo09 + db >Lo10,>Lo11,>Lo12 + db >Lo13,>Lo14,>Lo15 + db >Lo16,>Lo17,>Lo18 + db >Lo19,>Lo20,>Lo21 + db >Lo22,>Lo23,>Lo24 +LoLineTableL db