console-poker 1.0.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
+ SHA256:
3
+ metadata.gz: 2e70a169233864f5e2a074a20109adc0136b6a6a9e81d6877b90e37233390238
4
+ data.tar.gz: 16c18c8cee66bfe98d0a186faa7830f8c6dd0564f1ac0b0c4957fb489f0141e3
5
+ SHA512:
6
+ metadata.gz: 6c47146c022d7b5fdfb414b70c73d4355f38e5797be22c8dd485784d0be1c3a12e05d2e8b80972ec0aea9ffa2064894a3a449a66fe31baa578fc0046167e095e
7
+ data.tar.gz: 7444d0f39a2e31863afe4a42a96c66911d3424176431138b6f0adda77aa2a4b685cccc03f7dbc6160ce1f69f52d9fd4819a302363fb7c285305320ec3d2eed32
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ ruby '3.1.2'
4
+
5
+ source 'https://rubygems.org'
6
+
7
+ gem 'factory_bot'
8
+ gem 'pry'
9
+ gem 'rake'
10
+ gem 'rspec'
11
+ gem 'rubocop', require: false
12
+ gem 'rubocop-rake'
13
+ gem 'rubocop-rspec'
14
+ gem 'simplecov', require: false
data/Gemfile.lock ADDED
@@ -0,0 +1,89 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (7.0.4)
5
+ concurrent-ruby (~> 1.0, >= 1.0.2)
6
+ i18n (>= 1.6, < 2)
7
+ minitest (>= 5.1)
8
+ tzinfo (~> 2.0)
9
+ ast (2.4.2)
10
+ coderay (1.1.3)
11
+ concurrent-ruby (1.1.10)
12
+ diff-lcs (1.5.0)
13
+ docile (1.4.0)
14
+ factory_bot (6.2.1)
15
+ activesupport (>= 5.0.0)
16
+ i18n (1.12.0)
17
+ concurrent-ruby (~> 1.0)
18
+ json (2.6.2)
19
+ method_source (1.0.0)
20
+ minitest (5.16.3)
21
+ parallel (1.22.1)
22
+ parser (3.1.2.1)
23
+ ast (~> 2.4.1)
24
+ pry (0.14.1)
25
+ coderay (~> 1.1)
26
+ method_source (~> 1.0)
27
+ rainbow (3.1.1)
28
+ rake (13.0.6)
29
+ regexp_parser (2.5.0)
30
+ rexml (3.2.5)
31
+ rspec (3.11.0)
32
+ rspec-core (~> 3.11.0)
33
+ rspec-expectations (~> 3.11.0)
34
+ rspec-mocks (~> 3.11.0)
35
+ rspec-core (3.11.0)
36
+ rspec-support (~> 3.11.0)
37
+ rspec-expectations (3.11.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.11.0)
40
+ rspec-mocks (3.11.1)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.11.0)
43
+ rspec-support (3.11.0)
44
+ rubocop (1.36.0)
45
+ json (~> 2.3)
46
+ parallel (~> 1.10)
47
+ parser (>= 3.1.2.1)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ regexp_parser (>= 1.8, < 3.0)
50
+ rexml (>= 3.2.5, < 4.0)
51
+ rubocop-ast (>= 1.20.1, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 1.4.0, < 3.0)
54
+ rubocop-ast (1.21.0)
55
+ parser (>= 3.1.1.0)
56
+ rubocop-rake (0.6.0)
57
+ rubocop (~> 1.0)
58
+ rubocop-rspec (2.12.1)
59
+ rubocop (~> 1.31)
60
+ ruby-progressbar (1.11.0)
61
+ simplecov (0.21.2)
62
+ docile (~> 1.1)
63
+ simplecov-html (~> 0.11)
64
+ simplecov_json_formatter (~> 0.1)
65
+ simplecov-html (0.12.3)
66
+ simplecov_json_formatter (0.1.4)
67
+ tzinfo (2.0.5)
68
+ concurrent-ruby (~> 1.0)
69
+ unicode-display_width (2.2.0)
70
+
71
+ PLATFORMS
72
+ arm64-darwin-21
73
+ x86_64-linux
74
+
75
+ DEPENDENCIES
76
+ factory_bot
77
+ pry
78
+ rake
79
+ rspec
80
+ rubocop
81
+ rubocop-rake
82
+ rubocop-rspec
83
+ simplecov
84
+
85
+ RUBY VERSION
86
+ ruby 3.1.2p20
87
+
88
+ BUNDLED WITH
89
+ 2.3.15
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Greg Donald
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # console-poker-ruby
2
+
3
+ ![Poker](https://raw.githubusercontent.com/gdonald/console-poker-ruby/main/ss1.png)
4
+
5
+ ![Poker](https://raw.githubusercontent.com/gdonald/console-poker-ruby/main/ss2.png)
6
+
7
+ ## Getting Started
8
+
9
+ Install:
10
+
11
+ gem install console-poker
12
+
13
+ Run:
14
+
15
+ console-poker
16
+
17
+ ## Status
18
+
19
+ [![Ruby](https://github.com/gdonald/console-poker-ruby/workflows/Ruby/badge.svg)](https://github.com/gdonald/console-poker-ruby/actions)
20
+ [![Downloads](https://ruby-gem-downloads-badge.herokuapp.com/console-poker?color=blue&type=total&total_label=)](https://rubygems.org/gems/console-poker)
21
+
22
+ ## License
23
+
24
+ [![GitHub](https://img.shields.io/github/license/gdonald/console-poker-ruby?color=aa0000)](https://github.com/gdonald/console-poker-ruby/blob/main/LICENSE)
25
+
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+ task default: :spec
5
+ RSpec::Core::RakeTask.new
data/bin/console-poker ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/poker'
5
+ Poker.new.run
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.required_ruby_version = '>= 3.1'
7
+ spec.name = 'console-poker'
8
+ spec.version = '1.0.0'
9
+ spec.summary = 'Console Poker'
10
+ spec.description = 'Poker for your console, full version.'
11
+ spec.author = 'Greg Donald'
12
+ spec.email = 'gdonald@gmail.com'
13
+ spec.bindir = 'bin'
14
+ spec.executables << 'console-poker'
15
+ spec.files = FileList['lib/**/*.rb',
16
+ 'bin/*',
17
+ '[A-Z]*',
18
+ 'spec/**/*.rb'].to_a
19
+ spec.homepage = 'https://github.com/gdonald/console-poker-ruby'
20
+ spec.metadata = {
21
+ 'source_code_uri' => 'https://github.com/gdonald/console-poker-ruby',
22
+ 'rubygems_mfa_required' => 'true'
23
+ }
24
+ spec.license = 'MIT'
25
+ spec.post_install_message = "\nType `console-poker` to run!\n\n"
26
+ end
data/lib/poker/card.rb ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Card
4
+ attr_reader :poker, :value, :suit
5
+
6
+ def initialize(poker, value, suit)
7
+ @poker = poker
8
+ @value = value
9
+ @suit = suit
10
+ end
11
+
12
+ def to_s
13
+ return Card.faces[value][suit] if poker.face_type == 1
14
+
15
+ Card.faces2[value][suit]
16
+ end
17
+
18
+ def self.faces
19
+ [%w[🂡 🂱 🃁 🃑], %w[🂢 🂲 🃂 🃒], %w[🂣 🂳 🃃 🃓], %w[🂤 🂴 🃄 🃔],
20
+ %w[🂥 🂵 🃅 🃕], %w[🂦 🂶 🃆 🃖], %w[🂧 🂷 🃇 🃗], %w[🂨 🂸 🃈 🃘],
21
+ %w[🂩 🂹 🃉 🃙], %w[🂪 🂺 🃊 🃚], %w[🂫 🂻 🃋 🃛], %w[🂭 🂽 🃍 🃝],
22
+ %w[🂮 🂾 🃎 🃞], %w[🂠]]
23
+ end
24
+
25
+ def self.faces2
26
+ [%w[A♠ A♥ A♣ A♦], %w[2♠ 2♥ 2♣ 2♦],
27
+ %w[3♠ 3♥ 3♣ 3♦], %w[4♠ 4♥ 4♣ 4♦],
28
+ %w[5♠ 5♥ 5♣ 5♦], %w[6♠ 6♥ 6♣ 6♦],
29
+ %w[7♠ 7♥ 7♣ 7♦], %w[8♠ 8♥ 8♣ 8♦],
30
+ %w[9♠ 9♥ 9♣ 9♦], %w[T♠ T♥ T♣ T♦],
31
+ %w[J♠ J♥ J♣ J♦], %w[Q♠ Q♥ Q♣ Q♦],
32
+ %w[K♠ K♥ K♣ K♦], %w[??]]
33
+ end
34
+ end
data/lib/poker/deck.rb ADDED
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'card'
4
+
5
+ DECKS = {
6
+ 1 => :regular,
7
+ 2 => :aces,
8
+ 3 => :jacks,
9
+ 4 => :aces_jacks,
10
+ 5 => :sevens,
11
+ 6 => :eights
12
+ }.freeze
13
+
14
+ class Deck
15
+ TOTAL_CARDS = 52
16
+
17
+ attr_accessor :poker, :cards
18
+
19
+ def initialize(poker)
20
+ @poker = poker
21
+ @cards = []
22
+ end
23
+
24
+ def shuffle
25
+ 7.times { cards.shuffle! }
26
+ end
27
+
28
+ def new_regular
29
+ self.cards = []
30
+ 4.times do |suit_value|
31
+ 13.times do |value|
32
+ cards << Card.new(poker, value, suit_value)
33
+ end
34
+ end
35
+ shuffle
36
+ end
37
+
38
+ def new_irregular(values = [])
39
+ self.cards = []
40
+ while cards.count < TOTAL_CARDS
41
+ 4.times do |suit_value|
42
+ next if cards.count >= TOTAL_CARDS
43
+
44
+ values.each do |value|
45
+ cards << Card.new(poker, value, suit_value)
46
+ end
47
+ end
48
+ end
49
+ shuffle
50
+ end
51
+
52
+ def new_aces
53
+ new_irregular([0])
54
+ end
55
+
56
+ def new_jacks
57
+ new_irregular([10])
58
+ end
59
+
60
+ def new_aces_jacks
61
+ new_irregular([0, 10])
62
+ end
63
+
64
+ def new_sevens
65
+ new_irregular([6])
66
+ end
67
+
68
+ def new_eights
69
+ new_irregular([7])
70
+ end
71
+
72
+ def next_card
73
+ cards.shift
74
+ end
75
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Format
4
+ def self.money(value)
5
+ format_str = '%.2f'
6
+ format(format_str, value)
7
+ end
8
+ end
data/lib/poker/hand.rb ADDED
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hand_ranker'
4
+
5
+ class Hand
6
+ PAYOUT = {
7
+ royal_flush: 800,
8
+ straight_flush: 50,
9
+ four_of_a_kind: 25,
10
+ full_house: 9,
11
+ flush: 6,
12
+ straight: 4,
13
+ three_of_a_kind: 3,
14
+ two_pair: 2,
15
+ one_pair: 1
16
+ }.freeze
17
+
18
+ attr_accessor :poker, :bet, :result, :cards, :rank, :current_card, :discards
19
+
20
+ def initialize(poker, bet)
21
+ @poker = poker
22
+ @bet = bet
23
+ @result = nil
24
+ @cards = []
25
+ @discards = []
26
+ @current_card = 0
27
+ @rank = :unknown
28
+ end
29
+
30
+ def deal_card
31
+ cards << poker.deck.next_card
32
+ end
33
+
34
+ def pay
35
+ return if result
36
+
37
+ HandRanker.new(self)
38
+
39
+ self.result = rank == :unknown ? -bet : PAYOUT[rank] * bet
40
+ poker.money += result
41
+ end
42
+
43
+ def draw
44
+ out = String.new(' ')
45
+ out << draw_cards
46
+ out << draw_money
47
+ out << draw_card_selector
48
+ out << "\n\n"
49
+ out
50
+ end
51
+
52
+ def draw_card_selector
53
+ space = poker.face_type == 2 ? ' ' : ' '
54
+
55
+ out = String.new("\n ")
56
+ 5.times do |i|
57
+ out << (current_card == i ? '⇑' : ' ')
58
+ out << space
59
+ end
60
+ out
61
+ end
62
+
63
+ def draw_money
64
+ out = String.new('')
65
+ out << (result.negative? ? '-' : '+') if result
66
+ out << '$' << Format.money((result || bet).abs / 100.0)
67
+ out << ' '
68
+ out
69
+ end
70
+
71
+ def draw_cards
72
+ faces = poker.face_type == 2 ? Card.faces2 : Card.faces
73
+ card_back = faces[13][0]
74
+
75
+ out = String.new('')
76
+ 5.times do |i|
77
+ out << (discards.include?(i) ? card_back : cards[i].to_s)
78
+ out << ' '
79
+ end
80
+ out << rank_display
81
+ out
82
+ end
83
+
84
+ def rank_display
85
+ if rank == :unknown
86
+ ' '
87
+ else
88
+ rank_name = rank.to_s.split(/ |_/).map(&:capitalize).join(' ')
89
+ " ⇒ #{rank_name} "
90
+ end
91
+ end
92
+
93
+ def ask_hand_action
94
+ puts ' (K) Keep (D) Discard (N) Next (P) Prev (X) Draw'
95
+ c = Poker.getc($stdin)
96
+ case c
97
+ when 'k'
98
+ discards.delete(current_card)
99
+ self.current_card = current_card.succ
100
+ clear_draw_hand_actions
101
+ when 'd'
102
+ discards << current_card unless discards.include?(current_card)
103
+ self.current_card = current_card.succ
104
+ clear_draw_hand_actions
105
+ when 'n'
106
+ self.current_card = current_card.succ
107
+ clear_draw_hand_actions
108
+ when 'p'
109
+ self.current_card = current_card.pred
110
+ clear_draw_hand_actions
111
+ when 'x'
112
+ self.current_card = nil
113
+ replace_discards
114
+ pay
115
+ else
116
+ clear_draw_hand_actions
117
+ end
118
+ end
119
+
120
+ def clear_draw_hand_actions
121
+ normalize_current_card
122
+ poker.clear
123
+ poker.draw_hand
124
+ ask_hand_action
125
+ end
126
+
127
+ def normalize_current_card
128
+ self.current_card = 0 if current_card.negative?
129
+ self.current_card = 4 if current_card > 4
130
+ end
131
+
132
+ def replace_discards
133
+ 5.times do |i|
134
+ next unless discards.include?(i)
135
+
136
+ cards[i] = poker.deck.next_card
137
+ end
138
+
139
+ discards.clear
140
+ end
141
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HandRanker
4
+ attr_reader :hand, :vals
5
+
6
+ def initialize(hand)
7
+ @hand = hand
8
+ @vals = hand.cards.map(&:value).compact.sort
9
+ raise ArgumentError, 'hand must have exactly five Cards' unless vals.count == 5
10
+
11
+ hand.rank = rank_hand
12
+ end
13
+
14
+ private
15
+
16
+ def rank_hand
17
+ if royal_flush?
18
+ :royal_flush
19
+ elsif straight_flush?
20
+ :straight_flush
21
+ elsif four_of_a_kind?
22
+ :four_of_a_kind
23
+ elsif full_house?
24
+ :full_house
25
+ elsif flush?
26
+ :flush
27
+ elsif straight?
28
+ :straight
29
+ elsif three_of_a_kind?
30
+ :three_of_a_kind
31
+ elsif two_pair?
32
+ :two_pair
33
+ elsif one_pair?
34
+ :one_pair
35
+ else
36
+ :unknown
37
+ end
38
+ end
39
+
40
+ def royal_flush?
41
+ flush? && vals == [0, 9, 10, 11, 12]
42
+ end
43
+
44
+ def straight_flush?
45
+ flush? && straight?
46
+ end
47
+
48
+ def four_of_a_kind?
49
+ uniq_count_one?(vals, 0, 1, 2, 3) || uniq_count_one?(vals, 1, 2, 3, 4)
50
+ end
51
+
52
+ def full_house?
53
+ (uniq_count_one?(vals, 0, 1, 2) && uniq_count_one?(vals, 3, 4)) ||
54
+ (uniq_count_one?(vals, 0, 1) && uniq_count_one?(vals, 2, 3, 4))
55
+ end
56
+
57
+ def flush?
58
+ hand.cards.map(&:suit).uniq.count == 1
59
+ end
60
+
61
+ def straight?
62
+ vals == [vals[0], vals[0] + 1, vals[0] + 2, vals[0] + 3, vals[0] + 4]
63
+ end
64
+
65
+ def three_of_a_kind?
66
+ uniq_count_one?(vals, 0, 1, 2) ||
67
+ uniq_count_one?(vals, 1, 2, 3) ||
68
+ uniq_count_one?(vals, 2, 3, 4)
69
+ end
70
+
71
+ def two_pair?
72
+ (uniq_count_one?(vals, 0, 1) && uniq_count_one?(vals, 2, 3)) ||
73
+ (uniq_count_one?(vals, 0, 1) && uniq_count_one?(vals, 3, 4)) ||
74
+ (uniq_count_one?(vals, 1, 2) && uniq_count_one?(vals, 3, 4))
75
+ end
76
+
77
+ def one_pair?
78
+ uniq_count_one?(vals, 0, 1) ||
79
+ uniq_count_one?(vals, 1, 2) ||
80
+ uniq_count_one?(vals, 2, 3) ||
81
+ uniq_count_one?(vals, 3, 4)
82
+ end
83
+
84
+ def uniq_count_one?(array, *args)
85
+ array.values_at(*args).uniq.count == 1
86
+ end
87
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Menus
4
+ def draw_bet_options
5
+ puts ' (D) Deal Hand (B) Change Bet (O) Options (Q) Quit'
6
+ c = Poker.getc($stdin)
7
+ case c
8
+ when 'd'
9
+ deal_new_hand
10
+ when 'b'
11
+ new_bet($stdin)
12
+ when 'o'
13
+ clear_draw_hand_game_options
14
+ when 'q'
15
+ self.quitting = true
16
+ else
17
+ clear_draw_hand_bet_options
18
+ end
19
+ end
20
+
21
+ def new_face_type
22
+ puts ' (1) 🂡 (2) A♠'
23
+ loop do
24
+ c = Poker.getc($stdin).to_i
25
+ case c
26
+ when (1..2)
27
+ self.face_type = c
28
+ save_game
29
+ else
30
+ clear_draw_hand_new_face_type
31
+ end
32
+ break if (1..2).include?(c)
33
+ end
34
+ end
35
+
36
+ def new_deck_type
37
+ puts ' (1) Regular (2) Aces (3) Jacks (4) Aces & Jacks (5) Sevens (6) Eights'
38
+ loop do
39
+ c = Poker.getc($stdin).to_i
40
+ case c
41
+ when (1..6)
42
+ self.deck_type = c
43
+ deck.send("new_#{DECKS[c]}")
44
+ save_game
45
+ else
46
+ clear_draw_hand_new_deck_type
47
+ end
48
+ break if (1..6).include?(c)
49
+ end
50
+ end
51
+
52
+ def draw_game_options
53
+ puts ' (T) Deck Type (F) Face Type (B) Back'
54
+ loop do
55
+ c = Poker.getc($stdin)
56
+ case c
57
+ when 't'
58
+ clear_draw_hand_new_deck_type
59
+ clear_draw_hand_bet_options
60
+ when 'f'
61
+ clear_draw_hand_new_face_type
62
+ clear_draw_hand_bet_options
63
+ when 'b'
64
+ clear_draw_hand_bet_options
65
+ else
66
+ clear_draw_hand_game_options
67
+ end
68
+ break if %w[t b f].include?(c)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Utils
4
+ def load_game
5
+ return unless File.readable?(SAVE_FILE)
6
+
7
+ a = File.read(SAVE_FILE).split('|')
8
+ self.deck_type = a[0].to_i
9
+ self.face_type = a[1].to_i
10
+ self.money = a[2].to_i
11
+ self.current_bet = a[3].to_i
12
+ end
13
+
14
+ def save_game
15
+ File.open(SAVE_FILE, 'w') do |file|
16
+ file.puts "#{deck_type}|#{face_type}|#{money}|#{current_bet}"
17
+ end
18
+ end
19
+
20
+ def clear_draw_hand
21
+ clear
22
+ draw_hand
23
+ end
24
+
25
+ def clear_draw_hand_new_deck_type
26
+ clear_draw_hand
27
+ new_deck_type
28
+ end
29
+
30
+ def clear_draw_hand_new_face_type
31
+ clear_draw_hand
32
+ new_face_type
33
+ end
34
+
35
+ def clear_draw_hand_bet_options
36
+ clear_draw_hand
37
+ draw_bet_options
38
+ end
39
+
40
+ def clear_draw_hand_game_options
41
+ clear_draw_hand
42
+ draw_game_options
43
+ end
44
+ end