Initialize
Home What is Logo? Getting Logo Logo Lessons Tic-Tac-Toe Downloads

 

Design
Programming
Initialize
Grid
Winning
Two Player
Single Player

Back Up Next

Drawing the Grid

The first task is to draw the tic-tac-toe grid. At the commander prompt type:

Commander
edit "draw.grid

And enter the following definition:

Editor
to draw.grid
    ;
    ; draw the tic-tac-toe screen
    ;
    setsc [255 255 255]
    setpc [0 0 0]
    setpensize [5 5]
    ht
    pu
    cs
    seth 0
    setpos [-50 -150] pd fd 300 pu
    setpos [50 -150] pd fd 300 pu
    seth 90
    setpos [-150 -50] pd fd 300 pu
    setpos [-150 50] pd fd 300 pu
end

Extra spaces are there to make it easier to read, you should get into the habit of putting the spaces in (in this case, there are 4 spaces at the start of every line).

The "draw.grid" word sets the screen color to white, the pen color to black. It sets the pen size to 5 (thick). Hides the turtle, pen-up (no drawing) and clears the screen. We set the heading to 0 (north/up) and draw the two lines from bottom to top. Then we set the heading to 90 (east/right) and draw the two lines from left to right.

Press Alt+S to save this function, and now type at the commander prompt:

Commander
draw.grid

We should now see the grid.

Calculating Positions

We are going to split the tic-tac-toe grid into 9 numbered boxes. We will number them as follows:

6 7 8
3 4 5
0 1 2

We need to create a word to convert an position number (index) to a position (x,y) that represents the center of that box. We will call the word "pos.from.index". Bring up the editor in the same way as before:

Commander
edit "pos.from.index

And enter the following definition:

Editor
to pos.from.index :i
    ;
    ; get x,y position from index
    ;
    local [x y]
    make "x ((remainder :i 3)-1)*100
    make "y ((int :i/3)-1)*100
    output (list :x :y)
end

Notice the ":i" after the word in the first line? This means "pos.from.index" requires a value after it (in this case a number). We will refer to this value throughout the definition as ":i". (The colon ":" is important, and indicates that this is a value). We call "i" a variable, as the value may vary (can be different).

We want to remember two other values, an x-coordinate and a y-coordinate. We also only want to know about these values inside the definition. The word "local" is used for this purpose. When we want to remember the result of something we type, we "make" a variable have a value.

We also want this word to "output" a value so it can be used to provide values for other words. The value that the word outputs is the x-y coordinates. Notice that we create the x-y coordinates using "(list :x :y)". This takes the two values we calculated and pairs them together (a pair of values is a list of 2 values).

How do we get the coordinates from the box? Mathematics! We divide the index by three and obtain the quotient and remainder. E.g., if the index is 7, divide 7 by 3, and we get 2r1. 2*3+1 = 7. The '2' is the quotient, and the '1' is the remainder. Type at the command prompt:

Commander
show remainder 7 3
1

You will get the answer "1". Now type at the command prompt:

Commander
show 7/3
2.33333333333333

Almost but not quite what we want. We really want '2', so we have to do this:

Commander
show int 7/3
2

Better! Somehow we need to convert this to 100, the value '1' to 0, and the value '0' to -100. Subtract 1 from the result (giving -1, 0 and 1 respectively) and multiply by 100 (giving -100, 0, 100 respectively).

We now need to test the new word.

Commander
show pos.from.index 7
[0 100]
show pos.from.index 8
[100 100]
show pos.from.index 0
[-100 -100]
show pos.from.index 4
[0 0]

Does this look right? Yes? Good. The square brackets indicate this is a list. You might be used to writing x-y coordinates as (100,100). In logo, it's written as [100 100].

Drawing the Pieces

Given an index (0 to 8) we want to draw either an "O" (oh) or an "X" (ex) in the appropriate box. We're going to write two words called "O" and "X". (This is the letter "O" not the number "0"). You will find out later how we can use these names. Create the first word "O" using the editor:

Editor
to O :ind
    ;
    ; place O piece
    ;
    setpc [0 255 0]
    setpensize [3 3]
    pu
    setpos pos.from.index :ind
    pd circle 30 pu
end

This is very simple, we set the pen color to Green, the pen size to 3 (medium). We move the turtle to the center of the circle, using "pos.from.index" we wrote earlier, and draw a circle of radius 30 (what is the diameter? Remember that diameter = 2r or 2xRadius.). The box is slightly smaller than 100x100, so we want a circle that will fit nicely in the box.

Now create the word "X":

Editor
to X :ind
    ;
    ; draw X piece
    ;
    local [pos x y]
    make "pos pos.from.index :ind
    make "x item 1 :pos
    make "y item 2 :pos
    setpc [255 0 0]
    setpensize [3 3]
    pu
    setpos (LIST :x-30 :y-30)
    pd
    setpos (LIST :x+30 :y+30)
    pu
    setpos (LIST :x-30 :y+30)
    pd
    setpos (LIST :x+30 :y-30)
    pu
end

We are drawing a cross that is 60x60. We use the "setpos" command to draw between absolute positions. What other ways can you do this? Notice that we use "make" three times. The first is to remember the result of "pos.from.index" (we called this "pos"). We then take the x and y coordinate from the position. Remember that the position may be [0 100], where x is 0 and y is 100. 0 is the first item of the list (item 1), and y is the second item of the list (item 2). We can write a list as [0 100], unless we have to do any calculations or substitute any values, in which case we have to write (list (1+2) (3+4)).

Once these words have been saved, try them out (think first what you should be seeing).

Commander
draw.grid
o 4
x 1
o 3
x 5

Initialization

Apart from drawing the grid, we need to have an internal representation of the grid that the program can work with. It needs it's own boxes, numbered 0 to 8, which reflect what is in the tic tac toe grid boxes 0 to 8. We will use an array.

Editor
to init
    ;
    ; initialization - create a grid of 9 entries (0-8)
    ; representing bottom-left to to-right
    ; ie
    ; 6 | 7 | 8
    ; --+---+---
    ; 3 | 4 | 5
    ; --+---+---
    ; 0 | 1 | 2
    ;
    ; initialize them all to "? (empty)
    ;
    ; draw the empty grid
    ;
    make "grid (array 9 0)
    make "turn "O ; this must be capital letter O
    for [i 0 8 1] [setitem :i :grid "?]
    draw.grid
end

We call this array "grid" so we can refer to it later. Note that since we didn't use "local", the variables can be seen outside of this word. Each box will have one of three values, "?" (empty), "X" (X there) or "O" (O there). We use the variable "turn" to determine who's currently playing. We set this to "O" as we determined that "O" plays first.

The next line beginning with the word "for" will go through the numbers 0, 1, 2, 3, 4, 5, 6, 7 and 8 (for each box in the grid). We want to set the value of each box to "?" and put them into the grid. Since "grid" is an array, we have to use "setitem" to set the values.

Finally we call "draw.grid" to draw the grid. You can try out this word as follows:

Commander
init
show :turn
O 
show :grid
{? ? ? ? ? ? ? ? ?}

This shows that 'O' will be playing first, and there isn't anything in the grid.

Back Up Next

 

Comments to WebMaster