hands 0.2.1 → 0.3.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c2a3b037d84f5c0fbecc3d0d2d7b5828c0aeb00f
4
+ data.tar.gz: 6f697d707fafae24181d8fc5f0fdc8e69634ca91
5
+ SHA512:
6
+ metadata.gz: ef5243a890cfb119b0aed00020f7b335778bbfd3e96e2465cbccc5319927e46ce4ff7acd1752a3f5ad2ec0db2f769c1e87dbbf659c5acc071c8046fa2324aa31
7
+ data.tar.gz: 0878f55fddf5c7ec70b03106327c961808e46de9104143e272469697ab8d81822db7876234f0fb74903ecda591ea67b1a3426033511a8aa9600a2a126523f33b
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .ruby-version
data/.travis.yml CHANGED
@@ -1,3 +1,7 @@
1
1
  language: ruby
2
+ bundler_args: --without development
2
3
  rvm:
4
+ - 1.8.7
3
5
  - 1.9.3
6
+ - 2.0.0
7
+ - jruby-19mode
@@ -0,0 +1,19 @@
1
+ ## Submitting a Pull Request
2
+
3
+ 1. [Fork the repository.][fork]
4
+ 2. [Create a topic branch.][branch]
5
+ 3. Add tests for your unimplemented feature or bug fix.
6
+ 4. Run `bundle exec rake`. If your tests pass, return to step 3.
7
+ 5. Implement your feature or bug fix.
8
+ 6. Run `bundle exec rake`. If your tests fail, return to step 5.
9
+ 7. Run `open coverage/index.html`. If your changes are not completely covered
10
+ by your tests, return to step 3.
11
+ 8. Add documentation for your feature or bug fix.
12
+ 9. Run `bundle exec rake doc`. If your changes are not 100% documented, go
13
+ back to step 8.
14
+ 10. Add, commit, and push your changes.
15
+ 11. [Submit a pull request.][pr]
16
+
17
+ [fork]: http://help.github.com/fork-a-repo/
18
+ [branch]: http://learn.github.com/p/branching.html
19
+ [pr]: http://help.github.com/send-pull-requests/
data/Gemfile CHANGED
@@ -3,14 +3,17 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  # Utility
6
- gem 'rake'
6
+ gem 'rake', :group => [:development, :test]
7
7
 
8
8
  # Documentation
9
- gem 'yard'
10
- gem 'redcarpet'
9
+ group :development do
10
+ gem 'yard'
11
+ gem 'redcarpet', :platform => :ruby
12
+ end
11
13
 
14
+ # Testing
12
15
  group :test do
13
16
  gem 'minitest'
14
- gem 'minitest-wscolor'
15
- gem 'simplecov'
17
+ gem 'minitest-wscolor' if RUBY_VERSION >= '1.9.3'
18
+ gem 'simplecov', :require => false
16
19
  end
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ Rake::TestTask.new(:test) do |t|
5
5
  t.libs << 'test'
6
6
  t.pattern = 'test/**/*_test.rb'
7
7
  end
8
- task default: :test
8
+ task :default => :test
9
9
 
10
10
  task :coverage do
11
11
  `open coverage/index.html`
data/Readme.markdown CHANGED
@@ -4,8 +4,6 @@ Simple library for calculating poker hands.
4
4
 
5
5
  Currently this gem is very limited. I plan on adding outs, odds, and other actually useful stuff. I started writing this on a plane as a personal challenge. It's current state is crude, although tested and works.
6
6
 
