File Coverage

blib/lib/Games/Cards/ShuffleTrack.pm
Criterion Covered Total %
statement 316 320 98.7
branch 96 98 97.9
condition 26 27 96.3
subroutine 54 54 100.0
pod 34 34 100.0
total 526 533 98.6


line stmt bran cond sub pod time code
1             package Games::Cards::ShuffleTrack;
2              
3 17     17   235496 use 5.006;
  17         46  
4 17     17   67 use strict;
  17         25  
  17         623  
5 17     17   56 use warnings;
  17         23  
  17         433  
6              
7 17     17   57 use List::Util qw/any min/;
  17         27  
  17         1628  
8 17     17   8174 use List::MoreUtils qw/zip first_index/;
  17         136624  
  17         117  
9 17     17   8589 use Scalar::Util qw/looks_like_number/;
  17         25  
  17         44764  
10              
11             =head1 NAME
12              
13             Games::Cards::ShuffleTrack - Track cards through shuffles and cuts
14              
15             =head1 VERSION
16              
17             Version 0.04
18              
19             =cut
20              
21             our $VERSION = '0.04';
22              
23             my $cut_limits = {
24             normal => [0.19, 0.82], # on a 52 cards deck, cut between 10 and 43 cards
25             short => [0.09, 0.28], # on a 52 cards deck, cut between 5 and 15 cards
26             center => [0.36, 0.59], # on a 52 cards deck, cut between 19 and 31 cards
27             deep => [0.67, 0.86], # on a 52 cards deck, cut between 35 and 45 cards
28             };
29              
30             my $decks = {
31             empty => [],
32             new_deck_order => [qw/AH 2H 3H 4H 5H 6H 7H 8H 9H 10H JH QH KH
33             AC 2C 3C 4C 5C 6C 7C 8C 9C 10C JC QC KC
34             KD QD JD 10D 9D 8D 7D 6D 5D 4D 3D 2D AD
35             KS QS JS 10S 9S 8S 7S 6S 5S 4S 3S 2S AS/],
36             fournier => [qw/AS 2S 3S 4S 5S 6S 7S 8S 9S 10S JS QS KS
37             AH 2H 3H 4H 5H 6H 7H 8H 9H 10H JH QH KH
38             KD QD JD 10D 9D 8D 7D 6D 5D 4D 3D 2D AD
39             KC QC JC 10C 9C 8C 7C 6C 5C 4C 3C 2C AC/],
40             };
41              
42             my $shortcuts = {
43             'top' => 1,
44             'second' => 2,
45             'greek' => -2,
46             'bottom' => -1,
47             };
48              
49             my $expressions = {
50             A => qr/A[CHSD]/,
51             2 => qr/2[CHSD]/,
52             3 => qr/3[CHSD]/,
53             4 => qr/4[CHSD]/,
54             5 => qr/5[CHSD]/,
55             6 => qr/6[CHSD]/,
56             7 => qr/7[CHSD]/,
57             8 => qr/8[CHSD]/,
58             9 => qr/9[CHSD]/,
59             10 => qr/10[CHSD]/,
60             J => qr/J[CHSD]/,
61             Q => qr/Q[CHSD]/,
62             K => qr/K[CHSD]/,
63              
64             C => qr/(?:[A23456789JQK]|10)C/,
65             H => qr/(?:[A23456789JQK]|10)H/,
66             S => qr/(?:[A23456789JQK]|10)S/,
67             D => qr/(?:[A23456789JQK]|10)D/,
68             };
69              
70              
71             =head1 SYNOPSIS
72              
73             This module allows you to simulate shuffles and cuts.
74              
75             use Games::Cards::ShuffleTrack;
76              
77             my $deck = Games::Cards::ShuffleTrack->new();
78              
79             $deck->overhand_shuffle( 2 );
80             $deck->riffle_shuffle();
81             $deck->cut( 'short' );
82             $deck->riffle_shuffle();
83             print "@{$deck->get_deck()}";
84              
85             Or perhaps with more precision:
86              
87             my $deck = Games::Cards::ShuffleTrack->new();
88              
89             $deck->faro_in();
90             $deck->cut( 26 );
91             print $deck->get_deck();
92              
93             See the rest of the documentation for more advanced features. See the examples folder for more detailed usage.
94              
95              
96             =head1 INSTALLATION
97              
98             To install this module, run the following commands:
99              
100             perl Makefile.PL
101             make
102             make test
103             make install
104              
105              
106             =head1 DECK REPRESENTATION
107              
108             At the moment a deck is represented as a list of strings; each string represents a card where the first letter or digit (or digits, in the case of a 10) is the value of the card and the following letter is the suit:
109              
110             C - Clubs
111             H - Hearts
112             S - Spades
113             D - Diamonds
114              
115             As an example, some card representations:
116              
117             AC - Ace of Clubs
118             10S - Ten of Spades
119             4D - 4 of Diamonds
120             KH - King of Hearts
121              
122             Still, you can add whichever cards you want to the deck:
123              
124             $deck->put( 'Joker' ); # place a Joker on top of the deck
125              
126              
127             =head1 SUBROUTINES/METHODS
128              
129             =head2 Standard methods
130              
131             =head3 new
132              
133             Create a new deck.
134              
135             my $deck = Games::Cards::ShuffleTrack->new();
136              
137             The order of the deck is from top to bottom, which means it is the reverse of what you see when you spread a deck in your hands with the cards facing you.
138              
139             When you open most professional decks of cards you'll see the Ace of Spades (AS) in the front; this means it will actually be the 52nd card in the deck, since when you place the cards on the table facing down it will be the bottom card.
140              
141             Currently this module doesn't support specific orders or different orders other than the new deck.
142              
143             The order of the cards is as follows:
144              
145             Ace of Hearths through King of Hearts
146             Ace of Clubs through King of Clubs
147             King of Diamonds through Ace of Diamonds
148             King of Spades through Ace of Spades
149              
150             You can also specify the starting order of the deck among the following:
151              
152             =over 4
153              
154             =item * new_deck_order (the default order)
155              
156             =item * fournier
157              
158             =back
159              
160             my $deck = Games::Cards::ShuffleTrack->new( 'fournier' );
161              
162             You can also set your own order:
163              
164             my $pile = Games::Cards::ShufleTrack->new( [qw/10S JS QS KS AS/] );
165              
166             =cut
167              
168             # TODO: What happens if the user has a typo in the order?
169             sub new {
170 37     37 1 5415 my ($self, $order) = @_;
171 37   100     188 $order ||= 'new_deck_order';
172              
173 37         38 my $cards;
174 37 100       108 if ( ref $order eq 'ARRAY' ) {
175 1         2 $cards = $order;
176             }
177             else {
178 36         77 $cards = $decks->{ $order };
179             }
180              
181 37         185 return bless {
182             'deck' => $cards,
183             'original' => $cards,
184             'orientation' => 'down',
185             }, $self;
186             }
187              
188             =head3 restart
189              
190             Reset the deck to its original status. The original is whatever you selected when you created the deck.
191              
192             $deck->restart;
193              
194             Do bear in mind that by doing so you are replenishing the deck of whatever cards you took out of it.
195              
196             =cut
197              
198             sub restart {
199 134     134 1 17073 my $self = shift;
200 134         123 return $self->_set_deck( @{$self->{'original'}} );
  134         362  
201             }
202              
203              
204             =head3 size, deck_size
205              
206             Returns the size of the deck.
207              
208             my $size = $deck->deck_size;
209              
210             =cut
211              
212             sub size {
213 54     54 1 1050 my $self = shift;
214 54         64 return $self->deck_size;
215             }
216              
217             sub deck_size {
218 635     635 1 2453 my $self = shift;
219 635         435 return scalar @{$self->{'deck'}};
  635         1492  
220             }
221              
222              
223             =head3 original_size
224              
225             Returns the original size of the deck.
226              
227             if ($size < 0.5 * $deck->original_size) {
228             # if the deck has been exausted by over 50%
229             }
230              
231             =cut
232              
233             sub original_size {
234 4     4 1 5 my $self = shift;
235 4         5 return scalar @{$self->{'original'}};
  4         12  
236             }
237              
238              
239             =head3 get_deck
240              
241             Returns the deck (a reference to a list of strings).
242              
243             my $cards = $deck->get_deck();
244              
245             =cut
246              
247             # TODO: should we return a copy of the list instead of the list itself?
248             # TODO: use wantarray to allow for an array to be returned?
249             sub get_deck {
250 1243     1243 1 1109 my $self = shift;
251 1243         3511 return $self->{'deck'};
252             }
253              
254              
255             =head3 orientation
256              
257             Return whether the deck is face up or face down:
258              
259             if ( $deck->orientation eq 'down' ) {
260             ...
261             }
262              
263             The deck's orientation is either 'up' or 'down'.
264              
265             =cut
266              
267             sub orientation {
268 17     17 1 13 my $self = shift;
269              
270 17         62 return $self->{'orientation'};
271             }
272              
273              
274             =head3 turn
275              
276             If the deck was face up, it is turned face down; if the deck was face down, it is turned face up.
277              
278             Turning the deck reverses its order.
279              
280             $deck->turn;
281              
282             =cut
283              
284             sub turn {
285 14     14 1 13 my $self = shift;
286              
287 14 100       24 $self->{'orientation'} = $self->orientation eq 'down' ? 'up' : 'down';
288              
289 14         17 return $self->_set_deck( reverse @{$self->get_deck} );
  14         18  
290             }
291              
292             =head3 count
293              
294             Counts how many cards with specific characteristics are in the deck.
295              
296             # how many tens
297             $deck->count( '10' );
298              
299             # how many Clubs
300             $deck->count( 'C' );
301              
302             # how many Clubs and Hearts
303             my ($clubs, $hearts) = $deck->count( 'C', 'H' );
304             my $clubs_and_hearts = $deck->count( 'C', 'H' );
305              
306             # how many Jokers
307             $deck->count( 'Joker' );
308              
309             Since you can add whichever card you want to the deck, it should be noted how searching for values and suits works:
310              
311             =over 4
312              
313             =item * If looking for a value from 2 to A, you'll get the amount of cards with that value and one of the four suits
314              
315             =item * If looking for a suit (C, H, S, D), you'll get the amount of cards with a value from 2 through Ace and that suit
316              
317             =item * If looking for anything else, that something is compared to the whole card
318              
319             =back
320              
321             It is important to note:
322              
323             my $total = $deck->count( 'JC' ); # holds 4
324             my $total = $deck->count( 'C', J ); # holds 16, because the JC is only counted once
325             my @total = $deck->count( 'C', J ); # holds (13, 4)
326              
327             Also:
328              
329             $deck->put( 'Joker' );
330             $deck->put( 'Signed Joker' );
331             $deck->count( 'Joker' ); # returns 2
332              
333             $deck->put( 'Signed 4C' );
334             $deck->count( '4C' ); # returns 2, because you didn't removed the previous one
335              
336             =cut
337              
338             sub count {
339 33     33 1 3508 my $self = shift;
340 33         31 my @results;
341              
342 33 100 100     99 if ( wantarray and @_ > 1 ) {
343 3         7 return $self->_count_each( @_ );
344             }
345             else {
346 30         42 return $self->_count_all( @_ );
347             }
348             }
349              
350             sub _count_each {
351 3     3   3 my $self = shift;
352 3         4 my @results;
353 3         8 while (my $param = shift) {
354 6 100       12 if ( exists $expressions->{$param} ) {
355 5         3 push @results, scalar grep { /$expressions->{$param}/ } @{$self->get_deck};
  264         439  
  5         6  
356             }
357             else {
358 1         2 push @results, scalar grep { /$param/ } @{$self->get_deck};
  52         58  
  1         2  
359             }
360             }
361 3         32 return @results;
362             }
363              
364             sub _count_all {
365 30     30   29 my $self = shift;
366              
367 30         22 my @expressions;
368 30         42 for my $param (@_) {
369             push @expressions, exists $expressions->{$param} ?
370 35 100       116 $expressions->{$param} :
371             qr/$param/x,
372             }
373              
374 30         26 my @results;
375 30         28 for my $card (@{$self->get_deck}) {
  30         36  
376              
377 1586 100   1800   2629 if (any { $card =~ $_ } @expressions) {
  1800         4526  
378 211         349 push @results, $card;
379             }
380              
381             }
382 30         120 return scalar @results;
383             }
384              
385              
386             =head2 Shuffling
387              
388             =head3 Overhand Shuffle
389              
390             =head4 overhand_shuffle
391              
392             In an overhand shuffle the cards are moved from hand to the other in packets, the result being similar to that of running cuts (the difference being that the packets in an overhand shuffle may be smaller than the ones in a running cut sequence).
393              
394             $deck->overhand_shuffle;
395              
396             You can specify how many times you want to go through the deck (which is basically the same thing as calling the method that many times):
397              
398             $deck->overhand_shuffle( 2 );
399              
400             =cut
401              
402             sub overhand_shuffle {
403 6     6 1 11 my $self = shift;
404 6         8 my $times = shift;
405              
406 6 100       15 if (not defined $times) {
407 1         1 $times = 1;
408             }
409              
410 6 100       17 return $self if $times < 1;
411              
412 4         12 $self->_packet_transfer( 1, 10 );
413              
414 4 100       31 return $times > 1 ?
415             $self->overhand_shuffle( $times - 1 ) :
416             $self
417             }
418              
419              
420             =head4 run
421              
422             The act of running cards is similar to the overhand shuffle, but instead of in packets the cards are run singly.
423              
424             $deck->run( 10 );
425              
426             When running cards you can choose whether to drop those cards on the top or on the bottom of the deck. By default, the cards are moved to the bottom of the deck.
427              
428             $deck->run( 10, 'drop-top' );
429             $deck->run( 10, 'drop-bottom' );
430              
431             Running cards basically reverses their order.
432              
433             If no number is given then no cards are run.
434              
435             If we're doing multiple runs we can set everything at the same time:
436              
437             $deck->run( 4, 6, 2 );
438              
439             =cut
440              
441             # TODO: review this code
442             sub run {
443 15     15 1 25 my $self = shift;
444              
445 15         12 my @number_of_cards;
446             my $where_to_drop;
447              
448 15         29 while ( my $param = shift ) {
449 18 100       35 if ( looks_like_number( $param ) ) {
450 9         24 push @number_of_cards, $param;
451             }
452             else {
453 9         18 $where_to_drop = $param;
454             }
455             }
456              
457 15 100       41 @number_of_cards || return $self;
458 8   100     25 $where_to_drop ||= 'drop-bottom';
459              
460 8         9 my $number_of_cards = shift @number_of_cards;
461 8 100       16 $number_of_cards > 0 or return $self;
462              
463             # take cards from top and reverse their order
464 7         20 my @deck = @{$self->get_deck};
  7         10  
465 7         16 my @run = reverse splice @deck, 0, $number_of_cards;
466              
467 7 100       13 if ( $where_to_drop eq 'drop-top' ) {
468 2         7 $self->_set_deck( @run, @deck );
469             }
470             else { # drop-bottom is the default
471 5         8 $self->_set_deck( @deck, @run );
472             }
473              
474 7         21 return $self->run( @number_of_cards, $where_to_drop );
475             }
476              
477              
478             =head3 Hindu Shuffle
479              
480             =head4 hindu_shuffle
481              
482             In a Hindu shuffle the cards are moved from hand to the other in packets, the result being similar to that of running cuts (the difference being that the packets in an overhand shuffle may be smaller than the ones in a running cut sequence).
483              
484             $deck->hindu_shuffle;
485              
486             You can specify how many times you want to go through the deck (which is basically the same thing as calling the method that many times):
487              
488             $deck->hindu_shuffle( 2 );
489              
490             The Hindu shuffle differs in result from the Overhand shuffle in that the packets are usually thicker; the reason for this is that while in the Overhand shuffle it's the thumb that grabs the cards (and the thumb can easily carry just one or two cards) in the Hindu shuffle it's more than one finger accomplishing this task, grabbing the deck by the sides, which makes it more difficult (hence, rare) to cut just one or two cards.
491              
492             =cut
493              
494             sub hindu_shuffle {
495 3     3 1 7 my $self = shift;
496 3   100     11 my $times = shift || 1;
497              
498 3         5 $self->_packet_transfer( 4, 10 );
499              
500 3 100       18 return $times > 1 ?
501             $self->hindu_shuffle( $times - 1 ) :
502             $self
503             }
504              
505             sub _packet_transfer {
506 9     9   10 my $self = shift;
507 9         8 my $min = shift;
508 9         10 my $max = shift;
509              
510 9         8 my @deck = @{$self->get_deck};
  9         13  
511              
512 9         7 my @new_deck;
513              
514 9         20 while ( @deck ) {
515 91 100       174 if (@deck < $max) { $max = scalar @deck }
  19         18  
516 91 100       140 if (@deck < $min) { $min = scalar @deck }
  3         4  
517 91         103 unshift @new_deck, splice @deck, 0, _rand( $min, $max );
518             }
519              
520 9         21 return $self->_set_deck( @new_deck );
521             }
522              
523              
524             =head3 Riffle Shuffle
525              
526             =head4 riffle_shuffle
527              
528             Riffle shuffle the deck.
529              
530             $deck->riffle_shuffle();
531              
532             In the act of riffle shuffling a deck the deck is cut into two halves of approximately the same size; each half is riffled so that the cards of both halves interlace; these cards usually drop in groups of 1 to 5 cards.
533              
534             You can also decide where to cut the deck for the shuffle:
535              
536             $deck->riffle_shuffle( 'short' ); # closer to the top
537             $deck->riffle_shuffle( 'center' ); # near the center
538             $deck->riffle_shuffle( 'deep' ); # closer to the bottom
539             $deck->riffle_shuffle( 26 ); # precisely under the 26th card
540              
541             =cut
542              
543             # TODO: add an option for an out-shuffle
544             # TODO: add an option to control top or bottom stock
545             # TODO: when dropping cards, should we favor numbers 2 and 3?
546             # TODO: with a lot of cards, the riffle should be done breaking the deck in piles
547             # TODO: consider how fast each half is being depleted and whether the packets riffled on each side are of similar sizes
548             sub riffle_shuffle {
549 5     5 1 17 my $self = shift;
550 5         6 my $depth = shift;
551              
552             # cut the deck (left pile is the original top half)
553 5         10 my $cut_depth = _cut_depth( $self->deck_size, $depth );
554              
555 5         6 my @left_pile = @{$self->get_deck};
  5         9  
556 5         24 my @right_pile = splice @left_pile, $cut_depth;
557              
558 5         10 my @halves = ( \@left_pile, \@right_pile );
559              
560             # drop cards from the bottom of each half to the pile (1-5 at a time)
561 5         7 my @new_pile = ();
562 5   100     23 while ( @left_pile and @right_pile ) {
563 73         47 my $current_half = $halves[0];
564 73         115 my $number_of_cards = int(rand( min(5, scalar @$current_half) ))+1;
565              
566 73         100 unshift @new_pile, splice @$current_half, -$number_of_cards;
567              
568 73         214 @halves = reverse @halves;
569             }
570              
571             # drop the balance on top and set the deck to be the result
572 5         16 $self->_set_deck( @left_pile, @right_pile, @new_pile );
573              
574 5         21 return $self;
575             }
576              
577              
578             =head3 Faro shuffle
579              
580             In a faro shuffle the deck is split in half and the two halves are interlaced perfectly so that each card from one half is inserted in between two cards from the opposite half.
581              
582             =head4 faro out
583              
584             Faro out the deck.
585              
586             $deck->faro( 'out' );
587              
588             In a "faro out" the top and bottom cards remain in their original positions.
589              
590             Considering the positions on the cards from 1 to 52 the result of the faro would be as follows:
591              
592             1, 27, 2, 28, 3, 29, 4, 30, 5, 31, 6, 32, 7, 33, ...
593              
594             =head4 faro in
595              
596             Faro in the deck.
597              
598             $deck->faro( 'in' );
599              
600             In a "faro in" the top and bottom cards do not remain in their original positions (top card becomes second from the top, bottom card becomes second from the bottom).
601              
602             Considering the positions on the cards from 1 to 52 the result of the faro would be as follows:
603              
604             27, 1, 28, 2, 29, 3, 30, 4, 31, 5, 32, 6, 33, 7, ...
605              
606             =cut
607              
608             sub faro {
609 60     60 1 1523 my $self = shift;
610 60         50 my $faro = shift; # by default we're doing a faro out
611              
612             # TODO: what happens when the deck is odd-sized?
613 60         43 my @first_half = @{$self->get_deck};
  60         56  
614 60         64 my @second_half = splice @first_half, $self->deck_size / 2;
615              
616 60 100       438 $self->_set_deck(
617             $faro eq 'in' ?
618             zip @second_half, @first_half :
619             zip @first_half, @second_half
620             );
621              
622 60         379 return $self;
623             }
624              
625              
626             =head2 Cutting
627              
628             =head3 cut
629              
630             Cut the deck.
631              
632             $deck->cut();
633              
634             In a 52 cards deck, this would cut somewhere between 10 and 43 cards.
635              
636             Cut at a precise position (moving X cards from top to bottom):
637              
638             $deck->cut(26);
639              
640             If you try to cut to a position that doesn't exist nothing will happen (apart from a warning that you tried to cut to a non-existing position, of course).
641              
642             You can also cut at negative positions, meaning that you're counting from the bottom of the deck and cutting above that card. For instance, to cut the bottom two cards to the top:
643              
644             $deck->cut(-2);
645              
646             Additional ways of cutting:
647              
648             $deck->cut( 'short' ); # on a 52 cards deck, somewhere between 5 and 15 cards
649             $deck->cut( 'center' ); # on a 52 cards deck, somewhere between 19 and 31 cards
650             $deck->cut( 'deep' ); # on a 52 cards deck, somewhere between 35 and 45 cards
651              
652             =head3 cut_below
653              
654             You can cut below a specific card.
655              
656             $deck->cut_below( '9D' );
657              
658             If the desired card is already on the bottom of the deck nothing will happen.
659              
660             For more information on how to cut to a specific card please refer to the L section of this documentation.
661              
662             =head3 cut_above
663              
664             You can cut above a specific card.
665              
666             $deck->cut_above( 'JS' );
667              
668             If the desired card is already on top of the deck nothing will happen.
669              
670             For more information on how to cut to a specific card please refer to the L section of this documentation.
671              
672             =cut
673              
674             # TODO: delimit randomness of the cut between two numbers: $deck->cut( 1, 25 );
675             sub cut {
676 26     26 1 44 my $self = shift;
677 26         22 my $position = shift;
678              
679 26 50 100     152 if ( defined $position
      66        
680             and looks_like_number( $position )
681             and abs($position) > $self->deck_size ) {
682 0         0 warn "Tried to cut the deck at a non-existing position ($position).\n";
683 0         0 return $self;
684             }
685              
686 26         38 my $cut_depth = _cut_depth( $self->deck_size, $position );
687              
688 26         27 my @deck = @{$self->get_deck};
  26         31  
689 26         138 unshift @deck, splice @deck, $cut_depth;
690              
691 26         73 return $self->_set_deck( @deck );
692             }
693              
694             sub cut_below {
695 5     5 1 1112 my $self = shift;
696 5         5 my $card = shift;
697              
698 5         8 return $self->cut( $self->find( $card ) );
699             }
700              
701             sub cut_above {
702 6     6 1 2042 my $self = shift;
703 6         10 my $card = shift;
704              
705 6         11 return $self->cut( $self->find( $card ) - 1 );
706             }
707              
708             =head3 cut_to
709              
710             Cuts a portion of the deck to another position
711              
712             $deck->cut_to( $pile );
713              
714             You can specify exactly how many cards to cut or delimit the randomness of the cut:
715              
716             # cut exactly 15 cards to $pile
717             $deck->cut_to( $pile, 15 );
718              
719             # cut between 10 and 26 cards to $pile
720             $deck->cut_to( $pile, 10, 26 );
721              
722             If the position doesn't exist yet you can also automatically create it:
723              
724             my $pile = $deck->cut_to();
725              
726             This method returns the new pile.
727              
728             =cut
729              
730             # FIXME: in some situations this method alters the original order of the deck
731             sub cut_to {
732 19     19 1 17 my $self = shift;
733              
734             # create the new pile if required
735 19         14 my $new_pile;
736 19 100 100     86 if ( defined($_[0]) and ref( $_[0] ) eq 'Games::Cards::ShuffleTrack' ) {
737 11         13 $new_pile = shift;
738             }
739             else {
740 8         17 $new_pile = Games::Cards::ShuffleTrack->new( 'empty' );
741             }
742              
743             # TODO: could this be done with _cut_depth? (perhaps changing it a bit)
744             # set the position
745 19         19 my $lower_limit = shift;
746 19         16 my $upper_limit = shift;
747              
748 19         13 my $position;
749              
750 19 100       43 if ( not defined $lower_limit ) {
    100          
751 2         4 $position = _rand( 1, $self->deck_size );
752             }
753             elsif ( not defined $upper_limit ) {
754 10         11 $position = $lower_limit;
755             }
756             else {
757 7         14 $position = _rand( $lower_limit, $upper_limit );
758             }
759              
760             # cut the deck
761 19         21 $new_pile->place_on_top( splice @{$self->get_deck}, 0, $position );
  19         28  
762              
763 19         31 return $new_pile;
764             }
765              
766              
767             =head3 place_on_top
768              
769             Places a pile of cards on top of the deck.
770              
771             $deck->place_on_top( qw/AS KS QS JS 10S/ );
772              
773             =cut
774              
775             # TODO place_on_top and put share similar code; review
776             sub place_on_top {
777 20     20 1 16 my $self = shift;
778 20         68 my @pile = @_;
779              
780 20         25 $self->_set_deck( @pile, @{$self->get_deck} );
  20         30  
781              
782 20         40 return $self;
783             }
784              
785             =head3 complete_cut, move_to
786              
787             Complete the cut by moving all cards from one deck onto another:
788              
789             $deck->complete_cut( $new_pile );
790            
791             # or
792              
793             $deck->move_to( $table );
794              
795             =cut
796              
797             sub complete_cut {
798 7     7 1 6 my $self = shift;
799 7         7 my $destination = shift;
800              
801 7         18 $self->cut_to( $destination, $self->deck_size );
802              
803 7         10 return $self;
804             }
805              
806             sub move_to {
807 7     7 1 5 my $self = shift;
808              
809 7         17 return $self->complete_cut( @_ );
810             }
811              
812              
813             =head3 running_cuts
814              
815             Cut packets:
816              
817             $deck->running_cuts();
818              
819             To do the procedure twice:
820              
821             $deck->running_cuts( 2 );
822              
823             =cut
824              
825             sub running_cuts {
826 2     2 1 6 my $self = shift;
827 2   100     9 my $times = shift || 1;
828              
829 2         5 $self->_packet_transfer( 5, 15 );
830              
831 2 100       11 return $times > 1 ?
832             $self->overhand_shuffle( $times - 1 ) :
833             $self
834             }
835              
836              
837             =head3 bury
838              
839             Buries a group of cards under another group:
840              
841             # bury the top 10 cards under the following 3 cards
842             $deck->bury(10, 3);
843              
844             # move the top card to the 13th position
845             $deck->bury( 1, 12 );
846              
847             =cut
848              
849             sub bury {
850 2     2 1 10 my $self = shift;
851 2         3 my $first_amount = shift;
852 2         2 my $second_amount = shift;
853              
854 2         4 my @deck = @{$self->get_deck};
  2         5  
855              
856 2         8 splice @deck, $second_amount, 0, splice @deck, 0, $first_amount;
857              
858 2         10 $self->_set_deck( @deck );
859              
860 2         10 return $self;
861             }
862              
863              
864             =head2 Handling cards
865              
866             There are a few different methods to track down cards.
867              
868             =head3 find
869              
870             Get the position of specific cards:
871              
872             my $position = $deck->find( 'AS' ); # find the position of the Ace of Spades
873              
874             my @positions = $deck->find( 'AS', 'KH' ); # find the position of two cards
875              
876             If a card is not present on the deck the position returned will be a 0.
877              
878             This method can also return the card at a specific position:
879              
880             my $card = $deck->find( 3 );
881              
882             You can also request a card in a negative position (i.e., from the bottom of the deck). To get the second to last card in the deck:
883              
884             $deck->find( -2 );
885              
886             If you're dealing five hands of poker from the top of the deck, for instance, you can easily find which cards will fall on the dealer's hand:
887              
888             $deck->find( 5, 10, 15, 20, 25 );
889              
890             =cut
891              
892             sub find {
893 424     424 1 30471 my $self = shift;
894 424         561 my @cards = @_;
895              
896 424         335 my @results;
897              
898 424         522 my $deck = $self->get_deck();
899              
900 424         566 for my $card ( @cards ) {
901              
902 462 100       1214 push @results, looks_like_number( $card )
903             ? $self->_find_card_by_position( $card )
904             : $self->_find_card_by_name( $card );
905              
906             }
907              
908 424 100       1291 return wantarray ? @results : $results[0];
909             }
910              
911             sub _find_card_by_position {
912 398     398   321 my $self = shift;
913 398         284 my $card = shift;
914              
915 398 100       493 if ($card) {
916 396 100       627 if ($card > 0) { $card--; }
  368         291  
917 396 100       486 return $card > $self->deck_size - 1 ?
918             q{} :
919             $self->get_deck->[ $card ];
920             }
921             else {
922 2         5 return q{};
923             }
924             }
925              
926             sub _find_card_by_name {
927 64     64   58 my $self = shift;
928 64         52 my $card = shift;
929              
930 64     1431   180 my $position = 1 + first_index { $_ eq $card } @{$self->get_deck};
  1431         1330  
  64         84  
931              
932 64 100       244 return $position ? $position : 0;
933             }
934              
935              
936             =head3 find_card_before
937              
938             Finds the card immediately before another card:
939              
940             # return the card immediately before the Ace of Spades
941             $deck->find_card_before( 'AS' );
942              
943             If the specified card is on top of the deck you will get the card on the bottom of the deck.
944              
945             =cut
946              
947             sub find_card_before {
948 2     2 1 4 my $self = shift;
949 2         3 my $card = shift;
950              
951 2         4 my $position = $self->find( $card );
952              
953 2 100       6 if ($position == 1) {
954 1         3 return 0;
955             }
956             else {
957 1         3 return $self->find( $position - 1 );
958             }
959             }
960              
961              
962             =head3 find_card_after
963              
964             Finds the card immediately after another card:
965              
966             # return the card immediately after the King of Hearts
967             $deck->find_card_before( 'KH' );
968              
969             If the specified card is on the bottom of the deck you will get the card on the top of the deck.
970              
971             =cut
972              
973             sub find_card_after {
974 2     2 1 3 my $self = shift;
975 2         3 my $card = shift;
976              
977 2         5 my $position = 1 + $self->find( $card );
978            
979 2 100       4 if ( $position > $self->deck_size ) {
980 1         4 return 0;
981             }
982              
983 1         3 return $self->find( $self->find( $card ) + 1 );
984             }
985              
986              
987             =head3 distance
988              
989             Find the distance between two cards.
990              
991             To find the distance between the Ace of Spades and the King of Hearts:
992              
993             $deck->distance( 'AS', 'KH' );
994              
995             If the King of Hearts is just after the Ace of Spades, then the result is 1. If it's immediately before, the result is -1.
996              
997             =cut
998              
999             sub distance {
1000 7     7 1 796 my $self = shift;
1001 7         9 my $first_card = shift;
1002 7         9 my $second_card = shift;
1003              
1004 7         16 return $self->find( $second_card) - $self->find( $first_card );
1005             }
1006              
1007              
1008             =head3 put
1009              
1010             Put a card on top of the deck. This is a new card, and not a card already on the deck.
1011              
1012             $deck->put( $card );
1013              
1014             If the card was already on the deck, you now have a duplicate card.
1015              
1016             =cut
1017              
1018             sub put {
1019 17     17 1 21 my $self = shift;
1020 17         16 my $card = shift;
1021              
1022 17         29 $self->_set_deck( $card, @{$self->get_deck} );
  17         28  
1023              
1024 17         36 return $self;
1025             }
1026              
1027              
1028             =head3 insert
1029              
1030             Inserts a card in a specified position in the deck. If the position isn't specified than the card is inserted somewhere at random.
1031              
1032             # insert a Joker at position 20
1033             $deck->insert( 'Joker', 20 );
1034              
1035             # replace a card somewhere in the deck at random
1036             $deck->insert( $card );
1037              
1038             If the position doesn't exist the card will be replaced at the bottom of the deck.
1039              
1040             You can also add cards to negative positions, meaning that the resulting position will be that negative position:
1041              
1042             # insert card so that it ends up being the last one in the deck
1043             $deck->insert( $card, -1 );
1044              
1045             # insert card so that it ends up being the 10th from the bottom
1046             $deck->insert( $card, -10 );
1047              
1048             =cut
1049              
1050             # TODO: what if the user inserts at position 0?
1051             sub insert {
1052 7     7 1 13 my $self = shift;
1053 7         8 my $card = shift;
1054 7         10 my $position = shift;
1055              
1056 7 100       25 if ( not defined $position ) {
    100          
    100          
1057 1         4 $position = _rand( 1, $self->deck_size );
1058             }
1059             elsif ( $position > $self->deck_size ) {
1060 1         4 $position = $self->deck_size + 1;
1061             }
1062             elsif ( $position < 0 ) {
1063 2         10 $position = $self->deck_size + $position + 2;
1064             }
1065              
1066 7         11 splice @{$self->get_deck}, $position - 1, 0, $card;
  7         19  
1067              
1068 7         16 return $self;
1069             }
1070              
1071              
1072             =head3 deal
1073              
1074             Deals a card, removing it from the deck.
1075              
1076             my $removed_card = $deck->deal();
1077              
1078             Just as in regular gambling, you can deal cards from other positions:
1079              
1080             # deal the second card from the top
1081             my $card = $deck->deal( 'second' );
1082              
1083             # deal the second card from the bottom
1084             my $card = $deck->deal( 'greek' );
1085              
1086             # deal the card from the bottom of the deck
1087             my $card = $deck->deal( 'bottom' );
1088              
1089             For more information on false dealing see the L section.
1090              
1091             If you're dealing cards to a pile you can actually state where you're dealing:
1092              
1093             $deck->deal( $pile );
1094              
1095             You can still do a false deal to a pile:
1096              
1097             $deck->deal( 'second', $pile );
1098              
1099             # or
1100              
1101             $deck->deal( $pile, 'second' );
1102              
1103             Dealing from an empty deck won't do anything, but a warning will be issued.
1104              
1105             =cut
1106              
1107             sub deal {
1108 19     19 1 48 my $self = shift;
1109              
1110 19 100       24 if (not $self->size) {
1111 2         114 warn "Tried to deal without cards.\n";
1112 2         7 return $self;
1113             }
1114              
1115 17         34 my $deal = 'top';
1116 17         15 my $destination = undef;
1117 17         31 while (my $param = shift) {
1118 25 100       53 if ( ref( $param ) eq 'Games::Cards::ShuffleTrack' ) {
    100          
1119 11         23 $destination = $param;
1120             }
1121             elsif ( exists $shortcuts->{$param} ) {
1122 13         26 $deal = $param;
1123             }
1124             }
1125              
1126 17         19 my $position = $shortcuts->{$deal};
1127              
1128 17         20 my $card = $self->remove( $position );
1129              
1130 17 100       23 if ( defined $destination ) {
1131 11         18 return $destination->put( $card );
1132             }
1133             else {
1134 6         18 return $card;
1135             }
1136             }
1137              
1138             =head3 remove
1139              
1140             Removes a card from the deck.
1141              
1142             # remove the 4th card from the top
1143             my $card = $deck->remove( 4 );
1144              
1145             =cut
1146              
1147             # TODO: allow removal of several cards (do note that positions change as cards are removed)
1148             sub remove {
1149 74     74 1 69 my $self = shift;
1150 74         50 my $position = shift;
1151              
1152 74         47 my @deck = @{$self->get_deck};
  74         75  
1153              
1154 74 100       135 if ($position > 0) { $position--; }
  67         62  
1155              
1156 74         88 my $card = splice @deck, $position, 1;
1157              
1158 74         116 $self->_set_deck( @deck );
1159 74         302 return $card;
1160             }
1161              
1162              
1163             =head3 peek
1164              
1165             Peek at a position in the deck (this is essentially the same thing as &find()).
1166              
1167             # peek the top card
1168             my $card = $deck->peek( 1 );
1169              
1170             You can also peek the top and bottom card by using an alias:
1171              
1172             # peek the top card
1173             my $card = $deck->peek( 'top' );
1174              
1175             # peek the bottom card
1176             my $card = $deck->peek( 'bottom' );
1177              
1178             Negative indexes are also supported:
1179              
1180             # peek the second from bottom card
1181             my $card = $deck->peek( -2 );
1182              
1183             =cut
1184              
1185             sub peek {
1186 73     73 1 195 my $self = shift;
1187 73   100     145 my $position = shift || 1;
1188              
1189 73 100       110 if (_is_shortcut( $position )) {
1190 4         6 $position = $shortcuts->{$position};
1191             }
1192              
1193 73         158 return $self->find( $position );
1194             }
1195              
1196              
1197             =head3 take_random
1198              
1199             Remove a random card from the deck.
1200              
1201             my $random_card = $deck->take_random();
1202              
1203             You can also specify limits (if you're somehow directing the person taking the card to a particular section of the deck):
1204              
1205             my $random_card = $deck->take_random( 13, 39 );
1206              
1207             =cut
1208              
1209             sub take_random {
1210 56     56 1 44 my $self = shift;
1211              
1212 56   100     90 my $lower_limit = shift || 1;
1213 56         41 my $upper_limit = shift;
1214              
1215 56 100       71 $upper_limit = defined $upper_limit ?
1216             $upper_limit :
1217             $self->deck_size;
1218              
1219 56         68 return $self->remove( _rand( $lower_limit, $upper_limit ) );
1220             }
1221              
1222             =head3 dribble
1223              
1224             Dribble the cards (usually to select one, which could either be the last one to fall or the one that would be next).
1225              
1226             # dribble cards onto $pile
1227             $deck->dribble( $pile );
1228              
1229             # same thing, but declaring $pile
1230             $pile = $deck->dribble;
1231              
1232             # dribble to position 10 (in a 52 card deck, 42 cards would fall)
1233             $deck->dribble( 10 );
1234              
1235             # dribble 10 cards
1236             $deck->dribble( -10 );
1237              
1238             # dribble to position between 10 and 20
1239             $deck->dribble( 10, 20 );
1240              
1241             # dribble to position between 10th from the top and 10th from the bottom
1242             $deck->dribble( 10, -10 );
1243              
1244             =cut
1245              
1246             # TODO: what happens if you're dribbling and have no cards?
1247             sub dribble {
1248 6     6 1 12 my $self = shift;
1249 6         13 my $params = _parse_params( @_ );
1250              
1251 6         5 my $has_destination = @{$params->{'places'}};
  6         10  
1252             my $destination = $has_destination ?
1253 6 100       17 $params->{'places'}[0] :
1254             Games::Cards::ShuffleTrack->new( 'empty' );
1255              
1256 6         4 my ($lower_limit, $upper_limit) = $self->_fix_limits( @{$params->{'numbers'}} );
  6         16  
1257              
1258 6 100       13 if ( defined $lower_limit ) {
1259 4         19 $lower_limit = $self->size - $lower_limit;
1260 4 100       9 $upper_limit = defined $upper_limit ?
1261             $self->size - $upper_limit :
1262             $lower_limit;
1263             }
1264             else {
1265             # FIXME: this means we can't dribble if we have just 5 cards
1266 2         3 $lower_limit = 5; # minimum amount of cards to hold back
1267 2         6 $upper_limit = $self->size - 5; # minimum amount of cards to dribble
1268             }
1269              
1270 6         15 $self->turn;
1271 6         21 my $transfer = $self->cut_to( $lower_limit, $upper_limit );
1272 6         9 $transfer->turn;
1273 6         18 $transfer->move_to( $destination );
1274              
1275 6 100       36 return $has_destination ? $self : $destination;
1276             }
1277              
1278             # subroutines
1279              
1280             # TODO: fix limits in other methods (just being used in dribble)
1281             sub _fix_limits {
1282 6     6   6 my $self = shift;
1283 6         6 my @limits;
1284              
1285 6         19 while ( my $limit = shift ) {
1286 6 100       16 push @limits, $limit < 0 ? $self->size + $limit : $limit;
1287             }
1288              
1289 6         12 return @limits;
1290             }
1291              
1292             # TODO: use this for every method (just being used in dribble)
1293             sub _parse_params {
1294 6     6   20 my $params = {
1295             numbers => [],
1296             places => [],
1297             options => [],
1298             };
1299 6         21 while (my $param = shift) {
1300 7 100       26 if (looks_like_number($param)) {
    50          
1301 6         4 push @{$params->{'numbers'}}, $param;
  6         19  
1302             }
1303             elsif (ref $param eq 'Games::Cards::ShuffleTrack') {
1304 1         2 push @{$params->{'places'}}, $param;
  1         7  
1305             }
1306             else {
1307 0         0 push @{$params->{'options'}}, $param;
  0         0  
1308             }
1309             }
1310 6         9 return $params;
1311             }
1312              
1313             sub _set_deck {
1314 368     368   303 my $self = shift;
1315 368         2329 return $self->{'deck'} = [@_];
1316             }
1317              
1318             sub _rand {
1319 165     165   143 my ($lower_limit, $upper_limit) = @_;
1320              
1321 165         786 return int($lower_limit + int(rand( $upper_limit - $lower_limit )));
1322             }
1323              
1324             sub _cut_depth {
1325 31     31   26 my $deck_size = shift;
1326 31         28 my $position = shift;
1327              
1328 31 100       52 if (not defined $position) {
1329 5         7 $position = 'normal';
1330             }
1331              
1332 31 100   112   164 if ( any { $_ eq $position } keys %$cut_limits ) {
  112         120  
1333 8         9 my ($lower, $upper) = @{$cut_limits->{ $position }};
  8         19  
1334 8         45 $position = _rand( $deck_size * $lower, $deck_size * $upper );
1335             }
1336              
1337 31         79 return $position;
1338             }
1339              
1340             sub _is_shortcut {
1341 73     73   73 my $shortcut = shift;
1342              
1343 73         191 return exists $shortcuts->{$shortcut};
1344             }
1345              
1346              
1347             =head1 GLOSSARY
1348              
1349             The following is not a comprehensive list of gambling terms; it is simply a list of some terms used somewhere in this module that may be useful.
1350              
1351             The text has been taken verbatim from The Expert at the Card Table.
1352              
1353             =over 4
1354              
1355             =item * Stock
1356              
1357             That portion of the deck that contains certain cards, placed in some particular order for dealing; or certain
1358             desirable cards placed at top or bottom of the deck.
1359              
1360             =item * Run
1361              
1362             To draw off one card at a time during the process of the hand shuffle. There is little or no difficulty in acquiring
1363             perfect ability to run the whole deck through in this manner with the utmost rapidity. The left thumb presses
1364             lightly on the top card, the right hand alone making the movement necessary to shuffle.
1365              
1366             =item * Break
1367              
1368             A space or division held in the deck. While shuffling it is held at the end by the right thumb. It is formed under
1369             the in-jog when about to under cut for the shuffle, by pushing the in-jog card slightly upwards with the right
1370             thumb, making a space of from an eighth to a quarter of an inch wide, and holding the space, by squeezing the
1371             ends of the packet to be drawn out, between the thumb and second and third fingers. The use of the break
1372             during a shuffle makes it possible to throw any number of cards that are immediately above it, in one packet
1373             into the left hand, without disarranging their order. The break is used when not shuffling, to locate any particular
1374             card or position, and is infinitely superior to the common method of inserting the little finger. A break can be
1375             held firmly by a finger or thumb of either hand, and entirely concealed by the other fingers of the same hand. It
1376             is also the principal aid in the blind riffles and cuts.
1377              
1378             =item * Throw
1379              
1380             To pass from the right hand to the left, during a shuffle, a certain number of cards in one packet, thereby
1381             retaining their order. A throw may be required at the beginning, during the process, or at the end of a shuffle;
1382             and the packet to be thrown may be located by the jog, or break, or by both.
1383              
1384             =item * Top Card
1385              
1386             The card on top of packet held in the left hand, or the original top card of the full deck, which about to be
1387             shuffled.
1388              
1389             =item * Riffle
1390              
1391             The modern method of shuffling on the table by springing, the ends of two packets into each other.
1392              
1393             =item * Crimp
1394              
1395             To bend one or a number of cards, so that they may be distinguished or located.
1396              
1397             =back
1398              
1399              
1400             =head1 AUTHOR
1401              
1402             Jose Castro, C<< >>
1403              
1404             =head1 BUGS
1405              
1406             Please report any bugs or feature requests to C, or through
1407             the web interface at L. I will be notified, and then you'll
1408             automatically be notified of progress on your bug as I make changes.
1409              
1410              
1411             =head1 SUPPORT
1412              
1413             You can find documentation for this module with the perldoc command.
1414              
1415             perldoc Games::Cards::ShuffleTrack
1416              
1417              
1418             You can also look for information at:
1419              
1420             =over 4
1421              
1422             =item * Github
1423              
1424             L
1425              
1426             =item * Search CPAN
1427              
1428             L
1429              
1430             =back
1431              
1432              
1433             =head1 SEE ALSO
1434              
1435             The following is an extremely small list of recommended books:
1436              
1437             =over 4
1438              
1439             =item * The Expert at the Card Table, by S. W. Erdnase
1440              
1441             =item * Card College, by Roberto Giobbi
1442              
1443             =back
1444              
1445              
1446             =head1 LICENSE AND COPYRIGHT
1447              
1448             Copyright 2016 Jose Castro.
1449              
1450             This program is free software; you can redistribute it and/or modify it
1451             under the terms of the the Artistic License (2.0). You may obtain a
1452             copy of the full license at:
1453              
1454             L
1455              
1456             Any use, modification, and distribution of the Standard or Modified
1457             Versions is governed by this Artistic License. By using, modifying or
1458             distributing the Package, you accept this license. Do not use, modify,
1459             or distribute the Package, if you do not accept this license.
1460              
1461             If your Modified Version has been derived from a Modified Version made
1462             by someone other than you, you are nevertheless required to ensure that
1463             your Modified Version complies with the requirements of this license.
1464              
1465             This license does not grant you the right to use any trademark, service
1466             mark, tradename, or logo of the Copyright Holder.
1467              
1468             This license includes the non-exclusive, worldwide, free-of-charge
1469             patent license to make, have made, use, offer to sell, sell, import and
1470             otherwise transfer the Package with respect to any patent claims
1471             licensable by the Copyright Holder that are necessarily infringed by the
1472             Package. If you institute patent litigation (including a cross-claim or
1473             counterclaim) against any party alleging that the Package constitutes
1474             direct or contributory patent infringement, then this Artistic License
1475             to you shall terminate on the date that such litigation is filed.
1476              
1477             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
1478             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
1479             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
1480             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
1481             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
1482             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
1483             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
1484             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1485              
1486              
1487             =cut
1488              
1489             1; # End of Games::Cards::ShuffleTrack