poker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ # Loads mkmf which is used to make makefiles for Ruby extensions
2
+ require 'mkmf'
3
+
4
+ extension_name = 'handeval'
5
+ dir_config(extension_name)
6
+ have_library 'pokerlib'
7
+ create_makefile(extension_name)
@@ -0,0 +1,21 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE HandEval = Qnil;
4
+ void Init_handeval();
5
+
6
+ VALUE HandEval_hand_rank(VALUE self, int val);
7
+ VALUE HandEval_eval(VALUE self, int c1, int c2, int c3, int c4, int c5);
8
+
9
+ void Init_handeval() {
10
+ HandEval = rb_define_module("HandEval");
11
+ rb_define_singleton_method(HandEval, "hand_rank", HandEval_hand_rank, 1);
12
+ rb_define_singleton_method(HandEval, "eval", HandEval_eval, 5);
13
+ }
14
+
15
+ VALUE HandEval_hand_rank(VALUE self, int val) {
16
+ return INT2NUM(hand_rank(val));
17
+ }
18
+
19
+ VALUE HandEval_eval(VALUE self, int c1, int c2, int c3, int c4, int c5) {
20
+ return INT2NUM(eval_5cards(c1 / 2, c2 / 2, c3 / 2, c4 / 2, c5 / 2));
21
+ }
@@ -0,0 +1,43 @@
1
+ #define STRAIGHT_FLUSH 1
2
+ #define FOUR_OF_A_KIND 2
3
+ #define FULL_HOUSE 3
4
+ #define FLUSH 4
5
+ #define STRAIGHT 5
6
+ #define THREE_OF_A_KIND 6
7
+ #define TWO_PAIR 7
8
+ #define ONE_PAIR 8
9
+ #define HIGH_CARD 9
10
+
11
+ #define RANK(x) ((x >> 8) & 0xF)
12
+
13
+ static char *value_str[] = {
14
+ "",
15
+ "Straight Flush",
16
+ "Four of a Kind",
17
+ "Full House",
18
+ "Flush",
19
+ "Straight",
20
+ "Three of a Kind",
21
+ "Two Pair",
22
+ "One Pair",
23
+ "High Card"
24
+ };
25
+
26
+ #define CLUB 0x8000
27
+ #define DIAMOND 0x4000
28
+ #define HEART 0x2000
29
+ #define SPADE 0x1000
30
+
31
+ #define Deuce 0
32
+ #define Trey 1
33
+ #define Four 2
34
+ #define Five 3
35
+ #define Six 4
36
+ #define Seven 5
37
+ #define Eight 6
38
+ #define Nine 7
39
+ #define Ten 8
40
+ #define Jack 9
41
+ #define Queen 10
42
+ #define King 11
43
+ #define Ace 12
@@ -0,0 +1,205 @@
1
+ #include <stdio.h>
2
+ #include "arrays.h"
3
+ #include "poker.h"
4
+
5
+ // Poker hand evaluator
6
+ //
7
+ // Kevin L. Suffecool
8
+ // suffecool@bigfoot.com
9
+ //
10
+
11
+ void srand48();
12
+ double drand48();
13
+
14
+ // perform a binary search on a pre-sorted array
15
+ //
16
+ int findit( int key )
17
+ {
18
+ int low = 0, high = 4887, mid;
19
+
20
+ while ( low <= high )
21
+ {
22
+ mid = (high+low) >> 1; // divide by two
23
+ if ( key < products[mid] )
24
+ high = mid - 1;
25
+ else if ( key > products[mid] )
26
+ low = mid + 1;
27
+ else
28
+ return( mid );
29
+ }
30
+ fprintf( stderr, "ERROR: no match found; key = %d\n", key );
31
+ return( -1 );
32
+ }
33
+
34
+ //
35
+ // This routine initializes the deck. A deck of cards is
36
+ // simply an integer array of length 52 (no jokers). This
37
+ // array is populated with each card, using the following
38
+ // scheme:
39
+ //
40
+ // An integer is made up of four bytes. The high-order
41
+ // bytes are used to hold the rank bit pattern, whereas
42
+ // the low-order bytes hold the suit/rank/prime value
43
+ // of the card.
44
+ //
45
+ // +--------+--------+--------+--------+
46
+ // |xxxbbbbb|bbbbbbbb|cdhsrrrr|xxpppppp|
47
+ // +--------+--------+--------+--------+
48
+ //
49
+ // p = prime number of rank (deuce=2,trey=3,four=5,five=7,...,ace=41)
50
+ // r = rank of card (deuce=0,trey=1,four=2,five=3,...,ace=12)
51
+ // cdhs = suit of card
52
+ // b = bit turned on depending on rank of card
53
+ //
54
+ init_deck( int *deck )
55
+ {
56
+ int i, j, n = 0, suit = 0x8000;
57
+
58
+ for ( i = 0; i < 4; i++, suit >>= 1 )
59
+ for ( j = 0; j < 13; j++, n++ )
60
+ deck[n] = primes[j] | (j << 8) | suit | (1 << (16+j));
61
+ }
62
+
63
+
64
+ // This routine will search a deck for a specific card
65
+ // (specified by rank/suit), and return the INDEX giving
66
+ // the position of the found card. If it is not found,
67
+ // then it returns -1
68
+ //
69
+ int
70
+ find_card( int rank, int suit, int *deck )
71
+ {
72
+ int i, c;
73
+
74
+ for ( i = 0; i < 52; i++ )
75
+ {
76
+ c = deck[i];
77
+ if ( (c & suit) && (RANK(c) == rank) )
78
+ return( i );
79
+ }
80
+ return( -1 );
81
+ }
82
+
83
+
84
+ //
85
+ // This routine takes a deck and randomly mixes up
86
+ // the order of the cards.
87
+ //
88
+ shuffle_deck( int *deck )
89
+ {
90
+ int i, n, temp[52];
91
+
92
+ for ( i = 0; i < 52; i++ )
93
+ temp[i] = deck[i];
94
+
95
+ for ( i = 0; i < 52; i++ )
96
+ {
97
+ do {
98
+ n = (int)(51.9999999 * drand48());
99
+ } while ( temp[n] == 0 );
100
+ deck[i] = temp[n];
101
+ temp[n] = 0;
102
+ }
103
+ }
104
+
105
+
106
+ print_hand( int *hand, int n )
107
+ {
108
+ int i, r;
109
+ char suit;
110
+ static char *rank = "23456789TJQKA";
111
+
112
+ for ( i = 0; i < n; i++ )
113
+ {
114
+ r = (*hand >> 8) & 0xF;
115
+ if ( *hand & 0x8000 )
116
+ suit = 'c';
117
+ else if ( *hand & 0x4000 )
118
+ suit = 'd';
119
+ else if ( *hand & 0x2000 )
120
+ suit = 'h';
121
+ else
122
+ suit = 's';
123
+
124
+ printf( "%c%c ", rank[r], suit );
125
+ hand++;
126
+ }
127
+ }
128
+
129
+
130
+ int
131
+ hand_rank( short val )
132
+ {
133
+ if (val > 6185) return(HIGH_CARD); // 1277 high card
134
+ if (val > 3325) return(ONE_PAIR); // 2860 one pair
135
+ if (val > 2467) return(TWO_PAIR); // 858 two pair
136
+ if (val > 1609) return(THREE_OF_A_KIND); // 858 three-kind
137
+ if (val > 1599) return(STRAIGHT); // 10 straights
138
+ if (val > 322) return(FLUSH); // 1277 flushes
139
+ if (val > 166) return(FULL_HOUSE); // 156 full house
140
+ if (val > 10) return(FOUR_OF_A_KIND); // 156 four-kind
141
+ return(STRAIGHT_FLUSH); // 10 straight-flushes
142
+ }
143
+
144
+
145
+ short
146
+ eval_5cards( int c1, int c2, int c3, int c4, int c5 )
147
+ {
148
+ int q;
149
+ short s;
150
+
151
+ q = (c1|c2|c3|c4|c5) >> 16;
152
+
153
+ /* check for Flushes and StraightFlushes
154
+ */
155
+ if ( c1 & c2 & c3 & c4 & c5 & 0xF000 )
156
+ return( flushes[q] );
157
+
158
+ /* check for Straights and HighCard hands
159
+ */
160
+ s = unique5[q];
161
+ if ( s ) return ( s );
162
+
163
+ /* let's do it the hard way
164
+ */
165
+ q = (c1&0xFF) * (c2&0xFF) * (c3&0xFF) * (c4&0xFF) * (c5&0xFF);
166
+ q = findit( q );
167
+
168
+ return( values[q] );
169
+ }
170
+
171
+
172
+ short
173
+ eval_5hand( int *hand )
174
+ {
175
+ int c1, c2, c3, c4, c5;
176
+
177
+ c1 = *hand++;
178
+ c2 = *hand++;
179
+ c3 = *hand++;
180
+ c4 = *hand++;
181
+ c5 = *hand;
182
+
183
+ return( eval_5cards(c1,c2,c3,c4,c5) );
184
+ }
185
+
186
+
187
+ // This is a non-optimized method of determining the
188
+ // best five-card hand possible out of seven cards.
189
+ // I am working on a faster algorithm.
190
+ //
191
+ short
192
+ eval_7hand( int *hand )
193
+ {
194
+ int i, j, q, best = 9999, subhand[5];
195
+
196
+ for ( i = 0; i < 21; i++ )
197
+ {
198
+ for ( j = 0; j < 5; j++ )
199
+ subhand[j] = hand[ perm7[i][j] ];
200
+ q = eval_5hand( subhand );
201
+ if ( q < best )
202
+ best = q;
203
+ }
204
+ return( best );
205
+ }
@@ -0,0 +1,3 @@
1
+ require 'poker/card'
2
+ require 'poker/deck'
3
+ require 'poker/hand'
@@ -0,0 +1,38 @@
1
+ module Poker
2
+ class Card
3
+ RANKS = %w{ 2 3 4 5 6 7 8 9 T J Q K A }
4
+ SUITS = %w{ c d h s }
5
+ PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
6
+
7
+ attr_reader :rank, :rank_value, :suit, :suit_value
8
+
9
+ def initialize(str)
10
+ @str = str
11
+ @rank, @suit = str.split(//)
12
+ @rank_value = RANKS.index(@rank)
13
+ @suit_value = SUITS.index(@suit)
14
+ end
15
+
16
+ # An integer is made up of four bytes. The high-order
17
+ # bytes are used to hold the rank bit pattern, whereas
18
+ # the low-order bytes hold the suit/rank/prime value
19
+ # of the card.
20
+ #
21
+ # +--------+--------+--------+--------+
22
+ # |xxxbbbbb|bbbbbbbb|cdhsrrrr|xxpppppp|
23
+ # +--------+--------+--------+--------+
24
+ #
25
+ # p = prime number of rank (deuce=2,trey=3,four=5,five=7,...,ace=41)
26
+ # r = rank of card (deuce=0,trey=1,four=2,five=3,...,ace=12)
27
+ # cdhs = suit of card
28
+ # b = bit turned on depending on rank of card #
29
+ def value
30
+ PRIMES[rank_value] | (rank_value << 8) | 0x8000 >> suit_value |
31
+ (1 << (16 + rank_value))
32
+ end
33
+
34
+ def to_s
35
+ @str
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ module Poker
2
+ class Deck < Array
3
+ def initialize
4
+ cards = []
5
+ Card::SUITS.each { |s|
6
+ Card::RANKS.each { |r|
7
+ cards << Card.new(r+s)
8
+ }
9
+ }
10
+ super(cards)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/../../ext/handeval/handeval'
2
+
3
+ module Poker
4
+ class Hand
5
+ include Enumerable
6
+ include Comparable
7
+
8
+ def self.best(cards)
9
+ best = nil
10
+ cards.combination(5).each do |c|
11
+ hand = Hand.new(*c)
12
+ best = hand if !best || hand > best
13
+ end
14
+ best
15
+ end
16
+
17
+ def initialize(*str_or_ary)
18
+ if str_or_ary.size == 1
19
+ @cards = str_or_ary[0].split(/ /).map { |s| Card.new(s) }
20
+ else
21
+ if str_or_ary[0].kind_of?(Card)
22
+ @cards = str_or_ary
23
+ else
24
+ @cards = str_or_ary.map { |s| Card.new(s) }
25
+ end
26
+ end
27
+ end
28
+
29
+ def value
30
+ HandEval.eval(*(@cards.map { |c| c.value }))
31
+ end
32
+
33
+ def rank
34
+ v = value
35
+ return "High Card" if v > 6185
36
+ return "Pair" if v > 3325
37
+ return "Two Pair" if v > 2467
38
+ return "Three of a Kind" if v > 1609
39
+ return "Straight" if v > 1599
40
+ return "Flush" if v > 322
41
+ return "Full House" if v > 166
42
+ return "Four of a Kind" if v > 10
43
+ return "Straight Flush" if v > 1
44
+ return "Royal Flush" if v == 1
45
+ end
46
+
47
+ def <=>(hand)
48
+ - (value <=> hand.value)
49
+ end
50
+
51
+ def [](index)
52
+ @cards[index]
53
+ end
54
+
55
+ def each(&block)
56
+ @cards.each(&block)
57
+ end
58
+
59
+ def size
60
+ @cards.size
61
+ end
62
+
63
+ def to_s
64
+ r = rank
65
+ if r == "Pair" || r == "Two Pair" || r == "Three of a Kind" ||
66
+ r == "Full House" || r == "Four of a Kind"
67
+ h = @cards.inject({}) { |h, c|
68
+ r = c.rank_value + 1
69
+ h[r] = h[r] ? h[r] + 1 : 0
70
+ h
71
+ }
72
+ return @cards.sort_by { |c|
73
+ if h[c.rank_value + 1] > 0
74
+ - ((h[c.rank_value + 1] * 10_000) + (c.rank_value + 1) * 100) +
75
+ c.suit_value
76
+ else
77
+ - c.rank_value + c.suit_value
78
+ end
79
+ }.join(" ")
80
+ elsif r == "Straight Flush" || r == "Straight"
81
+ return @cards.sort_by { |c|
82
+ if c.rank_value == 12
83
+ 10_000
84
+ else
85
+ - (c.rank_value + 1) * 100 - c.suit_value
86
+ end
87
+ }.join(" ")
88
+ end
89
+ @cards.sort_by { |c| - (c.rank_value + 1) * 100 - c.suit_value }.
90
+ join(" ")
91
+ end
92
+
93
+ def to_str
94
+ to_s
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ module Poker
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "poker/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "poker"
7
+ s.version = Poker::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Wojciech Mach"]
10
+ s.email = ["wojtekmach1@gmail.com"]
11
+ s.homepage = "http://rubygems.org/gems/poker"
12
+ s.summary = %q{Poker hand evaluator}
13
+ s.description = %q{Poker hand evaluator}
14
+
15
+ s.rubyforge_project = "poker"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib", "ext"]
21
+ s.extensions = ["ext/handeval/extconf.rb"]
22
+ end