/tictactoe.asm 2005-01-01 /************************* /* TIC - TAC - TOE PROGRAM /* /* WITH ROTE LEARNING /* /* ABILITIES /**************************************** ORG 001 000 /RESERVE PG 0 FOR MONITOR ENTRY TICTAC RADIX 10D /**************************************** /* CONSTANTS EQU LF 10 EQU FF 12 EQU CR 13 /* STATIC MEMORY ALLOCATION BOARD, DS 9 /NINE BYTE ARRAY FOR CURRENT BOARD POSITION /80 200 SQUARE OCCUPIED /40 100 FORCED MOVE /20 40 LOSING MOVE /10 20 PLAYER MOVE /0# MOVE NUMBER SBOARD, DS 9 /WORKING COPY OF SAVED GAME ENDMEM, DS 2 /POINTER TO AVAILABLE MEMORY MOVENO, DS 1 /MOVE NUMBER IN CURRENT GAME (1-9) PROW, DS 1 /CURRENT ROW PTR PCURSB, DS 2 /PTR TO HOME OF CURRENT SBOARD PNXTSB, DS 2 /PTR TO NEXT SAVED BOARD COUNT, DS 1 MSG1, DS 'YOUR MOVE? ' DB 0 XS, DS 1 /# OF PLAYER MOVES IN CURRENT ROW OS, DS 1 /# OF COMPUTER MOVES IN CURRENT ROW PATTRN, DS ' | | ' DS ' 1 | 2 | 3 ' DS ' | | ' DS '---+---+---' DS ' | | ' DS ' 4 | 5 | 6 ' DS ' | | ' DS '---+---+---' DS ' | | ' DS ' 7 | 8 | 9 ' DS ' | | ' PATOFF, DB 0 DB 4 DB 8 DB 44 DB 48 DB 52 DB 88 DB 92 DB 96 EX, DS 'X X X X X' /LARGE X OH, DS '0000 0000' /LARGE O SP, DS ' # ' /BLANKS MSG4, DS 'CATS GAME! ' DB 0 WINPTR, DS 1 /OFFSET TO ROW WITH WINNING MOVE LOSPTR, DS 1 /OFFSET TO ROW WITH FORCED MOVE /* 8 TRIPLETS OF WINNING OFFSETS ROWS, DB 1 2 3 DB 4 5 6 DB 7 8 9 DB 1 4 7 DB 2 5 8 DB 3 6 9 DB 1 5 9 DB 3 5 7 /**************************************** TICTAC, LHI ENDMEM/256 /INIT PTR TO DYNAMIC MEMORY LLI ENDMEM LAI MEMLST/256 LMA INL LAI MEMLST LMA NEWGAM, CAL INIT /INIT PER GAME VARIABLES NXTMVE, LHI MOVENO/256 LLI MOVENO LAM /MOVE NUMBER CPI 10 /GAME OVER? JTZ DRAW /YES CAL GETMOV /GET PLAYERS MOVE CAL SELECT /GET MACHINE MOVE CPI 1 /TEST RETURN CODE JTS NXTMVE /GAME STILL UNDECIDED JTZ IWIN /VICTORY SPEECH CPI 3 /DRAW? JTZ DRAW /YES CAL LOST /MACHINE LOSS LHI MSG6/256 LLI MSG6 CAL WTO /CONCESSION MESSAGE JMP DRAWM DRAW, LHI MSG4/256 LLI MSG4 CAL WTO /DRAW MESSAGE JMP DRAWM /* SUBROUTINES /* INITIALIZE PER GAME STORAGE /* CLEAR BOARD INIT, LHI BOARD/256 LLI BOARD LCI 9 XRA /CLEAR ACCUMULATOR INIT1, LMA INL DCC JFZ INIT1 LHI MOVENO/256 LLI MOVENO LMI 0 /NEW GAME LLI COUNT LMI 9 /LAST SQUARE # INIT2, LLM COUNT /SQUARE TO CLEAR CAL MARKSQ /CLEAR IT LLI COUNT LAM /GET COUNT SUI 1 /DECREMENT LMA /SAVE JFZ INIT2 /NOT DONE YET LLI PATTRN LBI 31H /'1' LCI 121 INIT3, LAM /GET CHAR CPI 23H /'#' JFZ INIT4 /MATCH? LMB /INSERT SQ # INB /NEXT # INIT4, INL /NEXT CHAR DCC /DONE? JFZ INIT3 /NOT YET LLI MOVENO LMI 1 /INITIAL MOVE NUMBER LAI FF /FORM FEED CAL PUTCHR /PAGE EJECT CAL DISPAT /DISPLAY INITIAL BOARD LHI MSG1/256 LLI MSG1 JMP WTO /DISPLAY 'YOUR MOVE?' /* READ VALID CHAR; UPDATE & DISPLAY BOARD /* IF FIRST HUMAN MOVE = 0 THEN SKIP MOVE GETMOV, CAL INPCHR /GET PLAYER MOVE SUI 30H /CONVERT TO NUMBER JTS GETMOV /INVALID DIGIT JTZ GFIRST /PLAYER PASSES CPI 10 /DIGIT? JFC GETMOV /NO LHI MOVENO/256 LLI MOVENO LBM /GET MOVE NUMBER LHI BOARD/256 LLI BOARD-1 ADL /INDEX INTO BOARD LLA /UPDATE PTR LAM /GET SQUARE STATUS ORA /SET FLAG BYTES JTS GETMOV /ALREADY TAKEN LAB /MOVE NUMBER ORI 90H /MARK PLAYER MOVE LMA /UPDATE BOARD JMP DISPMV /DISPLAY NEW BOARD GFIRST, LHI MOVENO/256 LLI MOVENO LAM /GET MOVE NUMBER CPI 1 /FIRST MOVE? JFZ GETMOV /TOO LATE RET /* UPDATE PATTERN AND DISPLAY /* CALLED WITH L->BOARD.SQUARE DISPMV, LAL /PTR TO SQUARE SUI BOARD /CONVERT TO OFFSET CAL MARKSQ /PUT X/O ON BOARD LHI MOVENO/256 LLI MOVENO LAM /CURRENT MOVE NUMBER ADI 1 /NEXT MOVE LMA /UPDATE COUNTER CAL DISPAT /DISPLAY BOARD XRA /SET RETURN CODE RET /* SELECT MACHINE MOVE /* THIS ROUTINE REQUIRES THAT ALL VARIABLES IT USES /* MUST BE ON THE SAME PAGE SELECT, LHI BOARD/256 /COMMON PAGE ADDRESS LLI COUNT LAI 8 /ROWS TO CHECK LMA /SAVE AS COUNT XRA /CLEAR ACCUMULATOR LLI WINPTR LMA /NO WINNING MOVE LLI LOSPTR LMA /NO FORCED MOVE LAI ROWS /FIRST ROW TO CHECK LLI PROW /CURRENT ROW PTR LMA /SAVE PTR SELEC1, LCI 3 /LENGTH OF ROW XRA /CLEAR ACCUMULATOR LLI XS /# OF MACHINE MOVES LMA /CLEAR LLI OS /# OF PLAYER MOVES LMA /CLEAR SELEC2, LLI PROW /CURRENT ROW POINTER LBM /CURRENT ROW INB /POINT TO NEXT LMB /UPDATE SAVED POINTER DCB /BUT USE CURRENT PTR LLB /POINT TO ROW ENTRY LBM /LOAD SQUARE NUMBER LAI BOARD-1 /0 BASED OFFSET ADB /INDEX INTO BOARD LLA /AND POINT TO IT LAM /SQUARE VALUE ORA /SET FLAGS JFS SELEC3 /OPEN SQUARE LLI XS /ASSUME PLAYER SQUARE NDI 10H /PLAYER MOVE? JFZ SELC3A /YES - GO COUNT PLAYER SQUARE LLI OS /NO - COUNT MACHINE MOVE SELC3A, LBM /CURRENT COUNT INB /INCREMENT COUNT LMB /UPDATE MEMORY /* SQUARE STILL OPEN SELEC3, DCC /REMAINING SQUARES IN ROW JFZ SELEC2 /NOT DONE YET LLI XS /POINT TO PLAYER COUNT LAM /GET COUNT CPI 3 /PLAYER WIN? JTZ TOOBAD /YES - MACHINE LOSES LLI OS /POINT TO MACHINE COUNT LAM /GET COUNT CPI 2 /CHANCE TO WIN? JFZ SELEC4 /NO LLI XS /BACK TO PLAYER COUNT LAM /GET COUNT CPI 0 /WINNING SQUARE AVAILABLE? JFZ SELEC4 /NO LLI PROW /PTR TO CURRENT ROW LAM /LOAD PTR LLI WINPTR /PTR TO WINING ROW LMA /MARK WIN JMP SELEC5 /GO CHECK NEXT ROW SELEC4, LLI XS /POINT TO PLAYER MOVES LAM /GET PLAYER COUNT CPI 2 /THREAT BY PLAYER JFZ SELEC5 /NO - CHECK NEXT ROW LLI OS /BACK TO MACHINE COUNT LAM /GET COUNT CPI 0 /BLOCKING SQUARE AVAILABLE? JFZ SELEC5 /NO - ALREADY BLOCKED LLI PROW /PTR TO CURRENT ROW LAM /GET ROW PTR LLI LOSPTR /FORCED MOVE PTR LMA /MARK FORCED MOVE SELEC5, LLI COUNT LBM /REMAINING ROWS DCB /ANY ROWS LEFT? LMB /UPDATE COUNT JFZ SELEC1 /YES - KEEP GOING LLI MOVENO LAM /GET MOVE NUMBER CPI 10 /GAME OVER? JFZ SELE5A /NO LAI 3 /DRAW RET SELE5A, LLI WINPTR LAM /GET WIN PTR ORA /EXIST? JFZ SELEC8 /YES LLI LOSPTR LAM /GET LOSS PTR ORA /EXIST? JFZ SELEC9 /YES CAL MEMORY /SEEN THIS POSITION BEFORE? JTC SELE5B /YES - USE IT LLI BOARD /NO - WE ARE ON OUR OWN SELE5B, LCI 9 /REMAINING SQUARES LAL /SQUARE PTR LLI PROW /ROW POINTER LMA /SAVE CURRENT ROW LLA /RESTORE CURRENT PTR SELEC6, LAM /GET CURRENT SQUARE ORA /UNFLAGGED? JTZ SELEC7 /YES - GO FOR IT INL /NEXT SQUARE DCC /ANY SQUARES LEFT? JFZ SELEC6 /YES - KEEP LOOKING JMP TOOBAD /NO - RESIGN /* MAKE CHOSEN MOVE SELEC7, CAL GETCNT /ENSURE L->BOARD.SQUARE LBL LLI MOVENO LAM /CURRENT MOVE NUMBER LLB ORI 80H /FLAG AS MACHINE MOVE LMA /SAVE AS MACHINE MOVE JMP DISPMV /GO DISPLAY MOVE /* WINNING MOVE SELEC8, LLA /RESTORE ROW PTR CAL FINDSQ CAL DISPMV /GO DISPLAY MOVE LAI 1 /SET RETURN CODE RET /* FORCED MOVE SELEC9, LLA /RESTORE ROW PTR CAL FINDSQ LBL LLI MOVENO LAM /MOVE NUMBER ORI 0C0H /FLAG AS FORCED MACHINE MOVE LLB LMA /UPDATE BOARD JMP DISPMV /DISPLAY MOVE TOOBAD, LAI 2 /SET RETURN CODE RET /* FIND EMPTY SQUARE IN LOGICAL ROW /* CALLED WITH L-> PAST END OF ROW POINTERS /* RETURNS L->SQUARE A = SQUARE VALUE /* USES E = SQ PTR FINDSQ, DCL /CALLED WITH PTR AT END OF ROW LEL /SAVE SQ PTR LAM /SQUARE NUMBER ADI BOARD-1 /INDEX INTO BOARD LLA /POINT TO SQUARE LAM /GET SQUARE ORA /EMPTY? RTZ /YES - DONE LLE /RESTORE SQ PTR JMP FINDSQ /TRY AGAIN /* CURRENT PTR MAY BE TO SAVED GAME /* RETURN CORRESPONDING PTR TO BOARD GETCNT, LAL /CURRENT PTR SUI SBOARD JTS GETCN1 /PTR IS OK ADI BOARD /BASE IS NOW BOARD LLI COUNT /USE AS SAVE LOC LMA /SAVE PTR LHI COUNT/256 LLI COUNT LLM /RESTORE BOARD PTR GETCN1, RET /* VICTORY SPEECH IWIN, LHI MSG2/256 LLI MSG2 CAL WTO /I WIN THIS ONE /* PLAY AGAIN REQUEST DRAWM, LHI MSG5/256 LLI MSG5 CAL WTOR /DO YOU WANT TO TRY AGAIN? ORI 20H /CONVERT TO LC CPI 79H /Y? JTZ NEWGAM /YES RET /RETURN TO LOADER /* WRITE TO CONSOLE AND READ INPUT WTOR, CAL WTO /* READ FROM KBD REPLY, JMP INPCHR /* WRITE STRING TO CONSOLE WTO, LAM /NEXT CHAR ORA /END OF STRING? RTZ /YES CAL PUTCHR CAL INCPTR /POINT TO NEXT JMP WTO /KEEP IT MOVING MSG2, DS 'I WIN THIS ONE' DB 0 MSG5, DB 10,13 DS 'DO YOU WANT TO TRY AGAIN?' DB 0 MSG6, DS 'YOU WIN THIS TIME' DB 0 /* MARK LAST MOVE AS LOSING, AND SAVE POSITION /* USES B: MOVE NUMBER C: COUNTER LOST, LHI MOVENO/256 LLI MOVENO LAM /MOVE NUMBER SUI 2 /PREVIOUS MACHINE MOVE LMA /SAVE LBA /CACHE LLI BOARD /CURRENT BOARD LOST1, LAM /GET SQUARE INL /ASSUME NO MATCH NDI 0FH /CLEAR FLAG BITS CPB /MATCH? JFZ LOST1 /NO - KEEP TRYING DCL /YES - POINT TO IT AGAIN LAM /REFRESH MOVE NDI 40H /WAS MOVE FORCED? JFZ LOST /YES - GO FURTHER BACK LAM /REFRESH MOVE ORI 20H /MARK AS LOSING LMA /UPDATE BOARD LLI BOARD /START OF BOARD LCI 9 /# OF SQUARES LOST2, LAM /GET MOVE NDI 0FH /CLEAR FLAGS CPB /RELEVENT MOVE? JTZ LOST3 /YES - EQUAL JTS LOST3 /YES - LESS LMI 0 /NO - CLEAR LOST3, INL /NEXT SQUARE DCC /DONE? JFZ LOST2 /NO - LOOP CAL MEMORY /FIND MATCHING POSITION JTC LOST4 /MATCH FOUND JMP ADDMEM /ADD TO MEMORY AND RETURN RET / MERGE LOSING MOVES FROM BOARD INTO SBOARD LOST4, LCI 9 /# OF SQUARES LHI BOARD/256 LDI BOARD LEI SBOARD LOST5, LLD /PTR TO BOARD LBM /GET SQUARE CONTENTS LAB NDI 040 /LOSING MOVE? JTZ LOST6 /NO LLE /PTR TO SBOARD LMB /MERGE LOSING MOVE LOST6, IND INE DCC /DONE? JFZ LOST5 /NO JMP UPDMEM /MOVE SBOARD TO MEMORY AND RETURN /* FIND BOARD IN MEMORY /* BOARDS MATCH IF CORRESPONDING SQUARES /* HAVE SAME PLAYER AND OCCUPIED FLAGS, OR /* ARE BOTH UNOCCUPIED. A LOSING MOVE IS /* MATCHED AS IF IT WERE UNOCCUPIED. MEMORY, LDI MEMLST/256 LEI MEMLST /START OF LIST LLI ENDMEM /END OF SAVED BOARDS /* CHECK FOR END OF LIST MEMOR1, LAM /END PAGE CPD /CURRENT PAGE JFZ MEMOR2 /FOUND LIST ENTRY INL LAM /END ADDR CPE /CURRENT ADDR RTZ /END OF LIST /* MOVE CANDIDATE TO SBOARD MEMOR2, LHI PCURSB/256 LLI PCURSB LMD INL LME LHI SBOARD/256 LLI SBOARD LCI 9 /BYTES TO MOVE CAL SWAPTR /HL -> SOURCE MEMOR3, LBM /GET DATA CAL SWAPTR /HL -> DEST LMB /STORE DATA CAL INCPTR /INCREMENT DEST PTR CAL SWAPTR /HL -> SOURCE CAL INCPTR /INCREMENT SOURCE PTR DCC /DONE? JFZ MEMOR3 /NO CAL SWAPTR /DE -> NEXT SOURCE LHI PNXTSB/256 LLI PNXTSB LMD INL LME /UPDATE NXT PTR /* COMPARE BOARD & SBOARD LLI BOARD LEI SBOARD LCI 9 MEMOR4, LBM /MOVE FROM BOARD LAB NDI 20H /LOSING MOVE? JTZ MEMOR5 /NO - CONTINUE LBI 0 /YES - NOTHING ELSE MATTERS JMP MEMOR6 /GO TEST SBOARD MEMOR5, LAB NDI 90H /CLEAR ALL BUT PLAYER AND OCCUPIED FLAGS LBA MEMOR6, LAL LLE LEA LDM /MOVE FROM BOARD LAD NDI 20H /LOSING MOVE? JTZ MEMOR7 /NO - CONTINUE LDI 0 /YES - NOTHING ELSE MATTERS JMP MEMOR8 /GO COMPARE SQUARES MEMOR7, LAD NDI 90H /CLEAR ALL BUT PLAYER AND OCCUPIED FLAGS LDA MEMOR8, LAB /RESULT FROM BOARD CPD /RESULT FROM SBOARD JTZ MEMOR9 /OK - GO CHECK NEXT SQUARES /* BOARDS DO NOT MATCH - GO GET ANOTHER LHI PNXTSB/256 LLI PNXTSB LDM INL LEM LLI ENDMEM /END OF SAVED BOARDS JMP MEMOR1 /GO FETCH NEXT SAVED BOARD /* DONE WITH THIS BOARD? MEMOR9, INL INE DCC /DONE? JFZ MEMOR4 /NO LLI SBOARD /YES JMP SETC /RETURN WITH CARRY SET /* COPY SBOARD TO PCURSB->STORAGE /* USES D:E -> STORAGE, HL -> BOARD, B = DATA, C = COUNTER UPDMEM, LHI PCURSB/256 LLI PCURSB LDM /DYNAMIC STORAGE PAGE INL LEM /DYNAMIC STORAGE ADDR LHI SBOARD/256 LLI SBOARD CAL MOVMEM RET /* COPY BOARD TO ENDMEM->STORAGE /* USES D:E -> STORAGE, HL -> BOARD, B = DATA, C = COUNTER ADDMEM, LHI ENDMEM/256 LLI ENDMEM LDM /DYNAMIC STORAGE PAGE INL LEM /DYNAMIC STORAGE ADDR LHI BOARD/256 LLI BOARD CAL MOVMEM LHI ENDMEM/256 LLI ENDMEM LMD INL LME /UPDATE STORAGE PTR RET MOVMEM, LCI 9 /BYTES TO MOVE MOVME1, LBM /DATA BYTE CAL SWAPTR /SWAP HL WITH DE, USING A LMB /STORE DATA CAL INCPTR /INCREMENT DEST PTR CAL SWAPTR /UNDO SWAP CAL INCPTR /INCREMENT SOURCE PTR DCC /DONE? JFZ MOVME1 /NO RET /* DISPLAY BOARD ON CONSOLE DISPAT, LAI FF CAL PUTCHR LHI PATTRN/256 LLI PATTRN LDI 11 /ROWS TO PRINT DISPA1, LCI 11 /COLUMNS PER ROW DISPA2, LAM /CHAR TO PRINT CAL PUTCHR /PRINT TO CONSOLE INL /POINT TO NEXT CHAR DCC /DONE WITH LINE? JFZ DISPA2 /KEEP PRINTING LAI CR /CARRIAGE RETURN CHAR CAL PUTCHR LAI LF /NEW LINE CHAR CAL PUTCHR DCD /DONE? JFZ DISPA1 /NOT YET LHI BOARD/256 /RESTORE COMMON DATA PAGE RET /* MARK MOVE ON PATTERN A: 1-9 MARKSQ, LBA /OFFSET TO BOARD LLI MOVENO /POINT TO MOVE NUMBER LAM /GET NUMBER ORA /SET FLAGS JFZ MARKS1 /GAME HAS STARTED LEI SP /RESET STRING JMP MARKS2 /CONTINUE MARKS1, LEI EX /ASSUME ODD MOVE NDI 1 /ODD? JFZ MARKS2 /YES - CONTINUE LEI OH /NO MARKS2, LAI PATOFF /SQUARE OFFSET ARRAY ADB /SELECT SQUARE LLA /PTR INTO PATTRN LAM /GET OFFSET ADI PATTRN /ADD TO BASE LLA /POINT INTO PATTRN LDI 3 /NUMBER OF ROWS MARKS3, LCI 3 /NUMBER OF COLUMNS MARKS4, LAL LLE LBM /CHAR TO MOVE LLA LMB /STORE CHAR INL INE DCC /MORE COLS? JFZ MARKS4 /YES LAL ADI 8 LLA /STEP TO NEXT ROW DCD /DONE? JFZ MARKS3 /NO RET /* SYSTEM SUBROUTINES INPCHR, INP 0 /GET INPUT STATUS NDI 001 /KBD READY? JTZ INPCHR /NO INP 1 /READ KBD LBA /SAVE INPUT CHAR LAI 376Q /PORT 11 RESET MASK OUT 10Q /ACK KBD LAB /RESTORE INPUT RET PUTCHR, OUT 11Q /WRITE TO DISPLAY RET INCPTR, INL /NEXT ADDR RFZ /SAME PAGE INH /NEXT PAGE RET SETC, LAI 80H RLC /SET CARRY RET SWAPTR, LAD LDH LHA LAE LEL LLA RET MEMLST, END /* DYNAMIC MEMORY ALLOCATIONS