HomeArticlesProjectsBlogContact
Articles
Tic Tac Toe Page 4
Colin Mitchell
Colin Mitchell
Make sure to subscribe to our newsletter and be the first to know the news.

Table Of Contents

01
THE PROGRAM EXPLAINED
02
TIC TAC TOE PROGRAM
03
LET'S BEGIN . . .
04
STALEMATE

THE PROGRAM EXPLAINED

Page 4

Go to: Page 1 Page 2 Page 3


TIC TAC TOE PROGRAM

The Tic Tac Toe program needs to be explained in a number of different ways. It’s really a highly sophisticated program, but if you read our explanations, you will be able to see how it has been put together.
The operation and performance of each instruction needs to be known. This is called your “home-work.” You need to “read” each of the instructions and know what they are “saying.” These details have already been covered in our PIC Programming Course, and you should read this course or at least read the INSTRUCTION SET before starting on this part of the Tic Tac Toe program.
The Instruction Set for the PIC16F84A is identical to the PIC16F628.
The next thing that needs to be explained is the overall operation of each routine. That’s what we have done in this section.
You also need to know why the programmer chose each instruction, as well as the “hidden” elements of the routines such as the value of the “Computer Piece” and “Player Piece.”

LET’S BEGIN …

The micro starts at address location 000. To get it to start at this location, ORG 00 is the first instruction. It is really a “pseudo” instruction. It does not tell the micro to do anything, it tells the assembler to place the next instruction (MOVLW 07) at address 000. ORG 00 does not appear in the final .hex listing - it has already done its job.
MOVLW 07 disables the comparators in the PIC16F628. This makes the PIC16F628 very similar to a PIC16F84A as have produced a program to show how to migrate from an ‘F84A to a ‘628
The only differences between the two micro’s (for the moment) are: internal 4MHz oscillator and 3 extra in/out lines. This means the Tic Tac Toe project does not need external oscillator components and 3 more lines of PortA are available (RA5, RA6 and RA7 - of which we have used RA6 and RA7).
The remaining instructions in SetUp, determine the in/out situation for each of the lines of port A and B (via the TRIS registers - the registers that are directly below - figuratively speaking - PortA and PortB and can be found as file 05 and file 06 - but in Bank 1), clear the flag file (2F) and clear the output lines in files 05 and 06 - these files are in bank 0 - the bank where your program is placed.
The last instruction in SetUp sends the micro to Attract Mode. We deal with Attract mode on another page.

         ORG 0          ;This is the start of memory for the program.
SetUp    MOVLW 07       ;Disable the comparators
         MOVWF 1Fh      ;File 1F is the CMCON file
         BSF 03,5       ;Go to Bank 1
         CLRF 06        ;Make all port B output
         MOVLW 18h      ;Load W with 0001 1000
         MOVWF 05       ;Make RA0,1,2,6,7 output and RA3, RA4 input
         BCF 03,5       ;Go to Bank 0 - the program memory area.
         CLRF 2F        ;Clear the button-press file
         CLRF 05        ;Clear the output lines of PortA
         CLRF 06        ;Blank the output
         GOTO Att

Att sub-routine calls a Delay routine that contains an instruction to go to Preload when either button is pressed.
The program below shows Preload sub-routine. Preload puts “5” into file 30h and clears the 9 files for the display. Read below for the purpose of files 30h and 3Ah. The following diagram shows the board-files and the two “hidden” files:


Tic Tac Toe files for the “board”

