ventiuna 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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