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

 

Design
Programming
Initialize
Grid
Winning
Two Player
Single Player

Back Up

Against the Computer

We're not going to make the computer particularly clever (I'll leave that for you to change). When the computer takes its turn, it will do one of three things:

  1. Place a piece to win if we can win in this turn.
  2. Place a piece to block, if the opponent has two pieces in a row and could win in the next turn.
  3. Place a piece on the board at random.

Let's do the random placement first and fill in the game code:

Editor
to logoturn.random
    ;
    ; put a piece at random, must not be a piece already there
    ;
    localmake "sel 0
    do.while [make "sel (random 9)] [not grid.empty :sel]
    place :sel
end

Try this out:

Commander
init
logoturn.random
logoturn.random
logoturn.random

Create the initial "logoturn" word (we will change this later):

Editor
to logoturn
   ;
   ; processes computers turn
   ;
   logoturn.random
end

Decision on who plays the move:

Editor
to nextmove
    ;
    ; determine if next move is human or computer
    ; let that player move
    ;
    ifelse (equalp :turn "O) [yourturn] [logoturn]
end

The game loop for one-player game:

Editor
to tictactoe
    ;
    ; play tic tac toe
    ; we flip first, as flip is the first thing we do in loop
    ;
    init
    flip
    do.while [flip nextmove] [canmove]
end

We can create an alias word "go" as follows:

Editor

to go

    ;

    ; alternative word to tictactoe

    ;

    tictactoe

end

Try this out:

Commander
go

Adding AI

Here we get into some fun artificial intelligence. This word below is somewhat advanced so don't worry too much how it works. Its job is to allow us to try a sequence of solutions. If one of the solutions works for us, we stop there and respond "true" (yes, we have a solution). If we don't find any solutions, we respond "false" (no, we don't have a solution).

Editor
to l.or :lst
    ;
    ; list-or
    ; l.or [[cmd] [cmd] [cmd] ... ]
    ; execute each command in turn until the first cmd returns
    ; true
    ;
    ; returns "true if any returned "true, else returns "false
    ;
    localmake "flg "false
    foreach :lst [if (not :flg) [make "flg run ?]]
    output :flg
end

We need to test it:

Commander
show l.or ["false "false "false]
false 
show l.or ["false "false "true]
true 
show l.or ["true "false "false]
true 
show l.or ["true "true "false]
true 
show l.or [[= 1 1] "false "false]
true 

This will be a useful part of the AI as we want the computer to try different things until it was able to make a move. Once it's moved, we don't want it to make two moves. We'll now write the words "logoturn.win.row" and "logoturn.win" to determine if we can win, and place the winning piece:

Editor
to logoturn.win.row :a :b :c
    ;
    ; winning row is if two pieces are down,
    ; and the third place is empty
    ;
    ; runresult ["true] will result in [true]
    ; first [true] will result in true
    ; first runresult ["true] will result in true
    ; We do this, since logo didn't like [(place :c) "true]
    ; directly in the command parts of ifelse.
    ;
    output l.or [
        [ifelse (AND grid.me :a grid.me :b grid.empty :c)
                       [first runresult [(place :c) "true]]
                       ["false]
        ]
        [ifelse (AND grid.me :a grid.empty :b grid.me :c)
                       [first runresult [(place :b) "true]]
                       ["false]
        ]
        [ifelse (AND grid.empty :a grid.me :b grid.me :c)
                       [first runresult [(place :a) "true]]
                       ["false]
        ]
    ]
end

Notice how we used "l.or" to select one (and only one) of the winning combinations, responding "true" if we selected one, "false" if we didn't select any.

Editor
to logoturn.win
    ;
    ; if we're about to win, put the winning piece down
    ;
    output l.or [
        [logoturn.win.row 0 1 2]
        [logoturn.win.row 3 4 5]
        [logoturn.win.row 6 7 8]
        [logoturn.win.row 0 3 6]
        [logoturn.win.row 1 4 7]
        [logoturn.win.row 2 5 8]
        [logoturn.win.row 0 4 8]
        [logoturn.win.row 2 4 6]
    ]
end

Notice the use of "l.or" to try each of the winning rows. If we succeed, we will respond with "true", if we failed to place a winning piece, we respond with "false".

Similarly we need to block the opponent if they are about to win:

Editor
to logoturn.block.row :a :b :c
    ;
    ; like logoturn.win.row
    ; but checking for opponents pieces
    ;
    output l.or [
        [ifelse (AND grid.other :a grid.other :b grid.empty :c)
                  [first runresult [(place :c) "true]]
                  ["false]
        ]
        [ifelse (AND grid.other :a grid.empty :b grid.other :c)
                  [first runresult [(place :b) "true]]
                  ["false]
        ]
        [ifelse (AND grid.empty :a grid.other :b grid.other :c)
                  [first runresult [(place :a) "true]]
                  ["false]
        ]
    ]
end

Notice the use of "grid.other" to check for opponents pieces. We check for two pieces and one empty space.

Editor
to logoturn.block
    ;
    ; if the other player is about to win, block them
    ;
    output l.or [
        [logoturn.block.row 0 1 2]
        [logoturn.block.row 3 4 5]
        [logoturn.block.row 6 7 8]
        [logoturn.block.row 0 3 6]
        [logoturn.block.row 1 4 7]
        [logoturn.block.row 2 5 8]
        [logoturn.block.row 0 4 8]
        [logoturn.block.row 2 4 6]
    ]
end

We need to change the "logoturn" word to use the new AI.

Editor
to logoturn
   ;
   ; processes computers turn
   ;
   if not l.or [
       ;
       ; add to this to make computer more clever
       ;
       logoturn.win
       logoturn.block
   ] [
       ;
       ; if we didn't do anything clever, put a piece at random
       ;
       logoturn.random
   ]
end

Try it out and see if it works:

Commander
go

What now?

There are lots of ways you can improve this program. Make it more clever, print instructions on the screen, let the player know when it's their turn, do some fancy sounds/graphics when the player wins etc.

Back Up

 

Comments to WebMaster