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.
data/lib/poker.rb ADDED
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pry'
4
+
5
+ require_relative 'poker/deck'
6
+ require_relative 'poker/format'
7
+ require_relative 'poker/hand'
8
+ require_relative 'poker/menus'
9
+ require_relative 'poker/utils'
10
+
11
+ SAVE_FILE = 'poker.txt'
12
+ MIN_BET = 500
13
+ MAX_BET = 10_000_000
14
+
15
+ class Poker
16
+ include Utils
17
+ include Menus
18
+
19
+ attr_accessor :deck, :money, :hand, :deck_type, :face_type, :current_bet, :quitting
20
+
21
+ def initialize
22
+ @face_type = 2
23
+ @deck_type = 1
24
+ @money = 10_000
25
+ @current_bet = 500
26
+ end
27
+
28
+ def run
29
+ load_game
30
+ @deck = Deck.new(self)
31
+
32
+ deal_new_hand
33
+ clear_draw_hand_bet_options until quitting
34
+ end
35
+
36
+ def build_new_hand
37
+ self.hand = Hand.new(self, current_bet)
38
+ 5.times { hand.deal_card }
39
+ end
40
+
41
+ def deal_new_hand
42
+ deck.send("new_#{DECKS[deck_type]}")
43
+ build_new_hand
44
+
45
+ clear
46
+ draw_hand
47
+ hand.ask_hand_action
48
+ save_game
49
+ end
50
+
51
+ def clear
52
+ return if ENV['CLEAR_TERM'] == '0'
53
+
54
+ system('export TERM=linux; clear')
55
+ end
56
+
57
+ def draw_hand
58
+ out = String.new
59
+ out << "\n Player $"
60
+ out << Format.money(money / 100.0)
61
+ out << ":\n"
62
+ out << hand.draw
63
+ puts out
64
+ end
65
+
66
+ def new_bet(input)
67
+ clear
68
+ draw_hand
69
+
70
+ puts " Current Bet: $#{Format.money(current_bet / 100)}\n"
71
+ print ' Enter New Bet: $'
72
+
73
+ self.current_bet = input.gets.to_i * 100
74
+
75
+ normalize_current_bet
76
+ deal_new_hand
77
+ end
78
+
79
+ def normalize_current_bet
80
+ if current_bet < MIN_BET
81
+ self.current_bet = MIN_BET
82
+ elsif current_bet > MAX_BET
83
+ self.current_bet = MAX_BET
84
+ end
85
+
86
+ self.current_bet = money if current_bet > money
87
+ end
88
+
89
+ def self.getc(input)
90
+ begin
91
+ system('stty raw -echo')
92
+ c = input.getc
93
+ ensure
94
+ system('stty -raw echo')
95
+ end
96
+ c.chr
97
+ end
98
+ end
data/poker.txt ADDED
@@ -0,0 +1 @@
1
+ 1|1|10000|500
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :card do
5
+ poker { nil }
6
+ value { 0 }
7
+ suit { 0 }
8
+
9
+ trait :ace do
10
+ value { 0 }
11
+ end
12
+
13
+ trait :two do
14
+ value { 1 }
15
+ end
16
+
17
+ trait :three do
18
+ value { 2 }
19
+ end
20
+
21
+ trait :four do
22
+ value { 3 }
23
+ end
24
+
25
+ trait :five do
26
+ value { 4 }
27
+ end
28
+
29
+ trait :six do
30
+ value { 5 }
31
+ end
32
+
33
+ trait :seven do
34
+ value { 6 }
35
+ end
36
+
37
+ trait :eight do
38
+ value { 7 }
39
+ end
40
+
41
+ trait :nine do
42
+ value { 8 }
43
+ end
44
+
45
+ trait :ten do
46
+ value { 9 }
47
+ end
48
+
49
+ trait :jack do
50
+ value { 10 }
51
+ end
52
+
53
+ trait :queen do
54
+ value { 11 }
55
+ end
56
+
57
+ trait :king do
58
+ value { 12 }
59
+ end
60
+
61
+ trait :spades do
62
+ suit { 0 }
63
+ end
64
+
65
+ trait :hearts do
66
+ suit { 1 }
67
+ end
68
+
69
+ trait :clubs do
70
+ suit { 2 }
71
+ end
72
+
73
+ trait :diamonds do
74
+ suit { 3 }
75
+ end
76
+
77
+ initialize_with { new(poker, value, suit) }
78
+ end
79
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :deck do
5
+ poker { nil }
6
+ cards { [] }
7
+
8
+ trait :new_regular do
9
+ after(:build, &:new_regular)
10
+ end
11
+
12
+ initialize_with { new(poker) }
13
+ end
14
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :hand do
5
+ poker { nil }
6
+ bet { 500 }
7
+ cards { [] }
8
+
9
+ trait :unknown do
10
+ cards do
11
+ [
12
+ build(:card, :ace, suit: 1),
13
+ build(:card, :five),
14
+ build(:card, :six),
15
+ build(:card, :seven),
16
+ build(:card, :eight)
17
+ ]
18
+ end
19
+ end
20
+
21
+ trait :royal_flush do
22
+ cards do
23
+ [
24
+ build(:card, :ace),
25
+ build(:card, :king),
26
+ build(:card, :queen),
27
+ build(:card, :jack),
28
+ build(:card, :ten)
29
+ ]
30
+ end
31
+ end
32
+
33
+ trait :straight_flush do
34
+ cards do
35
+ [
36
+ build(:card, :king),
37
+ build(:card, :queen),
38
+ build(:card, :jack),
39
+ build(:card, :ten),
40
+ build(:card, :nine)
41
+ ]
42
+ end
43
+ end
44
+
45
+ trait :four_of_a_kind do
46
+ cards do
47
+ [
48
+ build(:card, :king),
49
+ build(:card, :ace),
50
+ build(:card, :ace),
51
+ build(:card, :ace),
52
+ build(:card, :ace)
53
+ ]
54
+ end
55
+ end
56
+
57
+ trait :full_house do
58
+ cards do
59
+ [
60
+ build(:card, :king),
61
+ build(:card, :king),
62
+ build(:card, :ace),
63
+ build(:card, :ace),
64
+ build(:card, :ace)
65
+ ]
66
+ end
67
+ end
68
+
69
+ trait :flush do
70
+ cards do
71
+ [
72
+ build(:card, :king),
73
+ build(:card, :queen),
74
+ build(:card, :jack),
75
+ build(:card, :ten),
76
+ build(:card, :eight)
77
+ ]
78
+ end
79
+ end
80
+
81
+ trait :straight do
82
+ cards do
83
+ [
84
+ build(:card, :king, suit: 1),
85
+ build(:card, :queen),
86
+ build(:card, :jack),
87
+ build(:card, :ten),
88
+ build(:card, :nine)
89
+ ]
90
+ end
91
+ end
92
+
93
+ trait :three_of_a_kind do
94
+ cards do
95
+ [
96
+ build(:card, :king),
97
+ build(:card, :queen),
98
+ build(:card, :ace, suit: 1),
99
+ build(:card, :ace),
100
+ build(:card, :ace)
101
+ ]
102
+ end
103
+ end
104
+
105
+ trait :two_pair do
106
+ cards do
107
+ [
108
+ build(:card, :king),
109
+ build(:card, :king, suit: 1),
110
+ build(:card, :queen),
111
+ build(:card, :queen, suit: 1),
112
+ build(:card, :ace)
113
+ ]
114
+ end
115
+ end
116
+
117
+ trait :one_pair do
118
+ cards do
119
+ [
120
+ build(:card, :king),
121
+ build(:card, :king, suit: 1),
122
+ build(:card, :queen),
123
+ build(:card, :jack),
124
+ build(:card, :ace)
125
+ ]
126
+ end
127
+ end
128
+
129
+ initialize_with { new(poker, bet) }
130
+ end
131
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :poker do
5
+ deck { nil }
6
+ money { 10_000 }
7
+ hand { nil }
8
+ face_type { 1 }
9
+ current_bet { 500 }
10
+ end
11
+
12
+ trait :with_deck do
13
+ deck { build(:deck, :new_regular) }
14
+ end
15
+
16
+ initialize_with { new }
17
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Card do
4
+ let(:poker) { build(:poker) }
5
+ let(:card) { build(:card, poker:) }
6
+
7
+ describe '.new' do
8
+ it 'creates a card' do
9
+ expect(card).to be
10
+ end
11
+
12
+ it 'has a value' do
13
+ expect(card.value).to eq(0)
14
+ end
15
+
16
+ it 'has a suit' do
17
+ expect(card.suit).to eq(0)
18
+ end
19
+ end
20
+
21
+ describe '#to_s' do
22
+ context 'with regular faces' do
23
+ it 'returns a string value' do
24
+ expect(card.to_s).to eq('🂡')
25
+ end
26
+ end
27
+
28
+ context 'with alternate faces' do
29
+ before do
30
+ poker.face_type = 2
31
+ end
32
+
33
+ it 'returns a string value' do
34
+ expect(card.to_s).to eq('A♠')
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '.faces' do
40
+ it 'returns a five of clubs' do
41
+ expect(described_class.faces[4][3]).to eq('🃕')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Deck do
4
+ let(:poker) { build(:poker) }
5
+ let(:deck) { build(:deck, poker:) }
6
+
7
+ describe '.new' do
8
+ it 'creates a deck' do
9
+ expect(deck).to be
10
+ end
11
+ end
12
+
13
+ describe '#new_regular' do
14
+ let(:deck) { build(:deck, poker:) }
15
+
16
+ it 'creates a deck' do
17
+ deck.new_regular
18
+ expect(deck.cards.size).to eq(Deck::TOTAL_CARDS)
19
+ end
20
+
21
+ it 'calls shuffle' do
22
+ allow(deck).to receive(:shuffle)
23
+ deck.new_regular
24
+ expect(deck).to have_received(:shuffle)
25
+ end
26
+ end
27
+
28
+ describe '#new_aces' do
29
+ let(:deck) { build(:deck, poker:) }
30
+
31
+ it 'creates a deck' do
32
+ deck.new_aces
33
+ expect(deck.cards.size).to eq(Deck::TOTAL_CARDS)
34
+ end
35
+
36
+ it 'calls shuffle' do
37
+ allow(deck).to receive(:shuffle)
38
+ deck.new_aces
39
+ expect(deck).to have_received(:shuffle)
40
+ end
41
+ end
42
+
43
+ describe '#new_jacks' do
44
+ let(:deck) { build(:deck, poker:) }
45
+
46
+ it 'creates a deck' do
47
+ deck.new_jacks
48
+ expect(deck.cards.size).to eq(Deck::TOTAL_CARDS)
49
+ end
50
+
51
+ it 'calls shuffle' do
52
+ allow(deck).to receive(:shuffle)
53
+ deck.new_jacks
54
+ expect(deck).to have_received(:shuffle)
55
+ end
56
+ end
57
+
58
+ describe '#new_aces_jacks' do
59
+ let(:deck) { build(:deck, poker:) }
60
+
61
+ it 'creates a deck' do
62
+ deck.new_aces_jacks
63
+ expect(deck.cards.size).to eq(Deck::TOTAL_CARDS)
64
+ end
65
+
66
+ it 'calls shuffle' do
67
+ allow(deck).to receive(:shuffle)
68
+ deck.new_aces_jacks
69
+ expect(deck).to have_received(:shuffle)
70
+ end
71
+ end
72
+
73
+ describe '#new_sevens' do
74
+ let(:deck) { build(:deck, poker:) }
75
+
76
+ it 'creates a deck' do
77
+ deck.new_sevens
78
+ expect(deck.cards.size).to eq(Deck::TOTAL_CARDS)
79
+ end
80
+
81
+ it 'calls shuffle' do
82
+ allow(deck).to receive(:shuffle)
83
+ deck.new_sevens
84
+ expect(deck).to have_received(:shuffle)
85
+ end
86
+ end
87
+
88
+ describe '#new_eights' do
89
+ let(:deck) { build(:deck, poker:) }
90
+
91
+ it 'creates a deck' do
92
+ deck.new_eights
93
+ expect(deck.cards.size).to eq(Deck::TOTAL_CARDS)
94
+ end
95
+
96
+ it 'calls shuffle' do
97
+ allow(deck).to receive(:shuffle)
98
+ deck.new_eights
99
+ expect(deck).to have_received(:shuffle)
100
+ end
101
+ end
102
+
103
+ describe '#next_card' do
104
+ let(:deck) { build(:deck, :new_regular, poker:) }
105
+
106
+ it 'removes the next card' do
107
+ expect { deck.next_card }.to change(deck.cards, :size).by(-1)
108
+ end
109
+
110
+ it 'returns a Card' do
111
+ expect(deck.next_card).to be_an_instance_of(Card)
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Format do
4
+ describe '#money' do
5
+ it 'returns a formatted money string' do
6
+ str = described_class.money(1)
7
+ expect(str).to eq('1.00')
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe HandRanker do
4
+ let(:poker) { build(:poker) }
5
+ let(:ranker) { described_class.new(hand) }
6
+
7
+ describe '.new' do
8
+ let(:hand) { build(:hand, :unknown, poker:) }
9
+
10
+ it 'creates a hand ranker' do
11
+ expect(ranker).to be
12
+ expect(hand.rank).to eq(:unknown)
13
+ end
14
+
15
+ context 'with less than 5 cards' do
16
+ let(:hand) { build(:hand, poker:) }
17
+
18
+ it 'raises an error' do
19
+ expect { ranker }.to raise_error(ArgumentError)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#rank_hand' do
25
+ before { ranker }
26
+
27
+ context 'with a royal_flush' do
28
+ let(:hand) { build(:hand, :royal_flush, poker:) }
29
+
30
+ it 'detects a royal_flush' do
31
+ expect(hand.rank).to eq(:royal_flush)
32
+ end
33
+ end
34
+
35
+ context 'with a straight_flush' do
36
+ let(:hand) { build(:hand, :straight_flush, poker:) }
37
+
38
+ it 'detects a straight_flush' do
39
+ expect(hand.rank).to eq(:straight_flush)
40
+ end
41
+ end
42
+
43
+ context 'with a four_of_a_kind' do
44
+ let(:hand) { build(:hand, :four_of_a_kind, poker:) }
45
+
46
+ it 'detects a four_of_a_kind' do
47
+ expect(hand.rank).to eq(:four_of_a_kind)
48
+ end
49
+ end
50
+
51
+ context 'with a full_house' do
52
+ let(:hand) { build(:hand, :full_house, poker:) }
53
+
54
+ it 'detects a full_house' do
55
+ expect(hand.rank).to eq(:full_house)
56
+ end
57
+ end
58
+
59
+ context 'with a flush' do
60
+ let(:hand) { build(:hand, :flush, poker:) }
61
+
62
+ it 'detects a flush' do
63
+ expect(hand.rank).to eq(:flush)
64
+ end
65
+ end
66
+
67
+ context 'with a straight' do
68
+ let(:hand) { build(:hand, :straight, poker:) }
69
+
70
+ it 'detects a straight' do
71
+ expect(hand.rank).to eq(:straight)
72
+ end
73
+ end
74
+
75
+ context 'with a three_of_a_kind' do
76
+ let(:hand) { build(:hand, :three_of_a_kind, poker:) }
77
+
78
+ it 'detects a three_of_a_kind' do
79
+ expect(hand.rank).to eq(:three_of_a_kind)
80
+ end
81
+ end
82
+
83
+ context 'with a two_pair' do
84
+ let(:hand) { build(:hand, :two_pair, poker:) }
85
+
86
+ it 'detects :two_pair' do
87
+ expect(hand.rank).to eq(:two_pair)
88
+ end
89
+ end
90
+
91
+ context 'with pair of twos and a pair of queens' do
92
+ let(:hand) do
93
+ build(:hand, poker:, cards: [build(:card, :two, :diamonds),
94
+ build(:card, :queen, :clubs),
95
+ build(:card, :queen, :hearts),
96
+ build(:card, :two, :spades),
97
+ build(:card, :ten, :hearts)])
98
+ end
99
+
100
+ it 'detects :two_pair' do
101
+ expect(hand.rank).to eq(:two_pair)
102
+ end
103
+ end
104
+
105
+ context 'with a one_pair' do
106
+ let(:hand) { build(:hand, :one_pair, poker:) }
107
+
108
+ it 'detects a one_pair' do
109
+ expect(hand.rank).to eq(:one_pair)
110
+ end
111
+ end
112
+
113
+ context 'with two successive values' do
114
+ let(:hand) do
115
+ build(:hand, poker:, cards:
116
+ [
117
+ build(:card, :king, suit: 1),
118
+ build(:card, :queen),
119
+ build(:card, :jack),
120
+ build(:card, :ten),
121
+ build(:card, :two)
122
+ ])
123
+ end
124
+
125
+ it 'is not a straight' do
126
+ expect(hand.rank).to eq(:unknown)
127
+ end
128
+ end
129
+ end
130
+ end