card_dealer 0.3.0 → 0.3.1

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: 0c3f3a33b1bc150361102599843b3cf9e7e1eb3d2b799b4116411f3445a00cf2
4
- data.tar.gz: 6f32d0a5b10e0703424304aba1e8e3172a50b56066c49505c08f1752ca0c5bbe
3
+ metadata.gz: 740499d4aa92d740445805a9e78e4c2ff72e0fdd79a44c1abd34d25aeed17b1d
4
+ data.tar.gz: 482ee0d77fcc5f171b220f601c99ce3beebfab94e60f989d2cf395ecd836178c
5
5
  SHA512:
6
- metadata.gz: 07f8695bf89b50776b4dbd412ed774679ae1d7cd9dccf78581148bd200b7afd30e97fdbe8eb392b640569faf3945dc738a67fd34d8501c6028216fb1d942a73f
7
- data.tar.gz: b6936af01081753ab4f0e46174ddab834c2c84091923eb73794660fa2f6ea30c04c495a72121f8ffcc2ac998fb6754927b305d50bd4eabfaf3ae815d988a4c47
6
+ metadata.gz: 67fe4b4516e2c4dd8857270330c7300a65abc6d038f9a0b8634cd63a003d6c96ccb4243ec9dbe86c5348dab9e783d9f2110d8c87443418a9bd11e5dc0aca5f29
7
+ data.tar.gz: 408fcce45791e37cc982665cf3432b104a21f15b937ecefed14c8dc360b9ed22ce695f4051a4e5a3a425d15eb58e2ff93e42effbb4cde84ba21e5f7abccf8f92
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
- --format documentation
2
1
  --color
3
2
  --require spec_helper
data/CHANGELOG.md CHANGED
@@ -16,6 +16,12 @@ removed.
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [0.3.1] - 2026-11-06
20
+
21
+ ### Fixed
22
+
23
+ - Binary decoding rejects payload lengths that do not match the declared card count with `CardDealer::BinaryDeck::InvalidEncodingError`, including truncated decks.
24
+
19
25
  ## [0.3.0] - 2026-09-07
20
26
 
21
27
  ### Changed
@@ -71,7 +77,8 @@ Initial release!
71
77
  - Ability to shuffle a deck
72
78
  - Ability to reset a deck
73
79
 
74
- [unreleased]: https://github.com/svyatov/card_dealer/compare/v0.3.0...HEAD
80
+ [unreleased]: https://github.com/svyatov/card_dealer/compare/v0.3.1...HEAD
81
+ [0.3.1]: https://github.com/svyatov/card_dealer/compare/v0.3.0...v0.3.1
75
82
  [0.3.0]: https://github.com/svyatov/card_dealer/compare/v0.2.0...v0.3.0
76
83
  [0.2.0]: https://github.com/svyatov/card_dealer/compare/v0.1.0...v0.2.0
77
84
  [0.1.0]: https://github.com/svyatov/card_dealer/releases/tag/v0.1.0
