TicTacToe

TicTacToe is the children's game everyone knows. It makes a very good first programming exercise because it has many of the essential elements of any program without being overly complex. Having said that, the very first React tutorial also uses TicTacToe, and for anyone who isn't already an accomplished JavaScript programmer it's mind-numbingly complex. The difference is, they are aiming at people who want to be highly-paid professional programmers, whereas here we're just showing you how to get results quickly.

So first we'll see what the game looks like, then how it's built.

 

Click the squares in turn to play the game.

Here is the script. First, the component we are using to hold the game board. Then the standard <pre> block that tells EasyCoder this is a script, followed by all the variables used by the script. Only 2 kinds of variable are used here; a "div" for each of the components of the game and a number of general-purpose numeric/string variables.

<div id="ec-root"></div>
<pre id="easycoder-script" style="display: none;">!
  div Root
  div Board
  div Row
  div Cell
  div Message
  variable Model
  variable Index
  variable Turn
  variable Moves
  variable Winner
  variable Score
  variable WinningCombinations

 

In the next part we initialize some variables. There are 9 cells in total - 3x3 - so we need an array of 9 elements for the cells on the screen. We also need a 9-element array to hold the current contents of each cell. This is what's known as the "model" for the game. All variables in EasyCoder are arrays, initially with one value each; here we are setting these two to have 9 each.

Then we set the value of Turn to false (by clearing it) and zero a counter that will record how many moves have been made in the game. There cannot be more than 9 because there are only 9 cells. We set the name of the winner to an empty string and initialize WinningCombinations with 24 values. There are 8 winning combinations; 3 rows, 3 columns and 2 diagonals.

! Initialization
  set the elements of Cell to 9
  set the elements of Model to 9
  clear Turn
  put 0 into Moves
  put `` into Winner
  set WinningCombinations to
    0 1 2
    3 4 5
    6 7 8
    0 3 6
    1 4 7
    2 5 8
    0 4 8
    2 4 6

 

The board is set up by attaching the Root variable to the <div> whose id is ec-root. Then we create a <div> to hold messages, add it to the Root and put a message into it.

The board itself is next; just an ordinary <div>. We set the font size so this will apply to all the text that goes on the board. You can set a single style like this or you can set a whole bunch of them together, as is done shortly for Row.

! Set up the board
  attach Root to `ec-root`
  create Message in Root
  set the content of Message to `Click to take your turn`
  create Board in Root
  set style `font-size` of Board to `24px`

 

Now we have a program loop, using the variable Index counting from 0 to 8 inclusive. Every time Index is divisible by 3 we create a new Row, adding it to the board and setting its style. Then we create a Cell and set its styles, one by one as it's clearer than doing them all in one long line.

  put 0 into Index
  while Index is less than 9
  begin
    if Index modulo 3 is 0
    begin
      create Row in Board
      set the style of Row to `width:105px;height:34px`
    end
    index Cell to Index
    create Cell in Row
    set style `display` of Cell to `inline-block`
    set style `border` of Cell to `1px solid gray`
    set style `float` of Cell to `left`
    set style `font-size` of Cell to `24px`
    set style `font-weight` of Cell to `bold`
    set style `line-height` of Cell to `34px`
    set style `height` of Cell to `34px`
    set style `margin-right` of Cell to `-1px`
    set style `margin-top` of Cell to `-1px`
    set style `padding` of Cell to `0`
    set style `text-align` of Cell to `center`
    set style `width` of Cell to `34px`
    index Model to Index
    put 0 into Model
    add 1 to Index
  end

 

The board is now set up so we wait for the user to click a cell. Because Cell is an array we only need a single command to listen for clicks; this will automatically apply to all 9. When the click occurs, the internal pointer inside Cell will be set to point to the clicked element.

But first we have to check that we haven't run out of moves and that there's not yet a winner. In either case we want to ignore the click.

Then we find which cell was clicked and put that value into Index. We can index the Model array so the value we're looking at is the one for that cell. It should still have its original value of zero, of course, but if the user clicked a cell that was already used then some other value will be there, so we ignore the click.

The variable Turn tells us whose turn it is , so this information goes into the model as -1 or 1 and into the displayed cell as O or X. Then we call a subroutine to find out if there is a winner, and if there is, set the message above the board. Then we toggle Turn (true to false or false to true) to point to the other player and add 1 to the count of moves. If this reaches 9 a stalemate message is needed.

  on click Cell
  begin
    if Moves is 9 stop
    if Winner stop
    put the index of Cell into Index
    index Model to Index
    if Model is not 0 stop
    if Turn
    begin
      put 1 into Model
      set the content of Cell to `X`
    end
    else
    begin
      put -1 into Model
      set the content of Cell to `O`
    end
    gosub to CheckWinner
    if Winner
    begin
      set the content of Message to `The winner is ` cat Winner
      stop
    end
    toggle Turn
    add 1 to Moves
    if Moves is 9
    begin
      set the content of Message to `Stalemate - no winner`
      stop
    end
  end
  stop

 

This is the subroutine that checks for a winner. This can be done in a number of ways, some more elegant than others. Here, each of the 8 groups of numbers in WinningCombinations holds the cell numbers of a winning combination, so we add up the contents of the model for those 3. If they add up to either -3 or 3 we have a winner.

CheckWinner:
  put 0 into Score
  put 0 into Index
  while Index is less than 24
  begin
    index WinningCombinations to Index
    index Model to WinningCombinations
    add Model to Score
    add 1 to Index
    index WinningCombinations to Index
    index Model to WinningCombinations
    add Model to Score
    add 1 to Index
    index WinningCombinations to Index
    index Model to WinningCombinations
    add Model to Score
    if Score is -3
    begin
      put `O` into Winner
      return
    end
    if Score is 3
    begin
      put `X` into Winner
      return
    end
    add 1 to Index
    put 0 into Score
  end
  return
</pre>