Tic-tac-toe: Difference between revisions

From Rosetta Code
Content added Content deleted
(New task and Python solution.)
 
(→‎Tcl: Added implementation)
Line 118: Line 118:


O wins across [1, 4, 7]</pre>
O wins across [1, 4, 7]</pre>

=={{header|Tcl}}==
{{trans|Python}}
<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:
<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
>>> 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]
</pre>

Revision as of 09:24, 5 February 2011

Task
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.

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]

Tcl

Translation of: Python

<lang tcl>package require Tcl 8.6

  1. 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"

   }

}

  1. 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"

   }

}

  1. 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"

   }

}

  1. 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]