When either button is pressed during Attract Mode, the micro goes to Tic Tac Toe section of the program. The loop routine for Tic Tac Toe is Main. It is accessed via Preload sub-routine.
The effect you will see on the Tic Tac Toe project is this: The display goes blank. When button “A” is pressed, a flashing orange cursor starts at the top left square. Each time button “A” is pressed, it increments across each row until it reaches the bottom right-hand square. It then disappears and starts at the top left square.
When button “B” is pressed, the flashing cursor is turned into a red “Player” piece. The micro then executes a number of sub-routines and produces a green “Computer” piece on the display.
Main is a loop routine similar to a RASTER on a TV. It takes information from 9 files (31h, 32h, 33h, 34h, 35h, 36h, 37h, 38h, and 39h) and displays it by showing the top row, middle row and bottom row. This is repeated at a rapid rate so that all rows appear to be illuminated at the same time. This is called SCANNING or MULTIPLEXING.
The cursor actually starts in file 30h. This file is not displayed and thus the cursor is “hidden.” At the end of the display it is transferred to file 3A and thus it is removed from the display. The program returns the cursor to file 30h.
Main is not an “intelligent” routine. It’s a simple “display” routine. It simply shows whatever is contained in the 9 display files.
A file can contain one of four values.
If it contains the value 01, bit0 is set and this represents the player. When bit0 is set, the red element of a LED will be illuminated, via Main sub-routine. We will see in a moment, how this is done.
If it contains the value 04, bit2 is set and this represents the computer. When bit2 is set, the green element of a LED will be illuminated, via Main sub-routine.
If it contains the value 05, bits 0and 2 are set and this represents the cursor. The LED will display “orange.”
If it contains the value 08, bit3 is set and this represents the “hidden cursor.”
On page 2 of this project, the activation of the display is explained. The six elements of the three top LEDs are taken to 6 lines of port B and when the corresponding “sinking” transistor is turned on, the LEDs will illuminate.
A table for the 64 combinations is also included and this shows how the different patterns are produced.
The display routine in Main uses bits 0 and 2 of the first three files to turn on the red and green emitters in top 3 LEDs. The sinking transistor is turned on and the top row is displayed. This is repeated with the middle and bottom rows.
To make the cursor flash, the program needs to know where it is located. When the cursor is visible on the display, it has the value 05. This represents the red and green crystals in a LED. The program turns on the top, middle and bottom rows for 20h loops (thirty-two loops)
After 20h loops, the micro goes to Main 19 where it executes ten loops, looking for 05, by testing bits 0 and 2. When 05 is found, it puts 08 into the file and returns to Main. If 05 is not found, the micro looks for 08. When 08 is found, it puts 05 in the file and returns to Main. This produces a flashing cursor with an equal on/off ratio. The cursor value is also changed, even when it is hidden in file 30h.

Preload  MOVLW 05          ;Put cursor into "ready" file
         MOVWF 30h
         CLRF 31h
         CLRF 32h
         CLRF 33h
         CLRF 34h
         CLRF 35h
         CLRF 36h
         CLRF 37h
         CLRF 38h
         CLRF 39h
         CLRF 3Ah
         BTFSS 05,3        ;Make sure button "A" is released
         GOTO Preload
         BTFSS 05,4        ;Make sure button "B" is released
         GOTO Preload
         GOTO Main         ;Go to Main


                           ;Player Value = 01 = red
                           ;Computer Value = 04 = green
                           ;Cursor = 05

Main     MOVLW 20h         ;Loops of Main for flashing cursor
         MOVWF 22h         ;File to decrement
MainA    BTFSC 2F,0        ;ButtonA pressed first time?
         GOTO MainB
         BTFSS 05,3        ;Test for ButtonA
         CALL ButtonA
MainB    BTFSC 2F,1        ;ButtonB pressed first time?
         GOTO MainC
         BTFSS 05,4        ;Test for ButtonB
         CALL ButtonB
MainC    BTFSS 31h,0
         GOTO Main1
         BSF 06,5
Main1    BTFSS 31h,2
         GOTO Main2
         BSF 06,4
Main2    BTFSS 32h,0
         GOTO Main3
         BSF 06,3
Main3    BTFSS 32h,2
         GOTO Main4
         BSF 06,2
Main4    BTFSS 33h,0
         GOTO Main5
         BSF 06,1
Main5    BTFSS 33h,2
         GOTO Main6
         BSF 06,0
Main6    BSF 05,0
         CALL Del1
         BCF 05,0
         CLRF 06
         CALL Del1

         BTFSS 34h,0
         GOTO Main7
         BSF 06,5
Main7    BTFSS 34h,2
         GOTO Main8
         BSF 06,4
Main8    BTFSS 35h,0
         GOTO Main9
         BSF 06,3
Main9    BTFSS 35h,2
         GOTO Main10
         BSF 06,2
Main10   BTFSS 36h,0
         GOTO Main11
         BSF 06,1
Main11   BTFSS 36h,2
         GOTO Main12
         BSF 06,0
