Introduction edit
MiHa 2015-06-24: One of the example-programs on my HelloWorld-page creates a deck of cards,so I had the idea to expand that into a simple cardgame, for the tcl-console.Blackjack
is quite simple, and with (debug-)options still in place to show the cards "in the open", this would nicely double as a tcl-tutorial (for using string and list), and a blackjack-trainer.With ideas and code from the following pages:
- HelloWorld
(MiHa) - the examples using foreach, while, gets, unicode and list - ...
Program edit
# Whitejack.tcl - MiHa - 2015-06-25
# http://wiki.tcl.tk/41565
# http://ideone.com/jVxnHV
puts "Whitejack:\n"
proc help {} { ;# Todo: needs rewording
puts "\nWhitejack - a cardgame much like simplified, self-service blackjack."
puts {It is played with one or more decks of 52 cards.
The object of the game is to beat the dealer:
* Get 21 points on the player's first two cards (called a blackjack), without a dealer blackjack;
* Reach a final score higher than the dealer without exceeding 21;
* orLet the dealer draw additional cards until his or her hand exceeds 21.
The player is dealt an initial two-card hand and add together the value of their cards.
Face cards (kings, queens, and jacks) count as ten points.
An ace is worth 1 point or 11 points, owners choice.
All other cards count as the numeric value shown on the card.
After their initial two cards, players can get a "hit", i.e. take an additional card.
In a given round, the player or the dealer wins by having a score of 21 or
by having the highest score that is less than 21.
Scoring higher than 21 (called "busting" or "going bust") results in a loss.
Commands:
---------
h : help
q : quit
n : new cards: add a fresh pack of 52 cards to the deck.
f = fill: move cards from discard-pile to the end of the deck.
t = trash: empty both hands and the discard-pile.
v = move the card from the front of the deck to the discard-pile
0-9 : move the card from position 0..9 of the deck to the end of the deck.
% = swap the two cards at the front of the deck (positions 0 and 1).
s = shuffle the deck (do a number of "1-9"-actions).
p,+ : player-draw: move first card from deck to player's hand
d,- : dealer-draw: move first card from deck to dealer's hand
b,l : bust: player loses the round
w : win : player wins the round
x = discard: move cards from player's hand to the discard-pile
y = discard: move cards from dealer's hand to the discard-pile
* : discard: move cards from both hands to the discard-pile
}
}
proc showStatus {} {
global deck discard playerHand dealerHand cWin cLoss
puts "\nStatus:"
puts -nonewline "Number of cards in "
puts -nonewline "deck: [llength $deck] "
puts -nonewline "discard: [llength $discard] "
puts -nonewline "playerHand: [llength $playerHand] "
puts "dealerHand: [llength $dealerHand] "
puts "Wins: $cWin Losses: $cLoss"
#puts "card #3 [lindex $::deck 2]" ;# index is zero-based
#showList "Deck" $deck 0 19
showFirst "Deck" $deck 18
showLast "Deck" $deck 18
puts "Player: $playerHand Value: [cardValue $playerHand]"
puts "Dealer: $dealerHand Value: [cardValue $dealerHand]"
}
proc win {x} {
if { $x>0 } {
incr ::cWin
puts "Win!"
} else {
puts "Lost!"
incr ::cLoss
}
}
proc makeCards {} {
global deck discard playerHand dealerHand
puts -nonewline "Making cards..."
set i 0
# For unicode, see also: http://wiki.tcl.tk/26403 : [HTML character entity references]
# Spades Hearts Diamonds Clubs
foreach {suit sym} { S \u2660 H \u2665 D \u2666 C \u2663 } {
foreach rank { A 2 3 4 5 6 7 8 9 10 J Q K } { ;# Ace 2 .. 10 Jack Queen King
incr i
set card "$rank$sym"
#puts -nonewline " $rank$suit=$card "
lappend deck $card ;# add card to list
}
#puts ""
}
set maxCard $i
puts "done.\nPack of $maxCard cards added to the deck."
#puts "\ndeck : $deck" ;##
}
proc c1 {s} { set c [string range $s 0 0] } ;# return first char of string
proc cardValue {L} {
# calculate value of the cards in the list
#puts "$tx $p1-$p2: [lrange $L $p1 $p2]"
#set v 0
for {set i 0; set sum 0} {$i < [llength $L]} {incr i} {
set card [lindex $L $i]
set c [c1 $card] ;# get first char from card
set v [string first $c "--234567891AJKQ"]
if { $v< 0 } {set v 0 } ;# not found
if { $v>11 } {set v 10 } ;# J,Q,K
#puts -nonewline "(($i: $c = $v)) " ;##
incr sum $v
}
return $sum
}
proc showList {tx L p1 p2} {
# show elements in list L from position p1 to p2
puts "$tx $p1-$p2: [lrange $L $p1 $p2]"
}
proc showFirst {tx L n} { ;# show the first n elements in list L
puts "$tx 0-$n: [lrange $L 0 $n] ..."
}
proc showLast {tx L n} { ;# show the last n elements in list L
set p2 [llength $L]
set p1 $p2; incr p1 -$n
puts "$tx $p1-$p2: ... [lrange $L $p1 $p2]"
}
proc deal_p {} {
# deal card from deck to player's hand:
global deck discard playerHand dealerHand
set card [lindex $deck 0] ;# get first card from deck
lappend playerHand $card ;# put it in his hand
;# delete it from the deck:
set deck [lreplace $deck[set deck {}] 0 0 ]
# see also: [lreplace] - "Modifying a List In-Place"
##puts "deck : $deck"
##showList "Deck" $deck 0 18
}
proc moveCard {p} {
# move card from position p at front of deck to end of deck:
global deck discard playerHand dealerHand
#puts "move $p:"
set card [lindex $deck $p] ;# get first card from deck
lappend deck $card ;# put it at end
;# delete it from the deck:
set deck [lreplace $deck[set deck {}] $p $p ]
}
proc clearHands {} {
# move cards to discard-pile
global deck discard playerHand dealerHand
set playerHand {}
set dealerHand {}
# Todo: move cards to the discard-pile
#puts "--"
}
proc deal_d {} {
# deal card from deck to dealer's hand:
global deck discard playerHand dealerHand
set card [lindex $deck 0] ;# get first card from deck
lappend dealerHand $card ;# put it in his hand
;# delete it from the deck:
set deck [lreplace $deck[set deck {}] 0 0 ]
}
proc deal {to} {
# deal card from deck to player- or dealer's hand:
#global deck discard playerHand dealerHand
set card [lindex $::deck 0] ;# get first card from deck
lappend $to $card ;# put it in his hand
;# delete it from the deck:
set ::deck [lreplace $::deck[set ::deck {}] 0 0 ]
# see also: [lreplace] - "Modifying a List In-Place"
##puts "deck : $::deck"
##showList "Deck" $::deck 0 18
}
set deck {} ;# create empty list
set discard {}
set playerHand {}
set dealerHand {}
set cWin 0
set cLoss 0
set dealerCash 1000
set playerCash 100
puts "Start with 'n' to get a fresh pack of cards."
set cmd "." ;# try: n 1 + - + - + - - w * q
while { $cmd ne "q" } {
puts -nonewline "\nEnter command (h for help, q to quit): "
set cmd [gets stdin]
puts $cmd
if {$cmd=="h"} { help }
if {$cmd=="q"} { puts "Bye!"; exit }
if {$cmd=="n"} { makeCards }
if {$cmd=="0"} { moveCard 0 }
if {$cmd=="1"} { moveCard 1 }
if {$cmd=="2"} { moveCard 2 }
if {$cmd=="3"} { moveCard 3 }
if {$cmd=="4"} { moveCard 4 }
if {$cmd=="5"} { moveCard 5 }
if {$cmd=="6"} { moveCard 6 }
if {$cmd=="7"} { moveCard 7 }
if {$cmd=="8"} { moveCard 8 }
if {$cmd=="9"} { moveCard 9 }
if {$cmd=="+"} { deal_p }
if {$cmd=="-"} { deal_d }
#if {$cmd=="d"} { deal $dealerHand }
#if {$cmd=="p"} { deal $playerHand }
if {$cmd=="w"} { win 1 }
if {$cmd=="b"} { win -1 }
if {$cmd=="*"} { clearHands }
# ...
showStatus
}
#.Output edit
Whitejack: Start with 'n' to get a fresh pack of cards. Enter command (h for help, q to quit): n Making cards...done. Pack of 52 cards added to the deck. Status: Number of cards in deck: 52 discard: 0 playerHand: 0 dealerHand: 0 Wins: 0 Losses: 0 Deck 0-18: A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ ... Deck 34-52: ... 9♦ 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ Player: Value: 0 Dealer: Value: 0 Enter command (h for help, q to quit): 1 Status: Number of cards in deck: 52 discard: 0 playerHand: 0 dealerHand: 0 Wins: 0 Losses: 0 Deck 0-18: A♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ ... Deck 34-52: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: Value: 0 Dealer: Value: 0 Enter command (h for help, q to quit): + Status: Number of cards in deck: 51 discard: 0 playerHand: 1 dealerHand: 0 Wins: 0 Losses: 0 Deck 0-18: 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ ... Deck 33-51: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ Value: 11 Dealer: Value: 0 Enter command (h for help, q to quit): - Status: Number of cards in deck: 50 discard: 0 playerHand: 1 dealerHand: 1 Wins: 0 Losses: 0 Deck 0-18: 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ ... Deck 32-50: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ Value: 11 Dealer: 3♠ Value: 3 Enter command (h for help, q to quit): + Status: Number of cards in deck: 49 discard: 0 playerHand: 2 dealerHand: 1 Wins: 0 Losses: 0 Deck 0-18: 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ ... Deck 31-49: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ 4♠ Value: 15 Dealer: 3♠ Value: 3 Enter command (h for help, q to quit): - Status: Number of cards in deck: 48 discard: 0 playerHand: 2 dealerHand: 2 Wins: 0 Losses: 0 Deck 0-18: 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ ... Deck 30-48: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ 4♠ Value: 15 Dealer: 3♠ 5♠ Value: 8 Enter command (h for help, q to quit): + Status: Number of cards in deck: 47 discard: 0 playerHand: 3 dealerHand: 2 Wins: 0 Losses: 0 Deck 0-18: 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ ... Deck 29-47: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ 4♠ 6♠ Value: 21 Dealer: 3♠ 5♠ Value: 8 Enter command (h for help, q to quit): - Status: Number of cards in deck: 46 discard: 0 playerHand: 3 dealerHand: 3 Wins: 0 Losses: 0 Deck 0-18: 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥ ... Deck 28-46: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ 4♠ 6♠ Value: 21 Dealer: 3♠ 5♠ 7♠ Value: 15 Enter command (h for help, q to quit): - Status: Number of cards in deck: 45 discard: 0 playerHand: 3 dealerHand: 4 Wins: 0 Losses: 0 Deck 0-18: 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥ A♦ ... Deck 27-45: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ 4♠ 6♠ Value: 21 Dealer: 3♠ 5♠ 7♠ 8♠ Value: 23 Enter command (h for help, q to quit): w Win! Status: Number of cards in deck: 45 discard: 0 playerHand: 3 dealerHand: 4 Wins: 1 Losses: 0 Deck 0-18: 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥ A♦ ... Deck 27-45: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: A♠ 4♠ 6♠ Value: 21 Dealer: 3♠ 5♠ 7♠ 8♠ Value: 23 Enter command (h for help, q to quit): * Status: Number of cards in deck: 45 discard: 0 playerHand: 0 dealerHand: 0 Wins: 1 Losses: 0 Deck 0-18: 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥ A♦ ... Deck 27-45: ... 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ 2♠ Player: Value: 0 Dealer: Value: 0 Enter command (h for help, q to quit): q Bye!
Comments edit
MiHa 2015-06-26: The most basic functionality is done, the largest missing parts now are the discard-pile, and shuffling.I think I need a much better look at upvar, and how params to proc work,with regard to changing values outside the proc.
As in call-by-value, vs. call-by-reference.
See also:

