Tic-tac-toe: Difference between revisions

338,435 bytes added ,  1 month ago
m
Fixed the name of the GitHub repo of the PostScript version
m (change “loose” to “lose” in three places)
m (Fixed the name of the GitHub repo of the PostScript version)
 
(231 intermediate revisions by 57 users not shown)
Line 1:
{{task|Games}}
[[Category:Games]]
Play a game of [[wp:Tic-tac-toe|tic-tac-toe]]. Ensure that legal moves are played and that a winning position is notified.
[[File:Tic_tac_toe.jpg|500px||right]]
 
;Task:
Play a game of [[wp:Tic-tac-toe|tic-tac-toe]].
 
Ensure that legal moves are played and that a winning position is notified.
 
 
''Tic-tac-toe''   is also known as:
::*   ''noughts and crosses''
::*   ''tic tac toe''
::*   ''tick tack toe''
::*   ''three in a row''
::*   ''tres en rayo''       and
::* &nbsp; ''<big>X</big>s &nbsp;and&nbsp; <big>O</big>s''
 
 
;See also
* &nbsp; [http://mathworld.wolfram.com/Tic-Tac-Toe.html MathWorld&trade;, Tic-Tac-Toe game].
* &nbsp; [https://en.wikipedia.org/wiki/Tic-tac-toe Wikipedia tic-tac-toe].
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">UInt32 seed = 0
F nonrandom_choice(lst)
:seed = 1664525 * :seed + 1013904223
R lst[:seed % UInt32(lst.len)]
 
V board = Array(‘123456789’)
V wins = ([0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6])
 
F printboard()
print([0, 3, 6].map(x -> (:board[x .+ 3]).join(‘ ’)).join("\n"))
 
F score(board = board) -> (Char, [Int])?
L(w) :wins
V b = board[w[0]]
I b C ‘XO’ & all(w.map(i -> @board[i] == @b))
R (b, w.map(i -> i + 1))
R N
 
F finished()
R all(:board.map(b -> b C ‘XO’))
 
F space(board = board)
R board.filter(b -> b !C ‘XO’)
 
F my_turn(xo, &board)
V options = space()
V choice = nonrandom_choice(options)
board[Int(choice) - 1] = xo
R choice
 
F my_better_turn(xo, &board)
‘Will return a next winning move or block your winning move if possible’
V ox = I xo == ‘X’ {Char(‘O’)} E Char(‘X’)
Int? oneblock
V options = space(board).map(s -> Int(s) - 1)
Int choice
L(chc) options
V brd = copy(board)
brd[chc] = xo
I score(brd) != N
choice = chc
L.break
I oneblock == N
brd[chc] = ox
I score(brd) != N
oneblock = chc
L.was_no_break
choice = oneblock ? nonrandom_choice(options)
board[choice] = xo
R choice + 1
 
F your_turn(xo, &board)
V options = space()
L
V choice = input("\nPut your #. in any of these positions: #. ".format(xo, options.join(‘’))).trim((‘ ’, "\t", "\r", "\n"))
I choice C options
board[Int(choice) - 1] = xo
R choice
print(‘Whoops I don't understand the input’)
 
F me(xo = Char(‘X’))
printboard()
print("\nI go at "my_better_turn(xo, &:board))
R score()
 
F you(xo = Char(‘O’))
printboard()
print("\nYou went at "my_turn(xo, &:board))
R score()
 
L !finished()
(Char, [Int])? s = me(Char(‘X’))
I s != N
printboard()
print("\n#. wins along #.".format(s[0], s[1]))
L.break
I !finished()
s = you(Char(‘O’))
I s != N
printboard()
print("\n#. wins along #.".format(s[0], s[1]))
L.break
L.was_no_break
print("\nA draw")</syntaxhighlight>
 
{{out}}
<pre>
1 2 3
4 5 6
7 8 9
 
I go at 8
1 2 3
4 5 6
7 X 9
 
You went at 3
1 2 O
4 5 6
7 X 9
 
I go at 1
X 2 O
4 5 6
7 X 9
 
You went at 5
X 2 O
4 O 6
7 X 9
 
I go at 7
X 2 O
4 O 6
X X 9
 
You went at 9
X 2 O
4 O 6
X X O
 
I go at 4
X 2 O
X O 6
X X O
 
X wins along [1, 4, 7]
</pre>
 
=={{header|Ada}}==
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO, Ada.Numerics.Discrete_Random;
-- can play human-human, human-computer, computer-human or computer-computer
-- the computer isn't very clever: it just chooses a legal random move
Line 126 ⟶ 281:
Ada.Text_IO.Put_Line("The winner is: " & Find_Winner(The_Board));
end if;
end Tic_Tac_Toe;</langsyntaxhighlight>
 
{{out}}
 
Output:
<pre>
> ./tic_tac_toe
Line 240 ⟶ 394:
</pre>
 
=={{header|ALGOL W}}==
The user can play O, X, both or neither. O goes first whether user or computer controlled.
<syntaxhighlight lang="algolw">begin
 
string(10) board;
 
% initialise the board %
procedure initBoard ; board := " 123456789";
 
% display the board %
procedure showBoard ;
begin
s_w := 0;
write( board(1//1), "|", board(2//1), "|", board(3//1) );
write( "-+-+-" );
write( board(4//1), "|", board(5//1), "|", board(6//1) );
write( "-+-+-" );
write( board(7//1), "|", board(8//1), "|", board(9//1) )
end showBoard ;
 
% returns true if board pos is free, false otherwise %
logical procedure freeSpace( integer value pos ) ;
( board(pos//1) >= "1" and board(pos//1) <= "9" );
 
% check for game over %
logical procedure gameOver ;
begin
logical noMoves;
noMoves := true;
for i := 1 until 9 do if noMoves then noMoves := not freeSpace( i );
noMoves
end gameOver ;
 
% makes the specified winning move or blocks it, if it will win %
logical procedure winOrBlock( integer value pos1, pos2, pos3
; string(1) value searchCharacter
; string(1) value playerCharacter
) ;
if board(pos1//1) = searchCharacter
and board(pos2//1) = searchCharacter
and freeSpace( pos3 )
then begin
board(pos3//1) := playerCharacter;
true
end
else if board(pos1//1) = searchCharacter
and freeSpace( pos2 )
and board(pos3//1) = searchCharacter
then begin
board(pos2//1) := playerCharacter;
true
end
else if freeSpace( pos1 )
and board(pos2//1) = searchCharacter
and board(pos3//1) = searchCharacter
then begin
board(pos1//1) := playerCharacter;
true
end
else begin
false
end winOrBlock ;
 
% makes a winning move or blocks a winning move, if there is one %
logical procedure makeOrBlockWinningMove( string(1) value searchCharacter
; string(1) value playerCharacter
) ;
( winOrBlock( 1, 2, 3, searchCharacter, playerCharacter )
or winOrBlock( 4, 5, 6, searchCharacter, playerCharacter )
or winOrBlock( 7, 8, 9, searchCharacter, playerCharacter )
or winOrBlock( 1, 4, 7, searchCharacter, playerCharacter )
or winOrBlock( 2, 5, 8, searchCharacter, playerCharacter )
or winOrBlock( 3, 6, 9, searchCharacter, playerCharacter )
or winOrBlock( 1, 5, 9, searchCharacter, playerCharacter )
or winOrBlock( 3, 5, 7, searchCharacter, playerCharacter )
) ;
 
% makes a move when there isn't an obvious winning/blocking move %
procedure move ( string(1) value playerCharacter ) ;
begin
logical moved;
moved := false;
% try for the centre, a corner or the midle of a line %
for pos := 5, 1, 3, 7, 9, 2, 4, 6, 8 do begin
if not moved and freeSpace( pos ) then begin
moved := true;
board(pos//1) := playerCharacter
end
end
end move ;
 
% gets a move from the user %
procedure userMove( string(1) value playerCharacter ) ;
begin
integer move;
while
begin
write( "Please enter the move for ", playerCharacter, " " );
read( move );
( move < 1 or move > 9 or not freeSpace( move ) )
end
do begin
write( "Invalid move" )
end;
board(move//1) := playerCharacter
end userMove ;
 
% returns true if the three board positions have the player character, %
% false otherwise %
logical procedure same( integer value pos1, pos2, pos3
; string(1) value playerCharacter
) ;
( board(pos1//1) = playerCharacter
and board(pos2//1) = playerCharacter
and board(pos3//1) = playerCharacter
);
 
% returns true if the player has made a winning move, false otherwise %
logical procedure playerHasWon( string(1) value playerCharacter ) ;
( same( 1, 2, 3, playerCharacter )
or same( 4, 5, 6, playerCharacter )
or same( 7, 8, 9, playerCharacter )
or same( 1, 4, 7, playerCharacter )
or same( 2, 5, 8, playerCharacter )
or same( 3, 6, 9, playerCharacter )
or same( 1, 5, 9, playerCharacter )
or same( 3, 5, 7, playerCharacter )
) ;
 
% takes a players turn - either automated or user input %
procedure turn ( string(1) value playerCharacter, otherCharacter
; logical value playerIsUser
) ;
begin
if playerIsUser then userMove( playerCharacter )
else begin
write( playerCharacter, " moves..." );
if not makeOrBlockWinningMove( playerCharacter, playerCharacter )
and not makeOrBlockWinningMove( otherCharacter, playerCharacter )
then move( playerCharacter )
end;
showBoard
end turn ;
 
% asks a question and returns true if the user inputs y/Y, %
% false otherwise %
logical procedure yes( string(32) value question ) ;
begin
string(1) answer;
write( question );
read( answer );
answer = "y" or answer = "Y"
end yes ;
 
% play the game %
while
begin
string(1) again;
string(32) gameResult;
logical oIsUser, xIsUser;
 
oIsUser := yes( "Do you want to play O? " );
xIsUser := yes( "Do you want to play X? " );
 
gameResult := "it's a draw";
initBoard;
showBoard;
while not gameOver and not playerHasWon( "O" ) and not playerHasWon( "X" ) do begin
turn( "O", "X", oIsUser );
if playerHasWon( "O" ) then gameResult := "O wins"
else if not gameOver then begin
turn( "X", "O", xIsUser );
if playerHasWon( "X" ) then gameResult := "X wins"
end
end ;
write( gameResult );
 
yes( "Play again? " )
end
do begin end
 
end.</syntaxhighlight>
{{out}}
<pre>
Do you want to play O? y
Do you want to play X? n
1|2|3
-+-+-
4|5|6
-+-+-
7|8|9
Please enter the move for O 5
1|2|3
-+-+-
4|O|6
-+-+-
7|8|9
X moves...
X|2|3
-+-+-
4|O|6
-+-+-
7|8|9
...etc...
Please enter the move for O 8
X|2|O
-+-+-
O|O|X
-+-+-
X|O|9
X moves...
X|X|O
-+-+-
O|O|X
-+-+-
X|O|9
Please enter the move for O 9
X|X|O
-+-+-
O|O|X
-+-+-
X|O|O
it's a draw
Play again? n
</pre>
 
=={{header|AppleScript}}==
<syntaxhighlight lang="applescript">property OMask : missing value
property XMask : missing value
property winningNumbers : {7, 56, 73, 84, 146, 273, 292, 448}
property difficulty : missing value
 
repeat
set OMask to 0
set XMask to 0
if button returned of (display dialog "Who should start?" buttons {"I shoud", "CPU"}) = "CPU" then set OMask to npcGet()
set difficulty to button returned of (display dialog "Please choose your difficulty" buttons {"Hard", "Normal"})
repeat
set XMask to XMask + 2 ^ (nGet() - 1)
if winnerForMask(XMask) or OMask + XMask = 511 then exit repeat
set OMask to npcGet()
if winnerForMask(OMask) or OMask + XMask = 511 then exit repeat
end repeat
if winnerForMask(OMask) then
set msg to "CPU Wins!"
else if winnerForMask(XMask) then
set msg to "You WON!!!"
else
set msg to "It's a draw"
end if
display dialog msg & return & return & drawGrid() & return & return & "Do you want to play again?"
end repeat
 
on nGet()
set theMessage to "It's your turn Player 1, please fill in the number for X" & return & return & drawGrid()
repeat
set value to text returned of (display dialog theMessage default answer "")
if (offset of value in "123456789") is not 0 then
if not positionIsUsed(value as integer) then exit repeat
end if
end repeat
return value as integer
end nGet
 
on npcGet()
--first get the free positions
set freeSpots to {}
repeat with s from 1 to 9
if not positionIsUsed(s) then set end of freeSpots to 2 ^ (s - 1)
end repeat
--second check if 1 move can make the CPU win
repeat with spot in freeSpots
if winnerForMask(OMask + spot) then return OMask + spot
end repeat
if difficulty is "Hard" and OMask is 0 then
if XMask = 1 or XMask = 4 then return 2
if XMask = 64 or XMask = 256 then return 128
end if
--third check if a user can make make it win (defensive) place it on position
repeat with spot in freeSpots
if winnerForMask(XMask + spot) then return OMask + spot
end repeat
--fourth check if CPU can win in two moves
repeat with spot1 in freeSpots
repeat with spot2 in freeSpots
if winnerForMask(OMask + spot1 + spot2) then return OMask + spot2
end repeat
end repeat
--fifth check if player can win in two moves
repeat with spot1 in freeSpots
repeat with spot2 in reverse of freeSpots
if winnerForMask(XMask + spot1 + spot2) then return OMask + spot1
end repeat
end repeat
--at last pick a random spot
if XMask + OMask = 0 and difficulty = "Hard" then return 1
return OMask + (some item of freeSpots)
end npcGet
 
on winnerForMask(mask)
repeat with winLine in winningNumbers
if BWAND(winLine, mask) = contents of winLine then return true
end repeat
return false
end winnerForMask
 
on drawGrid()
set grid to ""
repeat with o from 0 to 8
if BWAND(OMask, 2 ^ o) = 2 ^ o then
set grid to grid & "O"
else if BWAND(XMask, 2 ^ o) = 2 ^ o then
set grid to grid & "X"
else
set grid to grid & o + 1
end if
if o is in {2, 5} then set grid to grid & return
end repeat
return grid
end drawGrid
 
on positionIsUsed(pos)
return BWAND(OMask + XMask, 2 ^ (pos - 1)) = 2 ^ (pos - 1)
end positionIsUsed
 
on BWAND(n1, n2)
set theResult to 0
repeat with o from 0 to 8
if (n1 mod 2) = 1 and (n2 mod 2) = 1 then set theResult to theResult + 2 ^ o
set {n1, n2} to {n1 div 2, n2 div 2}
end repeat
return theResult as integer
end BWAND</syntaxhighlight>
 
=={{header|AutoHotkey}}==
This program uses a Gui with 9 buttons. Clicking on one will place an X there, disable the button, and cause the program to go somewhere.
It plays logically, trying to win, trying to block, or playing randomly in that order.
<langsyntaxhighlight AutoHotkeylang="autohotkey">Gui, Add, Button, x12 y12 w30 h30 vB1 gButtonHandler,
Gui, Add, Button, x52 y12 w30 h30 vB2 gButtonHandler,
Gui, Add, Button, x92 y12 w30 h30 vB3 gButtonHandler,
Line 350 ⟶ 844:
GuiClose:
ExitApp
</syntaxhighlight>
</lang>
 
=={{header|bashAWK}}==
<syntaxhighlight lang="awk">
# syntax: GAWK -f TIC-TAC-TOE.AWK
BEGIN {
move[12] = "3 7 4 6 8"; move[13] = "2 8 6 4 7"; move[14] = "7 3 2 8 6"
move[16] = "8 2 3 7 4"; move[17] = "4 6 8 2 3"; move[18] = "6 4 7 3 2"
move[19] = "8 2 3 7 4"; move[23] = "1 9 6 4 8"; move[24] = "1 9 3 7 8"
move[25] = "8 3 7 4 0"; move[26] = "3 7 1 9 8"; move[27] = "6 4 1 9 8"
move[28] = "1 9 7 3 4"; move[29] = "4 6 3 7 8"; move[35] = "7 4 6 8 2"
move[45] = "6 7 3 2 0"; move[56] = "4 7 3 2 8"; move[57] = "3 2 8 4 6"
move[58] = "2 3 7 4 6"; move[59] = "3 2 8 4 6"
split("7 4 1 8 5 2 9 6 3",rotate)
n = split("253 280 457 254 257 350 452 453 570 590",special)
i = 0
while (i < 9) { s[++i] = " " }
print("")
print("You move first, use the keypad:")
board = "\n7 * 8 * 9\n*********\n4 * 5 * 6\n*********\n1 * 2 * 3\n\n? "
printf(board)
}
state < 7 {
x = $0
if (s[x] != " ") {
printf("? ")
next
}
s[x] = "X"
++state
print("")
if (state > 1) {
for (i=0; i<r; ++i) { x = rotate[x] }
}
}
state == 1 {
for (r=0; x>2 && x!=5; ++r) { x = rotate[x] }
k = x
if (x == 5) { d = 1 } else { d = 5 }
}
state == 2 {
c = 5.5 * (k + x) - 4.5 * abs(k - x)
split(move[c],t)
d = t[1]
e = t[2]
f = t[3]
g = t[4]
h = t[5]
}
state == 3 {
k = x / 2.
c = c * 10
d = f
if (abs(c-350) == 100) {
if (x != 9) { d = 10 - x }
if (int(k) == k) { g = f }
h = 10 - g
if (x+0 == e+0) {
h = g
g = 9
}
}
else if (x+0 != e+0) {
d = e
state = 6
}
}
state == 4 {
if (x+0 == g+0) {
d = h
}
else {
d = g
state = 6
}
x = 6
for (i=1; i<=n; ++i) {
b = special[i]
if (b == 254) { x = 4 }
if (k+0 == abs(b-c-k)) { state = x }
}
}
state < 7 {
if (state != 5) {
for (i=0; i<4-r; ++i) { d = rotate[d] }
s[d] = "O"
}
for (b=7; b>0; b-=5) {
printf("%s * %s * %s\n",s[b++],s[b++],s[b])
if (b > 3) { print("*********") }
}
print("")
}
state < 5 {
printf("? ")
}
state == 5 {
printf("tie game")
state = 7
}
state == 6 {
printf("you lost")
state = 7
}
state == 7 {
printf(", play again? ")
++state
next
}
state == 8 {
if ($1 !~ /^[yY]$/) { exit(0) }
i = 0
while (i < 9) { s[++i] = " " }
printf(board)
state = 0
}
function abs(x) { if (x >= 0) { return x } else { return -x } }
</syntaxhighlight>
 
=={{header|Bash}}==
Computer is X. Computer randomly goes first. Computer plays a good game, but not a perfect game. It will win when it can and draw when it can not.
 
Line 372 ⟶ 983:
#encourage use of bash for more interesting tasks.
 
<langsyntaxhighlight lang="bash">
#!/bin/bash
declare -a B=( e e e e e e e e e ) # Board
Line 437 ⟶ 1,048:
show; [[ RANDOM%2 -eq 0 ]] && { turn O X; exit $?; } || turn X O
 
</syntaxhighlight>
</lang>
Output:{{out}} (nice ANSI formatting is not shown)
<pre>
Bic Bash Bow
Line 476 ⟶ 1,087:
3 | X | O
O | X | 8
</pre>
 
=={{header|BASIC}}==
==={{header|BASIC256}}===
<syntaxhighlight lang="basic256">
# basado en código de Antonio Rodrigo dos Santos Silva (gracias):
# http://statusgear.freeforums.net/thread/17/basic-256-tic-tac-toe
 
global playerturn$
global endGame$
global space$
global player1Score$
global player2Score$
global invalidMove$
global tecla$
global keyQ$
global keyW$
global keyE$
global keyA$
global keyS$
global keyD$
global keyZ$
global keyX$
global keyC$
global keySpace$
global keyEsc$
 
keyQ$ = 81
keyW$ = 87
keyE$ = 69
keyA$ = 65
keyS$ = 83
keyD$ = 68
keyZ$ = 90
keyX$ = 88
keyC$ = 67
keySpace$ = 32
keyEsc$ = 16777216
 
dim space$(9)
 
 
subroutine clearGameVars()
playerturn$ = 1
invalidMove$ = 0
endGame$ = 0
tecla$ = 0
 
for t = 0 to space$[?]-1
space$[t] = 0
next t
end subroutine
 
subroutine endGame()
cls
print "¡Hasta pronto!..."
end
end subroutine
 
subroutine printBoard()
print " " + space$[0]+" | "+space$[1]+" | "+space$[2]
print " " + "— + — + —"
print " " + space$[3]+" | "+space$[4]+" | "+space$[5]
print " " + "— + — + —"
print " " + space$[6]+" | "+space$[7]+" | "+space$[8]
print ""
end subroutine
 
subroutine changePlayer()
if playerturn$ = 1 then
playerturn$ = 2
else
playerturn$ = 1
end if
end subroutine
 
subroutine endMatchWithWinner()
cls
call printPlayerScore()
call printBoard()
endGame$ = 1
 
if playerturn$ = 1 then
player1Score$ += 1
else
player2Score$ += 1
end if
 
print "¡Jugador " + playerturn$ + " gana!" + chr(10)
print "Pulsa [SPACE] para jugar otra partida"
print "Pulsa [ESC] para dejar de jugar"
do
tecla$ = key
pause .01
if tecla$ = keySpace$ then call gamePlay()
if tecla$ = keyEsc$ then call endGame()
until false
end subroutine
 
subroutine endMatchWithoutWinner()
cls
call printPlayerScore()
call printBoard()
endGame$ = 1
 
print " Nadie ganó :( " + chr(10)
print " Pulsa [SPACE] para comenzar o [ESC] para salir. "
do
tecla$ = key
pause .01
if tecla$ = keySpace$ then call gamePlay()
if tecla$ = keyEsc$ then call endGame()
until false
end subroutine
 
subroutine printPlayerScore()
print "--------------------------------------------"
print " Jugador #1: " + player1Score$ + " pts"
print " Jugador #2: " + player2Score$ + " pts"
print "--------------------------------------------" + chr(10)
end subroutine
 
 
subroutine printPlayerMessage()
print "Jugador: " + playerturn$ + ", elige una casilla, por favor."
end subroutine
 
subroutine gamePlay()
call clearGameVars()
cls
call printPlayerScore()
call printBoard()
call printPlayerMessage()
while 0 = 0
invalidMove$ = 0
 
if endGame$ = 0 then
do
tecla$ = key
pause .01
validKeypressed$ = 0
if tecla$ = keyQ$ or tecla$ = keyW$ or tecla$ = keyE$ or tecla$ = keyA$ or tecla$ = keyS$ or tecla$ = keyD$ or tecla$ = keyZ$ or tecla$ = keyX$ or tecla$ = keyC$ then validKeypressed$ = 1
until validKeypressed$ = 1
endif
 
if tecla$ = keyQ$ then
if space$[0] = 0 then
space$[0] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyW$ then
if space$[1] = 0 then
space$[1] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyE$ then
if space$[2] = 0 then
space$[2] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyA$ then
if space$[3] = 0 then
space$[3] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyS$ then
if space$[4] = 0 then
space$[4] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyD$ then
if space$[5] = 0 then
space$[5] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyZ$ then
if space$[6] = 0 then
space$[6] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyX$ then
if space$[7] = 0 then
space$[7] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if tecla$ = keyC$ then
if space$[8] = 0 then
space$[8] = playerturn$
else
invalidMove$ = 1
endif
endif
 
if invalidMove$ = 0 then
tecla$ = 0
 
if space$[0] = 1 and space$[1] = 1 and space$[2] = 1 then call endMatchWithWinner()
if space$[3] = 1 and space$[4] = 1 and space$[5] = 1 then call endMatchWithWinner()
if space$[6] = 1 and space$[7] = 1 and space$[8] = 1 then call endMatchWithWinner()
if space$[0] = 1 and space$[3] = 1 and space$[6] = 1 then call endMatchWithWinner()
if space$[1] = 1 and space$[4] = 1 and space$[7] = 1 then call endMatchWithWinner()
if space$[2] = 1 and space$[5] = 1 and space$[8] = 1 then call endMatchWithWinner()
if space$[0] = 1 and space$[4] = 1 and space$[8] = 1 then call endMatchWithWinner()
if space$[2] = 1 and space$[4] = 1 and space$[6] = 1 then call endMatchWithWinner()
if space$[0] = 2 and space$[1] = 2 and space$[2] = 2 then call endMatchWithWinner()
if space$[3] = 2 and space$[4] = 2 and space$[5] = 2 then call endMatchWithWinner()
if space$[6] = 2 and space$[7] = 2 and space$[8] = 2 then call endMatchWithWinner()
if space$[0] = 2 and space$[3] = 2 and space$[6] = 2 then call endMatchWithWinner()
if space$[1] = 2 and space$[4] = 2 and space$[7] = 2 then call endMatchWithWinner()
if space$[2] = 2 and space$[5] = 2 and space$[8] = 2 then call endMatchWithWinner()
if space$[0] = 2 and space$[4] = 2 and space$[8] = 2 then call endMatchWithWinner()
if space$[2] = 2 and space$[4] = 2 and space$[6] = 2 then call endMatchWithWinner()
 
if space$[0] <> 0 and space$[1] <> 0 and space$[2] <> 0 and space$[3] <> 0 and space$[4] <> 0 and space$[5] <> 0 and space$[6] <> 0 and space$[7] <> 0 and space$[8] <> 0 then call endMatchWithoutWinner()
 
call changePlayer()
cls
call printPlayerScore()
call printBoard()
call printPlayerMessage()
end if
 
end while
end subroutine
 
subroutine gameMenu()
cls
call clearGameVars()
 
player1Score$ = 0
player2Score$ = 0
 
print "================================================="
print "| TIC-TAC-TOE |"
print "=================================================" + chr(10)
print " Teclas para jugar:"
print "---------------------"
print " | q | w | e |"
print " | a | s | d |"
print " | z | x | c |" + chr(10)
print " Pulsa [SPACE] para comenzar o [ESC] para salir. "
do
tecla$ = key
pause .01
if tecla$ = keySpace$ then call gamePlay()
if tecla$ = keyEsc$ then call endGame()
until false
end subroutine
 
call gameMenu()
end
</syntaxhighlight>
 
==={{header|FreeBASIC}}===
====graphics mode====
<syntaxhighlight lang="freebasic">
 
'About 400 lines of code, but it is a graphical (GUI ish) i.e. mouse driven.
'I have made provision for the player to beat the computer now and then.
 
Type box
As long x,y
As long wide,high,index
Dim As ulong colour
As String caption
Declare Sub show
Declare Sub NewCaption(s As String)
Declare Constructor
Declare Constructor(x As long,y As long,wide As long,_
high As long,index As long,colour As ulong,caption As String)
End Type
Constructor box
End Constructor
Constructor box(x As long,y As long,wide As long,_
high As long,index As long,colour As ulong,caption As String)
this.x=x
this.y=y
this.wide=wide
this.high=high
this.index=index
this.colour=colour
this.caption=caption
End Constructor
'ALL PROCEDURES:
Declare Function inside(B As box,px As long,py As long) As long
Declare Sub make_frame_image(im As ulong Pointer)
Declare Sub setup_grid(boxes() As box,cellsacross As long,cellsdown As long,xp As long,yp As long,w As long,h As long)
Declare Function all_clicked(b() As box) As long
Declare Sub OnCLICK(a() As box,b As box)
Declare Sub refresh_screen(b() As box,f1 As long=0,f2 As long=0)
Declare Function Get_Mouse_Events(boxes() As box) As long
Declare Sub thickline(x1 As long,y1 As long,x2 As long,y2 As long,thickness As Single,colour As ulong,im As Any Pointer=0)
Declare Sub lineto(x1 As long,y1 As long,x2 As long,y2 As long,l As long,th As Single,col As ulong,im As Any Pointer=0)
Declare Sub thickcircle(x As long,y As long,rad As long,th As Single,col As ulong,im As Any Pointer=0)
Declare Sub startup(b() As box)
Declare Sub get_computer_events(b() As box)
 
Declare Sub finish
'Macro used by more than one procedure
#macro incircle(cx,cy,radius,x,y)
(cx-x)*(cx-x) +(cy-y)*(cy-y)<= radius*radius
#endmacro
'=============== RUN ============================
Screen 19,32',1,16
Color ,Rgb(233,236,216) 'background colour
windowtitle string(100," ")+"Noughts and crosses"
'Globals:
Dim Shared As ulong Pointer frame
Dim Shared As long computer,player
Dim Shared As String msg1,msg2,message
message="In Play"
msg1="Computer Start"
msg2="Player Start"
'Custom Frame
frame=Imagecreate(800,600)
 
Dim As box boxes(0 To 9)
 
setup_grid(boxes(),3,3,175,85,150,150)
make_frame_image(frame)
 
Do
If player=0 And computer=0 Then
startup(boxes())
End If
If player Then
Get_Mouse_Events(boxes())
End If
If computer Then
get_computer_events(boxes())
End If
If all_clicked(boxes()) Then get_computer_events(boxes())
Loop Until Inkey=Chr(27)
finish
 
Sub box.show
Line(this.x,this.y)-(this.x+this.wide,this.y+this.high),this.colour,bf
Line(this.x,this.y)-(this.x+this.wide,this.y+this.high),Rgb(200,200,200),b
''Draw String(this.x+.5*this.wide-4*Len(this.caption),this.y+(.5*this.high-4)),this.caption,Rgb(0,0,0)
If this.index=0 Then
Draw String(this.x+.5*this.wide-4*Len(this.caption),this.y+.5*this.high-6),this.caption,Rgb(0,0,0)
End If
End Sub
 
Sub box.NewCaption(s As String)
Var cx=(this.x+this.x+this.wide)/2
Var cy=(this.y+this.y+this.high)/2
If s="X" Then
For k As long=20 To 0 Step -1
lineto(cx,cy,this.x,this.y,50,k,Rgb(50+10*k,5*k,0),frame)
lineto(cx,cy,this.x+this.wide,this.y+this.high,50,k,Rgb(50+10*k,5*k,0),frame)
lineto(cx,cy,this.x,this.y+this.high,50,k,Rgb(50+10*k,5*k,0),frame)
lineto(cx,cy,this.x+this.wide,this.y,50,k,Rgb(50+10*k,5*k,0),frame)
Next k
Else
For k As long=20 To 0 Step -1
thickcircle(cx,cy,40,k,Rgb(50+10*k,5*k,0),frame)
Next k
End If
End Sub
 
Sub get_computer_events(b() As box)
#define other(n) b(n).caption<>"0" And b(n).caption<>"C"
#define another(n) b(n).caption="0"
#define rr(f,l) (Rnd*((l)-(f))+(f))
Dim As long flag,i,k,Cwin,Pwin,NoWin
Static As long firstclick
var chance="001100"
dim as long ch
'horiz player finish
For x As long=1 To 3
If b(1+k).caption="0" And b(2+k).caption="0" And another((3+k)) Then b(3+k).Caption="0":Pwin=1:Goto fin
If b(2+k).caption="0" And b(3+k).caption="0" And another((1+k))Then b(1+k).Caption="0":Pwin=1=1:Goto fin
If b(1+k).caption="0" And b(3+k).caption="0" And another((2+k))Then b(2+k).Caption="0":Pwin=1:Goto fin
k=k+3
Next x
k=0
'vert player finish
For x As long=1 To 3
If b(1+k).caption="0" And b(4+k).caption="0" And another((7+k)) Then b(7+k).Caption="0":Pwin=1:Goto fin
If b(4+k).caption="0" And b(7+k).caption="0" And another((1+k))Then b(1+k).Caption="0":Pwin=1:Goto fin
If b(1+k).caption="0" And b(7+k).caption="0" And another((4+k))Then b(4+k).Caption="0":Pwin=1:Goto fin
k=k+1
Next x
k=0
'player finish main diag
If b(1+k).caption="0" And b(5+k).caption="0" And another((9+k)) Then b(9+k).Caption="0":Pwin=1:Goto fin
If b(1+k).caption="0" And b(9+k).caption="0" And another((5+k))Then b(5+k).Caption="0":Pwin=1:Goto fin
If b(5+k).caption="0" And b(9+k).caption="0" And another((1+k))Then b(1+k).Caption="0":Pwin=1:Goto fin
'player finish other diag
If b(7+k).caption="0" And b(5+k).caption="0" And another((3+k)) Then b(3+k).Caption="0":Pwin=1:Goto fin
If b(5+k).caption="0" And b(3+k).caption="0" And another((7+k))Then b(7+k).Caption="0":Pwin=1:Goto fin
If b(7+k).caption="0" And b(3+k).caption="0" And another((5+k))Then b(5+k).Caption="0":Pwin=1:Goto fin
'horiz computer finish
For x As long=1 To 3
If b(1+k).caption="C" And b(2+k).caption="C" And other((3+k)) Then b(3+k).Caption="C":Cwin=1:Goto fin
If b(2+k).caption="C" And b(3+k).caption="C" And other((1+k))Then b(1+k).Caption="C":Cwin=1:Goto fin
If b(1+k).caption="C" And b(3+k).caption="C" And other((2+k))Then b(2+k).Caption="C":Cwin=1:Goto fin
k=k+3
Next x
k=0
'vert computer finish
For x As long=1 To 3
If b(1+k).caption="C" And b(4+k).caption="C" And other((7+k)) Then b(7+k).Caption="C":Cwin=1:Goto fin
If b(4+k).caption="C" And b(7+k).caption="C" And other((1+k))Then b(1+k).Caption="C":Cwin=1:Goto fin
If b(1+k).caption="C" And b(7+k).caption="C" And other((4+k))Then b(4+k).Caption="C":Cwin=1:Goto fin
k=k+1
Next x
k=0
'computer finish main diag
If b(1+k).caption="C" And b(5+k).caption="C" And other((9+k)) Then b(9+k).Caption="C":Cwin=1:Goto fin
If b(1+k).caption="C" And b(9+k).caption="C" And other((5+k))Then b(5+k).Caption="C":Cwin=1:Goto fin
If b(5+k).caption="C" And b(9+k).caption="C" And other((1+k))Then b(1+k).Caption="C":Cwin=1:Goto fin
'computer finish other diag
If b(7+k).caption="C" And b(5+k).caption="C" And other((3+k)) Then b(3+k).Caption="C":Cwin=1:Goto fin
If b(5+k).caption="C" And b(3+k).caption="C" And other((7+k))Then b(7+k).Caption="C":Cwin=1:Goto fin
If b(7+k).caption="C" And b(3+k).caption="C" And other((5+k))Then b(5+k).Caption="C":Cwin=1:Goto fin
'block horizontals
For x As long=1 To 3
If b(1+k).caption="0" And b(2+k).caption="0" And other((3+k)) Then b(3+k).Caption="C":flag=1:Goto fin
If b(2+k).caption="0" And b(3+k).caption="0" And other((1+k))Then b(1+k).Caption="C":flag=1:Goto fin
If b(1+k).caption="0" And b(3+k).caption="0" And other((2+k))Then b(2+k).Caption="C":flag=1:Goto fin
k=k+3
Next x
k=0
'block verticals
For x As long=1 To 3
If b(1+k).caption="0" And b(4+k).caption="0" And other((7+k)) Then b(7+k).Caption="C":flag=1:Goto fin
If b(4+k).caption="0" And b(7+k).caption="0" And other((1+k))Then b(1+k).Caption="C":flag=1:Goto fin
If b(1+k).caption="0" And b(7+k).caption="0" And other((4+k))Then b(4+k).Caption="C":flag=1:Goto fin
k=k+1
Next x
k=0
'block main diag
If b(1+k).caption="0" And b(5+k).caption="0" And other((9+k)) Then b(9+k).Caption="C":flag=1:Goto fin
If b(1+k).caption="0" And b(9+k).caption="0" And other((5+k))Then b(5+k).Caption="C":flag=1:Goto fin
If b(5+k).caption="0" And b(9+k).caption="0" And other((1+k))Then b(1+k).Caption="C":flag=1:Goto fin
'block other diag
If b(7+k).caption="0" And b(5+k).caption="0" And other((3+k)) Then b(3+k).Caption="C":flag=1:Goto fin
If b(5+k).caption="0" And b(3+k).caption="0" And other((7+k))Then b(7+k).Caption="C":flag=1:Goto fin
If b(7+k).caption="0" And b(3+k).caption="0" And other((5+k))Then b(5+k).Caption="C":flag=1:Goto fin
If firstclick=0 Then
firstclick=1
var st="1379"
dim as long i=rr(0,3)
If Valint(b(5).caption)=0 and b(5).caption <> "C" Then b(st[i]-48).caption="C":Goto fin
End If
ch=rr(0,5)
if chance[ch]-48=1 then
If Valint(b(5).caption)<>0 Then b(5).caption="C":Goto fin
end if
If all_clicked(b()) Then Nowin=1:Goto fin
If flag=0 Then
Randomize
Do
i=rr(1,9)
If Valint(b(i).caption) <> 0 Then b(i).caption="C":Exit Do
Loop
End If
fin:
If Cwin=1 Or Pwin=1 Or NoWin=1 Then
Dim As long mx,my,mb
dim as integer x,y
screencontrol 0,x,y
for z as single=0 to 8*atn(1) step .001
dim as integer xx=x+100*cos(z)
dim as integer yy=y+100*sin(z)
screencontrol 100,xx,yy
next z
screencontrol 100,x,y
If Cwin=1 Then Message="You Loose"
If Pwin=1 Then Message="You WIN"
If Nowin=1 Then Message="DRAW"
cwin=0:k=0:pWin=0:Nowin=0:firstclick=0'i
Do
Getmouse mx,my,,mb
If inside(b(0),mx,my) And mb=1 Then finish
Var ic=incircle(500,55,20,mx,my)
If incircle(500,55,20,mx,my) And mb=1 Then Exit Do
refresh_screen(b(),ic)
Loop Until Inkey=chr(27)
For z As long=1 To Ubound(b)
b(z).caption=Str(b(z).index)
Next z
Imagedestroy frame
frame=Imagecreate(800,600)
make_frame_image(frame)
computer=0:player=0
Exit Sub
End If
player=1:computer=0
End Sub
 
Sub startup(b() As box)
message="In Play"
Dim As long mx,my,mb
Getmouse mx,my,,mb
For n As long=0 To Ubound(b)
If inside(b(n),mx,my) And mb=1 Then
If b(n).index=0 Then
finish
End If
End If
b(0).colour=Rgb(200,0,0)
Next n
Dim As long f1,f2
If incircle(80,230,10,mx,my) Then
f1=1:f2=0
If mb=1 Then computer=1:player=0
End If
If incircle(670,230,10,mx,my) Then
f1=0:f2=1
If mb=1 Then player=1:computer=0
End If
refresh_screen(b(),f1,f2)
End Sub
 
Sub thickcircle(x As long,y As long,rad As long,th As Single,col As ulong,im As Any Pointer=0)
Circle(x,y),rad+th/2,col
Circle(x,y),rad-th/2,col
Paint(x,y+rad),col,col
End Sub
 
Sub thickline(x1 As long,_
y1 As long,_
x2 As long,_
y2 As long,_
thickness As Single,_
colour As ulong,_
im As Any Pointer=0)
Dim p As ulong=Rgb(255, 255, 255)
If thickness<2 Then
Line(x1,y1)-(x2,y2),colour
Else
Dim As Double s,h,c
h=Sqr((x2-x1)^2+(y2-y1)^2)
If h=0 Then h=1e-6
s=(y1-y2)/h
c=(x2-x1)/h
For x As long=1 To 2
Line im,(x1+s*thickness/2,y1+c*thickness/2)-(x2+s*thickness/2,y2+c*thickness/2),p
Line im,(x1-s*thickness/2,y1-c*thickness/2)-(x2-s*thickness/2,y2-c*thickness/2),p
Line im,(x1+s*thickness/2,y1+c*thickness/2)-(x1-s*thickness/2,y1-c*thickness/2),p
Line im,(x2+s*thickness/2,y2+c*thickness/2)-(x2-s*thickness/2,y2-c*thickness/2),p
Paint im,((x1+x2)/2, (y1+y2)/2), p, p
p=colour
Next x
End If
End Sub
 
Sub lineto(x1 As long,y1 As long,x2 As long,y2 As long,l As long,th As Single,col As ulong,im As Any Pointer=0)
Dim As long diffx=x2-x1,diffy=y2-y1,ln=Sqr(diffx*diffx+diffy*diffy)
Dim As Single nx=diffx/ln,ny=diffy/ln
thickline(x1,y1,(x1+l*nx),(y1+l*ny),th,col,im)
End Sub
 
Function inside(B As box,px As long,py As long) As long
Return (px>B.x)*(px<(B.x+B.wide))*(py>B.y)*(py<(B.y+B.high))
End Function
Sub make_frame_image(im As ulong Pointer)
#macro map(a,b,x,d,c)
((d)-(c))*((x)-(a))/((b)-(a))+(c)
#endmacro
#macro logo(sx,sy,rad)
For k As Single=-rad/10 To rad/10 Step .5:Circle im,(sx,sy),rad+k,Rgb(15,118,155):Next
For k As Single=-rad/10 To rad/10 Step .5:Circle im,(sx+1.3*rad,sy+rad),rad+k,Rgb(230,193,78),2.,1.7:Next
For k As Single=-rad/10 To rad/10 Step .5:Circle im,(sx+2*1.3*rad,sy),rad+k,Rgb(21,3,0),3.25,3.05:Next
For k As Single=-rad/10 To rad/10 Step .5:Circle im,(sx+3*1.3*rad,sy+rad),rad+k,Rgb(26,143,76),2,1.8:Next
For k As Single=-rad/10 To rad/10 Step .5:Circle im,(sx+4*1.3*rad,sy),rad+k,Rgb(200,63,87),3.25,3.05:Next
#endmacro
For k As long=0 To 50
Var r=map(0,50,k,233,193-20)
Var g=map(0,50,k,236,153-20)
Var b=map(0,50,k,216,19-19)
Line im,(0+k,20+k)-(800-k,600-k),Rgb(r,g,b),b
Next k
For k As long=0 To 20
Var r=map(0,20,k,250,0)
Var g=map(0,20,k,250,0)
Var b=map(0,20,k,250,255)
Line im,(0,k)-(780,k),Rgb(r,g,b)',bf
Next k
logo(60,8,5)
logo(380,8,5)
logo(720,8,5)
End Sub
Sub setup_grid(boxes() As box,cellsacross As long,cellsdown As long,xp As long,yp As long,w As long,h As long)
Dim As long index
For y As long=yp To yp+h*(cellsdown-1) Step h
For x As long=xp To xp+w*(cellsacross-1) Step w
index=index+1
boxes(index)=Type<box>(x,y,w,h,index,Rgb(133,136,116),Str(index))
Next x
Next y
boxes(0)=Type<box>(780,-2,20,24,0,Rgb(200,0,0),"X")
End Sub
 
Function all_clicked(b() As box) As long
Dim As long sum
For z As long=1 To Ubound(b)
sum=sum+Valint(b(z).caption)
Next z
If sum<=0 Then Return -1
End Function
 
Sub OnCLICK(a() As box,b As box)
If b.caption="0" Then Exit Sub
If b.caption="C" Then Exit Sub
If b.caption <> "C" Then b.caption="0"
If b.index=0 Then finish
player=0:computer=1
End Sub
 
Sub refresh_screen(b() As box,f1 As long=0,f2 As long=0)
Screenlock:Cls
For n As long=0 To Ubound(b)
b(n).show 'draw boxes
If b(n).caption="0" Then b(n).NewCaption("X")
If b(n).caption="C" Then b(n).NewCaption("O")
Next n
Put(0,0),frame,trans
Draw String (390,50),message,Rgb(0,0,0)
If message <>"In Play" Then
Circle(500,55),20,Rgb(255,20,255),,,,f
If f1=-1 Then Circle(500,55),20,Rgb(202,200,200),,,,f
Draw String(480,50),"Click",Rgb(0,0,0)
End If
If computer=0 And player=0 Then
Draw String (60,200),msg1,Rgb(0,0,0)
Circle(80,230),10,Rgb(0,0,0)
Circle(80,230),5,Rgb(100,100,100),,,,f
If f1=1 Then Circle(80,230),10,Rgb(200,0,0),,,,f
Draw String (650,200),msg2,Rgb(0,0,0)
Circle(670,230),10,Rgb(0,0,0)
Circle(670,230),5,Rgb(100,100,100),,,,f
If f2=1 Then Circle(670,230),10,Rgb(200,0,0),,,,f
End If
Screenunlock:Sleep 1,1
End Sub
 
Function Get_Mouse_Events(boxes() As box) As long
Static released As long
Static pressed As long
Dim As long mousex,mousey,mousebutton ,x,y
Getmouse mousex,mousey,,mousebutton
Dim As box bar=Type<box>(0,0,780,50,0,0,"")
refresh_screen(boxes())
For n As long=0 To Ubound(boxes)
If inside(boxes(n),mousex,mousey) Then
If released Then
boxes(n).colour=Rgb(120,123,103)
If n=0 Then boxes(0).colour=Rgb(255,0,0)
End If
If mousebutton=1 Then
If released Then OnCLICK(boxes(),boxes(n))
Exit For
End If
Else
boxes(n).colour=Rgb(133,136,116)
If n=0 Then boxes(0).colour=Rgb(200,0,0)
End If
Next n
If mousebutton=0 Then released=1 Else released=0 'clean clicks
Return 0
End Function
Sub finish
Screenunlock
Imagedestroy frame
End
End Sub
</syntaxhighlight>
 
====text mode====
<syntaxhighlight lang="freebasic">
Screenres 320,240,32
 
'global variables globales
Dim Shared As Integer b(3,3) 'tablero
Dim Shared As Integer mx, my, btns, ox, oy
 
'prueba para ganar posición
'3 victorias horizontales
Function TestWin(t As Integer) As Integer
Dim As Integer win = 0
If b(0,0)= t And b(1,0)= t And b(2,0)= t Then win = t
If b(0,1)= t And b(1,1)= t And b(2,1)= t Then win = t
If b(0,2)= t And b(1,2)= t And b(2,2)= t Then win = t
'3 en vertical gana
If b(0,0)= t And b(0,1)= t And b(0,2)= t Then win = t
If b(1,0)= t And b(1,1)= t And b(1,2)= t Then win = t
If b(2,0)= t And b(2,1)= t And b(2,2)= t Then win = t
'cruzada gana
If b(0,0)= t And b(1,1)= t And b(2,2)= t Then win = t
If b(2,0)= t And b(1,1)= t And b(0,2)= t Then win = t
Return win
End Function
 
Sub InicializarTablero()
For j As Integer = 0 To 2
For i As Integer = 0 To 2
b(i,j)=0
Next i
Next j
End Sub
 
Sub DibujaTablero()
Locate 1,1 : Print "+---+---+---+"
For j As Integer = 0 To 2
Print "|";
For i As Integer = 0 To 2
If b(i,j) = 0 Then Print " |";
If b(i,j) = 1 Then Print " x |";
If b(i,j) = 2 Then Print " o |";
Next i
Print !"\n+---+---+---+"
Next j
End Sub
 
Function MovimientoHumano() As Integer
DibujaTablero()
Print !"\n HAZ CLICK CON EL MOUSE"
Print "EN LA CASILLA QUE ELIJAS"
Dim As Integer opcion = -1
While opcion = -1
Getmouse mx,my,,btns
While btns <> 1 'esperar a pulsar botón
Getmouse mx,my,,btns
Wend
mx = (mx-4)\32
my = (my-4)\16
If mx >= 0 And mx < 3 And my >= 0 And my < 3 Then
If b(mx,my) = 0 Then opcion = mx+my*3 'Casilla vacía?
End If
While btns=1
Getmouse mx,my,,btns
Wend
Wend
Return opcion
End Function
 
Function MovimientoAleatorio() As Integer
Dim As Integer opcion, i, j
opcion = Int(Rnd(1)*9)
j = Int(opcion/3)
i = opcion - Int(opcion/3)*3
While b(i,j) <> 0 Or (opcion > 8 Or opcion < 0)
opcion = Int(Rnd(1)*9)
j = Int(opcion/3)
i = opcion - Int(opcion/3)*3
Wend
Return j*3+i
End Function
 
Function MovimientoInteligente(t As Integer) As Integer
Dim As Integer i, j, opcion, t2
opcion = -1 'opcion aún no seleccionada
'obtener la ficha t2 de los oponentes
If t = 1 Then t2 = 2 Else t2 = 1
'prueba para la casilla central
If b(1,1) = 0 Then opcion = 4
'prueba para ganar
If opcion = -1 Then
If b(0,0)= 0 And b(1,0)= t And b(2,0)= t Then opcion = 0
If b(0,0)= t And b(1,0)= 0 And b(2,0)= t Then opcion = 1
If b(0,0)= t And b(1,0)= t And b(2,0)= 0 Then opcion = 2
If b(0,1)= 0 And b(1,1)= t And b(2,1)= t Then opcion = 3
If b(0,1)= t And b(1,1)= 0 And b(2,1)= t Then opcion = 4
If b(0,1)= t And b(1,1)= t And b(2,1)= 0 Then opcion = 5
If b(0,2)= 0 And b(1,2)= t And b(2,2)= t Then opcion = 6
If b(0,2)= t And b(1,2)= 0 And b(2,2)= t Then opcion = 7
If b(0,2)= t And b(1,2)= t And b(2,2)= 0 Then opcion = 8
'3 bloques verticales
If b(0,0)= 0 And b(0,1)= t And b(0,2)= t Then opcion = 0
If b(0,0)= t And b(0,1)= 0 And b(0,2)= t Then opcion = 3
If b(0,0)= t And b(0,1)= t And b(0,2)= 0 Then opcion = 6
If b(1,0)= 0 And b(1,1)= t And b(1,2)= t Then opcion = 1
If b(1,0)= t And b(1,1)= 0 And b(1,2)= t Then opcion = 4
If b(1,0)= t And b(1,1)= t And b(1,2)= 0 Then opcion = 7
If b(2,0)= 0 And b(2,1)= t And b(2,2)= t Then opcion = 2
If b(2,0)= t And b(2,1)= 0 And b(2,2)= t Then opcion = 5
If b(2,0)= t And b(2,1)= t And b(2,2)= 0 Then opcion = 8
'bloques cruzados
If b(0,0)= 0 And b(1,1)= t And b(2,2)= t Then opcion = 0
If b(0,0)= t And b(1,1)= 0 And b(2,2)= t Then opcion = 4
If b(0,0)= t And b(1,1)= t And b(2,2)= 0 Then opcion = 8
If b(2,0)= 0 And b(1,1)= t And b(0,2)= t Then opcion = 2
If b(2,0)= t And b(1,1)= 0 And b(0,2)= t Then opcion = 4
If b(2,0)= t And b(1,1)= t And b(0,2)= 0 Then opcion = 6
End If
'prueba para bloques
If opcion = -1 Then
If b(0,0)= 0 And b(1,0)= t2 And b(2,0)= t2 Then opcion = 0
If b(0,0)= t2 And b(1,0)= 0 And b(2,0)= t2 Then opcion = 1
If b(0,0)= t2 And b(1,0)= t2 And b(2,0)= 0 Then opcion = 2
If b(0,1)= 0 And b(1,1)= t2 And b(2,1)= t2 Then opcion = 3
If b(0,1)= t2 And b(1,1)= 0 And b(2,1)= t2 Then opcion = 4
If b(0,1)= t2 And b(1,1)= t2 And b(2,1)= 0 Then opcion = 5
If b(0,2)= 0 And b(1,2)= t2 And b(2,2)= t2 Then opcion = 6
If b(0,2)= t2 And b(1,2)= 0 And b(2,2)= t2 Then opcion = 7
If b(0,2)= t2 And b(1,2)= t2 And b(2,2)= 0 Then opcion = 8
'3 bloques verticales
If b(0,0)= 0 And b(0,1)= t2 And b(0,2)= t2 Then opcion = 0
If b(0,0)= t2 And b(0,1)= 0 And b(0,2)= t2 Then opcion = 3
If b(0,0)= t2 And b(0,1)= t2 And b(0,2)= 0 Then opcion = 6
If b(1,0)= 0 And b(1,1)= t2 And b(1,2)= t2 Then opcion = 1
If b(1,0)= t2 And b(1,1)= 0 And b(1,2)= t2 Then opcion = 4
If b(1,0)= t2 And b(1,1)= t2 And b(1,2)= 0 Then opcion = 7
If b(2,0)= 0 And b(2,1)= t2 And b(2,2)= t2 Then opcion = 2
If b(2,0)= t2 And b(2,1)= 0 And b(2,2)= t2 Then opcion = 5
If b(2,0)= t2 And b(2,1)= t2 And b(2,2)= 0 Then opcion = 8
'bloques cruzados
If b(0,0)= 0 And b(1,1)= t2 And b(2,2)= t2 Then opcion = 0
If b(0,0)= t2 And b(1,1)= 0 And b(2,2)= t2 Then opcion = 4
If b(0,0)= t2 And b(1,1)= t2 And b(2,2)= 0 Then opcion = 8
If b(2,0)= 0 And b(1,1)= t2 And b(0,2)= t2 Then opcion = 2
If b(2,0)= t2 And b(1,1)= 0 And b(0,2)= t2 Then opcion = 4
If b(2,0)= t2 And b(1,1)= t2 And b(0,2)= 0 Then opcion = 6
End If
If opcion = -1 Then
If b(0,0) = 0 Then opcion = 0
If b(2,0) = 0 Then opcion = 2
If b(0,2) = 0 Then opcion = 6
If b(2,2) = 0 Then opcion = 8
End If
'no hay opción de hacer una elección al azar
If opcion = -1 Then
opcion = Int(Rnd(1)*9)
j = Int(opcion/3)
i = opcion - Int(opcion/3)*3
'encontrar una casilla vacía
While b(i,j) <> 0
opcion = Int(Rnd(1)*9)
j = Int(opcion/3)
i = opcion - Int(opcion/3)*3
Wend
End If
Return opcion
End Function
 
 
InicializarTablero()
DibujaTablero()
Dim As Integer resultado
Dim As Integer jugador = 1
Dim As Integer ContarMovimientos = 0
Dim As Integer ContarPartidas = 0
Dim As Integer movimiento = 0
Dim As Integer i, j
 
Do
'alternar jugadores
If jugador = 1 Then jugador = 2 Else jugador = 1
'selecciona tipo de movimiento para cada jugador
If jugador = 1 Then
movimiento = MovimientoHumano()
Else
movimiento = MovimientoInteligente(2)
End If
'print "movimiento ="; movimiento
'print "jugador ="; jugador
'convertir la elección a las coordenadas del tablero i,j
j = Int(movimiento/3)
i = movimiento - (j*3)
b(i,j) = jugador 'ingrese la ficha de jugador 1 o 2
resultado = TestWin(jugador) 'comprobar si el jugador ha ganado
DibujaTablero()
ContarMovimientos += 1
'=======================================================
'Comprobar final de partida y/o un resultado de victoria
'=======================================================
If ContarMovimientos = 9 Or resultado <> 0 Then
DibujaTablero()
If resultado = 0 Then Print !"\n EMPATE "
If resultado = 1 Then Print !"\n x GANA "
If resultado = 2 Then Print !"\n o GANA "
Print Space(28)
Print "PULSA BARRA ESPACIADORA PARA"
Print "OTRA PARTIDA, ESC PARA SALIR"
Sleep
Cls
InicializarTablero() 'reiniciar tablero
ContarMovimientos = 0
ContarPartidas += 1
End If
Loop Until Multikey(&H01)
End
</syntaxhighlight>
 
==={{header|Microsoft Small Basic}}===
This game has a simple AI.
<syntaxhighlight lang="smallbasic">place1 = 1
place2 = 2
place3 = 3
place4 = 4
place5 = 5
place6 = 6
place7 = 7
place8 = 8
place9 = 9
symbol1 = "X"
symbol2 = "O"
reset:
TextWindow.Clear()
TextWindow.Write(place1 + " ")
TextWindow.Write(place2 + " ")
TextWindow.WriteLine(place3 + " ")
TextWindow.Write(place4 + " ")
TextWindow.Write(place5 + " ")
TextWindow.WriteLine(place6 + " ")
TextWindow.Write(place7 + " ")
TextWindow.Write(place8 + " ")
TextWindow.WriteLine(place9 + " ")
TextWindow.WriteLine("Where would you like to go to (choose a number from 1 to 9 and press enter)?")
n = TextWindow.Read()
If n = 1 then
If place1 = symbol1 or place1 = symbol2 then
Goto ai
Else
place1 = symbol1
EndIf
ElseIf n = 2 then
If place2 = symbol1 or place2 = symbol2 then
Goto ai
Else
place2 = symbol1
EndIf
ElseIf n = 3 then
If place3 = symbol1 or place3 = symbol2 then
Goto ai
Else
place3 = symbol1
EndIf
ElseIf n = 4 then
If place4 = symbol1 or place4 = symbol2 then
Goto ai
Else
place4 = symbol1
EndIf
ElseIf n = 5 then
If place5 = symbol1 or place5 = symbol2 then
Goto ai
Else
place5 = symbol1
EndIf
ElseIf n = 6 then
If place6 = symbol1 or place6 = symbol2 then
Goto ai
Else
place6 = symbol1
EndIf
ElseIf n = 7 then
If place8 = symbol1 or place7 = symbol2 then
Goto ai
Else
place7 = symbol1
EndIf
ElseIf n = 8 then
If place8 = symbol1 or place8 = symbol2 then
Goto ai
Else
place8 = symbol1
EndIf
ElseIf n = 9 then
If place9 = symbol1 or place9 = symbol2 then
Goto ai
Else
place9 = symbol1
EndIf
EndIf
Goto ai
ai:
n = Math.GetRandomNumber(9)
If n = 1 then
If place1 = symbol1 or place1 = symbol2 then
Goto ai
Else
place1 = symbol2
EndIf
ElseIf n = 2 then
If place2 = symbol1 or place2 = symbol2 then
Goto ai
Else
place2 = symbol2
EndIf
ElseIf n = 3 then
If place3 = symbol1 or place3 = symbol2 then
Goto ai
Else
place3 = symbol2
EndIf
ElseIf n = 4 then
If place4 = symbol1 or place4 = symbol2 then
Goto ai
Else
place4 = symbol2
EndIf
ElseIf n = 5 then
If place5 = symbol1 or place5 = symbol2 then
Goto ai
Else
place5 = symbol2
EndIf
ElseIf n = 6 then
If place6 = symbol1 or place6 = symbol2 then
Goto ai
Else
place6 = symbol2
EndIf
ElseIf n = 7 then
If place7 = symbol1 or place7 = symbol2 then
Goto ai
Else
place7 = symbol2
EndIf
ElseIf n = 8 then
If place8 = symbol1 or place8 = symbol2 then
Goto ai
Else
place8 = symbol2
EndIf
ElseIf n = 9 then
If place9 = symbol1 or place9 = symbol2 then
Goto ai
Else
place9 = symbol2
EndIf
EndIf
If place1 = symbol1 and place2 = symbol1 and place3 = symbol1 or place4 = symbol1 and place5 = symbol1 and place6 = symbol1 or place7 = symbol1 and place8 = symbol1 and place9 = symbol1 or place1 = symbol1 and place4 = symbol1 and place7 = symbol1 or place2 = symbol1 and place5 = symbol1 and place8 = symbol1 or place3 = symbol1 and place6 = symbol1 and place9 = symbol1 or place1 = symbol1 and place5 = symbol1 and place9 = symbol1 or place3 = symbol1 and place5 = symbol1 and place7 = symbol1 then
TextWindow.WriteLine("Player 1 (" + symbol1 + ") wins!")
ElseIf place1 = symbol2 and place2 = symbol2 and place3 = symbol2 or place4 = symbol2 and place5 = symbol2 and place6 = symbol2 or place7 = symbol2 and place8 = symbol2 and place9 = symbol2 or place1 = symbol2 and place4 = symbol2 and place7 = symbol2 or place2 = symbol2 and place5 = symbol2 and place8 = symbol2 or place3 = symbol2 and place6 = symbol2 and place9 = symbol2 or place1 = symbol2 and place5 = symbol2 and place8 = symbol2 or place3 = symbol2 and place5 = symbol2 and place7 = symbol2 then
TextWindow.WriteLine("Player 2 (" + symbol2 + ") wins!")
Else
Goto reset
EndIf</syntaxhighlight>
 
==={{header|QuickBASIC}}===
{{works with|QuickBasic|4.5}}
<syntaxhighlight lang="qbasic">
' Tic-tac-toe
 
DECLARE FUNCTION Win% (Piece AS STRING)
DECLARE FUNCTION SpacesFilled% ()
DECLARE SUB ClearBoard ()
DECLARE SUB DisplayNumberedBoard ()
DECLARE SUB DisplayPiecedBoard ()
DECLARE FUNCTION Evaluate% (Me AS STRING, Him AS STRING)
 
DIM SHARED Board(8) AS STRING * 1, BestMove AS INTEGER
DIM SHARED WinPos(7, 2) AS INTEGER
DIM SHARED MyPiece AS STRING, HisPiece AS STRING
 
FOR I = 0 TO 7
FOR J = 0 TO 2
READ WinPos(I, J)
NEXT J
NEXT I
' Winning positions
DATA 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 3, 6, 1, 4, 7, 2, 5, 8, 0, 4, 8, 2, 4, 6
MyWinsCnt = 0: HisWinsCnt = 0: DrawsCnt = 0
CompFirst = -1 ' It be reversed, so human goes first
CLS
PRINT
PRINT " TIC-TAC-TOE"
PRINT
PRINT "In this version, X always goes first."
PRINT "The board is numbered:"
DO
CompFirst = NOT CompFirst ' reverse who goes first
MovesCnt = 0
PRINT
DisplayNumberedBoard
PRINT
IF CompFirst THEN PRINT "I go first." ELSE PRINT "You go first. ";
ClearBoard
IF CompFirst THEN MyPiece = "X": HisPiece = "O" ELSE MyPiece = "O": HisPiece = "X"
' -1: human; 1: computer; 0: nobody
IF CompFirst THEN Mover = 1 ELSE Mover = -1
WHILE Mover <> 0
SELECT CASE Mover
CASE 1
IF MovesCnt = 0 THEN
BestMove = INT(RND * 9)
ELSEIF MovesCnt = 1 THEN
IF Board(4) <> " " THEN BestMove = INT(RND * 2) * 6 + INT(RND * 2) * 2 ELSE BestMove = 4
ELSE
T = Evaluate(MyPiece, HisPiece)
END IF
Board(BestMove) = MyPiece
MovesCnt = MovesCnt + 1
PRINT
CALL DisplayPiecedBoard
PRINT
IF Win(MyPiece) THEN
MyWinsCnt = MyWinsCnt + 1
PRINT "I win!"
Mover = 0
ELSEIF SpacesFilled THEN
DrawsCnt = DrawsCnt + 1
PRINT "It's a draw. Thank you."
Mover = 0
ELSE
Mover = -1
END IF
CASE -1
DO
INPUT "Where do you move? ", I
IF I < 1 OR I > 9 THEN
PRINT "Illegal! ";
ELSEIF Board(I - 1) <> " " THEN
PRINT "Place already occupied. ";
ELSE
EXIT DO
END IF
LOOP
Board(I - 1) = HisPiece
MovesCnt = MovesCnt + 1
PRINT
CALL DisplayPiecedBoard
PRINT
IF Win(HisPiece) THEN
HisWinsCnt = HisWinsCnt + 1
PRINT "You beat me! Good game."
Mover = 0
ELSEIF SpacesFilled THEN
DrawsCnt = DrawsCnt + 1
PRINT "It's a draw. Thank you."
Mover = 0
ELSE
Mover = 1
END IF
END SELECT
WEND
PRINT
INPUT "Another game (y/n)? ", Answ$
LOOP UNTIL UCASE$(Answ$) <> "Y"
PRINT
PRINT "Final score:"
PRINT "You won", HisWinsCnt; "game";
IF HisWinsCnt <> 1 THEN PRINT "s";
PRINT "."
PRINT "I won", MyWinsCnt; "game";
IF MyWinsCnt <> 1 THEN PRINT "s";
PRINT "."
PRINT "We tied", DrawsCnt; "game";
IF DrawsCnt <> 1 THEN PRINT "s";
PRINT "."
PRINT "See you later!"
END
 
SUB ClearBoard
FOR I = 0 TO 8: Board(I) = " ": NEXT I
END SUB
 
SUB DisplayNumberedBoard
FOR I = 0 TO 8 STEP 3
PRINT I + 1; "|"; I + 2; "|"; I + 3
IF I <> 6 THEN PRINT "---+---+---"
NEXT I
END SUB
 
SUB DisplayPiecedBoard
FOR I = 0 TO 8 STEP 3
PRINT " "; Board(I); " | "; Board(I + 1); " | "; Board(I + 2)
IF I <> 6 THEN PRINT "---+---+---"
NEXT I
END SUB
 
FUNCTION Evaluate% (Me AS STRING, Him AS STRING)
' Recursive algorithm
IF Win(Me) THEN Evaluate = 1: EXIT FUNCTION
IF Win(Him) THEN Evaluate = -1: EXIT FUNCTION
IF SpacesFilled THEN Evaluate = 0: EXIT FUNCTION
LoseFlag = 1
FOR I = 0 TO 8
IF Board(I) = " " THEN
Board(I) = Me ' Try the move.
V = Evaluate(Him, Me)
Board(I) = " " ' Restore the empty space.
IF V = -1 THEN BestMove = I: Evaluate = 1: EXIT FUNCTION
IF V = 0 THEN LoseFlag = 0: SafeMove = I
END IF
NEXT
BestMove = SafeMove
Evaluate = -LoseFlag
END FUNCTION
 
FUNCTION SpacesFilled%
FOR I = 0 TO 8
IF Board(I) = " " THEN SpacesFilled = 0: EXIT FUNCTION
NEXT I
SpacesFilled = -1
END FUNCTION
 
FUNCTION Win% (Piece AS STRING)
FOR I = 0 TO 7
IF Board(WinPos(I, 0)) = Piece AND Board(WinPos(I, 1)) = Piece AND Board(WinPos(I, 2)) = Piece THEN Win = -1: EXIT FUNCTION
NEXT I
Win = 0
END FUNCTION
</syntaxhighlight>
 
==={{header|RapidQ}}===
{{trans|QuickBASIC}}
<syntaxhighlight lang="basic">
' Tic-tac-toe
' Console application
 
DECLARE FUNCTION Win (Piece AS STRING) AS INTEGER
DECLARE FUNCTION SpacesFilled () AS INTEGER
DECLARE SUB ClearBoard ()
DECLARE SUB DisplayNumberedBoard ()
DECLARE SUB DisplayPiecedBoard ()
DECLARE FUNCTION Evaluate (Me AS STRING, Him AS STRING) AS INTEGER
 
DIM Board(8) AS STRING * 1, BestMove AS INTEGER
DIM WinPos(7, 2) AS INTEGER
DIM MyPiece AS STRING, HisPiece AS STRING
 
FOR I = 0 TO 7
FOR J = 0 TO 2
READ WinPos(I, J)
NEXT J
NEXT I
' Winning positions
DATA 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 3, 6, 1, 4, 7, 2, 5, 8, 0, 4, 8, 2, 4, 6
MyWinsCnt = 0: HisWinsCnt = 0: DrawsCnt = 0
CompFirst = -1 ' It be reversed, so human goes first
CLS
PRINT
PRINT " TIC-TAC-TOE"
PRINT
PRINT "In this version, X always goes first."
PRINT "The board is numbered:"
DO
CompFirst = NOT CompFirst ' reverse who goes first
MovesCnt = 0
PRINT
DisplayNumberedBoard
PRINT
PRINT IIF(CompFirst, "I go first.", "You go first.")
ClearBoard
IF CompFirst THEN MyPiece = "X": HisPiece = "O" ELSE MyPiece = "O": HisPiece = "X"
' -1: human; 1: computer; 0: nobody
Mover = IIF(CompFirst, 1, -1)
WHILE Mover <> 0
SELECT CASE Mover
CASE 1
IF MovesCnt = 0 THEN
BestMove = INT(RND * 9)
ELSEIF MovesCnt = 1 THEN
BestMove = IIF(Board(4) <> " ", INT(RND * 2) * 6 + INT(RND * 2) * 2, 4)
ELSE
T = Evaluate(MyPiece, HisPiece)
END IF
Board(BestMove) = MyPiece
INC(MovesCnt)
PRINT
CALL DisplayPiecedBoard
PRINT
IF Win(MyPiece) THEN
INC(MyWinsCnt)
PRINT "I win!"
Mover = 0
ELSEIF SpacesFilled THEN
INC(DrawsCnt)
PRINT "It's a draw. Thank you."
Mover = 0
ELSE
Mover = -1
END IF
CASE -1
DO
INPUT "Where do you move? ",I
IF I < 1 OR I > 9 THEN
PRINT "Illegal! ";
ELSEIF Board(I - 1) <> " " THEN
PRINT "Place already occupied. ";
ELSE
EXIT DO
END IF
LOOP
Board(I - 1) = HisPiece
INC(MovesCnt)
PRINT
CALL DisplayPiecedBoard
PRINT
IF Win(HisPiece) THEN
INC(HisWinsCnt)
PRINT "You beat me! Good game."
Mover = 0
ELSEIF SpacesFilled THEN
INC(DrawsCnt)
PRINT "It's a draw. Thank you."
Mover = 0
ELSE
Mover = 1
END IF
END SELECT
WEND
PRINT
INPUT "Another game (y/n)? ", Answ$
LOOP UNTIL UCASE$(Answ$) <> "Y"
PRINT
PRINT "Final score:"
PRINT "You won "; HisWinsCnt; " game"; IIF(HisWinsCnt <> 1, "s.", ".")
PRINT "I won "; MyWinsCnt; " game"; IIF(MyWinsCnt <> 1, "s.", ".")
PRINT "We tied "; DrawsCnt; " game"; IIF(DrawsCnt <> 1, "s.", ".")
PRINT "See you later!"
END
 
SUB ClearBoard
FOR I = 0 TO 8: Board(I) = " ": NEXT I
END SUB
 
SUB DisplayNumberedBoard
FOR I = 0 TO 8 STEP 3
PRINT " "; I + 1; " | "; I + 2; " | "; I + 3
IF I <> 6 THEN PRINT "---+---+---"
NEXT I
END SUB
 
SUB DisplayPiecedBoard
FOR I = 0 TO 8 STEP 3
PRINT " "; Board(I); " | "; Board(I + 1); " | "; Board(I + 2)
IF I <> 6 THEN PRINT "---+---+---"
NEXT I
END SUB
 
FUNCTION Evaluate (Me AS STRING, Him AS STRING)
' Recursive algorithm
DIM I AS INTEGER, SafeMove AS INTEGER, V AS INTEGER, LoseFlag AS INTEGER
IF Win(Me) THEN Evaluate = 1: EXIT FUNCTION
IF Win(Him) THEN Evaluate = -1: EXIT FUNCTION
IF SpacesFilled THEN Evaluate = 0: EXIT FUNCTION
LoseFlag = 1
I = 0
WHILE I <= 8
IF Board(I) = " " THEN
Board(I) = Me ' Try the move.
V = Evaluate(Him, Me)
Board(I) = " " ' Restore the empty space.
IF V = -1 THEN BestMove = I: Evaluate = 1: EXIT FUNCTION
IF V = 0 THEN LoseFlag = 0: SafeMove = I
END IF
INC(I)
WEND
BestMove = SafeMove
Evaluate = -LoseFlag
END FUNCTION
 
FUNCTION SpacesFilled
FOR I = 0 TO 8
IF Board(I) = " " THEN SpacesFilled = 0: EXIT FUNCTION
NEXT I
SpacesFilled = -1
END FUNCTION
 
FUNCTION Win (Piece AS STRING)
FOR I = 0 TO 7
IF Board(WinPos(I, 0)) = Piece AND Board(WinPos(I, 1)) = Piece AND Board(WinPos(I, 2)) = Piece THEN Win = -1: EXIT FUNCTION
NEXT I
Win = 0
END FUNCTION
</syntaxhighlight>
 
==={{header|Run BASIC}}===
<syntaxhighlight lang="runbasic">' ---------------------------
' TIC TAC TOE
' ---------------------------
winBox$ = "123 456 789 159 147 258 369 357"
boxPos$ = "123 231 456 564 789 897 159 591 357 753 132 465 798 174 285 396 159 471 582 693 147 258 369 195 375"
ai$ = "519628374"
ox$ = "OX"
[newGame]
for i = 1 to 9
box$(i) = ""
next i
goto [shoTic]
 
[loop]
for j = 1 to 2
tic$ = mid$(ox$,j,1)
for i = 1 to 25
b$ = word$(boxPos$,i," ")
b1 = val(mid$(b$,1,1))
b2 = val(mid$(b$,2,1))
b3 = val(mid$(b$,3,1))
if box$(b1) = tic$ AND box$(b2) = tic$ AND box$(b3) = "" then
box$(b3) = "O"
goto [shoTic]
end if
next i
next j
if box$(1) = "O" AND box$(5) = "X" and box$(9) = "X" then
if box$(3) = "" then
box$(3) = "O"
goto [shoTic]
end if
if box$(7) = "" then
box$(7) = "O"
goto [shoTic]
end if
end if
for i = 1 to 9
b1 = val(mid$(ai$,i,1))
if box$(b1) = "" then
box$(b1) = "O"
exit for
end if
next i
 
[shoTic]
cls
' ----------------------------------------
' show tic tac toe screen
' ----------------------------------------
html "<table border=1 width=300px height=225px><TR>"
for i = 1 to 9
html "<td align=center width=33%><h1>"
if box$(i) <> "" then
html box$(i)
else
button #box, " ";box$(i);" ", [doTic]
#box setkey(str$(i))
end if
if i mod 3 = 0 then html "</tr><tr>"
next i
html "</table>"
gosub [checkWin]
wait
 
[doTic]
box$(val(EventKey$)) = "X"
turn = 1
gosub [checkWin]
goto [loop]
 
' --- check for a winner ----------
[checkWin]
for i = 1 to 8
b$ = word$(winBox$,i," ")
b1 = val(mid$(b$,1,1))
b2 = val(mid$(b$,2,1))
b3 = val(mid$(b$,3,1))
if box$(b1) = "O" and box$(b2) = "O" and box$(b3) = "O" then
print "You Lose!"
goto [playAgain]
end if
if box$(b1) = "X" and box$(b2) = "X" and box$(b3) = "X" then
print "You Win!"
goto [playAgain]
end if
next i
 
moveCount = 0
for i = 1 to 9
if box$(i) <> "" then moveCount = moveCount + 1
next i
if moveCount = 9 then
print "Draw!"
goto [playAgain]
end if
RETURN
 
[playAgain]
input "Play again (y/n)";p$
if upper$(p$) = "Y" then goto [newGame]
end</syntaxhighlight>
 
==={{Header|Tiny BASIC}}===
<syntaxhighlight lang="basic"> REM Tic-tac-toe for Tiny BASIC
REM
REM Released as public domain by Damian Gareth Walker, 2019
REM Created: 21-Sep-2019
REM --- Variables
REM A - first square in line examined
REM B - second square in line examined
REM C - third square in line examined
REM D - player whose pieces to count
REM E - number of DREM s pieces on a line
REM F - first square of line to examine
REM G - game winner
REM H - which side the human takes
REM I - increment for line to examine
REM L - line to examine
REM M - where to move (various uses)
REM N - piece found in a square
REM P - player currently playing
REM Q - square to examine
REM R-Z - contents of the board
 
REM --- Main Program
GOSUB 40
GOSUB 60
GOSUB 80
END
 
REM --- Subroutine to initialise the game
REM Outputs: H - Human play order
REM P - Whose turn it is
40 PRINT "Tic tac toe. Board positions are:"
PRINT " 1 2 3"
PRINT " 4 5 6"
PRINT " 7 8 9"
PRINT "Play first or second (1/2)?"
INPUT H
IF H<1 THEN GOTO 40
IF H>2 THEN GOTO 40
LET P=1
RETURN
 
REM --- Subroutine to take turns
REM Inputs: H - who is the human
REM P - whose turn it is
REM Outputs: G - who won the game
60 IF P=H THEN GOSUB 100
IF P<>H THEN GOSUB 120
GOSUB 200
IF G>0 THEN RETURN
LET P=3-P
IF R=0 THEN GOTO 60
IF S=0 THEN GOTO 60
IF T=0 THEN GOTO 60
IF U=0 THEN GOTO 60
IF V=0 THEN GOTO 60
IF W=0 THEN GOTO 60
IF X=0 THEN GOTO 60
IF Y=0 THEN GOTO 60
IF Z=0 THEN GOTO 60
RETURN
 
REM --- Victory
REM Inputs: H - which side was the human
REM P - player who won
80 IF G=H THEN PRINT "You win!"
IF G<>0 THEN IF G<>H THEN PRINT "Computer wins"
IF G=0 THEN PRINT "A draw"
RETURN
 
REM --- Subroutine to allow the player to move
REM Inputs: P - player number
REM Outputs: M - where the player wishes to move
100 PRINT "Move? "
INPUT Q
IF Q<1 THEN GOTO 100
IF Q>9 THEN GOTO 100
GOSUB 220
IF N<>0 THEN GOTO 100
LET M=Q
GOSUB 240
RETURN
 
REM --- Subroutine to make the computerREM s move
REM Inputs: P - player number
REM Outputs: M - the move chosen
120 LET M=0
LET D=3-H
GOSUB 145
IF M>0 THEN GOTO 135
LET D=H
GOSUB 145
IF M=0 THEN IF V=0 THEN LET M=5
IF M=0 THEN IF R=0 THEN LET M=1
IF M=0 THEN IF T=0 THEN LET M=3
IF M=0 THEN IF X=0 THEN LET M=7
IF M=0 THEN IF Z=0 THEN LET M=9
IF M=0 THEN IF S=0 THEN LET M=2
IF M=0 THEN IF U=0 THEN LET M=4
IF M=0 THEN IF Y=0 THEN LET M=8
IF M=0 THEN IF W=0 THEN LET M=6
135 GOSUB 240
PRINT "Computer move ",M
RETURN
 
REM --- Identify moves to win or avoid a loss
REM Inputs: D - player whose pieces weREM re counting
REM Changes: E - number of pieces on line being scanned
REM F - first square in winning line
REM I - increment of winning line
REM L - line being scanned (counter)
145 LET L=1
146 GOSUB 170
IF E<2 THEN GOTO 152
IF A=0 THEN LET M=F
IF B=0 THEN LET M=F+I
IF C=0 THEN LET M=F+I+I
IF M>0 THEN RETURN
152 LET L=L+1
IF L<9 THEN GOTO 146
RETURN
 
REM --- Count a playerREM s pieces on a line
REM Inputs: D - player whose pieces weREM re counting
REM L - line number
REM Changes: F - first square on the line
REM I - increment of the line
REM Q - individual squares to examine
REM Outputs: A - contents of first square
REM B - contents of second square
REM C - contents of third square
REM E - number of the playerREM s pieces
170 IF L>3 THEN GOTO 174
LET F=3*L-2
LET I=1
GOTO 180
174 IF L>6 THEN GOTO 178
LET F=L-3
LET I=3
GOTO 180
178 LET F=1+2*(L-7)
LET I=4-2*(L-7)
180 LET E=0
LET Q=F
GOSUB 220
LET A=N
IF N=D THEN LET E=E+1
LET Q=Q+I
GOSUB 220
LET B=N
IF N=D THEN LET E=E+1
LET Q=Q+I
GOSUB 220
LET C=N
IF N=D THEN LET E=E+1
RETURN
 
REM --- Subroutine to check for a win
REM Inputs: R-Z - board squares
REM Outputs: G - the winning player (0 for neither)
200 LET G=0
IF R>0 THEN IF R=S THEN IF S=T THEN LET G=R
IF U>0 THEN IF U=V THEN IF V=W THEN LET G=U
IF X>0 THEN IF X=Y THEN IF Y=Z THEN LET G=X
IF R>0 THEN IF R=U THEN IF U=X THEN LET G=R
IF S>0 THEN IF S=V THEN IF V=Y THEN LET G=S
IF T>0 THEN IF T=W THEN IF W=Z THEN LET G=T
IF R>0 THEN IF R=V THEN IF V=Z THEN LET G=R
IF T>0 THEN IF T=V THEN IF V=X THEN LET G=T
RETURN
 
REM --- Subroutine to see what piece is in a square
REM Inputs: Q - the square to check
REM R-Z - the contents of the squares
REM Outputs: N - the piece in that square
220 LET N=0
IF Q=1 THEN LET N=R
IF Q=2 THEN LET N=S
IF Q=3 THEN LET N=T
IF Q=4 THEN LET N=U
IF Q=5 THEN LET N=V
IF Q=6 THEN LET N=W
IF Q=7 THEN LET N=X
IF Q=8 THEN LET N=Y
IF Q=9 THEN LET N=Z
RETURN
 
REM --- Subroutine to put a piece in a square
REM Inputs: P - the player whose piece should be placed
REM M - the square to put the piece in
REM Changes: R-Z - the contents of the squares
240 IF M=1 THEN LET R=P
IF M=2 THEN LET S=P
IF M=3 THEN LET T=P
IF M=4 THEN LET U=P
IF M=5 THEN LET V=P
IF M=6 THEN LET W=P
IF M=7 THEN LET X=P
IF M=8 THEN LET Y=P
IF M=9 THEN LET Z=P
RETURN </syntaxhighlight>
 
==={{header|VBA}}===
Human play first with the "X". You must choose the row and the column you want to play...
<syntaxhighlight lang="vb">
Option Explicit
 
Private Lines(1 To 3, 1 To 3) As String
Private Nb As Byte, player As Byte
Private GameWin As Boolean, GameOver As Boolean
 
Sub Main_TicTacToe()
Dim p As String
 
InitLines
printLines Nb
Do
p = WhoPlay
Debug.Print p & " play"
If p = "Human" Then
Call HumanPlay
GameWin = IsWinner("X")
Else
Call ComputerPlay
GameWin = IsWinner("O")
End If
If Not GameWin Then GameOver = IsEnd
Loop Until GameWin Or GameOver
If Not GameOver Then
Debug.Print p & " Win !"
Else
Debug.Print "Game Over!"
End If
End Sub
 
Sub InitLines(Optional S As String)
Dim i As Byte, j As Byte
Nb = 0: player = 0
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
Lines(i, j) = "#"
Next j
Next i
End Sub
 
Sub printLines(Nb As Byte)
Dim i As Byte, j As Byte, strT As String
Debug.Print "Loop " & Nb
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
strT = strT & Lines(i, j)
Next j
Debug.Print strT
strT = vbNullString
Next i
End Sub
 
Function WhoPlay(Optional S As String) As String
If player = 0 Then
player = 1
WhoPlay = "Human"
Else
player = 0
WhoPlay = "Computer"
End If
End Function
 
Sub HumanPlay(Optional S As String)
Dim L As Byte, C As Byte, GoodPlay As Boolean
 
Do
L = Application.InputBox("Choose the row", "Numeric only", Type:=1)
If L > 0 And L < 4 Then
C = Application.InputBox("Choose the column", "Numeric only", Type:=1)
If C > 0 And C < 4 Then
If Lines(L, C) = "#" And Not Lines(L, C) = "X" And Not Lines(L, C) = "O" Then
Lines(L, C) = "X"
Nb = Nb + 1
printLines Nb
GoodPlay = True
End If
End If
End If
Loop Until GoodPlay
End Sub
 
Sub ComputerPlay(Optional S As String)
Dim L As Byte, C As Byte, GoodPlay As Boolean
 
Randomize Timer
Do
L = Int((Rnd * 3) + 1)
C = Int((Rnd * 3) + 1)
If Lines(L, C) = "#" And Not Lines(L, C) = "X" And Not Lines(L, C) = "O" Then
Lines(L, C) = "O"
Nb = Nb + 1
printLines Nb
GoodPlay = True
End If
Loop Until GoodPlay
End Sub
 
Function IsWinner(S As String) As Boolean
Dim i As Byte, j As Byte, Ch As String, strTL As String, strTC As String
 
Ch = String(UBound(Lines, 1), S)
'check lines & columns
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
strTL = strTL & Lines(i, j)
strTC = strTC & Lines(j, i)
Next j
If strTL = Ch Or strTC = Ch Then IsWinner = True: Exit For
strTL = vbNullString: strTC = vbNullString
Next i
'check diagonales
strTL = Lines(1, 1) & Lines(2, 2) & Lines(3, 3)
strTC = Lines(1, 3) & Lines(2, 2) & Lines(3, 1)
If strTL = Ch Or strTC = Ch Then IsWinner = True
End Function
 
Function IsEnd() As Boolean
Dim i As Byte, j As Byte
 
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
If Lines(i, j) = "#" Then Exit Function
Next j
Next i
IsEnd = True
End Function
</syntaxhighlight>
{{out}}
<pre>Loop 0
###
###
###
Human Play
Loop 1
X##
###
###
Computer Play
Loop 2
X#O
###
###
Human Play
Loop 3
X#O
#X#
###
Computer Play
Loop 4
XOO
#X#
###
Human Play
Loop 5
XOO
#X#
##X
Human Win !</pre>
 
==={{header|Yabasic}}===
In the classic style.
<syntaxhighlight lang="yabasic">5 REM Adaptation to Yabasic of the program published in Tim Hartnell's book "Artificial Intelligence: Concepts and Programs", with some minor modifications. 6/2018.
10 REM TICTAC
15 INPUT "English (0), Spanish (other key): " IDIOMA : IF NOT IDIOMA THEN RESTORE 2020 ELSE RESTORE 2010 END IF
20 GOSUB 1180: REM INICIALIZACION
30 REM *** REQUISITOS PREVIOS AL JUEGO ***
40 FOR J = 1 TO 9
50 A(J) = 32
60 NEXT J
70 FOR J = 1 TO 5
80 D(J) = 0
90 NEXT J
100 CCONTADOR = 0
110 R$ = ""
120 GOSUB 1070: REM IMPRESION DEL TABLERO
130 REM ** CICLO PRINCIPAL **
140 GOSUB 540: REM MOVIMIENTO DEL ORDENADOR
150 GOSUB 1070: REM IMPRESION DEL TABLERO
160 GOSUB 870: REM COMPRUEBA LA VICTORIA
170 IF R$ <> "" GOTO 240
180 GOSUB 980: REM SE ACEPTA EL MOVIMIENTO DE LA PERSONA
190 GOSUB 1070: REM IMPRESION DEL TABLERO
200 GOSUB 870: REM COMPRUEBA LA VICTORIA
210 IF R$ = "" GOTO 140
220 REM ** FIN DEL CICLO PRINCIPAL **
230 REM *****************************
240 REM FIN DEL JUEGO
250 GOSUB 1070: REM IMPRESION DEL TABLERO
260 PRINT: PRINT
270 IF R$ = "G" PRINT MENSAJE$(1): BANDERA = -1
280 IF R$ = "P" PRINT MENSAJE$(2): BANDERA = 1
290 IF R$ = "D" PRINT MENSAJE$(3): GOTO 430
300 REM ACTUALIZACION DE LA BASE DE DATOS
310 FOR B = 1 TO 5
320 FOR J = 2 TO 9
330 IF M(J) = D(B) GOSUB 370
340 NEXT J
350 NEXT B
360 GOTO 430
370 REM ** REORDENACION DE LOS ELEMENTOS DE LA MATRIZ M **
380 TEMP = M(J + BANDERA)
390 M(J + BANDERA) = M(J)
400 M(J) = TEMP
410 J = 9
420 RETURN
430 PRINT: PRINT
440 PRINT MENSAJE$(4)
450 PRINT: PRINT
460 FOR J = 1 TO 9
470 PRINT M(J), " ";
480 NEXT J
490 PRINT: PRINT
500 PRINT MENSAJE$(5)
510 INPUT A$
520 GOTO 30
530 REM ************************
540 REM MOVIMIENTO DEL ORDENADOR
550 P = ASC("O")
560 X = 0
570 J = 1
580 IF A(W(J)) = A(W(J + 1)) AND A(W(J + 2)) = 32 AND A(W(J)) = P X = W(J + 2): GOTO 750
590 IF A(W(J)) = A(W(J + 2)) AND A(W(J + 1)) = 32 AND A(W(J)) = P X = W(J + 1): GOTO 750
600 IF A(W(J + 1)) = A(W(J + 2)) AND A(W(J)) = 32 AND A(W(J + 1)) = P X = W(J): GOTO 750
610 IF J < 21 J = J + 3: GOTO 580
620 IF P = ASC("O") P = ASC("X"): GOTO 570
630 REM ** SI NO SE GANA SE BUSCA UN MOVIMIENTO DE BLOQUEO **
640 REM * ENTONCES SE USA LA SIGUIENTE SECCION *
650 J = 1
660 IF A(M(J)) = 32 X = M(J): GOTO 750
670 IF J < 10 J = J + 1: GOTO 660
680 H = 0
690 H = H + 1
700 X = INT(RAN(1) * 9): IF A(X) = 32 GOTO 750
710 IF H < 100 GOTO 690
720 R$ = "D": REM ES SIMPLEMENTE UN DIBUJO
730 RETURN
740 REM *********************
750 REM REALIZA EL MOVIMIENTO
760 A(X) = ASC("O")
770 CCONTADOR = CCONTADOR + 1
780 D(CCONTADOR) = X
790 BANDERA = 0
800 FOR J = 1 TO 9
810 IF A(J) = 32 BANDERA = 1
820 NEXT J
830 IF BANDERA = 0 AND R$ = "" R$ = "D"
840 REM SI TODAS LAS CASILLAS ESTAN LLENAS Y R$ ESTA VACIO, ENTONCES ES SIMPLEMENTE UN DIBUJO
850 RETURN
860 REM *********************
870 REM COMPRUEBA LA VICTORIA
880 J = 1
890 IF A(W(J)) = 32 J = J + 3
900 IF J > 23 RETURN
910 IF A(W(J)) = A(W(J + 1)) AND A(W(J)) = A(W(J + 2)) GOTO 940
920 IF J < 22 J = J + 3: GOTO 890
930 RETURN
940 IF A(W(J)) = ASC("O") R$ = "G": REM EL ORDENADOR GANA
950 IF A(W(J)) = ASC("X") R$ = "P": REM EL ORDENADOR PIERDE
960 RETURN
970 REM ************************
980 REM MOVIMIENTO DE LA PERSONA
990 PRINT: PRINT
1000 PRINT MENSAJE$(6)
1010 PRINT MENSAJE$(7); : INPUT MOVIMIENTO
1020 IF MOVIMIENTO < 1 OR MOVIMIENTO > 9 GOTO 1010
1030 IF A(MOVIMIENTO) <> 32 GOTO 1010
1040 A(MOVIMIENTO) = ASC("X")
1050 RETURN
1060 REM *********************
1070 REM IMPRESION DEL TABLERO
1080 CLEAR SCREEN
1090 PRINT: PRINT: PRINT
1100 PRINT " 1 : 2 : 3 ", CHR$(A(1)), " : ", CHR$(A(2)), " : ", CHR$(A(3))
1110 PRINT "----------- ------------"
1120 PRINT " 4 : 5 : 6 ", CHR$(A(4)), " : ", CHR$(A(5)), " : ", CHR$(A(6))
1130 PRINT "----------- ------------"
1140 PRINT " 7 : 8 : 9 ", CHR$(A(7)), " : ", CHR$(A(8)), " : ", CHR$(A(9))
1150 PRINT
1160 RETURN
1170 REM **************
1180 REM INICIALIZACION
1190 CLEAR SCREEN
1200 DIM A(9) : REM TABLERO
1210 DIM M(10) : REM ACCESO A LA BASE DE DATOS
1220 DIM W(24) : REM DATOS DE VICTORIA O BLOQUEO
1230 DIM D(5) : REM ACCESO AL MOVIMIENTO EN EL JUEGO ACTUAL
1235 DIM MENSAJE$(1) : READ M$ : N = TOKEN(M$,MENSAJE$(),",") : RESTORE
1240 REM DATOS DE VICTORIA O BLOQUEO
1250 FOR J = 1 TO 24
1260 READ W(J)
1270 NEXT J
1280 DATA 1, 2, 3, 4, 5, 6, 7, 8, 9
1290 DATA 1, 4, 7, 2, 5, 8, 3, 6, 9
1300 DATA 1, 5, 9, 3, 5, 7
1310 REM BASE INICIAL DE DATOS
1320 FOR J = 1 TO 10
1330 READ M(J)
1340 NEXT J
1350 DATA 2, 6, 8, 4, 7, 3, 1, 9, 5, 2
1360 RETURN
2000 REM MENSAJES EN ESPAÑOL
2010 DATA "YO GANO,TU GANAS,ES SIMPLEMENTE UN DIBUJO,ESTA ES MI PRIORIDAD ACTUALIZADA,PULSE LA TECLA <RETURN> PARA CONTINUAR,REALICE SU MOVIMIENTO,MOVIMIENTO: "
2020 DATA "I WIN,YOU WIN,IT'S JUST A DRAWING,THIS IS MY PRIORITY UPDATE,PRESS <RETURN> TO CONTINUE,TO MAKE YOUR MOVE,MOVEMENT: "
</syntaxhighlight>
 
=={{header|Batch File}}==
This is just a game between two human players.
<syntaxhighlight lang="dos">@echo off
setlocal enabledelayedexpansion
:newgame
set a1=1
set a2=2
set a3=3
set a4=4
set a5=5
set a6=6
set a7=7
set a8=8
set a9=9
set ll=X
set /a zz=0
:display1
cls
echo Player: %ll%
echo %a7%_%a8%_%a9%
echo %a4%_%a5%_%a6%
echo %a1%_%a2%_%a3%
set /p myt=Where would you like to go (choose a number from 1-9 and press enter)?
if !a%myt%! equ %myt% (
set a%myt%=%ll%
goto check
)
goto display1
:check
set /a zz=%zz%+1
if %zz% geq 9 goto newgame
if %a7%+%a8%+%a9% equ %ll%+%ll%+%ll% goto win
if %a4%+%a5%+%a6% equ %ll%+%ll%+%ll% goto win
if %a1%+%a2%+%a3% equ %ll%+%ll%+%ll% goto win
if %a7%+%a5%+%a3% equ %ll%+%ll%+%ll% goto win
if %a1%+%a5%+%a9% equ %ll%+%ll%+%ll% goto win
if %a7%+%a4%+%a1% equ %ll%+%ll%+%ll% goto win
if %a8%+%a5%+%a2% equ %ll%+%ll%+%ll% goto win
if %a9%+%a6%+%a3% equ %ll%+%ll%+%ll% goto win
goto %ll%
:X
set ll=O
goto display1
:O
set ll=X
goto display1
:win
echo %ll% wins!
pause
goto newgame
</syntaxhighlight>
===Advanced===
This code makes a version of Tic Tac Toe with more features:
<syntaxhighlight lang="dos">@ECHO OFF
:BEGIN
REM Skill level
set sl=
cls
echo Tic Tac Toe (Q to quit)
echo.
echo.
echo Pick your skill level (press a number)
echo.
echo (1) Children under 6
echo (2) Average Mental Case
echo (3) Oversized Ego
CHOICE /c:123q /n > nul
if errorlevel 4 goto end
if errorlevel 3 set sl=3
if errorlevel 3 goto layout
if errorlevel 2 set sl=2
if errorlevel 2 goto layout
set sl=1
 
:LAYOUT
REM Player turn ("x" or "o")
set pt=
REM Game winner ("x" or "o")
set gw=
REM No moves
set nm=
REM Set to one blank space after equal sign (check with cursor end)
set t1=
set t2=
set t3=
set t4=
set t5=
set t6=
set t7=
set t8=
set t9=
 
:UPDATE
cls
echo (S to set skill level) Tic Tac Toe (Q to quit)
echo.
echo You are the X player.
echo Press the number where you want to put an X.
echo.
echo Skill level %sl% 7 8 9
echo 4 5 6
echo 1 2 3
echo.
echo : :
echo %t1% : %t2% : %t3%
echo ....:...:....
echo %t4% : %t5% : %t6%
echo ....:...:....
echo %t7% : %t8% : %t9%
echo : :
if "%gw%"=="x" goto winx2
if "%gw%"=="o" goto wino2
if "%nm%"=="0" goto nomoves
 
:PLAYER
set pt=x
REM Layout is for keypad. Change CHOICE to "/c:123456789sq /n > nul"
REM for numbers to start at top left (also change user layout above).
CHOICE /c:789456123sq /n > nul
if errorlevel 11 goto end
if errorlevel 10 goto begin
if errorlevel 9 goto 9
if errorlevel 8 goto 8
if errorlevel 7 goto 7
if errorlevel 6 goto 6
if errorlevel 5 goto 5
if errorlevel 4 goto 4
if errorlevel 3 goto 3
if errorlevel 2 goto 2
goto 1
 
:1
REM Check if "x" or "o" already in square.
if "%t1%"=="x" goto player
if "%t1%"=="o" goto player
set t1=x
goto check
:2
if "%t2%"=="x" goto player
if "%t2%"=="o" goto player
set t2=x
goto check
:3
if "%t3%"=="x" goto player
if "%t3%"=="o" goto player
set t3=x
goto check
:4
if "%t4%"=="x" goto player
if "%t4%"=="o" goto player
set t4=x
goto check
:5
if "%t5%"=="x" goto player
if "%t5%"=="o" goto player
set t5=x
goto check
:6
if "%t6%"=="x" goto player
if "%t6%"=="o" goto player
set t6=x
goto check
:7
if "%t7%"=="x" goto player
if "%t7%"=="o" goto player
set t7=x
goto check
:8
if "%t8%"=="x" goto player
if "%t8%"=="o" goto player
set t8=x
goto check
:9
if "%t9%"=="x" goto player
if "%t9%"=="o" goto player
set t9=x
goto check
 
:COMPUTER
set pt=o
if "%sl%"=="1" goto skill1
REM (win corner to corner)
if "%t1%"=="o" if "%t3%"=="o" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t1%"=="o" if "%t9%"=="o" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if "%t1%"=="o" if "%t7%"=="o" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t3%"=="o" if "%t7%"=="o" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if "%t3%"=="o" if "%t9%"=="o" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t9%"=="o" if "%t7%"=="o" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
REM (win outside middle to outside middle)
if "%t2%"=="o" if "%t8%"=="o" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if "%t4%"=="o" if "%t6%"=="o" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
REM (win all others)
if "%t1%"=="o" if "%t2%"=="o" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
if "%t1%"=="o" if "%t5%"=="o" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if "%t1%"=="o" if "%t4%"=="o" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t2%"=="o" if "%t5%"=="o" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
if "%t3%"=="o" if "%t2%"=="o" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t3%"=="o" if "%t5%"=="o" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t3%"=="o" if "%t6%"=="o" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if "%t4%"=="o" if "%t5%"=="o" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t6%"=="o" if "%t5%"=="o" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t7%"=="o" if "%t4%"=="o" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t7%"=="o" if "%t5%"=="o" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
if "%t7%"=="o" if "%t8%"=="o" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if "%t8%"=="o" if "%t5%"=="o" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t9%"=="o" if "%t8%"=="o" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t9%"=="o" if "%t5%"=="o" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t9%"=="o" if "%t6%"=="o" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
REM (block general attempts) -----------------------------------------------
if "%t1%"=="x" if "%t2%"=="x" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
if "%t1%"=="x" if "%t5%"=="x" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if "%t1%"=="x" if "%t4%"=="x" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t2%"=="x" if "%t5%"=="x" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
if "%t3%"=="x" if "%t2%"=="x" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t3%"=="x" if "%t5%"=="x" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t3%"=="x" if "%t6%"=="x" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if "%t4%"=="x" if "%t5%"=="x" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t6%"=="x" if "%t5%"=="x" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t7%"=="x" if "%t4%"=="x" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t7%"=="x" if "%t5%"=="x" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
if "%t7%"=="x" if "%t8%"=="x" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if "%t8%"=="x" if "%t5%"=="x" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t9%"=="x" if "%t8%"=="x" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t9%"=="x" if "%t5%"=="x" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t9%"=="x" if "%t6%"=="x" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
REM (block obvious corner to corner)
if "%t1%"=="x" if "%t3%"=="x" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t1%"=="x" if "%t9%"=="x" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if "%t1%"=="x" if "%t7%"=="x" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t3%"=="x" if "%t7%"=="x" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if "%t3%"=="x" if "%t9%"=="x" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t9%"=="x" if "%t7%"=="x" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
if "%sl%"=="2" goto skill2
REM (block sneaky corner to corner 2-4, 2-6, etc.)
if "%t2%"=="x" if "%t4%"=="x" if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if "%t2%"=="x" if "%t6%"=="x" if not "%t3%"=="x" if not "%t3%"=="o" goto c3
if "%t8%"=="x" if "%t4%"=="x" if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if "%t8%"=="x" if "%t6%"=="x" if not "%t9%"=="x" if not "%t9%"=="o" goto c9
REM (block offset corner trap 1-8, 1-6, etc.)
if "%t1%"=="x" if "%t6%"=="x" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
if "%t1%"=="x" if "%t8%"=="x" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t3%"=="x" if "%t8%"=="x" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t3%"=="x" if "%t4%"=="x" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
if "%t9%"=="x" if "%t4%"=="x" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t9%"=="x" if "%t2%"=="x" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t7%"=="x" if "%t2%"=="x" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t7%"=="x" if "%t6%"=="x" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
 
:SKILL2
REM (block outside middle to outside middle)
if "%t2%"=="x" if "%t8%"=="x" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if "%t4%"=="x" if "%t6%"=="x" if not "%t5%"=="x" if not "%t5%"=="o" goto c5
REM (block 3 corner trap)
if "%t1%"=="x" if "%t9%"=="x" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t3%"=="x" if "%t7%"=="x" if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if "%t1%"=="x" if "%t9%"=="x" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t3%"=="x" if "%t7%"=="x" if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if "%t1%"=="x" if "%t9%"=="x" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t3%"=="x" if "%t7%"=="x" if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if "%t1%"=="x" if "%t9%"=="x" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
if "%t3%"=="x" if "%t7%"=="x" if not "%t8%"=="x" if not "%t8%"=="o" goto c8
:SKILL1
REM (just take a turn)
if not "%t5%"=="x" if not "%t5%"=="o" goto c5
if not "%t1%"=="x" if not "%t1%"=="o" goto c1
if not "%t3%"=="x" if not "%t3%"=="o" goto c3
if not "%t7%"=="x" if not "%t7%"=="o" goto c7
if not "%t9%"=="x" if not "%t9%"=="o" goto c9
if not "%t2%"=="x" if not "%t2%"=="o" goto c2
if not "%t4%"=="x" if not "%t4%"=="o" goto c4
if not "%t6%"=="x" if not "%t6%"=="o" goto c6
if not "%t8%"=="x" if not "%t8%"=="o" goto c8
set nm=0
goto update
 
:C1
set t1=o
goto check
:C2
set t2=o
goto check
:C3
set t3=o
goto check
:C4
set t4=o
goto check
:C5
set t5=o
goto check
:C6
set t6=o
goto check
:C7
set t7=o
goto check
:C8
set t8=o
goto check
:C9
set t9=o
goto check
 
:CHECK
if "%t1%"=="x" if "%t2%"=="x" if "%t3%"=="x" goto winx
if "%t4%"=="x" if "%t5%"=="x" if "%t6%"=="x" goto winx
if "%t7%"=="x" if "%t8%"=="x" if "%t9%"=="x" goto winx
if "%t1%"=="x" if "%t4%"=="x" if "%t7%"=="x" goto winx
if "%t2%"=="x" if "%t5%"=="x" if "%t8%"=="x" goto winx
if "%t3%"=="x" if "%t6%"=="x" if "%t9%"=="x" goto winx
if "%t1%"=="x" if "%t5%"=="x" if "%t9%"=="x" goto winx
if "%t3%"=="x" if "%t5%"=="x" if "%t7%"=="x" goto winx
if "%t1%"=="o" if "%t2%"=="o" if "%t3%"=="o" goto wino
if "%t4%"=="o" if "%t5%"=="o" if "%t6%"=="o" goto wino
if "%t7%"=="o" if "%t8%"=="o" if "%t9%"=="o" goto wino
if "%t1%"=="o" if "%t4%"=="o" if "%t7%"=="o" goto wino
if "%t2%"=="o" if "%t5%"=="o" if "%t8%"=="o" goto wino
if "%t3%"=="o" if "%t6%"=="o" if "%t9%"=="o" goto wino
if "%t1%"=="o" if "%t5%"=="o" if "%t9%"=="o" goto wino
if "%t3%"=="o" if "%t5%"=="o" if "%t7%"=="o" goto wino
if "%pt%"=="x" goto computer
if "%pt%"=="o" goto update
 
:WINX
set gw=x
goto update
:WINX2
echo You win!
echo Play again (Y,N)?
CHOICE /c:ynsq /n > nul
if errorlevel 4 goto end
if errorlevel 3 goto begin
if errorlevel 2 goto end
goto layout
 
:WINO
set gw=o
goto update
:WINO2
echo Sorry, You lose.
echo Play again (Y,N)?
CHOICE /c:ynsq /n > nul
if errorlevel 4 goto end
if errorlevel 3 goto begin
if errorlevel 2 goto end
goto layout
 
:NOMOVES
echo There are no more moves left!
echo Play again (Y,N)?
CHOICE /c:ynsq /n > nul
if errorlevel 4 goto end
if errorlevel 3 goto begin
if errorlevel 2 goto end
goto layout
 
:END
cls
echo Tic Tac Toe
echo.
REM Clear all variables (no spaces after equal sign).
set gw=
set nm=
set sl=
set pt=
set t1=
set t2=
set t3=
set t4=
set t5=
set t6=
set t7=
set t8=
set t9=</syntaxhighlight>
 
=={{header|Befunge}}==
Requires an intepreter with working support for numeric input, which unfortunately excludes most online implementations.
 
Plays reasonably well, but not perfectly, so can be beaten.
 
<syntaxhighlight lang="befunge">v123456789 --- >9 >48*,:55+\-0g,1v
>9>066+0p076+0p^ ^,," |"_v#%3:- <
:,,0537051v>:#,_$#^5#,5#+<>:#v_55+
74 1098709<^+55"---+---+---"0<v520
69 04560123 >:!#v_0\1v>$2-:6%v>803
6 +0g\66++0p^ $_>#% v#9:-1_ 6/5
5 vv5!/*88\%*28 ::g0_^>9/#v_ "I",
,,5v>5++0p82*/3-:*+\:^v,_@ >"uoY",
0+5<v0+66_v#!%2:_55v >:^:" win!"\
1-^ g >$>0" :evom ruoY">:#,_$v>p
\*8+ 65_^#!/*88g0** `0\!`9:::<&<^0
v >:!67+0g:!56+0g *+*+0" :evom "
>"yM">:#,_$ :. 1234+++, 789*+ \0^<
"a s't"98:*+>:#,_$@>365*+"ward"48*
</syntaxhighlight>
 
{{out}}
<pre> 1 | 2 | 3
---+---+---
4 | 5 | 6
---+---+---
7 | 8 | 9
 
Your move: 1
 
X | 2 | 3
---+---+---
4 | 5 | 6
---+---+---
7 | 8 | 9
 
My move: 5
 
X | 2 | 3
---+---+---
4 | O | 6
---+---+---
7 | 8 | 9
 
Your move: 2
 
X | X | 3
---+---+---
4 | O | 6
---+---+---
7 | 8 | 9
 
My move: 3
 
X | X | O
---+---+---
4 | O | 6
---+---+---
7 | 8 | 9
 
Your move:
</pre>
 
=={{header|C}}==
Opening alternates between human and computer. Computer never loses.
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h>
 
Line 582 ⟶ 3,675:
while (1) printf("%s", game(first = !first));
return 0;
}</langsyntaxhighlight>
 
=={{header|C++}}==
<lang cpp>
#include <windows.h>
#include <iostream>
#include <string>
 
//--------------------------------------------------------------------------------------------------
using namespace std;
 
//--------------------------------------------------------------------------------------------------
enum players { Computer, Human, Draw, None };
const int iWin[8][3] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 0, 3, 6 }, { 1, 4, 7 }, { 2, 5, 8 }, { 0, 4, 8 }, { 2, 4, 6 } };
 
//--------------------------------------------------------------------------------------------------
class ttt
{
public:
ttt() { _p = rand() % 2; reset(); }
 
void play()
{
int res = Draw;
while( true )
{
drawGrid();
while( true )
{
if( _p ) getHumanMove();
else getComputerMove();
 
drawGrid();
 
res = checkVictory();
if( res != None ) break;
 
++_p %= 2;
}
 
if( res == Human ) cout << "CONGRATULATIONS HUMAN --- You won!";
else if( res == Computer ) cout << "NOT SO MUCH A SURPRISE --- I won!";
else cout << "It's a draw!";
 
cout << endl << endl;
 
string r;
cout << "Play again( Y / N )? "; cin >> r;
if( r != "Y" && r != "y" ) return;
 
++_p %= 2;
reset();
 
}
}
 
private:
void reset()
{
for( int x = 0; x < 9; x++ )
_field[x] = None;
}
 
void drawGrid()
{
system( "cls" );
COORD c = { 0, 2 };
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
 
cout << " 1 | 2 | 3 " << endl;
cout << "---+---+---" << endl;
cout << " 4 | 5 | 6 " << endl;
cout << "---+---+---" << endl;
cout << " 7 | 8 | 9 " << endl << endl << endl;
 
int f = 0;
for( int y = 0; y < 5; y += 2 )
for( int x = 1; x < 11; x += 4 )
{
if( _field[f] != None )
{
COORD c = { x, 2 + y };
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
string o = _field[f] == Computer ? "X" : "O";
cout << o;
}
f++;
}
 
c.Y = 9;
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
}
 
int checkVictory()
{
for( int i = 0; i < 8; i++ )
{
if( _field[iWin[i][0]] != None &&
_field[iWin[i][0]] == _field[iWin[i][1]] && _field[iWin[i][1]] == _field[iWin[i][2]] )
{
return _field[iWin[i][0]];
}
}
 
int i = 0;
for( int f = 0; f < 9; f++ )
{
if( _field[f] != None )
i++;
}
if( i == 9 ) return Draw;
 
return None;
}
 
void getHumanMove()
{
int m;
cout << "Enter your move ( 1 - 9 ) ";
while( true )
{
m = 0;
do
{ cin >> m; }
while( m < 1 && m > 9 );
 
if( _field[m - 1] != None )
cout << "Invalid move. Try again!" << endl;
else break;
}
 
_field[m - 1] = Human;
}
 
void getComputerMove()
{
int move = 0;
 
do{ move = rand() % 9; }
while( _field[move] != None );
 
for( int i = 0; i < 8; i++ )
{
int try1 = iWin[i][0], try2 = iWin[i][1], try3 = iWin[i][2];
 
if( _field[try1] != None && _field[try1] == _field[try2] && _field[try3] == None )
{
move = try3;
if( _field[try1] == Computer ) break;
}
 
if( _field[try1] != None && _field[try1] == _field[try3] && _field[try2] == None )
{
move = try2;
if( _field[try1] == Computer ) break;
}
 
if( _field[try2] != None && _field[try2] == _field[try3] && _field[try1] == None )
{
move = try1;
if( _field[try2] == Computer ) break;
}
}
_field[move] = Computer;
}
 
 
int _p;
int _field[9];
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
srand( GetTickCount() );
 
ttt tic;
tic.play();
 
return 0;
}
//--------------------------------------------------------------------------------------------------
</lang>
Output: Computer plays 'X' and human plays 'O'
<pre>
1 | 2 | X
---+---+---
X | 5 | 6
---+---+---
7 | O | 9
 
Enter your move ( 1 - 9 )
</pre>
 
=={{header|C sharp}}==
Line 781 ⟶ 3,681:
It tries to show a number of C# code features while still keeping each function small and understandable.
 
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 1,026 ⟶ 3,926:
}
 
}</langsyntaxhighlight>
 
{{out}}
Output example:
<pre>Welcome to Rosetta Code Tic-Tac-Toe for C#.
1 | 2 | 3
Line 1,070 ⟶ 3,970:
 
HUMAN, enter you move (number):</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">
#include <windows.h>
#include <iostream>
#include <string>
 
//--------------------------------------------------------------------------------------------------
using namespace std;
 
//--------------------------------------------------------------------------------------------------
enum players { Computer, Human, Draw, None };
const int iWin[8][3] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 0, 3, 6 }, { 1, 4, 7 }, { 2, 5, 8 }, { 0, 4, 8 }, { 2, 4, 6 } };
 
//--------------------------------------------------------------------------------------------------
class ttt
{
public:
ttt() { _p = rand() % 2; reset(); }
 
void play()
{
int res = Draw;
while( true )
{
drawGrid();
while( true )
{
if( _p ) getHumanMove();
else getComputerMove();
 
drawGrid();
 
res = checkVictory();
if( res != None ) break;
 
++_p %= 2;
}
 
if( res == Human ) cout << "CONGRATULATIONS HUMAN --- You won!";
else if( res == Computer ) cout << "NOT SO MUCH A SURPRISE --- I won!";
else cout << "It's a draw!";
 
cout << endl << endl;
 
string r;
cout << "Play again( Y / N )? "; cin >> r;
if( r != "Y" && r != "y" ) return;
 
++_p %= 2;
reset();
 
}
}
 
private:
void reset()
{
for( int x = 0; x < 9; x++ )
_field[x] = None;
}
 
void drawGrid()
{
system( "cls" );
COORD c = { 0, 2 };
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
 
cout << " 1 | 2 | 3 " << endl;
cout << "---+---+---" << endl;
cout << " 4 | 5 | 6 " << endl;
cout << "---+---+---" << endl;
cout << " 7 | 8 | 9 " << endl << endl << endl;
 
int f = 0;
for( int y = 0; y < 5; y += 2 )
for( int x = 1; x < 11; x += 4 )
{
if( _field[f] != None )
{
COORD c = { x, 2 + y };
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
string o = _field[f] == Computer ? "X" : "O";
cout << o;
}
f++;
}
 
c.Y = 9;
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
}
 
int checkVictory()
{
for( int i = 0; i < 8; i++ )
{
if( _field[iWin[i][0]] != None &&
_field[iWin[i][0]] == _field[iWin[i][1]] && _field[iWin[i][1]] == _field[iWin[i][2]] )
{
return _field[iWin[i][0]];
}
}
 
int i = 0;
for( int f = 0; f < 9; f++ )
{
if( _field[f] != None )
i++;
}
if( i == 9 ) return Draw;
 
return None;
}
 
void getHumanMove()
{
int m;
cout << "Enter your move ( 1 - 9 ) ";
while( true )
{
m = 0;
do
{ cin >> m; }
while( m < 1 && m > 9 );
 
if( _field[m - 1] != None )
cout << "Invalid move. Try again!" << endl;
else break;
}
 
_field[m - 1] = Human;
}
 
void getComputerMove()
{
int move = 0;
 
do{ move = rand() % 9; }
while( _field[move] != None );
 
for( int i = 0; i < 8; i++ )
{
int try1 = iWin[i][0], try2 = iWin[i][1], try3 = iWin[i][2];
 
if( _field[try1] != None && _field[try1] == _field[try2] && _field[try3] == None )
{
move = try3;
if( _field[try1] == Computer ) break;
}
 
if( _field[try1] != None && _field[try1] == _field[try3] && _field[try2] == None )
{
move = try2;
if( _field[try1] == Computer ) break;
}
 
if( _field[try2] != None && _field[try2] == _field[try3] && _field[try1] == None )
{
move = try1;
if( _field[try2] == Computer ) break;
}
}
_field[move] = Computer;
}
 
 
int _p;
int _field[9];
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
srand( GetTickCount() );
 
ttt tic;
tic.play();
 
return 0;
}
//--------------------------------------------------------------------------------------------------
</syntaxhighlight>
{{out}} Computer plays 'X' and human plays 'O'
<pre>
1 | 2 | X
---+---+---
X | 5 | 6
---+---+---
7 | O | 9
 
Enter your move ( 1 - 9 )
</pre>
 
=={{header|Common Lisp}}==
<syntaxhighlight lang="lisp">
(defun generate-board ()
(loop repeat 9 collect nil))
 
(defparameter *straights* '((1 2 3) (4 5 6) (7 8 9) (1 4 7) (2 5 8) (3 6 9) (1 5 9) (3 5 7)))
(defparameter *current-player* 'x)
 
(defun get-board-elt (n board)
(nth (1- n) board))
 
(defun legal-p (n board)
(null (get-board-elt n board)))
 
(defun set-board-elt (n board symbol)
(if (legal-p n board)
(setf (nth (1- n) board) symbol)
(progn (format t "Illegal move. Try again.~&")
(set-board-elt (read) board symbol))))
 
(defun list-legal-moves (board)
(loop for i from 1 to (length board)
when (legal-p i board)
collect i))
 
(defun get-random-element (lst)
(nth (random (length lst)) lst))
 
(defun multi-non-nil-eq (lst)
(and (notany #'null lst)
(notany #'null (mapcar #'(lambda (x) (eq (car lst) x)) lst))
(car lst)))
(defun elements-of-straights (board)
(loop for i in *straights*
collect (loop for j from 0 to 2
collect (get-board-elt (nth j i) board))))
 
(defun find-winner (board)
(car (remove-if #'null (mapcar #'multi-non-nil-eq (elements-of-straights board)))))
 
(defun set-player (mark)
(format t "Shall a computer play as ~a? (y/n)~&" mark)
(let ((response (read)))
(cond ((equalp response 'y) t)
((equalp response 'n) nil)
(t (format t "Come again?~&")
(set-player mark)))))
 
(defun player-move (board symbol)
(format t "~%Player ~a, please input your move.~&" symbol)
(set-board-elt (read) board symbol)
(format t "~%"))
 
(defun computer-move (board symbol)
(let ((move (get-random-element (list-legal-moves board))))
(set-board-elt move board symbol)
(format t "~%computer selects ~a~%~%" move)))
 
(defun computer-move-p (current-player autoplay-x-p autoplay-o-p)
(if (eq current-player 'x)
autoplay-x-p
autoplay-o-p))
 
(defun perform-turn (current-player board autoplay-x-p autoplay-o-p)
(if (computer-move-p current-player autoplay-x-p autoplay-o-p)
(computer-move board current-player)
(player-move board current-player)))
 
(defun switch-player ()
(if (eq *current-player* 'x)
(setf *current-player* 'o)
(setf *current-player* 'x)))
 
(defun display-board (board)
(loop for i downfrom 2 to 0
do (loop for j from 1 to 3
initially (format t "|")
do (format t "~a|" (or (get-board-elt (+ (* 3 i) j) board) (+ (* 3 i) j)))
finally (format t "~&"))))
 
(defun tic-tac-toe ()
(setf *current-player* 'x)
(let ((board (generate-board))
(autoplay-x-p (set-player 'x))
(autoplay-o-p (set-player 'o)))
(format t "~%")
(loop until (or (find-winner board) (null (list-legal-moves board)))
do (display-board board)
do (perform-turn *current-player* board autoplay-x-p autoplay-o-p)
do (switch-player)
finally (if (find-winner board)
(format t "The winner is ~a!" (find-winner board))
(format t "It's a tie.")))))
</syntaxhighlight>
 
{{out}}
<pre>CL-USER> (tic-tac-toe)
Shall a computer play as X? (y/n)
n
Shall a computer play as O? (y/n)
y
 
|7|8|9|
|4|5|6|
|1|2|3|
 
Player X, please input your move.
5
 
|7|8|9|
|4|X|6|
|1|2|3|
 
computer selects 8
 
|7|O|9|
|4|X|6|
|1|2|3|
 
Player X, please input your move.</pre>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.string, std.algorithm, std.conv, std.random,
std.ascii, std.array, std.range, std.math;
 
Line 1,080 ⟶ 4,295:
enum Game { going, humanWins, computerWins, draw }
 
const pure nothrow @safe @nogc invariant() {
int nHuman = 0, nComputer = 0;
foreach (immutable i, immutable c; board)
Line 1,096 ⟶ 4,311:
}
 
bool isAvailable(in int i) const pure nothrow @safe @nogc {
return i >= 0 && i < 9 && board[i].isDigit;
}
 
int[]auto availablePositions() const pure nothrow @safe /*@nogc*/ {
return 9.iota.filter!(i => isAvailable(i)).array;
}
 
Game winner() const pure nothrow @safe /*@nogc*/ {
static immutable wins = [[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
Line 1,123 ⟶ 4,338:
}
 
bool isFinished() const pure nothrow @safe /*@nogc*/ {
return winner != Game.going;
}
Line 1,131 ⟶ 4,346:
assert(res >= 0 && res < 9 && isAvailable(res));
} body {
// return availablePositions.array.choice;
return availablePositions.array[uniform(0, $)];
}
}
Line 1,186 ⟶ 4,401:
break;
}
}</langsyntaxhighlight>
{{out}}
<pre>Tic-tac-toe game player.
Line 1,230 ⟶ 4,445:
 
You win!</pre>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
This is a GUI, event driven version of the game. The game board is a "TStringGrid" component, which has a grid that can hold and display characters. In this case, the grid displays Xs and Ox using a large font.
 
When the user clicks on the grid, this generates an event that is handled by the program. The mouse click coordinates are converted to a cell coordinates and a large X is placed in the box. At this point program tests if this resulted in a win. Next it calculate the computer's response and it checks to see if the computer won. The process is repeated until there is a winner or a draw.
 
[[File:DelphiTicTacToe.png|frame|none]]
 
<syntaxhighlight lang="Delphi">
{Array contain possiple winning lines}
 
type TWinLine = array [0..3-1] of TPoint;
 
var WinLines: array [0..8-1] of TWinLine = (
((X:0; Y:0), (X:1; Y:0), (X:2; Y:0)),
((X:0; Y:1), (X:1; Y:1), (X:2; Y:1)),
((X:0; Y:2), (X:1; Y:2), (X:2; Y:2)),
((X:0; Y:0), (X:0; Y:1), (X:0; Y:2)),
((X:1; Y:0), (X:1; Y:1), (X:1; Y:2)),
((X:2; Y:0), (X:2; Y:1), (X:2; Y:2)),
((X:0; Y:0), (X:1; Y:1), (X:2; Y:2)),
((X:2; Y:0), (X:1; Y:1), (X:0; Y:2))
);
 
 
{Array containing all characters in a line}
 
type TCellArray = array [0..3-1] of char;
 
var WinLineInx: integer;
var GameOver: boolean;
 
procedure ClearGrid;
{Clear TTT Grid by setting all cells to a space}
var X,Y: integer;
begin
with TicTacToeDlg do
begin
for Y:=0 to GameGrid.RowCount-1 do
for X:=0 to GameGrid.ColCount-1 do GameGrid.Cells[X,Y]:=' ';
WinLineInx:=-1;
Status1Dis.Caption:='';
GameOver:=False;
end;
 
end;
 
 
function FirstEmptyCell(var P: TPoint): boolean;
{Find first empty grid i.e. the one containing a space}
{Returns false if there are no empty cells (a tie game)}
var X,Y: integer;
begin
Result:=True;
with TicTacToeDlg do
begin
{Iterate through all cells in array}
for Y:=0 to GameGrid.RowCount-1 do
for X:=0 to GameGrid.ColCount-1 do
if GameGrid.Cells[X,Y]=' ' then
begin
P.X:=X; P.Y:=Y;
Exit;
end;
end;
Result:=False;
end;
 
 
 
procedure GetLineChars(Inx: integer; var CA: TCellArray);
{Get all the characters in a specific win line}
var P1,P2,P3: TPoint;
begin
with TicTacToeDlg do
begin
{Get cell position of specific win line}
P1:=WinLines[Inx,0];
P2:=WinLines[Inx,1];
P3:=WinLines[Inx,2];
{Get the characters from each and put in array}
CA[0]:=GameGrid.Cells[P1.X,P1.Y][1];
CA[1]:=GameGrid.Cells[P2.X,P2.Y][1];
CA[2]:=GameGrid.Cells[P3.X,P3.Y][1];
end;
end;
 
 
 
function IsWinner(var Inx: integer; var C: char): boolean;
{Test if the specified line is a winner}
{Return index of line and the char of winner}
var I,J: integer;
var CA: TCellArray;
begin
with TicTacToeDlg do
begin
Result:=False;
{Go through all winning patterns}
for J:=0 to High(WinLines) do
begin
{Get one winning pattern}
GetLineChars(J,CA);
{Look for line that has the same char in all three places}
if (CA[0]<>' ') and (CA[0]=CA[1]) and (CA[0]=CA[2]) then
begin
Result:=True;
Inx:=J;
C:=CA[0];
end;
end;
 
end;
end;
 
 
procedure DrawWinLine(Inx: integer);
{Draw line through winning squares}
var Line: TWinLine;
var C1,C2: TPoint;
var P1,P2: TPoint;
var W2,H2: integer;
begin
with TicTacToeDlg do
begin
{Offset to center of cell}
W2:=GameGrid.ColWidths[0] div 2;
H2:=GameGrid.RowHeights[0] div 2;
{Get winning pattern of lines}
Line:=WinLines[Inx];
{Get beginning and ending cell of win}
C1:=Line[0]; C2:=Line[2];
{Convert to screen coordinates}
P1.X:=C1.X * GameGrid.ColWidths[0] + W2;
P1.Y:=C1.Y * GameGrid.RowHeights[0] + H2;
P2.X:=C2.X * GameGrid.ColWidths[0] + W2;
P2.Y:=C2.Y * GameGrid.RowHeights[0] + H2;
{Set line attributes}
GameGrid.Canvas.Pen.Color:=clRed;
GameGrid.Canvas.Pen.Width:=5;
{Draw line}
GameGrid.Canvas.MoveTo(P1.X,P1.Y);
GameGrid.Canvas.LineTo(P2.X,P2.Y);
end;
end;
 
 
 
procedure DoBestComputerMove;
{Analyze game board and execute the best computer move}
var I,J,Inx: integer;
var CA: TCellArray;
var P: TPoint;
 
 
function UrgentMove(CA: TCellArray; var EmptyInx: integer): boolean;
{Test row, column or diagonal for an urgent move}
{This would be either an immediate win or immediate loss}
{Returns True if there is an urgent move and the index of location to respond}
var I: integer;
var OCnt,XCnt,EmptyCnt: integer;
begin
Result:=False;
OCnt:=0; XCnt:=0;
EmptyCnt:=0; EmptyInx:=-1;
{Count number of Xs, Os or Spaces in line}
for I:=0 to High(CA) do
begin
case CA[I] of
'O': Inc(OCnt);
'X': Inc(XCnt);
' ':
begin
Inc(EmptyCnt);
if EmptyCnt=1 then EmptyInx:=I;
end;
end;
end;
{Look for pattern of one empty and two Xs or two Os}
{Which means it's one move away from a win}
Result:=(EmptyCnt=1) and ((OCnt=2) or (XCnt=2));
end;
 
 
begin
with TicTacToeDlg do
begin
{Look for urgent moves in all patterns of wins}
for J:=0 to High(WinLines) do
begin
{Get a winning pattern of chars}
GetLineChars(J,CA);
if UrgentMove(CA,Inx) then
begin
{Urgent move found - take it}
P:=WinLines[J,Inx];
GameGrid.Cells[P.X,P.Y]:='O';
exit;
end;
end;
{No urgent moves, so use first empty}
{If there is no empty, the game is stalemated}
if FirstEmptyCell(P) then GameGrid.Cells[P.X,P.Y]:='O';
end;
end;
 
 
function TestWin: boolean;
{Test if last move resulted in win/draw}
var Inx: integer; var C: char;
var P: TPoint;
var S: string;
begin
Result:=True;
{Test if somebody won}
if IsWinner(Inx,C) then
begin
WinLineInx:=Inx;
TicTacToeDlg.GameGrid.Invalidate;
if C='O' then S:=' Computer Won!!' else S:=' You Won!!';
TicTacToeDlg.Status1Dis.Caption:=S;
GameOver:=True;
exit;
end;
{Test if game is a draw}
if not FirstEmptyCell(P) then
begin
TicTacToeDlg.Status1Dis.Caption:=' Game is Draw.';
GameOver:=True;
exit;
end;
Result:=False;
end;
 
 
procedure PlayTicTacToe;
{Show TicTacToe dialog box}
begin
ClearGrid;
TicTacToeDlg.ShowModal
end;
 
 
 
procedure TTicTacToeDlg.GameGridMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
{Handle user click on TicTacToe grid}
var Row,Col: integer;
begin
with TicTacToeDlg do
begin
if GameOver then exit;;
{Convert Mouse X,Y to Grid row and column}
GameGrid.MouseToCell(X,Y,Col,Row);
{Mark user's selection by placing X in the cell}
if GameGrid.Cells[Col,Row]=' 'then
GameGrid.Cells[Col,Row]:='X';
{Did this result in a win? }
if TestWin then exit;
{Get computer's response}
DoBestComputerMove;
{Did computer win}
TestWin;
end;
end;
 
procedure TTicTacToeDlg.ReplayBtnClick(Sender: TObject);
begin
ClearGrid;
end;
 
 
 
procedure TTicTacToeDlg.GameGridDrawCell(Sender: TObject; ACol,
ARow: Integer; Rect: TRect; State: TGridDrawState);
{Draw winner line on top of Xs and Os}
begin
if WinLineInx>=0 then DrawWinLine(WinLineInx);
end;
 
 
 
</syntaxhighlight>
{{out}}
<pre>
 
Elapsed Time: 19.126 Sec.
 
</pre>
 
=={{header|EasyLang}}==
 
It uses minimax with alpha-beta pruning. Therefore, the computer never loses.
 
[https://easylang.dev/apps/tictactoe.html Run it]
 
<syntaxhighlight>
len f[] 9
state = 0
textsize 14
#
proc init . .
linewidth 2
clear
color 666
move 34 96
line 34 20
move 62 96
line 62 20
move 10 72
line 86 72
move 10 44
line 86 44
linewidth 2.5
for i = 1 to 9
f[i] = 0
.
if state = 1
timer 0.2
.
.
proc draw ind . .
c = (ind - 1) mod 3
r = (ind - 1) div 3
x = c * 28 + 20
y = r * 28 + 30
if f[ind] = 4
color 900
move x - 7 y - 7
line x + 7 y + 7
move x + 7 y - 7
line x - 7 y + 7
elif f[ind] = 1
color 009
move x y
circle 10
color -2
circle 7.5
.
.
proc sum3 a d . st .
for i = 1 to 3
s += f[a]
a += d
.
if s = 3
st = -1
elif s = 12
st = 1
.
.
proc rate . res done .
res = 0
for i = 1 step 3 to 7
sum3 i 1 res
.
for i = 1 to 3
sum3 i 3 res
.
sum3 1 4 res
sum3 3 2 res
cnt = 1
for i = 1 to 9
if f[i] = 0
cnt += 1
.
.
res *= cnt
done = 1
if res = 0 and cnt > 1
done = 0
.
.
proc minmax player alpha beta . rval rmov .
rate rval done
if done = 1
if player = 1
rval = -rval
.
else
rval = alpha
start = randint 9
mov = start
repeat
if f[mov] = 0
f[mov] = player
minmax (5 - player) (-beta) (-rval) val h
val = -val
f[mov] = 0
if val > rval
rval = val
rmov = mov
.
.
mov = mov mod 9 + 1
until mov = start or rval >= beta
.
.
.
proc show_result val . .
color 555
move 16 4
if val < 0
# this never happens
text "You won"
elif val > 0
text "You lost"
else
text "Tie"
.
state += 2
.
proc computer . .
minmax 4 -11 11 val mov
f[mov] = 4
draw mov
rate val done
state = 0
if done = 1
show_result val
.
.
proc human . .
mov = floor ((mouse_x - 6) / 28) + 3 * floor ((mouse_y - 16) / 28) + 1
if f[mov] = 0
f[mov] = 1
draw mov
state = 1
timer 0.5
.
.
on timer
rate val done
if done = 1
show_result val
else
computer
.
.
on mouse_down
if state = 0
if mouse_x > 6 and mouse_x < 90 and mouse_y > 16
human
.
elif state >= 2
state -= 2
init
.
.
init
</syntaxhighlight>
 
=={{header|Erlang}}==
The program will randomly chose if the computer ("X") or the user ("O") starts. The computer look ahead is only one level. Perhaps the computer might lose?
<syntaxhighlight lang="erlang">
<lang Erlang>
-module(tic_tac_toe).
 
Line 1,339 ⟶ 5,007:
turn_next_move_ok( true, _Prompt, _Ns, N ) -> N;
turn_next_move_ok( false, Prompt, Ns, _N ) -> turn_next_move( Prompt, Ns ).
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,368 ⟶ 5,036:
Player, "O", select one of [4]: 4
Result: draw.
</pre>
 
=={{header|ERRE}}==
Taken from ERRE distribution disk: comments and messages are in Italian.
<pre>!--------------------------------------------
! TRIS.R : gioca a tris contro l'operatore
!--------------------------------------------
 
PROGRAM TRIS
 
DIM TRIS%[9],T1%[9],PIECES$[3]
 
!$SEGMENT=$B800
 
!$INCLUDE="PC.LIB"
 
PROCEDURE DELAY(COUNT%)
FOR Z%=1 TO COUNT DO
END FOR
END PROCEDURE
 
PROCEDURE SET_BOARD
!
! Disegna lo schema del gioco
!
CLS
BLOAD("TRIS.BLD",0)
!$KEY
END PROCEDURE
 
PROCEDURE PUT_PIECES
!
! Pone i pezzi sulla scacchiera
!
Z%=0
FOR ROW%=6 TO 12 STEP 3 DO ! posizioni assolute sullo schermo
FOR COL%=32 TO 48 STEP 8 DO
LOCATE(ROW%+1,COL%+1)
Z%=Z%+1
PRINT(PIECES$[TRIS%[Z%]])
END FOR
END FOR
END PROCEDURE
 
PROCEDURE COMPUTE_MOVE(A%)
CASE A% OF
2-> C1%=C1%+1 END ->
4-> C2%=C2%+1 END ->
8-> S1%=TRUE S2%=TRUE END ->
3-> N1%=N1%+1 END ->
9-> N2%=N2%+1 END ->
27-> S1%=FALSE S2%=FALSE END ->
END CASE
END PROCEDURE
 
PROCEDURE PREPAREMOVE(T1%[],I%->M%)
!
! Prepara la mossa del calcolatore
!
T1%[I%]=2
C1%=0
C2%=0
N1%=0
N2%=0
FOR K%=0 TO 2 DO
COMPUTE_MOVE(T1%[3*K%+1]*T1%[3*K%+2]*T1%[3*K%+3])
COMPUTE_MOVE(T1%[K%+1]*T1%[K%+4]*T1%[K%+7])
END FOR
COMPUTE_MOVE(T1%[1]*T1%[5]*T1%[9])
COMPUTE_MOVE(T1%[3]*T1%[5]*T1%[7])
M%=-63*N2%+31*C2%-15*N1%+7*C1%
END PROCEDURE
 
PROCEDURE COMPUTER_MOVE
!
! Coordina le mosse del calcolatore
!
MAXSCORE%=-1000
FOR I%=1 TO 9 DO
IF TRIS%[I%]=1
THEN
PREPAREMOVE(TRIS%[],I%->MV%)
EXIT IF S2% AND NOT S1%
IF S1% AND S2%
THEN
TRIS%[I%]=2
DIARY$=DIARY$+"c"+MID$(STR$(I%),2)+"*"
PUT_PIECES
EXIT
END IF
IF MV%=0
THEN
MOVE%=I%
EXIT
END IF
IF MV%>MAXSCORE%
THEN
MOVE%=I%
MAXSCORE%=MV%
END IF
END IF
END FOR
IF NOT S2%
THEN
TRIS%[MOVE%]=2
DIARY$=DIARY$+"c"+MID$(STR$(MOVE%),2)+";"
PUT_PIECES
NMOVE%=NMOVE%-1
S1%=(NMOVE%=0)
END IF
END PROCEDURE
 
PROCEDURE PLAYER_MOVE
!
! Gioca l'avversario umano usando i tasti cursore per lo spostamento
!
LOCATE(19,13)
PRINT("Tocca a te .... ")
REPEAT
ROW%=7
COL%=32
LOCATE(ROW%+1,COL%+1)
PRINT("Ü")
REPEAT
GET(B$)
IF LEN(B$)=2 THEN
CASE ASC(RIGHT$(B$,1)+CHR$(0)) OF
77-> ! codice tastiera per CRSR =>
LOCATE(ROW%+1,COL%+1)
PRINT(" ")
COL%=-(COL%+8)*(COL%<=40)-32*(COL%>40)
LOCATE(ROW%+1,COL%+1)
PRINT("Ü")
END ->
75-> ! codice tastiera per CRSR <=
LOCATE(ROW%+1,COL%+1)
PRINT(" ")
COL%=-(COL%-8)*(COL%>=40)-48*(COL%<40)
LOCATE(ROW%+1,COL%+1)
PRINT("Ü")
END ->
80-> ! codice tastiera per CRSR DOWN
LOCATE(ROW%+1,COL%+1)
PRINT(" ")
ROW%=-(ROW%+3)*(ROW%<=10)-7*(ROW%>10)
LOCATE(ROW%+1,COL%+1)
PRINT("Ü")
END ->
72-> ! codice tastiera per CRSR UP
LOCATE(ROW%+1,COL%+1)
PRINT(" ")
ROW%=-(ROW%-3)*(ROW%>=10)-13*(ROW%<10)
LOCATE(ROW%+1,COL%+1)
PRINT("Ü")
END ->
END CASE
END IF
UNTIL B$=CHR$(13)
MM%=ROW%+COL%/8-10 ! da coordinate schermo a coordinate scacchiera
UNTIL TRIS%[MM%]=1
TRIS%[MM%]=3
LOCATE(ROW%+1,COL%+1)
PRINT(" ")
DIARY$=DIARY$+"p"+MID$(STR$(MM%),2)+";"
PUT_PIECES
NMOVE%=NMOVE%-1
S1%=(NMOVE%=0)
LOCATE(19,13)
PRINT(STRING$(45," "))
END PROCEDURE
 
BEGIN
DATA(" ","+","o")
SET_BOARD
REPEAT
S1%=FALSE S2%=FALSE ! determinano lo stato della partita
NMOVE%=9
FOR Z%=1 TO 3 DO
READ(PIECES$[Z%])
END FOR
FOR Z%=1 TO 9 DO
TRIS%[Z%]=1
END FOR
LOCATE(19,13)
PRINT("Giochi per primo ?")
REPEAT
GET(A$)
UNTIL A$="S" OR A$="s" OR A$="N" OR A$="n"
PUT_PIECES
FOR INDICE%=1 TO 9 DO
IF A$="s" OR A$="S"
THEN
PLAYER_MOVE
EXIT IF S1% OR S2%
COMPUTER_MOVE
EXIT IF S1% OR S2%
ELSE
COMPUTER_MOVE
EXIT IF S1% OR S2%
PLAYER_MOVE
EXIT IF S1% OR S2%
END IF
END FOR
LOCATE(19,13)
CASE TRUE OF
(S1% AND NOT S2%)->
PRINT("E' finita pari !!! ")
END ->
(S2% AND NOT S1%)->
PRINT("HAI VINTO !!! ")
END ->
(S1% AND S2%)->
PRINT("HO VINTO IO !!! ")
END ->
END CASE
DELAY(500)
LOCATE(19,13)
PRINT(DIARY$)
DELAY(500)
LOCATE(19,13)
PRINT("Vuoi giocare ancora ? ")
REPEAT
GET(A$)
UNTIL A$="S" OR A$="s" OR A$="N" OR A$="n"
UNTIL A$="N" OR A$="n"
END PROGRAM
</pre>
{{out}}
A game example
<pre>
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░
░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░
░░▒▒▓▓ ▓▓▒▒░░
░░▒▒▓▓ ┌───────────────┐ ╔═══════╤═══════╤═══════╗ ┌────────────┐ ▓▓▒▒░░
░░▒▒▓▓ │───── TRIS ────│ ║ + │ o │ + ║ │Il calcola- │ ▓▓▒▒░░
░░▒▒▓▓ │ │ ║ │ │ ║ │tore non può│ ▓▓▒▒░░
░░▒▒▓▓ │Si gioca contro│ ╟───────┼───────┼───────╢ │perdere e │ ▓▓▒▒░░
░░▒▒▓▓ │il calcolatore.│ ║ + │ o │ o ║ │perciò il │ ▓▓▒▒░░
░░▒▒▓▓ │Per muoversi │ ║ │ │ ║ │giocatore │ ▓▓▒▒░░
░░▒▒▓▓ │usare i tasti │ ╟───────┼───────┼───────╢ │può al mas- │ ▓▓▒▒░░
░░▒▒▓▓ │cursore e ◄──┘ │ ║ o │ + │ o ║ │simo pareg- │ ▓▓▒▒░░
░░▒▒▓▓ │per confermare.│ ║ │ │ ║ │giare. │ ▓▓▒▒░░
░░▒▒▓▓ └───────────────┘ ╚═══════╧═══════╧═══════╝ └────────────┘ ▓▓▒▒░░
░░▒▒▓▓ ▓▓▒▒░░
░░▒▒▓▓ ▓▓▒▒░░
░░▒▒▓▓ ┌────────────────────────────────────────────────────────────┐ ▓▓▒▒░░
░░▒▒▓▓ │ Vuoi giocare ancora ? │ ▓▓▒▒░░
░░▒▒▓▓ └────────────────────────────────────────────────────────────┘ ▓▓▒▒░░
░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░
░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
</pre>
 
=={{header|Euphoria}}==
{{works with|OpenEuphoria}}
No computer AI
<syntaxhighlight lang="euphoria">
include std/console.e
include std/text.e
include std/search.e
include std/sequence.e
 
sequence board
sequence players = {"X","O"}
 
function DisplayBoard()
for i = 1 to 3 do
for j = 1 to 3 do
printf(1,"%s",board[i][j])
if j < 3 then
printf(1,"%s","|")
end if
end for
if i < 3 then
puts(1,"\n-----\n")
else
puts(1,"\n\n")
end if
end for
return 1
end function
 
function CheckWinner()
sequence temp = board
for a = 1 to 2 do
for i = 1 to 3 do
if equal({"X","X","X"},temp[i]) then
puts(1,"X wins\n\n")
return 1
elsif equal({"O","O","O"},temp[i]) then
puts(1,"O wins\n\n")
return 1
end if
end for
temp = columnize(board)
end for
if equal({"X","X","X"},{board[1][1],board[2][2],board[3][3]}) or
equal({"X","X","X"},{board[1][3],board[2][2],board[3][1]}) then
puts(1,"X wins\n")
return 1
elsif equal({"O","O","O"},{board[1][1],board[2][2],board[3][3]}) or
equal({"O","O","O"},{board[1][3],board[2][2],board[3][1]}) then
puts(1,"O wins\n")
return 1
end if
if moves = 9 then
puts(1,"Draw\n\n")
return 1
end if
return 0
end function
 
integer turn, row, column, moves
sequence replay
while 1 do
board = repeat(repeat(" ",3),3)
DisplayBoard()
turn = rand(2)
moves = 0
while 1 do
while 1 do
printf(1,"%s's turn\n",players[turn])
row = prompt_number("Enter row: ",{})
column = prompt_number("Enter column: ",{})
if match(board[row][column]," ") then
board[row][column] = players[turn]
moves += 1
exit
else
puts(1,"Space already taken - pick again\n")
end if
end while
DisplayBoard()
if CheckWinner() then
exit
end if
if turn = 1 then
turn = 2
else
turn = 1
end if
end while
 
replay = lower(prompt_string("Play again (y/n)?\n\n"))
if match(replay,"n") then
exit
end if
 
end while
</syntaxhighlight>
{{out}}
<pre>
| |
-----
| |
-----
| |
 
O's turn
Enter row: 1
Enter column: 1
O| |
-----
| |
-----
| |
 
X's turn
Enter row: 3
Enter column: 3
O| |
-----
| |
-----
| |X
 
O's turn
Enter row: 3
Enter column: 1
O| |
-----
| |
-----
O| |X
 
X's turn
Enter row: 2
Enter column: 1
O| |
-----
X| |
-----
O| |X
 
O's turn
Enter row: 2
Enter column: 2
O| |
-----
X|O|
-----
O| |X
 
X's turn
Enter row: 1
Enter column: 3
O| |X
-----
X|O|
-----
O| |X
 
O's turn
Enter row: 1
Enter column: 2
O|O|X
-----
X|O|
-----
O| |X
 
X's turn
Enter row: 3
Enter column: 2
O|O|X
-----
X|O|
-----
O|X|X
 
O's turn
Enter row: 2
Enter column: 3
O|O|X
-----
X|O|O
-----
O|X|X
 
Draw
 
Play again (y/n)?
</pre>
 
Line 1,373 ⟶ 5,492:
A purely-functional solution with a naive (but perfect) computer player implementation. The first move is played randomly by the computer.
 
<langsyntaxhighlight lang="fsharp">type Brick =
| Empty
| Computer
Line 1,505 ⟶ 5,624:
let b = set Computer emptyBoard (choose (freeSpace emptyBoard))
printBoard b
gameLoop b User</langsyntaxhighlight>
 
Example game:
Line 1,577 ⟶ 5,696:
Game over. I have won.
</pre>
 
 
 
=={{header|Forth}}==
{{works with|gforth|0.7.3}}
Game between two humans.
 
<syntaxhighlight lang="forth">create board 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
 
\ board: 0=empty, 1=player X, 2=player O
: player. ( player -- ) C" XO" 1+ + @ emit ;
: spot ( n -- addr ) cells board + ;
: clean-board ( -- ) 9 0 do 0 i spot ! loop ;
: show-board
CR ." +---+---+---+ +---+---+---+" CR
3 0 do
." | "
3 0 do
i j 3 * + spot @ player. ." | "
loop
." | "
3 0 do
i j 3 * + . ." | "
loop
CR ." +---+---+---+ +---+---+---+" CR
loop ;
 
: spots-equal ( n1 n2 n3 -- f )
over spot @ swap spot @ = >r spot @ swap spot @ = r> and ;
: spots-win ( n1 n2 n3 -- f )
dup >r spots-equal r> spot @ 0<> and ;
 
: winner-check ( -- player )
0 1 2 spots-win if 0 spot @ exit then
3 4 5 spots-win if 3 spot @ exit then
6 7 8 spots-win if 6 spot @ exit then
0 3 6 spots-win if 0 spot @ exit then
1 4 7 spots-win if 1 spot @ exit then
2 5 8 spots-win if 2 spot @ exit then
0 4 8 spots-win if 0 spot @ exit then
2 4 6 spots-win if 2 spot @ exit then
0 ;
 
: player-move ( player -- )
begin
key dup emit [char] 0 - dup
spot @ 0= if spot ! exit else drop then
again ;
 
: game
clean-board show-board
9 0 do
i 2 mod 1+ dup ." Player " player. ." : "
player-move show-board
winner-check dup 0<> if player. ." wins !" unloop exit else drop then
loop
." Draw!" ;
 
game
</syntaxhighlight>
 
{{out}}
<pre>
+---+---+---+ +---+---+---+
| | | | | 0 | 1 | 2 |
+---+---+---+ +---+---+---+
| | | | | 3 | 4 | 5 |
+---+---+---+ +---+---+---+
| | | | | 6 | 7 | 8 |
+---+---+---+ +---+---+---+
Player X: 0
+---+---+---+ +---+---+---+
| X | | | | 0 | 1 | 2 |
+---+---+---+ +---+---+---+
| | | | | 3 | 4 | 5 |
+---+---+---+ +---+---+---+
| | | | | 6 | 7 | 8 |
+---+---+---+ +---+---+---+
Player O: 3
+---+---+---+ +---+---+---+
| X | | | | 0 | 1 | 2 |
+---+---+---+ +---+---+---+
| O | | | | 3 | 4 | 5 |
+---+---+---+ +---+---+---+
| | | | | 6 | 7 | 8 |
+---+---+---+ +---+---+---+
Player X: 1
+---+---+---+ +---+---+---+
| X | X | | | 0 | 1 | 2 |
+---+---+---+ +---+---+---+
| O | | | | 3 | 4 | 5 |
+---+---+---+ +---+---+---+
| | | | | 6 | 7 | 8 |
+---+---+---+ +---+---+---+
Player O: 4
+---+---+---+ +---+---+---+
| X | X | | | 0 | 1 | 2 |
+---+---+---+ +---+---+---+
| O | O | | | 3 | 4 | 5 |
+---+---+---+ +---+---+---+
| | | | | 6 | 7 | 8 |
+---+---+---+ +---+---+---+
Player X: 2
+---+---+---+ +---+---+---+
| X | X | X | | 0 | 1 | 2 |
+---+---+---+ +---+---+---+
| O | O | | | 3 | 4 | 5 |
+---+---+---+ +---+---+---+
| | | | | 6 | 7 | 8 |
+---+---+---+ +---+---+---+
X wins ! ok
</pre>
 
 
 
 
=={{header|Fortran}}==
Objective: write program in less than 100 lines, not using semicolons. Computer never loses, but plays as random as possible. Player gets first move of first game. Afterwards, first move alternates between computer and player.
<syntaxhighlight lang="fortran">
! This is a fortran95 implementation of the game of tic-tac-toe.
! - Objective was to use less than 100 lines.
! - No attention has been devoted to efficiency.
! - Indentation by findent: https://sourceforge.net/projects/findent/
! - This is free software, use as you like at own risk.
! - Compile: gfortran -o tictactoe tictactoe.f90
! - Run: ./tictactoe
! Comments to: wvermin at gmail dot com
module tic
implicit none
integer :: b(9)
contains
logical function iswin(p)
integer,intent(in) :: p
iswin = &
all(b([1,2,3])==p).or.all(b([4,5,6])==p).or.all(b([7,8,9])==p).or.&
all(b([1,4,7])==p).or.all(b([2,5,8])==p).or.all(b([3,6,9])==p).or.&
all(b([1,5,9])==p).or.all(b([3,5,7])==p)
end function iswin
subroutine printb(mes)
character(len=*) :: mes
integer :: i,j
character :: s(0:2) = ['.','X','O']
print "(3a3,' ',3i3)",(s(b(3*i+1:3*i+3)),(j,j=3*i+1,3*i+3),i=0,2)
if(mes /= ' ') print "(/,a)",mes
end subroutine printb
integer recursive function minmax(player,bestm) result(bestv)
integer :: player,bestm,move,v,bm,win=1000,inf=100000
real :: x
if (all(b .ne. 0)) then
bestv = 0
else
bestv = -inf
do move=1,9
if (b(move) == 0) then
b(move) = player
if (iswin(player)) then
v = win
else
call random_number(x)
v = -minmax(3-player,bm) - int(10*x)
endif
if (v > bestv) then
bestv = v
bestm = move
endif
b(move) = 0
if (v == win) exit
endif
enddo
endif
end function minmax
end module tic
program tictactoe
! computer: player=1, user: player=2
use tic
implicit none
integer :: move,ios,v,bestmove,ply,player=2,k,values(8)
integer,allocatable :: seed(:)
call date_and_time(values=values)
call random_seed(size=k)
allocate(seed(k))
seed = values(8)+1000*values(7)+60*1000*values(6)+60*60*1000*values(5)
call random_seed(put=seed)
mainloop: do
b = 0
call printb('You have O, I have X. You enter 0: game ends.')
plyloop: do ply=0,4
if (player == 2 .or. ply >0 ) then ! user move
write(*,"(/,a)",advance='no'),'Your move? (0..9) '
getloop: do
readloop: do
read (*,*,iostat=ios),move
if (ios == 0 .and. move >= 0 .and. move <= 9) exit readloop
write(*,"(a)",advance='no'),'huh? Try again (0..9): '
enddo readloop
if ( move == 0) exit mainloop
if (b(move) == 0) exit getloop
write(*,"(a)",advance='no'),'Already occupied, again (0..9): '
enddo getloop
b(move) = 2
if(iswin(2)) then ! this should not happen
call printb('***** You win *****')
exit plyloop
endif
endif
v = minmax(1,bestmove) ! computer move
b(bestmove) = 1
if(iswin(1)) then
call printb('***** I win *****')
exit plyloop
endif
write(*,"(/,a,i3)"), 'My move: ',bestmove
call printb(' ')
enddo plyloop
if(ply == 5) write(*,"('***** Draw *****',/)")
player = 3-player
enddo mainloop
end program
</syntaxhighlight>
 
=={{header|Go}}==
Intermediate, like Python's "Better skilled player." Computer wins and blocks where it can, but otherwise plays randomly. Plays multiple games and keeps score. Player gets first move of first game. Afterwards, loser gets to go first, or after cat games, first move alternates.
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,739 ⟶ 6,078:
{0, 4, 8}, // diagonals
{2, 4, 6},
}</langsyntaxhighlight>
 
=={{header|Groovy}}==
Simplified version of Tic Tac Toe for player vs. player (no AI computer-controlled option).
<langsyntaxhighlight Groovylang="groovy">class Main {
 
def input = new Scanner(System.in)
Line 1,875 ⟶ 6,215:
return builder.toString();
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
Computer player has three strategies: 1. Try to block the opponent first, 2. Try to guess a good position for the next move, 3. Place a piece randomly.
There are lots of comments throughout the code.
<syntaxhighlight lang="haskell">
<lang Haskell>
module Main where
 
Line 2,101 ⟶ 6,441:
putStrLn "3 : player X is human and player O is computer"
putStrLn "Player X always begins."
</syntaxhighlight>
</lang>
{{out}}
'''Output:'''
Player X is computer, O is human.
<pre>
Line 2,230 ⟶ 6,570:
The following works in both Icon and Unicon. The computer plays randomly against a human player, with legal moves enforced and wins/draws notified.
 
<syntaxhighlight lang="icon">
<lang Icon>
# Play TicTacToe
 
Line 2,343 ⟶ 6,683:
play_game ()
end
</syntaxhighlight>
</lang>
 
=={{header|J}}==
To subsequent j poster: replacing this entry is fine by me.
<syntaxhighlight lang="j">
<lang J>
Note 'ttt adjudicates or plays'
 
Line 2,442 ⟶ 6,782:
nor=: 8 b.
infix_pairs_agree=: 2&(=/\)
</syntaxhighlight>
</lang>
 
=={{header|Java}}==
This version works in the terminal itself, and uses the numpad for data entry. The computer is unbeatable, but some lines can be removed to avoid that. There's also an override that thrown in, just for fun.
<langsyntaxhighlight lang="java">
import java.io.BufferedReader;
import java.io.InputStreamReader;
Line 2,771 ⟶ 7,111:
}
}
</syntaxhighlight>
</lang>
 
<pre>
Line 2,821 ⟶ 7,161:
 
This version uses javax.swing.
<langsyntaxhighlight lang="java">import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
Line 2,984 ⟶ 7,324:
}
}
</syntaxhighlight>
</lang>
 
Graphical Java Example
<langsyntaxhighlight lang="java">
import javax.swing.*;
import java.awt.event.*;
Line 3,462 ⟶ 7,802:
}
}
</syntaxhighlight>
</lang>
The following program may be executed for a player-against-player game.
<syntaxhighlight lang="java">
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
 
public class TicTacToe {
private static int turnNumber = 0;
private static final JPanel panel = new JPanel();
private static final JTextField ta = new JTextField("Player A's Turn (X)");
private static final JButton r1c1 = new JButton("");
private static final JButton r1c2 = new JButton("");
private static final JButton r1c3 = new JButton("");
private static final JButton r2c1 = new JButton("");
private static final JButton r2c2 = new JButton("");
private static final JButton r2c3 = new JButton("");
private static final JButton r3c1 = new JButton("");
private static final JButton r3c2 = new JButton("");
private static final JButton r3c3 = new JButton("");
private static final JButton restart = new JButton("New Game");
private static final JPanel startMain = new JPanel();
 
public static void main(String[]args){
JFrame frame = new JFrame("Tic Tac Toe");
frame.setSize(600,650);
ta.setEditable(false);
restart.addActionListener(e -> {
enableAll();
ta.setText("Player A's Turn (X)");
});
r1c1.setSize(67,67);
r1c1.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r1c1.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r1c1.setText("O");
r1c1.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r1c1.setText("X");
r1c1.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r1c2.setSize(67,67);
r1c2.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r1c2.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r1c2.setText("O");
r1c2.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r1c2.setText("X");
r1c2.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r1c3.setSize(67,67);
r1c3.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r1c3.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r1c3.setText("O");
r1c3.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r1c3.setText("X");
r1c3.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r2c1.setSize(67,67);
r2c1.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r2c1.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r2c1.setText("O");
r2c1.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r2c1.setText("X");
r2c1.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r2c2.setSize(67,67);
r2c2.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r2c2.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r2c2.setText("O");
r2c2.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r2c2.setText("X");
r2c2.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r2c3.setSize(67,67);
r2c3.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r2c3.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r2c3.setText("O");
r2c3.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r2c3.setText("X");
r2c3.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r3c1.setSize(67,67);
r3c1.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r3c1.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r3c1.setText("O");
r3c1.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r3c1.setText("X");
r3c1.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r3c2.setSize(67,67);
r3c2.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r3c2.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r3c2.setText("O");
r3c2.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r3c2.setText("X");
r3c2.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
r3c3.setSize(67,67);
r3c3.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
r3c3.addActionListener(e -> {
turnNumber++;
if(turnNumber % 2 == 0){
r3c3.setText("O");
r3c3.setEnabled(false);
ta.setText("Player A's Turn (X)");
}else{
r3c3.setText("X");
r3c3.setEnabled(false);
ta.setText("Player B's Turn (O)");
}
checkWin();
});
panel.setLayout(new GridLayout(3,3));
 
panel.add(r1c1);
panel.add(r1c2);
panel.add(r1c3);
panel.add(r2c1);
panel.add(r2c2);
panel.add(r2c3);
panel.add(r3c1);
panel.add(r3c2);
panel.add(r3c3);
startMain.setLayout(new GridLayout(5,5));
JButton start = new JButton("Start");
JLabel main = new JLabel("Tic Tac Toe", SwingConstants.CENTER);
main.setFont(new Font("Trebuchet MS", Font.PLAIN, 70));
main.setSize(400,400);
startMain.add(main);
startMain.add(start);
frame.add(startMain);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start.addActionListener(e -> {
startMain.setVisible(false);
frame.add(restart, BorderLayout.PAGE_START);
frame.add(ta, BorderLayout.PAGE_END);
frame.add(panel, BorderLayout.CENTER);
});
}
public static void checkWin(){
if(r1c1.getText().equals("X") && r1c2.getText().equals("X") && r1c3.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r1c1.getText().equals("O") && r1c2.getText().equals("O") && r1c3.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r1c1.getText().equals("X") && r2c2.getText().equals("X") && r3c3.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r1c1.getText().equals("O") && r2c2.getText().equals("O") && r3c3.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r1c1.getText().equals("X") && r2c1.getText().equals("X") && r3c1.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r1c1.getText().equals("O") && r2c1.getText().equals("O") && r3c1.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r2c1.getText().equals("X") && r2c2.getText().equals("X") && r2c3.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r2c1.getText().equals("O") && r2c2.getText().equals("O") && r2c3.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r1c2.getText().equals("X") && r2c2.getText().equals("X") && r3c2.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r1c2.getText().equals("O") && r2c2.getText().equals("O") && r3c2.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r1c3.getText().equals("X") && r2c3.getText().equals("X") && r3c3.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r1c3.getText().equals("O") && r2c3.getText().equals("O") && r3c3.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r3c1.getText().equals("X") && r3c2.getText().equals("X") && r3c3.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r3c1.getText().equals("O") && r3c2.getText().equals("O") && r3c3.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(r3c1.getText().equals("X") && r2c2.getText().equals("X") && r1c3.getText().equals("X")){
ta.setText("Player A Won! (X)");
disableAll();
}else if(r3c1.getText().equals("O") && r2c2.getText().equals("O") && r1c3.getText().equals("O")){
ta.setText("Player B Won! (O)");
disableAll();
}else if(!r1c1.isEnabled() && !r1c2.isEnabled() && !r1c3.isEnabled() && !r2c1.isEnabled() && !r2c2.isEnabled() && !r2c3.isEnabled() && !r3c1.isEnabled() && !r3c2.isEnabled() && !r3c3.isEnabled()){
ta.setText("Draw!");
disableAll();
}
}
public static void disableAll(){
r1c1.setEnabled(false);
r1c2.setEnabled(false);
r1c3.setEnabled(false);
r2c1.setEnabled(false);
r2c2.setEnabled(false);
r2c3.setEnabled(false);
r3c1.setEnabled(false);
r3c2.setEnabled(false);
r3c3.setEnabled(false);
}
 
public static void enableAll(){
turnNumber = 0;
r1c1.setEnabled(true);
r1c2.setEnabled(true);
r1c3.setEnabled(true);
r2c1.setEnabled(true);
r2c2.setEnabled(true);
r2c3.setEnabled(true);
r3c1.setEnabled(true);
r3c2.setEnabled(true);
r3c3.setEnabled(true);
r1c1.setText("");
r1c2.setText("");
r1c3.setText("");
r2c1.setText("");
r2c2.setText("");
r2c3.setText("");
r3c1.setText("");
r3c2.setText("");
r3c3.setText("");
panel.setEnabled(true);
}
}
</syntaxhighlight>
 
=={{header|Javascript}}==
HTML5 Canvas implementation. Should play perfectly or near-perfectly.
<syntaxhighlight lang="javascript">
<!DOCTYPE html>
 
<html>
 
<head>
<meta charset="utf-8" />
<title>TicTacToe</title>
</head>
 
<body>
<canvas id="canvas" width="400" height="400"></canvas>
 
<script>
//All helper functions
isBetween = (num, a, b) => {
return num >= a && num <= b;
}
 
randInt = (low, high) => {
return Math.floor(Math.random() * (high - low + 1)) + low;
}
 
choice = arr => {
return arr[randInt(0, arr.length - 1)];
}
 
//Checks if every value in an array equals an item
equals = (arr, item) => {
return arr.filter(a => {
return a === item;
}).length === arr.length;
}
 
//Returns number of items in array that equal an item
equallen = (arr, item) => {
return arr.filter(a => {
return a === item;
}).length
}
 
//Checks if any value in the array equals an item
equalanyof = (arr, item) => {
return equallen(arr, item) > 0;
}
 
//Should be scalable, but it uses default elements for calculations and tracking
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
const width = canvas.width;
const blockSize = canvas.width / 3;
const lineSize = blockSize / 5;
 
//Draws background
ctx.fillStyle = "rgb(225, 225, 225)";
ctx.fillRect(0, 0, 400, 400);
 
//Title page
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.font = width / (250 / 17) + "px Arial"; //34
ctx.textAlign = "center";
ctx.fillText("Tic Tac Toe", width / 2, width / (2 + 2 / 3)); //200, 150
 
//Button for starting
ctx.fillStyle = "rgb(200, 200, 200)";
ctx.fillRect(width / 3.2, width / 2, width / (2 + 2 / 3), width / 8); //125, 200, 150, 50
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.font = width / (200 / 9) + "px Arial"; //18
ctx.fillText("Start", width / 2, width / (40 / 23)); //200, 230
 
//Uses an array so a forEach loop can scan it for the correct tile
let tileArray = []; //Contains all tiles
let available = []; //Contains only available tiles
 
class Tile {
constructor(x, y) {
this.x = x * blockSize;
this.y = y * blockSize;
this.state = "none";
tileArray.push(this);
available.push(this);
}
 
draw() {
ctx.strokeStyle = "rgb(175, 175, 175)";
ctx.lineWidth = blockSize / 10;
 
if (this.state === "X") {
ctx.beginPath();
ctx.moveTo(this.x + blockSize / 4, this.y + blockSize / 4);
ctx.lineTo(this.x + blockSize / (4 / 3), this.y + blockSize / (4 / 3));
ctx.moveTo(this.x + blockSize / 4, this.y + blockSize / (4 / 3));
ctx.lineTo(this.x + blockSize / (4 / 3), this.y + blockSize / 4);
ctx.stroke();
} else if (this.state === "O") {
ctx.beginPath();
ctx.arc(this.x + blockSize / 2, this.y + blockSize / 2, blockSize / 4, 0, 2 * Math.PI);
ctx.stroke();
}
 
//Removes this from the available array
const ind = available.indexOf(this);
available = available.slice(0, ind).concat(available.slice(ind + 1, available.length));
}
}
 
 
//Defines the game
let game = {
state: "start",
turn: "Player",
player: "X",
opp: "O"
}
 
//Generates tiles
for (let x = 0; x < 3; x++) {
for (let y = 0; y < 3; y++) {
new Tile(x, y);
}
}
 
//Gets the mouse position
getMousePos = evt => {
let rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
}
}
 
//Checks for win conditions
checkCondition = () => {
//Local variables are created to make access easier
let as = tileArray[0].state;
let bs = tileArray[1].state;
let cs = tileArray[2].state;
let ds = tileArray[3].state;
let es = tileArray[4].state;
let fs = tileArray[5].state;
let gs = tileArray[6].state;
let hs = tileArray[7].state;
let is = tileArray[8].state;
 
//Equals function checks if each value in the array has a state of X or O
if (equals([as, bs, cs], "X") || equals([ds, es, fs], "X") || equals([gs, hs, is], "X") ||
equals([as, ds, gs], "X") || equals([bs, es, hs], "X") || equals([cs, fs, is], "X") ||
equals([as, es, is], "X") || equals([cs, es, gs], "X")) {
alert("Player wins!");
game.state = "over";
} else if (equals([as, bs, cs], "O") || equals([ds, es, fs], "O") || equals([gs, hs, is], "O") ||
equals([as, ds, gs], "O") || equals([bs, es, hs], "O") || equals([cs, fs, is], "O") ||
equals([as, es, is], "O") || equals([cs, es, gs], "O")) {
alert("Opponent wins!");
game.state = "over";
//It is a tie if none of the above conditions are fulfilled and there are no available tiles
} else if (available.length === 0) {
alert("It's a tie!");
game.state = "over";
}
}
 
//Controls the opponent. Uses many nested switches/if-else for efficiency
oppTurn = () => {
if (game.state === "game") {
let tile = 0;
 
//Similar local variables as the win checker
let at = tileArray[0].state;
let bt = tileArray[1].state;
let ct = tileArray[2].state;
let dt = tileArray[3].state;
let et = tileArray[4].state;
let ft = tileArray[5].state;
let gt = tileArray[6].state;
let ht = tileArray[7].state;
let it = tileArray[8].state;
let all = [at, bt, ct, dt, et, ft, gt, ht, it];
 
/*The AI will automatically win if possible
I considered using a filter based system, but it was ugly and
inelegant, and also redundant
I used a nested if-else instead
Equallen checks how many values in the array equal the given value*/
if (equallen(all, "O") >= 2) {
if (equallen([at, bt, ct], "O") === 2 && equallen([at, bt, ct], "X") === 0) {
if (at === "none") {
tile = tileArray[0];
} else if (bt === "none") {
tile = tileArray[1];
} else if (ct === "none") {
tile = tileArray[2];
}
} else if (equallen([dt, et, ft], "O") === 2 && equallen([dt, et, ft], "X") === 0) {
if (dt === "none") {
tile = tileArray[3];
} else if (et === "none") {
tile = tileArray[4];
} else if (ft === "none") {
tile = tileArray[5];
}
} else if (equallen([gt, ht, it], "O") === 2 && equallen([gt, ht, it], "X") === 0) {
if (gt === "none") {
tile = tileArray[6];
} else if (ht === "none") {
tile = tileArray[7];
} else if (it === "none") {
tile = tileArray[8];
}
} else if (equallen([at, dt, gt], "O") === 2 && equallen([at, dt, gt], "X") === 0) {
if (at === "none") {
tile = tileArray[0];
} else if (dt === "none") {
tile = tileArray[3];
} else if (gt === "none") {
tile = tileArray[6];
}
} else if (equallen([bt, et, ht], "O") === 2 && equallen([bt, et, ht], "X") === 0) {
if (bt === "none") {
tile = tileArray[1];
} else if (et === "none") {
tile = tileArray[4];
} else if (ht === "none") {
tile = tileArray[7];
}
} else if (equallen([ct, ft, it], "O") === 2 && equallen([ct, ft, it], "X") === 0) {
if (ct === "none") {
tile = tileArray[2];
} else if (ft === "none") {
tile = tileArray[5];
} else if (it === "none") {
tile = tileArray[8];
}
} else if (equallen([at, et, it], "O") === 2 && equallen([at, et, it], "X") === 0) {
if (at === "none") {
tile = tileArray[0];
} else if (et === "none") {
tile = tileArray[4];
} else if (it === "none") {
tile = tileArray[8];
}
} else if (equallen([ct, et, gt], "O") === 2 && equallen([ct, et, gt], "X") === 0) {
if (ct === "none") {
tile = tileArray[2];
} else if (et === "none") {
tile = tileArray[4];
} else if (gt === "none") {
tile = tileArray[6];
}
}
}
 
//Stops player from winning if possible
if (equallen(all, "X") >= 2 && tile === 0) {
if (equallen([at, bt, ct], "X") === 2 && equallen([at, bt, ct], "O") === 0) {
if (at === "none") {
tile = tileArray[0];
} else if (bt === "none") {
tile = tileArray[1];
} else if (ct === "none") {
tile = tileArray[2];
}
} else if (equallen([dt, et, ft], "X") === 2 && equallen([dt, et, ft], "O") === 0) {
if (dt === "none") {
tile = tileArray[3];
} else if (et === "none") {
tile = tileArray[4];
} else if (ft === "none") {
tile = tileArray[5];
}
} else if (equallen([gt, ht, it], "X") === 2 && equallen([gt, ht, it], "O") === 0) {
if (gt === "none") {
tile = tileArray[6];
} else if (ht === "none") {
tile = tileArray[7];
} else if (it === "none") {
tile = tileArray[8];
}
} else if (equallen([at, dt, gt], "X") === 2 && equallen([at, dt, gt], "O") === 0) {
if (at === "none") {
tile = tileArray[0];
} else if (dt === "none") {
tile = tileArray[3];
} else if (gt === "none") {
tile = tileArray[6];
}
} else if (equallen([bt, et, ht], "X") === 2 && equallen([bt, et, ht], "O") === 0) {
if (bt === "none") {
tile = tileArray[1];
} else if (et === "none") {
tile = tileArray[4];
} else if (ht === "none") {
tile = tileArray[7];
}
} else if (equallen([ct, ft, it], "X") === 2 && equallen([ct, ft, it], "O") === 0) {
if (ct === "none") {
tile = tileArray[2];
} else if (ft === "none") {
tile = tileArray[5];
} else if (it === "none") {
tile = tileArray[8];
}
} else if (equallen([at, et, it], "X") === 2 && equallen([at, et, it], "O") === 0) {
if (at === "none") {
tile = tileArray[0];
} else if (et === "none") {
tile = tileArray[4];
} else if (it === "none") {
tile = tileArray[8];
}
} else if (equallen([ct, et, gt], "X") === 2 && equallen([ct, et, gt], "O") === 0) {
if (ct === "none") {
tile = tileArray[2];
} else if (et === "none") {
tile = tileArray[4];
} else if (gt === "none") {
tile = tileArray[6];
}
}
}
 
//Other options in case the above are not fulfilled
//Controls the course of play over the game
if (tile === 0) {
switch (9 - available.length) {
case 1:
//If the center is taken, it plays randomly in the corner
//Otherwise, it takes the center
if (et === "X") {
tile = tileArray[choice([0, 2, 6, 8])];
} else {
tile = tileArray[4];
}
break;
 
case 3:
if (et === "X" && (equalanyof([at, ct, gt, it], "O"))) {
/*To counter the strategy of
O - -
- X -
X - -
 
O - -
- X -
- - X
and related strategies*/
if (at === "X") {
if (it === "none") {
tile = tileArray[8];
} else {
tile = tileArray[choice([2, 6])];
}
} else if (ct === "X") {
if (gt === "none") {
tile = tileArray[6];
} else {
tile = tileArray[choice([0, 8])];
}
} else if (gt === "X") {
if (ct === "none") {
tile = tileArray[2];
} else {
tile = tileArray[choice([0, 8])];
}
} else if (it === "X") {
if (at === "none") {
tile = tileArray[0];
} else {
tile = tileArray[choice([2, 6])];
}
}
} else {
tile = choice(tileArray);
}
break;
}
}
 
//Generates a random number if it could cause an error
if (tile.state != "none") {
tile = choice(available);
}
 
//Draws the selection
tile.state = game.opp;
tile.draw();
checkCondition();
game.turn = "Player";
}
}
 
//Click handler
document.onclick = event => {
let pos = getMousePos(event);
 
switch (game.state) {
case "start":
//Checks if the button was clicked
if (isBetween(pos.x, width / 3.2, width / (16 / 11)) && isBetween(pos.y, width / 2, width / 1.6)) {
game.state = "game"
 
//Draws the setup for the game
ctx.fillStyle = "rgb(225, 225, 225)";
ctx.fillRect(0, 0, 400, 400);
 
//Draws the lines
ctx.fillStyle = "rgb(200, 200, 200)";
ctx.fillRect(blockSize - lineSize / 2, 0, lineSize, width);
ctx.fillRect(blockSize * 2 - lineSize / 2, 0, lineSize, width);
ctx.fillRect(0, blockSize - lineSize / 2, width, lineSize);
ctx.fillRect(0, blockSize * 2 - lineSize / 2, width, lineSize);
}
break;
 
case "game":
if (game.turn === "Player") {
//Goes through the tile array, checking if the click occurred there
tileArray.forEach(tile => {
if (isBetween(pos.x, tile.x, tile.x + blockSize) && isBetween(pos.y, tile.y, tile.y + blockSize)) {
if (available.indexOf(tile) != -1) {
tile.state = game.player;
tile.draw();
checkCondition();
game.turn = "Opponent";
oppTurn();
}
}
});
}
break;
}
 
}
</script>
</body>
 
</html>
</syntaxhighlight>
 
 
A Node.js implementation using strategy heuristics as defined in the Wikipedia page linked above.
Some of the steps can be embargoed until the board only has n plays left. This makes for a bit of
randomness in the gameplay.
Human is X and goes first.
 
<syntaxhighlight lang="javascript">
// Board
const topLeft = 1;
const topMid = 2;
const topRight = 3;
const midLeft = 4;
const center = 5;
const midRight = 6;
const botLeft = 7;
const botMid = 8;
const botRight = 9;
const tiles = [
topLeft, topMid, topRight,
midLeft, center, midRight,
botLeft, botMid, botRight
];
const corners = [
topLeft, topRight,
botLeft, botRight
];
const sides = [
topMid,
midLeft, midRight,
botMid
];
const winningCombos = [
[topLeft, topMid, topRight],
[midLeft, center, midRight],
[botLeft, botMid, botRight],
[topLeft, midLeft, botLeft],
[topMid, center, botMid],
[topRight, midRight, botRight],
[topLeft, center, botRight],
[topRight, center, botLeft],
];
const board = new Map();
 
// Utility
const reset = () => tiles.forEach(e => board.set(e, ' '));
const repeat = (s, n) => Array(n).fill(s).join('');
const fromBoard = e => board.get(e);
const notSpace = e => e !== ' ';
const occupied = e => notSpace(fromBoard(e));
const isAvailable = e => !occupied(e);
const notString = s => e => fromBoard(e) !== s;
const containsOnly = s => a => a.filter(occupied).map(fromBoard).join('') === s;
const chooseRandom = a => a[Math.floor(Math.random() * a.length)];
const legalPlays = () => tiles.filter(isAvailable);
const legalCorners = () => corners.filter(isAvailable);
const legalSides = () => sides.filter(isAvailable);
const opponent = s => s === 'X' ? 'O' : 'X';
const hasElements = a => a.length > 0;
const compose = (...fns) => (...x) => fns.reduce((a, b) => c => a(b(c)))(...x);
const isDef = t => t !== undefined;
const flatten = a => a.reduce((p, c) => [...p, ...c], []);
 
const findShared = a => [...flatten(a).reduce((p, c) =>
p.has(c) ? p.set(c, [...p.get(c), c]) : p.set(c, [c]),
new Map()).values()].filter(e => e.length > 1).map(e => e[0]);
 
const wrap = (f, s, p = 9) => n => {
if (isDef(n) || legalPlays().length > p) {
return n;
}
const r = f(n);
if (isDef(r)) {
console.log(`${s}: ${r}`);
}
return r;
};
 
const drawBoard = () => console.log(`
${[fromBoard(topLeft), fromBoard(topMid), fromBoard(topRight)].join('|')}
-+-+-
${[fromBoard(midLeft), fromBoard(center), fromBoard(midRight)].join('|')}
-+-+-
${[fromBoard(botLeft), fromBoard(botMid), fromBoard(botRight)].join('|')}
`);
 
const win = s => () => {
if (winningCombos.find(containsOnly(repeat(s, 3)))) {
console.log(`${s} wins!`);
reset()
} else if (hasElements(legalPlays())) {
console.log(`${opponent(s)}s turn:`);
} else {
console.log('Draw!');
reset();
}
};
 
const play = s => n => occupied(n) ? console.log('Illegal') : board.set(n, s);
 
 
// Available strategy steps
const attack = (s, t = 2) => () => {
const m = winningCombos.filter(containsOnly(repeat(s, t)));
if (hasElements(m)) {
return chooseRandom(chooseRandom(m).filter(notString(s)))
}
};
 
const fork = (s, isDefence = false) => () => {
let result;
const p = winningCombos.filter(containsOnly(s));
const forks = findShared(p).filter(isAvailable);
 
// On defence, when there is only one fork, play it, else choose a
// two-in-a row attack to force the opponent to not execute the fork.
if (forks.length > 1 && isDefence) {
const me = opponent(s);
const twoInRowCombos = winningCombos.filter(containsOnly(repeat(me, 1)));
const chooseFrom = twoInRowCombos.reduce((p, a) => {
const avail = a.filter(isAvailable);
avail.forEach((e, i) => {
board.set(e, me).set(i ? avail[i - 1] : avail[i + 1], opponent(me));
winningCombos.filter(containsOnly(repeat(s, 2))).length < 2
? p.push(e)
: undefined;
});
avail.forEach(e => board.set(e, ' '));
return p;
}, []);
result = hasElements(chooseFrom)
? chooseRandom(chooseFrom)
: attack(opponent(s), 1)()
}
return result || chooseRandom(forks);
};
 
const defend = (s, t = 2) => attack(opponent(s), t);
 
const defendFork = s => fork(opponent(s), true);
 
const chooseCenter = () => isAvailable(center) ? center : undefined;
 
const chooseCorner = () => chooseRandom(legalCorners());
 
const chooseSide = () => chooseRandom(legalSides());
 
const randLegal = () => chooseRandom(legalPlays());
 
// Implemented strategy
const playToWin = s => compose(
win(s),
drawBoard,
play(s),
wrap(randLegal, 'Chose random'),
wrap(chooseSide, 'Chose random side', 8),
wrap(chooseCorner, 'Chose random corner', 8),
wrap(chooseCenter, 'Chose center', 7),
wrap(defendFork(s), 'Defended fork'),
wrap(fork(s), 'Forked'),
wrap(defend(s), 'Defended'),
wrap(attack(s), 'Attacked')
);
 
// Prep players
const O = n => playToWin('O')(n);
const X = n => playToWin('X')(n);
 
// Begin
reset();
console.log("Let's begin...");
drawBoard();
console.log('X Begins: Enter a number from 1 - 9');
 
// Manage user input.
const standard_input = process.stdin;
const overLog = s => {
process.stdout.moveCursor(0, -9);
process.stdout.cursorTo(0);
process.stdout.clearScreenDown();
process.stdout.write(s);
};
standard_input.setEncoding('utf-8');
standard_input.on('data', (data) => {
if (data === '\n') {
overLog('O: ');
O();
} else {
overLog(`X: Plays ${data}`);
X(Number(data));
}
});
</syntaxhighlight>
 
{{out}}
<pre>
 
Let's begin...
X: Plays 1
O: Chose random corner: 7
X: Plays 5
O: Defended: 9
X: Plays 8
O: Defended: 2
X: Plays 3
O: Chose random side: 6
X: Plays 4
 
X|O|X
-+-+-
X|X|O
-+-+-
O|X|O
Draw!
 
</pre>
 
=={{header|Julia}}==
One move look-ahead algorithm. Computer plays to win or at least draw.
<syntaxhighlight lang="julia">const winningpositions = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 4, 7],
[2, 5, 8], [3, 6, 9],[1, 5, 9], [7, 5, 3]]
 
function haswon(brd, xoro)
marked = findall(x -> x == xoro, brd)
for pos in winningpositions
if length(pos) <= length(marked) && pos == sort(marked)[1:3]
return true
end
end
false
end
 
function readcharwithprompt(prompt, expected)
ret = '*'
while !(ret in expected)
print("\n", prompt, " -> ")
ret = lowercase(chomp(readline()))[1]
end
ret
end
 
availablemoves(brd) = findall(x -> x == ' ', brd)
cornersopen(brd) = [x for x in [1, 3, 7, 9] if brd[x] == ' ']
int2char(x) = Char(x + UInt8('0'))
char2int(x) = UInt8(x) - UInt8('0')
getyn(query) = readcharwithprompt(query, ['y', 'n'])
gettheirmove(brd) = char2int(readcharwithprompt("Your move(1-9)", int2char.(availablemoves(brd))))
 
function findwin(brd, xoro)
tmpbrd = deepcopy(brd)
for mv in availablemoves(tmpbrd)
tmpbrd[mv] = xoro
if haswon(tmpbrd, xoro)
return mv
end
tmpbrd[mv] = ' '
end
return nothing
end
 
function choosemove(brd, mychar, theirchar)
if all(x -> x == ' ', brd)
brd[rand(cornersopen(brd))] = mychar # corner trap if starting game
elseif availablemoves(brd) == [] # no more moves
println("Game is over. It was a draw.")
exit(0)
elseif (x = findwin(brd, mychar)) != nothing || (x = findwin(brd, theirchar)) != nothing
brd[x] = mychar # win if possible, block their win otherwise if their win is possible
elseif brd[5] == ' '
brd[5] = mychar # take center if open and not doing corner trap
elseif (corners = cornersopen(brd)) != []
brd[rand(corners)] = mychar # choose a corner over a side middle move
else
brd[rand(availablemoves(brd))] = mychar # random otherwise
end
end
 
function display(brd)
println("+-----------+")
println("| ", brd[1], " | ", brd[2], " | ", brd[3], " |")
println("| ", brd[4], " | ", brd[5], " | ", brd[6], " |")
println("| ", brd[7], " | ", brd[8], " | ", brd[9], " |")
println("+-----------+")
end
 
function tictactoe()
board = fill(' ', 9)
println("Board move grid:\n 1 2 3\n 4 5 6\n 7 8 9")
yn = getyn("Would you like to move first (y/n)?")
if yn == 'y'
mychar = 'O'
theirchar = 'X'
board[gettheirmove(board)] = theirchar
else
mychar = 'X'
theirchar = 'O'
end
while true
choosemove(board, mychar, theirchar)
println("Computer has moved.")
display(board)
if haswon(board, mychar)
println("Game over. Computer wins!")
exit(0)
elseif availablemoves(board) == []
break
end
board[gettheirmove(board)] = theirchar
println("Player has moved.")
display(board)
if haswon(board, theirchar)
println("Game over. Player wins!")
exit(0)
elseif availablemoves(board) == []
break
end
end
println("Game over. It was a draw.")
end
 
tictactoe()
</syntaxhighlight> {{output}} <pre>
Board move grid:
1 2 3
4 5 6
7 8 9
Would you like to move first (y/n)? -> y
Your move(1-9) -> 5
Computer has moved.
+-----------+
| | | |
| | X | |
| O | | |
+-----------+
Your move(1-9) -> 1
Player has moved.
+-----------+
| X | | |
| | X | |
| O | | |
+-----------+
Computer has moved.
+-----------+
| X | | |
| | X | |
| O | | O |
+-----------+
Your move(1-9) -> 3
Player has moved.
+-----------+
| X | | X |
| | X | |
| O | | O |
+-----------+
Computer has moved.
+-----------+
| X | | X |
| | X | |
| O | O | O |
+-----------+
Game over. Computer wins!
</pre>
 
=={{header|Koka}}==
Effectful Version
<syntaxhighlight lang="koka">
import std/os/readline
 
fun member(x: a, xs: list<a>, compare: (a, a) -> bool) : bool
match xs
Nil -> False
Cons(y, ys) -> x.compare(y) || member(x, ys,compare)
 
fun member(xs: list<a>, x: a, compare: (a, a) -> bool) : bool
x.member(xs, compare)
 
 
struct coord
x: int
y: int
 
fun show(c: coord) : string {
"(" ++ c.x.show() ++ ", " ++ c.y.show() ++ ")"
}
 
 
fun (==)(c1: coord, c2: coord) : bool
c1.x == c2.x && c1.y == c2.y
 
 
effect ctl eject(): a
 
 
fun parse(str : string, moves : list<coord>) : <console, exn|_e>coord
match str.list()
Cons('0', Cons(' ', Cons('0', Nil))) -> Coord(0,0)
Cons('0', Cons(' ', Cons('1', Nil))) -> Coord(0,1)
Cons('0', Cons(' ', Cons('2', Nil))) -> Coord(0,2)
Cons('1', Cons(' ', Cons('0', Nil))) -> Coord(1,0)
Cons('1', Cons(' ', Cons('1', Nil))) -> Coord(1,1)
Cons('1', Cons(' ', Cons('2', Nil))) -> Coord(1,2)
Cons('2', Cons(' ', Cons('0', Nil))) -> Coord(2,0)
Cons('2', Cons(' ', Cons('1', Nil))) -> Coord(2,1)
Cons('2', Cons(' ', Cons('2', Nil))) -> Coord(2,2)
Cons('0', Cons(',', Cons('0', Nil))) -> Coord(0,0)
Cons('0', Cons(',', Cons('1', Nil))) -> Coord(0,1)
Cons('0', Cons(',', Cons('2', Nil))) -> Coord(0,2)
Cons('1', Cons(',', Cons('0', Nil))) -> Coord(1,0)
Cons('1', Cons(',', Cons('1', Nil))) -> Coord(1,1)
Cons('1', Cons(',', Cons('2', Nil))) -> Coord(1,2)
Cons('2', Cons(',', Cons('0', Nil))) -> Coord(2,0)
Cons('2', Cons(',', Cons('1', Nil))) -> Coord(2,1)
Cons('2', Cons(',', Cons('2', Nil))) -> Coord(2,2)
Cons('q', Nil) -> eject()
_ ->
println("Invalid move, please try again")
gen_move(moves)
 
fun gen_move(moves : list<coord>) : <console, exn|_e> coord
val move : coord = parse(readline(), moves)
 
if moves.any() fn (c : coord) { c == move } then {
println("Invalid move, please try again")
gen_move(moves)
} else {
move
}
 
fun create-board() : list<list<char>> {
[['.','.','.'],['.','.','.'],['.','.','.']]
}
 
fun show(grid: list<list<char>>) : string
var line := 0
grid.foldl(" 0 1 2\n") fn(acc, row: list<char>)
val out = row.foldl(acc ++ line.show() ++ " ") fn(acc, col: char)
acc ++ col.string() ++ " "
++ "\n"
line := line + 1
out
 
fun get_board_position(board : list<list<char>>, coord : coord) : maybe<char> {
match board[coord.y] {
Nothing -> Nothing
Just(row) -> row[coord.x]
}
}
fun mark_board(board: list<list<char>>,coord: coord, mark: char): maybe<list<list<char>>>
val new_row: maybe<list<char>> = match board[coord.y]
Nothing -> Nothing
Just(row) -> Just(row.take(coord.x) ++ mark.Cons(row.drop(coord.x + 1)))
match new_row
Nothing -> Nothing
Just(row) -> Just(board.take(coord.y) ++ row.Cons(board.drop(coord.y + 1)))
 
 
effect ctl not_full() : ()
 
fun check_full(board: list<list<char>>) : bool
fun helper()
var full := True
board.foreach() fn(row)
if '.'.member(row) fn (a, b) a == b then {
not_full()
}
full
with ctl not_full() False
helper()
 
fun check_win(board: list<list<char>>, mark: char) : <div, exn|_e>bool
var win := False
var i := 0
while {i < 3} {
if board.get_board_position(Coord(i,0)).unwrap() == mark && board.get_board_position(Coord(i,1)).unwrap() == mark && board.get_board_position(Coord(i,2)).unwrap() == mark then {
win := True
}
if board.get_board_position(Coord(0,i)).unwrap() == mark && board.get_board_position(Coord(1,i)).unwrap() == mark && board.get_board_position(Coord(2,i)).unwrap() == mark then {
win := True
}
i := i + 1
}
if board.get_board_position(Coord(0,0)).unwrap() == mark && board.get_board_position(Coord(1,1)).unwrap() == mark && board.get_board_position(Coord(2,2)).unwrap() == mark then {
win := True
}
if board.get_board_position(Coord(0,2)).unwrap() == mark && board.get_board_position(Coord(1,1)).unwrap() == mark && board.get_board_position(Coord(2,0)).unwrap() == mark then {
win := True
}
win
 
 
 
fun human_logic(board: list<list<char>>, moves: list<coord>, mark: char, other_mark: char) : <console,div,exn|_e> coord
gen_move(moves)
 
fun ai_logic(board: list<list<char>>, moves: list<coord>, mark: char, other_mark: char)
board.gen_ai_move(moves,mark, other_mark)
 
 
struct move
move : coord
score: int
 
fun (==)(m1 : move, m2 : move) : bool {
m1.move == m2.move && m1.score == m2.score
}
 
fun eval_board(board : list<list<char>>, mark: char, other-mark : char) {
if board.check_win(mark) then {
10
}
elif board.check_win(other-mark) then {
-10
}
else {
0
}
}
 
fun maximum-move(a : move, b : move) : move {
if a.score > b.score then {
a
}
else {
b
}
}
 
 
fun gen_ai_move(board : list<list<char>>, moves : list<coord>, mark : char, other-mark : char) {
val best_move : move = Move(Coord(-1,-1), -1000)
[0,1,2].foldl(best_move) fn (bstMove : move, i : int) {
[0,1,2].foldl(bstMove) fn (bstMve : move, j : int) {
if Coord(i,j).member(moves) fn (a,b) {a == b} then {
bstMve
}
else {
val new_board : list<list<char>> = board.mark_board(Coord(i,j), mark).unwrap()
val new-max = maximum-move(bstMve, Move(Coord(i,j), new_board.minimax(moves ++ [Coord(i,j)], 0, False, mark, other-mark)))
new-max
}
}
}.move
}
 
fun unwrap(x: maybe<a>): <exn> a
match x
Just(a) -> a
Nothing -> throw("value was Nothing")
 
// A basic implementation of Minimax
// This uses brace style to show that it is possible
fun minimax(board : list<list<char>>, moves: list<coord>, depth : int, isMaximizingPlayer : bool, mark : char, other-mark : char) : <div,exn|_e> int {
val score : int = board.eval_board(mark, other-mark)
if score == 10 then {
score
}
elif score == -10 then {
score
}
elif board.check_full() then {
0
}
else {
if isMaximizingPlayer then {
val bestVal: int = -1000
[0,1,2].foldl(bestVal) fn (bstVal : int, i : int) {
[0,1,2].foldl(bstVal) fn (bstVl : int, j : int) {
if Coord(i,j).member(moves) fn(a, b) {a == b} then {
bstVl
}
else {
val new_board : list<list<char>> = board.mark_board(Coord(i,j), mark).unwrap()
val value : int = new_board.minimax(moves ++ [Coord(i,j)], depth + 1, !isMaximizingPlayer, mark, other-mark)
max(bstVl, value)
}
}
}
}
else {
val bestVal: int = 1000
[0,1,2].foldl(bestVal) fn (bstVal : int, i : int) {
[0,1,2].foldl(bstVal) fn (bstVl : int, j : int) {
if Coord(i,j).member(moves) fn(a,b) {a == b} then {
bstVl
}
else {
val new_board : list<list<char>> = board.mark_board(Coord(i,j), other-mark).unwrap()
val value : int = new_board.minimax(moves ++ [Coord(i,j)], depth + 1, !isMaximizingPlayer, mark, other-mark)
min(bstVl, value)
}
}
}
}
}
}
 
// The main business logic of the entire game
// This function checks if there is a draw or a win
fun play_game()
val board = get_board()
if board.check_full() then
println("Draw!")
println("Final board:")
board.show().println
else
"Next Turn:".println
board.show().println
val current_mark = get_current_mark()
val other_mark = get_other_mark()
play_turn(current_mark, other_mark)
val new_board = get_board()
if new_board.check_win(current_mark) then
println("Player " ++ current_mark.show() ++ " wins!")
println("Final board:")
new_board.show().println
else
flip()
play_game()
 
 
effect human_turn
fun play_human_turn(pair: (list<list<char>>, list<coord>), marks: (char, char)) : coord
effect ai_turn
fun play_ai_turn(pair: (list<list<char>>, list<coord>), marks: (char, char)) : coord
 
effect player1
fun player1_turn(pair: (list<list<char>>, list<coord>), marks: (char, char)) : coord
fun get_player1_mark() : char
effect player2
fun player2_turn(pair: (list<list<char>>, list<coord>), marks: (char, char)) : coord
fun get_player2_mark() : char
 
 
effect turn
// Changes the current player to a different one
fun flip() : ()
// Calls the appropriate code for the current player
fun play_turn(mark: char, other_mark: char) : ()
// Gets the symbol of the active player
fun get_current_mark(): char
// Gets the symbol of the inactive player
fun get_other_mark(): char
// This allows us to access the board
fun get_board() : list<list<char>>
// This allows us to access the moves that have been made
fun get_moves(): list<coord>
 
 
 
type player
Human
AI
 
type players
One
Two
 
// This function encapsulates the state of the entire game
// Think of it as calling a method on an object but with pure functions
fun initialize_and_start_game(game_type: int)
var current_player := One
var current_board := create-board()
var all_moves := []
 
var player1 := Human
var player2 := AI
 
match game_type
1 -> {
player1 := Human
player2 := Human
}
2 -> {
player1 := Human
player2 := AI
}
3 -> {
player1 := AI
player2 := AI
}
_ -> throw("invalid game type")
 
with handler
ctl eject()
println("Have a nice day.")
with fun play_human_turn(pair: (list<list<char>>, list<coord>), marks: (char, char))
human_logic(pair.fst,pair.snd,marks.fst,marks.snd)
with fun play_ai_turn(pair: (list<list<char>>, list<coord>), marks: (char, char))
ai_logic(pair.fst,pair.snd,marks.fst,marks.snd)
with handler
fun player1_turn(pair: (list<list<char>>, list<coord>), marks: (char, char))
match player1
Human -> play_human_turn(pair, marks)
AI -> play_ai_turn(pair, marks)
fun get_player1_mark()
'X'
with handler
fun player2_turn(pair: (list<list<char>>, list<coord>), marks: (char, char))
match player2
Human -> play_human_turn(pair, marks)
AI -> play_ai_turn(pair, marks)
fun get_player2_mark()
'O'
with handler
return(x) ()
fun flip()
match current_player
One -> current_player := Two
Two -> current_player := One
fun play_turn(mark: char, other_mark: char)
match current_player
One -> {
val coord = player1_turn((current_board, all_moves), (mark, other_mark))
current_board := mark_board(current_board,coord,get_player1_mark()).unwrap
all_moves := Cons(coord, all_moves)
()
}
Two -> {
val coord = player2_turn((current_board, all_moves), (mark, other_mark))
 
current_board := mark_board(current_board,coord,get_player2_mark()).unwrap
all_moves := Cons(coord, all_moves)
()
}
fun get_current_mark() match current_player
One -> get_player1_mark()
Two -> get_player2_mark()
fun get_other_mark() match current_player
Two -> get_player1_mark()
One -> get_player2_mark()
fun get_board() current_board
fun get_moves() all_moves
play_game()
 
 
fun prompt_game_type()
match readline().list()
Cons('1', Nil) -> 1
Cons('2', Nil) -> 2
Cons('3', Nil) -> 3
_ ->
println("Invalid game mode, please try again")
prompt_game_type()
 
 
fun main ()
println("Welcome to Tic Tac Toe!")
println("Please select a game mode:")
println("1. Two player")
println("2. One player")
println("3. Zero player")
println("Enter the number of the game mode you want to play")
 
val game_type = prompt_game_type()
 
"Enter your input as 'x y' or 'x,y' when selecting a spot".println
 
initialize_and_start_game(game_type)
</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|C}}
<syntaxhighlight lang="scala">// version 1.1.51
 
import java.util.Random
 
val r = Random()
val b = Array(3) { IntArray(3) } // board -> 0: blank; -1: computer; 1: human
 
var bestI = 0
var bestJ = 0
 
fun checkWinner(): Int {
for (i in 0..2) {
if (b[i][0] != 0 && b[i][1] == b[i][0] && b[i][2] == b[i][0]) return b[i][0]
if (b[0][i] != 0 && b[1][i] == b[0][i] && b[2][i] == b[0][i]) return b[0][i]
}
if (b[1][1] == 0) return 0
if (b[1][1] == b[0][0] && b[2][2] == b[0][0]) return b[0][0]
if (b[1][1] == b[2][0] && b[0][2] == b[1][1]) return b[1][1]
return 0
}
 
fun showBoard() {
val t = "X O"
for (i in 0..2) {
for (j in 0..2) print("${t[b[i][j] + 1]} ")
println()
}
println("-----")
}
 
fun testMove(value: Int, depth: Int): Int {
var best = -1
var changed = 0
var score = checkWinner()
if (score != 0) return if (score == value) 1 else -1
for (i in 0..2) {
for (j in 0..2) {
if (b[i][j] != 0) continue
b[i][j] = value
changed = value
score = -testMove(-value, depth + 1)
b[i][j] = 0
if (score <= best) continue
if (depth == 0) {
bestI = i
bestJ = j
}
best = score
}
}
return if (changed != 0) best else 0
}
 
fun game(user: Boolean): String {
var u = user
for (i in 0..2) b[i].fill(0)
print("Board postions are numbered so:\n1 2 3\n4 5 6\n7 8 9\n")
print("You have O, I have X.\n\n")
 
for (k in 0..8) {
while (u) {
var move: Int?
do {
print("Your move: ")
move = readLine()!!.toIntOrNull()
}
while (move != null && move !in 1..9)
move = move!! - 1
val i = move / 3
val j = move % 3
if (b[i][j] != 0) continue
b[i][j] = 1
break
}
if (!u) {
if (k == 0) { // randomize if computer opens, less boring
bestI = r.nextInt(Int.MAX_VALUE) % 3
bestJ = r.nextInt(Int.MAX_VALUE) % 3
}
else testMove(-1, 0)
b[bestI][bestJ] = -1
val myMove = bestI * 3 + bestJ + 1
println("My move: $myMove")
}
showBoard()
val win = checkWinner()
if (win != 0) return (if (win == 1) "You win" else "I win") + ".\n\n"
u = !u
}
return "A draw.\n\n"
}
 
fun main(args: Array<String>) {
var user = false
while (true) {
user = !user
print(game(user))
var yn: String
do {
print("Play again y/n: ")
yn = readLine()!!.toLowerCase()
}
while (yn != "y" && yn != "n")
if (yn != "y") return
println()
}
}</syntaxhighlight>
 
Sample game:
<pre>
Board postions are numbered so:
1 2 3
4 5 6
7 8 9
You have O, I have X.
 
Your move: 2
O
-----
My move: 1
X O
-----
Your move: 8
X O
O
-----
My move: 5
X O
X
O
-----
Your move: 9
X O
X
O O
-----
My move: 7
X O
X
X O O
-----
Your move: 3
X O O
X
X O O
-----
My move: 4
X O O
X X
X O O
-----
I win.
 
Play again y/n: n
</pre>
 
=={{header|Lasso}}==
Line 3,471 ⟶ 9,473:
 
As image uploads has been disabled, a live version can be viewed at: [http://jono.guthrie.net.nz/rosetta/Tic-tac-toe.lasso http://jono.guthrie.net.nz/rosetta/Tic-tac-toe.lasso]
<syntaxhighlight lang="lasso">[
<lang Lasso>[
session_start('user')
session_addvar('user', 'matrix')
Line 3,565 ⟶ 9,567:
$matrix = array('-','-','-','-','-','-','-','-','-')
$turn = 'x'
}]</langsyntaxhighlight>
 
=={{header|MathematicaLingo}}==
The standard way to create GUI apps in Lingo is to use the authoring tool "Director" as GUI builder. The code below instead uses a simple framework (stored in global "$") that eases programmatic GUI creation.<br />
<lang>DynamicModule[{board = ConstantArray[0, {3, 3}], text = "Playing...",
Screenshot of application window: http://valentin.dasdeck.com/lingo/tic-tac-toe/tic-tac-toe-lingo.png<br />
"Human" cannot win this game.
<syntaxhighlight lang="lingo">global $ -- object representing simple framework
global gBoard -- current board image
global gBoardTemplate -- empty board image
global gHumanChip -- cross image
global gComputerChip -- circle image
global gM -- 3x3 matrix storing game state: 0=free cell, 1=human cell, -1=computer cell
global gStep -- index of current move (1..9)
global gGameOverFlag -- TRUE if current game is over
 
----------------------------------------
-- Entry point
----------------------------------------
on startMovie
 
-- libs
$.import("sprite")
 
-- window properties
_movie.stage.title = "Tic-Tac-Toe"
_movie.stage.rect = rect(0, 0, 224, 310)
_movie.centerStage = TRUE
 
-- load images from filesystem
m = new(#bitmap)
m.importFileInto($.@("resources/cross.bmp"), [#trimWhiteSpace:FALSE])
gHumanChip = m.image
 
m = new(#bitmap)
m.importFileInto($.@("resources/circle.bmp"), [#trimWhiteSpace:FALSE])
gComputerChip = m.image
 
-- create GUI
m = new(#bitmap)
m.importFileInto($.@("resources/board.bmp"))
m.regpoint = point(0, 0)
s = $.sprite.make(m, [#loc:point(20, 20)], TRUE)
s.addListener(#mouseDown, _movie, #humanMove)
 
gBoard = m.image
gBoardTemplate = gBoard.duplicate()
 
m = $.sprite.newMember(#button, [#text:"New Game (Human starts)", #fontstyle:"bold", #rect:rect(0, 0, 180, 0)])
s = $.sprite.make(m, [#loc:point(20, 220)], TRUE)
s.addListener(#mouseDown, _movie, #newGame, 1)
 
m = $.sprite.newMember(#button, [#text:"New Game (Computer starts)", #fontstyle:"bold", #rect:rect(0, 0, 180, 0)])
s = $.sprite.make(m, [#loc:point(20, 250)], TRUE)
s.addListener(#mouseDown, _movie, #newGame, -1)
 
m = $.sprite.newMember(#field, [#name:"feedback", #editable:FALSE, #fontstyle:"bold", #alignment:"center",\
#border:0, #color:rgb(255, 0, 0), #rect:rect(0, 0, 180, 0)])
s = $.sprite.make(m, [#loc:point(20, 280)], TRUE)
 
newGame(1)
 
-- show the application window
_movie.updateStage()
_movie.stage.visible = TRUE
end
 
----------------------------------------
-- Starts a new game
----------------------------------------
on newGame (whoStarts)
-- reset board
gBoard.copyPixels(gBoardTemplate, gBoardTemplate.rect, gBoardTemplate.rect)
-- clear feedback
member("feedback").text = ""
-- reset states
gM = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
gStep = 0
gGameOverFlag = FALSE
if whoStarts=-1 then computerMove()
end
 
----------------------------------------
-- Handles a human move (mouse click)
----------------------------------------
on humanMove ()
if gGameOverFlag then return
-- find cell for mouse position
p = _mouse.clickLoc - sprite(1).loc
if p.locH mod 60<4 or p.locV mod 60<4 then return
p = p / 60
x = p[1] + 1
y = p[2] + 1
if gM[x][y] then return -- ignore illegal moves
gM[x][y] = 1
-- update cell image
p = p * 60
gBoard.copyPixels(gHumanChip, gHumanChip.rect.offset(4+p[1], 4+p[2]), gHumanChip.rect)
-- proceed (unless game over)
gStep = gStep + 1
if not checkHumanMove(x, y) then computerMove()
end
 
----------------------------------------
-- Checks if human has won or game ended with draw
----------------------------------------
on checkHumanMove (x, y)
if sum([gM[x][1], gM[x][2], gM[x][3]])=3 then return gameOver(1, [[x, 1], [x, 2], [x, 3]])
if sum([gM[1][y], gM[2][y], gM[3][y]])=3 then return gameOver(1, [[1, y], [2, y], [3, y]])
if x=y and sum([gM[1][1], gM[2][2], gM[3][3]])=3 then return gameOver(1, [[1, 1], [2, 2], [3, 3]])
if x+y=4 and sum([gM[1][3], gM[2][2], gM[3][1]])=3 then return gameOver(1, [[1, 3], [2, 2], [3, 1]])
if gStep=9 then return gameOver(0)
return FALSE
end
 
----------------------------------------
-- Checks if selecting specified empty cell makes computer or human win
----------------------------------------
on checkCellWins (x, y, who)
wins = who*2
if sum([gM[1][y], gM[2][y], gM[3][y]]) = wins then return [[1, y], [2, y], [3, y]]
if sum([gM[x][1], gM[x][2], gM[x][3]]) = wins then return [[x, 1], [x, 2], [x, 3]]
if x=y and sum([gM[1][1], gM[2][2], gM[3][3]]) = wins then return [[1, 1], [2, 2], [3, 3]]
if x+y=4 and sum([gM[1][3], gM[2][2], gM[3][1]]) = wins then return [[1, 3], [2, 2], [3, 1]]
return FALSE
end
 
----------------------------------------
-- Handles game over
----------------------------------------
on gameOver (winner, cells)
gGameOverFlag = TRUE
if winner = 0 then
member("feedback").text = "It's a draw!"
else
-- hilite winning line with yellow
img = image(56, 56, 32)
img.fill(img.rect, rgb(255, 255, 0))
repeat with c in cells
x = (c[1]-1)*60 + 4
y = (c[2]-1)*60 + 4
gBoard.copyPixels(img, img.rect.offset(x, y), img.rect, [#ink:#darkest])
end repeat
member("feedback").text = ["Human", "Computer"][1+(winner=-1)] & " has won!"
end if
return TRUE
end
 
----------------------------------------
-- Calculates next computer move
----------------------------------------
on computerMove ()
gStep = gStep + 1
 
-- move 1: select center
if gStep=1 then return doComputerMove(2, 2)
 
-- move 2 (human started)
if gStep=2 then
if gM[2][2]=1 then
-- if center, select arbitrary corner
return doComputerMove(1, 1)
else
-- otherwise select center
return doComputerMove(2, 2)
end if
end if
 
-- move 3 (computer started)
if gStep=3 then
-- if corner, select diagonally opposite corner
if gM[1][1]=1 then return doComputerMove(3, 3)
if gM[3][3]=1 then return doComputerMove(1, 1)
if gM[1][3]=1 then return doComputerMove(3, 1)
return doComputerMove(1, 1) -- top left corner as default
end if
 
-- get free cells
free = []
repeat with x = 1 to 3
repeat with y = 1 to 3
if gM[x][y]=0 then free.add([x, y])
end repeat
end repeat
 
-- check if computer can win now
repeat with c in free
res = checkCellWins(c[1], c[2], -1)
if res<>FALSE then
doComputerMove(c[1], c[2])
return gameOver(-1, res)
end if
end repeat
 
-- check if human could win with next move (if yes, prevent it)
repeat with c in free
res = checkCellWins(c[1], c[2], 1)
if res<>FALSE then return doComputerMove(c[1], c[2], TRUE)
end repeat
 
-- move 4 (human started): prevent "double mills"
if gStep=4 then
if gM[2][2]=1 and (gM[1][1]=1 or gM[3][3]=1) then return doComputerMove(3, 1)
if gM[2][2]=1 and (gM[1][3]=1 or gM[3][1]=1) then return doComputerMove(1, 1)
if gM[2][3]+gM[3][2]=2 then return doComputerMove(3, 3)
if gM[1][2]+gM[2][3]=2 then return doComputerMove(1, 3)
if gM[1][2]+gM[2][1]=2 then return doComputerMove(1, 1)
if gM[2][1]+gM[3][2]=2 then return doComputerMove(3, 1)
if (gM[1][3]+gM[3][1]=2) or (gM[1][1]+gM[3][3]=2) then return doComputerMove(2, 1)
end if
 
-- move 5 (computer started): try to create a "double mill"
if gStep=5 then
repeat with x = 1 to 3
col = [gM[x][1], gM[x][2], gM[x][3]]
if not (sum(col)=-1 and max(col)=0) then next repeat
repeat with y = 1 to 3
row = [gM[1][y], gM[2][y], gM[3][y]]
if not (sum(row)=-1 and max(row)=0 and gM[x][y]=0) then next repeat
return doComputerMove(x, y)
end repeat
end repeat
end if
 
-- otherwise use first free cell
c = free[1]
doComputerMove(c[1], c[2])
end
 
----------------------------------------
-- Updates state matrix and cell image
----------------------------------------
on doComputerMove (x, y, checkDraw)
gM[x][y] = -1
gBoard.copyPixels(gComputerChip, gComputerChip.rect.offset(4+(x-1)*60, 4+(y-1)*60), gComputerChip.rect)
if checkDraw and gStep=9 then gameOver(0)
end
 
----------------------------------------
--
----------------------------------------
on sum (aLine)
return aLine[1]+aLine[2]+aLine[3]
end</syntaxhighlight>
 
=={{header|Lua}}==
Version for LuaJIT with or without ffi, negamax algorithm with alpha-beta pruning and caching of results. Human can't win.
<syntaxhighlight lang="lua">#!/usr/bin/env luajit
ffi=require"ffi"
local function printf(fmt,...) io.write(string.format(fmt, ...)) end
local board="123456789" -- board
local pval={1, -1} -- player 1=1 2=-1 for negamax
local pnum={} for k,v in ipairs(pval) do pnum[v]=k end
local symbol={'X','O'} -- default symbols X and O
local isymbol={} for k,v in pairs(symbol) do isymbol[v]=pval[k] end
math.randomseed(os.time()^5*os.clock()) -- time-seed the random gen
local random=math.random
-- usage of ffi variables give 20% speed
ffi.cdef[[
typedef struct{
char value;
char flag;
int depth;
}cData;
]]
-- draw the "board" in the way the numpad is organized
local function draw(board)
for i=7,1,-3 do
print(board:sub(i,i+2))
end
end
-- pattern for win situations
local check={"(.)...%1...%1","..(.).%1.%1..",
"(.)%1%1......","...(.)%1%1...","......(.)%1%1",
"(.)..%1..%1..",".(.)..%1..%1.","..(.)..%1..%1",
}
-- calculate a win situation for which player or draw
local function win(b)
local sub
for i=1,#check do
sub=b:match(check[i])
if sub then break end
end
sub=isymbol[sub]
return sub or 0
end
-- input only validate moves of not yet filled positions
local function input(b,player)
char=symbol[pnum[player]]
local inp
repeat
printf("Player %d (\"%s\") move: ",pnum[player],char)
inp=tonumber(io.read()) or 0
until inp>=1 and inp<=9 and b:find(inp)
b=b:gsub(inp,char)
return b,inp
end
-- ask how many human or AI players
local function playerselect()
local ai={}
local yn
for i=1,2 do
repeat
printf("Player %d human (Y/n)? ", i) yn=io.read():lower()
until yn:match("[yn]") or yn==''
if yn=='n' then
ai[pval[i]]=true
printf("Player %d is AI\n", i)
else
printf("Player %d is human\n", i)
end
end
return ai
end
local function endgame()
repeat
printf("\nEnd game? (y/n)? ", i) yn=io.read():lower()
until yn:match("[yn]")
if yn=='n' then
return false
else
printf("\nGOOD BYE PROFESSOR FALKEN.\n\nA STRANGE GAME.\nTHE ONLY WINNING MOVE IS\nNOT TO PLAY.\n\nHOW ABOUT A NICE GAME OF CHESS?\n")
return true
end
end
-- AI Routine
local function shuffle(t)
for i=#t,1,-1 do
local rnd=random(i)
t[i], t[rnd] = t[rnd], t[i]
end
return t
end
-- move generator
local function genmove(node, color)
return coroutine.wrap(function()
local moves={}
for m in node:gmatch("%d") do
moves[#moves+1]=m
end
shuffle(moves) -- to make it more interesting
for _,m in ipairs(moves) do
local child=node:gsub(m,symbol[pnum[color]])
coroutine.yield(child, m)
end
end)
end
--[[
Negamax with alpha-beta pruning and table caching
]]
local cache={}
local best, aimove, tDepth
local LOWERB,EXACT,UPPERB=-1,0,1 -- has somebody an idea how to make them real constants?
local function negamax(node, depth, color, α, β)
color=color or 1
α=α or -math.huge
β=β or math.huge
-- check for cached node
local αOrg=α
local cData=cache[node]
if cData and cData.depth>=depth and depth~=tDepth then
if cData.flag==EXACT then
return cData.value
elseif cData.flag==LOWERB then
α=math.max(α,cData.value)
elseif cData.flag==UPPERB then
β=math.min(β,cData.value)
end
if α>=β then
return cData.value
end
end
 
local winner=win(node)
if depth==0 or winner~=0 then
return winner*color
end
local value=-math.huge
for child,move in genmove(node, color) do
value=math.max(value, -negamax(child, depth-1, -color, -β, -α))
if value>α then
α=value
if depth==tDepth then
best=child
aimove=move
end
end
if α>=β then break end
end
-- cache known data
--cData={} -- if you want Lua tables instead of ffi you can switch the two lines here, costs 20% speed
cData=ffi.new("cData")
cData.value=value
if value<=αOrg then
cData.flag=UPPERB
elseif value>=β then
cData.flag=LOWERB
else
cData.flag=EXACT
end
cData.depth=depth
cache[node]=cData
return α
end
-- MAIN
do
local winner,value
local score={[-1]=0, [0]=0, [1]=0}
repeat
print("\n TIC-TAC-TOE\n")
local aiplayer=playerselect()
local player=1
board="123456789"
for i=1,#board do
draw(board)
tDepth=10-i
if aiplayer[player] then
negamax(board, tDepth, player, -math.huge, math.huge)
board=best
printf("AI %d moves %s\n", pnum[player], aimove)
else
board=input(board,player)
end
winner=win(board)
if winner~=0 then break end
player=-player
end
score[winner]=score[winner]+1
if winner and winner~=0 then
printf("*** Player %d (%s) has won\n", pnum[winner], symbol[pnum[winner]])
else
printf("*** No winner\n")
end
printf("Score Player 1: %d Player 2: %d Draw: %d\n",score[1],score[-1],score[0])
draw(board)
until endgame()
end</syntaxhighlight>
 
{{out}}
 
<pre>> time echo "n\nn\ny\n"| ./tictactoe.lua ⏎
 
TIC-TAC-TOE
 
Player 1 human (Y/n)? Player 1 is AI
Player 2 human (Y/n)? Player 2 is AI
789
456
123
AI 1 moves 1
789
456
X23
AI 2 moves 5
789
4O6
X23
AI 1 moves 9
78X
4O6
X23
AI 2 moves 2
78X
4O6
XO3
AI 1 moves 8
7XX
4O6
XO3
AI 2 moves 7
OXX
4O6
XO3
AI 1 moves 3
OXX
4O6
XOX
AI 2 moves 6
OXX
4OO
XOX
AI 1 moves 4
*** No winner
Score Player 1: 0 Player 2: 0 Draw: 1
OXX
XOO
XOX
 
End game? (y/n)?
GOOD BYE PROFESSOR FALKEN.
 
A STRANGE GAME.
THE ONLY WINNING MOVE IS
NOT TO PLAY.
 
HOW ABOUT A NICE GAME OF CHESS?
echo "n\nn\ny\n" 0,00s user 0,00s system 69% cpu 0,002 total
./tictactoe.lua 0,03s user 0,00s system 98% cpu 0,035 total</pre>
 
=={{header|M2000 Interpreter}}==
Computer May loose;
<syntaxhighlight lang="m2000 interpreter">
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
</syntaxhighlight>
{{out}}
<pre style="height:30ex;overflow:scroll">
Computer Move:
R/C 1 2 3
1) | |
-+-+-
2) | |
-+-+-
3) | |X
Input Row:2
Input Column:2
R/C 1 2 3
1) | |
-+-+-
2) |O|
-+-+-
3) | |X
Computer Move:
R/C 1 2 3
1) | |
-+-+-
2) |O|
-+-+-
3) X| |X
Input Row:3
Input Column:2
R/C 1 2 3
1) | |
-+-+-
2) |O|
-+-+-
3) X|O|X
Computer Move:
R/C 1 2 3
1) |X|
-+-+-
2) |O|
-+-+-
3) X|O|X
Input Row:2
Input Column:1
R/C 1 2 3
1) |X|
-+-+-
2) O|O|
-+-+-
3) X|O|X
Computer Move:
R/C 1 2 3
1) |X|
-+-+-
2) O|O|X
-+-+-
3) X|O|X
Input Row:1
Input Column:3
R/C 1 2 3
1) |X|O
-+-+-
2) O|O|X
-+-+-
3) X|O|X
Computer Move:
R/C 1 2 3
1) X|X|O
-+-+-
2) O|O|X
-+-+-
3) X|O|X
 
</pre >
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="text">DynamicModule[{board = ConstantArray[0, {3, 3}], text = "Playing...",
first, rows =
Join[#, Transpose@#, {Diagonal@#, Diagonal@Reverse@#}] &},
Line 3,603 ⟶ 10,288:
text = "Draw."]]]]], {i, 1, 3}, {j, 1, 3}], Thickness[.01],
Line[{{{1, 0}, {1, 3}}, {{2, 0}, {2, 3}}, {{0, 1}, {3, 1}}, {{0,
2}, {3, 2}}}]}], Dynamic@text}]</langsyntaxhighlight>
 
=={{header|MATLAB}}==
Allows for choice between any combination of human or computer players. Computer players are intelligent, but not perfect. It implements the "rules" used by the Newell and Simon's 1972 tic-tac-toe program (as explained by Wikipedia), but this implementation does not factor in the move before the move causing the fork (either for creation or prevention).
<syntaxhighlight lang="matlab">function TicTacToe
% Set up the board (one for each player)
boards = false(3, 3, 2); % Players' pieces
rep = [' 1 | 4 | 7' ; ' 2 | 5 | 8' ; ' 3 | 6 | 9'];
% Prompt user with options
fprintf('Welcome to Tic-Tac-Toe!\n')
nHumans = str2double(input('Enter the number of human players: ', 's'));
if isnan(nHumans) || ceil(nHumans) ~= nHumans || nHumans < 1 || nHumans > 2
nHumans = 0;
pHuman = false(2, 1);
elseif nHumans == 1
humanFirst = input('Would the human like to go first (Y/N)? ', 's');
if length(humanFirst) == 1 && lower(humanFirst) == 'n'
pHuman = [false ; true];
else
pHuman = [true ; false];
end
else
pHuman = true(2, 1);
end
if any('o' == input('Should Player 1 use X or O? ', 's'))
marks = 'OX';
else
marks = 'XO';
end
fprintf('So Player 1 is %shuman and %cs and Player 2 is %shuman and %cs.\n', ...
char('not '.*~pHuman(1)), marks(1), char('not '.*~pHuman(2)), marks(2))
if nHumans > 0
fprintf('Select the space to mark by entering the space number.\n')
fprintf('No entry will quit the game.\n')
end
% Play game
gameOver = false;
turn = 1;
while ~gameOver
fprintf('\n')
disp(rep)
fprintf('\n')
if pHuman(turn)
[move, isValid, isQuit] = GetMoveFromPlayer(turn, boards);
gameOver = isQuit;
else
move = GetMoveFromComputer(turn, boards);
fprintf('Player %d chooses %d\n', turn, move)
isValid = true;
isQuit = false;
end
if isValid && ~isQuit
[r, c] = ind2sub([3 3], move);
boards(r, c, turn) = true;
rep(r, 4*c) = marks(turn);
if CheckWin(boards(:, :, turn))
gameOver = true;
fprintf('\n')
disp(rep)
fprintf('\nPlayer %d wins!\n', turn)
elseif CheckDraw(boards)
gameOver = true;
fprintf('\n')
disp(rep)
fprintf('\nCat''s game!\n')
end
turn = ~(turn-1)+1;
end
end
end
 
function [move, isValid, isQuit] = GetMoveFromPlayer(pNum, boards)
% move - 1-9 indicating move position, 0 if invalid move
% isValid - logical indicating if move was valid, true if quitting
% isQuit - logical indicating if player wishes to quit game
p1 = boards(:, :, 1);
p2 = boards(:, :, 2);
moveStr = input(sprintf('Player %d: ', pNum), 's');
if isempty(moveStr)
fprintf('Play again soon!\n')
move = 0;
isValid = true;
isQuit = true;
else
move = str2double(moveStr);
isQuit = false;
if isnan(move) || move < 1 || move > 9 || p1(move) || p2(move)
fprintf('%s is an invalid move.\n', moveStr)
isQuit = 0;
isValid = false;
else
isValid = true;
end
end
end
 
function move = GetMoveFromComputer(pNum, boards)
% pNum - 1-2 player number
% boards - 3x3x2 logical array where pBoards(:,:,1) is player 1's marks
% Assumes that it is possible to make a move
if ~any(boards(:)) % Play in the corner for first move
move = 1;
else % Use Newell and Simon's "rules to win"
pMe = boards(:, :, pNum);
pThem = boards(:, :, ~(pNum-1)+1);
possMoves = find(~(pMe | pThem)).';
% Look for a winning move
move = FindWin(pMe, possMoves);
if move
return
end
% Look to block opponent from winning
move = FindWin(pThem, possMoves);
if move
return
end
% Look to create a fork (two non-blocked lines of two)
for m = possMoves
newPMe = pMe;
newPMe(m) = true;
if CheckFork(newPMe, pThem)
move = m;
return
end
end
% Look to make two in a row so long as it doesn't force opponent to fork
notGoodMoves = false(size(possMoves));
for m = possMoves
newPMe = pMe;
newPMe(m) = true;
if CheckPair(newPMe, pThem)
nextPossMoves = possMoves;
nextPossMoves(nextPossMoves == m) = [];
theirMove = FindWin(newPMe, nextPossMoves);
newPThem = pThem;
newPThem(theirMove) = true;
if ~CheckFork(newPThem, newPMe)
move = m;
return
else
notGoodMoves(possMoves == m) = true;
end
end
end
possMoves(notGoodMoves) = [];
% Play the center if available
if any(possMoves == 5)
move = 5;
return
end
% Play the opposite corner of the opponent's piece if available
corners = [1 3 7 9];
move = intersect(possMoves, ...
corners(~(pMe(corners) | pThem(corners)) & pThem(fliplr(corners))));
if ~isempty(move)
move = move(1);
return
end
% Play an empty corner if available
move = intersect(possMoves, corners);
if move
move = move(1);
return
end
% Play an empty side if available
sides = [2 4 6 8];
move = intersect(possMoves, sides);
if move
move = move(1);
return
end
% No good moves, so move randomly
possMoves = find(~(pMe | pThem));
move = possMoves(randi(length(possMoves)));
end
end
 
function move = FindWin(board, possMoves)
% board - 3x3 logical representing one player's pieces
% move - integer indicating position to move to win, or 0 if no winning move
for m = possMoves
newPMe = board;
newPMe(m) = true;
if CheckWin(newPMe)
move = m;
return
end
end
move = 0;
end
 
function win = CheckWin(board)
% board - 3x3 logical representing one player's pieces
% win - logical indicating if that player has a winning board
win = any(all(board)) || any(all(board, 2)) || ...
all(diag(board)) || all(diag(fliplr(board)));
end
 
function fork = CheckFork(p1, p2)
% fork - logical indicating if player 1 has created a fork unblocked by player 2
fork = sum([sum(p1)-sum(p2) (sum(p1, 2)-sum(p2, 2)).' ...
sum(diag(p1))-sum(diag(p2)) ...
sum(diag(fliplr(p1)))-sum(diag(fliplr(p2)))] == 2) > 1;
end
 
function pair = CheckPair(p1, p2)
% pair - logical indicating if player 1 has two in a line unblocked by player 2
pair = any([sum(p1)-sum(p2) (sum(p1, 2)-sum(p2, 2)).' ...
sum(diag(p1))-sum(diag(p2)) ...
sum(diag(fliplr(p1)))-sum(diag(fliplr(p2)))] == 2);
end
 
function draw = CheckDraw(boards)
% boards - 3x3x2 logical representation of all players' pieces
draw = all(all(boards(:, :, 1) | boards(:, :, 2)));
end</syntaxhighlight>
{{out}}
Computer goes first and plays perfectly:
<pre>Welcome to Tic-Tac-Toe!
Enter the number of human players: 1
Would the human like to go first (Y/N)? n
Should Player 1 use X or O? x
So Player 1 is not human and Xs and Player 2 is human and Os.
Select the space to mark by entering the space number.
No entry will quit the game.
 
1 | 4 | 7
2 | 5 | 8
3 | 6 | 9
 
Player 1 chooses 1
 
X | 4 | 7
2 | 5 | 8
3 | 6 | 9
 
Player 2: 4
 
X | O | 7
2 | 5 | 8
3 | 6 | 9
 
Player 1 chooses 2
 
X | O | 7
X | 5 | 8
3 | 6 | 9
 
Player 2: 3
 
X | O | 7
X | 5 | 8
O | 6 | 9
 
Player 1 chooses 5
 
X | O | 7
X | X | 8
O | 6 | 9
 
Player 2: 8
 
X | O | 7
X | X | O
O | 6 | 9
 
Player 1 chooses 9
 
X | O | 7
X | X | O
O | 6 | X
 
Player 1 wins!</pre>
Computer goes first, but misses opportunity to set up for a fork, setting up human player instead:
<pre>Welcome to Tic-Tac-Toe!
Enter the number of human players: 1
Would the human like to go first (Y/N)? n
Should Player 1 use X or O? x
So Player 1 is not human and Xs and Player 2 is human and Os.
Select the space to mark by entering the space number.
No entry will quit the game.
 
1 | 4 | 7
2 | 5 | 8
3 | 6 | 9
 
Player 1 chooses 1
 
X | 4 | 7
2 | 5 | 8
3 | 6 | 9
 
Player 2: 9
 
X | 4 | 7
2 | 5 | 8
3 | 6 | O
 
Player 1 chooses 2
 
X | 4 | 7
X | 5 | 8
3 | 6 | O
 
Player 2: 3
 
X | 4 | 7
X | 5 | 8
O | 6 | O
 
Player 1 chooses 6
 
X | 4 | 7
X | 5 | 8
O | X | O
 
Player 2: 7
 
X | 4 | O
X | 5 | 8
O | X | O
 
Player 1 chooses 5
 
X | 4 | O
X | X | 8
O | X | O
 
Player 2: 8
 
X | 4 | O
X | X | O
O | X | O
 
Player 2 wins!</pre>
 
=={{header|mIRC Scripting Language}}==
<langsyntaxhighlight lang="mirc">alias ttt {
if ($2 isin %ttt) || (!%ttt) {
var %ttt~ = $remove($iif(%ttt,%ttt,1 2 3 4 5 6 7 8 9),$2,X,O)
Line 3,636 ⟶ 10,667:
echo -ag � $+ $iif($7 isnum,$chr(32),$7) $+ $chr(124) $+ $iif($8 isnum,$chr(32),$8) $+ $chr(124) $+ $iif($9 isnum, ,$9)
}
}</langsyntaxhighlight>
 
=={{header|МК-61/52}}==
<syntaxhighlight lang="mk-61">9 С/П ПП 28 пи * cos x<0 16 ИП2
ПП 28 1 - БП 51 ИП7 ПП 28 ИП7
ПП 28 КИП2 ИП2 ВП 4 4 С/П 1 -
x=0 33 8 П2 С/П П7 ИП2 4 - x#0
43 x<0 45 8 + П8 ИП7 - x#0 55
ИП8 ВП 6 6 С/П ИП2 В/О</syntaxhighlight>
 
Cell numbering 1 to 9; starts from the upper left cell, then clockwise in a spiral. The first move is a calculator. Result: 44 - draw, 66 - victory of the calculator.
 
=={{header|Nim}}==
{{trans|Python}}
This is a translation of the second version with the better AI, but with some differences. For instance, we have chosen to display the board in the same way as the first version. All procedures have a parameter "board" rather accessing a global variable. We use also base 1-indexing for the board. Etc.
 
<syntaxhighlight lang="nim">import options, random, sequtils, strutils
 
type
Board = array[1..9, char]
Score = (char, array[3, int])
 
const NoChoice = 0
 
var board: Board = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
 
const Wins = [[1, 2, 3], [4, 5, 6], [7, 8, 9],
[1, 4, 7], [2, 5, 8], [3, 6, 9],
[1, 5, 9], [3, 5, 7]]
 
template toIndex(ch: char): int =
## Convert a character to an index in board.
ord(ch) - ord('0')
 
proc print(board: Board) =
for i in [1, 4, 7]:
echo board[i..(i + 2)].join(" ")
 
proc score(board: Board): Option[Score] =
for w in Wins:
let b = board[w[0]]
if b in "XO" and w.allIt(board[it] == b):
return some (b, w)
result = none(Score)
 
proc finished(board: Board): bool =
board.allIt(it in "XO")
 
proc space(board: Board): seq[char] =
for b in board:
if b notin "XO":
result.add b
 
proc myTurn(board: var Board; xo: char): char =
let options = board.space()
result = options.sample()
board[result.toIndex] = xo
 
proc myBetterTurn(board: var Board; xo: char): int =
let ox = if xo == 'X': 'O' else: 'X'
var oneBlock = NoChoice
let options = board.space.mapIt(it.toIndex)
block search:
for choice in options:
var brd = board
brd[choice] = xo
if brd.score.isSome:
result = choice
break search
if oneBlock == NoChoice:
brd[choice] = ox
if brd.score.isSome:
oneBlock = choice
result = if oneBlock != NoChoice: oneBlock else: options.sample()
board[result] = xo
 
proc yourTurn(board: var Board; xo: char): int =
let options = board.space()
var choice: char
while true:
stdout.write "\nPut your $# in any of these positions: $# ".format(xo, options.join())
let input = stdin.readLine().strip()
if input.len == 1 and input[0] in options:
choice = input[0]
break
echo "Whoops I don't understand the input"
result = choice.toIndex
board[result] = xo
 
proc me(board: var Board; xo: char): Option[Score] =
board.print()
echo "\nI go at ", board.myBetterTurn(xo)
result = board.score()
 
proc you(board: var Board; xo: char): Option[Score] =
board.print()
echo "\nYou went at ", board.yourTurn(xo)
result = board.score()
 
proc play() =
while not board.finished():
let score = board.me('X')
if score.isSome:
board.print()
let (winner, line) = score.get()
echo "\n$# wins along ($#).".format(winner, line.join(", "))
return
if not board.finished():
let score = board.you('O')
if score.isSome:
board.print()
let (winner, line) = score.get()
echo "\n$# wins along ($#).".format(winner, line.join(", "))
return
echo "\nA draw."
 
echo "Tic-tac-toe game player."
echo "Input the index of where you wish to place your mark at your turn."
randomize()
play()</syntaxhighlight>
 
{{out}}
<pre>Tic-tac-toe game player.
Input the index of where you wish to place your mark at your turn.
1 2 3
4 5 6
7 8 9
 
I go at 9
1 2 3
4 5 6
7 8 X
 
Put your O in any of these positions: 12345678 7
 
You went at 7
1 2 3
4 5 6
O 8 X
 
I go at 5
1 2 3
4 X 6
O 8 X
 
Put your O in any of these positions: 123468 1
 
You went at 1
O 2 3
4 X 6
O 8 X
 
I go at 4
O 2 3
X X 6
O 8 X
 
Put your O in any of these positions: 2368 6
 
You went at 6
O 2 3
X X O
O 8 X
 
I go at 3
O 2 X
X X O
O 8 X
 
Put your O in any of these positions: 28 8
 
You went at 8
O 2 X
X X O
O O X
 
I go at 2
 
A draw.</pre>
 
=={{header|Objeck}}==
Tic-tac-toe game using Minimax algorithm.
<syntaxhighlight lang="objeck">class TicTacToe {
@board : Char[,];
@cpu_opening : Bool;
 
enum Status {
INVALID_MOVE,
PLAYING,
QUIT,
TIE,
CPU_WIN,
PLAYER_WIN
}
 
consts Weights {
MIN := -1000,
MAX := 1000
}
 
function : Main(args : String[]) ~ Nil {
cpu_score := 0;
player_score := 0;
 
for(i :=0; i < 5; i += 1;) {
game := TicTacToe->New();
result := game->Play();
 
if(result = Status->PLAYER_WIN) {
player_score += 1;
"\n=> Player Wins!"->PrintLine();
}
else if(result = Status->CPU_WIN) {
cpu_score += 1;
"\n=> CPU Wins!"->PrintLine();
}
else if(result = Status->TIE) {
"\n=> Tie."->PrintLine();
}
else {
break;
};
};
 
"\nHuman={$player_score}, CPU={$cpu_score}"->PrintLine();
}
 
New() {
@board := Char->New[3, 3];
for(index := 0; index < 9; index += 1;) {
j := index / 3;
i := index % 3;
@board[i, j] := '1' + index;
};
 
@cpu_opening := true;
}
 
method : Play() ~ Status {
players_turn := Int->Random(1) = 1 ? true : false;
 
if(players_turn) {
@cpu_opening := false;
"\n*** NEW (Player) ***\n"->PrintLine();
Draw();
}
else {
"\n*** NEW (CPU) ***\n"->PrintLine();
};
 
playing := true;
do {
status : Status;
 
if(players_turn) {
status := PlayerMove();
players_turn := false;
}
else {
status := CpuMove();
players_turn := true;
};
 
if(players_turn) {
Draw();
};
 
select(status) {
label Status->INVALID_MOVE: {
"\n=> Invalid Move"->PrintLine();
}
 
label Status->PLAYER_WIN: {
return Status->PLAYER_WIN;
}
 
label Status->CPU_WIN: {
return Status->CPU_WIN;
}
 
label Status->TIE: {
return Status->TIE;
}
 
label Status->QUIT: {
playing := false;
}
};
}
while(playing);
 
return Status->QUIT;
}
 
method : PlayerMove() ~ Status {
move := System.IO.Console->ReadString();
if(move->Size() = 0) {
return Status->INVALID_MOVE;
};
 
option := move->Get(0);
if(option = 'q') {
return Status->QUIT;
};
 
if(LegalMove(option, 'X')) {
if(IsWinner(@board, 'X')) {
return Status->PLAYER_WIN;
}
else if(IsTied()) {
return Status->TIE;
}
else {
return Status->PLAYING;
};
}
else {
return Status->INVALID_MOVE;
};
}
 
method : CpuMove() ~ Status {
if(@cpu_opening) {
select(Int->Random(2)) {
label 0: {
@board[0, 0] := 'O';
}
 
label 1: {
@board[1, 1] := 'O';
}
 
label 2: {
@board[2, 2] := 'O';
}
};
@cpu_opening := false;
}
else {
BestCpuMove(CopyBoard());
};
 
if(IsWinner(@board, 'O')) {
return Status->CPU_WIN;
}
else if(IsTied()) {
return Status->TIE;
}
else {
return Status->PLAYING;
};
}
 
method : Minimax(board : Char[,], depth : Int, is_max : Bool, alpha : Int, beta : Int) ~ Int {
score := EvaluateMove(board);
if(score = 10 | score = -10) {
return score;
};
 
if(IsTied()) {
return 0;
};
 
if(is_max) {
best := Weights->MIN;
for(i := 0; i < 3; i += 1;) {
for(j := 0; j < 3; j += 1;) {
if(board[i,j] <> 'X' & board[i,j] <>'O') {
test := board[i,j];
board[i,j] := 'O';
best := Int->Max(best, Minimax(board, depth + 1, false, alpha, beta));
alpha := Int->Max(alpha, best);
board[i,j] := test;
 
if(beta <= alpha) {
return best;
};
};
};
};
 
return best;
}
else {
best := Weights->MAX;
for(i := 0; i < 3; i += 1;) {
for(j := 0; j < 3; j += 1;) {
if(board[i,j] <> 'X' & board[i,j] <>'O') {
test := board[i,j];
board[i,j] := 'X';
best := Int->Min(best, Minimax(board, depth + 1, true, alpha, beta));
beta := Int->Min(beta, best);
board[i,j] := test;
 
if(beta <= alpha) {
return best;
};
};
};
};
 
return best;
};
}
 
method : BestCpuMove(board : Char[,]) ~ Nil {
best := Weights->MIN; # empty
best_i := -1;
best_j := -1;
 
for(i := 0; i < 3; i += 1;) {
for(j := 0; j < 3; j += 1;) {
if(board[i,j] <> 'X' & board[i,j] <> 'O') {
test := board[i,j];
board[i,j] := 'O';
move := Int->Max(best, Minimax(board, 0, false, Weights->MIN, Weights->MAX));
board[i,j] := test;
 
if(move > best) {
best_i := i;
best_j := j;
best := move;
};
};
};
};
 
@board[best_i, best_j] := 'O';
}
 
method : EvaluateMove(board : Char[,]) ~ Int {
if(IsWinner(board, 'O')) {
return 10;
}
else if(IsWinner(board, 'X')) {
return -10;
}
else {
return 0;
};
}
method : CopyBoard() ~ Char[,] {
board := Char->New[3, 3];
 
for(i := 0; i < 3; i += 1;) {
for(j := 0; j < 3; j += 1;) {
board[i,j] := @board[i,j];
};
};
 
return board;
}
 
method : LegalMove(move : Char, player: Char) ~ Bool {
if(move >= '1' & move <= '9') {
index := (move - '1')->As(Int);
j := index / 3; i := index % 3;
 
if(@board[i, j] = 'X' | @board[i, j] = 'O') {
return false;
};
 
@board[i, j] := player;
return true;
}
else {
return false;
};
}
 
method : IsWinner(board : Char[,], player : Char) ~ Bool {
# --- diagonal ---
check := 0;
for(i := 0; i < 3; i += 1;) {
if(board[i, i] = player) {
check += 1;
};
};
 
if(check = 3) {
return true;
};
 
check := 0;
j := 2;
for(i := 0; i < 3; i += 1;) {
if(board[i, j] = player) {
check += 1;
};
j -= 1;
};
 
if(check = 3) {
return true;
};
 
# --- vertical ---
for(i := 0; i < 3; i += 1;) {
check := 0;
for(j := 0; j < 3; j += 1;) {
if(board[i, j] = player) {
check += 1;
};
};
 
if(check = 3) {
return true;
};
};
 
# --- horizontal ---
for(j := 0; j < 3; j += 1;) {
check := 0;
for(i := 0; i < 3; i += 1;) {
if(board[i, j] = player) {
check += 1;
};
};
 
if(check = 3) {
return true;
};
};
 
return false;
}
 
method : IsTied() ~ Bool {
for(i := 0; i < 3; i += 1;) {
for(j := 0; j < 3; j += 1;) {
if(@board[i, j] <> 'X' & @board[i, j] <> 'O') {
return false;
};
};
};
 
return true;
}
 
method : Draw() ~ Nil {
a1 := @board[0, 0]; a2 := @board[1, 0]; a3 := @board[2, 0];
b1 := @board[0, 1]; b2 := @board[1, 1]; b3 := @board[2, 1];
c1 := @board[0, 2]; c2 := @board[1, 2]; c3 := @board[2, 2];
 
"==========="->PrintLine();
" {$a1} | {$a2} | {$a3} "->PrintLine();
"---|---|---"->PrintLine();
" {$b1} | {$b2} | {$b3} "->PrintLine();
"---|---|---"->PrintLine();
" {$c1} | {$c2} | {$c3} "->PrintLine();
"===========\n"->PrintLine();
}
}</syntaxhighlight>
 
=={{header|Pascal}}==
Similar to on C version (same depth first strategy). Computer always win.
In some ways easier to read, but because Pascal lack return/break/continue
functions a little long and different style. Tested with FreePascal on macOS.
I would expect this version should compile with most Pascal variants including Delphi, but YMMR.
 
<syntaxhighlight lang="pascal">program Tic(Input, Output);
 
type
Contents = (Unassigned, Human, Computer);
var
BestI, BestJ: integer; { best solution a depth of zero in the search }
B: array[0..2, 0..2] of Contents; {zero based so modulus works later}
Player: Contents;
 
procedure DisplayBoard;
var
I, J: integer;
T: array [Contents] of char;
begin
T[Unassigned] := ' ';
T[Human] := 'O';
T[Computer] := 'X';
for I := 0 to 2 do
begin
for J := 0 to 2 do
begin
Write(T[B[I, J]]);
if J <> 2 then
Write(' | ');
end;
WriteLn;
if I < 2 then
WriteLn('---------');
end;
WriteLn;
WriteLn;
end;
 
function SwapPlayer(Player: Contents): Contents;
begin
if Player = Computer then
SwapPlayer := Human
else
SwapPlayer := Computer;
end;
 
function CheckWinner: Contents;
var
I: integer;
begin
CheckWinner := Unassigned; { no winner yet }
for I := 0 to 2 do
begin
{ first horizontal solution }
if (CheckWinner = Unassigned) and (B[I, 0] <> Unassigned) and
(B[I, 1] = B[I, 0]) and (B[I, 2] = B[I, 0]) then
CheckWinner := B[I, 0]
else
{ now vertical solution }
if (CheckWinner = Unassigned) and (B[0, I] <> Unassigned) and
(B[1, I] = B[0, I]) and (B[2, I] = B[0, I]) then
CheckWinner := B[0, I];
end;
{ now check the paths of the two cross line slants that share the middle position }
if (CheckWinner = Unassigned) and (B[1, 1] <> Unassigned) then
begin
if (B[1, 1] = B[0, 0]) and (B[2, 2] = B[0, 0]) then
CheckWinner := B[0, 0]
else if (B[1, 1] = B[2, 0]) and (B[0, 2] = B[1, 1]) then
CheckWinner := B[1, 1];
end;
end;
 
{ Basic strategy test - is this te best solution we have seen }
function SaveBest(CurScore, CurBest: Contents): boolean;
begin
if CurScore = CurBest then
SaveBest := False
else if (CurScore = Unassigned) and (CurBest = Human) then
SaveBest := False
else if (CurScore = Computer) and ((CurBest = Unassigned) or
(CurBest = Human)) then
SaveBest := False
else
SaveBest := True;
end;
 
 
{ Basic strategy - recursive depth first search of possible moves
if computer can win save it, otherwise block if need be, else do deeper.
At each level modify the board for the next call, but clean up as go back up,
by remembering the modified position on the call stack. }
function TestMove(Val: Contents; Depth: integer): Contents;
var
I, J: integer;
Score, Best, Changed: Contents;
begin
Best := Computer;
Changed := Unassigned;
Score := CheckWinner;
if Score <> Unassigned then
begin
if Score = Val then
TestMove := Human
else
TestMove := Computer;
end
else
begin
for I := 0 to 2 do
for J := 0 to 2 do
begin
if B[I, J] = Unassigned then
begin
Changed := Val;
B[I, J] := Val;
{ the value for now and try wioth the other player }
Score := TestMove(SwapPlayer(Val), Depth + 1);
if Score <> Unassigned then
Score := SwapPlayer(Score);
B[I, J] := Unassigned;
if SaveBest(Score, Best) then
begin
if Depth = 0 then
begin { top level, so remember actual position }
BestI := I;
BestJ := J;
end;
Best := Score;
end;
end;
end;
if Changed <> Unassigned then
TestMove := Best
else
TestMove := Unassigned;
end;
end;
 
function PlayGame(Whom: Contents): string;
var
I, J, K, Move: integer;
Win: Contents;
begin
Win := Unassigned;
for I := 0 to 2 do
for J := 0 to 2 do
B[I, J] := Unassigned;
WriteLn('The board positions are numbered as follows:');
WriteLn('1 | 2 | 3');
WriteLn('---------');
WriteLn('4 | 5 | 6');
WriteLn('---------');
WriteLn('7 | 8 | 9');
WriteLn('You have O, I have X.');
WriteLn;
K := 1;
repeat {rather a for loop but can not have two actions or early termination in Pascal}
if Whom = Human then
begin
repeat
Write('Your move: ');
ReadLn(Move);
if (Move < 1) or (Move > 9) then
WriteLn('Opps: enter a number between 1 - 9.');
Dec(Move);
{humans do 1 -9, but the computer wants 0-8 for modulus to work}
I := Move div 3; { convert from range to corridinated of the array }
J := Move mod 3;
if B[I, J] <> Unassigned then
WriteLn('Opps: move ', Move + 1, ' was already done.')
until (Move >= 0) and (Move <= 8) and (B[I, J] = Unassigned);
B[I, J] := Human;
end;
if Whom = Computer then
begin
{ randomize if computer opens, so its not always the same game }
if K = 1 then
begin
BestI := Random(3);
BestJ := Random(3);
end
else
Win := TestMove(Computer, 0);
B[BestI, BestJ] := Computer;
WriteLn('My move: ', BestI * 3 + BestJ + 1);
end;
DisplayBoard;
Win := CheckWinner;
if Win <> Unassigned then
begin
if Win = Human then
PlayGame := 'You win.'
else
PlayGame := 'I win.';
end
else
begin
Inc(K); { "for" loop counter actions }
Whom := SwapPlayer(Whom);
end;
until (Win <> Unassigned) or (K > 9);
if Win = Unassigned then
PlayGame := 'A draw.';
end;
 
begin
Randomize;
Player := Human;
while True do
begin
WriteLn(PlayGame(Player));
WriteLn;
Player := SwapPlayer(Player);
end
end.</syntaxhighlight>
 
=={{header|Perl}}==
Line 3,647 ⟶ 11,449:
the computer. Anyone who can identify the mistake, is welcome to fix it.
 
<langsyntaxhighlight Perllang="perl">use warnings;
use strict;
 
Line 3,746 ⟶ 11,548:
$whose_turn = !$whose_turn;
}
</syntaxhighlight>
</lang>
 
{{out}}
Line 3,803 ⟶ 11,605:
Place your X on one of [a b c d e f g h i]:
</pre>
===Alternate with GUI===
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict;
=={{header|Perl 6}}==
use warnings;
{{works with|Rakudo| 2011.11}}
use Tk;
The computer plays a random game.
use List::Util qw( shuffle );
Output is formatted in a similar way to that of the better python version.
<lang Perl6>
use v6;
 
my $win = qr/(?| ^(\w)...\1...\1 | ^..(\w).\1.\1 # diagonals
my @board = 1..9;
| ^(?:...)*?(\w)\1\1 | (\w)..\1..\1 )/x; # row or column
my @winning-positions = [0..2], [3..5], [6..8], [0,3,6], [1,4,7], [2,5,8],
my (%cache, $message, $game);
[0,4,8], [6,4,2];
 
my $mw = MainWindow->new( -title => 'TicTacToe' );
sub get-winner() {
$mw->geometry('+1000+300');
for @winning-positions {
$mw->Label(-textvariable => \$message, -font => 'courierbold 16',
return (@board[$_][0], $_) if [eq] @board[$_];
)->pack(-fill => 'x');
}
my $grid = $mw->Frame( -borderwidth => 5, -relief => 'ridge' )->pack;
}
$mw->Button(-text => $_->[0], -command => $_->[1],
)->pack(-side => 'left', -fill => 'x', -expand => 1) for
['Restart X first' => sub { restart(1) }],
['Restart O first' => sub { restart(0) }],
[ 'Exit' => sub { $mw->destroy }];
my @cells = map { my $me = $_;
$grid->Button( -command => sub { person($me) },
-width => 1, -height => 1, -font => 'courierbold 40',
)->grid(-row => int $_ / 3, -column => $_ % 3)
} 0 .. 8;
 
restart(1);
sub free-indexes() {
@board.keys.grep: { @board[$_] eq any(1..9) }
}
 
MainLoop;
sub ai-move() {
given free-indexes.pick {
@board[$_] = 'o';
say "I go at: { $_ + 1 }\n";
}
}
 
sub show { $cells[$_]->configure(-text => substr $game, $_, 1) for 0 .. 8 }
sub print-board() {
say @board.map({ "$^a | $^b | $^c" }).join("\n--+---+--\n"), "\n";
}
 
sub human-move() {person
{
my $pos = prompt "Choose one of { (free-indexes >>+>> 1).join(",") }: ";
$message =~ /O's turn/ or return;
if $pos eq any(free-indexes >>+>> 1) {
pos($game) = shift();
@board[$pos - 1] = 'x';
if( $game =~ s/\G /O/ )
} else {
{
say "Sorry, you want to put your 'x' where?";
$message = $game =~ $win ? "O Wins" :
human-move();
$game !~ / / ? "Draw" : do {
}
$game = move( $game, 'X' )->[1];
}
$game =~ $win ? 'X Wins' :
$game !~ / / ? 'Draw' : "O's turn to move"
};
show;
}
}
 
sub restart
for (&ai-move, &human-move) xx * {
{
print-board;
. %cache = ();
$game = shift() ? move( ' ' x 9, 'X' )->[1] : ' ' x 9;
last if get-winner() or not free-indexes;
show;
$message = "O's turn to move";
}
 
sub move
{
(local $_, my $who, my @moves) = @_;
/$win/ and return [ 2 * ($1 eq 'X'), $_ ];
/ / or return [ 1, $_ ];
$cache{$_ . $who} //= do
{
while( / /g )
{
my $move = "$`$who$'";
push @moves, [ move($move, $who ^ 'X' ^ 'O')->[0], $move ];
}
(sort {$a->[0] <=> $b->[0]} shuffle @moves)[ -($who eq 'X') ]
};
}</syntaxhighlight>
 
=={{header|Phix}}==
AI copied from C. User goes first, as does loser. After a draw the start player alternates.
{{libheader|Phix/pGUI}}
{{libheader|Phix/online}}
You can run this online [http://phix.x10.mx/p2js/Tic_tac_toe.htm here].
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Tic_tac_toe.exw
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Tic Tac Toe"</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- {' '/'X'/'O'}</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">human</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span> <span style="color: #000080;font-style:italic;">-- (flipped in new_game)</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">game_over</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">play_dumb</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span>
<span style="color: #000080;font-style:italic;">-- saved in redraw_cb() for check_position():</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">cw</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- board centre</span>
<span style="color: #000000;">d</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- tile spacing</span>
<span style="color: #000000;">h</span> <span style="color: #000080;font-style:italic;">-- tile size/radius</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posx*/</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">/*posy*/</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">8</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">h</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">/</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cw</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupGLMakeCurrent</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttributePtr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"DBUFFER"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #004600;">CD_BLUE</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetLineWidth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">d3</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">*</span><span style="color: #000000;">d</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">+</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">pdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=+</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">my</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">+</span><span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">d</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">mx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">d</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">mark</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pdx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">mark</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'X'</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">my</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">my</span><span style="color: #0000FF;">+</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">my</span><span style="color: #0000FF;">+</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">my</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">mark</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'O'</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">cdCanvasCircle</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">my</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">pdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupGLMakeCurrent</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_GL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"10x10 %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">IupSetAttributePtr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"DBUFFER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_PARCHMENT</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">canvas_resize_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttributePtr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"DBUFFER"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">canvas_width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas_height</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span>
<span style="color: #7060A8;">cdCanvasSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"%dx%d %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">canvas_width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas_height</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">wins</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">check_winner</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wins</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">wins</span><span style="color: #0000FF;">[</span><span style="color: #000000;">w</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">mark</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">mark</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">and</span> <span style="color: #000000;">mark</span><span style="color: #0000FF;">=</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">and</span> <span style="color: #000000;">mark</span><span style="color: #0000FF;">=</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">mark</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">best_i</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">test_move</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">mark</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">depth</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">score</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">check_winner</span><span style="color: #0000FF;">(),</span>
<span style="color: #000000;">best</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">changed</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">score</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">score</span><span style="color: #0000FF;">=</span><span style="color: #000000;">mark</span><span style="color: #0000FF;">?</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">changed</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">mark</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">mark</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">test_move</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'O'</span><span style="color: #0000FF;">+</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">-</span><span style="color: #000000;">mark</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">depth</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">score</span><span style="color: #0000FF;">></span><span style="color: #000000;">best</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">depth</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">best_i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">;</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">best</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">score</span><span style="color: #0000FF;">;</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">changed</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">best</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">check_game_over</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">win</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">check_winner</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">win</span> <span style="color: #008080;">or</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">winner</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">win</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'O'</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"You win!"</span><span style="color: #0000FF;">,</span>
<span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">win</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"Computer wins"</span>
<span style="color: #0000FF;">:</span><span style="color: #008000;">"Draw"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s - %s"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">winner</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">game_over</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">play_move</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">move</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">move</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">move</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'O'</span>
<span style="color: #000000;">check_game_over</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">game_over</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">human</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">play_dumb</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find_all</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">best_i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">))]</span>
<span style="color: #008080;">else</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">test_move</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">best_i</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">best_i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'X'</span>
<span style="color: #000000;">check_game_over</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">human</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">not</span> <span style="color: #000000;">game_over</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">new_game</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">human</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">not</span> <span style="color: #000000;">human</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">human</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">9</span><span style="color: #0000FF;">)]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'X'</span>
<span style="color: #000000;">human</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">check_position</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">px</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">py</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- check if x,y is on a legal move.
-- uses ch,cw,d,h as saved by redraw_cb().
--</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">pdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">my</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">+</span><span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">d</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">mx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">d</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">px</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span> <span style="color: #008080;">and</span> <span style="color: #000000;">px</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">h</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">py</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">my</span><span style="color: #0000FF;">-</span><span style="color: #000000;">h</span> <span style="color: #008080;">and</span> <span style="color: #000000;">py</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">my</span><span style="color: #0000FF;">+</span><span style="color: #000000;">h</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">mark</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pdx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mark</span><span style="color: #0000FF;">==</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">?</span><span style="color: #000000;">pdx</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">pdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">button_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*canvas*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">button</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pressed</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000080;font-style:italic;">/*pStatus*/</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">button</span><span style="color: #0000FF;">=</span><span style="color: #004600;">IUP_BUTTON1</span> <span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #000000;">pressed</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (left button released)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">game_over</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">game_over</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #000000;">new_game</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">play_move</span><span style="color: #0000FF;">(</span><span style="color: #000000;">check_position</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">IupRedraw</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">exit_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">help_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
Tic Tac Toe, also known as Noughts and Crosses.
The aim is to get three Os (or Xs) in a row.
Human(O) plays first, as does loser. After a draw first player alternates.
Computer(X) plays a random move first, to make it more interesting.
Setting the constant play_dumb to true disables the internal AI.
Once a game is over click anywhere on the board to start a new game.
"""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">help_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandln</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #000000;">title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help_text</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">-- Other possible keys:
-- Q - quit (end program) [==X?]
-- C - concede (start new game)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*dlg*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_F1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">help_cb</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGLCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=800x800"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="%s",MINSIZE=245x180`</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"RESIZE_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"canvas_resize_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"BUTTON_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"button_cb"</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"KEY_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"PARENTDIALOG"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">new_game</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PHP}}==
A simple interactive version for the browser.
NOTE: While PHP can considered a super-set of HTML/JS, usage has been kept to a minimum to focus on the more specific PHP parts.
 
<syntaxhighlight lang="php">
<?php
const BOARD_NUM = 9;
const ROW_NUM = 3;
$EMPTY_BOARD_STR = str_repeat('.', BOARD_NUM);
 
function isGameOver($board, $pin) {
$pat =
'/X{3}|' . //Horz
'X..X..X..|' . //Vert Left
'.X..X..X.|' . //Vert Middle
'..X..X..X|' . //Vert Right
'..X.X.X..|' . //Diag TL->BR
'X...X...X|' . //Diag TR->BL
'[^\.]{9}/i'; //Cat's game
if ($pin == 'O') $pat = str_replace('X', 'O', $pat);
return preg_match($pat, $board);
}
 
//Start
if get-winner() -> ($player, $across) {
$boardStr = isset($_GET['b'])? $_GET['b'] : $EMPTY_BOARD_STR;
say "$player wins across [", ($across >>+>> 1).join(", "), "].";
$turn = substr_count($boardStr, '.')%2==0? 'O' : 'X';
} else {
$oppTurn = $turn == 'X'? 'O' : 'X';
say "How boring, a draw!";
$gameOver = isGameOver($boardStr, $oppTurn);
 
//Display board
echo '<style>';
echo 'td {width: 200px; height: 200px; text-align: center; }';
echo '.pin {font-size:72pt; text-decoration:none; color: black}';
echo '.pin.X {color:red}';
echo '.pin.O {color:blue}';
echo '</style>';
echo '<table border="1">';
$p = 0;
for ($r = 0; $r < ROW_NUM; $r++) {
echo '<tr>';
for ($c = 0; $c < ROW_NUM; $c++) {
$pin = $boardStr[$p];
echo '<td>';
if ($gameOver || $pin != '.') echo '<span class="pin ', $pin, '">', $pin, '</span>'; //Occupied
else { //Available
$boardDelta = $boardStr;
$boardDelta[$p] = $turn;
echo '<a class="pin ', $pin, '" href="?b=', $boardDelta, '">';
echo $boardStr[$p];
echo '</a>';
}
echo '</td>';
$p++;
}
echo '</tr>';
echo '<input type="hidden" name="b" value="', $boardStr, '"/>';
}
echo '</table>';
</lang>
echo '<a href="?b=', $EMPTY_BOARD_STR, '">Reset</a>';
if ($gameOver) echo '<h1>Game Over!</h1>';
</syntaxhighlight>
 
=={{header|PicoLisp}}==
This solution doesn't bother about the game logic, but simply uses the alpha-beta-pruning 'game' function in the "simul" library.
<langsyntaxhighlight PicoLisplang="picolisp">(load "@lib/simul.l") # for 'game' function
 
(de display ()
Line 3,927 ⟶ 12,056:
((find3 T) "Congratulation, you won!")
((not (myMove)) "No moves")
((find3 0) "Sorry, you lost!") ) )</langsyntaxhighlight>
{{out}}
Output:
<pre>: (main)
+---+---+---+
Line 3,956 ⟶ 12,085:
+---+---+---+
a b c</pre>
 
=={{header|PostScript}}==
<syntaxhighlight lang="postscript">
%!PS
%
% Play Tic-Tac-Toe against your printer
% 2024-04 Nicolas Seriot https://github.com/nst/PSTicTacToe
%
% On GhostScript:
% gs -DNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile="%d.pdf" ttt.ps
%
% On a real PostScript printer:
% cat ttt.ps - | nc 192.168.2.10 9100
 
<</PageSize[595 842]>>setpagedevice/Courier findfont 48 scalefont setfont/b
(.........)def/f{/n 0 def b{46 eq{/n n 1 add def}if}forall n}def/w{/c exch def
[(O)(X)]{/p exch def[[0 1 2][3 4 5][6 7 8][0 3 6][1 4 7][2 5 8][0 4 8][2 4 6]]{
/t exch def/o true def t{/pos exch def/o c pos 1 getinterval p eq o and def}
forall o{exit}if}forall o{exit}if}forall o}def/g{/s exch def/m null def f 0 eq{
/m(TIE)def}if b w{/m(XXXXXXX WINS)def m 0 s putinterval}if()= 0 3 6{b exch 3
getinterval =}for()= m null ne{m =}if 4 setlinewidth 200 700 moveto 200 400
lineto 300 700 moveto 300 400 lineto 100 600 moveto 400 600 lineto 100 500
moveto 400 500 lineto stroke 0 1 b length 1 sub{/i exch def b i 1 getinterval
(.)ne{gsave 0 0 moveto 100 i 3 mod 100 mul add 35 add 700 i 3 idiv 100 mul sub
65 sub moveto b i 1 getinterval show grestore}if}for m null ne{100 300 moveto m
show}if showpage m null ne{quit}if}def{/d false def 0 1 8{/i exch def/e b dup
length string cvs def e i 1 getinterval(.)eq{[(X)(O)]{/p exch def e i p
putinterval e w{b i(X)putinterval/d true def exit}if}forall}if d{exit}if}for d
not{/x rand f mod def/c 0 def 0 1 b length 1 sub{/i exch def b i 1 getinterval
(.)eq{c x eq{b i(X)putinterval exit}if/c c 1 add def}if}for}if(PRINTER)g b{
(human turn (1-9) >)print flush(%lineedit)(r)file( )readline pop dup length
0 gt{0 1 getinterval}{pop( )}ifelse/o exch def(123456789)o search{pop pop pop b
o cvi 1 sub 1 getinterval(.)eq{o cvi 1 sub exit}if}{pop}ifelse(bad input) ==}
loop(O)putinterval(HUMAN )g}loop
</syntaxhighlight>
 
=={{header|Prolog}}==
Line 3,961 ⟶ 12,125:
Uses a minimax algorithm with no Alpha-beta pruning, as the max depth of the recursion is 8. Computer never loses.<br>
A GUI interface written in XPCE is given.
<langsyntaxhighlight Prologlang="prolog">:- use_module('min-max.pl').
 
:-dynamic box/2.
Line 4,170 ⟶ 12,334:
computer(o).
 
</syntaxhighlight>
</lang>
Module min-max.pl defines minimax algorithm.
<langsyntaxhighlight lang="prolog">:- module('min-max.pl', [minimax/5]).
 
% minimax(Player, Deep, MaxDeep, B, V-B)
Line 4,199 ⟶ 12,363:
lie(TTT, V-_, V-TTT).
 
</syntaxhighlight>
</lang>
 
=={{header|Python}}==
The computer enforces the rules but plays a random game.
<langsyntaxhighlight lang="python">
'''
Tic-tac-toe game player.
Line 4,278 ⟶ 12,442:
else:
print('\nA draw')
</syntaxhighlight>
</lang>
 
'''Sample Game'''
Line 4,321 ⟶ 12,485:
In this version, The computer player will first complete a winning line of its own if it can, otherwise block a winning line of its opponent if they have two in a row, or then choose a random move.
 
<langsyntaxhighlight lang="python">
'''
Tic-tac-toe game player.
Line 4,412 ⟶ 12,576:
break
else:
print('\nA draw')</langsyntaxhighlight>
 
{{out}}
'''Sample output'''
<pre>
Tic-tac-toe game player.
Line 4,493 ⟶ 12,657:
A draw</pre>
 
=={{header|R}}==
 
This program simulates a game of Tic-Tac-Toe inside of an interactive window. It includes three player modes, which are a two-player game, a human versus random AI, or human versus maximized AI. This implementation belongs to "X", and can also be found here.
 
<syntaxhighlight lang="r">
rm(list=ls())
library(RColorBrewer)
 
 
# Create tic.tac.toe function.
 
 
tic.tac.toe <- function(name="Name", mode=0, type=0){
place.na <<- matrix(1:9, 3, 3)
value <<- matrix(-3, 3, 3)
k <<- 1 ; r <<- 0
# Make game board.
image(1:3, 1:3, matrix(sample(9), 3, 3), asp=c(1, 1),
xaxt="n", yaxt="n", xlab="", ylab="", frame=F, col=brewer.pal(9, "Set3"))
segments(c(0.5,0.5,1.5,2.5), c(2.5,1.5,0.5,0.5),
c(3.5,3.5,1.5,2.5), c(2.5,1.5,3.5,3.5), lwd=8, col=gray(0.3))
segments(c(0.5,0.5,0.5,3.5), c(0.52,3.47,0.5,0.5),
c(3.5,3.5,0.5,3.5), c(0.52,3.47,3.5,3.5), lwd=8, col=gray(0.3))
# Allow player to choose between a human v. human, human v. random AI, or human vs. smart AI.
if(mode==0) title(list(paste(name, "'s Tic-Tac-Toe !"), cex=2),
"2P : Human v.s. Human", font.sub=2, cex.sub=2)
if(mode==1) title(list(paste(name, "'s Tic-Tac-Toe !"), cex=2),
"1P : Human v.s. AI (Easy)", font.sub=2, cex.sub=2)
if(mode==2) title(list(paste(name, "'s Tic-Tac-Toe !"), cex=2),
"1P : Human v.s. AI (Hard)", font.sub=2, cex.sub=2)
# Dole out symbols.
if(type==0){symbol <- "O" ; symbol.op <- "X"}
if(type==1){symbol <- "X" ; symbol.op <- "O"}
out <- list(name=name, mode=mode, type=type, symbol=symbol, symbol.op=symbol.op)
}
 
# Checks if the game has ended.
 
isGameOver <- function(){
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==0 | total.2==0 | total.1==3 | total.2==3){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==0 | total.2==0 | total.3==0 | total.4==0 | total.1==3 | total.2==3 | total.3==3 | total.4==3){
place.na[!is.na(place.na)] <<- NA
if(total.1==0 | total.2==0 | total.3==0 | total.4==0){
title(sub=list("You Won ?! That's a first!", col="red", font=2, cex=2.5), line=2)
}else{
title(sub=list("You Don't Get Tired of Losing ?!", col="darkblue", font=2, cex=2.5), line=2)
}
}
if(all(is.na(place.na))){
if(total.1==0 | total.2==0 | total.3==0 | total.4==0 | total.1==3 | total.2==3 | total.3==3 | total.4==3){
if(total.1==0 | total.2==0 | total.3==0 | total.4==0){
title(sub=list("You Won ! Pigs Must Be Flying!", col="orange", font=2, cex=2.5), line=2)
}else{
title(sub=list("You Lost ... Once Again !", col="darkblue", font=2, cex=2.5), line=2)
}
}else{
title(sub=list("A measly tie! Try Again", col="blue", font=2, cex=2.5), line=2)
}
}
}
 
 
# AI attack function
 
 
attack <- function(){
### Identify rows and columns
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-1 | total.2==-1){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==-1){
text(i, which(value[i,]!=1), symbol.op, cex=6, font=2)
place.na[i, which(value[i,]!=1)] <<- NA
value[i, which(value[i,]!=1)] <<- 1
}else if(total.2==-1){
text(which(value[,i]!=1), i, symbol.op, cex=6, font=2)
place.na[which(value[,i]!=1), i] <<- NA
value[which(value[,i]!=1), i] <<- 1
}else if(total.3==-1){
r.1 <- which(c(value[1, 1], value[2, 2], value[3, 3])!=1)
text(r.1, r.1, symbol.op, cex=6, font=2)
place.na[r.1, r.1] <<- NA
value[r.1, r.1] <<- 1
}else if(total.4==-1){
r.2 <- which(c(value[1, 3], value[2, 2], value[3, 1])!=1)
text(r.2, -r.2+4, symbol.op, cex=6, font=2)
place.na[r.2, -r.2+4] <<- NA
value[r.2, -r.2+4] <<- 1
}
}
 
 
# AI defense function
 
 
defend <- function(){
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-3 | total.2==-3){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==-3){
text(i, which(value[i,]!=0), symbol.op, cex=6, font=2)
place.na[i, which(value[i,]!=0)] <<- NA
value[i, which(value[i,]!=0)] <<- 1
}else if(total.2==-3){
text(which(value[,i]!=0), i, symbol.op, cex=6, font=2)
place.na[which(value[,i]!=0), i] <<- NA
value[which(value[,i]!=0), i] <<- 1
}else if(total.3==-3){
r.1 <- which(c(value[1, 1], value[2, 2], value[3, 3])!=0)
text(r.1, r.1, symbol.op, cex=6, font=2)
place.na[r.1, r.1] <<- NA
value[r.1, r.1] <<- 1
}else if(total.4==-3){
r.2 <- which(c(value[1, 3], value[2, 2], value[3, 1])!=0)
text(r.2, -r.2+4, symbol.op, cex=6, font=2)
place.na[r.2, -r.2+4] <<- NA
value[r.2, -r.2+4] <<- 1
}else{
rn <- sample(place.na[!is.na(place.na)], 1)
text(rn-3*rn%/%3.5, rn%/%3.5+1, symbol.op, cex=6, font=2)
place.na[rn-3*rn%/%3.5, rn%/%3.5+1] <<- NA
value[rn-3*rn%/%3.5, rn%/%3.5+1] <<- 1
}
}
 
 
# Allow aim in program.
 
 
aim <- function(x, y, tic.tac.toe=ttt){
mode <- tic.tac.toe$mode
symbol <<- tic.tac.toe$symbol
symbol.op <<- tic.tac.toe$symbol.op
x <<- x ; y <<- y
# Mode 0, Two Players
if(mode==0){
turn <- rep(c(0, 1), length.out=9)
if(is.na(place.na[x, y])){
cat("This square is taken !")
}else{
if(turn[k]==0){
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
}
if(turn[k]==1){
text(x, y, symbol.op, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 1
}
k <<- k + 1
}
}
# Mode 1, Random AI
if(mode==1){
if(is.na(place.na[x, y])){
cat("This square had been chosen !")
}else{
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
isGameOver()
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-1 | total.2==-1){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(all(is.na(place.na))){
isGameOver()
}else if(total.1==-1 | total.2==-1 | total.3==-1 | total.4==-1){
attack()
}else{
defend()
}
}
}
# Mode 2, Hard AI
if(mode==2){
if(is.na(place.na[x, y])){
cat("This square is taken!")
}else{
# AI First Turn
if(sum(is.na(place.na))==0){
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
if(is.na(place.na[2, 2])==F){
text(2, 2, symbol.op, cex=6, font=2)
place.na[2, 2] <<- NA
value[2, 2] <<- 1
}else{
corner.1 <- sample(c(1, 3), 1) ; corner.2 <- sample(c(1, 3), 1)
text(corner.1, corner.2, symbol.op, cex=6, font=2)
place.na[corner.1, corner.2] <<- NA
value[corner.1, corner.2] <<- 1
}
# AI Second Turn
}else if(sum(is.na(place.na))==2){
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-3 | total.2==-3){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==-3 | total.2==-3 | total.3==-3 | total.4==-3){
defend()
}else{
total.1 <- value[2, 1] + value[2, 2] + value[2, 3]
total.2 <- value[1, 2] + value[2, 2] + value[3, 2]
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==1 | total.2==1 | total.3==1 | total.4==1){
if((value[2, 2]==1 & total.3==1) | (value[2, 2]==1 & total.4==1)){
vector.side <- c(place.na[2, 1], place.na[1, 2], place.na[3, 2], place.na[2, 3])
rn <- sample(vector.side[!is.na(vector.side)], 1)
text(rn-3*rn%/%3.5, rn%/%3.5+1, symbol.op, cex=6, font=2)
place.na[rn-3*rn%/%3.5, rn%/%3.5+1] <<- NA
value[rn-3*rn%/%3.5, rn%/%3.5+1] <<- 1
}else{
matrix.cor <- place.na[c(1, 3), c(1, 3)]
rn <- sample(matrix.cor[!is.na(matrix.cor)], 1)
text(rn-3*rn%/%3.5, rn%/%3.5+1, symbol.op, cex=6, font=2)
place.na[rn-3*rn%/%3.5, rn%/%3.5+1] <<- NA
value[rn-3*rn%/%3.5, rn%/%3.5+1] <<- 1
}
}else{
if((x==1 & y==2) | (x==3 & y==2)){
rn <- sample(c(1, 3), 1)
text(x, rn, symbol.op, cex=6, font=2)
place.na[x, rn] <<- NA
value[x, rn] <<- 1
}else if((x==2 & y==3) | (x==2 & y==1)){
rn <- sample(c(1, 3), 1)
text(rn, y, symbol.op, cex=6, font=2)
place.na[rn, y] <<- NA
value[rn, y] <<- 1
}else if((x==1 & y==1) | (x==1 & y==3) | (x==3 & y==1) | (x==3 & y==3)){
text(-x+4, -y+4, symbol.op, cex=6, font=2)
place.na[-x+4, -y+4] <<- NA
value[-x+4, -y+4] <<- 1
}
}
}
# AI Other Turn
}else{
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
isGameOver()
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-1 | total.2==-1){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(all(is.na(place.na))){
isGameOver()
}else if(total.1==-1 | total.2==-1 | total.3==-1 | total.4==-1){
attack()
}else{
defend()
}
}
}
}
isGameOver()
}
 
 
# Allow users to click on program.
 
 
click <- function(tic.tac.toe=ttt){
name <- tic.tac.toe$name
mode <- tic.tac.toe$mode
type <- tic.tac.toe$type
while(length(place.na)==9){
mouse.at <- locator(n = 1, type = "n")
#cat(mouse.at$x,"\t", mouse.at$y, "\n")
x.at <- round(mouse.at$x)
y.at <- round(mouse.at$y)
#cat(x.at,"\t", y.at, "\n")
if(all(is.na(place.na))){
ttt <<- tic.tac.toe(name, mode, type)
}else if(x.at > 3.5 | x.at < 0.5 | y.at > 3.5 | y.at < 0.5){
r <<- r + 1
title(sub=list("Click outside:Quit / inside:Restart", col="deeppink", font=2, cex=2), line=2)
if(r==2){
dev.off()
break
}
}else{
if(r==1){
ttt <<- tic.tac.toe(name, mode, type)
}else{
aim(x.at, y.at)
}
}
}
}
 
 
# Play the game
 
 
start <- function(name="Name", mode=0, type=0){
x11()
ttt <<- tic.tac.toe(name, mode, type)
click()
}
 
#start("name", "mode" = 0 - 2, type = 0,1)
 
</syntaxhighlight>
 
=={{header|Racket}}==
Line 4,506 ⟶ 13,089:
V
+ game.rkt -- Written in Lazy Racket, defines general classes for the game and players.
| Knows nothing about tick-tack-toe, oronly anyabout otherzero-sum particular game.two-player
| turn-taking games with perfect information in general.
V
+ tick-tack.rkt -- Written in Racket, implements the tick-tack-toe game.
Line 4,512 ⟶ 13,096:
 
The <tt>minimax.rkt</tt> module:
<langsyntaxhighlight lang="racket">
#lang lazy
(provide minimax)
Line 4,533 ⟶ 13,117:
(next (cdr x)
(min β (minimax (car x) α β (not max-player))))))]))))
</langsyntaxhighlight>
 
The <tt>game.rkt</tt> module:
 
<langsyntaxhighlight lang="racket">
#lang lazy
(require racket/class
Line 4,565 ⟶ 13,149:
;; optimal-move :: State -> Move
;; Choses the optimal move.
;; If several equipollentequivalent moves exist -- choses one randomly.
(define/public ((optimal-move look-ahead) S)
(! (argmax (λ (m) (! (minimax (game-tree S m look-ahead))))
Line 4,647 ⟶ 13,231:
(set-field! opponent p2 p1)
(send p1 your-turn initial-state))
</syntaxhighlight>
</lang>
 
The <tt>tick-tack.rkt</tt> module:
<langsyntaxhighlight lang="racket">#lang racket
 
(require "game.rkt"
Line 4,741 ⟶ 13,325:
(new (interactive-player o%) [name "Dummy"] [look-ahead 0]))
 
</syntaxhighlight>
</lang>
 
Sample games:
Line 4,868 ⟶ 13,452:
As an example of another zero-sum game consider the classical [http://en.wikipedia.org/wiki/Nim Nim] game:
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 4,908 ⟶ 13,492:
(define player-B
(new (interactive-player second%) [name "B"] [look-ahead 4]))
</syntaxhighlight>
</lang>
 
Computer plays with the computer:
Line 4,938 ⟶ 13,522:
 
With use of memoization it is easy to train automatic players so that they would never lose and play very fast.
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.03}}
The computer plays a random game.
 
<syntaxhighlight lang="raku" line>my @board = 1..9;
my @winning-positions = [0..2], [3..5], [6..8], [0,3,6], [1,4,7], [2,5,8],
[0,4,8], [6,4,2];
 
sub get-winner() {
for @winning-positions {
return (@board[|$_][0], $_) if [eq] @board[|$_];
}
}
 
sub free-indexes() {
@board.keys.grep: { @board[$_] eq any(1..9) }
}
 
sub ai-move() {
given free-indexes.pick {
@board[$_] = 'o';
say "I go at: { $_ + 1 }\n";
}
}
 
sub print-board() {
print "\e[2J";
say @board.map({ "$^a | $^b | $^c" }).join("\n--+---+--\n"), "\n";
}
 
sub human-move() {
my $pos = prompt "Choose one of { (free-indexes() »+» 1).join(",") }: ";
if $pos eq any(free-indexes() »+» 1) {
@board[$pos - 1] = 'x';
} else {
say "Sorry, you want to put your 'x' where?";
human-move();
}
}
 
for flat (&ai-move, &human-move) xx * {
print-board;
last if get-winner() or not free-indexes;
.();
}
 
if get-winner() -> ($player, $across) {
say "$player wins across [", ($across »+» 1).join(", "), "].";
} else {
say "How boring, a draw!";
}</syntaxhighlight>
 
=={{header|REXX}}==
This REXX program uses an analytical solution instead of hard─fast choices that can be
Options:
:*assumed allowfor user to specify anya &nbsp; NxN 3&times;3 &nbsp; size tic-tac-toegame gridboard.
 
:* allow user to specify who plays first (default is the user)
Options used within the REXX program:
:* allow user to specify what markers (symbols) to be used (can use hex pairs)
::* &nbsp; a (single)separate numbered grid is used instead of coördinates for easier marker placement specification
::* &nbsp; the game board is separated from the numbered grid, this makes it much easier to see the playing field
:* allows user to quit (exit) the game at any time
::* &nbsp; straight lines (wins) are handled dynamically instead of hard─coding them
:* allows the human player to win (if human goes first and makes a certain move)
::* &nbsp; allows the human player to:
<lang rexx>/*REXX program plays (with a human) the tic-tac-toe game on an NxN grid.*/
::::* &nbsp; specify any &nbsp; '''N'''&times;'''N''' &nbsp; size tic─tac─toe board &nbsp; (a square grid)
oops =$ '***error!*** '; cell# ='cell number' /*a couple of literals*/
::::* &nbsp; specify who plays first &nbsp; (default is the human)
$=copies('─',9) /*eyecatcher literal for messages*/
::::* &nbsp; specify what markers (symbols) to be used for both players &nbsp; (can use hexadecimal pairs)
sing='│─┼'; jam='║'; bar='═'; junc='╬'; dbl=jam || bar || junc
::::* &nbsp; quit (exit) the game at any time
sw=80-1 /*LINESIZE() bif would be better.*/
::::* &nbsp; win &nbsp; (if the human goes first &nbsp; ''and'' &nbsp; makes a certain move)
parse arg N hm cm .,@.; if N=='' then N=3; oN=N /*specifying some args?*/
 
N=abs(N); NN=N*N; middle=NN%2+N%2 /*if N < 0, computer goes first.*/
<br>A fair amount of code was dedicated to error detection &nbsp; and &nbsp; the displaying of error messages, &nbsp; and
if N<2 then do; say oops 'tic-tac-toe grid is too small: ' N; exit; end
<br>also the presentation of the tic─tac─toe game boards (grids).
pad=copies(left('',sw%NN),1+(N<5)) /*display padding: 6x6 in 80 cols*/
<syntaxhighlight lang="rexx">/*REXX program plays (with a human) the tic─tac─toe game on an NxN grid. */
if hm=='' then hm='X'; if cm=='' then cm='O' /*markers: Human, Computer*/
$= copies('─', 9) /*eyecatcher for error messages, prompt*/
hm=aChar(hm,'human'); cm=aChar(cm,'computer') /*process the markers.*/
ifoops hm==cm $ then cm='X***error*** ' /*Humanliteral for wantswhen thean "O"?error happens. Sheesh! */
single = '│─┼'; jam= "║"; bar= '═'; junc= "╬"; dbl=jam || bar || junc
if oN<0 then call Hmove middle /*comp moves 1st? Choose middling*/
sw = linesize() - 1 else call showGrid /*···alsoobtain width checksof forthe winsterminal &(less draws1)*/
parse arg N hm cm .,@. do forever /*'tilobtain theoptional cowsarguments comefrom home, bythe gumCL*/
if N=='' | N=="," then N=3; oN=N /*N not specified? call CBLF Then use /*do carbon-based lifeform's movedefault.*/
N = abs(N) call Hal /*figureif HalN the< 0. then computer's movegoes first. */
NN = N*N end /*forever····showGridcalculate the square of N. does wins & draws*/
middle = NN % 2 + N % 2 /* " " middle " the grid. */
/*──────────────────────────────────ACHAR subroutine────────────────────*/
aChar:if parseN<2 arg xthen do; L=length(x) say oops 'tic─tac─toe grid is too small: ' N; exit 13; /*process markers.*/end
if Lpad==1 left('', sw % NN) then return x /*display padding: 6x6 /*1in char,80 as iscolumns. */
if Lhm==2 & datatype(x,'X') then returnhm= "X"; x2c(x) /*2define chars,the hexmarker for a human. */
if Lcm==3 & datatype(x,'W') then returncm= "O" d2c(x) /*3 chars, decimal " " " " the computer. */
hm= aChar(hm, 'human') /*determine if the marker is legitimate*/
say oops 'illegal character or character code for' arg(2) "marker: " x
exit cm= aChar(cm, 'computer') /* " /*stick a" fork in" " " " it, we're done.*/
parse upper value hm cm with uh uc /*use uppercase values is markers: X x*/
/*──────────────────────────────────CBLF subroutine─────────────────────*/
if uh==uc then cm= word('O X', 1 + (uh=="O") ) /*The human wants Hal's marker? Swap. */
CBLF: prompt='Please enter a' cell# "to place your next marker ["hm'] (or Quit):'
if oN<0 then call Hmove middle /*Hal moves first? Then choose middling*/
do forever; say $ prompt; parse pull x 1 ux 1 ox; upper ux
else call showGrid /*showGrid also checks for wins & draws*/
if datatype(ox,'W') then ox=ox/1 /*maybe normalize cell#: +0007. */
 
select
/*tic─tac─toe game───►*/ do forever /*'til the cows come home (or QUIT). */
when abbrev('QUIT',ux,1) then call tell 'quitting.'
/*tic─tac─toe game───►*/ call CBLF /*process carbon─based lifeform's move.*/
when x='' then iterate /*Nada? Try again.*/
/*tic─tac─toe game───►*/ call Hal /*determine Hal's (the computer) move.*/
when words(x)\==1 then say oops "too many" cell# 'specified:' x
/*tic─tac─toe game───►*/ end /*forever*/ /*showGrid subroutine does wins & draws*/
when \datatype(x,'N') then say oops cell# "isn't numeric: " x
/*──────────────────────────────────────────────────────────────────────────────────────*/
when \datatype(x,'W') then say oops cell# "isn't an integer: " x
aChar: parse arg x,whoseX; when xL=0length(x) then say oops cell# "can't be zero: " x/*process markers.*/
when x<0 if L==1 then say oops cell# "can't be negative: " then return testB( x ) /*1 char, as is. */
when x>NN if L==2 & datatype(x, 'X') then sayreturn oopstestB( cell#x2c(x) "can't) exceed " /*2 chars, hex. NN*/
when @.ox\ if L==3 & datatype(x, 'W') & , then say oops cell# "is already occupied: " x /*3 chars, decimal*/
otherwise x>=0 & x<256 leave then return testB( d2c(x) ) /*do···and in foreverrange.*/
say oops 'illegal character or character code for' whoseX "marker: " x
end /*select*/
exit 13 /*stick a fork in it, we're all done. */
end /*forever*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
@.ox=hm /*place a marker for the human.*/
CBLF: prompt='Please enter a cell number to place your next marker ['hm"] (or Quit):"
call showGrid /*and show the tic-tac-toe grid.*/
 
return
do forever; say $ prompt
/*──────────────────────────────────Hal subroutine──────────────────────*/
Hal: select parse pull x 1 ux 1 ox; upper ux /*Hal will tryget variousversions moves.of answer; uppercase ux*/
if when windatatype(cmox,N-1 'W') then call Hmove ,ecox=ox / 1 /*normalize cell number: +0007 winning───► move?7 */
when win(hm,N-1) then call Hmove ,ec /*(division blockingby move?unity normalizes a num.)*/
when @.middle==''select then call Hmove middle /*perform some validations centerof move.X (cell#)*/
when @.N.N==abbrev('QUIT' ,ux,1) then call Hmovetell ,N N /*bR corner move'quitting. */'
when @.N.1=x='' then calliterate Hmove ,N 1 /*bLNada? corner move.Try again.*/
when @.1.Nwords(x)\==''1 then call Hmove ,1 Nthen say oops "too many" /*tRcell# 'specified:' corner move. */x
when @.1.1==\datatype(x, 'N' ) then callsay Hmoveoops ,1"cell number isn't numeric: 1" /*tL corner move. */x
otherwise when \datatype(x, 'W') then say oops "cell number isn't an integer: call" Hmove ,ac /*some blank cell.*/x
when x=0 then say oops "cell number can't be zero: " x
end /*select*/
when x<0 then say oops "cell number can't be negative: " x
return
when x>NN then say oops "cell number can't exceed " NN
/*──────────────────────────────────HMOVE subroutine────────────────────*/
when @.ox\=='' then say oops "cell number is already occupied: " x
Hmove: parse arg Hplace,dr dc; if Hplace=='' then Hplace = (dr-1)*N + dc
@.Hplace=cm otherwise leave /*put marker for Hal the computerforever*/
end /*select*/
say; say $ 'computer places a marker ['cm"] at cell number " Hplace
 
call showGrid
end /*forever*/
return
/* [↓] OX is a normalized version of X*/
/*──────────────────────────────────SHOWGRID subroutine─────────────────*/
showGrid: _=0; open @.ox=0; hm cW=5; cH=3 /*cellplace width,a cellmarker heightfor the human (CLBF). */
call showGrid /*and display the tic─tac─toe grid. */
do r=1 for N; do c=1 for N; _=_+1; @.r.c=@._; open=open|@._==''; end; end
return
say; z=0 /* [↑] create grid coörds.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
do j=1 for N /* [↓] show grids&markers.*/
Hal: select do t=1 for cH; _=; __= /*mk is a marker in a cell /*Hal tries various moves. */
when win(cm, do k=N-1) for then N;call Hmove , if t==2 then z=z+1;ec mk=;/*is this the winning c#=move?*/
when win(hm, N-1) if t==2 then do;call Hmove mk=@.z;, ec c#=z; end /*c# is" " a blocking " cell#*/
when @.middle== '' _=then _||jam||center(mk,cW);call Hmove middle /*pick the __= __||jam||center(c#,cW) cell. */
when @.N.N == '' then call Hmove , N N end /*kbottom right corner cell.*/
when @.N.1 == '' then call Hmove , N 1 /* " left " " */
say pad substr(_,2) pad translate(substr(__,2), sing,dbl)
when @.1.N end == '' then call Hmove , 1 N /*t top right " " */
if jwhen @.1.1 ==N '' then leave;call _=Hmove , 1 1 /* " left " " */
otherwise do b=1 for N; _=_||junc||copies(bar call Hmove ,cW); ac end /*bpick a blank cell in grid*/
say padend substr(_,2) pad translate(substr(_,2),sing,dbl)/*select*/
end /*j*/return
/*──────────────────────────────────────────────────────────────────────────────────────*/
say
Hmove: parse arg Hplace,dr dc; if Hplace=='' then Hplace = (dr - 1)*N + dc
if win(hm) then call tell 'You ('hm") won!"
@.Hplace= cm /*place computer's marker. */
if win(cm) then call tell 'The computer ('cm") won."
say; say $ 'computer places a marker ['cm"] at cell number " Hplace
if \open then call tell 'This tic-tac-toe is a draw.'
call showGrid
return
return
/*──────────────────────────────────TELL subroutine─────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell: do 4; say; end; say center(' 'arg(1)" ",sw,'─'); do 5; say; end
exit showGrid: _= 0; cW= 5; cH= 3; open= 0 /*stickcell awidth, fork in it, we'recell doneheight.*/
do r=1 for N /*construct array of cells.*/
/*──────────────────────────────────WIN subroutine──────────────────────*/
do c=1 for N; _= _ + 1; @.r.c= @._; open= open | @._==''
win: parse arg wm,w; if w=='' then w=N /*see if there are W # of markers*/
ac=; do r=1 for N; _=0; ec= end /*see if any rows are a winner.c*/
end /*r*/ /* [↑] OPEN≡a cell is open*/
do c=1 for N; _=_+ (@.r.c==wm); if @.r.c=='' then ec=r c; end
say /* [↑] create grid coörds.*/
if ec\=='' then @c=ec; if _==N | (_>=w & ec\=='') then return 1
end z= /*r*/0; do j=1 for N /*if w=N-1,[↓] checking for nearshow wingrids&markers.*/
do ct=1 for NcH; _=0; ec __= /*seeMK ifis any colsa marker arein a winnercell.*/
do rk=1 for N; _=_+ (@.r.c==wm); if @.r.ct==''2 then ecz=r cz + 1; end mk=; c#=
if ec\t==''2 then @cdo; mk=ec @.z; if _==N | (_> c#=w &z ec\=='') then return 1 /*c# is cell number*/
end /*r*/ /*EC is a r,c version of cell #*/end
_=0; ec= _= _ || jam /*see if|| winning descendingcenter(mk, diag.*/cW)
do d=1 for N; _=_+ (@.d.d==wm); if @.d.d=='' then ec __=d d;__ end || jam || center(c#, cW)
end /*k*/
if _==N | (_>=w & ec\=='') then return 1
_=0; ec=; r=0 say pad substr(_, 2) pad /*seetranslate( ifsubstr(__, winning2), ascendingsingle, diag.*/dbl)
end /*t*/ /* [↑] show a line*/
do c=N for N by -1; r=r+1; _=_+ (@.r.c==wm); if @.r.c=='' then ec=r c
if j==N then leave
end /*r*/
_=
if _==N | (_>=w & ec\=='') then return 1
do b=1 for N; _= _ || junc || copies(bar, cW)
return 0</lang>
end /*b*/ /* [↑] a grid part*/
'''output''' when using the input of: <tt> -3 </tt>
say pad substr(_, 2) pad translate( substr(_, 2), single, dbl)
<br>(a negative 3 indicates a grid of <tt> 3x3 </tt> and that the computer should play first.)
end /*j*/
say
if win(hm) then call tell 'You ('hm") won"copies('!',random(1, 5) )
if win(cm) then call tell 'The computer ('cm") won."
if \open then call tell 'This tic─tac─toe game is a draw (a cat scratch).'
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell: do 4; say; end; say center(' 'arg(1)" ", sw, '─'); do 5; say; end; exit
/*──────────────────────────────────────────────────────────────────────────────────────*/
testB: parse arg bx; if bx\==' ' then return bx /*test if the marker isn't a blank.*/
say oops 'character code for' whoseX "marker can't be a blank."
exit 13 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
win: parse arg wm,w; if w=='' then w= N /* [↓] see if there is a win. */
ac= /* [↓] EC ≡ means Empty Cell. */
do r=1 for N; _= 0; ec= /*see if any rows are a winner*/
do c=1 for N; _= _ + (@.r.c==wm) /*count the # of markers in col*/
if @.r.c=='' then ec= r c /*Cell empty? Then remember it*/
end /*c*/ /* [↓] AC≡means available cell*/
if ec\=='' then ac=ec /*Found an empty? Then use it.*/
if _==N | (_>=w & ec\=='') then return 1==1 /*a winner has been determined.*/
end /*r*/ /*w=N-1? Checking for near win*/
 
do c=1 for N; _= 0; ec= /*see if any cols are a winner*/
do r=1 for N; _= _ + (@.r.c==wm) /*count the # of markers in row*/
if @.r.c=='' then ec= r c /*Cell empty? Then remember it*/
end /*r*/
if ec\=='' then ac= ec /*Found an empty? Then remember*/
if _==N | (_>=w & ec\=='') then return 1==1 /*a winner has been determined.*/
end /*c*/
_= 0; ec= /*EC≡location of an empty cell.*/
do d=1 for N; _= _ + (@.d.d==wm) /*A winning descending diag. ? */
if @.d.d=='' then ec= d d /*Empty cell? Then note cell #*/
end /*d*/
 
if _==N | (_>=w & ec\=='') then return 1==1 /*a winner has been determined.*/
_= 0; r= 1
do c=N for N by -1; _=_ + (@.r.c==wm) /*A winning ascending diagonal?*/
if @.r.c=='' then ec= r c /*Empty cell? Then note cell #*/
r= r + 1 /*bump the counter for the rows*/
end /*c*/
 
if _==N | (_>=w & ec\=='') then return 1==1 /*a winner has been determined.*/
return 0==1 /*no winner " " " */</syntaxhighlight>
This REXX program makes use of &nbsp; '''LINESIZE''' &nbsp; REXX program (or BIF) which is used to determine the screen width (or linesize) of the terminal (console); &nbsp; this is used to determine the amount of padding for a centered display of the two grids.
 
The &nbsp; '''LINESIZE.REX''' &nbsp; REXX program is included here &nbsp; ──► &nbsp; [[LINESIZE.REX]]. <br><br>
{{out|output|text=&nbsp; when using the input of: &nbsp; &nbsp; <tt> -3 </tt>}}
 
(a negative &nbsp; '''3''' &nbsp; indicates a grid of &nbsp; '''3<small>x</small>3''' &nbsp; and that the computer should play first.)
<br><br>Note: &nbsp; the user input is shown along with the program output.
<pre style="height:95ex;overflow:scroll153ex">
───────── computer places a marker [O] at cell number 5
 
│ │
1 │ 2 │ 3
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
O O 4 │ 5 │ 6
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
7 │ 8 │ 9
│ │
 
───────── Please enter a cell number to place your next marker [X] (or Quit):
2 ◄■■■■■■■■■■ human player's move.
2
 
│ │
X X 1 │ 2 │ 3
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
O O 4 │ 5 │ 6
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
7 │ 8 │ 9
│ │
 
 
───────── computer places a marker [O] at cell number 1 9
 
│ │
O X X ║ 1 │ 2 │ 3
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
O O 4 │ 5 │ 6
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
O 7 │ 8 │ 9
│ │
 
───────── Please enter a cell number to place your next marker [X] (or Quit):
1 ◄■■■■■■■■■■ human player's move.
9
 
│ │
O X X X 1 │ 2 │ 3
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
O O 4 │ 5 │ 6
│ │
═════╬═════╬═════ ═════╬═════╬═════ ─────┼─────┼─────
│ │
X O 7 │ 8 │ 9
│ │
 
───────── computer places a marker at cell number 7
 
───────── computer places a marker [O] at cell number 3
║ ║ │ │
O ║ X ║ 1 │ 2 │ 3
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
║ O ║ 4 │ 5 │ 6
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
O ║ ║ X 7 │ 8 │ 9
║ ║ │ │
 
║ ║ │ │
───────── Please enter a cell number to place your next marker (or Quit):
X ║ X ║ O 1 │ 2 │ 3
3
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
║ O ║ 4 │ 5 │ 6
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
║ ║ O 7 │ 8 │ 9
║ ║ │ │
 
───────── Please enter a cell number to place your next marker [X] (or Quit):
║ ║ │ │
7 ◄■■■■■■■■■■ human player's move.
O ║ X ║ X 1 │ 2 │ 3
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
║ O ║ 4 │ 5 │ 6
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
O ║ ║ X 7 │ 8 │ 9
║ ║ │ │
 
║ ║ │ │
───────── computer places a marker at cell number 4
X ║ X ║ O 1 │ 2 │ 3
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
║ O ║ 4 │ 5 │ 6
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
X ║ ║ O 7 │ 8 │ 9
║ ║ │ │
 
║ ║ │ │
O ║ X ║ X 1 │ 2 │ 3
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
O ║ O ║ 4 │ 5 │ 6
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
O ║ ║ X 7 │ 8 │ 9
║ ║ │ │
 
───────── computer places a marker [O] at cell number 6
 
║ ║ │ │
X ║ X ║ O 1 │ 2 │ 3
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
║ O ║ O 4 │ 5 │ 6
║ ║ │ │
═════╬═════╬═════ ─────┼─────┼─────
║ ║ │ │
X ║ ║ O 7 │ 8 │ 9
║ ║ │ │
 
 
 
 
─────────────────────────── The computer (O) won. ───────────────────────────
 
────────────────────────────── The computer (O) won. ──────────────────────────────
</pre>
'''output''' &nbsp; when using the input of: &nbsp; <tt> 5 &nbsp; db </tt>
<br>(which indicates a grid of <tt>&nbsp; '''5x5''' </tt>&nbsp; and that the marker for the human is a hex hexadecimal &nbsp; '''db''' &nbsp; [█].)
<pre style="height:80ex;overflow:scroll153ex">
║ ║ ║ ║ │ │ │ │
║ ║ ║ ║ 1 │ 2 │ 3 │ 4 │ 5
Line 5,187 ⟶ 13,876:
║ ║ ║ ║ │ │ │ │
 
───────── Please enter a cell number to place your next marker [█] (or Quit):
5 ◄■■■■■■■■■■ human player's move.
5
 
║ ║ ║ ║ │ │ │ │
Line 5,211 ⟶ 13,900:
 
 
───────── computer places a marker [O] at cell number 14
 
║ ║ ║ ║ │ │ │ │
Line 5,233 ⟶ 13,922:
║ ║ ║ ║ │ │ │ │
 
───────── Please enter a cell number to place your next marker [█] (or Quit):
q ◄■■■■■■■■■■ human player's response.
q
 
 
Line 5,241 ⟶ 13,930:
────────────────────────────────── quitting. ──────────────────────────────────
</pre>
 
=={{header|Ring}}==
 
Easy and simple implementation of tecTacToe in ring programming language with human-human type of game(for now).
 
This implementation is a gui implementation using the default gui provided by the language
 
The tecTacToe.ring is provided [https://github.com/AbdelrahmanGIT/RingSamples/blob/master/src/TecTacToe.ring here]
<syntaxhighlight lang="ring">
Load "guilib.ring"
 
#Provide a list to save each button status in numeric readable format
#0=nothing 1=X 2=O
lst=[]
 
#Provide onScreen button status and style
btns=[]
 
#Define who has the turn
isXTurn=true
 
 
app=new qApp
{
 
frmMain=new qMainWindow()
{
setWindowTitle("TicTacToe!")
resize(300,320)
move(200,200)
//buttons
pos=0
for y=0 to 2
for x=0 to 2
//Creating Buttons on the screen
pos++
Add(lst,0)
Add(btns,new qPushButton(frmMain)
{
setGeometry(x*100,y*100,100,100)
setText("-")
setclickevent("Disp(" + pos +")")
setstylesheet("font-size:24pt ; font: bold ; color:yellow ; background-color: green")
})
next
next
//StatusBar
status=new qStatusBar(frmMain)
{
showMessage("Ready",0)
}
setwindowflags(Qt_dialog)
setStatusbar(status)
show()
}
exec()
}
 
//Restart the game by re init buttons status
func reStart
for i=1 to 9
lst[i]=0
btns[i].setText("-")
next
isXTurn=true
 
func Disp x
if isXTurn=true and lst[x]=0
btns[x].setText("X")
lst[x]=1
isXTurn=false
but isXTurn=false and lst[x]=0
btns[x].setText("O")
lst[x]=2
isXTurn=true
ok
 
winner = CheckWinner()
#if there is no Winner and still there is ability to winner
#continue playing.
if winner<1 return ok
 
//Who is the winner!
switch winner
on 1
new qMessagebox(frmMain)
{
SetWindowTitle("We have a winner!")
SetText("Good job X you won!")
show()
}
on 2
new qMessagebox(frmMain)
{
SetWindowTitle("We have a winner!")
SetText("Good job O you won!")
show()
}
on 3
new qMessagebox(frmMain)
{
SetWindowTitle("Oh no it's a tie")
SetText("Oh no it's a tie!")
show()
}
off
reStart()
 
func CheckWinner
//vertical check
for v=1 to 9 step 3
if lst[v]!=0 and lst[v+1]!=0 and lst[v+2]!=0
if lst[v]=lst[v+1] and lst[v+1]=lst[v+2]
return lst[v]
ok
ok
next
//horzintal
for h=1 to 3
if lst[h]!=0 and lst[h+3]!=0 and lst[h+6]!=0
if lst[h]=lst[h+3] and lst[h+3]=lst[h+6]
return lst[h]
ok
ok
next
//Cross
if lst[1]!=0 and lst[5]!=0 and lst[9]!=0
if lst[1]=lst[5] and lst[5]=lst[9] return lst[1] ok
ok
if lst[3]!=0 and lst[5]!=0 and lst[7]!=0
if lst[3]=lst[5] and lst[5]=lst[7] return lst[3] ok
ok
//tie
tie=true
for i=1 to 9
if lst[i]=0 tie=false exit ok
next
if tie=true return 3 ok return 0
</syntaxhighlight>
 
{{out}}
[[http://ring-lang.sourceforge.net/tictactoe.jpg image]]
 
=={{header|Ruby}}==
Line 5,249 ⟶ 14,080:
This implementation stores the board as a one-dimensional array and hardcodes all possible straight lines in <code>LINES</code>, rather than storing the board as a two-dimensional matrix and identifying straight lines dynamically.
 
<syntaxhighlight lang="ruby">module TicTacToe
<lang ruby>require 'set'
 
module TicTacToe
LINES = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]]
Line 5,257 ⟶ 14,086:
def initialize(player_1_class, player_2_class)
@board = Array.new(10) # we ignore index 0 for convenience
@free_positions = Set.new(1..9)
@players = [player_1_class.new(self), player_2_class.new(self)]
@current_player_id = 0
@players = [player_1_class.new(self, "X"), player_2_class.new(self, "O")]
@players[@current_player_id].marker = "X"
puts "#{current_player} goes first."
@players[other_player_id].marker = "O"
puts "#{@players[@current_player_id]} goes first."
end
attr_reader :board, :free_positions, :current_player_id
def play
loop do
place_player_marker(current_player)
player = @players[@current_player_id]
place_player_markerif player_has_won?(playercurrent_player)
puts "#{current_player} wins!"
if player_has_won?(player)
puts "#{player} wins!"
print_board
return
Line 5,285 ⟶ 14,109:
switch_players!
end
end
def free_positions
(1..9).select {|position| @board[position].nil?}
end
def place_player_marker(player)
position = player.select_position!
puts "#{player} selects #{player.marker} position #{position}"
@board[position] = player.marker
@free_positions.delete(position)
end
Line 5,302 ⟶ 14,128:
def board_full?
@free_positions.empty?
end
Line 5,311 ⟶ 14,137:
def switch_players!
@current_player_id = other_player_id
end
def current_player
@players[current_player_id]
end
Line 5,318 ⟶ 14,148:
def turn_num
10 - @free_positions.size
end
Line 5,333 ⟶ 14,163:
class Player
def initialize(game, marker)
@game = game
@marker = nilmarker
end
attr_accessorattr_reader :marker
end
class HumanPlayer < Player
def select_position!
@game.print_board
loop do
Line 5,365 ⟶ 14,195:
end
def select_position!
opponent_marker = @game.opponent.marker
Line 5,435 ⟶ 14,265:
puts
players_with_human = [HumanPlayer, ComputerPlayer].shuffle
Game.new(*players_with_human).play</langsyntaxhighlight>
 
{{out}}
sample output
<pre>
Computer0 goes first.
Line 5,503 ⟶ 14,333:
X | O | X</pre>
 
=={{header|Run BASICRust}}==
<syntaxhighlight lang="rust">
<lang runbasic>' ---------------------------
use GameState::{ComputerWin, Draw, PlayerWin, Playing};
' TIC TAC TOE
' ---------------------------
winBox$ = "123 456 789 159 147 258 369 357"
boxPos$ = "123 231 456 564 789 897 159 591 357 753 132 465 798 174 285 396 159 471 582 693 147 258 369 195 375"
ai$ = "519628374"
ox$ = "OX"
[newGame]
for i = 1 to 9
box$(i) = ""
next i
goto [shoTic]
 
use rand::prelude::*;
[loop]
for j = 1 to 2
tic$ = mid$(ox$,j,1)
for i = 1 to 25
b$ = word$(boxPos$,i," ")
b1 = val(mid$(b$,1,1))
b2 = val(mid$(b$,2,1))
b3 = val(mid$(b$,3,1))
if box$(b1) = tic$ AND box$(b2) = tic$ AND box$(b3) = "" then
box$(b3) = "O"
goto [shoTic]
end if
next i
next j
if box$(1) = "O" AND box$(5) = "X" and box$(9) = "X" then
if box$(3) = "" then
box$(3) = "O"
goto [shoTic]
end if
if box$(7) = "" then
box$(7) = "O"
goto [shoTic]
end if
end if
for i = 1 to 9
b1 = val(mid$(ai$,i,1))
if box$(b1) = "" then
box$(b1) = "O"
exit for
end if
next i
 
#[derive(PartialEq, Debug)]
[shoTic]
enum GameState {
cls
PlayerWin,
' ----------------------------------------
ComputerWin,
' show tic tac toe screen
Draw,
' ----------------------------------------
Playing,
html "<table border=1 width=300px height=225px><TR>"
}
for i = 1 to 9
html "<td align=center width=33%><h1>"
if box$(i) <> "" then
html box$(i)
else
button #box, " ";box$(i);" ", [doTic]
#box setkey(str$(i))
end if
if i mod 3 = 0 then html "</tr><tr>"
next i
html "</table>"
gosub [checkWin]
wait
 
type Board = [[char; 3]; 3];
[doTic]
box$(val(EventKey$)) = "X"
turn = 1
gosub [checkWin]
goto [loop]
 
fn main() {
' --- check for a winner ----------
let mut rng = StdRng::from_entropy();
[checkWin]
for i = 1 to 8
b$ = word$(winBox$,i," ")
b1 = val(mid$(b$,1,1))
b2 = val(mid$(b$,2,1))
b3 = val(mid$(b$,3,1))
if box$(b1) = "O" and box$(b2) = "O" and box$(b3) = "O" then
print "You Lose!"
goto [playAgain]
end if
if box$(b1) = "X" and box$(b2) = "X" and box$(b3) = "X" then
print "You Win!"
goto [playAgain]
end if
next i
 
let mut board: Board = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']];
moveCount = 0
 
for i = 1 to 9
draw_board(board);
if box$(i) <> "" then moveCount = moveCount + 1
loop {
next i
player_turn(&mut board);
if moveCount = 9 then
if check_win(board) != Playing {
print "Draw!"
break;
goto [playAgain]
}
end if
computer_turn(&mut rng, &mut board);
RETURN
if check_win(board) != Playing {
break;
}
draw_board(board);
}
 
draw_board(board);
let announcement = match check_win(board) {
PlayerWin => "The Player has won!",
ComputerWin => "The Computer has won!",
Draw => "Draw!",
Playing => unreachable!(),
};
println!("{}", announcement);
}
 
fn is_empty(cell: &char) -> bool {
*cell != 'X' && *cell != 'O'
}
 
fn check_win(board: Board) -> GameState {
// check for win
for (i, row) in board.iter().enumerate() {
if row[0] == row[1] && row[0] == row[2] {
return which_win(row[0]);
} else if board[0][i] == board[1][i] && board[0][i] == board[2][i] {
return which_win(board[0][i]);
}
}
if board[0][0] == board[1][1] && board[0][0] == board[2][2] {
return which_win(board[0][0]);
} else if board[0][2] == board[1][1] && board[0][2] == board[2][0] {
return which_win(board[0][2]);
}
 
// check if it's not a draw
let is_draw = board.iter().flatten().any(is_empty);
if is_draw {
Playing
} else {
Draw
}
}
 
fn which_win(s: char) -> GameState {
match s {
'X' => PlayerWin,
'O' => ComputerWin,
_ => unreachable!(),
}
}
 
fn player_turn(board: &mut Board) {
use std::io;
 
println!("Player, enter your field of choice!: ");
let mut ln = String::new();
io::stdin()
.read_line(&mut ln)
.expect("Failed to read stdin");
let choice = ln.trim().parse::<usize>().expect("Failed to parse input");
let row = (choice - 1) / 3;
let col = (choice - 1) % 3;
 
if board[row][col] == 'X' || board[row][col] == 'O' {
println!("Someone already took this field!");
player_turn(board);
} else {
board[row][col] = 'X';
}
}
 
fn computer_turn<R: Rng>(rng: &mut R, board: &mut Board) {
let possible_choices: Vec<_> = board
.iter()
.flatten()
.enumerate()
.filter(|&(_, c)| is_empty(c))
.map(|(i, _)| i)
.collect();
 
let choice = possible_choices.choose(rng).unwrap();
println!("Computer chose: {}", choice);
let row = choice / 3;
let col = choice % 3;
board[row][col] = 'O';
}
 
fn draw_board(board: Board) {
for row in &board {
println!("{} {} {}", row[0], row[1], row[2]);
}
}
 
</syntaxhighlight>
{{out}}
<pre>
1 2 3
4 5 6
7 8 9
Player, enter your field of choice!:
1
Computer chose: 6
X 2 3
4 5 6
O 8 9
Player, enter your field of choice!:
5
Computer chose: 7
X 2 3
4 X 6
O O 9
Player, enter your field of choice!:
9
X 2 3
4 X 6
O O X
The Player has won!
</pre>
 
[playAgain]
input "Play again (y/n)";p$
if upper$(p$) = "Y" then goto [newGame]
end</lang>
 
=={{header|Scala}}==
===Functional implementation.===
 
Computer vs. human. Human starts. Computer plays 'O' and human plays 'X'.
Computer moves are legal, but random.
<langsyntaxhighlight lang="scala">package object tictactoe {
val Human = 'X'
val Computer = 'O'
Line 5,653 ⟶ 14,528:
 
 
object TicTacToe extends ApplicationApp {
def play(board : Board, turn : Char) {
Line 5,693 ⟶ 14,568:
}
 
}</langsyntaxhighlight>
 
sample output {{out}}(human is always first)
<pre>
1 2 3
Line 5,723 ⟶ 14,598:
X 8 O
You win.</pre>
 
=={{header|Scilab}}==
 
Can be a game of human v. human, human v. machine, or machine v. machine. Machine moves have a hierarchy: firstly, it looks for a winning move; secondly, it looks for a way to block the opponent's victory; lastly, it makes a random move.
 
<syntaxhighlight lang="text">function [] = startGame()
//Board size and marks
N = 3;
marks = ["X" "O"];
//Creating empty board
board = string(zeros(N,N));
for i = 1:(N*N)
board(i) = "";
end
//Initialising players
clc();
players= [%F %F];
players = playerSetup(marks);
//Console header
header = [strsplit(marks(1)+" is ----")';...
strsplit(marks(2)+" is ----")'];
for i = 1:2
if players(i) then
header(i,6:10) = strsplit("P"+string(i)+". ");
else
header(i,6:10) = strsplit("COMP.");
end
end
//Game loop
sleep(1000);
win_flag = %F;
count = 0;
while count<N*N
//Clear console, and print header and board
clc();
printf("%s\n %s\n",strcat(header(1,:)),strcat(header(2,:)));
dispBoard(board);
//Find which player should move
player_n = modulo(count,2) + 1;
if players(player_n) == %T then
//Human plays
pos = [];
valid_move = %F;
disp(marks(player_n)+"''s turn.");
while valid_move ~= %T
[pos,valid_move] = readHumanMove(board);
if ~valid_move then
disp("You should input a valid cell number.");
end
end
if valid_move then
board = updateBoard(board,pos,marks(player_n));
else
error("Invalid move.");
end
else
//Computer plays
disp("Computer is playing.");
board = ComputerMove(board,marks(player_n),marks);
sleep(800);
end
//Count number of movements
count = count + 1;
//Check if the game has finished
[win_flag,winning_mark] = detectWin(board)
if win_flag then
break
end
end
//Clear screen at the end of game
clc();
disp("Game finished:");
dispBoard(board);
//Print results
if win_flag then
disp(winning_mark+" won!");
else
disp("It''s a tie.");
end
//Play again?
play_again = "";
while play_again ~= "Y" & play_again ~= "N"
play_again = input("Would you like to play again? (Y/N)","s");
play_again = strsplit(play_again);
play_again = convstr(play_again(1),"u");
if play_again ~= "Y" & play_again ~= "N" then
disp("Invalid answer.");
end
end
if play_again == "Y" then
startGame();
else
disp("Quit game.");
end
endfunction
 
function players = playerSetup(marks)
//Determines who plays which mark
players = [%F %F]; //True for human, Flase for computer
printf("\n%s always starts.\n",marks(1));
for i = 1:2
user_input = "";
while user_input ~= "Y" & user_input ~= "N"
user_input = input("Would you like to play as "+marks(i)+"? (Y/N)","s");
user_input = strsplit(user_input);
user_input = convstr(user_input(1),"u");
if user_input ~= "Y" & user_input ~= "N" then
disp("Invalid answer.");
end
end
//Print choice
if user_input == "Y" then
players(i) = %T;
printf("%s shall be player %d (P%d).\n\n",marks(i),i,i);
else
printf("%s shall be the computer (COMP).\n\n",marks(i));
end
end
endfunction
 
function [] = dispBoard(board)
//Print ASCII board on console
//Get board marks
marks = [" " " "];
mark_inds = find(board ~= "");
if mark_inds ~= [] then
marks(1) = board(mark_inds(1));
mark_inds = find( (board ~= "") & (board ~= marks(1)) );
if mark_inds ~= [] then
marks(2) = board(mark_inds(1));
end
end
//Transpose to display for humans
//[compatibility with readHumanMove()]
disp_board = board';
rows = 3*size(board,'r');
cols = 4*size(board,'c');
ascii_board = string(zeros(rows, cols));
mark_1=[...
strsplit(" |")';...
strsplit(" "+marks(1)+" |")';...
strsplit("___|")'];
mark_2=[...
strsplit(" |")';...
strsplit(" "+marks(2)+" |")';...
strsplit("___|")'];
Blank_mark=[...
strsplit(" |")';...
strsplit(" |")';...
strsplit("___|")'];
for r = ([1:size(board,'r')] - 1 )
for c = ([1:size(board,'c')] - 1)
if disp_board(r+1,c+1) == marks(1) then
ascii_board((r*3 + 1):((r+1)*3),...
(c*4 + 1):((c+1)*4)) = mark_1;
elseif disp_board(r+1,c+1) == marks(2) then
ascii_board((r*3 + 1):((r+1)*3),...
(c*4 + 1):((c+1)*4)) = mark_2;
else
ascii_board((r*3 + 1):((r+1)*3),...
(c*4 + 1):((c+1)*4)) = Blank_mark;
end
end
end
for i = 1:cols
if modulo(i,4)>0 then
ascii_board(rows,i) = " ";
end
end
for i = 1:rows
ascii_board(i,cols) = " ";
end
printf("\n");
for i = 1:size(ascii_board,'r')
printf("%s\n",strcat(ascii_board(i,:)))
end
endfunction
 
function moves_board = availableMoves(board)
//Find empty cells on the board
moves_board = board;
for i = 1:(size(board,'r')*size(board,'c'))
if board(i) == "" then
moves_board(i) = string(i);
else
moves_board(i) = "_";
end
end
endfunction
 
function varargout = readHumanMove(board)
//Read human input
printf("\nAvailable cells:");
moves_board = availableMoves(board);
disp(moves_board');
x = input("\nEnter a move (0 to quit game): ");
valid = %F;
pos = 0;
total = size(moves_board,'r') * size(moves_board,'c');
//Check if it is a valid move
if x == 0 then
disp("Quit game.")
abort
elseif (x>=1 & x<=total) then
if (moves_board(x) == string(x)) then
valid = %T;
pos = x;
end
end
varargout = list(pos,valid);
endfunction
 
function varargout = updateBoard(board,pos,player)
//Add move to the board
if board(pos) ~= "" then
error('Error: Invalid move.');
end
board(pos) = player
varargout = list(board);
endfunction
 
function varargout = detectWin(board)
//Detect if there is a winner or not
win_flag = %F;
winner = "";
//Get board marks
marks = ["" ""];
mark_inds = find(board ~= "");
marks(1) = board(mark_inds(1))
mark_inds = find( (board ~= "") & (board ~= marks(1)) );
marks(2) = board(mark_inds(1));
//If there is a minimum number of moves, check if there is a winner
n_moves = find(~(board == ""));
n_moves = length(n_moves)
if n_moves >= size(board,'r') then
board_X = (board == marks(1));
board_O = (board == marks(2));
for i = 1:size(board,'r')
//Check rows
if find(~board_X(i,:)) == [] then
win_flag = %T;
winner = marks(1);
break
end
if find(~board_O(i,:)) == [] then
win_flag = %T;
winner = marks(2);
break
end
//Check columns
if find(~board_X(:,i)) == [] then
win_flag = %T;
winner = marks(1);
break
end
if find(~board_O(:,i)) == [] then
win_flag = %T;
winner = marks(2);
break
end
end
//Check diagonal
if ~win_flag then
if find(~diag(board_X)) == [] then
win_flag = %T;
winner = marks(1);
elseif find(~diag(board_O)) == [] then
win_flag = %T;
winner = marks(2);
end
end
//Check anti-diagonal
if ~win_flag then
board_X = board_X(:,$:-1:1);
board_O = board_O(:,$:-1:1);
if find(~diag(board_X)) == [] then
win_flag = %T;
winner = marks(1);
elseif find(~diag(board_O)) == [] then
win_flag = %T;
winner = marks(2);
end
end
end
varargout = list(win_flag,winner)
endfunction
 
function threat_pos = findThreat(board,player)
//Returns a list of moves that can finish the game
//Available moves
move_inds = find(~( availableMoves(board) == "_" ));
//If there is a minimum number of moves, check if there is a threat
threat_pos = [];
if (size(board,'r')*size(board,'c')) - length(move_inds) >...
(size(board,'r') - 1) then
for i = 1:length(move_inds)
temp_board = updateBoard(board,move_inds(i),player);
[win_flag,winner] = detectWin(temp_board);
if win_flag & winner == player then
threat_pos = [threat_pos move_inds(i)];
end
end
end
endfunction
 
function varargout = ComputerMove(board,mark,all_marks)
//Atomatically add a move to the board with no human input
//Find winning moves moves
move_inds = findThreat(board,mark);
//If there are no winning moves, find opponent's winning moves
//to block opponent's victory
if move_inds == [] then
if mark == all_marks(1) then
opponent = all_marks(2);
elseif mark == all_marks(2) then
opponent = all_marks(1);
end
move_inds = findThreat(board,opponent);
end
//If there are no winning moves or threats, find all possible moves
if move_inds == [] then
move_inds = find(~( availableMoves(board) == "_" ));
end
//Choose a random move among the selected possible moves
pos = grand(1,"prm",move_inds);
pos = pos(1);
//Update board by adding a new mark
board(pos) = mark;
varargout = list(board);
endfunction
 
startGame()</syntaxhighlight>
 
=={{header|SQL}}==
Basic playable TicTacToe in SQLite using only the sqlite3 CLI.
The CLI wasn't really designed for this, making the interactivity a little bit clunky. However, some of the higher-level constructs in SQL allow for some intriguingly elegant game logic.
<syntaxhighlight lang="sql">
--Setup
drop table if exists board;
create table board (p char, r integer, c integer);
insert into board values('.', 0, 0),('.', 0, 1),('.', 0, 2),('.', 1, 0),('.', 1, 1),('.', 1, 2),('.', 2, 0),('.', 2, 1),('.', 2, 2);
 
 
-- Use a trigger for move events
drop trigger if exists after_moved;
create trigger after_moved after update on board for each row when new.p <> '.' and new.p <> 'O'
begin
 
-- Verify move is valid
select
case
when (select v from msg) like '%Wins!' then raise(ABORT, 'The game is already over.')
when (select old.p from board where rowid = rid) <> '.' then raise(ABORT, 'That position has already been taken. Please choose an available position.')
when new.p <> 'X' then raise(ABORT, 'Please place an ''X''')
end
from (
select rowid rid from board
where p = new.p
except
select p from board where p = old.p
);
-- Check for game over
update msg set v = (
select
case
when max(num) >= 3 then 'X Wins!'
when (select count(*) from board where p = '.') = 0 then 'Cat Wins!'
else 'Move made'
end
from ( -- Is Game Over
select count(*) num from board where p = 'X' group by r union -- Horz
select count(*) num from board where p = 'X' group by c union -- Vert
select count(*) num from board where p = 'X' and r = c union -- Diag TL->BR
select count(*) num from board where p = 'X' and (2-r) = c -- Diag TR->BL
)
);
 
--Have computer player make a random move
update board set p = 'O'
where rowid = (select rid from (select max(rnd),rid from (select rowid rid, random() rnd from board where p = '.')))
and (select v from msg) not like '%Wins!';
--NOTE: SQLite doesn't allow update order by in triggers, otherwise we could just use this beautiful line:
-- update board set p = 'O' where p = '.' order by random() limit 1;
--Check to see if the computer player won
update msg set v = (
select
case
when max(num) >= 3 then 'O Wins!'
else v
end
from ( -- Is Game Over
select count(*) num from board where p = 'O' group by r union -- Horz
select count(*) num from board where p = 'O' group by c union -- Vert
select count(*) num from board where p = 'O' and r = c union -- Diag TL->BR
select count(*) num from board where p = 'O' and (2-r) = c -- Diag TR->BL
)
);
end;
 
-- UI to display the logical board as a grid
drop view if exists ui;
create view ui as
select case when p = '.' then col0.rowid else p end c0, c1, c2
from board as col0
join (select case when p = '.' then board.rowid else p end c1, r from board where c = 1) as col1 on col0.r = col1.r
join (select case when p = '.' then board.rowid else p end c2, r from board where c = 2) as col2 on col0.r = col2.r
where c = 0;
 
drop table if exists msg;
create table msg (v text);
insert into msg values('');
 
-- Readme
select * from ui;
.print "Use this to play:"
.print "->update board set p = 'X' where rowid = ?; select * from ui; select * from msg;"'
 
</syntaxhighlight>
{{out}}
<pre>
(Assuming the above code is in a file called ttt.sql)
sqlite>.read ttt.sql
1|2|3
4|5|6
7|8|9
Use this to play:
update board set p = 'X' where rowid = ?; select * from ui; select * from msg;
 
sqlite> update board set p = 'X' where rowid = 1; select * from ui; select * from msg;
X|2|3
4|5|O
7|8|9
Move made
 
sqlite> update board set p = 'X' where rowid = 2; select * from ui; select * from msg;
X|X|3
4|5|O
7|O|9
Move made
 
sqlite> update board set p = 'X' where rowid = 3; select * from ui; select * from msg;
X|X|X
4|5|O
7|O|9
X Wins!
</pre>
 
=={{header|Swift}}==
Some Basic AI for obvious losing and winning conditions
<syntaxhighlight lang="swift">
import Darwin
 
enum Token : CustomStringConvertible {
case cross, circle
func matches(tokens: [Token?]) -> Bool {
for token in tokens {
guard let t = token, t == self else {
return false
}
}
return true
}
func emptyCell(in tokens: [Token?]) -> Int? {
if tokens[0] == nil
&& tokens[1] == self
&& tokens[2] == self {
return 0
} else
if tokens[0] == self
&& tokens[1] == nil
&& tokens[2] == self {
return 1
} else
if tokens[0] == self
&& tokens[1] == self
&& tokens[2] == nil {
return 2
}
return nil
}
var description: String {
switch self {
case .cross: return "x"
case .circle: return "o"
}
}
}
 
struct Board {
var cells: [Token?] = [nil, nil, nil, nil, nil, nil, nil, nil, nil]
func cells(atCol col: Int) -> [Token?] {
return [cells[col], cells[col + 3], cells[col + 6]]
}
func cells(atRow row: Int) -> [Token?] {
return [cells[row * 3], cells[row * 3 + 1], cells[row * 3 + 2]]
}
func cellsTopLeft() -> [Token?] {
return [cells[0], cells[4], cells[8]]
}
func cellsBottomLeft() -> [Token?] {
return [cells[6], cells[4], cells[2]]
}
func winner() -> Token? {
let r0 = cells(atRow: 0)
let r1 = cells(atRow: 1)
let r2 = cells(atRow: 2)
let c0 = cells(atCol: 0)
let c1 = cells(atCol: 1)
let c2 = cells(atCol: 2)
let tl = cellsTopLeft()
let bl = cellsBottomLeft()
if Token.cross.matches(tokens: r0)
|| Token.cross.matches(tokens: r1)
|| Token.cross.matches(tokens: r2)
|| Token.cross.matches(tokens: c0)
|| Token.cross.matches(tokens: c1)
|| Token.cross.matches(tokens: c2)
|| Token.cross.matches(tokens: tl)
|| Token.cross.matches(tokens: bl) {
return .cross
} else
if Token.circle.matches(tokens: r0)
|| Token.circle.matches(tokens: r1)
|| Token.circle.matches(tokens: r2)
|| Token.circle.matches(tokens: c0)
|| Token.circle.matches(tokens: c1)
|| Token.circle.matches(tokens: c2)
|| Token.circle.matches(tokens: tl)
|| Token.circle.matches(tokens: bl) {
return .circle
}
return nil
}
func atCapacity() -> Bool {
return cells.filter { $0 == nil }.count == 0
}
mutating func play(token: Token, at location: Int) {
cells[location] = token
}
func findBestLocation(for player: Token) -> Int? {
let r0 = cells(atRow: 0)
let r1 = cells(atRow: 1)
let r2 = cells(atRow: 2)
let c0 = cells(atCol: 0)
let c1 = cells(atCol: 1)
let c2 = cells(atCol: 2)
let tl = cellsTopLeft()
let bl = cellsBottomLeft()
if let cell = player.emptyCell(in: r0) {
return cell
} else if let cell = player.emptyCell(in: r1) {
return cell + 3
} else if let cell = player.emptyCell(in: r2) {
return cell + 6
} else if let cell = player.emptyCell(in: c0) {
return cell * 3
} else if let cell = player.emptyCell(in: c1) {
return cell * 3 + 1
} else if let cell = player.emptyCell(in: c2) {
return cell * 3 + 2
} else if let cell = player.emptyCell(in: tl) {
return cell == 0 ? 0 : (cell == 1 ? 4 : 8)
} else if let cell = player.emptyCell(in: bl) {
return cell == 0 ? 6 : (cell == 1 ? 4 : 2)
}
return nil
}
func findMove() -> Int {
let empties = cells.enumerated().filter { $0.1 == nil }
let r = Int(arc4random()) % empties.count
return empties[r].0
}
}
 
extension Board : CustomStringConvertible {
var description: String {
var result = "\n---------------\n"
for (idx, cell) in cells.enumerated() {
if let cell = cell {
result += "| \(cell) |"
} else {
result += "| \(idx) |"
}
if (idx + 1) % 3 == 0 {
result += "\n---------------\n"
}
}
return result
}
}
 
while true {
var board = Board()
print("Who do you want to play as ('o' or 'x'): ", separator: "", terminator: "")
let answer = readLine()?.characters.first ?? "x"
var player: Token = answer == "x" ? .cross : .circle
var pc: Token = player == .cross ? .circle : .cross
print(board)
while true {
print("Choose cell to play on: ", separator: "", terminator: "")
var pos = Int(readLine() ?? "0") ?? 0
while !board.atCapacity() && board.cells[pos] != nil {
print("Invalid move. Choose cell to play on: ", separator: "", terminator: "")
pos = Int(readLine() ?? "0") ?? 0
}
if board.atCapacity() {
print("Draw")
break
}
board.play(token: player, at: pos)
print(board)
if let winner = board.winner() {
print("winner is \(winner)")
break
} else if board.atCapacity() {
print("Draw")
break
}
if let win = board.findBestLocation(for: pc) {
board.play(token: pc, at: win)
} else if let def = board.findBestLocation(for: player) {
board.play(token: pc, at: def)
} else {
board.play(token: pc, at: board.findMove())
}
print(board)
if let winner = board.winner() {
print("winner is \(winner)")
break
}
}
}
</syntaxhighlight>
{{out}}
<pre>
Who do you want to play as ('o' or 'x'): x
 
---------------
| 0 || 1 || 2 |
---------------
| 3 || 4 || 5 |
---------------
| 6 || 7 || 8 |
---------------
 
Choose cell to play on: 4
 
---------------
| 0 || 1 || 2 |
---------------
| 3 || x || 5 |
---------------
| 6 || 7 || 8 |
---------------
 
 
---------------
| o || 1 || 2 |
---------------
| 3 || x || 5 |
---------------
| 6 || 7 || 8 |
---------------
 
Choose cell to play on: 6
 
---------------
| o || 1 || 2 |
---------------
| 3 || x || 5 |
---------------
| x || 7 || 8 |
---------------
 
 
---------------
| o || 1 || o |
---------------
| 3 || x || 5 |
---------------
| x || 7 || 8 |
---------------
 
Choose cell to play on: 1
 
---------------
| o || x || o |
---------------
| 3 || x || 5 |
---------------
| x || 7 || 8 |
---------------
 
 
---------------
| o || x || o |
---------------
| 3 || x || 5 |
---------------
| x || o || 8 |
---------------
 
Choose cell to play on: 5
 
---------------
| o || x || o |
---------------
| 3 || x || x |
---------------
| x || o || 8 |
---------------
 
 
---------------
| o || x || o |
---------------
| o || x || x |
---------------
| x || o || 8 |
---------------
 
Choose cell to play on: 8
 
---------------
| o || x || o |
---------------
| o || x || x |
---------------
| x || o || x |
---------------
 
Draw
Who do you want to play as ('o' or 'x'):
</pre>
 
=={{header|Tailspin}}==
<syntaxhighlight lang="tailspin">
processor Tic-Tac-Toe
@: [position´1..position´9];
 
source isWonOrDone
[$@Tic-Tac-Toe(1..3) -> #, $@Tic-Tac-Toe(4..6) -> #, $@Tic-Tac-Toe(7..9) -> #,
$@Tic-Tac-Toe(1..9:3) -> #, $@Tic-Tac-Toe(2..9:3) -> #, $@Tic-Tac-Toe(3..9:3) -> #,
$@Tic-Tac-Toe([1,5,9]) -> #, $@Tic-Tac-Toe([3,5,7]) -> #
] -> \(
when <=[]?($@Tic-Tac-Toe <~[<position>]>)> do 'draw' !
when <~=[]> do $(1) !
\) !
when <[<mark>+ VOID]?($ <[<=$(first)>+ VOID]>)> do '$(first); wins!'!
end isWonOrDone
 
source validMoves
$@Tic-Tac-Toe -> \[i](<position> $ !\) !
end validMoves
 
templates move
when <?($@Tic-Tac-Toe($.position::raw) <position>)> do @Tic-Tac-Toe($.position::raw): $.mark;
$ !
otherwise
'Incorrect move$#10;' -> !OUT::write
end move
 
source showString
'$:1..9:3 -> '$#10;$@Tic-Tac-Toe($..$+2)...;';$#10;' !
end showString
end Tic-Tac-Toe
 
composer toInt
<INT>
end toInt
 
source play
def board: $Tic-Tac-Toe;
@: mark´'X';
templates getMove
[] -> #
when <=[]> do
$board::showString -> !OUT::write
'$@play; to move $board::validMoves;:$#10;' -> !OUT::write
[{mark: $@play, position: $IN::readline -> toInt} -> board::move] -> #
otherwise
$(1) !
end getMove
 
$getMove -> #
when <{}> do
'$.mark; played $.position;$#10;' -> !OUT::write
@: $@ -> \(<=mark´'X'> mark´'O'! <=mark´'O'> mark´'X' !\);
[$board::isWonOrDone] -> \(
when <=[]> do $getMove!
otherwise '$(1);$#10;' -> !OUT::write
\) -> #
end play
 
$play -> !VOID</syntaxhighlight>
{{out}}
<pre>
 
123
456
789
X to move [1, 2, 3, 4, 5, 6, 7, 8, 9]:
5
X played 5
 
123
4X6
789
O to move [1, 2, 3, 4, 6, 7, 8, 9]:
4
O played 4
 
123
OX6
789
X to move [1, 2, 3, 6, 7, 8, 9]:
1
X played 1
 
X23
OX6
789
O to move [2, 3, 6, 7, 8, 9]:
9
O played 9
 
X23
OX6
78O
X to move [2, 3, 6, 7, 8]:
2
X played 2
 
XX3
OX6
78O
O to move [3, 6, 7, 8]:
8
O played 8
 
XX3
OX6
7OO
X to move [3, 6, 7]:
3
X played 3
X wins!
</pre>
 
=={{header|Tcl}}==
{{trans|Python}}
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
 
# This code splits the players from the core game engine
Line 5,846 ⟶ 15,651:
# Assemble the pieces
set ttt [TicTacToe new HumanPlayer RandomRoboPlayer]
$ttt game</langsyntaxhighlight>
Sample game:
<pre>
Line 5,895 ⟶ 15,700:
 
X wins across [1, 4, 7]
</pre>
 
=={{header|UNIX Shell}}==
{{works with|Bourne Again SHell}}
The computer plays randomly.
 
<syntaxhighlight lang="sh">#!/usr/bin/env bash
# play tic-tac-toe
main() {
local play_again=1
while (( play_again )); do
local board=(1 2 3 4 5 6 7 8 9) tokens=(X O)
show_board "${board[@]}"
# player colors: computer is red, human is green
local computer=31 human=32
if (( RANDOM % 2 )); then
players=(computer human)
colors=($computer $human)
printf 'I go first!\n'
else
players=(human computer)
colors=($human $computer)
printf 'You go first!\n'
fi
local token winner
local -i turn=0
while ! winner=$(winner "${board[@]}"); do
token=${tokens[turn%2]}
case "${players[turn%2]}" in
human) board=($(human_turn "$token" "${board[@]}"));;
computer) board=($(computer_turn "$token" "${board[@]}"));;
*) printf 'Unknown player "%s"\n' "${players[turn%2]}"; exit 1;;
esac
show_board "${board[@]}" | sed -e "s/${tokens[0]}/"$'\e['"${colors[0]}"$'m&\e[0m/g' \
-e "s/${tokens[1]}/"$'\e['"${colors[1]}"$'m&\e[0m/g'
 
(( turn=turn+1 ))
done
case "$winner${players[0]}" in
Ohuman|Xcomputer) printf 'I win!\n';;
Xhuman|Ocomputer) printf 'You win!\n';;
cat*) printf 'The cat wins!\n';;
esac
yorn 'Play again'
play_again=$(( ! $? ))
done
}
 
show_board() {
printf '\n'
printf '%s %s %s\n' "$@"
printf '\n'
}
 
winner() {
local board=("$@") i j k
local lines=("0 1 2" "0 3 6" "0 4 8" "1 4 7"
"2 4 6" "2 5 8" "3 4 5" "6 7 8")
local line i j k
for line in "${lines[@]}"; do
read i j k <<<"$line"
local token=${board[i]}
if [[ "${board[j]}" == $token && "${board[k]}" == $token ]]; then
printf '%s\n' "$token"
return 0
fi
done
case "${board[*]}" in
*[1-9]*) return 1;;
*) printf 'cat\n'; return 0;;
esac
}
 
human_turn() {
local token=$1
shift
local board=("$@")
local n=0
while (( n < 1 || n > 9 )) || [[ "${board[n-1]}" != $n ]]; do
printf 'Enter space number: ' "$n" "${board[n-1]}" >/dev/tty
read n </dev/tty >/dev/tty 2>&1
done
board[n-1]=$token
printf '%s\n' "${board[@]}"
}
 
computer_turn() {
local token=$1
shift
local board=("$@")
local i=0 blanks=() choice
for (( i=0; i<9; ++i )); do
if [[ "${board[i]}" == [1-9] ]]; then
blanks+=("$i")
fi
done
choice=${blanks[RANDOM % ${#blanks[@]}]}
board[choice]=$token
printf '%s\n' "${board[@]}"
}
 
yorn() {
local yorn=
while [[ $yorn != [Yy]* && $yorn != [Nn]* ]]; do
printf '%s? ' "$*"
read yorn
done
[[ $yorn == [Yy]* ]]
}
 
main "$@"</syntaxhighlight>
 
{{Out}}
<pre>
1 2 3
4 5 6
7 8 9
 
I go first!
I go in space 5.
 
1 2 3
4 X 6
7 8 9
 
Enter space number: 1
 
O 2 3
4 X 6
7 8 9
 
I go in space 8.
 
O 2 3
4 X 6
7 X 9
 
Enter space number: 2
 
O O 3
4 X 6
7 X 9
 
I go in space 7.
 
O O 3
4 X 6
X X 9
 
Enter space number: 3
 
O O O
4 X 6
X X 9
 
You win!
Play again? n
</pre>
 
=={{header|V (Vlang)}}==
{{trans|Kotlin}}
<syntaxhighlight lang="v (vlang)">
import rand
import os
 
__global (
b = [3][3]int{}
best_i = 0
best_j = 0
)
 
fn main() {
mut user := false
mut yn :=''
for {
user = !user
print(game(user))
for (yn != "y" ) && (yn != "n") {
yn = os.input('Play again y/n: ').str().to_lower()
}
if yn != "y" {exit(0)} else {yn =''}
println('')
}
}
 
fn game(user bool) string {
mut u := user
mut move, mut my_move, mut i, mut j, mut win := 0, 0, 0, 0, 0
for k in 0..3 {
for l in 0..3 {
if b[k][l] != 0 {b[k][l] = 0}
}
}
print("Board postions are numbered so:\n1 2 3\n4 5 6\n7 8 9\n")
print("You have O, I have X.\n\n")
for k in 1..9 {
if u {
for move !in [1,2,3,4,5,6,7,8,9] {
move = os.input('your move: ').int()
}
move--
i = move / 3
j = move % 3
if b[i][j] != 0 {continue}
b[i][j] = 1
move = 0
}
if !u {
if k == 1 {
best_i = (rand.int_in_range(1, 9) or {exit(1)}) % 3
best_j = (rand.int_in_range(1, 9) or {exit(1)}) % 3
}
else {test_move(-1, 0)}
b[best_i][best_j] = -1
my_move = best_i * 3 + best_j + 1
println("My move: $my_move")
}
show_board()
win = check_winner()
println("win res: $win")
if win != 0 {
if win == 1 {return "You win" + ".\n\n"}
else {return "I win" + ".\n\n"}
}
u = !u
}
return "A draw.\n\n"
}
 
fn check_winner() int {
for i in 0..3 {
if b[i][0] != 0 && b[i][1] == b[i][0] && b[i][2] == b[i][0] {return b[i][0]}
if b[0][i] != 0 && b[1][i] == b[0][i] && b[2][i] == b[0][i] {return b[0][i]}
}
if b[1][1] == 0 {return 0}
if b[1][1] == b[0][0] && b[2][2] == b[0][0] {return b[0][0]}
if b[1][1] == b[2][0] && b[0][2] == b[1][1] {return b[1][1]}
return 0
}
 
fn show_board() {
mut t := "X O"
for i in 0..3 {
for j in 0..3 {
print("${t[b[i][j] + 1].ascii_str()} ")
}
println('')
}
println("-----")
}
 
fn test_move(value int, depth int) int {
mut best := -1
mut changed := 0
mut score := check_winner()
if score != 0 {
if score == value {return 1} else {return -1}
}
for i in 0..3 {
for j in 0..3 {
if b[i][j] != 0 {continue}
b[i][j] = value
changed = value
score = -test_move(-value, depth + 1)
b[i][j] = 0
if score <= best {continue}
if depth == 0 {
best_i = i
best_j = j
}
best = score
}
}
if changed != 0 {return best}
return 0
}
</syntaxhighlight>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-ioutil}}
<syntaxhighlight lang="wren">import "random" for Random
import "./ioutil" for Input
 
var r = Random.new()
var b = List.filled(3, null)
for (i in 0..2) b[i] = List.filled(3, 0) // board -> 0: blank; -1: computer; 1: human
 
var bestI = 0
var bestJ = 0
 
var checkWinner = Fn.new {
for (i in 0..2) {
if (b[i][0] != 0 && b[i][1] == b[i][0] && b[i][2] == b[i][0]) return b[i][0]
if (b[0][i] != 0 && b[1][i] == b[0][i] && b[2][i] == b[0][i]) return b[0][i]
}
if (b[1][1] == 0) return 0
if (b[1][1] == b[0][0] && b[2][2] == b[0][0]) return b[0][0]
if (b[1][1] == b[2][0] && b[0][2] == b[1][1]) return b[1][1]
return 0
}
 
var showBoard = Fn.new {
var t = "X O"
for (i in 0..2) {
for (j in 0..2) System.write("%(t[b[i][j] + 1]) ")
System.print()
}
System.print("-----")
}
 
var testMove // recursive
testMove = Fn.new { |value, depth|
var best = -1
var changed = 0
var score = checkWinner.call()
if (score != 0) return (score == value) ? 1 : -1
for (i in 0..2) {
for (j in 0..2) {
if (b[i][j] == 0) {
b[i][j] = value
changed = value
score = -testMove.call(-value, depth + 1)
b[i][j] = 0
if (score > best) {
if (depth == 0) {
bestI = i
bestJ = j
}
best = score
}
}
}
}
return (changed != 0) ? best : 0
}
 
var game = Fn.new { |u|
for (i in 0..2) {
for (j in 0..2) b[i][j] = 0
}
System.print("Board postions are numbered so:\n1 2 3\n4 5 6\n7 8 9")
System.print("You have O, I have X.\n")
 
for (k in 0..8) {
while (u) {
var move = Input.integer("Your move: ", 1, 9) - 1
var i = (move/3).floor
var j = move % 3
if (b[i][j] == 0) {
b[i][j] = 1
break
}
}
if (!u) {
if (k == 0) { // randomize if computer opens, less boring
bestI = r.int(1e6) % 3
bestJ = r.int(1e6) % 3
} else {
testMove.call(-1, 0)
}
b[bestI][bestJ] = -1
var myMove = bestI * 3 + bestJ + 1
System.print("My move: %(myMove)")
}
showBoard.call()
var win = checkWinner.call()
if (win != 0) return ((win == 1) ? "You win" : "I win") + ".\n\n"
u = !u
}
return "A draw.\n\n"
}
 
var user = false
while (true) {
user = !user
System.write(game.call(user))
var yn = Input.option("Play again y/n: ", "yYnN")
if (yn == "n" || yn == "N") return
System.print()
}</syntaxhighlight>
 
{{out}}
Sample game:
<pre>
Board postions are numbered so:
1 2 3
4 5 6
7 8 9
You have O, I have X.
 
Your move: 1
O
-----
My move: 5
O
X
-----
Your move: 3
O O
X
-----
My move: 2
O X O
X
-----
Your move: 8
O X O
X
O
-----
My move: 4
O X O
X X
O
-----
Your move: 6
O X O
X X O
O
-----
My move: 9
O X O
X X O
O X
-----
Your move: 7
O X O
X X O
O O X
-----
A draw.
 
Play again y/n: n
</pre>
 
=={{header|XPL0}}==
[[File:TTTXPL0.GIF|right]]
<langsyntaxhighlight XPL0lang="xpl0">\The computer marks its moves with an "O" and the player uses an "X". The
\ numeric keypad is used to make the player's move.
\
Line 6,043 ⟶ 16,287:
[SetVid(3); exit]; \clear screen & restore normal text mode
];
]</langsyntaxhighlight>
 
{{omit from|GUISS}}
2

edits