Main12   BSF 05,2
         CALL Del1
         BCF 05,2
         CLRF 06
         CALL Del1

         BTFSS 37h,0
         GOTO Main13
         BSF 06,5
Main13   BTFSS 37h,2
         GOTO Main14
         BSF 06,4
Main14   BTFSS 38h,0
         GOTO Main15
         BSF 06,3
Main15   BTFSS 38h,2
         GOTO Main16
         BSF 06,2
Main16   BTFSS 39h,0
         GOTO Main17
         BSF 06,1
Main17   BTFSS 39h,2
         GOTO Main18
         BSF 06,0
Main18   BSF 05,1
         CALL Del1
         BCF 05,1
         CLRF 06
         BTFSC 05,3        ;Skip if ButtonA is still pressed
         BCF 2F,0          ;Clear button-press flag
         BTFSC 05,4        ;Skip if ButtonB is still pressed
         BCF 2F,1          ;Clear button-press flag
         DECFSZ 22h,1
         GOTO MainA

                           ;The following section hides and shows cursor
                           ;If cursor is showing, it hides cursor
                           ;If cursor is hidden, it shows cursor
                           ;Cursor changes from 05 to 08 to 05 etc

         MOVLW 0A          ;Ten loops of routine
         MOVWF 23h         ;Loop file
         MOVLW 30h         ;Start of files for board
         MOVWF 04          ;Load start into FSR
Main19   BTFSS 00,0        ;Test bit0 of INDF
         GOTO Main20
         BTFSS 00,2        ;Is bit2 = HIGH?
         GOTO Main20
         MOVLW 08          ;File contains cursor. Put 08 into file to "hide"
         MOVWF 00          ;08 will be put into a file 30h to 39h
         GOTO Main         ;Cursor has been hidden

Main20   INCF 04,1         ;Increment pointer
         DECFSZ 23h,1      ;Decrement loop file
         GOTO Main19


         MOVLW 30h         ;Start of files for board
         MOVWF 04          ;Load start into FSR
Main21   BTFSC 00,3        ;Look for "8" in a file
         GOTO Main22
         INCF 04,1         ;Increment the pointer
         GOTO Main21
Main22   MOVLW 05          ;Put 5 in file looked at by FSR
         MOVWF 00h
         INCF 28h          ;Increment the RANDOM NUMBER file
         INCF 28h
         CALL **Stale**
         GOTO Main

         END               ;Tells assembler end of program

During the execution of Main, the micro is looking for Button “A” or “B.”
If button “A” (Move) is pressed, the player has the first move on the board. If button “B” is pressed, the computer has the first move.
If button A is pressed, the micro goes to ButtonA routine. The button-press flag is set so the routine is only accessed ONCE for each press of the button. If a button-press flag is not included, the micro will increment the cursor and return to Main. If the button is still pressed, the micro will advance the cursor one more location. This will continue until the button is released. We only want one advancement.
If the “Win LED” bit is set, the display is cleared for a new game. If the bit is not set, the micro looks for the cursor. The cursor can be 08 or 05. To test for 08, the program tests bit 3 in files 30h to 39h.
The program assumes (correctly), that the cursor will be found. Consequently, there is no decrementing loop. The program looks at these files via a feature called INDIRECT ADDRESSING.
The first file is loaded into FSR - the File Select Register. The micro then looks at file 00. This is not a normal file. It is called the INDIRECT FILE. It always contains the data of the file looked at by FSR. In our case, looking at file 00 will be looking at file 30h. You can carry out all the tests and operations on file 30h, via file 00.
By incrementing FSR, we look at file 31h. This is done until the cursor is found.
When the cursor is found, the program tests to see if it has passed the end of the board (file 3Ah).
At ButA3, the working register (W) is loaded with 3A and compared with FSR. If it has reached file 3A, the zero flag (bit 2) in file 03 will be SET. The micro will advance down the program and clear file 3A. File 30h will be loaded with 05 and the micro will return to Main.
If the cursor has not reached the end of the board, the file containing the cursor is cleared via indirect addressing mode and the next file is tested at ButA6. If it is empty, it is loaded with 05. If it is not empty, the FSR file incremented and tested. The micro then returns to Main.

