13
Jan
10

Tic-Tac-Toe: COBOL

I have to say, COBOL was more fun than I was expecting. I’m sure working on ancient, multi-KLOC mainframe apps is not as fun. But for my purposes, explicitly laying out my working memory and writing keywords in all caps is entertaining. More impressions:

  • COBOL is very bureaucratic. This is not a surprise, in itself, but it is surprising just how bureaucratic it is. Rigid divisions and sections for required metadata, working data, the equivalent of procedure parameters, the procedures themselves. Lots of verbiage and boilerplate. From a modern perspective, I think of high level languages as abstracting away much of the nitty gritty of memory management, function call mechanics, etc. COBOL strikes me, instead, as a way of supporting and enforcing organizational best practices of the day, while leaving a fair bit of the nitty gritty up to the programmer.
  • The punch card legacy is alive and well. Top-level lines must begin in column 8, and any text after column 80 is simply ignored. (If vim’s syntax highlighting had not warned me, I’m sure I’d have lost many hours to this.) There is a “free” layout mode available in more recent COBOL, but what fun is that?
  • You don’t really have typed variables. In fact, everything is, more or less, a string as far as I can tell. Instead, you lay out sections of memory, give them labels, and show the compiler a “picture” of how the memory is structured. The only type information you do have is that you can specify whether a given memory region should contain alphabetic, numeric, or alphanumeric characters. Alphabetic is represented by “A”, numeric by “9″ and alphanumeric by “X”. So, for example “XXX9A” represents a 5-byte region that should contain three characters, a number, and a letter. You can also define totally different overlays on top of the same region of memory — which you would routinely do in order to, say, define an array with initial values. You can see this below where I used the “REDEFINES” keyword.
  • The wild-west memory layout and overlays, together with call by reference, let me do some magic tricks. For instance, I can check for a tie by just asking if the whole region where I keep the board placements is numeric. Or, I lay out the whole, formatted board at once, and overwrite sections of it as I go, rather than reformatting each time. I assume that this is the sort of “cleverness” that modern languages hope to prevent. :)
  • The syntax bears a strong resemblance to SQL. I presume this is not accidental.

Here’s the code:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  TicTacToe.
       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01 CurrentPlayer     PIC A VALUE "X".
       01 CurrentMove       PIC 9(10).
       01 RowSeparator      PIC X(11) VALUE "---+---+---". 

      * The board, for calculation purposes
       01 CurrentBoard.
           02 CurrentBoardValues        PIC X(9) VALUE "123456789".
           02 CurrentBoardTable REDEFINES CurrentBoardValues.
               03 Cell OCCURS 9 TIMES PIC X.

      * The board, for display purposes
       01 BoardForDisplay.
           02 BoardValuesForDisplay.
               03 RowOne        PIC X(11) VALUE "(1)|(2)|(3)".
               03 FILLER        PIC X.
               03 RowTwo        PIC X(11) VALUE "(4)|(5)|(6)".
               03 FILLER        PIC X.
               03 RowThree      PIC X(11) VALUE "(7)|(8)|(9)".
               03 FILLER        PIC X.

           02 FILLER REDEFINES BoardValuesForDisplay.
               03 DisplayCell   OCCURS 9 TIMES PIC X(4).

       01 GameOver          PIC X VALUE 'F'.

       PROCEDURE DIVISION.
       Begin.
           PERFORM WITH TEST AFTER UNTIL GameOver EQUAL 'T'
               PERFORM DisplayBoard
               DISPLAY "Select a square, " CurrentPlayer ": "
                   WITH NO ADVANCING
               ACCEPT  CurrentMove
               IF CurrentMove > 0 AND CurrentMove < 10 AND
                       Cell(CurrentMove) NUMERIC
                   MOVE CurrentPlayer TO Cell(CurrentMove)
                   CALL "FormatCell" USING BY CONTENT CurrentPlayer
                       BY REFERENCE DisplayCell(CurrentMove)
                   PERFORM CheckForWin
                   PERFORM CheckForDraw
                   PERFORM SwitchPlayer
               END-IF
           END-PERFORM.
           STOP RUN.

       DisplayBoard.
           DISPLAY ""
           DISPLAY RowOne
           DISPLAY RowSeparator
           DISPLAY RowTwo
           DISPLAY RowSeparator
           DISPLAY RowThree
           DISPLAY "".
           
       CheckForWin.
           IF Cell(1) EQUAL Cell(2) AND Cell(2) EQUAL Cell(3)
                   OR Cell(4) EQUAL Cell(5) AND Cell(5) EQUAL Cell(6)
                   OR Cell(7) EQUAL Cell(8) AND Cell(8) EQUAL Cell(9)
                   OR Cell(1) EQUAL Cell(4) AND Cell(4) EQUAL Cell(7)
                   OR Cell(2) EQUAL Cell(5) AND Cell(5) EQUAL Cell(8)
                   OR Cell(3) EQUAL Cell(6) AND Cell(6) EQUAL Cell(9)
                   OR Cell(1) EQUAL Cell(5) AND Cell(5) EQUAL Cell(9)
                   OR Cell(3) EQUAL Cell(5) AND Cell(5) EQUAL Cell(7)
               PERFORM DisplayBoard
               DISPLAY CurrentPlayer " Wins!"
               SET GameOver TO 'T'
           END-IF.

       CheckForDraw.
           IF CurrentBoard ALPHABETIC AND GameOver NOT EQUAL 'T'
               PERFORM DisplayBoard
               DISPLAY "It's a Draw!"
               SET GameOver TO 'T'
           END-IF.

       SwitchPlayer.
           IF CurrentPlayer EQUAL "X" THEN
               SET CurrentPlayer TO "O"
           ELSE
               SET CurrentPlayer TO "X"
           END-IF.


       IDENTIFICATION DIVISION.
       PROGRAM-ID. FormatCell
       DATA DIVISION.
       LINKAGE SECTION.

       01 CellValue             PIC X.

       01 CellRepresentation.
           02 LeftPad           PIC X.
           02 ContentSpace      PIC X.
           02 RightPad          PIC X.
           02 FILLER            PIC X.

       PROCEDURE DIVISION USING CellValue, CellRepresentation.
       Begin.
           MOVE CellValue to ContentSpace
           IF CellValue NUMERIC
               MOVE "(" TO LeftPad
               MOVE ")" TO RightPad
           ELSE
               MOVE " " TO LeftPad
               MOVE " " TO RightPad
           END-IF.
           EXIT PROGRAM.

       END PROGRAM FormatCell.

       END PROGRAM TicTacToe.


6 Responses to “Tic-Tac-Toe: COBOL”


  1. 1 ed from ga
    January 13, 2010 at 11:38 am

    COBOL predates SQL, and it’s likely that the SQL syntax was made similar to COBOL’s because of COBOL’s once-upon-a-time position as the dominant development language for businesses.

  2. 3 James
    January 13, 2010 at 7:59 pm

    Which implementation of Cobol did you use?
    Just curious and wishing to try your code out.

    Could you present at the end of each week the compiler/interpreter you used?

  3. January 14, 2010 at 11:19 am

    Ruby, then COBOL? Rather a violent transition, don’t you think? :)


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.