
Task

Play a game of tic-tac-toe.

Ensure that legal moves are played and that a winning position is notified.


Tic-tac-toe   is also known as:

   naughts and crosses 
   tic tac toe 
   tick tack toe 
   three in a row 
   tres en rayo       and
   Xs  and  Os


See also
   MathWorld™, Tic-Tac-Toe game.
   Wikipedia tic-tac-toe.


 
Module Tic.Tac.Toe {
      Dim Board$(1 to 3, 1 to 3)=" "
      WinGame=False
      p=Board$()
      RandomPosition=lambda -> {
            =(random(1,3), random(1,3))
      }
 
      BoardItemEmpty=Lambda p (x, y) -> {
            =Array$(p, x, y)=" "
      }
      BoardSetItem=Lambda p (x, y, w$) -> {
            link p to a$()
            a$(x, y)=w$
      }
      T=9
      R=0
      C=0
      Repeat {
            Print "Computer Move:"
            CompMove()
            T--
            DrawBoard()
            CheckWin()
            if WinGame Then Print "Computer Win": Exit
            if T=0 then exit
            Repeat {
                  GetRowCol("Input Row", &R)
                  GetRowCol("Input Column", &C)
                  If BoardItemEmpty(R,C) then call boardsetitem(R,C,"O") : exit 
            } Always
            T--
            DrawBoard()
            CheckWin()
            if WinGame Then Print "You Win": Exit
      } until T=0 or WinGame
      Sub DrawBoard()
      Print "R/C 1 2 3"
      Print " 1) "; Board$(1,1);"|";Board$(1,2);"|";Board$(1,3)
      Print "    -+-+-"
      Print " 2) "; Board$(2,1);"|";Board$(2,2);"|";Board$(2,3)
      Print "    -+-+-"
      Print " 3) "; Board$(3,1);"|";Board$(3,2);"|";Board$(3,3)
      End Sub
      Sub CheckWin()
            WinGame=false
            local i,j,three$
            For i=1 to 3
                  three$=""
                  For j=1 to 3 : three$+=Board$(i,j) : Next j
                  CheckThree()
                  three$=""
                  For j=1 to 3 :  three$+=Board$(j,i) :Next j
                  CheckThree()
            Next i
            three$=""
            For i=1 to 3 : three$+=Board$(i,i): Next i
            CheckThree()
            three$=""
            For i=1 to 3:three$+=Board$(i,4-i): Next i
            CheckThree()
      End Sub
      Sub CheckThree()
            if instr(three$," ")=0 then  WinGame=WinGame or Filter$(three$, left$(three$,1))=""
      End Sub
      Sub CompMove()
            if T<9 and Board$(2,2)=" " then {
                  call boardsetitem(2,2,"X")
            } Else {
                  local i=3, j=3, found=false
                  if T<=6 then {
                        CompThink("X","X")
                  } 
                  let i=3, j=3
                  If Not found And T<6 then {
                        CompThink("O","X")    
                  }
                  If not found then {
                        Repeat {
                              comp=RandomPosition()
                              If BoardItemEmpty(!comp) then call boardsetitem(!comp, "X") : exit
                        } Always
                  }
            }
      End Sub
      Sub CompThink(Bad$, Good$)
                        While i>0 {
                              j=3
                              While j>0 {
                                    if Board$(i,j)=" " then {
                                          Board$(i,j)=Bad$
                                          CheckWin()
                                          if WinGame then {
                                                 Board$(i,j)=Good$:i=0:j=0: found=true
                                          } Else Board$(i,j)=" "
                                    }
                                    j--
                              }
                              i--
                        }
 
      End Sub
      Sub GetRowCol(What$, &W)
            Print What$;":";
            Repeat {
                  W=Val("0"+Key$)
            } until W>=1 and W<=3
            Print Str$(W,"")
      End Sub
}
Tic.Tac.Toe
 