File Coverage

blib/lib/Game/Cribbage.pm
Criterion Covered Total %
statement 9 360 2.5
branch 0 110 0.0
condition 0 27 0.0
subroutine 3 31 9.6
pod 28 28 100.0
total 40 556 7.1


line stmt bran cond sub pod time code
1             package Game::Cribbage;
2              
3             our $VERSION = "0.12";
4              
5 1     1   130082 use Rope;
  1         15334  
  1         8  
6 1     1   1019 use Rope::Autoload;
  1         4192  
  1         8  
7 1     1   759 use Game::Cribbage::Board;
  1         3  
  1         3789  
8              
9             prototyped 'board' => undef, dealer => undef, crib_set => 0, starter_card => undef;
10              
11             sub start {
12 0     0 1   my ($self, %params) = @_;
13              
14 0           $self->clear_screen;
15              
16 0           $self->print_header("Welcome to terminal Cribbage");
17              
18 0           $self->print_footer("Insert name: ");
19              
20 0           my $name = ;
21              
22 0           chomp($name);
23              
24 0           my $board = Game::Cribbage::Board->new();
25              
26 0           $board->add_player(name => 'Bot');
27 0           $board->add_player(name => $name);
28              
29 0           $board->start_game();
30              
31 0           $self->board = $board;
32              
33 0           $self->init_game();
34             }
35              
36             sub init_game {
37 0     0 1   my ($self) = @_;
38              
39 0           $self->clear_screen;
40              
41 0           $self->reset_cursor();
42              
43 0           $self->split_cards();
44              
45 0           $self->init_draw();
46             }
47              
48             sub init_draw {
49 0     0 1   my ($self, $switch) = @_;
50              
51 0           $self->crib_set = 0;
52 0           $self->starter_card = undef;
53 0 0         $self->dealer = !$self->dealer if $switch;
54              
55 0           my $winner;
56 0 0         if ($self->board->score->player1->{current} > 120) {
    0          
57 0           $winner = 'player1';
58             } elsif ($self->board->score->player2->{current} > 120) {
59 0           $winner = 'player2';
60             }
61 0 0         return $self->winner($winner) if $winner;
62              
63 0           $self->draw_cards();
64              
65 0           $self->discard_cards();
66              
67 0           $self->starter();
68              
69 0           while (!$winner) {
70 0           $self->clear_screen();
71              
72 0           $self->print_header(q|It is your turn to play a card, type go if you're unable to play.|);
73              
74 0           my $ok = eval { $self->play_hand(); };
  0            
75              
76 0 0         unless ($@) {
77 0 0         if ($self->board->score->player1->{current} > 120) {
    0          
78 0           $winner = 'player1';
79 0           next;
80             } elsif ($self->board->score->player2->{current} > 120) {
81 0           $winner = 'player2';
82 0           next;
83             }
84              
85              
86 0           my $hands = $self->board->get_hands;
87 0 0         unless (grep { !$_->{used} } @{$hands->player2->cards}, @{$hands->player1->cards}) {
  0            
  0            
  0            
88 0           eval {
89 0           $self->end_hands();
90             };
91 0 0         if ($@) {
92 0           while (1) {
93 0           print $@;
94             }
95             }
96 0           return $self->init_draw(1);
97             }
98              
99 0 0         if ($self->board->no_player_can_play) {
100 0           eval { $self->board->next_play(); };
  0            
101 0 0         if ($@) {
102 0           while (1) {
103 0           print $@;
104             }
105             }
106             }
107             }
108             }
109 0           $self->winner($winner);
110             }
111              
112             sub end_hands {
113 0     0 1   my ($self) = @_;
114              
115 0           $self->board->end_play();
116            
117 0           my $hands = $self->board->get_hands;
118              
119 0           $self->board->end_hands();
120              
121 0           $self->crib_set = 0;
122              
123 0           $self->clear_screen();
124              
125 0           my $last = $self->board->last_round_hands();
126 0           my $player1_score = $last->player1->score->total_score;
127 0           my $player2_score = $last->player2->score->total_score;
128 0 0         my $crib_player = $self->dealer ? $self->board->players->[-1]->name : 'Bot';
129 0 0         my $crib_score = $last->{$self->dealer ? 'player2' : 'player1'}->crib_score->total_score;
130              
131 0           $self->print_header(sprintf "Bot scored: %s - %s scored: %s - %s crib scored: %s",
132             $player1_score,
133             $self->board->players->[-1]->name,
134             $player2_score,
135             $crib_player,
136             $crib_score
137             );
138              
139 0           $self->draw_scores();
140              
141 0           $self->render_player_cards($hands->player1->cards, 3, 20, 1);
142              
143 0           $self->render_player_cards($hands->{$hands->crib_player}->crib, 15, 20, 1);
144              
145 0           $self->render_player_cards($hands->player2->cards, 26, 20, 1);
146              
147 0           $self->print_footer(q|Press enter to continue|);
148              
149            
150 0           }
151              
152             sub play_hand {
153 0     0 1   my ($self) = @_;
154              
155 0           my $hands = $self->board->get_hands;
156            
157 0 0         if ($self->board->next_to_play->player eq 'player1') {
158 0           my $card = $self->board->best_run_play('player1');
159 0 0         if ($card->go) {
160 0           $self->board->cannot_play('player1');
161 0           $self->draw_go(6, 2);
162             } else {
163 0           $self->board->play_card('player1', $card);
164 0 0         if ($self->board->current_play_score == 31) {
165 0           $self->board->next_play();
166 0           return;
167             }
168              
169 0 0         if ($self->board->score->player1->{current} > 120) {
170 0           return;
171             }
172             }
173             }
174              
175 0 0         if ($self->board->player_cannot_play('player2')) {
176 0 0         if (!$self->board->player_cannot_play('player1')) {
177 0           $self->board->set_next_to_play('player1');
178             }
179 0           return;
180             }
181              
182 0           $_[0]->draw_scores();
183              
184 0           $self->render_opponent_cards(scalar grep { !$_->{used} } @{$hands->player1->cards});
  0            
  0            
185              
186 0           $self->render_run_play();
187              
188 0           $self->render_player_cards($hands->player2->cards, 26, 20);
189              
190 0           $self->print_footer(q|Pick a card: |);
191              
192 0           my $number = ;
193              
194 0           chomp($number);
195              
196 0 0         if ($number =~ m/go/i) {
197 0           my @can = $self->board->cannot_play('player2');
198 0 0 0       if (scalar @can && ref $can[0]) {
199 0           return;
200             }
201 0           $self->draw_go(30);
202 0           return;
203             }
204              
205 0 0         if ($number eq 'b') {
206 0           my $card = $self->board->best_run_play('player2');
207 0 0         if ($card->go) {
208 0           $self->board->cannot_play('player2');
209 0           $self->draw_go(6, 2);
210             } else {
211 0           $self->board->play_card('player2', $card);
212 0 0         if ($self->board->current_play_score == 31) {
213 0           $self->board->next_play();
214             }
215             }
216 0           return;
217             }
218            
219 0 0 0       if ($number !~ m/^\d+$/ || $number > scalar @{$hands->player2->cards}) {
  0            
220 0           return;
221             }
222              
223 0           my $card = $self->board->get_card('player2', $number - 1);
224 0           $self->board->play_card('player2', $card);
225              
226 0 0         if ($self->board->current_play_score == 31) {
227 0           $self->board->next_play();
228             }
229              
230 0           return 1;
231             }
232              
233             sub split_cards {
234 0     0 1   my ($self) = @_;
235              
236 0           $self->print_header(q|Split cards lowest goes first|);
237              
238 0           $self->show_face_down_split(52);
239            
240 0           $self->print_footer(q|Pick a number: |);
241              
242 0           my $number = ;
243            
244 0 0 0       if ($number !~ m/^\d+$/ || $number > 52) {
245 0           $self->clear_screen();
246 0           $self->split_cards();
247 0           return;
248             }
249              
250 0           my $low = $self->board->deck->get($number - 1);
251              
252 0           my $rand = int(rand(52));
253            
254 0           while ($number == $rand) {
255 0           $rand = int(rand(52));
256             }
257              
258 0           my $bot = $self->board->deck->get($rand - 1);
259              
260 0           $self->clear_screen();
261              
262 0 0         my $dealer = $low->value < $bot->value ? 1 : 0;
263              
264 0 0         $self->print_header(q|Low cards picked, | . ($dealer ? "you are the dealer" : "they are the dealer"));
265              
266 0           $self->render_card($bot, 2, 45);
267              
268 0           $self->render_card($low, 27, 45);
269              
270 0 0         $self->board->set_crib_player($dealer ? 'player2' : 'player1');
271              
272 0           $self->print_footer(q|Press enter to continue|);
273              
274 0           $self->dealer = $dealer;
275              
276            
277 0           }
278              
279             sub draw_cards {
280 0     0 1   my ($self) = @_;
281              
282 0           $self->board->draw_hands();
283             }
284              
285             sub discard_cards {
286 0     0 1   my ($self) = @_;
287            
288 0           $self->clear_screen();
289              
290 0           $self->print_header(q|Discard two cards to the crib, seperate the indexes with a space.|);
291              
292 0           my $hands = $self->board->get_hands;
293              
294 0           $self->render_opponent_cards(6);
295              
296 0           $self->render_player_cards($hands->player2->cards, 26, 5);
297              
298 0           $self->print_footer(q|Discard cards: |);
299              
300 0           my $cards_index = ;
301              
302 0           chomp($cards_index);
303              
304             my @cards = map {
305 0           $self->board->get_card('player2', $_ - 1);
306 0 0         } grep { $_ =~ m/^\d+$/ && $_ <= 6 } split " ", $cards_index;
  0            
307              
308 0 0         unless (scalar @cards == 2) {
309 0           $self->discard_cards();
310 0           return;
311             }
312              
313 0           $self->board->crib_player_cards('player2', \@cards);
314              
315 0           my @bot = $self->board->identify_worst_cards('player1');
316              
317 0           $self->board->crib_player_cards('player1', $bot[0]);
318              
319 0           $self->crib_set = 1;
320             }
321              
322             sub starter {
323 0     0 1   my ($self) = @_;
324              
325 0           $self->clear_screen();
326              
327 0           my $count = scalar @{$self->board->deck->{deck}};
  0            
328 0 0         if ($self->dealer) {
329 0           my $card = $self->board->deck->get(int(rand(39)));
330 0           $self->starter_card = $card;
331 0           $self->board->add_starter_card('player1', $card);
332 0           return;
333             }
334              
335 0           $self->print_header(q|Split deck for starter card.|);
336            
337 0           $self->show_face_down_split(40, 13);
338              
339 0           $self->print_footer(q|Split deck: |);
340              
341 0           my $number = ;
342            
343 0           chomp($number);
344            
345 0 0 0       if ($number !~ m/^\d+$/ || $number > 52) {
346 0           $self->clear_screen();
347 0           $self->starter();
348 0           return;
349             }
350              
351 0           my $card = $self->board->deck->get($number);
352 0           $self->starter_card = $card;
353 0           my $scored = $self->board->add_starter_card('player2', $card);
354 0           return;
355             }
356              
357             sub render_card {
358 0     0 1   my ($self, $card, $row, $col) = @_;
359              
360 0           $self->set_cursor_vertical($row);
361 0           $self->set_cursor_horizontal($col);
362 0 0         my $color = $card->suit =~ m/H|D/ ? 91 : 90;
363            
364 0           my %suits = (
365             H => '♥',
366             D => '♦',
367             C => '♣',
368             S => '♠'
369             );
370              
371             my @card = (
372             "┌─────────┐",
373             sprintf("│%s. . . .│", $card->symbol =~ m/10/ ? $card->symbol : $card->symbol . " "),
374             "│. . . . .│",
375             "│. . . . .│",
376 0 0         sprintf("│. . %s . .│", $suits{$card->suit}),
    0          
377             "│. . . . .│",
378             "│. . . . .│",
379             sprintf("│. . . .%s│", $card->symbol =~ m/10/ ? $card->symbol : " " . $card->symbol),
380             "└─────────┘"
381             );
382              
383 0           for (@card) {
384 0           $self->say($_, 1, 0, $color);
385 0           $self->set_cursor_horizontal($col);
386             }
387             }
388              
389              
390             sub render_opponent_cards {
391 0     0 1   my ($self, $num) = @_;
392              
393 0 0         return unless $num;
394              
395 0           $self->set_cursor_vertical(2);
396 0           $self->set_cursor_horizontal((100 - ($num * 4)) / 2);
397              
398 0           my $string = "┌──" x ($num - 1);
399 0           $self->say($string);
400 0           $self->say("┌─────────┐", 1, 1);
401 0           $self->set_cursor_horizontal((100 - ($num * 4)) / 2);
402 0           for (0..6) {
403 0           $string = "│. " x ($num - 1);
404 0           $self->say($string);
405 0           $self->say("│. . . . .│", 1, 1);
406 0           $self->set_cursor_horizontal((100 - ($num * 4)) / 2);
407             }
408 0           $string = "└──" x ($num - 1);
409 0           $self->say($string);
410 0           $self->say("└─────────┘", 1, 1);
411             }
412              
413             sub render_player_cards {
414 0     0 1   my ($self, $cards, $top, $left, $all) = @_;
415 0           my $i = 1;
416 0           for (@{$cards}) {
  0            
417 0 0 0       if (!$all && $_->{used}) {
418 0           $i++;
419 0           next;
420             }
421 0           $left += 11;
422 0           $self->set_cursor_vertical($top);
423 0           $self->set_cursor_horizontal($left + 5);
424 0           $self->say($i++);
425 0           $self->render_card($_, $top + 1, $left);
426             }
427             }
428              
429             sub render_run_play {
430 0     0 1   my ($self) = @_;
431              
432 0           my $cards = $self->board->current_play->cards;
433              
434 0 0         return unless (scalar @{$cards});
  0            
435              
436 0           my $left = 25;
437 0           for (@{$cards}) {
  0            
438 0           $self->render_card($_->card, 15, $left);
439 0           $left += 10;
440             }
441             }
442              
443              
444             sub show_face_down_split {
445 0     0 1   my ($self, $num, $vertical) = @_;
446              
447 0   0       $self->set_cursor_vertical($vertical || 10);
448              
449 0           my $width = ($num / 2) - 1;
450              
451 0           for my $it (0 .. 1) {
452 0           my $string = "┌──" x $width;
453 0           $self->say($string);
454 0           $self->say("┌─────────┐", 1, 1);
455 0           $string = "";
456 0           for (1 .. $width) {
457 0 0         my $v = $it ? 26 + $_ : $_;
458 0 0 0       $string .= sprintf("│%s", (!$it && $_ < 10 ? "$v " : $v));
459             }
460 0           $self->say($string);
461 0 0         $self->say(sprintf("│%s. . . .│", $it ? ($width + 1) * 2 : $width + 1), 1, 1);
462 0           for (0..4) {
463 0           $string = "│. " x $width;
464 0           $self->say($string);
465 0           $self->say("│. . . . .│", 1, 1);
466             }
467 0           $string = "│. " x $width;
468 0           $self->say($string);
469 0 0         $self->say(sprintf("│. . . .%s│", $it ? ($width + 1) * 2 : $width + 1), 1, 1);
470 0           my $string = "└──" x $width;
471 0           $self->say($string);
472 0           $self->say("└─────────┘", 1, 1);
473             }
474             }
475              
476             sub draw_background {
477 0     0 1   for (0 .. 35) {
478 0           print "\e[102;1m";
479 0           print pack("A100", " ");
480 0           print "\n";
481 0           print "\e[0";
482             }
483 0           $_[0]->draw_dealer();
484             #$_[0]->draw_scores();
485 0           $_[0]->draw_crib();
486 0           $_[0]->draw_starter();
487 0           $_[0]->reset_cursor();
488             }
489              
490             sub draw_starter {
491 0     0 1   my ($self) = @_;
492              
493 0 0         return unless $self->starter_card;
494              
495 0           $self->render_card($self->starter_card, 15, 2);
496             }
497              
498              
499             sub draw_crib {
500 0     0 1   my ($self) = shift;
501 0           my $dealer = $self->dealer;
502 0 0         return unless defined $dealer;
503 0 0         return unless $self->crib_set;
504 0           my @card = (
505             "┌─────────┐",
506             "│. . . . .│",
507             "│. . . . .│",
508             "│. . . . .│",
509             "│. . . . .│",
510             "│. . . . .│",
511             "│. . . . .│",
512             "│. . . . .│",
513             "└─────────┘"
514             );
515              
516 0 0         if ($dealer) {
517 0           $self->set_cursor_vertical(27);
518             } else {
519 0           $self->set_cursor_vertical(3);
520             }
521              
522 0           for (@card) {
523 0           $self->set_cursor_horizontal(10);
524 0           $self->say($_, 1, 0);
525             }
526             }
527              
528             sub draw_go {
529 0     0 1   my ($self, $top, $left) = @_;
530 0           my $message = ' GO ';
531 0           $self->set_cursor_vertical($top);
532 0           $self->say($message, 0, 0, 31, 40);
533             }
534              
535              
536             sub draw_dealer {
537 0     0 1   my ($self) = @_;
538            
539 0           my $dealer = $self->dealer;
540              
541 0 0         return unless defined $dealer;
542 0           my $message = ' Dealer ';
543 0 0         if ($dealer) {
544 0           $self->set_cursor_vertical(34);
545 0           $self->say($message, 0, 0, 31, 40);
546             } else {
547 0           $self->set_cursor_vertical(3);
548 0           $self->say($message, 0, 0, 31, 40);
549             }
550             }
551              
552             sub draw_scores {
553 0     0 1   my ($self) = @_;
554 0           my $message;
555 0 0         return unless $self->board;
556 0 0 0       if ($self->board && $self->board->current_play_score) {
557 0           $message = pack("A2", $self->board->current_play_score);
558 0           $self->set_cursor_vertical(14);
559 0           $self->set_cursor_horizontal(49);
560 0           $self->say($message, 0, 0, 31, 40);
561             }
562 0           $message = ' Score: ' . $self->board->score->player2->{current} . ' ';
563 0           $self->set_cursor_vertical(34);
564 0           $self->set_cursor_horizontal(100 - (length($message) + 1));
565 0           $self->say($message, 0, 0, 31, 40);
566 0           $message = ' Score: ' . $self->board->score->player1->{current} . ' ';
567 0           $self->set_cursor_vertical(3);
568 0           $self->set_cursor_horizontal(100 - (length($message) + 1));
569 0           $self->say($message, 0, 0, 31, 40);
570             }
571              
572             sub winner {
573 0     0 1   print "\e[0m\e[2J\e[0;1H";
574 0           for (0 .. 35) {
575 0           print "\e[102;1m";
576 0           print pack("A100", " ");
577 0           print "\n";
578 0           print "\e[0";
579             }
580 0           $_[0]->set_cursor_vertical(17);
581 0           my $player = $_[0]->board->players->[1];
582 0 0         $_[0]->say($_[1] eq 'player2'
583             ? sprintf(q|Congratualations %s, you won the game!|, $player->name)
584             : sprintf(q|Unlucky %s, you lost this time!|, $player->name)
585             );
586            
587 0           }
588              
589              
590             sub clear_screen {
591 0     0 1   print "\e[0m\e[2J\e[0;1H";
592 0           $_[0]->draw_background();
593             }
594              
595             sub reset_cursor {
596 0     0 1   print "\e[;2H";
597             }
598              
599             sub set_cursor_vertical {
600 0     0 1   print "\e[$_[1];2H";
601             }
602              
603             sub set_cursor_horizontal {
604 0     0 1   print "\e[$_[1]G";
605             }
606              
607             sub say {
608 0     0 1   my ($self, $msg, $nl, $indent, $color, $back) = @_;
609 0   0       $color ||= 90;
610 0   0       $back ||= 102;
611 0           print "\e[$color;1;1m\e[$back;1m";
612 0           print $msg;
613 0 0         print "\n" if $nl;
614 0 0         $self->set_cursor_horizontal(2) if $indent;
615 0           print "\e[0";
616 0           1;
617             }
618              
619             sub print_header {
620 0     0 1   my ($self, $message) = @_;
621 0           $self->set_cursor_verical(0);
622 0           $self->set_cursor_horizontal(0);
623 0           print "\e[40;1m";
624 0           print pack("A100", " ");
625 0           $self->set_cursor_horizontal(2);
626 0           $self->say($message, 0, 0, 31, 40);
627             }
628              
629             sub print_footer {
630 0     0 1   my ($self, $message) = @_;
631 0           $self->set_cursor_vertical(36);
632 0           $self->set_cursor_horizontal(0);
633 0           print "\e[40;1m";
634 0           print pack("A100", " ");
635 0           $self->set_cursor_horizontal(2);
636 0           $self->say($message, 0, 0, 31, 40);
637 0           $self->set_cursor_horizontal(length($message) + 2);
638             }
639              
640              
641             1;
642              
643             __END__