Tic Tac Toe for GNUCobol
This program is transcribed into COBOL from Tic Tac Toe from BASIC Computer Games. There is a bug in the original BASIC game. It is possible for the computer to wrongly conclude that the game was a draw even though it won. This is because the scan for a diagonal win happens after the check for a full board. This bug has been corrected in the COBOL version.
If you think there are a lot of GO TOs, you should see the BASIC program.
IDENTIFICATION DIVISION. PROGRAM-ID. TIC-TAC-TOE. ENVIRONMENT DIVISION. CONFIGURATION SECTION. SOURCE-COMPUTER. GNUCOBOL. OBJECT-COMPUTER. GNUCOBOL. DATA DIVISION. WORKING-STORAGE SECTION. 01 BOARD. 10 S OCCURS 9 PIC S9. 01 BOARD2D REDEFINES BOARD. 10 ROW OCCURS 3. 20 CELL OCCURS 3 PIC S9. 01 ROW-DISPLAY. 10 CELLD OCCURS 3. 15 FILLER PIC X. 15 CELL-DISPLAY PIC X. 15 FILLER PIC X. 15 DIVIDER PIC X. 77 I PIC 99. 77 J PIC 9. 77 K PIC 9. 77 INX PIC 9. 77 M PIC 9. * If G = -1 then computer has just made move 77 G PIC S9. 77 H PIC S9. 01 COMP-MARK CONSTANT AS -1. 01 UNOCCUPIED CONSTANT AS 0. 01 OPPO-MARK CONSTANT AS 1. * C = Player choice of O or X 77 C PIC X. 77 P PIC X. 77 Q PIC X. PROCEDURE DIVISION. TICTACTOE. MOVE ZEROS TO BOARD. MOVE " ! ! " TO ROW-DISPLAY. DISPLAY " TIC-TAC-TOE". DISPLAY "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY". DISPLAY SPACE. DISPLAY SPACE. DISPLAY SPACE. DISPLAY "THE BOARD IS NUMBERED:". DISPLAY " 1 2 3". DISPLAY " 4 5 6". DISPLAY " 7 8 9". DISPLAY SPACE. DISPLAY SPACE. DISPLAY SPACE. DISPLAY "DO YOU WANT 'X' OR 'O'?" WITH NO ADVANCING. ACCEPT C. IF C = "X" OR "x" GO TO PLAYER-IS-X. MOVE "O" TO P. MOVE "X" TO Q. NEXT-ROUND. MOVE COMP-MARK TO G. MOVE OPPO-MARK TO H. * Is center occupied? IF S(5) = UNOCCUPIED MOVE COMP-MARK TO S (5) GO TO DISP-COMP-MOVE. * Is center mine? IF S(5) <> OPPO-MARK GO TO LIN106. * Is top left occupied? IF S(1) <> UNOCCUPIED GO TO LIN110. MOVE COMP-MARK TO S(1). GO TO DISP-COMP-MOVE. LIN106. IF S(2) = OPPO-MARK AND S(1) = UNOCCUPIED OR S(4) = OPPO-MARK AND S(1) = UNOCCUPIED GO TO TAKE-CELL-1. IF S(6) = OPPO-MARK AND S(9) = UNOCCUPIED GO TO TAKE-CELL-9. IF S(8) = OPPO-MARK AND S(9) = UNOCCUPIED GO TO TAKE-CELL-9. LIN110. IF G = OPPO-MARK GO TO LIN112. GO TO LIN118. LIN112. MOVE M TO INX. SUBTRACT 1 FROM INX. * Calculate row DIVIDE 3 INTO INX. MULTIPLY 3 BY INX. ADD 1 TO INX. MOVE INX TO J. IF INX = M THEN MOVE 1 TO K. ADD 1 TO INX. IF INX = M THEN MOVE 2 TO K. ADD 1 TO INX. IF INX = M THEN MOVE 3 TO K. GO TO LIN120. LIN118. MOVE 1 TO J. LIN119. MOVE 1 TO K. LIN120. IF S(J) <> G GO TO LIN130. IF S(J + 2) <> G GO TO LIN135. IF S(J + 1) <> UNOCCUPIED GO TO LIN150. MOVE COMP-MARK TO S(J + 1). GO TO DISP-COMP-MOVE. LIN130. IF S(J) = H GO TO LIN150. IF S(J + 1) <> G GO TO LIN150. IF S(J + 2) <> G GO TO LIN150. MOVE COMP-MARK TO S(J). GO TO DISP-COMP-MOVE. * Take last in row LIN135. IF S(J + 1) <> G GO TO LIN150. IF S(J + 2) <> UNOCCUPIED GO TO LIN150. MOVE COMP-MARK TO S(J + 2). GO TO DISP-COMP-MOVE. * Take middle in column if top and bottom not taken LIN150. IF S(K) <> G GO TO LIN160. IF S(K + 6) <> G GO TO LIN165. IF S(K + 3) <> UNOCCUPIED GO TO LIN170. MOVE COMP-MARK TO S(K + 3). GO TO DISP-COMP-MOVE. * Take top in column LIN160. IF S(K) = H GO TO LIN170. IF S(K + 3) <> G GO TO LIN170. IF S(K + 6) <> G GO TO LIN170. MOVE COMP-MARK TO S(K). GO TO DISP-COMP-MOVE. LIN165. IF S(K + 3) <> G GO TO LIN170. IF S(K + 6) <> UNOCCUPIED GO TO LIN170. MOVE COMP-MARK TO S(K + 6). GO TO DISP-COMP-MOVE. LIN170. GO TO LIN450. LIN171. IF S(3) = G AND S(7) = UNOCCUPIED MOVE COMP-MARK TO S(7) GO TO DISP-COMP-MOVE. IF S(9) = G AND S(1) = UNOCCUPIED GO TO TAKE-CELL-1. IF S(7) = G AND S(3) = UNOCCUPIED GO TO TAKE-CELL-3. IF S(9) = UNOCCUPIED AND S(1) = G GO TO TAKE-CELL-9. LIN175. IF G = COMP-MARK THEN MOVE OPPO-MARK TO G MOVE COMP-MARK TO H GO TO LIN110. IF S(9) = OPPO-MARK AND S(3) = UNOCCUPIED GO TO MAYBE-CELL-3. * Take first non-empty cell larger than 1 FIND-FREE. MOVE 2 TO I. NEXT-FREE-CELL. IF I < 10 IF S(I) <> UNOCCUPIED ADD 1 TO I GO TO NEXT-FREE-CELL ELSE MOVE COMP-MARK TO S(I) GO TO DISP-COMP-MOVE. TAKE-CELL-1. MOVE COMP-MARK TO S(1). GO TO DISP-COMP-MOVE. MAYBE-CELL-3. IF S(1) = OPPO-MARK GO TO FIND-FREE. TAKE-CELL-3. MOVE COMP-MARK TO S(3). GO TO DISP-COMP-MOVE. TAKE-CELL-9. MOVE COMP-MARK TO S(9). DISP-COMP-MOVE. DISPLAY SPACE. DISPLAY "THE COMPUTER MOVES TO...". PERFORM PRINT-BOARD THRU PRINT-BOARD-EXIT. GO TO ASK-PLAYER. LIN450. IF G=1 GO TO LIN465. IF J=7 AND K=3 GO TO LIN465. ADD 1 TO K. IF K NOT > 3 GO TO LIN120. ADD 3 TO J. IF J NOT > 7 GO TO LIN119. LIN465. IF S(5) = G GO TO LIN171. GO TO LIN175. PLAYER-IS-X. MOVE "X" TO P. MOVE "O" TO Q. ASK-PLAYER. DISPLAY SPACE. DISPLAY "WHERE DO YOU MOVE? (0 = END)" WITH NO ADVANCING. ACCEPT M. IF M = 0 THEN DISPLAY "THANKS FOR THE GAME." GO TO END-GAME. IF S(M) = UNOCCUPIED GO TO MARK-CHOICE. ILLEGAL-MOVE. DISPLAY "THAT SQUARE IS OCCUPIED.". DISPLAY SPACE. DISPLAY SPACE. GO TO ASK-PLAYER. * Set player's marker in cell MARK-CHOICE. MOVE OPPO-MARK TO G. MOVE OPPO-MARK TO S(M). PERFORM PRINT-BOARD THRU PRINT-BOARD-EXIT. GO TO NEXT-ROUND. PRINT-BOARD. DISPLAY SPACE. PERFORM PRINT-ROW VARYING J FROM 1 BY 1 UNTIL J > 3. GO TO BOARD-STATUS. PRINT-ROW. PERFORM MARK-CELL VARYING I FROM 1 BY 1 UNTIL I > 3. DISPLAY ROW-DISPLAY. IF J < 3 DISPLAY "---+---+---". MARK-CELL. IF CELL(J,I) = COMP-MARK MOVE Q TO CELL-DISPLAY(I). IF CELL(J,I) = UNOCCUPIED MOVE " " TO CELL-DISPLAY(I). IF CELL(J,I) = OPPO-MARK MOVE P TO CELL-DISPLAY(I). * Check board status BOARD-STATUS. DISPLAY SPACE. DISPLAY SPACE. MOVE 1 TO I. * Check horizontally NEXT-ROW. IF S(I) <> S(I + 1) GO TO SKIP-ROW. IF S(I) <> S(I + 2) GO TO SKIP-ROW. IF S(I) = COMP-MARK GO TO COMPUTER-WIN. IF S(I) = OPPO-MARK GO TO PLAYER-WIN. SKIP-ROW. ADD 3 TO I. IF I NOT > 7 GO TO NEXT-ROW. * Check vertically MOVE 1 TO I. NEXT-COL. IF S(I) <> S(I + 3) GO TO SKIP-COL. IF S(I) <> S(I + 6) GO TO SKIP-COL. IF S(I) = COMP-MARK GO TO COMPUTER-WIN. IF S(I) = OPPO-MARK GO TO PLAYER-WIN. SKIP-COL. ADD 1 TO I. IF I NOT > 3 GO TO NEXT-COL. * Same markers diagonally? CHECK-DIAG. IF S(5) <> G GO TO CHECK-ALL-FILLED. IF S(1) = G AND S(9) = G GO TO WIN-DIAGONAL. IF S(3) = G AND S(7) = G GO TO WIN-DIAGONAL. * Any unfilled cells? CHECK-ALL-FILLED. MOVE 1 TO I. CHECK-NEXT-CELL. IF S(I) = UNOCCUPIED GO TO PRINT-BOARD-EXIT. ADD 1 TO I IF I NOT > 9 GO TO CHECK-NEXT-CELL. DISPLAY "IT'S A DRAW. THANK YOU.". GO TO END-GAME. * There are still empty cells. PRINT-BOARD-EXIT. EXIT. WIN-DIAGONAL. IF G = COMP-MARK GO TO COMPUTER-WIN. PLAYER-WIN. DISPLAY "YOU BEAT ME!! GOOD GAME.". GO TO END-GAME. COMPUTER-WIN. DISPLAY "I WIN, TURKEY!!!". END-GAME. STOP RUN.
Output
TIC-TAC-TOE CREATIVE COMPUTING MORRISTOWN, NEW JERSEY THE BOARD IS NUMBERED: 1 2 3 4 5 6 7 8 9 DO YOU WANT 'X' OR 'O'? X WHERE DO YOU MOVE? (0 = END) 5 ! ! ---+---+--- ! X ! ---+---+--- ! !