7
- [![Build Status](https://travis-ci.org/soffes/hands.png?branch=master)](undefined) [![Dependency Status](https://gemnasium.com/soffes/hands.png)](https://gemnasium.com/soffes/hands) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/soffes/hands)
8
-
9
7
  ## Installation
10
8
 
11
9
  Add this line to your application's Gemfile:
@@ -58,20 +56,12 @@ card2 = Hands::Card.new(:value => 3, :suit => :clubs)
58
56
  card2 > card1 # true
59
57
  ```
60
58
 
61
- ## Running Tests
59
+ ## Supported Ruby Versions
62
60
 
63
- Running and reading the tests is (for now) the best way to see the functionality of this gem.
61
+ Hands is tested under 1.9.3, 2.0.0, and JRuby (1.9 mode).
64
62
 
65
- ```
66
- $ bundle exec rake
67
- ```
63
+ [![Build Status](https://travis-ci.org/soffes/hands.png?branch=master)](https://travis-ci.org/soffes/hands)
68
64
 
69
65
  ## Contributing
70
66
 
71
- 1. Fork it
72
- 2. Create your feature branch (`git checkout -b my-new-feature`)
73
- 3. Write passing specs
74
- 4. Write documentation
75
- 5. Commit your changes (`git commit -am 'Added some feature'`)
76
- 6. Push to the branch (`git push origin my-new-feature`)
77
- 7. Create new Pull Request
67
+ See the [contributing guide](Contributing.markdown).
data/hands.gemspec CHANGED
@@ -7,6 +7,7 @@ Gem::Specification.new do |gem|
7
7
  gem.description = 'Simple library for various poker hands calculations.'
8
8
  gem.summary = 'Simple library for various poker hands calculations.'
9
9
  gem.homepage = 'http://github.com/soffes/hands'
10
+ gem.license = 'MIT'
10
11
 
11
12
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
13
  gem.files = `git ls-files`.split("\n")
@@ -14,4 +15,6 @@ Gem::Specification.new do |gem|
14
15
  gem.name = 'hands'
15
16
  gem.require_paths = ['lib']
16
17
  gem.version = Hands::VERSION
18
+
19
+ gem.required_ruby_version = '>= 1.9.2'
17
20
  end
data/lib/hands.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'hands/version'
2
4
  require 'hands/card'
3
5
  require 'hands/hand'
@@ -13,12 +15,19 @@ module Hands
13
15
  # All card value descriptions
14
16
  VALUE_DESCRIPTIONS = %w{two three four five six seven eight nine ten jack queen king ace}
15
17
 
16
- # Reverse alphabetically ordered suits
18
+ # Alphabetically ordered suits (higher index in the array is higher value)
17
19
  SUITS = [:clubs, :diamonds, :hearts, :spades]
20
+ SUIT_CHARACTERS = %w{♣ ♦ ♥ ♠}
18
21
 
19
22
  # Ranks of poker hands
20
23
  HAND_ORDER = [
21
24
  :high_card, :pair, :two_pair, :three_of_a_kind, :straight, :flush, :full_house,
22
25
  :four_of_a_kind, :straight_flush, :royal_flush
23
26
  ]
27
+
28
+ # Raised when an invalid suit is used
29
+ class InvalidSuit < StandardError; end
30
+
31
+ # Raised when an invalid value is used
32
+ class InvalidValue < StandardError; end
24
33
  end
data/lib/hands/card.rb CHANGED
@@ -65,14 +65,20 @@ module Hands
65
65
 
66
66
  # Invalid
67
67
  @value = nil
68
+ raise InvalidValue, "'#{val}' is an invalid suit."
68
69
  end
69
70
 
70
71
  def suit=(suit)
71
- if (suit.is_a?(String) or suit.is_a?(Symbol)) and SUITS.include?(suit.to_sym)
72
- @suit = suit.to_sym
73
- else
72
+ # Convert to symbol
73
+ suit = suit.to_sym if suit.is_a?(String)
74
+
75
+ # Make sure it's valid
76
+ unless suit.is_a?(Symbol) and SUITS.include?(suit)
74
77
  @suit = nil
78
+ raise InvalidSuit, "'#{suit}' is an invalid suit."
75
79
  end
80
+
81
+ @suit = suit
76
82
  end
77
83
 
78
84
  # Standard inspect
@@ -96,15 +102,24 @@ module Hands
96
102
  !self.is_valid?
97
103
  end
98
104
 
105
+ # Get a short string representation of the card
106
+ #
107
+ # Example: "♥2"
108
+ #
109
+ # @return [String] short string representation of the card
110
+ def description
111
+ return 'invalid' unless self.is_valid?
112
+ self.value.capitalize + SUIT_CHARACTERS[self.suit_index]
113
+ end
114
+
99
115
  # Get a string representation of the card
100
116
  #
117
+ # Example: "Two of Hearts"
118
+ #
101
119
  # @return [String] string representation of the card
102
- def description
103
- if self.is_valid?
104
- "#{VALUE_DESCRIPTIONS[self.value_index].capitalize} of #{self.suit.to_s.capitalize}"
105
- else
106
- 'invalid'
107
- end
120
+ def long_description
121
+ return 'invalid' unless self.is_valid?
122
+ "#{VALUE_DESCRIPTIONS[self.value_index].capitalize} of #{self.suit.to_s.capitalize}"
108
123
  end
109
124
 
110
125
  # Compares the card with another card
@@ -129,6 +144,7 @@ module Hands
129
144
  # @return [Integer] index of the card's suit
130
145
  # @see SUITS
131
146
  def suit_index
147
+ return nil unless self.suit
132
148
  SUITS.index(self.suit.downcase)
133
149
  end
134
150
 
@@ -139,6 +155,7 @@ module Hands
139
155
  # @return [Integer] index of the card's value
140
156
  # @see VALUES
141
157
  def value_index
158
+ return nil unless self.value
142
159
  VALUES.index(self.value.downcase)
143
160
  end
144
161
  end
@@ -35,60 +35,42 @@ module Hands
35
35
 
36
36
  # @return [Array, Nil] Array of {Card} objects with the straight in decending order or `nil` if there isn't a straight in the {Hand}
37
37
  def straight
38
- return nil unless self.cards.length == 5
38
+ # Require at least 5 cards
39
+ return nil unless self.cards.length >= 5
40
+
41
+ # Sort
39
42
  cs = self.cards.sort.reverse
40
43
 
41
44
  # Ace's low
42
- if cs.first.value == 'a' and cs[1].value == '5'
43
- # Move ace to end
44
- ace = cs.first
45
- cs = cs[1..4]
46
- cs << ace
47
-
48
- # Check succession
49
- csr = cs.reverse
50
- 4.times do |i|
51
- next if i == 0
52
- return nil unless csr[i].value_index == i - 1
53
- end
54
-
55
- # Normal
56
- else
57
- # Check range
58
- return nil unless cs.first.value_index - cs.last.value_index == 4
59
-
60
- # Check succession
61
- 4.times do |i|
62
- return nil unless cs[i].value_index == cs[i + 1].value_index + 1
63
- end
64
- end
45
+ return cs if cs.first.value == 'a' and cs[1].value == '5'
46
+
47
+ # Check succession
48
+ return nil unless succession?
49
+
50
+ # Avoid wrap-around
51
+ values = self.cards.collect(&:value)
52
+ return nil if values.include?('k') and values.include?(2)
53
+
65
54
  cs
66
55
  end
67
56
 
68
57
  # @return [Array, Nil] Array of {Card} objects with the flush in decending order or `nil` if there isn't a flush in the {Hand}
69
58
  def flush
70
59
  # If all of the {Card}s are the same suit, we have a flush
71
- return nil unless self.suits.length == 1
60
+ return nil unless self.cards.length >= 5 and self.suits.length == 1
72
61
  self.cards.sort.reverse
73
62
  end
74
63
 
75
64
  # @return [Array, Nil] Array of {Card} objects with the full house in decending order or `nil` if there isn't a full house in the {Hand}
76
65
  def full_house
77
66
  dupes = self.duplicates
78
- return nil unless dupes.length == 2
79
-
80
- a = []
81
- b = []
82
-
83
- hand = self.cards.select do |card|
84
- if dupes.first == card.value
85
- a << card
86
- elsif dupes.last == card.value
87
- b << card
88
- end
67
+ return nil unless self.cards.length >= 5 and dupes.length == 2
68
+
69
+ # Ensure all {Card}s are one of the duplicates
70
+ self.cards.each do |card|
71
+ return nil unless dupes.include? card.value
89
72
  end
90
73
 
91
- return nil unless a.length + b.length == 5
92
74
  self.cards.sort.reverse
93
75
  end
94
76
 
@@ -136,7 +118,7 @@ module Hands
136
118
 
137
119
  def pairs(min)
138
120
  dupes = self.duplicates
139
- return nil if dupes.length < min
121
+ return nil unless dupes.length >= min
140
122
 
141
123
  hand = self.cards.select do |card|
142
124
  dupes.include?(card.value)
@@ -161,5 +143,13 @@ module Hands
161
143
  hand << (self.cards - hand).sort.reverse
162
144
  hand.flatten
163
145
  end
146
+
147
+ def succession?
148
+ cs = self.cards.sort.reverse
149
+ 4.times do |i|
150
+ return false unless cs[i].value_index == cs[i + 1].value_index + 1
151
+ end
152
+ true
153
+ end
164
154
  end
165
155
  end
data/lib/hands/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Hands
2
2
  # Gem version
3
- VERSION = '0.2.1'
3
+ VERSION = '0.3.0'
4
4
  end
data/test/test_helper.rb CHANGED
@@ -1,11 +1,17 @@
1
- require 'simplecov'
2
- SimpleCov.start
3
-
4
1
  require 'rubygems'
5
2
  require 'bundler'
6
3
  Bundler.require :test
4
+
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+
7
8
  require 'minitest/autorun'
8
9
  require 'hands'
9
10
 
11
+ # Support files
12
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/support/*.rb"].each do |file|
13
+ require file
14
+ end
15
+
10
16
  class Hands::TestCase < MiniTest::Unit::TestCase
11
17
  end
@@ -1,6 +1,13 @@
1
+ # encoding: UTF-8
1
2
  require 'test_helper'
2
3
 
3
4
  class CardTest < Hands::TestCase
5
+ def test_shorthand
6
+ card1 = Hands::Card[4, :hearts]
7
+ card2 = Hands::Card.new(:value => 4, :suit => :hearts)
8
+ assert_equal card1, card2
9
+ end
10
+
4
11
  def test_that_it_validates_cards
5
12
  card = Hands::Card.new
6
13
  refute card.is_valid?
@@ -12,26 +19,31 @@ class CardTest < Hands::TestCase
12
19
  card.value = 9
13
20
  assert card.is_valid?
14
21
 
15
- card.suit = 17
16
- refute card.is_valid?
22
+ assert_raises Hands::InvalidSuit do
23
+ card.suit = 17
24
+ end
25
+
26
+ assert_raises Hands::InvalidValue do
27
+ card.value = 19
28
+ end
17
29
 
18
30
  card.suit = :hearts
19
- card.value = 19
20
- refute card.is_valid?
31
+ card.value = 5
32
+ assert card.is_valid?
21
33
  end
22
34
 
23
35
  def test_that_it_allows_integers_for_high_cards
24
- card1 = Hands::Card.new(value: 11, suit: :clubs)
36
+ card1 = Hands::Card[11, :clubs]
25
37
  assert card1.is_valid?
26
38
  assert_equal 'j', card1.value
27
39
 
28
- card2 = Hands::Card.new(value: 'j', suit: :clubs)
40
+ card2 = Hands::Card['j', :clubs]
29
41
  assert_equal card1, card2
30
42
  end
31
43
 
32
44
  def test_that_its_comparable
33
- card1 = Hands::Card.new(value: 2, suit: :hearts)
34
- card2 = Hands::Card.new(value: 3, suit: :clubs)
45
+ card1 = Hands::Card[2, :hearts]
46
+ card2 = Hands::Card[3, :clubs]
35
47
 
36
48
  assert card2 > card1
37
49
  assert card1 < card2
@@ -43,30 +55,34 @@ class CardTest < Hands::TestCase
43
55
  end
44
56
 
45
57
  def test_that_it_is_sortable
46
- c2 = Hands::Card.new(value: 2, suit: :hearts)
47
- c3 = Hands::Card.new(value: 3, suit: :hearts)
48
- c4 = Hands::Card.new(value: 4, suit: :hearts)
49
- c5 = Hands::Card.new(value: 5, suit: :hearts)
50
- c6 = Hands::Card.new(value: 6, suit: :hearts)
51
- c7 = Hands::Card.new(value: 7, suit: :hearts)
52
- c8 = Hands::Card.new(value: 8, suit: :hearts)
53
- c9 = Hands::Card.new(value: 9, suit: :hearts)
54
- c10 = Hands::Card.new(value: 10, suit: :hearts)
55
- cJ = Hands::Card.new(value: 'j', suit: :hearts)
56
- cQ = Hands::Card.new(value: 'q', suit: :hearts)
57
- cK = Hands::Card.new(value: 'k', suit: :hearts)
58
- cA = Hands::Card.new(value: 'a', suit: :hearts)
58
+ c2 = Hands::Card[2, :hearts]
59
+ c3 = Hands::Card[3, :hearts]
60
+ c4 = Hands::Card[4, :hearts]
61
+ c5 = Hands::Card[5, :hearts]
62
+ c6 = Hands::Card[6, :hearts]
63
+ c7 = Hands::Card[7, :hearts]
64
+ c8 = Hands::Card[8, :hearts]
65
+ c9 = Hands::Card[9, :hearts]
66
+ c10 = Hands::Card[10, :hearts]
67
+ cJ = Hands::Card['j', :hearts]
68
+ cQ = Hands::Card['q', :hearts]
69
+ cK = Hands::Card['k', :hearts]
70
+ cA = Hands::Card['a', :hearts]
59
71
 
60
72
  cards = [c2, c3, c4, c5, c6, c7, c8, c9, c10, cJ, cQ, cK, cA]
61
73
  assert_equal cards, cards.sort
62
74
  end
63
75
 
64
76
  def test_that_it_includes_the_description_in_inspect
65
- card = Hands::Card.new(value: 2, suit: :hearts)
66
- assert_includes card.inspect, 'Two of Hearts'
77
+ card = Hands::Card[2, :hearts]
78
+ assert_equal '2♥', card.description
79
+ assert_includes card.inspect, '2♥'
80
+ assert_equal 'Two of Hearts', card.long_description
67
81
 
68
82
  card = Hands::Card.new
69
83
  assert_equal 'invalid', card.description
84
+ assert_equal 'invalid', card.description
70
85
  refute_includes card.inspect, 'invalid'
86
+ assert_equal 'invalid', card.description
71
87
  end
72
88
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hands
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Sam Soffes
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-22 00:00:00.000000000 Z
11
+ date: 2013-02-25 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: Simple library for various poker hands calculations.
15
14
  email:
@@ -21,6 +20,7 @@ files:
21
20
  - .gitignore
22
21
  - .travis.yml
23
22
  - .yardopts
23
+ - Contributing.markdown
24
24
  - Gemfile
25
25
  - LICENSE
26
26
  - Rakefile
@@ -43,34 +43,28 @@ files:
43
43
  - test/units/player_test.rb
44
44
  - test/units/table_test.rb
45
45
  homepage: http://github.com/soffes/hands
46
- licenses: []
46
+ licenses:
47
+ - MIT
48
+ metadata: {}
47
49
  post_install_message:
48
50
  rdoc_options: []
49
51
  require_paths:
50
52
  - lib
51
53
  required_ruby_version: !ruby/object:Gem::Requirement
52
- none: false
53
54
  requirements:
54
- - - ! '>='
55
+ - - '>='
55
56
  - !ruby/object:Gem::Version
56
- version: '0'
57
- segments:
58
- - 0
59
- hash: 2894117233871191635
57
+ version: 1.9.2
60
58
  required_rubygems_version: !ruby/object:Gem::Requirement
61
- none: false
62
59
  requirements:
63
- - - ! '>='
60
+ - - '>='
64
61
  - !ruby/object:Gem::Version
65
62
  version: '0'
66
- segments:
67
- - 0
68
- hash: 2894117233871191635
69
63
  requirements: []
70
64
  rubyforge_project:
71
- rubygems_version: 1.8.23
65
+ rubygems_version: 2.0.0
72
66
  signing_key:
73
- specification_version: 3
67
+ specification_version: 4
74
68
  summary: Simple library for various poker hands calculations.
75
69
  test_files:
76
70
  - test/test_helper.rb