ofcp_scoring 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.autotest +8 -0
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +1 -0
- data/lib/.DS_Store +0 -0
- data/lib/ofcp_scoring/chinese_poker_hand.rb +22 -0
- data/lib/ofcp_scoring/flush.rb +11 -0
- data/lib/ofcp_scoring/four_of_a_kind.rb +10 -0
- data/lib/ofcp_scoring/full_house.rb +4 -0
- data/lib/ofcp_scoring/hand_categorizer.rb +30 -0
- data/lib/ofcp_scoring/hand_evaluator.rb +50 -0
- data/lib/ofcp_scoring/hand_factory.rb +12 -0
- data/lib/ofcp_scoring/hand_organizer.rb +45 -0
- data/lib/ofcp_scoring/high_card.rb +6 -0
- data/lib/ofcp_scoring/organized_hand.rb +37 -0
- data/lib/ofcp_scoring/pair.rb +16 -0
- data/lib/ofcp_scoring/ranked_hand.rb +35 -0
- data/lib/ofcp_scoring/royal_flush.rb +3 -0
- data/lib/ofcp_scoring/royalties_calculator.rb +38 -0
- data/lib/ofcp_scoring/scoring_engine.rb +9 -0
- data/lib/ofcp_scoring/straight.rb +14 -0
- data/lib/ofcp_scoring/straight_flush.rb +2 -0
- data/lib/ofcp_scoring/three_of_a_kind.rb +10 -0
- data/lib/ofcp_scoring/two_pair.rb +22 -0
- data/lib/ofcp_scoring/version.rb +3 -0
- data/lib/ofcp_scoring.rb +9 -0
- data/ofcp_scoring-0.0.1.gem +0 -0
- data/ofcp_scoring.gemspec +24 -0
- data/spec/acceptance_spec.rb +32 -0
- data/spec/chinese_poker_hand_categorizer_spec.rb +117 -0
- data/spec/chinese_poker_hand_evaluator_spec.rb +69 -0
- data/spec/chinese_poker_hand_organizer_spec.rb +19 -0
- data/spec/chinese_poker_hand_spec.rb +23 -0
- data/spec/chinese_poker_scoring_engine_spec.rb +23 -0
- data/spec/hand_factory_spec.rb +22 -0
- data/spec/organized_hand_spec.rb +4 -0
- data/spec/ranked_hand_spec.rb +159 -0
- data/spec/royalties_calculator_spec.rb +103 -0
- data/spec/spec_helper.rb +28 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: 10da65d396f4b5efaf31275afdf8100f8f2b7a8c
|
4
|
+
data.tar.gz: 5ea2afe03038edb5e9b4cd8408d255659c5c1d93
|
5
|
+
!binary "U0hBNTEy":
|
6
|
+
metadata.gz: 9f1e47a0593cf4276ed52dd9f77e848f9f87f45607e3657c4cdcf7167b33673bdc72d7cfd2960b97c41b79ae1a4914b29fa0b56fe8b9e187c89c5721c6b4aab6
|
7
|
+
data.tar.gz: 5ba7cafebbc4e425ac7106b92410ef9d078a87d1be2e9c3f4deda9f1b36dc6efaf898f593aaf13c75951e4492ecae6c3e6b8d54e1fae963b8e3a266837528603
|
data/.DS_Store
ADDED
Binary file
|
data/.autotest
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ofcp_scoring (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.4)
|
10
|
+
rake (10.1.0)
|
11
|
+
rspec (2.14.1)
|
12
|
+
rspec-core (~> 2.14.0)
|
13
|
+
rspec-expectations (~> 2.14.0)
|
14
|
+
rspec-mocks (~> 2.14.0)
|
15
|
+
rspec-core (2.14.5)
|
16
|
+
rspec-expectations (2.14.2)
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
18
|
+
rspec-mocks (2.14.3)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (~> 1.3)
|
25
|
+
ofcp_scoring!
|
26
|
+
rake
|
27
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Clayton Lengel-Zigich
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Open Face Chinese Poker Scoring
|
2
|
+
|
3
|
+
A library for evaluating two open face chinese poker hands.
|
4
|
+
|
5
|
+
## Build Status
|
6
|
+
[![Build Status](https://travis-ci.org/clayton/ofcp_scoring.png)](https://travis-ci.org/clayton/ofcp_scoring)
|
7
|
+
|
8
|
+
## Getting Started
|
9
|
+
|
10
|
+
Without Bundler:
|
11
|
+
`gem install ofcp_scoring`
|
12
|
+
|
13
|
+
With Bundler:
|
14
|
+
Add `gem 'ofcp_scoring'` to your Gemfile
|
15
|
+
|
16
|
+
## Basic Usage
|
17
|
+
|
18
|
+
The basic scoring engine will evaluate two Chinese Poker hands calculating
|
19
|
+
royalties and scoop bonuses.
|
20
|
+
|
21
|
+
Example:
|
22
|
+
|
23
|
+
engine = OfcpScoring::ScoringEngine.new
|
24
|
+
engine.score(
|
25
|
+
%w(2h 3h 5h 10d 10h 4h 7c 8s Jd Js 6c 7d 9c),
|
26
|
+
%w(Ah 3h 5h 6d 6h 4h 7c 8s Qd Qs 6c 7d 9c)
|
27
|
+
)
|
28
|
+
#=> [1,2]
|
29
|
+
|
30
|
+
## Royalty Calculation
|
31
|
+
|
32
|
+
With Royalties you receive the following points for Back hands:
|
33
|
+
|
34
|
+
* 20 for a Royal
|
35
|
+
* 10 for StraightFlush
|
36
|
+
* 8 for Quads
|
37
|
+
* 6 for a Full House
|
38
|
+
* 4 for a OfcpScoring::Flush
|
39
|
+
* 2 for a Straight
|
40
|
+
|
41
|
+
You receive the following points for Middle hands:
|
42
|
+
|
43
|
+
* 20 for StraightFlush
|
44
|
+
* 16 for Quads
|
45
|
+
* 2 for a Full House
|
46
|
+
* 8 for a OfcpScoring::Flush
|
47
|
+
* 4 for a Straight
|
48
|
+
|
49
|
+
You receive the following points for Front hands (the 3 card hand):
|
50
|
+
|
51
|
+
* Pair of Aces: 9 points
|
52
|
+
* Pair of Kings: 8 points
|
53
|
+
* Pair of Queens: 7 points
|
54
|
+
* Pair of Jacks: 6 points
|
55
|
+
* Pair of Tens: 5 points
|
56
|
+
* Pair of Nines: 4 points
|
57
|
+
* Pair of Eights: 3 points
|
58
|
+
* Pair of Sevens: 2 points
|
59
|
+
* Paid of Sixes: 1 point
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/.DS_Store
ADDED
Binary file
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class OfcpScoring::ChinesePokerHand
|
2
|
+
def initialize(hand)
|
3
|
+
@hand = hand
|
4
|
+
end
|
5
|
+
|
6
|
+
def front
|
7
|
+
@hand[:front]
|
8
|
+
end
|
9
|
+
|
10
|
+
def middle
|
11
|
+
@hand[:middle]
|
12
|
+
end
|
13
|
+
|
14
|
+
def back
|
15
|
+
@hand[:back]
|
16
|
+
end
|
17
|
+
|
18
|
+
def misset?
|
19
|
+
true if front > middle || middle > back || front > back
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class OfcpScoring::FourOfAKind < OfcpScoring::RankedHand
|
2
|
+
def <=>(other)
|
3
|
+
return super if super
|
4
|
+
highest_quad_card <=> other.highest_quad_card
|
5
|
+
end
|
6
|
+
|
7
|
+
def highest_quad_card
|
8
|
+
grouped_ranks.map{|card,matches| card if matches.size == 4}.compact.max
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class OfcpScoring::HandCategorizer
|
2
|
+
|
3
|
+
def initialize(organizer = OfcpScoring::HandOrganizer.new)
|
4
|
+
@organizer = organizer
|
5
|
+
end
|
6
|
+
|
7
|
+
def categorize(hand)
|
8
|
+
return "" if hand.nil?
|
9
|
+
|
10
|
+
organized_hand = @organizer.organize(hand)
|
11
|
+
|
12
|
+
categorization = OfcpScoring::HighCard
|
13
|
+
categorization = OfcpScoring::Pair if organized_hand.two_cards_match?
|
14
|
+
categorization = OfcpScoring::TwoPair if organized_hand.two_different_cards_match?
|
15
|
+
categorization = OfcpScoring::ThreeOfAKind if organized_hand.three_cards_match?
|
16
|
+
|
17
|
+
unless organized_hand.three_card_hand?
|
18
|
+
categorization = OfcpScoring::Straight if organized_hand.ranks_in_order?
|
19
|
+
categorization = OfcpScoring::Flush if organized_hand.all_suits_match?
|
20
|
+
categorization = OfcpScoring::FullHouse if organized_hand.three_cards_match? && organized_hand.two_cards_match?
|
21
|
+
categorization = OfcpScoring::FourOfAKind if organized_hand.four_cards_match?
|
22
|
+
categorization = OfcpScoring::StraightFlush if organized_hand.all_suits_match? && organized_hand.ranks_in_order?
|
23
|
+
categorization = OfcpScoring::RoyalFlush if organized_hand.all_suits_match? && organized_hand.ranks_in_order? && organized_hand.high_card_ace?
|
24
|
+
end
|
25
|
+
|
26
|
+
return categorization.new(organized_hand)
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class OfcpScoring::HandEvaluator
|
2
|
+
def initialize(hand_factory = OfcpScoring::HandFactory.new, royalties_calculator = OfcpScoring::RoyaltiesCalculator.new)
|
3
|
+
@hand_factory = hand_factory
|
4
|
+
@royalties_calculator = royalties_calculator
|
5
|
+
@hand_one_score = 0
|
6
|
+
@hand_two_score = 0
|
7
|
+
@hand_one_royalties = 0
|
8
|
+
@hand_two_royalties = 0
|
9
|
+
|
10
|
+
end
|
11
|
+
def evaluate(hand_one, hand_two)
|
12
|
+
organized_hand_one = @hand_factory.build(hand_one)
|
13
|
+
organized_hand_two = @hand_factory.build(hand_two)
|
14
|
+
|
15
|
+
score_hands(organized_hand_one, organized_hand_two)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def score_hands(organized_hand_one, organized_hand_two)
|
20
|
+
[:front, :middle, :back].each do |sub_hand|
|
21
|
+
if organized_hand_one.send(sub_hand) > organized_hand_two.send(sub_hand)
|
22
|
+
@hand_one_score += 1
|
23
|
+
@hand_one_royalties += @royalties_calculator.calculate_bonus(organized_hand_one.send(sub_hand), sub_hand)
|
24
|
+
end
|
25
|
+
if organized_hand_two.send(sub_hand) > organized_hand_one.send(sub_hand)
|
26
|
+
@hand_two_score += 1
|
27
|
+
@hand_two_royalties += @royalties_calculator.calculate_bonus(organized_hand_two.send(sub_hand), sub_hand)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
adjust_for_missets(organized_hand_one, organized_hand_two)
|
32
|
+
|
33
|
+
[(@hand_one_score + @hand_one_royalties), (@hand_two_score + @hand_two_royalties)]
|
34
|
+
end
|
35
|
+
|
36
|
+
def adjust_for_missets(organized_hand_one, organized_hand_two)
|
37
|
+
if organized_hand_one.misset?
|
38
|
+
@hand_one_score = 0
|
39
|
+
@hand_two_score = 3
|
40
|
+
end
|
41
|
+
|
42
|
+
if organized_hand_two.misset?
|
43
|
+
@hand_one_score = 3
|
44
|
+
@hand_two_score = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
@hand_one_score += 3 if @hand_two_score == 0
|
48
|
+
@hand_two_score += 3 if @hand_one_score == 0
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class OfcpScoring::HandFactory
|
2
|
+
def initialize(categorizer = OfcpScoring::HandCategorizer.new)
|
3
|
+
@categorizer = categorizer
|
4
|
+
end
|
5
|
+
def build(hand)
|
6
|
+
OfcpScoring::ChinesePokerHand.new({
|
7
|
+
:front => @categorizer.categorize(hand[0..2]),
|
8
|
+
:middle => @categorizer.categorize(hand[3..7]),
|
9
|
+
:back => @categorizer.categorize(hand[8..12])
|
10
|
+
})
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class OfcpScoring::HandOrganizer
|
2
|
+
def organize(hand)
|
3
|
+
return "" if hand.nil?
|
4
|
+
suits_only = Hash.new(0)
|
5
|
+
ranks_only = Hash.new(0)
|
6
|
+
sorted_ranks = []
|
7
|
+
hand.each do |card|
|
8
|
+
ranks_only[card[0..-2]] += 1
|
9
|
+
suits_only[card[1]] += 1
|
10
|
+
case card[0]
|
11
|
+
when "A"
|
12
|
+
sorted_ranks << 1
|
13
|
+
when "K"
|
14
|
+
sorted_ranks << 13
|
15
|
+
when "Q"
|
16
|
+
sorted_ranks << 12
|
17
|
+
when "J"
|
18
|
+
sorted_ranks << 11
|
19
|
+
else
|
20
|
+
sorted_ranks << card[0..-2].to_i
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
sorted_ranks.sort!
|
25
|
+
|
26
|
+
OfcpScoring::OrganizedHand.new(build_organized_hand(ranks_only, suits_only, sorted_ranks))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def build_organized_hand(ranks, suits, sorted)
|
31
|
+
params = {:ranks => sorted}
|
32
|
+
|
33
|
+
params.merge!({:two_cards_match => true}) if ranks.values.include?(2)
|
34
|
+
params.merge!({:two_different_cards_match => true}) if ranks.find_all{|k,v| v == 2}.size > 1
|
35
|
+
params.merge!({:three_cards_match => true}) if ranks.values.include?(3)
|
36
|
+
params.merge!({:four_cards_match => true}) if ranks.values.include?(4)
|
37
|
+
params.merge!({:all_suits_match => true}) if suits.values.include?(5)
|
38
|
+
params.merge!({:ranks_in_order => true}) if (sorted.first..sorted.last).to_a == sorted
|
39
|
+
params.merge!({:ranks_in_order => true}) if (sorted & [1,10,11,12,13]) == sorted
|
40
|
+
params.merge!({:high_card_ace => true}) if sorted.include?(1)
|
41
|
+
params.merge!({:three_card_hand => true}) if sorted.size == 3
|
42
|
+
|
43
|
+
params
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class OfcpScoring::OrganizedHand
|
2
|
+
def initialize(organized_hand)
|
3
|
+
@hand = organized_hand
|
4
|
+
end
|
5
|
+
|
6
|
+
def ranks
|
7
|
+
@hand[:ranks]
|
8
|
+
end
|
9
|
+
|
10
|
+
def two_cards_match?
|
11
|
+
@hand[:two_cards_match]
|
12
|
+
end
|
13
|
+
|
14
|
+
def two_different_cards_match?
|
15
|
+
@hand[:two_different_cards_match]
|
16
|
+
end
|
17
|
+
|
18
|
+
def three_cards_match?
|
19
|
+
@hand[:three_cards_match]
|
20
|
+
end
|
21
|
+
|
22
|
+
def four_cards_match?
|
23
|
+
@hand[:four_cards_match]
|
24
|
+
end
|
25
|
+
|
26
|
+
def all_suits_match?
|
27
|
+
@hand[:all_suits_match]
|
28
|
+
end
|
29
|
+
|
30
|
+
def ranks_in_order?
|
31
|
+
@hand[:ranks_in_order]
|
32
|
+
end
|
33
|
+
|
34
|
+
def three_card_hand?
|
35
|
+
@hand[:three_card_hand]
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class OfcpScoring::Pair < OfcpScoring::RankedHand
|
2
|
+
|
3
|
+
def <=>(other)
|
4
|
+
return super if super
|
5
|
+
if highest_paired_card == other.highest_paired_card
|
6
|
+
compare_ranks(other)
|
7
|
+
else
|
8
|
+
highest_paired_card <=> other.highest_paired_card
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def highest_paired_card
|
13
|
+
grouped_ranks.map{|card,matches| card if matches.size == 2}.compact.first
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class OfcpScoring::RankedHand
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
RANKINGS = [
|
5
|
+
"HighCard", "Pair", "TwoPair", "ThreeOfAKind", "Straight", "Flush",
|
6
|
+
"FullHouse", "FourOfAKind", "StraightFlush", "RoyalFlush"
|
7
|
+
]
|
8
|
+
|
9
|
+
def rank_name
|
10
|
+
self.class.to_s.split("::").last
|
11
|
+
end
|
12
|
+
|
13
|
+
def <=>(other_hand)
|
14
|
+
RANKINGS.index(rank_name) <=> RANKINGS.index(other_hand.rank_name) unless rank_name == other_hand.rank_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(hand=nil)
|
18
|
+
@hand = hand
|
19
|
+
end
|
20
|
+
|
21
|
+
def ranks
|
22
|
+
ranks = @hand.ranks
|
23
|
+
ranks.map{|r| r == 1 ? 14 : r}.sort
|
24
|
+
end
|
25
|
+
|
26
|
+
def grouped_ranks
|
27
|
+
ranks.group_by{|card| card }
|
28
|
+
end
|
29
|
+
|
30
|
+
def compare_ranks(other)
|
31
|
+
(ranks - (ranks & other.ranks)).max <=> (other.ranks - (ranks & other.ranks)).max
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class OfcpScoring::RoyaltiesCalculator
|
2
|
+
MIDDLE = {
|
3
|
+
"StraightFlush" => 20, "FourOfAKind" => 16, "FullHouse" => 12,
|
4
|
+
"Flush" => 8, "Straight" => 4, "Pair" => 0, "HighCard" => 0
|
5
|
+
}
|
6
|
+
|
7
|
+
BACK = {
|
8
|
+
"RoyalFlush" => 20, "StraightFlush" => 10, "FourOfAKind" => 8,
|
9
|
+
"FullHouse" => 6, "Flush" => 4, "Straight" => 2, "Pair" => 0,
|
10
|
+
"HighCard" => 0
|
11
|
+
}
|
12
|
+
|
13
|
+
def calculate_bonus(hand, position)
|
14
|
+
return calculate_front(hand) if position == :front
|
15
|
+
return calculate_middle(hand) if position == :middle
|
16
|
+
return calculate_back(hand) if position == :back
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def calculate_back(hand)
|
21
|
+
BACK[hand.rank_name]
|
22
|
+
end
|
23
|
+
|
24
|
+
def calculate_middle(hand)
|
25
|
+
MIDDLE[hand.rank_name]
|
26
|
+
end
|
27
|
+
|
28
|
+
def calculate_front(hand)
|
29
|
+
return 0 unless hand.rank_name == "Pair"
|
30
|
+
bonus_accumulator = 0
|
31
|
+
bonus_start = 5
|
32
|
+
while hand.ranks.max > bonus_start
|
33
|
+
bonus_accumulator += 1
|
34
|
+
bonus_start += 1
|
35
|
+
end
|
36
|
+
bonus_accumulator
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class OfcpScoring::Straight < OfcpScoring::RankedHand
|
2
|
+
|
3
|
+
def <=>(other)
|
4
|
+
return super if super
|
5
|
+
highest_straight_card <=> other.highest_straight_card
|
6
|
+
end
|
7
|
+
|
8
|
+
def highest_straight_card
|
9
|
+
return ranks.max unless ranks.include?(14)
|
10
|
+
return 1 if ranks.include?(14) && ranks.include?(5)
|
11
|
+
return 14
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class OfcpScoring::ThreeOfAKind < OfcpScoring::RankedHand
|
2
|
+
def <=>(other)
|
3
|
+
return super if super
|
4
|
+
highest_trip_card <=> other.highest_trip_card
|
5
|
+
end
|
6
|
+
|
7
|
+
def highest_trip_card
|
8
|
+
grouped_ranks.map{|card,matches| card if matches.size == 3}.compact.max
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class OfcpScoring::TwoPair < OfcpScoring::RankedHand
|
2
|
+
def <=>(other)
|
3
|
+
return super if super
|
4
|
+
if higher_paired_card == other.higher_paired_card
|
5
|
+
if lower_paired_card == other.lower_paired_card
|
6
|
+
compare_ranks(other)
|
7
|
+
else
|
8
|
+
lower_paired_card <=> other.lower_paired_card
|
9
|
+
end
|
10
|
+
else
|
11
|
+
higher_paired_card <=> other.higher_paired_card
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def higher_paired_card
|
16
|
+
grouped_ranks.map{|card,matches| card if matches.size == 2}.compact.max
|
17
|
+
end
|
18
|
+
|
19
|
+
def lower_paired_card
|
20
|
+
grouped_ranks.map{|card,matches| card if matches.size == 2}.compact.min
|
21
|
+
end
|
22
|
+
end
|
data/lib/ofcp_scoring.rb
ADDED
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ofcp_scoring/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ofcp_scoring"
|
8
|
+
spec.version = OfcpScoring::VERSION
|
9
|
+
spec.authors = ["Clayton Lengel-Zigich"]
|
10
|
+
spec.email = ["clayton@claytonlz.com"]
|
11
|
+
spec.description = %q{Open Face Chinese Poker Scoring}
|
12
|
+
spec.summary = %q{A library to categorize, rank and score open face chinese poker hands with royalties.}
|
13
|
+
spec.homepage = "http://github.com/clayton/ofcp_scoring"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Open Face Chinese Poker" do
|
4
|
+
it "should determine how many points each poker hand owes the other" do
|
5
|
+
my_hand = %w(2h 3h 5h 10d 10h 4h 7c 8s Jd Js 6c 7d 9c)
|
6
|
+
their_hand = %w(Ah 3h 5h 6d 6h 4h 7c 8s Qd Qs 6c 7d 9c)
|
7
|
+
sut = OfcpScoring::ScoringEngine.new
|
8
|
+
expect(sut.score(my_hand, their_hand)).to eq([1, 2])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should give me a scoop bonus when I scoop the other player" do
|
12
|
+
my_hand = %w(Ah 4s Qs Js Jd 7d 6c 8h Kc Kd Ad 2c 4d)
|
13
|
+
their_hand = %w(9h 4c Qs 10s 10d 7d 6c 8h Qc Qd Ad 2c 4d)
|
14
|
+
sut = OfcpScoring::ScoringEngine.new
|
15
|
+
expect(sut.score(my_hand, their_hand)).to eq([6, 0])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should give the other player a scoop bonus when they scoop me" do
|
19
|
+
my_hand = %w(9h 4c Qs 10s 10d 7d 6c 8h Qc Qd Ad 2c 4d)
|
20
|
+
their_hand = %w(Ah 4s Qs Js Jd 7d 6c 8h Kc Kd Ad 2c 4d)
|
21
|
+
sut = OfcpScoring::ScoringEngine.new
|
22
|
+
expect(sut.score(my_hand, their_hand)).to eq([0, 6])
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
it "should give royalties for extra special hands" do
|
27
|
+
my_hand = %w(Ah 4s Qs 2h 3h 4h 5h 7h Kh Kd Ks 9c 9s)
|
28
|
+
their_hand = %w(9h 4c Qs 10s 10d 7d 6c 8h Qc Qd Ad 2c 4d)
|
29
|
+
sut = OfcpScoring::ScoringEngine.new
|
30
|
+
expect(sut.score(my_hand, their_hand)).to eq([20, 0])
|
31
|
+
end
|
32
|
+
end
|