Tic-tac-toe
You are encouraged to solve this task according to the task description, using any language you may know.
Play a game of tic-tac-toe. Ensure that legal moves are played and that a winning position is notified.
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. <lang 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, Gui, Add, Button, x12 y52 w30 h30 vB4 gButtonHandler, Gui, Add, Button, x52 y52 w30 h30 vB5 gButtonHandler, Gui, Add, Button, x92 y52 w30 h30 vB6 gButtonHandler, Gui, Add, Button, x12 y92 w30 h30 vB7 gButtonHandler, Gui, Add, Button, x52 y92 w30 h30 vB8 gButtonHandler, Gui, Add, Button, x92 y92 w30 h30 vB9 gButtonHandler,
- Generated using SmartGUI Creator 4.0
Gui, Show, x127 y87 h150 w141, Tic-Tac-Toe Winning_Moves := "123,456,789,147,258,369,159,357" Return
ButtonHandler:
; Fired whenever the user clicks on an enabled button Go(A_GuiControl,"X") GoSub MyMove
Return
MyMove: ; Loops through winning moves. First attempts to win, then to block, then a random move
Went=0 Loop, parse, Winning_Moves,`, { Current_Set := A_LoopField X:=O:=0 Loop, parse, Current_Set { GuiControlGet, Char,,Button%A_LoopField% If ( Char = "O" ) O++ If ( Char = "X" ) X++ } If ( O = 2 and X = 0 ) or ( X = 2 and O = 0 ){ Finish_Line(Current_Set) Went = 1 Break ; out of the Winning_Moves Loop to ensure the computer goes only once } } If (!Went) GoSub RandomMove
Return
Go(Control,chr){
GuiControl,,%Control%, %chr% GuiControl,Disable,%Control% GoSub, CheckWin
}
CheckWin:
Loop, parse, Winning_Moves,`, { Current_Set := A_LoopField X:=O:=0 Loop, parse, Current_Set { GuiControlGet, Char,,Button%A_LoopField% If ( Char = "O" ) O++ If ( Char = "X" ) X++ } If ( O = 3 ){ Msgbox O Wins! GoSub DisableAll Break } If ( X = 3 ){ MsgBox X Wins! GoSub DisableAll Break } }
return
DisableAll:
Loop, 9 GuiControl, Disable, Button%A_Index%
return
Finish_Line(Set){ ; Finish_Line is called when a line exists with 2 of the same character. It goes in the remaining spot, thereby blocking or winning.
Loop, parse, set { GuiControlGet, IsEnabled, Enabled, Button%A_LoopField% Control=Button%A_LoopField% If IsEnabled Go(Control,"O") }
}
RandomMove:
Loop{ Random, rnd, 1, 9 GuiControlGet, IsEnabled, Enabled, Button%rnd% If IsEnabled { Control=Button%rnd% Go(Control,"O") Break } }
return
GuiClose: ExitApp </lang>
D
<lang d>import std.stdio, std.string, std.algorithm, std.conv, std.random;
struct Board {
int[9] board;
string positionString(int pos) in { assert(pos >= 0); assert(pos < 9); } out(ret) { assert(ret.length == 1); } body { if(board[pos]) return board[pos] == 1 ? "X" : "O"; return to!string(pos + 1); } string toString() { string lineSeparator = "-+-+-\n"; string row(int start) { return format("%s|%s|%s\n", positionString(start + 0), positionString(start + 1), positionString(start + 2)); } string ret; ret ~= row(0); ret ~= lineSeparator; ret ~= row(3); ret ~= lineSeparator; ret ~= row(6); return ret; } int[] openPositions() { int[] ret; foreach(i, v; board) { if(!v) ret ~= i; } return ret; } bool isAvailable(int position) { if(position < 0 || position >= 9) return false; return board[position] == 0; } bool finished() { return winner() != -1; } int winner() { enum 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] ]; foreach(win; wins) { int desired = board[win[0]]; if(desired == 0) continue; // nobody wins on this one // the same player needs to take all three positions if(board[win[1]] == desired && board[win[2]] == desired) return desired; // a winner! } if(openPositions().length == 0) return 0; // a draw return -1; // the game is still going } int suggestMove(int player) out(ret) { assert(ret >= 0); assert(ret < 9); assert(isAvailable(ret)); } body { return randomCover(openPositions(), Random(unpredictableSeed)).front; }
}
void main() {
writeln("\tTic-tac-toe game player."); Board board; int currentPlayer = 1; while(!board.finished()) { writeln(board); int move; if(currentPlayer == 1) { do { writef("Input the index of your move (from %s): ", map!"a+1"(board.openPositions())); readf("%d\n", &move); move--; // zero based indexing } while(!board.isAvailable(move)); } else { move = board.suggestMove(currentPlayer); } assert(board.isAvailable(move)); writefln("%s chose %d", currentPlayer == 1 ? "You" : "I", move + 1); board.board[move] = currentPlayer; currentPlayer = currentPlayer == 2 ? 1 : 2; } int winner = board.winner(); if(winner == 0) writeln("\nDraw"); if(winner == 1) writeln("\nYou win!"); if(winner == 2) writeln("\nComputer wins.");
}</lang> Output:
Tic-tac-toe game player. 1|2|3 -+-+- 4|5|6 -+-+- 7|8|9 Input the index of your move (from [1, 2, 3, 4, 5, 6, 7, 8, 9]): 1 You chose 1 X|2|3 -+-+- 4|5|6 -+-+- 7|8|9 I chose 5 X|2|3 -+-+- 4|O|6 -+-+- 7|8|9 Input the index of your move (from [2, 3, 4, 6, 7, 8, 9]): 2 You chose 2 X|X|3 -+-+- 4|O|6 -+-+- 7|8|9 I chose 4 X|X|3 -+-+- O|O|6 -+-+- 7|8|9 Input the index of your move (from [3, 6, 7, 8, 9]): 3 You chose 3 You win!
F#
A purely-functional solution with a naive (but perfect) computer player implementation. The first move is played randomly by the computer.
<lang fsharp>type Brick =
| Empty | Computer | User
let brickToString = function
| Empty -> ' ' | Computer -> 'X' | User -> 'O'
// y -> x -> Brick type Board = Map<int, Map<int, Brick> >
let emptyBoard =
let emptyRow = Map.ofList [0,Empty; 1,Empty; 2,Empty] Map.ofList [0,emptyRow; 1,emptyRow; 2,emptyRow]
let get (b:Board) (x,y) = b.[y].[x]
let set player (b:Board) (x,y) : Board =
let row = b.[y].Add(x, player) b.Add(y, row)
let winningPositions =
[for x in [0..2] -> x,x] // first diagonal ::[for x in [0..2] -> 2-x,x] // second diagonal ::[for y in [0..2] do yield! [[for x in [0..2]->(y,x)]; // columns [for x in [0..2] -> (x,y)]]] // rows
let hasWon player board =
List.exists (fun ps -> List.forall (fun pos -> get board pos = player) ps) winningPositions
let freeSpace board =
[for x in 0..2 do for y in 0..2 do if get board (x,y) = Empty then yield x,y]
type Evaluation =
| Win | Draw | Lose
let rec evaluate board move =
let b2 = set Computer board move if hasWon Computer b2 then Win else match freeSpace b2 with | [] -> Draw | userChoices -> let b3s = List.map (set User b2) userChoices if List.exists (hasWon User) b3s then Lose elif List.exists (fun b3 -> bestOutcome b3 = Lose) b3s then Lose elif List.exists (fun b3 -> bestOutcome b3 = Draw) b3s then Draw else Win
and findBestChoice b =
match freeSpace b with | [] -> ((-1,-1), Draw) | choices -> match List.tryFind (fun c -> evaluate b c = Win) choices with | Some c -> (c, Win) | None -> match List.tryFind (fun c -> evaluate b c = Draw) choices with | Some c -> (c, Draw) | None -> (List.head choices, Lose)
and bestOutcome b = snd (findBestChoice b)
let bestChoice b = fst (findBestChoice b)
let computerPlay b = set Computer b (bestChoice b)
let printBoard b =
printfn " | A | B | C |" printfn "---+---+---+---+" for y in 0..2 do printfn " %d | %c | %c | %c |" (3-y) (get b (0,y) |> brickToString) (get b (1,y) |> brickToString) (get b (2,y) |> brickToString) printfn "---+---+---+---+"
let rec userPlay b =
printfn "Which field do you play? (format: a1)" let input = System.Console.ReadLine() if input.Length <> 2 || input.[0] < 'a' || input.[0] > 'c' || input.[1] < '1' || input.[1] > '3' then printfn "illegal input" userPlay b else let x = int(input.[0]) - int('a') let y = 2 - int(input.[1]) + int('1') if get b (x,y) <> Empty then printfn "Field is not free." userPlay b else set User b (x,y)
let rec gameLoop b player =
if freeSpace b = [] then printfn "Game over. Draw." elif player = Computer then printfn "Computer plays..." let b2 = computerPlay b printBoard b2 if hasWon Computer b2 then printfn "Game over. I have won." else gameLoop b2 User elif player = User then let b2 = userPlay b printBoard b2 if hasWon User b2 then printfn "Game over. You have won." else gameLoop b2 Computer
// randomly choose an element of a list let choose =
let rnd = new System.Random() fun (xs:_ list) -> xs.[rnd.Next(xs.Length)]
// play first brick randomly printfn "Computer starts." let b = set Computer emptyBoard (choose (freeSpace emptyBoard)) printBoard b gameLoop b User</lang>
Example game:
Computer starts. | A | B | C | ---+---+---+---+ 3 | | | X | ---+---+---+---+ 2 | | | | ---+---+---+---+ 1 | | | | ---+---+---+---+ Which field do you play? (format: a1) a1 | A | B | C | ---+---+---+---+ 3 | | | X | ---+---+---+---+ 2 | | | | ---+---+---+---+ 1 | O | | | ---+---+---+---+ Computer plays... | A | B | C | ---+---+---+---+ 3 | X | | X | ---+---+---+---+ 2 | | | | ---+---+---+---+ 1 | O | | | ---+---+---+---+ Which field do you play? (format: a1) b3 | A | B | C | ---+---+---+---+ 3 | X | O | X | ---+---+---+---+ 2 | | | | ---+---+---+---+ 1 | O | | | ---+---+---+---+ Computer plays... | A | B | C | ---+---+---+---+ 3 | X | O | X | ---+---+---+---+ 2 | | | | ---+---+---+---+ 1 | O | | X | ---+---+---+---+ Which field do you play? (format: a1) c2 | A | B | C | ---+---+---+---+ 3 | X | O | X | ---+---+---+---+ 2 | | | O | ---+---+---+---+ 1 | O | | X | ---+---+---+---+ Computer plays... | A | B | C | ---+---+---+---+ 3 | X | O | X | ---+---+---+---+ 2 | | X | O | ---+---+---+---+ 1 | O | | X | ---+---+---+---+ Game over. I have won.
Icon and Unicon
The following works in both Icon and Unicon. The computer plays randomly against a human player, with legal moves enforced and wins/draws notified.
<lang Icon>
- Play TicTacToe
$define E " " # empty square $define X "X" # X piece $define O "O" # O piece
- -- define a board
record Board(a, b, c, d, e, f, g, h, i)
procedure display_board (board, player)
write ("\n===============") write (board.a || " | " || board.b || " | " || board.c) write ("---------") write (board.d || " | " || board.e || " | " || board.f) write ("---------") write (board.g || " | " || board.h || " | " || board.i)
end
- return a set of valid moves (empty positions) in given board
procedure empty_fields (board)
fields := set() every i := !fieldnames(board) do if (board[i] == E) then insert (fields, i) return fields
end
procedure game_start ()
return Board (E, E, E, E, E, E, E, E, E)
end
procedure game_is_drawn (board)
return *empty_fields(board) = 0
end
procedure game_won_by (board, player)
return (board.a == board.b == board.c == player) | (board.d == board.e == board.f == player) | (board.g == board.h == board.i == player) | (board.a == board.d == board.g == player) | (board.b == board.e == board.h == player) | (board.c == board.f == board.i == player) | (board.a == board.e == board.i == player) | (board.g == board.e == board.c == player)
end
procedure game_over (board)
return game_is_drawn (board) | game_won_by (board, O) | game_won_by (board, X)
end
- -- players make their move on the board
- assume there is at least one empty square
procedure human_move (board, player)
choice := "z" options := empty_fields (board) # keep prompting until player selects a valid square until member (options, choice) do { writes ("Choose one of: ") every writes (!options || " ") writes ("\n> ") choice := read () } board[choice] := player
end
- pick and make a move at random from empty positions
procedure random_move (board, player)
board[?empty_fields(board)] := player
end
- -- manage the game play
procedure play_game ()
# hold procedures for players' move in variables player_O := random_move player_X := human_move
# randomly determine if human or computer moves first if (?2 = 0) then { write ("Human plays first as O") player_O := human_move player_X := random_move } else write ("Computer plays first, human is X")
# set up the game to start board := game_start () player := O display_board (board, player) # loop until the game is over, getting each player to move in turn until game_over (board) do { write (player || " to play next") # based on player, prompt for the next move if (player == O) then (player_O (board, player)) else (player_X (board, player)) # change player to move player := if (player == O) then X else O display_board (board, player) } # finish by writing out result if game_won_by (board, O) then write ("O won") else if game_won_by (board, X) then write ("X won") else write ("draw") # neither player won, so must be a draw
end
- -- get things started
procedure main ()
play_game ()
end </lang>
PicoLisp
This solution doesn't bother about the game logic, but simply uses the alpha-beta-pruning 'game' function in the "simul" library. <lang PicoLisp>(load "@lib/simul.l") # for 'game' function
(de display ()
(for Y (3 2 1) (prinl " +---+---+---+") (prin " " Y) (for X (1 2 3) (prin " | " (or (get *Board X Y) " ")) ) (prinl " |") ) (prinl " +---+---+---+") (prinl " a b c") )
(de find3 (P)
(find '((X Y DX DY) (do 3 (NIL (= P (get *Board X Y))) (inc 'X DX) (inc 'Y DY) T ) ) (1 1 1 1 2 3 1 1) (1 2 3 1 1 1 1 3) (1 1 1 0 0 0 1 1) (0 0 0 1 1 1 1 -1) ) )
(de myMove ()
(when (game NIL 8 '((Flg) # Moves (unless (find3 (or (not Flg) 0)) (make (for (X . L) *Board (for (Y . P) L (unless P (link (cons (cons X Y (or Flg 0)) (list X Y) ) ) ) ) ) ) ) ) '((Mov) # Move (set (nth *Board (car Mov) (cadr Mov)) (cddr Mov)) ) '((Flg) # Cost (if (find3 (or Flg 0)) -100 0) ) ) (let Mov (caadr @) (set (nth *Board (car Mov) (cadr Mov)) 0) ) (display) ) )
(de yourMove (X Y)
(and (sym? X) (>= 3 (setq X (- (char X) 96)) 1) (num? Y) (>= 3 Y 1) (not (get *Board X Y)) (set (nth *Board X Y) T) (display) ) )
(de main ()
(setq *Board (make (do 3 (link (need 3))))) (display) )
(de go Args
(cond ((not (yourMove (car Args) (cadr Args))) "Illegal move!" ) ((find3 T) "Congratulation, you won!") ((not (myMove)) "No moves") ((find3 0) "Sorry, you lost!") ) )</lang>
Output:
: (main) +---+---+---+ 3 | | | | +---+---+---+ 2 | | | | +---+---+---+ 1 | | | | +---+---+---+ a b c : (go a 1) +---+---+---+ 3 | | | | +---+---+---+ 2 | | | | +---+---+---+ 1 | T | | | +---+---+---+ a b c +---+---+---+ 3 | | | | +---+---+---+ 2 | | 0 | | +---+---+---+ 1 | T | | | +---+---+---+ a b c
Python
The computer enforces the rules but plays a random game. <lang python>
Tic-tac-toe game player. Input the index of where you wish to place your mark at your turn.
import random
board = list('123456789') 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))
def printboard():
print('\n'.join(' '.join(board[x:x+3]) for x in(0,3,6)))
def score():
for w in wins: b = board[w[0]] if b in 'XO' and all (board[i] == b for i in w): return b, [i+1 for i in w] return None, None
def finished():
return all (b in 'XO' for b in board)
def space():
return [ b for b in board if b not in 'XO']
def my_turn(xo):
options = space() choice = random.choice(options) board[int(choice)-1] = xo return choice
def your_turn(xo):
options = space() while True: choice = input(" Put your %s in any of these positions: %s " % (xo, .join(options))).strip() if choice in options: break print( "Whoops I don't understand the input" ) board[int(choice)-1] = xo return choice
def me(xo='X'):
printboard() print('I go at', my_turn(xo)) return score() assert not s[0], "\n%s wins across %s" % s
def you(xo='O'):
printboard() # Call my_turn(xo) below for it to play itself print('You went at', your_turn(xo)) return score() assert not s[0], "\n%s wins across %s" % s
print(__doc__)
while not finished():
s = me('X') if s[0]: printboard() print("\n%s wins across %s" % s) break if not finished(): s = you('O') if s[0]: printboard() print("\n%s wins across %s" % s) break
else:
print('\nA draw')
</lang>
Sample Game
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 1 You went at 1 O 2 3 4 5 6 7 8 X I go at 3 O 2 X 4 5 6 7 8 X Put your O in any of these positions: 245678 4 You went at 4 O 2 X O 5 6 7 8 X I go at 2 O X X O 5 6 7 8 X Put your O in any of these positions: 5678 7 You went at 7 O X X O 5 6 O 8 X O wins across [1, 4, 7]
Better skilled player
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.
<lang python>
Tic-tac-toe game player. Input the index of where you wish to place your mark at your turn.
import random
board = list('123456789') 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))
def printboard():
print('\n-+-+-\n'.join('|'.join(board[x:x+3]) for x in(0,3,6)))
def score(board=board):
for w in wins: b = board[w[0]] if b in 'XO' and all (board[i] == b for i in w): return b, [i+1 for i in w] return None
def finished():
return all (b in 'XO' for b in board)
def space(board=board):
return [ b for b in board if b not in 'XO']
def my_turn(xo, board):
options = space() choice = random.choice(options) board[int(choice)-1] = xo return choice
def my_better_turn(xo, board):
'Will return a next winning move or block your winning move if possible' ox = 'O' if xo =='X' else 'X' oneblock = None options = [int(s)-1 for s in space(board)] for choice in options: brd = board[:] brd[choice] = xo if score(brd): break if oneblock is None: brd[choice] = ox if score(brd): oneblock = choice else: choice = oneblock if oneblock is not None else random.choice(options) board[choice] = xo return choice+1
def your_turn(xo, board):
options = space() while True: choice = input("\nPut your %s in any of these positions: %s " % (xo, .join(options))).strip() if choice in options: break print( "Whoops I don't understand the input" ) board[int(choice)-1] = xo return choice
def me(xo='X'):
printboard() print('\nI go at', my_better_turn(xo, board)) return score()
def you(xo='O'):
printboard() # Call my_turn(xo, board) below for it to play itself print('\nYou went at', your_turn(xo, board)) return score()
print(__doc__)
while not finished():
s = me('X') if s: printboard() print("\n%s wins along %s" % s) break if not finished(): s = you('O') if s: printboard() print("\n%s wins along %s" % s) break
else:
print('\nA draw')</lang>
Sample output
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 2 1|X|3 -+-+- 4|5|6 -+-+- 7|8|9 Put your O in any of these positions: 13456789 5 You went at 5 1|X|3 -+-+- 4|O|6 -+-+- 7|8|9 I go at 1 X|X|3 -+-+- 4|O|6 -+-+- 7|8|9 Put your O in any of these positions: 346789 3 You went at 3 X|X|O -+-+- 4|O|6 -+-+- 7|8|9 I go at 7 X|X|O -+-+- 4|O|6 -+-+- X|8|9 Put your O in any of these positions: 4689 4 You went at 4 X|X|O -+-+- O|O|6 -+-+- X|8|9 I go at 6 X|X|O -+-+- O|O|X -+-+- X|8|9 Put your O in any of these positions: 89 9 You went at 9 X|X|O -+-+- O|O|X -+-+- X|8|O I go at 8 A draw
Tcl
<lang tcl>package require Tcl 8.6
- This code splits the players from the core game engine
oo::class create TicTacToe {
variable board player letter who constructor {player1class player2class} {
set board {1 2 3 4 5 6 7 8 9} set player(0) [$player1class new [self] [set letter(0) "X"]] set player(1) [$player2class new [self] [set letter(1) "O"]] set who 0
}
method PrintBoard {} {
lassign $board a1 b1 c1 a2 b2 c2 a3 b3 c3 puts [format " %s | %s | %s" $a1 $b1 $c1] puts "---+---+---" puts [format " %s | %s | %s" $a2 $b2 $c2] puts "---+---+---" puts [format " %s | %s | %s" $a3 $b3 $c3]
}
method WinForSomeone {} {
foreach w { {0 1 2} {3 4 5} {6 7 8} {0 3 6} {1 4 7} {2 5 8} {0 4 8} {2 4 6} } { set b [lindex $board [lindex $w 0]] if {$b ni "X O"} continue foreach i $w {if {[lindex $board $i] ne $b} break} if {[lindex $board $i] eq $b} { foreach p $w {lappend w1 [expr {$p+1}]} return [list $b $w1] } } return ""
}
method status {} {
return $board
}
method IsDraw {} {
foreach b $board {if {[string is digit $b]} {return false}} return true
}
method legalMoves {} {
foreach b $board {if {[string is digit $b]} {lappend legal $b}} return $legal
}
method DoATurn {} {
set legal [my legalMoves] my PrintBoard while 1 { set move [$player($who) turn] if {$move in $legal} break puts "Illegal move!" } lset board [expr {$move - 1}] $letter($who) $player($who) describeMove $move set who [expr {1 - $who}] return [my WinForSomeone]
}
method game {} { puts " Tic-tac-toe game player. Input the index of where you wish to place your mark at your turn.\n"
while {![my IsDraw]} { set winner [my DoATurn] if {$winner eq ""} continue lassign $winner winLetter winSites my PrintBoard puts "\n$winLetter wins across \[[join $winSites {, }]\]" return $winLetter } puts "\nA draw"
}
}
- Stupid robotic player
oo::class create RandomRoboPlayer {
variable g constructor {game letter} {
set g $game
} method turn {} {
set legal [$g legalMoves] return [lindex $legal [expr {int(rand()*[llength $legal])}]]
} method describeMove {move} {
puts "I go at $move"
}
}
- Interactive human player delegate
oo::class create HumanPlayer {
variable g char constructor {game letter} {
set g $game set char $letter
} method turn {} {
set legal [$g legalMoves] puts ">>> Put your $char in any of these positions: [join $legal {}]" while 1 { puts -nonewline ">>> " flush stdout gets stdin number if {$number in $legal} break puts ">>> Whoops I don't understand the input!" } return $number
} method describeMove {move} {
puts "You went at $move"
}
}
- Assemble the pieces
set ttt [TicTacToe new HumanPlayer RandomRoboPlayer] $ttt game</lang> Sample game:
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 >>> Put your X in any of these positions: 123456789 >>> 1 You went at 1 X | 2 | 3 ---+---+--- 4 | 5 | 6 ---+---+--- 7 | 8 | 9 I go at 5 X | 2 | 3 ---+---+--- 4 | O | 6 ---+---+--- 7 | 8 | 9 >>> Put your X in any of these positions: 2346789 >>> 7 You went at 7 X | 2 | 3 ---+---+--- 4 | O | 6 ---+---+--- X | 8 | 9 I go at 9 X | 2 | 3 ---+---+--- 4 | O | 6 ---+---+--- X | 8 | O >>> Put your X in any of these positions: 23468 >>> 4 You went at 4 X | 2 | 3 ---+---+--- X | O | 6 ---+---+--- X | 8 | O X wins across [1, 4, 7]