deck_of_cards_handler 0.1.3 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 429d1307ee681bdbe06c04a5b4232a106d2ad4a0f07cbe684eaab13254e9f402
4
- data.tar.gz: 4d89bba0e091028380bb6481dacf2f48a97b3df1147a67a0f8c3bfbc67a3997b
3
+ metadata.gz: ada5266ea6fced842e0110cfb42413202aecd0344b6e50d7e03284b148a3de12
4
+ data.tar.gz: 69e43292eb8d3476afd899093ec29391e96dcc97cc52c0378c08830c5b35b47e
5
5
  SHA512:
6
- metadata.gz: 971705372f4d56fc9d63d44f0d0c7b1a999209ff6f197084f8e951a58689ba45448c62ef3608eca4f97784dc9b6a4c8474aca0ce58de02e5811a3d9c654d47f4
7
- data.tar.gz: bbe3e25a0fe903c1e687455225d64aeacd033d726d910f0516a7de7b83d626aa65e9d328234f654326a86f74c90a7f479c043aabe31a696f0259eaa99c400d7f
6
+ metadata.gz: b65f41b901b72be9ad9e8978b34cc2ada7f886ed5e6fe704d8fb630cd02cba94bbee162e9e09097b4496663e41cd50d251b653ed77ac9ff92bb7bb5f1458d19f
7
+ data.tar.gz: 62ce89b3c2cf352ad82a8fd3f8c2c86cfbe731cfe4c9f633b53dbd3ff6183d822d48916f6e1b5b66647c85e1e96a75038e1b00916f201119e51dc118e3cfc155
data/README.md CHANGED
@@ -1,38 +1,154 @@
1
- # DeckOfCards
1
+ # Deck of cards handler
2
2
 
3
- This is a gem that simulates the handling of a deck of cards.
4
- It provides all the moves one could do such as shuffling, cutting, dealing, culling, etc.
3
+ A ruby gem for simulating real-world deck handling: shuffle, cut, deal, cull
4
+ and more.
5
5
 
6
6
  ## Installation
7
7
 
8
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
8
+ Run the following terminal command:
9
9
 
10
- Install the gem and add to the application's Gemfile by executing:
10
+ ```zsh
11
+ gem install deck_of_cards_handler
12
+ ```
11
13
 
