File Coverage

blib/lib/Poker/Eval.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Poker::Eval;
2 1     1   22691 use strict;
  1         3  
  1         27  
3 1     1   962 use Moo;
  1         20032  
  1         11  
4 1     1   3437 use Poker::Hand;
  1         3  
  1         31  
5 1     1   605 use Poker::Dealer;
  0            
  0            
6             use Algorithm::Combinatorics qw(combinations);
7             use Storable qw(dclone);
8              
9             =head1 NAME
10              
11             Poker::Eval - Deal, score, and calculate expected win rates of poker hands. Base class for specific game types.
12              
13             =head1 VERSION
14              
15             Version 0.02
16              
17             =cut
18              
19             our $VERSION = '0.02';
20              
21             =head1 SYNOPSIS
22              
23             This is just a base class. Poker::Eval::Omaha shows a real example.
24              
25             use Poker::Eval::Omaha; # Omaha style rules
26             use Poker::Score::High; # Highball scoring system
27             use feature qw(say);
28              
29             # Object to represent a typical post flop situation
30             my $ev = Poker::Eval::Omaha->new(
31             scorer => Poker::Score::High->new,
32             hole_remaining => 0, # hole cards already dealt
33             community_remaining => 2, # turn and river yet to come
34             );
35              
36             # shuffle deck
37             $ev->dealer->shuffle_deck;
38              
39             # deal three community cards (post flop)
40             $ev->community_cards( $ev->deal_named(['5c','9h','Ks']));
41              
42             # deal and score three separate hands
43             my $hand1 = $ev->best_hand($ev->deal_named(['Ts','Js','3d','4d']));
44             my $hand2 = $ev->best_hand($ev->deal_named(['5h','5s','6s','7s']));
45             my $hand3 = $ev->best_hand($ev->deal(4)); # random cards
46              
47             # best combination (hole + community) in human-readable form
48             say $hand1->best_combo_flat;
49              
50             # english name of best combination (e.g. 'Two Pair')
51             say $hand1->name;
52              
53             # numerical score of best combination
54             say $hand1->score;
55              
56             # hole cards in human-readable form
57             say $hand1->cards_flat;
58              
59             # calculate expected win rate of each hand
60             $ev->calc_ev([$hand1, $hand2, $hand3]);
61              
62             # expected win rate of each hand (as percent)
63             say $hand1->ev; say $hand2->ev; say $hand3->ev;
64              
65             # hands 1, 2 and 3 win 13, 76, and 11 percent of the time respectively.
66              
67             =head1 INTRODUCTION
68              
69             Poker::Eval defines rules for evaluating poker hands. In Holdem for example, any combination of hole and community cards can be used to make the best hand, so Poker::Eval::Community is the correct subclass. But in Omaha, your best hand is made using EXACTLY two hole cards and EXACTLY three community cards, so Poker::Eval::Omaha is what you want. Other subclasses include Badugi, Chinese, and Wild.
70              
71             Poker::Eval also provides methods for calculating expected win rates in specific situations.
72             Poker::Score defines the scoring systme itself (e.g., highball, lowball 8 or better, lowball 2-7, lowball A-5, badugi, etc) See Poker::Score for a complete list.
73              
74             =head1 SEE ALSO
75              
76             Poker::Eval::Community, Poker::Eval::Omaha, Poker::Eval::Wild, Poker::Eval::Badugi, Poker::Eval::Chinese, Poker::Eval::Bitch, Poker::Eval::Badugi27, Poker::Score, Poker::Dealer
77              
78             =head1 ATTRIBUTES
79              
80             =head2 community_cards
81              
82             Array ref of Poker::Card objects representing community cards
83             =cut
84              
85             has 'community_cards' => (
86             is => 'rw',
87             isa => sub { die "Not an array ref!" unless ref( $_[0] ) eq 'ARRAY' },
88             builder => '_build_community_cards',
89             );
90              
91             sub _build_community_cards {
92             return [];
93             }
94              
95             =head2 scorer
96              
97             Required attribute that identifies the scoring system. Must be a Poker::Score
98             object. See Poker::Score for available options.
99              
100             =cut
101              
102             has 'scorer' => (
103             is => 'rw',
104             isa => sub { die "Not an Score object!" unless $_[0]->isa('Poker::Score') },
105             );
106              
107             =head2 dealer
108              
109             Standard Poker::Dealer created by default (52 card deck with no wildcards). See Poker::Dealer for options.
110              
111             =cut
112              
113             has 'dealer' => (
114             is => 'rw',
115             isa => sub { die "Not a Poker::Dealer" unless $_[0]->isa('Poker::Dealer') },
116             builder => '_build_dealer',
117             );
118              
119             =head2 simulations
120              
121             Number of simulations to run when calculating expected win rate. A high number gives you a better estimate, but also take longer. 100 is the default.
122              
123             =cut
124              
125             has 'simulations' => (
126             is => 'rw',
127             default => sub { 100 },
128             );
129              
130             =head2 hole_remaining
131              
132             Number of hole cards remaining to be dealt in the game.
133              
134             =cut
135              
136             has 'hole_remaining' => (
137             is => 'rw',
138             default => sub { 0 },
139             );
140              
141             =head2 community_remaining
142              
143             Number of community cards remaining to be dealt in the game.
144              
145             =cut
146              
147             has 'community_remaining' => (
148             is => 'rw',
149             default => sub { 0 },
150             );
151              
152             sub _build_dealer {
153             return Poker::Dealer->new;
154             }
155              
156             =head1 METHODS
157              
158             =head2 best_hand
159              
160             Returns the best Poker::Hand you can make. See Poker::Hand
161              
162             =cut
163              
164             sub best_hand { }
165              
166             sub flatten {
167             my ( $self, $cards ) = @_;
168             return join( '', map { $_->rank . $_->suit } @{$cards} );
169             }
170              
171             =head2 community_flat
172              
173             Community cards in human-readable form.
174              
175             =cut
176              
177             sub community_flat {
178             my $self = shift;
179             return $self->flatten( $self->community_cards );
180             }
181              
182             =head2 deal
183              
184             Alias for dealer->deal. See Poker::Dealer
185              
186             =cut
187              
188              
189             sub deal {
190             my ( $self, $count ) = @_;
191             return $self->dealer->deal($count);
192             }
193              
194             =head2 deal_named
195              
196             Alias for dealer->deal_named. See Poker::Dealer
197              
198             =cut
199              
200             sub deal_named {
201             my ( $self, $cards ) = @_;
202             return $self->dealer->deal_named($cards);
203             }
204              
205             =head2 calc_ev
206              
207             Takes an array ref of Poker::Hands and calculates the expected win rate for each.
208              
209             =cut
210              
211             sub calc_ev {
212             my ( $self, $hands ) = @_;
213             my $community_orig = dclone( $self->community_cards );
214             for ( 1 .. $self->simulations ) {
215             $self->dealer->shuffle_deck;
216             if ( $self->community_remaining ) {
217             $self->community_cards(
218             [ @$community_orig, @{ $self->deal( $self->community_remaining ) } ] );
219             }
220             for my $hand (@$hands) {
221             my $combo =
222             [ @{ $hand->cards }, @{ $self->deal( $self->hole_remaining ) } ];
223              
224             my $best_hand = $self->best_hand($combo);
225             $hand->temp_score( $best_hand->score );
226             }
227              
228             my @scores =
229             map { $_->temp_score } sort { $a->temp_score <=> $b->temp_score } @$hands;
230             my $top_score = pop @scores;
231             for my $hand (@$hands) {
232             $hand->wins( $hand->wins + 1 ) if $hand->temp_score == $top_score;
233             }
234             }
235             my $total_wins = 0;
236             for my $hand (@$hands) {
237             $total_wins += $hand->wins;
238             }
239             for my $hand (@$hands) {
240             $hand->ev( int( $hand->wins / $total_wins * 100 ) );
241             }
242             }
243              
244             sub BUILD {
245             my $self = shift;
246             $self->dealer->shuffle_deck;
247             }
248              
249             =head1 BUGS
250              
251             Probably. Only developer tested so far.
252              
253             =head1 AUTHOR
254              
255             Nathaniel Graham, C<< >>
256              
257             =head1 LICENSE AND COPYRIGHT
258              
259             Copyright 2016 Nathaniel Graham.
260              
261             This program is free software; you can redistribute it and/or modify it
262             under the terms of the the Artistic License (2.0). You may obtain a
263             copy of the full license at:
264              
265             L
266              
267             =cut
268              
269             1;