ButtonA  BSF 2F,0          ;Set button-press flag
         BTFSS 2F,3        ;Is Win-LED/stalemate bit=1?
         GOTO ButAA
         BCF 2F,3
         BCF 05,6
         BCF 05,7
         MOVLW 05          ;Put cursor into "ready" file
         MOVWF 30h
         CLRF 31h
         CLRF 32h
         CLRF 33h
         CLRF 34h
         CLRF 35h
         CLRF 36h
         CLRF 37h
         CLRF 38h
         CLRF 39h
         CLRF 3Ah
         RETURN
ButAA    MOVLW 30h         ;Start of "board"
         MOVWF 04          ;Start FSR at file 30h
ButA1    BTFSC 00,3        ;Look for "8"
         GOTO ButA3        ;Found cursor
         BTFSS 00,0        ;Look for first part of "05"
         GOTO ButA2        ;Cursor not found
         BTFSS 00,2        ;Look for second part of "05"
         GOTO ButA2
         GOTO ButA3        ;Found cursor
ButA2    INCF 04
         GOTO ButA1
ButA3    MOVLW 3Ah         ;Has cursor reached end of "board?"
         XORWF 04,0
         BTFSS 03,2        ;Test the zero flag
         GOTO ButA4        ;not at end of board
         CLRF 3Ah          ;reached end of board
         MOVLW 05
         MOVWF 30h         ;Return cursor to start
         RETURN
ButA4    CLRF 00           ;Clear the cursor
ButA5    INCF 04,1
         MOVLW 3A
         XORWF 04,0        ;If cursor has reached end of board,
         BTFSS 03,2        ; return it to file 30h
         GOTO ButA6
         MOVLW 30h
         MOVWF 04          ;Return cursor to start
ButA6    MOVLW 00
         XORWF 00,0        ;Is board location empty?
         BTFSS 03,2        ;Test zero flag
         GOTO ButA5        ;Not empty
         MOVLW 05          ;Empty location
         MOVWF 00          ;Show cursor in new location
         RETURN

Button B (Play) converts a flashing cursor into a red “Player Piece.” It does this by creating 9 loops to look at files 31h to 39h. It looks at the files via Indirect Addressing. It firstly looks for the cursor with a value of 05, then 08. The program “looks into” file 00 ands “sees” the file we have placed in FSR (file 04).
If the cursor is found, the file00 is loaded with 01. The value 01 creates a red LED on the display. File 30h is then loaded with 05 to hide the cursor.
If the cursor is not found, the program assumes the player wants the computer to make the first move.

ButtonB  BSF 2F,1       ;Set button-press flag
         MOVLW 09
         MOVWF 23h      ;Decrementing file
         MOVLW 31h      ;Start of "board"
         MOVWF 04       ;FSR starts at file 31h
ButB1    MOVLW 05
         XORWF 00,0     ;Is the file looked at by FSR=5?
         BTFSC 03,2     ;Test zero flag
         GOTO ButB2     ;Found
         MOVLW 08       ;Not found try "08" = flashing cursor
         XORWF 00,0     ;Is the file looked at by FSR=8?
         BTFSS 03,2
         GOTO ButB3     ;Not found
ButB2    MOVLW 01       ;Cursor found
         MOVWF 00       ;Make file = 1 = red
         MOVLW 05
         MOVWF 30h      ;Put cursor into "hide" file
         GOTO PWin
ButB3    INCF 04,1      ;Increment the pointer
         DECFSZ 23h
         GOTO ButB1
         GOTO PWin      ;ButtonB pushed for computer goes first

ButtonB converts the cursor into a player piece and exits with the cursor in file 30h. The micro then goes to PWin.
(PWin looks for all possibilities for PLAYER WIN by looking for a “1” in bit0 in three files.) The sub-routine contains all possible combinations of rows, columns and diagonals.
If bit0 is HIGH in three files in a row or column etc, the “Player Wins” LED is illuminated and the flag (2F,3) is SET.
If no “Player Win” is detected, a stalemate possibility is tested (CALL Stale). If the stalemate flag (2F,3) is not set, the micro goes to CWin.

                           ;This sub-routine sees if "Player WINS"
                           ;Check all possibilities for PLAYER WIN
                           ;Looking for a HIGH in bit0 = 01 in three files
                           ;This routine is in "Linear Programming Mode"
