File Coverage

blib/lib/Games/Tournament/BlackJack/Game.pm
Criterion Covered Total %
statement 9 114 7.8
branch 0 22 0.0
condition 0 27 0.0
subroutine 3 15 20.0
pod 0 12 0.0
total 12 190 6.3


line stmt bran cond sub pod time code
1             # Games::Tournament::BlackJack::Game.pm - perl module for playing blackjack with a deck.pm of cards.
2             # Author: Paul Jacobs, paul@pauljacobs.net
3             package Games::Tournament::BlackJack::Game;
4              
5 1     1   5 use Games::Tournament::BlackJack::Shoe;
  1         3  
  1         89  
6 1     1   561 use Games::Tournament::BlackJack::Utilities;
  1         3  
  1         77  
7 1     1   567 use Games::Tournament::BlackJack::Player;
  1         3  
  1         1743  
8              
9             our $running = 0; # not running at first
10              
11             sub new {
12 0     0 0   my $invocant = shift;
13 0   0       my $class = ref($invocant) || $invocant;
14 0           my $self = {
15             'deck' => Games::Tournament::BlackJack::Shoe::openNewShoe(), # shuffles before every round, and before returning for good measure.
16             'players' => [], # add them later or override
17             'playersScores' => [], # 1 per win
18             'playersHands' => [], # need seperate official record -- can't trust player code to not change hand
19             # is parallel array to players[]. is 2D array (one array of cards per player)
20             'dealer' => undef, # add later or specify in override attribute
21             'dealersHand' => [], # card 1 is the upcard
22             'numDecks' => 2, # defaults to 2 decks
23             'srand' => time(), # rand seed for game - can be overridden by attr.
24             'options' => ['hit','stand'], # list of acceptable responses to a decide_complex
25             # call, may (later) include split, døuble..
26             @_, # Override previous (default) attributes
27             };
28 0           srand($self->{'srand'}); # randomness is per game.
29 0           $self->{'deck'}->shuffle(); # have to do after the srand().
30 0           return bless $self, $class;
31             }
32              
33             sub clearHands {
34 0     0 0   my $self = shift;
35 0           foreach my $p (@{$self->{'players'}}) {
  0            
36 0           $self->{'playersHands'}[$p->{'storage'}{'num'}] = [];
37 0           $p->{'hand'} = [];
38             }
39 0           $self->{'dealersHand'} = [];
40             }
41              
42             my $total_players = 0;
43             sub addPlayers {
44 0     0 0   my $self = shift;
45 0           my @players = @_;
46 0           foreach my $player (@players) {
47 0           $player->{'storage'}{'num'} = $total_players++;
48 0           push @{$self->{'players'}}, $player;
  0            
49 0           push @{$self->{'playersHands'}}, [];
  0            
50             }
51             }
52              
53 0     0 0   sub addPlayer { return addPlayers(@_); }
54              
55             sub setDealer {
56 0     0 0   $_[0]->{'dealer'} = $_[1]; # set the dealer pointer to point to the passed obj.
57             }
58              
59 0 0   0 0   sub dealersUpcard { $_[0]->{'dealersHand'}->[1] || ''; }
60              
61 0 0   0 0   sub playersScores { $_[0]->{'playersScores'} || []; }
62              
63             sub setupPlayerScenario {
64 0     0 0   my $self = shift;
65 0           my $player = shift;
66            
67 0 0         if ($player eq $self->{'dealer'}) {
68             # player is the dealer
69 0   0       $player->{'hand'} = $self->{'dealersHand'} || [];
70             } else {
71             # player is not the dealer
72 0   0       $player->{'hand'} = $self->{'playersHands'}->[$player->{'storage'}{'num'}] || [];
73 0   0       $player->{'dealerUpcard'} = $self->dealersUpcard() || '';
74             }
75 0           return $player;
76             }
77              
78             # playRound is the SIMPLE version. playComplexRound will come later.
79             sub playRound {
80 0     0 0   my $self = shift;
81 0           my @players = @{$self->{'players'}};
  0            
82            
83             # open new deck
84 0           $self->{"deck"} = openNewDeck();
85            
86             # shuffle deck
87 0           $self->{"deck"}->shuffle;
88              
89             # clear hands
90 0           $self->clearHands();
91              
92             # deal two cards in proper order:
93 0           foreach (0..1) {
94 0           print "dealing card to each player..\n";
95 0           foreach (0..$#players) {
96             #deal one from the deck to each player's hand
97 0           deal( 1, $self->{"deck"}, $self->{"playersHands"}->[$_]);
98             }
99              
100 0           print "dealing card to dealer..\n";
101             #deal one from the deck to the dealer's hand
102 0           deal( 1, $self->{"deck"}, $self->{"dealersHand"} );
103             }
104              
105             # each player in turn decides to hit or stay until they are done.
106 0           my $player_hit = 1; # to get into loop
107 0           foreach (0..$#players) {
108 0           $player_hit = 1; # to get into loop
109 0           $player = $players[$_] = $self->setupPlayerScenario($players[$_]); # load up private data fields in player obj.
110 0           my $handVal = handValue($self->{"playersHands"}->[$_]);
111 0   0       while ( ($handVal = handValue($self->{"playersHands"}->[$_])) < 21 and $player_hit) {
112 0           my $decision = $player->decide_simple();
113 0 0 0       if ($decision eq 'hit' or ($decision and $decision ne 'stand')) {
      0        
114             #deal one from the deck to the player's hand
115 0           deal( 1, $self->{"deck"}, $self->{"playersHands"}->[$_]);
116 0           print "player $_ hits on $handVal..\n";
117             } else {
118 0           print "player $_ stays on $handVal..\n";
119 0           $player_hit = 0;
120             }
121             }
122            
123             }
124              
125             # now let dealer play out
126 0           my $dealer = $self->{'dealer'} = $self->setupPlayerScenario($self->{'dealer'});
127 0           $player_hit = 1; # get into loop
128 0   0       while ( ($handVal = $dealer->myHandValue()) < 21 and $player_hit) {
129 0           my $decision = $dealer->decide_simple();
130 0           my $handStr = $dealer->myHandStr();
131 0 0 0       if ($decision eq 'hit' or ($decision and $decision ne 'stand')) {
      0        
132             #deal one from the deck to the player's hand
133 0           deal( 1, $self->{"deck"}, $self->{"dealersHand"});
134 0           print "dealer hits on [$handStr] ($handVal)..\n";
135 0 0         if ($handVal == 0) {my $handStr = $dealer->myHandStr(); print "dealer hand [$handStr]";}
  0            
  0            
136             } else {
137 0           print "dealer stays on [$handStr] ($handVal)..\n";
138 0           $player_hit = 0;
139             }
140             }
141              
142              
143            
144             # compare values
145 0           my $dval = handValue($self->{'dealersHand'});
146 0           print "dealer hand value $dval\n";
147              
148 0           my @pvals = map {handValue($_)} @{$self->{'playersHands'}};
  0            
  0            
149 0           print "player hand values [@pvals]\n";
150              
151 0           my @phstrs = map {handStr($_)} @{$self->{'playersHands'}};
  0            
  0            
152              
153 0 0         if ($dval > 21) {
154             # dealer busts
155 0           print "dealer busts with $dval; all players win.\n";
156 0           foreach (0..$#players) {$self->{'playersScores'}[$_]++} # add 1 for all players
  0            
157 0           return; # and end the round.
158             }
159 0           my $pnum = 0;
160 0           foreach my $p (@pvals) {
161            
162 0 0         if ($p > 21) {
    0          
    0          
    0          
163 0           print "player $pnum busts with $p ($phstrs[$pnum]).\n";
164 0           $pnum++;
165 0           next; }
166             elsif ($p == 21) {
167 0           print "player $pnum gets a 21 (Assuming blackjack for now) $p ($phstrs[$pnum]) (score 1.5).\n";
168 0           $self->{'playersScores'}[$pnum] += 1.5;
169 0           next; }
170             elsif ($p == $dval) {
171 0           print "player $pnum has $p ($phstrs[$pnum]) vs. dealer's $dval, push (score 0.5).\n";
172 0           $self->{'playersScores'}[$pnum] += 0.5;
173             }
174             elsif ($p > $dval) {
175 0           print "player $pnum has $p ($phstrs[$pnum]) vs. dealer's $dval, player $pnum wins (score 1).\n";
176 0           $self->{'playersScores'}[$pnum]++;
177             } else {
178 0           print "player $pnum has $p ($phstrs[$pnum]) vs. dealer's $dval, player $pnum loses (score 0)\n";
179             }
180 0           $pnum++;
181             }
182              
183             }
184              
185             sub running {
186 0     0 0   return $running;
187             }
188              
189             sub quit {
190 0     0 0   $running = 0;
191             }
192              
193             sub start {
194 0     0 0   my $self = shift;
195 0           my @players = @{$self->{'players'}};
  0            
196             # game config is done and I can prepare to run game
197 0           $running = 1;
198             # blank out player scores
199 0           foreach (0..$#players) {
200 0           $self->{'playersScores'}[$_] = 0;
201             }
202             }
203              
204             1;