data/CLAUDE.md ADDED
@@ -0,0 +1,57 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ CardDealer is a Ruby gem for creating, shuffling, and dealing decks of playing cards. It supports standard 52-card and 36-card decks, custom deck configurations, and binary serialization for storage.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ bin/setup
14
+
15
+ # Run all checks (default task: steep + rubocop + rspec)
16
+ bundle exec rake
17
+
18
+ # Run tests only
19
+ bundle exec rake spec
20
+
21
+ # Run a single test file
22
+ bundle exec rspec spec/card_dealer/card_spec.rb
23
+
24
+ # Run a specific test by line number
25
+ bundle exec rspec spec/card_dealer/deck_spec.rb:42
26
+
27
+ # Run linter
28
+ bundle exec rake rubocop
29
+
30
+ # Run type checker
31
+ bundle exec rake steep
32
+
33
+ # Interactive console
34
+ bin/console
35
+ ```
36
+
37
+ ## Architecture
38
+
39
+ The gem has four main classes under the `CardDealer` module:
40
+
41
+ - **Card** (`lib/card_dealer/card.rb`) - Represents a single playing card with rank (2-A, where T=10) and suit (c/d/h/s). Cards are comparable and can be used as hash keys.
42
+
43
+ - **Deck** (`lib/card_dealer/deck.rb`) - A collection of cards supporting shuffle (Fisher-Yates with optional seed), deal, and burn operations. Tracks burned cards separately.
44
+
45
+ - **BuildDeck** (`lib/card_dealer/build_deck.rb`) - Factory class with class methods for creating decks:
46
+ - `standard52` / `standard36` for common configurations
47
+ - `custom` for specifying decks count, cards per suit, ranks (`:highest`, `:lowest`, or array), and suits
48
+
49
+ - **BinaryDeck** (`lib/card_dealer/binary_deck.rb`) - Encodes/decodes decks to/from binary strings using 6-bit card representations. Supports decks up to 4 billion cards with three template sizes (8/16/32-bit headers).
50
+
51
+ ## Type Definitions
52
+
53
+ RBS type signatures are in `sig/`. The project uses Steep for type checking with lenient diagnostics configured in `Steepfile`.
54
+
55
+ ## Requirements
56
+
57
+ - Ruby >= 3.3.0
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ gem "rake", "~> 13.4"
10
10
  gem "rspec", "~> 3.13"
11
11
  gem "simplecov", require: false
12
12
 
13
- gem "rubocop", "~> 1.90"
13
+ gem "rubocop", "~> 1.92"
14
14
  gem "rubocop-rake", "~> 0.7"
15
15
  gem "rubocop-rspec", "~> 3.10"
16
16
 
data/Gemfile.lock CHANGED
@@ -1,28 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- card_dealer (0.3.0)
4
+ card_dealer (0.3.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.3)
10
10
  concurrent-ruby (1.3.8)
11
- csv (3.3.6)
11
+ csv (3.3.7)
12
12
  diff-lcs (1.6.2)
13
13
  ffi (1.17.4-arm64-darwin)
14
14
  ffi (1.17.4-x86_64-linux-gnu)
15
- fileutils (1.8.0)
16
- json (2.21.2)
15
+ fileutils (1.8.1)
16
+ json (3.1.0)
17
17
  language_server-protocol (3.17.0.6)
18
18
  lint_roller (1.1.0)
19
- listen (3.10.0)
19
+ listen (3.10.1)
20
20
  logger
21
21
  rb-fsevent (~> 0.10, >= 0.10.3)
22
22
  rb-inotify (~> 0.9, >= 0.9.10)
23
23
  logger (1.7.0)
24
- parallel (2.1.0)
25
- parser (3.3.12.0)
24
+ parallel (2.3.0)
25
+ parser (3.3.13.0)
26
26
  ast (~> 2.4.1)
27
27
  racc
28
28
  prism (1.9.0)
@@ -36,7 +36,7 @@ GEM
36
36
  logger
37
37
  prism (>= 1.6.0)
38
38
  tsort
39
- regexp_parser (2.12.0)
39
+ regexp_parser (2.13.1)
40
40
  rspec (3.13.2)
41
41
  rspec-core (~> 3.13.0)
42
42
  rspec-expectations (~> 3.13.0)
@@ -50,14 +50,14 @@ GEM
50
50
  diff-lcs (>= 1.2.0, < 2.0)
51
51
  rspec-support (~> 3.13.0)
52
52
  rspec-support (3.13.7)
53
- rubocop (1.90.0)
53
+ rubocop (1.92.2)
54
54
  json (>= 2.3)
55
55
  language_server-protocol (~> 3.17.0.2)
56
56
  lint_roller (~> 1.1.0)
57
57
  parallel (>= 1.10)
58
58
  parser (>= 3.3.0.2)
59
59
  rainbow (>= 2.2.2, < 4.0)
60
- regexp_parser (>= 2.9.3, < 3.0)
60
+ regexp_parser (>= 2.11.3, < 3.0)
61
61
  rubocop-ast (>= 1.49.0, < 2.0)
62
62
  ruby-progressbar (~> 1.7)
63
63
  unicode-display_width (>= 2.4.0, < 4.0)
@@ -73,7 +73,7 @@ GEM
73
73
  rubocop (~> 1.86, >= 1.86.2)
74
74
  ruby-progressbar (1.13.0)
75
75
  securerandom (0.4.1)
76
- simplecov (1.1.1)
76
+ simplecov (1.3.2)
77
77
  steep (2.1.0)
78
78
  concurrent-ruby (>= 1.1.10)
79
79
  csv (>= 3.0.9)
@@ -94,26 +94,27 @@ GEM
94
94
  terminal-table (4.0.0)
95
95
  unicode-display_width (>= 1.1.1, < 4)
96
96
  tsort (0.2.0)
97
- unicode-display_width (3.2.0)
98
- unicode-emoji (~> 4.1)
99
- unicode-emoji (4.2.0)
100
- uri (1.1.1)
97
+ unicode-display_width (3.3.0)
98
+ unicode-emoji (~> 4.3)
99
+ unicode-emoji (4.3.0)
100
+ uri (1.1.2)
101
101
 
102
102
  PLATFORMS
103
103
  arm64-darwin-22
104
104
  arm64-darwin-23
105
105
  arm64-darwin-24
106
+ arm64-darwin-25
106
107
  x86_64-linux
107
108
 
108
109
  DEPENDENCIES
109
110
  card_dealer!
110
111
  rake (~> 13.4)
111
112
  rspec (~> 3.13)
112
- rubocop (~> 1.90)
113
+ rubocop (~> 1.92)
113
114
  rubocop-rake (~> 0.7)
114
115
  rubocop-rspec (~> 3.10)
115
116
  simplecov
116
117
  steep
117
118
 
118
119
  BUNDLED WITH
119
- 4.0.17
120
+ 4.0.23
data/README.md CHANGED
@@ -119,6 +119,8 @@ deck = CardDealer::Deck.from_binary(encoded)
119
119
  deck.to_a # => ["As", "Td"]
120
120
  ```