PWin     BTFSS 31h,0
         GOTO PWin1
         BTFSS 32h,0
         GOTO PWin1
         BTFSC 33h,0
         GOTO PWin21
PWin1    BTFSS 34h,0
         GOTO PWin2
         BTFSS 35h,0
         GOTO PWin2
         BTFSC 36h,0
         GOTO PWin21
PWin2    BTFSS 37h,0
         GOTO PWin3
         BTFSS 38h,0
         GOTO PWin3
         BTFSC 39h,0
         GOTO PWin21
PWin3    BTFSS 31h,0
         GOTO PWin4
         BTFSS 34h,0
         GOTO PWin4
         BTFSC 37h,0
         GOTO PWin21
PWin4    BTFSS 32h,0
         GOTO PWin5
         BTFSS 35h,0
         GOTO PWin5
         BTFSC 38h,0
         GOTO PWin21
PWin5    BTFSS 33h,0
         GOTO PWin6
         BTFSS 36h,0
         GOTO PWin6
         BTFSC 39h,0
         GOTO PWin21
PWin6    BTFSS 31h,0
         GOTO PWin7
         BTFSS 35h,0
         GOTO PWin7
         BTFSC 39h,0
         GOTO PWin21
PWin7    BTFSS 33h,0
         GOTO PWin8
         BTFSS 35h,0
         GOTO PWin8
         BTFSC 37h,0
         GOTO PWin21
PWin8    CALL Stale
         BTFSS 2F,3
         GOTO **CWin**
         RETURN
PWin21   BSF 05,6          ;Player WINS!
         BSF 2F,3          ;Set the Win-LED/stalemate bit
         RETURN

CWin checks for a Computer WIN. The program checks for all possibilities for “COMPUTER WIN”
The program looks for a HIGH in bit2 = 04 in 2 files. This routine is a “Algorithm.”

**CWin** MOVLW 0FFh        ;The value will be incremented to 00!
         MOVWF 25h         ;Table jump file
CWin1    CLRF 27h          ;Clear the Computer counter
         MOVLW 03
         MOVWF 26h         ;Fetch 3 table values in a loop.
CWin2    INCF 25h,1        ;Increment the table-jump file
         MOVF 25h,0        ;Copy jump file into W
         CALL Table1       ;Get first table value
         XORLW 0FFh        ;Look for end-of-table
         BTFSC 03,2        ;Test zero flag
         GOTO **Stop**     ;End of table found - no result obtained
         MOVF 25h,0        ;Copy jump file into W again
         CALL Table1       ;Call table again as previous value was lost via XORLW
         MOVWF 04          ;Move table value into FSR
         BTFSC 00,0        ;Look for unwanted player piece
         DECF 27h,1        ;Dec. computer counter so count cannot be recognised
         BTFSC 00,2        ;Look at bit2 of file 31h (first table value)
         INCF 27h,1        ;Increment the Computer counter
CWin3    DECFSZ 26h,1      ;Decrement the 3 table-values counter
         GOTO CWin2        ;Loop for next piece
         MOVLW 02          ;See if 2 computer pieces are found
         XORWF 27h,0
         BTFSS 03,2
         GOTO CWin1        ;2 computer pieces not found
CWin4    MOVF 25h,0        ;2 Computer pieces found. Put 25h into W
         CALL Table1       ;Locate table value
         MOVWF 04          ;Put W into FSR
         MOVF 00,1         ;Move value in file in and out to see if it is zero
         BTFSS 03,2        ;Test zero flag
         GOTO CWin5        ;Not zero
         MOVLW 04          ;Square is zero. Load computer piece
         MOVWF 00
         BSF 05,7          ;Computer WINS!
         BSF 2F,3          ;Set the Win-LED/stalemate bit
         RETURN
CWin5    DECF 25h,1
         GOTO CWin4

