diff --git a/MINESWEEPER-MOUSETEXT.dsk b/MINESWEEPER-MOUSETEXT.dsk new file mode 100644 index 0000000..099bd1f Binary files /dev/null and b/MINESWEEPER-MOUSETEXT.dsk differ diff --git a/MINESWEEPER-MOUSETEXT.s b/MINESWEEPER-MOUSETEXT.s new file mode 100644 index 0000000..91dd188 --- /dev/null +++ b/MINESWEEPER-MOUSETEXT.s @@ -0,0 +1,1152 @@ + 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: end-of-game state, so you can't keep marking cells after you lose +* elegant quit to prodos? +* +************************************************** + + + +************************************************** +* 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 +WAIT EQU $FCA8 +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 + +ROMINIT EQU $FB2F +ROMSETKBD EQU $FE89 +ROMSETVID EQU $FE93 + +ALTCHAR EQU $C00F ; enables alternative character set - mousetext + +BLINK EQU $F3 +SPEED EQU $F1 + +************************************************** +* START - sets up various fiddly zero page bits +************************************************** + + ORG $2000 ; PROGRAM DATA STARTS AT $2000 + + JSR ROMSETVID ;Init char output hook at $36/$37 + JSR ROMSETKBD ;Init key input hook at $38/$39 + JSR ROMINIT ;GR/HGR off, Text page 1 + + LDA #$01 + STA SPEED ; string/char output speed + STA ALTCHAR ; enable mousetext + LDA #$00 + STA BLINK ; blinking text? no thanks. + +DRAWBOARD JSR HOME + + + +************************************************** +* Draws the blank board borders, corners, borders +************************************************** + + +HLINES LDA #$01 ; start at column 2 + STA PLOTCOLUMN + +HLINESLOOP LDA #$4C ; - + STA CHAR + LDA #$01 ; row 1 + STA PLOTROW + JSR PLOTCHAR + + LDA #$12 + STA PLOTROW + LDA #$4C + STA CHAR + JSR PLOTCHAR + + INC PLOTCOLUMN + LDA PLOTCOLUMN + CMP #$12 ; goes to 16 + BMI HLINESLOOP +;/HLINES + + + + +VLINES LDA #$01 ; start at row 2 + STA PLOTROW +VLINESLOOP LDA #$5A ; : + STA CHAR + + LDA #$00 ; row 1 - left border + STA PLOTCOLUMN + JSR PLOTCHAR + + LDA #$12 + STA PLOTCOLUMN + LDA #$5F ; right box border + STA CHAR + JSR PLOTCHAR + + + INC PLOTROW + LDA PLOTROW + CMP #$12 ; goes to 16 + BMI VLINESLOOP +;/VLINES + + + + +************************************************** +* 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 #$40 ; $#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 #$05 ; SLIGHT DELAY + JSR WAIT + LDA SPEAKER ; 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 + + ; if current square is already solved, ignore + LDA ROW ; get ROW and COLUMN + CLC + ROL + ROL ; offset = ROW * 8 + COLUMN + ROL + CLC + ADC COLUMN + TAX + LDA PROGRESSORIGIN,X ; is progress already marked? + CLC + CMP #$FF + BEQ GOMARKMINE ; STILL UNMARKED + JSR BONK ; ignore the mark, keep as solved. + RTS + +GOMARKMINE 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 + + CMP #$64 + BNE PROGRESSGO + JMP YOUWIN + +PROGRESSGO 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 + JSR BONK ; BONK! + LDA #$52 ; FOUND BOMB. YOU LOSE. + JSR YOULOSE + RTS ; stop solving and return to waiting for key + +SOLVENOBOMB CLC + ADC #$10 ; add #$30 (becomes #) +SOLVECLEAR CLC + ADC #$20 + 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 + + LDA SOLVEORIGIN,X ; if solution is zero + BNE SOLVEDADJACENT ; mark adjacent squares as solved as well + JSR SOLVEADJACENTSQUARES +SOLVEDADJACENT RTS + + + +SOLVEBOMB LDA #$FF ; unmark as bomb + STA PROGRESSORIGIN,X ; + ; decrement bombs found + LDA SCORE ; decrement as decimal for printy printy. + SED + SEC + SBC #1 + CLD + STA SCORE + JSR PRINTSCORE + + LDA PROGRESS ; decrement progress as well, so it will increment properly on jump + SED + SEC + SBC #1 + CLD + STA PROGRESS + JSR PRINTPROGRESS + + JMP DRAWSOLVEDSQUARE ; go back and solve it as normal + + +;/DRAWSOLVEDSQUARE + + + + + + + + +SOLVEADJACENTSQUARE ; puts number in adjacent squares + JSR CLICK ; little sound clicks + LDA ROW ; get ROW and COLUMN + CLC + ROL + ROL ; offset = ROW * 8 + COLUMN + ROL + CLC + ADC COLUMN + TAX + LDA PROGRESSORIGIN,X ; check if it hasn't been solved yet, + CLC + BEQ SOLVECLEAR2 + CMP #$FF ; put the solution in the square, + BNE SOLVENOBOMB2 ; increment the progress + + LDA PROGRESS ; inc as decimal for printy printy. + SED + CLC + ADC #1 + CLD + STA PROGRESS + JSR PRINTPROGRESS + + LDA SOLVEORIGIN,X ; get SOLVEORIGIN + offset + STA PROGRESSORIGIN,X ; store progress + BEQ SOLVECLEAR2 + +SOLVENOBOMB2 CLC + ADC #$10 ; add #$30 (becomes #) +SOLVECLEAR2 CLC + ADC #$20 + 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 + +;/SOLVEADJACENTSQUARE + + + + +************************************************** +* solves adjacent squares if solved square is 0 +************************************************** +SOLVEADJACENTSQUARES + +SOLVERIGHT LDA COLUMN ; column + 1 unless col=7 + CLC + CMP #$07 + BEQ SOLVELEFT ; = 7 skip ahead + INC COLUMN + JSR SOLVEADJACENTSQUARE ; solve with col + 1 + + LDA ROW ; solve lower right + CMP #$07 + BEQ SOLVEUR + INC ROW + JSR SOLVEADJACENTSQUARE ; solve with col + 1, row + 1 + DEC ROW +SOLVEUR LDA ROW ; solve upper right + BEQ SOLVERIGHTDONE ; if ROW = 0, skip ahead + DEC ROW + JSR SOLVEADJACENTSQUARE ; solve with col + 1, row - 1 + INC ROW + +SOLVERIGHTDONE DEC COLUMN ; reset column + +SOLVELEFT LDA COLUMN + BEQ SOLVEDOWN ; if column = 0, skip ahead + DEC COLUMN ; solve with col - 1 + JSR SOLVEADJACENTSQUARE + + LDA ROW ; solve lower left + CMP #$07 + BEQ SOLVEUL + INC ROW + JSR SOLVEADJACENTSQUARE ; solve with col - 1, row + 1 + DEC ROW +SOLVEUL LDA ROW ; solve upper right + BEQ SOLVELEFTDONE ; if ROW = 0, skip ahead + DEC ROW + JSR SOLVEADJACENTSQUARE ; solve with col - 1, row - 1 + INC ROW + +SOLVELEFTDONE INC COLUMN ; reset column + +SOLVEDOWN LDA ROW + CLC + CMP #$07 + BEQ SOLVEUP + INC ROW + JSR SOLVEADJACENTSQUARE ; solve with row + 1 + DEC ROW ; reset row +SOLVEUP LDA ROW + BEQ ADJDONE ; if row = 0, skip ahead + DEC ROW ; solve with row - 1 + JSR SOLVEADJACENTSQUARE + INC ROW ; reset column + +ADJDONE + RTS +;/SOLVEADJACENTSQUARES + + + +************************************************** +* WIN or LOSE? +************************************************** + +WINNER ASC "YOU WIN! ",00 +LOSER ASC "YOU LOSE! ",00 +RESETLINE ASC "Press R to Reset. ",00 + + +YOUWIN LDA #$13 + STA CV ; jump down + JSR LEFTCOLUMN + LDY #>WINNER + LDA #LOSER + LDA #RESETLINE + LDA #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