121
121
 
122
+ If the payload length does not match the declared card count, decoding raises `CardDealer::BinaryDeck::InvalidEncodingError`.
123
+
122
124
  ## Development
123
125
 
124
126
  After checking out the repo, run `bin/setup` to install dependencies. Run `bundle exec rake` to run the type checker, the linter, and the tests. Run `bin/console` for an interactive prompt.
@@ -0,0 +1,131 @@
1
+ # Next feature for CardDealer
2
+
3
+ ## Subject
4
+
5
+ Identify the next obvious missing feature in this Ruby gem. Rank one feature, as requested.
6
+
7
+ The best feature candidate is atomic round-robin dealing to multiple hands. There is no evidence that any feature is mandatory.
8
+
9
+ Repair the confirmed binary-decoder truncation defect before adding features. The validation section records its reproduction.
10
+
11
+ Follow-up: commit `4376fae` implements the length check and documents `CardDealer::BinaryDeck::InvalidEncodingError`. The findings below describe the checkout examined before that repair.
12
+
13
+ ### Grounding
14
+
15
+ - README.md:3 defines the purpose: "CardDealer builds, shuffles, and deals decks of playing cards for Ruby card game applications."
16
+ - `lib/card_dealer/deck.rb:56-58` implements one contiguous deal with optional burns. Multi-hand distribution requires caller loops.
17
+ - `spec/card_dealer/deck_spec.rb:97-102` intentionally permits empty results. Exact dealing must use an explicit new contract.
18
+ - `lib/card_dealer/binary_deck.rb:68-98` stores remaining card order. It omits the seed and burned cards.
19
+ - `CHANGELOG.md:54-56` records removal of `Deck#reset` and recommends rebuilding with `BuildDeck`.
20
+ - Recent commits `83513ab`, `bb3d2ce`, and `afa9a3d` concern dependency maintenance. They supply no feature-demand evidence.
21
+ - GitHub returned no open issues for `svyatov/card_dealer` on 2026-11-06. No glossary, ADRs, or tracker guide were found.
22
+
23
+ ### Method
24
+
25
+ One read-only explorer supplied grounding. Four generation tasks covered all six ideation frames. Their results merged into 18 distinct candidates and three combinations.
26
+
27
+ An independent verifier checked all 21 candidates against the source and arguments. No verifier verdict was overruled.
28
+
29
+ Utility is inferred from the API. Source evidence establishes capability gaps, not consumer demand. Sizes include implementation, signatures, documentation, and meaningful tests.
30
+
31
+ ## Ranked ideas
32
+
33
+ ### 1. Atomic round-robin dealing to multiple hands
34
+
35
+ Distribute one card to each hand per round, returning ordinary arrays of cards. Check the entire request before removing cards.
36
+
37
+ If capacity is insufficient, raise a documented error and leave the deck unchanged. Preserve the permissive behavior of `deal`.
38
+
39
+ **Basis, direct:** `lib/card_dealer/deck.rb:56` defines `def deal(num = 1, burn: 0)`. Line 57 executes `@burned_cards += cards.shift(burn) if burn.positive?`. Line 58 executes `cards.shift(num)`. This returns a single contiguous group and performs no capacity preflight. `spec/card_dealer/deck_spec.rb:97-102` explicitly tests empty-array results for empty decks.
40
+
41
+ **Why it matters:** Games that distribute alternating cards need a caller loop. Games that require complete hands also need a capacity check.
42
+
43
+ Combining those operations gives one bounded dealing capability. It fits the stated purpose without introducing game rules, players, or hand classes.
44
+
45
+ **Size:** M. The algorithm is small, but public error semantics, signatures, compatibility, and examples need care.
46
+
47
+ **Proposed shape, subject to design:**
48
+
49
+ ```ruby
50
+ hands = deck.deal_hands(players: 3, cards_each: 2)
51
+ # From an unshuffled standard deck:
52
+ # [[2c, 5c], [3c, 6c], [4c, 7c]] as Card objects
53
+ ```
54
+
55
+ The smallest scope has positive player counts, nonnegative card counts, capacity validation, and no burns. Names and zero-count behavior require design review.
56
+
57
+ Atomic means capacity validation before mutation. It does not imply thread safety or protection against external mutation through `cards`.
58
+
59
+ **Main objection:** A short Ruby loop already performs distribution. The feature earns its maintenance cost only if consumers need the shared ordering and failure contract.
60
+
61
+ **Take it further**
62
+
63
+ ```text
64
+ $grill-with-docs Atomic round-robin dealing to multiple hands in CardDealer.
65
+
66
+ Basis, direct: lib/card_dealer/deck.rb:56 defines `def deal(num = 1, burn: 0)`. Line 57 executes `@burned_cards += cards.shift(burn) if burn.positive?`. Line 58 executes `cards.shift(num)`. This returns a single contiguous group and performs no capacity preflight. spec/card_dealer/deck_spec.rb:97-102 explicitly tests empty-array results for empty decks.
67
+
68
+ Why it matters: Games that distribute alternating cards need a caller loop. Games that require complete hands also need a capacity check. Combining those operations gives one bounded dealing capability. It fits the stated purpose without introducing game rules, players, or hand classes.
69
+
70
+ Consider a separate API such as deal_hands(players:, cards_each:), returning arrays of Card objects. Distribute one card per player per round. Validate the complete request before mutation. Insufficient capacity must leave the deck unchanged. Preserve existing deal behavior. Start without burns.
71
+
72
+ Challenge whether a documented loop is sufficient before accepting a permanent API. There is no open-issue demand evidence. Resolve names, zero counts, error types, size limits, and compatibility before implementation.
73
+ ```
74
+
75
+ ## Cut
76
+
77
+ These cuts rank one next feature. They do not declare every alternative useless. IDs refer to the merged candidate list.
78
+
79
+ | ID | Idea | Basis | Reason |
80
+ | --- | --- | --- | --- |
81
+ | I1 | Round-robin dealing alone | direct: `deck.rb:58`, `cards.shift(num)`, returns one group. | Duplicate of the stronger ranked combination, I20. |
82
+ | I2 | Exact dealing alone | direct: `deck.rb:57-58` burns before dealing, without preflight. | Combined into I20; a standalone strict API remains a separate design choice. |
83
+ | I3 | Peek | direct: `deck.rb:12`, `attr_reader :cards`, already exposes inspection. | Cost over value: `deck.cards.first(n)` already expresses the operation. |
84
+ | I4 | Enumerable iteration | direct: `deck.rb:93`, `cards.map(&:to_s)`, defines string-valued `to_a`. | Cost over value: collection methods exist through `cards`; iteration would need a careful `to_a` contract. |
85
+ | I5 | Full state snapshots | direct: `binary_deck.rb:70-71` encodes cards and size; `:98`, `Deck.new cards`, reconstructs fresh state. | Cost over value: no demonstrated consumer needs seed and burned cards restored. |
86
+ | I6 | Independent deck copies | direct: `deck.rb:23`, `@cards = cards`; `:35` and `:58` mutate the collection. | Cost over value for the next feature: branching demand is unproven and card mutability needs a defined policy. |
87
+ | I7 | Exclude known cards by multiplicity | direct: `build_deck.rb:112-115` repeats decks; `card.rb:91` compares rank and suit values. | Cost over value: useful for simulations, but the scenario is not evidenced. |
88
+ | I8 | Validated binary decoding | direct: `binary_deck.rb:94-95` uses `scan(/.{6}/).take(deck_size)` and map `fetch`; a truncated payload silently decoded one of two declared cards. | Classify as a confirmed repair, not a speculative feature. Prioritize the repair before the ranked feature. |
89
+ | I9 | Ordered import from card notation | direct: `README.md:103` constructs individual cards inside `Deck.new`. | Cost over value: mapping card strings through `Card.new` is already small. |
90
+ | I10 | Generic arbitrary-card decks | reasoned: dealing requires ordered removal, not ranks or suits; separating those concerns enables more games. | Cost over value: expands the domain and conflicts with assumptions in card encoding. |
91
+ | I11 | Caller-supplied random generator | direct: `deck.rb:35`, `Random.new(@seed.to_i)`, constructs the generator internally. | Cost over value: coordinating random streams is unproven demand and complicates replay semantics. |
92
+ | I12 | Replayable operation transcript | direct: `deck.rb:33-35` records a seed; `:56-58` does not log deal operations. | Cost over value: operation history adds persistent session responsibilities. |
93
+ | I13 | Conservation checks | reasoned: comparing initial multiplicities with remaining, burned, and supplied dealt cards detects missing or extra values. | Cost over value: the caller must supply dealt inventory; equal physical copies remain indistinguishable. |
94
+ | I14 | Scenario builder | reasoned: subtracting known cards from the starting multiset reconstructs a remaining population, with multiplicity preserved. | Duplicate of I7 plus existing shuffle composition. |
95
+ | I15 | Streaming binary encoding | direct: `binary_deck.rb:70` builds a complete mapped binary-text string with `join`. | Cost over value: no measured memory or throughput problem justifies the added interface. |
96
+ | I16 | Batch independent simulations | reasoned: each independent trial requires a fresh population; a helper can enforce reconstruction and seed handling. | Outside the focus: adds a simulation workflow above the deck primitives. |
97
+ | I17 | Jokers | reasoned: a distinct joker needs an identity outside ordinary rank/suit pairs; built-in support enables joker games. | Cost over value: no demand evidence justifies changes to Card and binary-format compatibility. |
98
+ | I18 | Documentation recipe only | reasoned: a recipe can teach composition without adding public compatibility obligations. | Outside the requested missing-feature result; retain as the main alternative during design. |
99
+ | I19 | Safe inspection, peek plus iteration | direct: `deck.rb:12` exposes mutable cards; `:93` converts them to strings. | Duplicate of I3 and I4; a combined inspection interface adds scope without stronger demand. |
100
+ | I21 | Reproducible simulation branches | direct: I5, I6, and I7 establish snapshot, copying, and exclusion gaps. | Cost over value: combining three speculative needs creates a larger simulation feature set. |
101
+
102
+ Paths abbreviated in this table refer to `lib/card_dealer/`, except `README.md`.
103
+
104
+ ## Validation
105
+
106
+ Read-only Ruby checks confirmed contiguous repeated deals and round-robin distribution using a caller loop.
107
+
108
+ Three two-card contiguous deals produced `[["2c", "3c"], ["4c", "5c"], ["6c", "7c"]]`.
109
+
110
+ The equivalent round-robin loop produced `[["2c", "5c"], ["3c", "6c"], ["4c", "7c"]]` and left 46 cards.
111
+
112
+ A one-card deck given `deal(5, burn: 1)` returned `[]`, left zero remaining cards, and recorded the card as burned.
113
+
114
+ These checks validate the observed primitives. The proposed API has not been implemented.
115
+
116
+ ### Confirmed maintenance priority
117
+
118
+ The independent verifier found that a truncated payload can decode successfully with fewer cards than its header declares. A separate local reproduction confirmed it:
119
+
120
+ ```ruby
121
+ payload = [2, 0].pack("CC")
122
+ CardDealer::Deck.from_binary(payload).to_a # => ["2c"]
123
+ ```
124
+
125
+ Location: `lib/card_dealer/binary_deck.rb:93-98`. The header declares two cards, but the returned deck contains one.
126
+
127
+ Cause: scanning produces available six-bit groups, and `take(deck_size)` accepts fewer groups without validating the declared count.
128
+
129
+ Proposed repair: reject incomplete payloads before returning a deck. Define a documented format error and preserve valid binary encodings.
130
+
131
+ The repair is implemented in `4376fae`. Broader malformed-input cases require a separate bounded investigation.
@@ -12,6 +12,7 @@ module CardDealer
12
12
  #