Stop sub-routine looks for a “stopper.” Any row or diagonal containing a “2” must be stopped.
i.e: look for two files in a row or diag with a value of 01. The sub-routine uses Table 1. It contains all the row and diagonals for the game. The sub-routine picks up 3 values at a time and sees if the answer is “2.”
The value “01” has been chosen for the player value so the values in a row can be added to get “3” for a “Player Win” or “2” for this sub-routine. That’s why the “Computer Value” has been chosen as “04.”
A very clever programming trick is to load a file with a value that is one more than the required value. This allows the program to decrement the file in a loop. You will notice the file gets decremented before it enters to loop during the first execution. That’s why the file must have a value “one higher” than required.
The end-of-table is detected by testing the highest bit. Since no values are higher than 80h, this method can be used.
If the sub-routine does not produce a result, the micro goes to the next sub-routine: Corner.
The program does not know if the player is in the first two locations, the last two or the end locations of a row or diagonal. It must go back to the beginning of the set-of-three in the table and check each location. That’s why the program must complete the 3 values in the table before adding the computer piece.
If you jump out of the program as soon as you get a result of “2,” you will not know where the player pieces are located and the program will not be able to locate the 3 files in the row.
If a computer piece is found, the player counter (file 27h) is incremented by 80h, by setting bit 7. This prevents the file becoming “02.”
The rest of the program is quite clear. The computer value is placed in the file by “Indirect Addressing.”

**Stop** MOVLW 0FFh         ;The value will be incremented to 00!
        MOVWF 25h           ;Table jump file
Stop1   CLRF 27h            ;Clear the "player" counter
        MOVLW 04            ;This will be decremented to 3!
        MOVWF 26h           ;Fetch 3 table-values in a loop.
Stop2   DECFSZ 26h,1
        GOTO Stop2A
        GOTO Stop4          ;3 values have been processed
Stop2A  INCF 25h,1          ;Increment the table-jump file
        MOVF 25h,0          ;Copy jump file into W
        CALL Table1         ;Get first table value
        MOVWF 04            ;Move table value into FSR
        BTFSC 00,7          ;Look for end-of-table
        GOTO **Corner**     ;End of table found - no result obtained
        BTFSC 00,2          ;Look at bit2 of file 31h for computer piece
        GOTO Stop3          ;Computer piece found
        BTFSC 00,0          ;Look at bit0 of file 31h (first table value)
        INCF 27h,1          ;Increment the "player" counter
        GOTO Stop2
Stop3   BSF 27h,7           ;Set bit 7 of "player" counter
        GOTO Stop2
Stop4   BTFSC 27h,7         ;Is computer in the row?
        GOTO Stop1
        BTFSS 27h,1         ;Is counter=2?
        GOTO Stop1
        DECF 25h,1          ;Two player files found! Go back to start of the 3 files.
        DECF 25h,1          ;Take table-jump value up-table
Stop5   MOVF 25h,0          ;Start of the three files. Move Jump value into W
        CALL Table1         ;Look at value of first of three files.
        MOVWF 04            ;Put jump value into FSR
        BTFSC 00,0          ;Test for player
        GOTO Stop6          ;Not empty
        MOVLW 04            ;Empty so put 04 into file looked at by FSR
        MOVWF 00
        RETURN
Stop6   INCF 25h,1          ;Increment the pointer
        GOTO Stop5

See if all locations are empty. Place a computer piece in a random corner if first move.
If board is not empty, go to Center. This routine will be activated when the computer is required to make the first move.

**Corner**  MOVLW 09
            MOVWF 25h           ;The loop file
            MOVLW 30h           ;This will be incremented before starting routine
            MOVWF 04            ;The pointer file
Corner1     INCF 04,1           ;Look at first board location
            MOVLW 00            ;Put 00 into W
            XORWF 00,0          ;Is location empty?
            BTFSS 03,2          ;Test the zero flag
            GOTO **Center**     ;Location is not empty
            DECFSZ 25h,1        ;File is zero. Decrement the loop file
            GOTO Corner1        ;Loop again
            MOVLW 07            ;Board is empty. Put masking value (7) into W
            ANDWF 28h,1         ;AND 07 with random number file. Result in 28h
            INCF 28h,1          ;File will be 1 to 8
            MOVF 28h,0          ;Put value in file 28 into W
            CALL Table2         ;Fetch random corner from table
            MOVWF 04            ;Put random corner into FSR
            MOVLW 04
            MOVWF 00            ;Put computer piece onto board
            RETURN

