cribbage_game 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f082325ee2fa9bad9eb816d32295d2c7efd3e2fee83698184d48f2e966308263
4
+ data.tar.gz: 8781e57a759011c7ecbc55e76b0965f2de5e076d0d2ffb7e571afe48364a107f
5
+ SHA512:
6
+ metadata.gz: 4f0aabf20f150a33c422a5670209fedda21a51a275f1a7114eaa07eaac7a786fd6d206f31a44ebdb6b11827fe4f98950cdcde18ede6c3e0086f381cac1f15593
7
+ data.tar.gz: c501dd8c015ab55f95ca9bf536042616a52b18c0718f7f135c6920c5917fbcf05df5afee1f619bc140e98271d4ae4817cfeb240b4583df97b7c94107ce438e50
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-11-20
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in cribbage_game.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+
11
+ gem "standard", "~> 1.3"
data/Gemfile.lock ADDED
@@ -0,0 +1,73 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cribbage_game (0.1.0)
5
+ aasm (~> 5.0, >= 5.0.6)
6
+ card_deck
7
+ sum_all_number_combinations (~> 0.1.2)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ aasm (5.4.0)
13
+ concurrent-ruby (~> 1.0)
14
+ ast (2.4.2)
15
+ card_deck (4.02)
16
+ concurrent-ruby (1.1.10)
17
+ diff-lcs (1.3)
18
+ json (2.6.2)
19
+ parallel (1.22.1)
20
+ parser (3.1.2.1)
21
+ ast (~> 2.4.1)
22
+ rainbow (3.1.1)
23
+ rake (13.0.6)
24
+ regexp_parser (2.6.1)
25
+ rexml (3.2.5)
26
+ rspec (3.9.0)
27
+ rspec-core (~> 3.9.0)
28
+ rspec-expectations (~> 3.9.0)
29
+ rspec-mocks (~> 3.9.0)
30
+ rspec-core (3.9.0)
31
+ rspec-support (~> 3.9.0)
32
+ rspec-expectations (3.9.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.9.0)
35
+ rspec-mocks (3.9.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.9.0)
38
+ rspec-support (3.9.0)
39
+ rubocop (1.39.0)
40
+ json (~> 2.3)
41
+ parallel (~> 1.10)
42
+ parser (>= 3.1.2.1)
43
+ rainbow (>= 2.2.2, < 4.0)
44
+ regexp_parser (>= 1.8, < 3.0)
45
+ rexml (>= 3.2.5, < 4.0)
46
+ rubocop-ast (>= 1.23.0, < 2.0)
47
+ ruby-progressbar (~> 1.7)
48
+ unicode-display_width (>= 1.4.0, < 3.0)
49
+ rubocop-ast (1.23.0)
50
+ parser (>= 3.1.1.0)
51
+ rubocop-performance (1.15.0)
52
+ rubocop (>= 1.7.0, < 2.0)
53
+ rubocop-ast (>= 0.4.0)
54
+ ruby-progressbar (1.11.0)
55
+ standard (1.18.0)
56
+ rubocop (= 1.39.0)
57
+ rubocop-performance (= 1.15.0)
58
+ sum_all_number_combinations (0.1.2)
59
+ unicode-display_width (2.3.0)
60
+
61
+ PLATFORMS
62
+ ruby
63
+ x64-mingw32
64
+ x86-mingw32
65
+
66
+ DEPENDENCIES
67
+ cribbage_game!
68
+ rake (~> 13.0)
69
+ rspec (~> 3.0)
70
+ standard (~> 1.3)
71
+
72
+ BUNDLED WITH
73
+ 2.3.6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 buchowski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # CribbageGame
2
+
3
+ Two player cribbage game. https://bicyclecards.com/how-to-play/cribbage/
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'cribbage_game'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install cribbage_game
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ game = Game.new
25
+ game.cut_for_deal # randomly determines dealer
26
+ game.deal # deals 6 cards to game.dealer.hand & game.opponent.hand
27
+ game.dealer.discard ["7d", "qc"] # takes cards from hand and puts in crib
28
+ game.opponent.discard ["6h", "9s"]
29
+ game.flip_top_card # two for his heels if Jack
30
+ game.opponent.play_card 'ah' # game.opponent.total_score is updated automatically
31
+ game.dealer.play_card '8h'
32
+ ... # continue until all cards are played
33
+ game.submit_hand_scores(game.opponent) # adds the hand's score to game.opponent.total_score
34
+ game.submit_hand_scores(game.dealer)
35
+ game.submit_crib_scores # adds the crib's score to game.dealer.total_score
36
+ game.deal # begin next round
37
+ ```
38
+ ### Initialization options
39
+ ```ruby
40
+ game = Game.new ({
41
+ points_to_win: 35, # overrides default of 121
42
+ game_over_cb: lambda { puts "game over" } # function called on game_over
43
+ })
44
+ ```
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
+
50
+ 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).
51
+
52
+ ## Contributing
53
+
54
+ Bug reports and pull requests are welcome on GitHub at https://github.com/buchowski/ruby-cribbage.
55
+
56
+ ## License
57
+
58
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "standard/rake"
9
+
10
+ task default: %i[spec standard]
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/cribbage_game/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "cribbage_game"
7
+ spec.version = CribbageGame::VERSION
8
+ spec.authors = ["buchowski"]
9
+ spec.email = ["bucholz.adam@gmail.com"]
10
+
11
+ spec.summary = "Two player cribbage card game"
12
+ spec.homepage = "https://github.com/buchowski/ruby-cribbage"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/buchowski/ruby-cribbage"
18
+ spec.metadata["changelog_uri"] = "https://github.com/buchowski/ruby-cribbage/blob/master/CHANGELOG.md"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ end
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_dependency "card_deck"
32
+ spec.add_dependency "aasm", "~> 5.0", ">= 5.0.6"
33
+ spec.add_dependency "sum_all_number_combinations", "~> 0.1.2"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+
36
+ # For more information and examples about making a new gem, check out our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
@@ -0,0 +1,47 @@
1
+ module CribbageGame
2
+ require "card_deck"
3
+
4
+ class CardDeck::Card # Represents a card in the deck
5
+ # Value of the card
6
+ def value
7
+ case @num
8
+ when "Ace" then 1
9
+ when 2..10 then @num
10
+ when "Jack" then 10
11
+ when "Queen" then 10
12
+ when "King" then 10
13
+ when "Joker" then 10
14
+ end
15
+ end
16
+
17
+ def sort_value
18
+ case @num
19
+ when "Ace" then 1
20
+ when 2..10 then @num
21
+ when "Jack" then 11
22
+ when "Queen" then 12
23
+ when "King" then 13
24
+ when "Joker" then 14
25
+ end
26
+ end
27
+
28
+ def id
29
+ suit = case @suit
30
+ when Hearts then "h"
31
+ when Spades then "s"
32
+ when Diamonds then "d"
33
+ when Clubs then "c"
34
+ end
35
+ num = case @num
36
+ when "Ace" then "a"
37
+ when "Jack" then "j"
38
+ when "Queen" then "q"
39
+ when "King" then "k"
40
+ when "Joker" then "r"
41
+ else @num.to_s
42
+ end
43
+
44
+ num + suit
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ require "aasm"
2
+
3
+ module CribbageGame
4
+ class Fsm
5
+ include AASM
6
+
7
+ aasm do
8
+ state :cutting_for_deal, initial: true
9
+ state :flipping_top_card
10
+ state :discarding, :dealing, :playing
11
+ state :scoring_opponent_hand, :scoring_dealer_hand, :scoring_dealer_crib
12
+ state :game_over
13
+
14
+ event :deal do
15
+ transitions from: :cutting_for_deal, to: :dealing
16
+ transitions from: :scoring_dealer_crib, to: :dealing
17
+ end
18
+
19
+ event :discard do
20
+ transitions from: :dealing, to: :discarding
21
+ end
22
+
23
+ event :flip_top_card do
24
+ transitions from: :discarding, to: :flipping_top_card
25
+ end
26
+
27
+ event :play do
28
+ transitions from: :flipping_top_card, to: :playing
29
+ end
30
+
31
+ event :score do
32
+ transitions from: :playing, to: :scoring_opponent_hand
33
+ transitions from: :scoring_opponent_hand, to: :scoring_dealer_hand
34
+ transitions from: :scoring_dealer_hand, to: :scoring_dealer_crib
35
+ end
36
+
37
+ event :declare_winner do
38
+ transitions to: :game_over
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,192 @@
1
+ require "cribbage_game/card"
2
+ require "cribbage_game/score"
3
+ require "cribbage_game/player"
4
+ require "cribbage_game/fsm"
5
+
6
+ module CribbageGame
7
+ class NotYourTurnError < RuntimeError; end
8
+
9
+ class NotYourCardError < RuntimeError; end
10
+
11
+ class CardTooLargeError < RuntimeError; end
12
+
13
+ class WrongStateError < RuntimeError; end
14
+
15
+ class Game
16
+ attr_accessor :players, :deck, :crib, :pile, :cut_card, :dealer, :whose_turn, :fsm, :points_to_win, :round, :winner
17
+ attr_reader :auto_score
18
+
19
+ def initialize args = {}
20
+ @points_to_win = args[:points_to_win] || 121
21
+ @auto_score = args[:is_auto_score] || true
22
+ @game_over_cb = args[:game_over_cb] || lambda {}
23
+ @players = 2.times.map { |id| Player.new self, id.to_s }
24
+ @score_client = Score.new self
25
+ @fsm = Fsm.new
26
+ @deck = self.class.get_cards_hash CardDeck::Deck.new.cards
27
+ @round = 0
28
+ @winner = nil
29
+
30
+ reset_cards
31
+ end
32
+
33
+ def self.get_cards_hash cards
34
+ cards.each_with_object({}) do |card, card_map|
35
+ card_map[card.id] = card
36
+ end
37
+ end
38
+
39
+ def self.get_hand_hash card_ids
40
+ card_ids.to_h { |id| [id, true] }
41
+ end
42
+
43
+ def undealt_card_ids
44
+ @deck.keys.difference(@dealer.hand.keys, opponent.hand.keys)
45
+ end
46
+
47
+ def opponent
48
+ @players.difference([@dealer]).first
49
+ end
50
+
51
+ def not_whose_turn
52
+ @players.difference([@whose_turn]).first
53
+ end
54
+
55
+ def can_play_card? card_id
56
+ pile_score + @deck[card_id].value <= 31
57
+ end
58
+
59
+ def player_hands_empty?
60
+ @players.none? { |player| player.hand.values.any? }
61
+ end
62
+
63
+ def has_playable_card? hand
64
+ card_ids = hand.keys.filter { |card_id| hand[card_id] } # false has been played
65
+ card_ids.map { |card_id| can_play_card?(card_id) }.any?
66
+ end
67
+
68
+ def can_whose_turn_play?
69
+ has_playable_card? @whose_turn.hand
70
+ end
71
+
72
+ def can_not_whose_turn_play?
73
+ has_playable_card? not_whose_turn.hand
74
+ end
75
+
76
+ def can_either_player_play?
77
+ can_whose_turn_play? || can_not_whose_turn_play?
78
+ end
79
+
80
+ def pile_score
81
+ @pile.map { |card_id| @deck[card_id].value }.sum
82
+ end
83
+
84
+ def all_cards_discarded?
85
+ @players.all? { |player| player.hand.keys.size == 4 }
86
+ end
87
+
88
+ def is_valid_play? player, card_id
89
+ raise WrongStateError if !@fsm.playing?
90
+ raise NotYourTurnError if player != @whose_turn
91
+ raise NotYourCardError if !player.hand[card_id]
92
+ raise CardTooLargeError if !can_play_card? card_id
93
+ true
94
+ end
95
+
96
+ def reset_cards
97
+ @round += 1
98
+ @cut_card = nil
99
+ @crib = []
100
+ @pile = []
101
+ @players.each { |player| player.hand = {} }
102
+ end
103
+
104
+ def cut_for_deal
105
+ raise WrongStateError if !@fsm.cutting_for_deal?
106
+
107
+ @dealer = @players.sample
108
+ @whose_turn = opponent
109
+ @fsm.deal
110
+ end
111
+
112
+ def deal
113
+ raise WrongStateError if !@fsm.dealing?
114
+
115
+ random_card_ids = @deck.keys.sample 12
116
+ @dealer.hand = self.class.get_hand_hash random_card_ids.slice!(0, 6)
117
+ opponent.hand = self.class.get_hand_hash random_card_ids.slice!(0, 6)
118
+
119
+ @fsm.discard
120
+ end
121
+
122
+ def play_card player, card_id
123
+ is_valid_play?(player, card_id)
124
+
125
+ player.hand[card_id] = false
126
+ @pile << card_id
127
+ is_last_card = !can_either_player_play?
128
+ @score_client.score_play(@pile, is_last_card, player)
129
+ @score_client.submit_play_score player
130
+ return if we_have_a_winner?
131
+
132
+ @pile = [] if is_last_card
133
+ @whose_turn = not_whose_turn if can_not_whose_turn_play?
134
+ @fsm.score if player_hands_empty?
135
+ end
136
+
137
+ def flip_top_card top_card = nil
138
+ raise WrongStateError if !@fsm.flipping_top_card?
139
+
140
+ @cut_card = top_card || undealt_card_ids.sample
141
+ @whose_turn = opponent
142
+ @score_client.score_crib
143
+ @score_client.score_hands
144
+ @fsm.play
145
+ end
146
+
147
+ def discard player, card_id
148
+ raise WrongStateError if !@fsm.discarding?
149
+ raise NotYourCardError if !player.hand[card_id]
150
+
151
+ player.hand.delete(card_id)
152
+ @crib << card_id
153
+
154
+ @fsm.flip_top_card if all_cards_discarded?
155
+ end
156
+
157
+ def submit_hand_scores player
158
+ raise NotYourTurnError if player == @dealer && !@fsm.scoring_dealer_hand?
159
+ raise NotYourTurnError if player == opponent && !@fsm.scoring_opponent_hand?
160
+
161
+ @score_client.submit_scores player, :hand
162
+ return if we_have_a_winner?
163
+ @fsm.score
164
+ end
165
+
166
+ def submit_crib_scores
167
+ raise WrongStateError if !@fsm.scoring_dealer_crib?
168
+
169
+ @score_client.submit_scores @dealer, :crib
170
+ return if we_have_a_winner?
171
+ reset_cards
172
+ @dealer = opponent
173
+ @fsm.deal
174
+ end
175
+
176
+ def auto_score_hands_and_crib
177
+ @score_client.score_hands
178
+ @score_client.score_crib
179
+ end
180
+
181
+ def we_have_a_winner?
182
+ winner = @players.select { |player| player.total_score >= @points_to_win }
183
+ return false if winner.empty?
184
+ raise "You can only have one winner" if winner.size > 1
185
+
186
+ @winner = winner.first
187
+ @fsm.declare_winner
188
+ @game_over_cb.call
189
+ true
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,26 @@
1
+ module CribbageGame
2
+ class Player
3
+ attr_accessor :id, :name, :hand, :total_score
4
+
5
+ def initialize game, id
6
+ @id = id
7
+ @game = game
8
+ @hand = {}
9
+ @total_score = 0
10
+ end
11
+
12
+ def discard cards
13
+ [cards].flatten.each do |card|
14
+ @game.discard self, card
15
+ end
16
+ end
17
+
18
+ def play_card card
19
+ @game.play_card self, card
20
+ end
21
+
22
+ def score_hand
23
+ @game.score_hand self
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,78 @@
1
+ require "cribbage_game/score_utils"
2
+
3
+ module CribbageGame
4
+ class Score
5
+ include ScoreUtils
6
+
7
+ def initialize game
8
+ @game = game
9
+ @scorecards = {}
10
+ end
11
+
12
+ def get_cards card_ids
13
+ card_ids.map { |id| @game.deck[id] }
14
+ end
15
+
16
+ def empty_scorecard
17
+ {crib: {total_score: 0}, hand: {total_score: 0}}
18
+ end
19
+
20
+ def get_scorecard player
21
+ @scorecards[@game.round] = @scorecards[@game.round] || {play: []}
22
+ @scorecards[@game.round][player.id] = @scorecards[@game.round][player.id] || empty_scorecard
23
+ @scorecards[@game.round][player.id]
24
+ end
25
+
26
+ def score_crib
27
+ cards = get_cards(@game.crib + [@game.cut_card])
28
+ get_scorecard(@game.dealer)[:crib][:total_score] = score_hand(cards, true)
29
+ end
30
+
31
+ def score_hands
32
+ @game.players.each do |player|
33
+ cards = get_cards(player.hand.keys + [@game.cut_card])
34
+ get_scorecard(player)[:hand][:total_score] = score_hand cards
35
+ end
36
+ end
37
+
38
+ def score_hand cards, is_crib = false
39
+ n_of_kind_score = score_n_of_a_kind cards
40
+ sum_score = score_fifteens cards
41
+ run_score = score_hand_runs cards
42
+ flush_score = score_flush(cards, is_crib)
43
+ nobs_score = score_nobs(cards)
44
+ n_of_kind_score + sum_score + run_score + flush_score + nobs_score
45
+ end
46
+
47
+ def score_play pile_ids, is_last_card, player
48
+ @scorecards[@game.round] = @scorecards[@game.round] || {play: []}
49
+ pile_cards = get_cards pile_ids
50
+ points = get_pile_points(pile_cards, is_last_card) # pass pile cards not ids
51
+ @scorecards[@game.round][:play] << {
52
+ points: points,
53
+ player_id: player.id,
54
+ pile: pile_ids,
55
+ card_id: pile_ids.last
56
+ }
57
+ end
58
+
59
+ def submit_play_score player, submitted_scores = nil
60
+ raise "You must submit scores if auto_score=false" if submitted_scores.nil? && !@game.auto_score
61
+
62
+ if @game.auto_score
63
+ player.total_score += @scorecards[@game.round][:play].last[:points]
64
+ end
65
+ end
66
+
67
+ def submit_scores player, card_group, submitted_scores = nil
68
+ raise "You must submit scores if auto_score=false" if submitted_scores.nil? && !@game.auto_score
69
+ raise "card_group must be :hand or :crib" if ![:hand, :crib].include? card_group
70
+
71
+ possible_scores = get_scorecard(player)[card_group]
72
+
73
+ if @game.auto_score
74
+ player.total_score += possible_scores[:total_score]
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,126 @@
1
+ require "sum_all_number_combinations"
2
+
3
+ module CribbageGame
4
+ module ScoreUtils
5
+ def is_run sort_vals, is_allow_double_runs = false
6
+ sort_vals.each_index do |i|
7
+ return true if i == sort_vals.size - 1
8
+ card_val = sort_vals[i]
9
+ next_card_val = sort_vals[i + 1]
10
+ is_same_card = next_card_val == card_val
11
+ is_adj_card = next_card_val - card_val == 1
12
+ is_run_possible = is_adj_card || (is_same_card && is_allow_double_runs)
13
+ return false if !is_run_possible
14
+ end
15
+ end
16
+
17
+ def score_hand_runs cards
18
+ return 0 if cards.size < 3
19
+
20
+ sort_vals = cards.map(&:sort_value).sort
21
+ sort_vals.each_index do |i|
22
+ (3..(sort_vals.size)).to_a.reverse_each do |n|
23
+ subset = sort_vals[i...n]
24
+ uniq_count = subset.uniq.size
25
+ break if uniq_count < 3
26
+
27
+ if is_run(subset, true)
28
+ points = uniq_count
29
+ subset.uniq.each do |sort_val|
30
+ count = subset.count sort_val
31
+ points *= count if count > 1
32
+ end
33
+ return points
34
+ end
35
+ end
36
+ end
37
+
38
+ 0
39
+ end
40
+
41
+ def score_pile_runs cards
42
+ return 0 if cards.size < 3
43
+
44
+ (3..cards.size).to_a.reverse_each do |n|
45
+ # get the last n cards played and sort_by sort_value
46
+ sort_vals = cards.map(&:sort_value)
47
+ subset = sort_vals.reverse[0...n].sort
48
+ return n if is_run subset
49
+ end
50
+
51
+ 0
52
+ end
53
+
54
+ def score_consecutive cards
55
+ count = 0
56
+
57
+ cards.each_index do |i|
58
+ break if i == cards.size - 1
59
+ count = (cards[i].num == cards[i + 1].num) ? count + 1 : 0
60
+ end
61
+ # returns 0, 2, 6 or 12
62
+ count**2 + count
63
+ end
64
+
65
+ def score_n_of_a_kind cards
66
+ # 2, 3, 4 of a kind
67
+ counts = cards.each_with_object({}) do |card, counts|
68
+ if counts[card.num].nil?
69
+ counts[card.num] = 1
70
+ else
71
+ counts[card.num] += 1
72
+ end
73
+ end
74
+
75
+ counts.values.reduce(0) do |points, count|
76
+ points + count * (count - 1)
77
+ end
78
+ end
79
+
80
+ def score_fifteens cards
81
+ card_values = cards.map(&:value)
82
+ sum_of_all = SumAllCombinations.new card_values
83
+ sum_of_all.sum
84
+ fifteen_count = sum_of_all.calculated_values.count 15.0
85
+
86
+ fifteen_count * 2
87
+ end
88
+
89
+ def are_same_suit cards
90
+ cards.map(&:suit).uniq.size == 1
91
+ end
92
+
93
+ def score_flush cards, is_crib = false
94
+ raise ArgumentError, "only pass 4 or 5 cards to score_flush" if !cards.size.between?(4, 5)
95
+ is_five_card_flush = cards.size == 5 && are_same_suit(cards)
96
+ is_four_card_flush = cards.size == 4 && are_same_suit(cards[0...4])
97
+
98
+ return 5 if is_five_card_flush
99
+ return 4 if is_four_card_flush && !is_crib
100
+ 0
101
+ end
102
+
103
+ def score_nobs cards
104
+ top_card = cards.pop
105
+ jack = cards.find { |card| card.num == "Jack" }
106
+ return 1 if jack && jack.suit == top_card.suit
107
+ 0
108
+ end
109
+
110
+ def get_pile_points pile_cards, is_last_card
111
+ pile_score = pile_cards.map(&:value).sum
112
+
113
+ throw "31 should always be is_last_card" if pile_score == 31 && !is_last_card
114
+
115
+ points = 0
116
+ points = 1 if pile_score == 31
117
+ points = 2 if pile_score == 15
118
+
119
+ points += 1 if is_last_card
120
+ points += score_consecutive pile_cards
121
+ points += score_pile_runs pile_cards
122
+
123
+ points
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,3 @@
1
+ module CribbageGame
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,2 @@
1
+ require "cribbage_game/version"
2
+ require "cribbage_game/game"
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cribbage_game
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - buchowski
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-12-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: card_deck
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aasm
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 5.0.6
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '5.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 5.0.6
47
+ - !ruby/object:Gem::Dependency
48
+ name: sum_all_number_combinations
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.1.2
61
+ - !ruby/object:Gem::Dependency
62
+ name: rspec
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ description:
76
+ email:
77
+ - bucholz.adam@gmail.com
78
+ executables: []
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - ".rspec"
83
+ - CHANGELOG.md
84
+ - Gemfile
85
+ - Gemfile.lock
86
+ - LICENSE.txt
87
+ - README.md
88
+ - Rakefile
89
+ - cribbage_game.gemspec
90
+ - lib/cribbage_game.rb
91
+ - lib/cribbage_game/card.rb
92
+ - lib/cribbage_game/fsm.rb
93
+ - lib/cribbage_game/game.rb
94
+ - lib/cribbage_game/player.rb
95
+ - lib/cribbage_game/score.rb
96
+ - lib/cribbage_game/score_utils.rb
97
+ - lib/cribbage_game/version.rb
98
+ homepage: https://github.com/buchowski/ruby-cribbage
99
+ licenses:
100
+ - MIT
101
+ metadata:
102
+ homepage_uri: https://github.com/buchowski/ruby-cribbage
103
+ source_code_uri: https://github.com/buchowski/ruby-cribbage
104
+ changelog_uri: https://github.com/buchowski/ruby-cribbage/blob/master/CHANGELOG.md
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 2.6.0
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubygems_version: 3.2.22
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: Two player cribbage card game
124
+ test_files: []