12
- ```bash
13
- bundle add deck_of_card_handler
14
+ ## Usage examples
15
+
16
+ <details>
17
+ <summary>Create the Mnemonica stack from Stay Stack</summary>
18
+
19
+ ```ruby
20
+ require "deck_of_cards_handler"
21
+
22
+ # create a deck in stay stack order
23
+ clubs = Card.values.map { Card.new(suit: "C", value: _1) }
24
+ hearts = Card.values.map { Card.new(suit: "H", value: _1) }
25
+ diamonds = Card.values.map { Card.new(suit: "D", value: _1) }
26
+ spades = Card.values.map { Card.new(suit: "S", value: _1) }
27
+ deck = Packet.new(cards: [clubs, hearts, diamonds.reverse, spades.reverse].flatten)
28
+
29
+ # make 4 faro shuffles
30
+ 4.times do
31
+ top_half = deck.cut(number: 26)
32
+ deck.faro(other_packet: top_half)
33
+ end
34
+
35
+ # reverse the first 26 cards
36
+ top_half = deck.cut(number: 26)
37
+ top_half.reverse
38
+ deck.cards = [top_half.cards, deck.cards].flatten
39
+
40
+ # faro the 18 first cards
41
+ top_half = deck.cut(number: 18)
42
+ deck.faro(other_packet: top_half)
43
+
44
+ # cut the 9D to the bottom
45
+ deck.cut_and_complete(number: 9)
46
+ # assign a position value to the cards
47
+ deck.set_cards_positions
48
+
49
+ deck
50
+ # =>
51
+ # <Packet:0x000000012ae2b848
52
+ # @cards=
53
+ [#<Card:0x000000012ae2bd20 @position=1, @suit="S", @value="4">,
54
+ #<Card:0x000000012ae2cae0 @position=2, @suit="H", @value="2">,
55
+ #<Card:0x000000012ae2c220 @position=3, @suit="D", @value="7">,
56
+ #<Card:0x000000012ae2bd98 @position=4, @suit="S", @value="3">,
57
+ #<Card:0x000000012ae2c9f0 @position=5, @suit="H", @value="4">,
58
+ #<Card:0x000000012ae2c298 @position=6, @suit="D", @value="6">,
59
+ #<Card:0x000000012ae2df08 @position=7, @suit="C", @value="A">,
60
+ #<Card:0x000000012ae2c978 @position=8, @suit="H", @value="5">,
61
+ #<Card:0x000000012ae2ce00 @position=9, @suit="C", @value="9">,
62
+ #<Card:0x000000012ae2d260 @position=10, @suit="C", @value="2">,
63
+ #<Card:0x000000012ae2c630 @position=11, @suit="H", @value="Q">,
64
+ #<Card:0x000000012ae2c400 @position=12, @suit="D", @value="3">,
65
+ #<Card:0x000000012ae2b960 @position=13, @suit="S", @value="Q">,
66
+ #<Card:0x000000012ae2c810 @position=14, @suit="H", @value="8">,
67
+ #<Card:0x000000012ae2cf68 @position=15, @suit="C", @value="6">,
68
+ #<Card:0x000000012ae2cfe0 @position=16, @suit="C", @value="5">,
69
+ #<Card:0x000000012ae2c798 @position=17, @suit="H", @value="9">,
70
+ #<Card:0x000000012ae2b8e8 @position=18, @suit="S", @value="K">,
71
+ #<Card:0x000000012ae2c478 @position=19, @suit="D", @value="2">,
72
+ #<Card:0x000000012ae2c6a8 @position=20, @suit="H", @value="J">,
73
+ #<Card:0x000000012ae2d0d0 @position=21, @suit="C", @value="3">,
74
+ #<Card:0x000000012ae2ce78 @position=22, @suit="C", @value="8">,
75
+ #<Card:0x000000012ae2c900 @position=23, @suit="H", @value="6">,
76
+ #<Card:0x000000012ae2ba50 @position=24, @suit="S", @value="10">,
77
+ #<Card:0x000000012ae2c310 @position=25, @suit="D", @value="5">,
78
+ #<Card:0x000000012ae2bf50 @position=26, @suit="D", @value="K">,
79
+ #<Card:0x000000012ae2be10 @position=27, @suit="S", @value="2">,
80
+ #<Card:0x000000012ae2ca68 @position=28, @suit="H", @value="3">,
81
+ #<Card:0x000000012ae2c1a8 @position=29, @suit="D", @value="8">,
82
+ #<Card:0x000000012ae2bca8 @position=30, @suit="S", @value="5">,
83
+ #<Card:0x000000012ae2cc20 @position=31, @suit="C", @value="K">,
84
+ #<Card:0x000000012ae2c040 @position=32, @suit="D", @value="J">,
85
+ #<Card:0x000000012ae2bb40 @position=33, @suit="S", @value="8">,
86
+ #<Card:0x000000012ae2cd88 @position=34, @suit="C", @value="10">,
87
+ #<Card:0x000000012ae2c5b8 @position=35, @suit="H", @value="K">,
88
+ #<Card:0x000000012ae2b9d8 @position=36, @suit="S", @value="J">,
89
+ #<Card:0x000000012ae2cef0 @position=37, @suit="C", @value="7">,
90
+ #<Card:0x000000012ae2c720 @position=38, @suit="H", @value="10">,
91
+ #<Card:0x000000012ae2c4f0 @position=39, @suit="D", @value="A">,
92
+ #<Card:0x000000012ae2d058 @position=40, @suit="C", @value="4">,
93
+ #<Card:0x000000012ae2c888 @position=41, @suit="H", @value="7">,
94
+ #<Card:0x000000012ae2c388 @position=42, @suit="D", @value="4">,
95
+ #<Card:0x000000012ae2be88 @position=43, @suit="S", @value="A">,
96
+ #<Card:0x000000012ae2bac8 @position=44, @suit="S", @value="9">,
97
+ #<Card:0x000000012ae2cd10 @position=45, @suit="C", @value="J">,
98
+ #<Card:0x000000012ae2bfc8 @position=46, @suit="D", @value="Q">,
99
+ #<Card:0x000000012ae2bbb8 @position=47, @suit="S", @value="7">,
100
+ #<Card:0x000000012ae2cc98 @position=48, @suit="C", @value="Q">,
101
+ #<Card:0x000000012ae2c0b8 @position=49, @suit="D", @value="10">,
102
+ #<Card:0x000000012ae2bc30 @position=50, @suit="S", @value="6">,
103
+ #<Card:0x000000012ae2cb58 @position=51, @suit="H", @value="A">,
104
+ #<Card:0x000000012ae2c130 @position=52, @suit="D", @value="9">]>
14
105
  ```
15
106
 
16
- If bundler is not being used to manage dependencies, install the gem by executing:
107
+ </details>
17
108
 
18
- ```bash
19
- gem install deck_of_card_handler
20
- ```
109
+ <details>
110
+ <summary>Distribute 5 hands of poker</summary>
111
+
112
+ ```ruby
113
+ require "deck_of_cards_handler"
21
114
 
22
- ## Usage
115
+ # create a full deck of cards
116
+ cards = []
117
+ Card.suits.each do |suit|
118
+ Card.values.each do |value|
119
+ cards << Card.new(suit:, value:)
120
+ end
121
+ end
122
+ deck = Packet.new(cards:)
23
123
 
24
- TODO: Write usage instructions here
124
+ deck.shuffle
125
+
126
+ hands = deck.deal_into_piles(number_of_piles: 5, number_of_cards: 5)
127
+
128
+ hands.map(&:to_s)
129
+ # => [["5 of D", "8 of C", "6 of S", "10 of D", "5 of C"], ["7 of C", "5 of S", "4 of C", "2 of D", "Q of D"], ["3 of S", "8 of D", "A of D", "2 of C", "7 of D"], ["Q of H", "4 of S", "3 of D", "J of S", "9 of S"], ["6 of C", "6 of H", "10 of C", "4 of D", "A of H"]]
130
+ ```
131
+
132
+ </details>
25
133
 
26
134
  ## Development
27
135
 
28
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
136
+ After checking out the repo, run:
29
137
 
30
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
138
+ ```zsh
139
+ bin/setup
140
+ ```
31
141
 
32
- ## Contributing
142
+ This installs dependencies.
33
143
 
34
- Bug reports and pull requests are welcome on GitHub at <https://github.com/simonbernard2/deck_of_cards>.
144
+ Run the test suite:
35
145
 
36
- ## License
146
+ ```zsh
147
+ rake test
148
+ ```
37
149
 
38
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
150
+ You can also open an interactive console for experimentation:
151
+
152
+ ```zsh
153
+ bin/console
154
+ ```
@@ -50,28 +50,20 @@ class Card
50
50
  other.suit == suit && other.value == value
51
51
  end
52
52
 
53
- sig { returns(T::Array[Integer]) }
54
- def rank
53
+ sig { params(low_ace: T::Boolean).returns(Integer) }
54
+ def rank(low_ace: false)
55
55
  case value
56
- when "A" then [1, 14]
57
- when "J" then [11]
58
- when "Q" then [12]
59
- when "K" then [13]
60
- else [value.to_i]
56
+ when "A" then low_ace ? 1 : 14
57
+ when "J" then 11
58
+ when "Q" then 12
59
+ when "K" then 13
60
+ else value.to_i
61
61
  end
62
62
  end
63
63
 
64
64
  sig { params(other: Card).returns(Integer) }
65
65
  def <=>(other)
66
- # compare by all possible ranks (Ace flexible)
67
- my_ranks = rank
68
- other_ranks = other.rank
69
-
70
- # check if any ranks overlap (Ace == 1 or 14)
71
- return 0 if (my_ranks & other_ranks).any?
72
-
73
- # otherwise compare by highest possible
74
- T.must(my_ranks.max) <=> T.must(other_ranks.max)
66
+ rank <=> other.rank
75
67
  end
76
68
 
77
69
  class << self
@@ -47,14 +47,14 @@ class Packet
47
47
  end
48
48
 
49
49
  packet = Packet.new(cards:)
50
- set_cards_positions(packet:)
50
+ packet.set_cards_positions
51
51
 
52
52
  packet
53
53
  end
54
54
 
55
- sig { params(string: String).returns(Packet) }
55
+ sig { overridable.params(string: String).returns(Packet) }
56
56
  def build_from_string(string:) # rubocop:disable Metrics
57
- content = string.split(",")
57
+ content = string.split(",").map(&:strip)
58
58
  cards = []
59
59
  cards_set = Set.new
60
60
 
@@ -71,19 +71,10 @@ class Packet
71
71
  end
72
72
 
73
73
  packet = Packet.new(cards:)
74
- set_cards_positions(packet:)
74
+ packet.set_cards_positions
75
75
 
76
76
  packet
77
77
  end
78
-
79
- private
80
-
81
- sig { params(packet: Packet).void }
82
- def set_cards_positions(packet:)
83
- packet.cards.each_with_index do |card, index|
84
- card.position = index + 1
85
- end
86
- end
87
78
  end
88
79
 
89
80
  sig { params(other_packet: Packet).void }
@@ -106,6 +97,13 @@ class Packet
106
97
  self.cards = cards.reverse
107
98
  end
108
99
 
100
+ sig { void }
101
+ def set_cards_positions
102
+ cards.each_with_index do |card, index|
103
+ card.position = index + 1
104
+ end
105
+ end
106
+
109
107
  sig { returns(T::Array[String]) }
110
108
  def to_s
111
109
  cards.map(&:to_s)
@@ -0,0 +1,123 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # This represents a poker hands raking
5
+ class PokerHand < Packet
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ sig { params(cards: T::Array[Card]).void }
10
+ def initialize(cards:)
11
+ raise ArgumentError if cards.size != 5
12
+
13
+ super
14
+ end
15
+
16
+ class << self
17
+ sig { override.params(string: String).returns(PokerHand) }
18
+ def build_from_string(string:)
19
+ result = super
20
+ PokerHand.new(cards: result.cards)
21
+ end
22
+ end
23
+
24
+ HAND_RANKS = T.let(
25
+ {
26
+ nothing: 0,
27
+ pair: 1,
28
+ two_pairs: 2,
29
+ three_of_a_kind: 3,
30
+ straight: 4,
31
+ flush: 5,
32
+ full_house: 6,
33
+ four_of_a_kind: 7,
34
+ straight_flush: 8
35
+ }.freeze, T::Hash[Symbol, Integer]
36
+ )
37
+
38
+ sig { returns(Integer) }
39
+ def rank # rubocop:disable Metrics
40
+ return T.must(HAND_RANKS[:straight_flush]) if straight_flush?
41
+ return T.must(HAND_RANKS[:four_of_a_kind]) if four_of_a_kind?
42
+ return T.must(HAND_RANKS[:full_house]) if full_house?
43
+ return T.must(HAND_RANKS[:flush]) if flush?
44
+ return T.must(HAND_RANKS[:straight]) if straight?
45
+ return T.must(HAND_RANKS[:three_of_a_kind]) if three_of_a_kind?
46
+ return T.must(HAND_RANKS[:two_pairs]) if two_pairs?
47
+ return T.must(HAND_RANKS[:pair]) if pair?
48
+
49
+ T.must(HAND_RANKS[:nothing])
50
+ end
51
+
52
+ sig { returns(T::Boolean) }
53
+ def pair?
54
+ validate_hand_size
55
+
56
+ counts = cards.map(&:rank).flatten.tally
57
+ counts.values.count(2) == 1
58
+ end
59
+
60
+ sig { returns(T::Boolean) }
61
+ def two_pairs?
62
+ validate_hand_size
63
+
64
+ counts = cards.map(&:rank).flatten.tally
65
+ counts.values.count(2) == 2
66
+ end
67
+
68
+ sig { returns(T::Boolean) }
69
+ def three_of_a_kind?
70
+ validate_hand_size
71
+
72
+ counts = cards.map(&:rank).flatten.tally
73
+ counts.values.count(3) == 1
74
+ end
75
+
76
+ sig { returns(T::Boolean) }
77
+ def straight? # rubocop:disable Metrics/AbcSize
78
+ validate_hand_size
79
+
80
+ ranks = cards.map(&:rank).sort
81
+ return true if ranks.each_cons(2).all? { |a, b| b == T.must(a) + 1 }
82
+
83
+ ranks = cards.map { _1.rank(low_ace: true) }
84
+ ranks.each_cons(2).all? { |a, b| b == T.must(a) + 1 }
85
+ end
86
+
87
+ sig { returns(T::Boolean) }
88
+ def flush?
89
+ validate_hand_size
90
+
91
+ suit = T.must(cards.first).suit
92
+ cards.all? { _1.suit == suit }
93
+ end
94
+
95
+ sig { returns(T::Boolean) }
96
+ def full_house?
97
+ validate_hand_size
98
+
99
+ three_of_a_kind? && pair?
100
+ end
101
+
102
+ sig { returns(T::Boolean) }
103
+ def four_of_a_kind?
104
+ validate_hand_size
105
+
106
+ counts = cards.map(&:rank).flatten.tally
107
+ counts.values.count(4) == 1
108
+ end
109
+
110
+ sig { returns(T::Boolean) }
111
+ def straight_flush?
112
+ validate_hand_size
113
+
114
+ straight? && flush?
115
+ end
116
+
117
+ private
118
+
119
+ sig { void }
120
+ def validate_hand_size
121
+ raise StandardError unless size == 5
122
+ end
123
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeckOfCardsHandler
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.5"
5
5
  end
@@ -4,3 +4,4 @@ require "sorbet-runtime"
4
4
  require_relative "deck_of_cards_handler/version"
5
5
  require_relative "deck_of_cards_handler/card"
6
6
  require_relative "deck_of_cards_handler/packet"
7
+ require_relative "deck_of_cards_handler/poker_hand"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deck_of_cards_handler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Bernard
@@ -75,6 +75,7 @@ files:
75
75
  - lib/deck_of_cards_handler/packet/deals.rb
76
76
  - lib/deck_of_cards_handler/packet/packet.rb
77
77
  - lib/deck_of_cards_handler/packet/shuffles.rb
78
+ - lib/deck_of_cards_handler/poker_hand.rb
78
79
  - lib/deck_of_cards_handler/version.rb
79
80
  - sig/deck_of_cards.rbs
80
81
  - sorbet/config