The previous sub-routine (Corner) has determined the board is not empty. Center places “Computer Piece” in the center square (if it is empty). If the centre square is not empty, the micro goes to Fork.

**Center**  MOVF 35h,1      ;Move 35h in and out of file to see if it is zero
            BTFSS 03,2      ;Test zero flag
            GOTO **Fork**
            MOVLW 04
            MOVWF 35h       ;Put computer into center square
            RETURN

Fork solves a “trick” situation where the player is forming a “fork.” If two player and one computer piece is found, and computer is in middle, computer plays a side square. The routine firstly determines if the computer is in the centre square. If the computer is not in the centre square, the micro goes to Look4 (look-for). If the player is not in location 39h, 33h or 37h, the micro goes to the next sub-routine: Divide.
If the player is in the first and last square, and the computer is in the centre, the computer plays a random side. If player is in the top-right and bottom-left, the computer plays a side.
This is the first sub-routine to have two branches. The first branch is Look4.

**Fork**  BTFSS 35h,2       ;Is computer in centre square?
        GOTO **Look4**      ;Not computer piece
        BTFSS 31h,0         ;Computer in centre. Is player in first square?
        GOTO ForkA          ;Player not in first square
        BTFSC 39h,0         ;Player in first square. Is player in last square?
        GOTO ForkB          ;Player in last square
ForkA   BTFSS 33h,0
        GOTO **Divide**
        BTFSS 37h,0
        GOTO **Divide**
ForkB   MOVLW 07            ;Get a random value. Put masking value (7) into W
        ANDWF 28h,1         ;AND 07 with random number file. Result in file
        INCF 28h,1          ;File will be 1 to 8
        MOVF 28h,0          ;Put value in file 28 into W
        CALL Table3         ;Fetch random side from table
        MOVWF 04            ;Put random side into FSR
        MOVF 00,1           ;Move side value in and out of file to see if it is zero
        BTFSS 03,2
        GOTO ForkB          ;Side not empty
        MOVLW 04
        MOVWF 00            ;Put computer piece onto board
        RETURN

Divide is another “trick” situation. If computer in centre and player on two adjoining sides, computer must go between player pieces.

**Divide**  BTFSC 31h,0         ;Test for player in first square
            GOTO **Look4**
            BTFSC 31h,2         ;Test for computer in first square
            GOTO **Look4**
            BTFSC 32h,0         ;Test for player in second square
            GOTO **Look4**
            BTFSC 32h,2         ;Test for computer in second square
            GOTO **Look4**
            BTFSC 33h,0         ;Test for player in third square
            **GOTO** Look4
            BTFSC 33h,2         ;Test for computer in third square
            GOTO **Look4**
            BTFSC 34h,0         ;Test for player in fourth square
            GOTO **Look4**
            BTFSC 34h,2         ;Test for computer in fourth square
            GOTO **Look4**
            BTFSS 35h,2         ;Look for computer in centre square
            GOTO Look4
            BTFSS 36h,0         ;Test for player in sixth square
            GOTO **Look4**
            BTFSC 37h,0         ;Test for player in seventh square
            GOTO **Look4**
            BTFSC 37h,2         ;Test for computer in seventh square
            GOTO **Look4**
            BTFSS 38h,0         ;Test for player in eighth square
            GOTO **Look4**
            BTFSC 39h,0         ;Test for player in ninth square
            GOTO **Look4**
            BTFSC 39h,2         ;Look for computer in last location
            GOTO **Look4**
            MOVLW 04
            MOVWF 39h           ;Put computer piece into last location
            RETURN

Look for a row containing just a computer piece (04) and add another computer piece. If not, add a random computer piece. Table 1 is used again to get the files for each row, column and diagonal.
The program is looking for the value 04 in a single file, in row, column or diagonal. If the end-of-table is reached before a value is found, the micro goes to Random. At Look4C the program compares the counter (file27h) with 01 and if only one computer piece is found in a row etc, the beginning of the row is found by loading the “jump value” into W and calling Table1 at Look 4G. The file from the table is loaded into FSR and looked at to see if it is empty. If is is empty, 04 is loaded into the file via indirect addressing. If it is not empty, the “jump value” is increased twice so that only a corner is loaded with the computer piece.

