ventiuna 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a32c5d1a85b6195f1788e7140ba4ccea7c09a9ed
4
+ data.tar.gz: 48236ffbfd90c0aa4b9735c6defd6b1a2e24e807
5
+ SHA512:
6
+ metadata.gz: 3311d5355c7e6bd203bd2a7b7c0db32784d7b637916243567ab541cc8e30ba10d417871cc45ba6f2d881d40924b2a7a321eadc947dee9df298190da00c48291e
7
+ data.tar.gz: 16c1a72d42e6f1bcf4302307a9f859a1dba938fc2091b637a3a017a05f0226a9548e1463bd4f7011fc04ec20b25a792a31aae8ea6426328d861272a263267150
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ventiuna.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dru Ibarra
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Ventiuna
2
+
3
+ ![blackjack and hookers](/img/bender.jpg)
4
+
5
+ TODO: Add hookers
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'ventiuna'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ventiuna
20
+
21
+ ## Usage
22
+
23
+ $ require 'ventiuna'
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/test*.rb']
7
+ t.verbose = true
8
+ end
Binary file
@@ -0,0 +1,18 @@
1
+ require "ventiuna/database/connection"
2
+ require "ventiuna/database/schema"
3
+ require "ventiuna/strategies/strategy"
4
+ require "ventiuna/strategies/move"
5
+ require "ventiuna/version"
6
+ require "ventiuna/card"
7
+ require "ventiuna/hand"
8
+ require "ventiuna/deck"
9
+ require "ventiuna/shoe"
10
+ require "ventiuna/player"
11
+ require "ventiuna/dealer"
12
+ require "ventiuna/game"
13
+
14
+ module Ventiuna
15
+ players = []
16
+ players << Ventiuna::Player.new("Player 1")
17
+ Ventiuna::Game.new(players).play
18
+ end
@@ -0,0 +1,35 @@
1
+ module Ventiuna
2
+ class Card
3
+ attr_accessor :rank, :suit
4
+
5
+ def initialize(rank: "joker", suit: "joker")
6
+ @rank = rank.to_s.upcase
7
+ @suit = suit
8
+ end
9
+
10
+ def to_i(high: true, low: false)
11
+ return 1 if self.ace? && low
12
+ return 11 if self.ace? && high
13
+ return 10 if ["K", "Q", "J"].include?(self.rank)
14
+ self.rank.to_i
15
+ end
16
+ alias :value :to_i
17
+
18
+ def ace?
19
+ self.rank == "A"
20
+ end
21
+
22
+ # sorts cards with Aces always high
23
+ def <=>(other_card)
24
+ self.value(high: true) <=> other_card.value(high: true)
25
+ end
26
+
27
+ def ==(other_card)
28
+ self.to_s == other_card.to_s
29
+ end
30
+
31
+ def to_s
32
+ "#{self.rank} #{self.suit}"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ require 'active_record'
2
+ require 'sqlite3'
3
+
4
+ DB_FILE = "lib/ventiuna/database/ventiuna_strategy.db"
5
+
6
+ ActiveRecord::Base.establish_connection(
7
+ :adapter => "sqlite3",
8
+ :database => DB_FILE
9
+ )
@@ -0,0 +1,23 @@
1
+ unless File.exists?(DB_FILE)
2
+ ActiveRecord::Schema.define do
3
+ create_table :strategies do |t|
4
+ t.column :name, :string, :null => false
5
+ end
6
+
7
+ create_table :moves do |t|
8
+ t.column :strategy_id, :integer, :null => false
9
+ t.column :dealers_card_value, :integer, :null => false
10
+ #t.column :cards, :string
11
+ t.column :hand, :string, :null => false
12
+ t.column :decision, :string, :null => false
13
+ t.column :win, :integer, :default => 0
14
+ t.column :tie, :integer, :default => 0
15
+ t.column :lose, :integer, :default => 0
16
+ t.column :progress, :integer, :default => 0
17
+ t.column :bust, :integer, :default => 0
18
+ end
19
+
20
+ #add_index(:moves, [:strategy_id, :dealers_card_value, :cards], :name => 'by_players_cards')
21
+ add_index(:moves, [:strategy_id, :dealers_card_value, :hand], :name => 'by_players_hand_value')
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Ventiuna
2
+ class Dealer < Ventiuna::Player
3
+ def decision
4
+ if self.hand.value < 17
5
+ "h"
6
+ elsif self.hand.value == 17 && self.hand.soft?
7
+ "h"
8
+ else
9
+ "s"
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ module Ventiuna
2
+ class Deck
3
+ @@suits = ["club", "spade", "heart", "diamond"]
4
+ @@ranks = %w(2 3 4 5 6 7 8 9 10 J Q K A)
5
+
6
+ attr_accessor :cards
7
+
8
+ def initialize
9
+ @cards = []
10
+ @@suits.each do |suit|
11
+ @@ranks.each do |rank|
12
+ @cards << Ventiuna::Card.new(rank: rank, suit: suit)
13
+ end
14
+ end
15
+ @shuffled = false
16
+ end
17
+
18
+ def shuffle
19
+ @cards.shuffle!
20
+ @shuffled = true
21
+ self
22
+ end
23
+
24
+ def shuffled?
25
+ @shuffled
26
+ end
27
+
28
+ def size
29
+ self.cards.size
30
+ end
31
+
32
+ def pop
33
+ @cards.pop
34
+ end
35
+
36
+ def ==(other_deck)
37
+ self.cards == other_deck.cards
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,273 @@
1
+ module Ventiuna
2
+ class Game
3
+ def initialize(players, shoe_size: 8, min_bet: 10, max_bet: 500, max_rounds: 1000)
4
+ @dealer = Ventiuna::Dealer.new("Dealer")
5
+ @shoe_size = shoe_size
6
+ @shoe = Ventiuna::Shoe.new(@shoe_size).shuffle
7
+ @players = Array(players)
8
+ @losers = []
9
+ @min_bet = min_bet
10
+ @max_bet = max_bet
11
+ @max_rounds = max_rounds
12
+ @rounds_count = 0
13
+ end
14
+
15
+ def play
16
+ remove_dead_beats
17
+ while @rounds_count < @max_rounds
18
+ #puts @rounds_count
19
+ puts "********************** NEW DEAL ******************************"
20
+ start_round
21
+
22
+ @rounds_count += 1
23
+ remove_dead_beats
24
+ break if @players.empty?
25
+ end
26
+ print_stats
27
+ end
28
+
29
+ private
30
+ def print_stats
31
+ puts ""
32
+ puts "################## STATS ##################"
33
+ (@players + @losers).each do |player|
34
+ puts "#{player.name}:"
35
+ puts player.stats
36
+ puts "Balance: $#{player.balance}"
37
+ end
38
+ puts ""
39
+ puts "#{@dealer.name}:"
40
+ puts @dealer.stats
41
+ end
42
+
43
+ def remove_dead_beats
44
+ @players.each_with_index do |player, i|
45
+ @losers << @players.delete_at(i) if player.balance < @min_bet
46
+ end
47
+ end
48
+
49
+ def setup
50
+ @shoe = Ventiuna::Shoe.new(@shoe_size).shuffle if @shoe.needs_shuffling?
51
+ (@players + [@dealer]).each do |player|
52
+ player.hands = [Ventiuna::Hand.new]
53
+ player.reset_decisions
54
+ end
55
+ end
56
+
57
+ def place_bets()
58
+ @players.each do |player|
59
+ player.place_bet(@min_bet, @max_bet)
60
+ end
61
+ end
62
+
63
+ def deal
64
+ 2.times do
65
+ (@players + [@dealer]).each do |player|
66
+ player.hand << @shoe.pop
67
+ end
68
+ end
69
+ end
70
+
71
+ def print_hands(print_dealers_full_hand: false)
72
+ puts @dealer.name
73
+ if print_dealers_full_hand
74
+ puts @dealer.hands.first.to_s
75
+ else
76
+ puts @dealer.hands.first.cards.first.to_s
77
+ end
78
+ puts "----"
79
+
80
+ @players.each do |player|
81
+ puts player.name
82
+ puts player.hands.each{|h| h.to_s}
83
+ puts "----"
84
+ end
85
+ end
86
+
87
+ def build_hands
88
+ @players.each do |player|
89
+ while player.hand
90
+ player.hand << @shoe.pop if player.hand.cards.size == 1
91
+
92
+ #puts ""
93
+ puts "Hit/Stand/Double/SPlit:"
94
+ puts player.hand.to_s
95
+
96
+ if player.hand.bust?
97
+ player.hand.stand
98
+ next
99
+ end
100
+
101
+ case player.decision(@dealer.hand.cards.first)
102
+ when "h"
103
+ puts "HIT"
104
+ player.hand << @shoe.pop
105
+ build_hands
106
+ when "s"
107
+ puts "STAND"
108
+ player.hand.stand
109
+ when "d"
110
+ if player.hand.cards.size == 2
111
+ puts "DOUBLE"
112
+ player.hand << @shoe.pop
113
+ puts player.hand.to_s
114
+ player.hand.stand
115
+ else
116
+ puts "Can't double down on this hand!"
117
+ build_hands
118
+ end
119
+ when "sp"
120
+ if player.hand.pair? && player.hands.count == 1
121
+ puts "SPLIT"
122
+ #$stdin.gets
123
+ if player.hand.cards.first.ace? && player.hand.cards.last.ace?
124
+ player.hands = player.hand.split
125
+ player.hands.each do |h|
126
+ h << @shoe.pop
127
+ puts h.to_s
128
+ h.stand
129
+ end
130
+ else
131
+ player.hands = player.hand.split
132
+ end
133
+ else
134
+ puts "Can't split this hand!"
135
+ end
136
+ build_hands
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ def dealer_draw
143
+ return false if @players.collect{ |p| p.hands }.flatten.all?{ |h| h.bust? }
144
+
145
+ while @dealer.hand && !@dealer.hand.bust?
146
+ case @dealer.decision
147
+ when "h"
148
+ @dealer.hand << @shoe.pop
149
+ dealer_draw
150
+ when "s"
151
+ @dealer.hand.stand
152
+ end
153
+ end
154
+ end
155
+
156
+ def start_round
157
+ setup
158
+ place_bets
159
+ deal
160
+ print_hands
161
+ return end_round if @dealer.hand.blackjack?
162
+ build_hands
163
+ dealer_draw
164
+ end_round
165
+ end
166
+
167
+ def end_round
168
+ print_hands(print_dealers_full_hand: true)
169
+ payout
170
+ record_moves!
171
+ end
172
+
173
+ def determine_outcome(player_hand)
174
+ if player_hand.value == @dealer.hands.first.value
175
+ "tie"
176
+ elsif player_hand.blackjack?
177
+ "blackjack"
178
+ elsif player_hand.bust?
179
+ "bust"
180
+ elsif @dealer.hands.first.bust? && !player_hand.bust?
181
+ "win"
182
+ elsif player_hand.value > @dealer.hands.first.value
183
+ "win"
184
+ elsif player_hand.value < @dealer.hands.first.value
185
+ "lose"
186
+ end
187
+ end
188
+
189
+ def record_split(player, hand)
190
+
191
+ end
192
+
193
+ def record_moves!()
194
+ #puts "record moves!!!!"
195
+ @players.each do |player|
196
+ #puts player
197
+ #puts player.decisions
198
+ player.decisions.each do |hand, moves|
199
+ #puts hand
200
+ #puts moves
201
+ last_move = moves.pop
202
+ if last_move.decision == "sp"
203
+ puts "split"
204
+ puts hand
205
+ puts moves.inspect
206
+ puts player.decisions.keys
207
+ #$stdin.gets
208
+ # record split
209
+ next
210
+ end
211
+ #puts last_move.decision
212
+ $stdin.gets if last_move.decision == "sp"
213
+ outcome = determine_outcome(hand)
214
+
215
+ last_move.update_counts(outcome)
216
+
217
+ moves.each do |move|
218
+ next if move.decision == "sp"
219
+ move.update_counts("progress")
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ def record_moves(player, hand, outcome)
226
+ last_move = player.decisions[hand].last
227
+ return false unless last_move
228
+ value = 1
229
+ value = 2 if last_move.decision == "d"
230
+
231
+ puts outcome.upcase
232
+ case outcome
233
+ when "win", "blackjack"
234
+ last_move.win += value
235
+ when "bust"
236
+ last_move.bust += value
237
+ when "lose"
238
+ last_move.lose += value
239
+ when "tie"
240
+ last_move.tie += 1
241
+ end
242
+ last_move.save
243
+ end
244
+
245
+ def payout
246
+ @players.each do |player|
247
+ player.hands.each do |hand|
248
+ outcome = determine_outcome(hand)
249
+ puts outcome.upcase
250
+ #record_moves(player, hand, outcome)
251
+ case outcome
252
+ when "blackjack"
253
+ player.balance += (player.bet * 2.5)
254
+ player.wins += 1
255
+ @dealer.loses += 1
256
+ when "win"
257
+ player.balance += (player.bet * 2)
258
+ player.wins += 1
259
+ @dealer.loses += 1
260
+ when "lose", "bust"
261
+ player.bet = 0
262
+ player.loses += 1
263
+ @dealer.wins += 1
264
+ when "tie"
265
+ player.balance += player.bet
266
+ player.ties += 1
267
+ @dealer.ties += 1
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end