RosettaCodeData/Task/Rock-paper-scissors/Tcl/rock-paper-scissors.tcl
Ingy döt Net b83f433714 tasks a-s
2013-04-10 23:57:08 -07:00

64 lines
1.7 KiB
Tcl

package require Tcl 8.5
### Choices are represented by integers, which are indices into this list:
### Rock, Paper, Scissors
### Normally, idiomatic Tcl code uses names for these sorts of things, but it
### turns out that using integers simplifies the move-comparison logic.
# How to ask for a move from the human player
proc getHumanMove {} {
while 1 {
puts -nonewline "Your move? \[R\]ock, \[P\]aper, \[S\]cissors: "
flush stdout
gets stdin line
if {[eof stdin]} {
puts "\nBye!"
exit
}
set len [string length $line]
foreach play {0 1 2} name {"rock" "paper" "scissors"} {
# Do a prefix comparison
if {$len && [string equal -nocase -length $len $line $name]} {
return $play
}
}
puts "Sorry, I don't understand that. Try again please."
}
}
# How to ask for a move from the machine player
proc getMachineMove {} {
global states
set choice [expr {int(rand() * [::tcl::mathop::+ {*}$states 3])}]
foreach play {1 2 0} count $states {
if {[incr sum [expr {$count+1}]] > $choice} {
puts "I play \"[lindex {Rock Paper Scissors} $play]\""
return $play
}
}
}
# Initialize some state variables
set states {0 0 0}
set humanWins 0
set machineWins 0
# The main game loop
while 1 {
# Get the moves for this round
set machineMove [getMachineMove]
set humanMove [getHumanMove]
# Report on what happened
if {$humanMove == $machineMove} {
puts "A draw!"
} elseif {($humanMove+1)%3 == $machineMove} {
puts "I win!"
incr machineWins
} else {
puts "You win!"
incr humanWins
}
puts "Cumulative scores: $humanWins to you, $machineWins to me"
# Update the state of how the human has played in the past
lset states $humanMove [expr {[lindex $states $humanMove] + 1}]
}