**Look4**   MOVLW 0FFh          ;The value will be incremented to 00!
            MOVWF 25h           ;Table jump file
Look4A      CLRF 27h            ;Clear the Look counter
            MOVLW 03
            MOVWF 26h           ;Fetch 3 table values in a loop.
Look4B      INCF 25h,1          ;Increment the table-jump file
            MOVF 25h,0          ;Copy jump file into W
            CALL Table1         ;Get first table value
            MOVWF 04            ;Move table value into FSR
            BTFSC 00,7          ;Look for end-of-table
            GOTO **Random**     ;End of table found - no result obtained
            BTFSC 00,2          ;Look for computer
            GOTO Look4L
            BTFSS 00,0          ;Look for player
            GOTO Look4C
            INCF 27h,1          ;Prevent row being accessed
Look4L      INCF 27h,1          ;Increment the Look counter (If=1, Computer only once)
Look4C      DECFSZ 26h,1        ;Decrement the 3 table-values counter
            GOTO Look4B
            MOVLW 01
            XORWF 27h,1
            BTFSS 03,2
            GOTO Look4A         ;Computer nil or more than once
            DECF 25h,1          ;Computer only once. Find start of row
            DECF 25h,1
Look4G      MOVF 25h,0          ;Move 25h into W
            CALL Table1
            MOVWF 04            ;Move table value into pointer
            MOVF 00,1           ;Move file in and out to see it is zero
            BTFSS 03,2          ;Test zero flag
            GOTO Look4H
            MOVLW 04            ;Square is empty
            MOVWF 00            ;Put computer piece into empty square
            RETURN
Look4H      INCF 25h,1
            INCF 25h,1          ;Place computer piece only in corner!
            GOTO Look4G

Insert a random computer piece. Corners are first selected. The game must have a sub-routine that definitely places a piece on the board, just in case all the above routines do not find a result. This is the last routine for the “decision-making” section of the program. A random number is obtained from the Random Number file. This file is incremented every time the display cycles and will contain a different value due to the player pressing the buttons (for each “turn”), at a different time.

**Random**  MOVLW 03            ;Put masking value (3) into W
            ANDWF 28h,1         ;AND 03 with random number file. Result in file
Random1     INCF 28h,1          ;File will be 1 to 4 on first pass.
            MOVF 28h,0          ;Put value into W
            CALL Table5         ;Fetch random location from table
            MOVWF 04            ;Put random location into FSR
            BTFSC 00,7          ;Test for end-of-table
            RETURN
            MOVF 00,1           ;Move value in and out of file to see if it is zero
            BTFSS 03,2          ;Test the zero-bit
            GOTO Random1        ;location not empty
            MOVLW 04
            MOVWF 00            ;Put computer piece onto board
            RETURN

STALEMATE

Stalemate is CALLed from the Main routine.
The board is checked to see if any square is empty. If all are full, both LEDs are illuminated. The program creates 9 loops to check each square. It checks to see if the cursor is present by testing for 05 and 08. If so, the micro returns. It then checks to see if each square is full. If all squares are occupied, both LEDs are illuminated and the “Stalemate flag” is set.

Stale   BTFSC 05,6          ;Check Player-WINS! bit
        RETURN
        MOVLW 09
        MOVWF 25h           ;Decrementing file
        MOVLW 31h
        MOVWF 04            ;Start of files into FSR
Stale1  MOVLW 05
        XORWF 00,0
        BTFSC 03,2
        RETURN              ;Square has cursor
        BTFSC 00,3          ;Test for "hidden" cursor
        RETURN
        MOVLW 00
        XORWF 00,0
        BTFSC 03,2          ;Test zero flag
        RETURN              ;Square is empty
        INCF 04,1           ;Square is full. Increment the pointer
        DECFSZ 25h,1
        GOTO Stale1
        BSF 05,6
        BSF 05,7
        BSF 2F,3            ;Set the Win-LED/stalemate bit
        RETURN


Colin Mitchell

Colin Mitchell

Expertise

electronics
writing
PIC-Chips

Social Media

instagramtwitterwebsite

Related Posts

TODO
Transistor Test
© 2021, All Rights Reserved.

Quick Links

Advertise with usAbout UsContact Us

Social Media