13
13
  class BinaryDeck
14
14
  class DeckTooLargeError < Error; end
15
+ class InvalidEncodingError < Error; end
15
16
 
16
17
  SUIT_MAP = Card::SUIT_MAP.transform_values { |value| value * 13 }
17
18
  RANK_MAP = Card::RANK_MAP
@@ -83,6 +84,8 @@ module CardDealer
83
84
  #
84
85
  # @return [Deck] The decoded deck of cards.
85
86
  #
87
+ # @raise [InvalidEncodingError] If the payload length does not match the declared card count.
88
+ #
86
89
  # @example
87
90
  # encoded_deck = "\x02\xCDP" # (binary string)
88
91
  # decoded_deck = CardDealer::BinaryDeck.decode(encoded_deck)
@@ -91,6 +94,10 @@ module CardDealer
91
94
  def decode(encoded_deck)
92
95
  template = decoding_template_for encoded_deck.bytesize
93
96
  deck_size, binary_numbers = encoded_deck.unpack(template)
97
+ if deck_size.nil? || binary_numbers.size != (((deck_size * 6) + 7) / 8) * 8
98
+ raise InvalidEncodingError, "Encoded deck length does not match its card count"
99
+ end
100
+
94
101
  cards = binary_numbers.scan(/.{6}/).take(deck_size).map do |binary_number|
95
102
  REVERSE_CARD_BINARY_NUMBER_MAP.fetch(binary_number)
96
103
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CardDealer
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: card_dealer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leonid Svyatov
@@ -23,6 +23,7 @@ files:
23
23
  - ".rspec"
24
24
  - ".rubocop.yml"
25
25
  - CHANGELOG.md
26
+ - CLAUDE.md
26
27
  - CODE_OF_CONDUCT.md
27
28
  - CONTRIBUTING.md
28
29
  - Gemfile
@@ -33,6 +34,7 @@ files:
33
34
  - SECURITY.md
34
35
  - Steepfile
35
36
  - card_dealer.gemspec
37
+ - docs/ideation/2026-11-06-next-feature.md
36
38
  - lib/card_dealer.rb
37
39
  - lib/card_dealer/binary_deck.rb
38
40
  - lib/card_dealer/build_deck.rb