poker-ranking 1.0.0

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.
data/lib/card.rb ADDED
@@ -0,0 +1,40 @@
1
+
2
+ module PokerRanking
3
+ class PokerRanking::Card
4
+
5
+ RANKS = %w(2 3 4 5 6 7 8 9 10 Jack Queen King Ace)
6
+ SUITS = %w(Hearts Diamonds Spades Clubs)
7
+
8
+ def initialize(card_data)
9
+ @suit = card_data[:suit]
10
+ @rank = card_data[:rank].to_s
11
+ set_value_by_rank_name(@rank)
12
+ end
13
+
14
+ def set_value_by_rank_name(rank)
15
+ @value = RANKS.index(rank) + 2
16
+ end
17
+
18
+ def worth_less_than(other_hand)
19
+ @value < other_hand.value
20
+ end
21
+
22
+ def to_s
23
+ "#{@rank} of #{@suit}"
24
+ end
25
+
26
+ def ==(other_card)
27
+ @value == other_card.value && @rank == other_card.rank
28
+ end
29
+
30
+ attr_reader :value
31
+ attr_reader :rank
32
+ attr_reader :suit
33
+
34
+ def self.from_name(name)
35
+ rank, suit = name.split /\s+of\s+/
36
+ PokerRanking::Card.new({rank: rank, suit: suit})
37
+ end
38
+
39
+ end
40
+ end
data/lib/hand.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 'card'
2
+
3
+ require_relative 'hand_type'
4
+
5
+ module PokerRanking
6
+
7
+
8
+ class Hand
9
+
10
+ HAND_TYPES = [HandType::StraightFlush, HandType::FourOfAKind, HandType::FullHouse, HandType::Flush, HandType::Straight, HandType::ThreeOfAKind, HandType::TwoPair, HandType::Pair, HandType::HighCard]
11
+
12
+ attr_reader :cards
13
+ attr_reader :rank
14
+ attr_reader :value
15
+ attr_reader :second_value
16
+ attr_reader :kickers
17
+
18
+ def initialize(cards)
19
+ @cards = []
20
+ cards.each do |card|
21
+ if card.is_a? PokerRanking::Card
22
+ @cards << card
23
+ elsif card.is_a? String
24
+ @cards << PokerRanking::Card::from_name(card)
25
+ else
26
+ @cards << PokerRanking::Card.new(card)
27
+ end
28
+ end
29
+
30
+ if @cards.length > 0
31
+ @cards.sort_by! { |card| card.value }
32
+
33
+ calculate_rank
34
+ end
35
+ end
36
+
37
+
38
+ def defeats?(other_hand)
39
+ if @cards.length == 0
40
+ return false
41
+ end
42
+
43
+ if other_hand.cards.length == 0
44
+ return true
45
+ end
46
+
47
+ return self.rank > other_hand.rank unless self.rank == other_hand.rank
48
+ return self.value > other_hand.value unless self.value == other_hand.value
49
+ return self.second_value > other_hand.second_value unless self.second_value == other_hand.second_value
50
+ self.kickers.each_with_index do |kicker,index|
51
+ return kicker > other_hand.kickers[index] unless kicker == other_hand.kickers[index]
52
+ end
53
+ return false
54
+ end
55
+
56
+ def name
57
+ hand_type.name
58
+ end
59
+
60
+ def ==(other)
61
+ cards == other.cards
62
+ end
63
+
64
+
65
+ private
66
+
67
+ def calculate_rank
68
+ @rank = hand_type.rank
69
+ @value = hand_type.value
70
+ @second_value = hand_type.second_value
71
+ @kickers = hand_type.kickers
72
+ end
73
+
74
+ def hand_type
75
+ HAND_TYPES.each do |hand_type_class|
76
+ hand_type = hand_type_class.new @cards
77
+ if hand_type.handles?
78
+ return hand_type
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ end
data/lib/hand_type.rb ADDED
@@ -0,0 +1,12 @@
1
+
2
+ require_relative 'hand_type/base'
3
+ require_relative 'hand_type/high_card'
4
+ require_relative 'hand_type/pair'
5
+ require_relative 'hand_type/two_pair'
6
+ require_relative 'hand_type/three_of_a_kind'
7
+ require_relative 'hand_type/straight'
8
+ require_relative 'hand_type/flush'
9
+ require_relative 'hand_type/full_house'
10
+ require_relative 'hand_type/four_of_a_kind'
11
+ require_relative 'hand_type/straight_flush'
12
+
@@ -0,0 +1,58 @@
1
+ module PokerRanking
2
+ module HandType
3
+ class Base
4
+ attr_reader :cards
5
+
6
+ def initialize(cards)
7
+ @cards = cards
8
+ end
9
+
10
+ def value
11
+ cards[-1].value
12
+ end
13
+
14
+ def n_of_a_kind?(n)
15
+ highest_same_value(n) > 0
16
+ end
17
+
18
+ def highest_same_value(n)
19
+ highest_same_value_except n, 0
20
+ end
21
+
22
+ def number_of_kickers
23
+ 5
24
+ end
25
+
26
+ def second_value
27
+ value
28
+ end
29
+
30
+ def highest_same_value_except(n, skipped_values)
31
+ skipped_values = [skipped_values] unless skipped_values.respond_to? :include?
32
+ value = 0
33
+ count = 1
34
+ last_value = 0
35
+ @cards.each do |card|
36
+ if card.value == last_value && !(skipped_values.include? card.value)
37
+ count += 1
38
+ value = last_value if count == n
39
+ else
40
+ count = 1
41
+ last_value = card.value
42
+ end
43
+ end
44
+ value
45
+ end
46
+
47
+ def kickers
48
+ kickers = []
49
+ @cards.map(&:value).reverse.each do |value|
50
+ kickers << value if @cards.map(&:value).count(value) == 1
51
+ end
52
+ kickers[0..number_of_kickers-1]
53
+ end
54
+
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,47 @@
1
+ module PokerRanking
2
+ module HandType
3
+ class Flush < Base
4
+
5
+ attr_reader :flush_suit
6
+
7
+ def handles?
8
+ count = { 'Hearts' => 0, 'Clubs' => 0, 'Diamonds' => 0, 'Spades' => 0 }
9
+ @cards.each do |card|
10
+ count[card.suit] += 1
11
+ end
12
+
13
+ count.each do |suit, suit_count|
14
+ if suit_count >= 5
15
+ @flush_suit = suit
16
+ return true
17
+ end
18
+ end
19
+
20
+ return false
21
+ end
22
+
23
+ def value
24
+ kickers.first
25
+ end
26
+
27
+ #only use kickers that are of the suit
28
+ def kickers
29
+ kick = []
30
+ @cards.reverse.each do |card|
31
+ if card.suit == @flush_suit
32
+ kick << card.value
33
+ end
34
+ end
35
+ kick[0..number_of_kickers-1]
36
+ end
37
+
38
+ def rank
39
+ 5
40
+ end
41
+
42
+ def name
43
+ 'flush'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module PokerRanking
3
+ module HandType
4
+ class FourOfAKind < Base
5
+
6
+ def handles?
7
+ n_of_a_kind? 4
8
+ end
9
+
10
+ def number_of_kickers
11
+ 1
12
+ end
13
+
14
+ def rank
15
+ 7
16
+ end
17
+
18
+ def value
19
+ highest_same_value 4
20
+ end
21
+
22
+ #because the kicker could be part of a pair
23
+ def kickers
24
+ [[super,highest_same_value_except(2,value)].flatten.max]
25
+ end
26
+
27
+ def name
28
+ 'four of a kind'
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ module PokerRanking
2
+ module HandType
3
+ class FullHouse < Base
4
+
5
+ def handles?
6
+ return false unless n_of_a_kind? 3
7
+ second_value > 0
8
+ end
9
+
10
+ def rank
11
+ 6
12
+ end
13
+
14
+ def second_value
15
+ highest_same_value_except(2, value)
16
+ end
17
+
18
+ def value
19
+ highest_same_value 3
20
+ end
21
+
22
+ def name
23
+ 'full house'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module PokerRanking
2
+ module HandType
3
+ class HighCard < Base
4
+
5
+ def handles?
6
+ true
7
+ end
8
+
9
+ def rank
10
+ 0
11
+ end
12
+
13
+ def name
14
+ 'high card'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+
2
+ module PokerRanking
3
+ module HandType
4
+ class Pair < Base
5
+
6
+ def handles?
7
+ n_of_a_kind? 2
8
+ end
9
+
10
+ def rank
11
+ 1
12
+ end
13
+
14
+ def value
15
+ highest_same_value 2
16
+ end
17
+
18
+ def number_of_kickers
19
+ 3
20
+ end
21
+
22
+ def name
23
+ 'pair'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ module PokerRanking
2
+ module HandType
3
+ class Straight < Base
4
+
5
+ def handles?
6
+ straight_value > 0
7
+ end
8
+
9
+ def rank
10
+ 4
11
+ end
12
+
13
+ def value
14
+ straight_value
15
+ end
16
+
17
+ def name
18
+ 'straight'
19
+ end
20
+
21
+ private
22
+
23
+ def straight_value
24
+ count = 1
25
+ last_value = 0
26
+ value = 0
27
+
28
+ if has_ace()
29
+ count += 1
30
+ last_value = 1
31
+ end
32
+
33
+ @cards.each do |card|
34
+ if card.value == last_value + 1
35
+ count += 1
36
+ else
37
+ count = 1
38
+ end
39
+ last_value = card.value
40
+
41
+ if count >= 5
42
+ value = card.value
43
+ end
44
+ end
45
+ value
46
+ end
47
+
48
+ def has_ace
49
+ @cards[-1].rank == 'Ace'
50
+ end
51
+
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ module PokerRanking
2
+ module HandType
3
+ class StraightFlush < Base
4
+
5
+ SUITS = %w(Hearts Diamonds Spades Clubs)
6
+
7
+ def handles?
8
+ (value > 0)
9
+ end
10
+
11
+ def rank
12
+ 8
13
+ end
14
+
15
+ def value
16
+ SUITS.each do |suit|
17
+ value_for_suit = straight_value_for_suit(suit)
18
+ return value_for_suit if value_for_suit > 0
19
+ end
20
+ 0
21
+ end
22
+
23
+ def name
24
+ 'straight flush'
25
+ end
26
+
27
+ private
28
+
29
+ def straight_value_for_suit(suit)
30
+ count = 1
31
+ last_value = 0
32
+ value = 0
33
+
34
+ if has_ace_of_suit(suit)
35
+ count += 1
36
+ last_value = 1
37
+ end
38
+
39
+ cards.each do |card|
40
+ if card.suit == suit
41
+ if card.value == last_value + 1
42
+ count += 1
43
+ else
44
+ count = 1
45
+ end
46
+ last_value = card.value
47
+
48
+ if count >= 5
49
+ value = card.value
50
+ end
51
+ end
52
+ end
53
+ value
54
+ end
55
+
56
+ def has_ace_of_suit(suit)
57
+ cards.each do |card|
58
+ return true if card.value == 14 && card.suit == suit
59
+ end
60
+
61
+ false
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+
2
+ module PokerRanking
3
+ module HandType
4
+ class ThreeOfAKind < Base
5
+
6
+ def handles?
7
+ n_of_a_kind? 3
8
+ end
9
+
10
+ def number_of_kickers
11
+ 2
12
+ end
13
+
14
+ def rank
15
+ 3
16
+ end
17
+
18
+ def value
19
+ highest_same_value 3
20
+ end
21
+
22
+ def name
23
+ 'three of a kind'
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,50 @@
1
+ module PokerRanking
2
+
3
+ module HandType
4
+ class TwoPair < Base
5
+
6
+ def handles?
7
+ has_two_pair?
8
+ end
9
+
10
+ def rank
11
+ 2
12
+ end
13
+
14
+ def value
15
+ highest_same_value 2
16
+ end
17
+
18
+ def number_of_kickers
19
+ 1
20
+ end
21
+
22
+ def second_value
23
+ highest_same_value_except(2, value)
24
+ end
25
+
26
+ def kickers
27
+ [[super,highest_same_value_except(2,[value,second_value])].flatten.max]
28
+ end
29
+
30
+ def name
31
+ 'two pairs'
32
+ end
33
+
34
+ private
35
+
36
+ def has_two_pair?
37
+ pair_count = 0
38
+ last_value = 0
39
+ @cards.each do |card|
40
+ if card.value == last_value
41
+ pair_count += 1
42
+ end
43
+ last_value = card.value
44
+ end
45
+ return pair_count >= 2
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,6 @@
1
+ require_relative 'hand'
2
+ require_relative 'card'
3
+
4
+ module PokerRanking
5
+ VERSION = '1.0.0'
6
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poker-ranking
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Rafael Ordog aka DeVill
9
+ - Paul Yule
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-01-31 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rake
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Created for the lean poker project
48
+ email: rafael@ordog.tk
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/hand_type/high_card.rb
54
+ - lib/hand_type/straight.rb
55
+ - lib/hand_type/flush.rb
56
+ - lib/hand_type/full_house.rb
57
+ - lib/hand_type/straight_flush.rb
58
+ - lib/hand_type/base.rb
59
+ - lib/hand_type/pair.rb
60
+ - lib/hand_type/four_of_a_kind.rb
61
+ - lib/hand_type/two_pair.rb
62
+ - lib/hand_type/three_of_a_kind.rb
63
+ - lib/card.rb
64
+ - lib/hand_type.rb
65
+ - lib/poker_ranking.rb
66
+ - lib/hand.rb
67
+ homepage: http://leanpoker.org
68
+ licenses:
69
+ - MIT
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 1.8.23
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Poker cards, and ranking utilities for poker apps.
92
+ test_files: []