poker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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