simpleblackjack 0.1.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
+ SHA1:
3
+ metadata.gz: 48e580c4ae782c8d7626d4cd36d9a965f4a1c217
4
+ data.tar.gz: dba6046bbd683ef8c5c06a1ed48ff2abb83744e4
5
+ SHA512:
6
+ metadata.gz: f3edd852c1e1e13abc2c59f8c92e1922633e7a5d9255b9882469b688b4012f3500454429a9905655c97a6c36d5534b15a169b1dcc54413130579b5cc8e3d73d9
7
+ data.tar.gz: 704e55b6a7fd00f27e102e0d2276caf84b20a899a09647c68c6678b83d9f3cb74e41d352d016423df7a54008f24d09805599d527d42b641db76a2ab3943a137e
data/bin/blackJack ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../'))
4
+
5
+ require 'rubygems'
6
+ require 'colorize'
7
+ require 'lib/blackjack'
8
+
9
+ @game = BlackJackGame::Game.new
data/bin/blackjack ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../'))
4
+
5
+ require 'rubygems'
6
+ require 'colorize'
7
+ require 'lib/blackjack'
8
+
9
+ @game = BlackJackGame::Game.new
data/lib/blackjack.rb ADDED
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+ require 'lib/blackjack/version'
3
+ require 'lib/blackjack/cards/deck'
4
+ require 'lib/blackjack/cards/card'
5
+ require 'lib/blackjack/cards/card_types'
6
+ require 'lib/blackjack/players/player'
7
+ require 'lib/blackjack/players/blackjack_player'
8
+ require 'lib/blackjack/players/dealer'
9
+ require 'lib/blackjack/game/game_logic'
10
+ require 'lib/blackjack/game/board'
11
+
12
+
13
+ module BlackJackGame
14
+
15
+ class Game
16
+ attr_accessor :players
17
+ attr_accessor :game_logic
18
+
19
+ # Create a new player list and Game Deck
20
+ def initialize
21
+ @players = []
22
+ @players.push(Dealer.new("Mr. Dealer"))
23
+ @players.push(BlackJackPlayer.new("Human"))
24
+ @game_logic = GameLogic.new(@players)
25
+ start_game
26
+ end
27
+
28
+ # The Game
29
+ def start_game
30
+ @game_logic.game_round
31
+
32
+ puts 'Thanks for playing!'
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+ require 'colorize'
3
+
4
+ class Card
5
+ # Container for a game card and helper methods.
6
+ attr_accessor :type
7
+ attr_accessor :suit
8
+
9
+ # card_suit: shape of card:
10
+ # card_type: numerical value
11
+ def initialize(card_suit, card_type)
12
+ @suit = card_suit[0]
13
+ @type = card_type[0]
14
+ end
15
+
16
+ # Returns the printed notation of a card
17
+ # i.e. 2 of diamonds: 2♦
18
+ def to_s
19
+ return "#{FrenchDeck.card_face(@type)}#{FrenchDeck::SUIT[@suit]}"
20
+ end
21
+
22
+ # Easy accesor to the value of the card
23
+ def value
24
+ return FrenchDeck::TYPE[@type]
25
+ end
26
+
27
+ # Helper to return the text representation of the card in the respective color
28
+ def print
29
+ case @suit
30
+ when :heart, :diamond
31
+ text = "[#{to_s}]".red.on_white
32
+ else
33
+ text = "[#{to_s}]".black.on_white
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: UTF-8
2
+ class FrenchDeck
3
+ # Representation of a 52 poker/blackjack card deck.
4
+
5
+ # Numeric Type
6
+ TYPE = {
7
+ :ace => 1,
8
+ :two => 2,
9
+ :three => 3,
10
+ :four => 4,
11
+ :five => 5,
12
+ :six => 6,
13
+ :seven => 7,
14
+ :eight => 8,
15
+ :nine => 9,
16
+ :ten => 10,
17
+ :jack => 11,
18
+ :queen => 12,
19
+ :king => 13
20
+ }.freeze
21
+
22
+ # Figure
23
+ SUIT = {
24
+ :spade => "♠",
25
+ :heart => "♥",
26
+ :diamond => "♦",
27
+ :clove => "♣"
28
+ }.freeze
29
+
30
+ # Returns the value as it would appear visually on a french deck card
31
+ # i.e: J or a Jack card.
32
+ def self.card_face(card_type)
33
+ case TYPE[card_type]
34
+ when 2..10
35
+ TYPE[card_type]
36
+ when 1
37
+ "A"
38
+ when 11
39
+ "J"
40
+ when 12
41
+ "Q"
42
+ when 13
43
+ "K"
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ class Deck
3
+ # Represents a game deck containing 52 cards.
4
+ # plus helper methods to handle the deck.
5
+
6
+ # Creates a new ordered deck. 52 card deck of cards. 1 per suite
7
+ def self.build_deck
8
+ deck = []
9
+ FrenchDeck::SUIT.each do |suit|
10
+ FrenchDeck::TYPE.each do |type|
11
+ deck.push( Card.new(suit, type))
12
+ end
13
+ end
14
+ deck
15
+ end
16
+
17
+ # Returns a copy of a random shuffled deck.
18
+ def self.shuffle(deck)
19
+ deck.shuffle(Time.now.to_i)
20
+ end
21
+ end
@@ -0,0 +1,140 @@
1
+ # encoding: UTF-8
2
+ class Board
3
+ # Graphic helper methods to display the game board
4
+
5
+
6
+ ####################################################################
7
+ # Interactive methods
8
+ ####################################################################
9
+
10
+
11
+ # Drawing routine.
12
+ # Receives a game state, and draws the board.
13
+ def self.re_draw(players, action_list = nil, winners = false, game_stats = nil)
14
+ clear_screen
15
+ print_header
16
+ print_separator
17
+
18
+ players.each do |p|
19
+ print_player(p)
20
+ end
21
+
22
+ print_separator
23
+
24
+ print_winner_list(winners) if winners
25
+
26
+ ask_action(action_list) if action_list
27
+ end
28
+
29
+ # Displays a list of actions to the user, and returns the user's selected action
30
+ # as a char, being the first letter of the action typed by the user.
31
+ def self.ask_action(action_list = nil)
32
+ if action_list
33
+ action_bar = "Action? (Type key followed by enter)\t".blue
34
+ action_list.each do |action|
35
+ action_bar += " - [#{action[0]}]".green + action[1..-1]
36
+ end
37
+
38
+ puts action_bar
39
+
40
+ output = STDIN.gets
41
+
42
+ return output.capitalize[0]
43
+ end
44
+
45
+ return nil
46
+ end
47
+
48
+
49
+ ####################################################################
50
+ # Screen printing
51
+ ####################################################################
52
+
53
+
54
+ # Prints a player's data and current card deck.
55
+ def self.print_player(player)
56
+ hidding = false
57
+ player_deck = ""
58
+
59
+ player.cards_in_hand.keys.each do |card|
60
+ if player.cards_in_hand[card] #hidden
61
+ player_deck += "[░░]".black.on_white
62
+ hidding = true
63
+ else
64
+ player_deck += card.print
65
+ end
66
+ end
67
+
68
+ puts print_avatar(player)
69
+ puts " Card Total: #{player.hand_value}".cyan unless hidding
70
+ puts "\t\t #{player_deck} \n\n"
71
+
72
+ print_board_logo if player.kind == :dealer
73
+ end
74
+
75
+ # Helper to print percent of many games a player won
76
+ def self.print_win_ratio_in_percent(player)
77
+ "\t\t=> Percent of Games Won: #{player.win_ratio_in_percent}%".green
78
+ end
79
+
80
+ # Prints a colored line
81
+ def self.print_separator
82
+ separator = "=-_-=" * 15
83
+ puts separator.yellow + "\n"
84
+ end
85
+
86
+ # Pretty prints the winner list
87
+ def self.print_winner_list(winners)
88
+ puts " **!!!! #{winners.join(' and ')} wins this round!".magenta
89
+ end
90
+
91
+ # clears the display to ready it for a redraw.
92
+ # this works on linux/osx only
93
+ def self.clear_screen
94
+ system('clear')
95
+ end
96
+
97
+
98
+ ####################################################################
99
+ # Ascii drawing methods
100
+ ####################################################################
101
+
102
+
103
+ def self.print_avatar(player)
104
+ avt = ""
105
+ case player.kind
106
+ when :human
107
+ avt = player_avatar
108
+ when :dealer
109
+ avt = dealer_avatar
110
+ end
111
+
112
+ avt + "*".yellow + " #{player.name} #{print_win_ratio_in_percent(player)} \t\t\t".magenta
113
+ end
114
+
115
+ # Player Character drawing
116
+ def self.player_avatar
117
+ return "(゜_゜)".cyan
118
+ end
119
+
120
+ # Dealer Character drawing
121
+ def self.dealer_avatar
122
+ return "(ノ◕".cyan+"ヮ".blue+"◕)-☆".cyan
123
+ end
124
+
125
+ # Awesomeness generated by http://www.network-science.de/ascii/
126
+ def self.print_header
127
+ puts "| | | o | ".light_green
128
+ puts "|---.| ,---.,---.|__/ .,---.,---.|__/ ".light_green
129
+ puts "| || ,---|| | \\ |,---|| | \\ ".green
130
+ puts "`---'`---'`---^`---'` ` |`---^`---'` `".green
131
+ puts " `---' ".yellow
132
+ end
133
+
134
+ def self.print_board_logo
135
+ puts "\n\t\t / \\ ".yellow
136
+ puts "\t\t ==== | =BJ= | ====".light_green
137
+ puts "\t\t \\ / \n\n".yellow
138
+ end
139
+
140
+ end
@@ -0,0 +1,159 @@
1
+ # encoding: UTF-8
2
+ class GameLogic
3
+ # Game logic methods
4
+
5
+ attr_accessor :player_list
6
+ attr_accessor :game_number
7
+ attr_accessor :card_deck
8
+ attr_accessor :games_before_shuffle
9
+
10
+ def initialize(players)
11
+ @game_number = 0
12
+ @player_list = players
13
+ @card_deck = Deck.build_deck
14
+ @games_before_shuffle = 6
15
+ end
16
+
17
+ # Go Through each player in the game and deal a black jack game.
18
+ def game_round
19
+ begin
20
+ @game_number+=1
21
+ shuffle_deck!
22
+ deal_initial_cards(@player_list)
23
+ do_player_turns
24
+ update_stats(pick_winner)
25
+ end while player_wants_to_continue
26
+ end
27
+
28
+ # Ask the player if another round should be dealt
29
+ def player_wants_to_continue
30
+ response = Board.re_draw(@player_list,["Quit", "Continue"], pick_winner)
31
+
32
+ if response == 'C'
33
+ return true
34
+ elsif response == 'Q'
35
+ return false
36
+ else
37
+ player_wants_to_continue
38
+ end
39
+ end
40
+
41
+ # Iterate each player's turns
42
+ def do_player_turns
43
+ last_action = nil
44
+
45
+ @player_list.reverse.each do |current_player|
46
+ if current_player.blackjack_in_hand?
47
+ current_player.blackjack!
48
+ next
49
+ end
50
+
51
+ Board.re_draw(@player_list)
52
+
53
+ case current_player.kind
54
+ when :dealer
55
+ dealer_handler(current_player)
56
+ when :human
57
+ while current_player.hand_value < 21 and last_action != :stay
58
+ last_action = action_handler(current_player)
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ # Reshuffle after 6 games OR if remaining stack is less than 15
66
+ # so the game doesn't run out of cards.
67
+ def shuffle_deck!
68
+ if @game_number % @games_before_shuffle == 1 or @card_deck.count < 15
69
+ @card_deck = Deck.shuffle(Deck.build_deck)
70
+ end
71
+ end
72
+
73
+ #give 2 start cards to each player
74
+ def deal_initial_cards(players)
75
+ players.each do |p|
76
+
77
+ p.clear_cards
78
+
79
+ if p.kind == :dealer
80
+ p.add_card(@card_deck.pop, true) #first card from dealer is hidden :)
81
+ p.add_card(@card_deck.pop, false)
82
+ else
83
+ p.add_card(@card_deck.pop, false)
84
+ p.add_card(@card_deck.pop, false)
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ # Game action
91
+ def action_handler(player)
92
+
93
+ puts "dealing with #{player.name}"
94
+ response = Board.re_draw(@player_list,["Hit", "Stay"])
95
+ case response
96
+ when 'H'
97
+ player.add_card(@card_deck.pop, false)
98
+ when 'S'
99
+ return :stay
100
+ else
101
+ #iterate again
102
+ action_handler(player)
103
+ end
104
+ end
105
+
106
+ #deals with the turn of the dealer
107
+ def dealer_handler(dealer)
108
+ dealer.reveal_deck
109
+ Board.re_draw(@player_list)
110
+
111
+ while dealer.should_hit?(@player_list)
112
+ sleep(1)
113
+ dealer.add_card(@card_deck.pop)
114
+ Board.re_draw(@player_list)
115
+ end
116
+
117
+ end
118
+
119
+ # Logic to picking a winner
120
+ # Since there is no betting:
121
+ # If somebody on the table has blackjack, they are the winners
122
+ # Otherwise. whomever gets the top score wins.
123
+ # Note: According to casino rules online => Blackjack beats 21
124
+ def pick_winner
125
+ max_score = 0
126
+ winners = []
127
+ blackjackers = []
128
+
129
+ @player_list.each do |p|
130
+ if p.blackjack_in_hand?
131
+ blackjackers.push(p.name)
132
+ elsif p.hand_value == max_score
133
+ winners.push(p.name)
134
+ elsif p.hand_value > max_score and p.hand_value <= 21
135
+ winners = []
136
+ winners.push(p.name)
137
+ max_score = p.hand_value
138
+ end
139
+ end
140
+
141
+ #choose the winner!
142
+ if blackjackers.count > 0
143
+ return blackjackers
144
+ else
145
+ return winners
146
+ end
147
+ end
148
+
149
+ # update game win/loss ratio stats
150
+ def update_stats(winners)
151
+ @player_list.each do |player|
152
+ player.games_played +=1
153
+ if winners.include? player.name
154
+ player.games_won += 1
155
+ end
156
+ end
157
+ end
158
+
159
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+ class BlackJackPlayer < Player
3
+ # Represents a game player with the logic for a Black Jack game
4
+
5
+ # key value pairs.
6
+ # k/v pairs for: Card object, Value: boolean representing visibility
7
+ attr_accessor :cards_in_hand
8
+
9
+ # New player with no cards in hand.
10
+ # Requires name of the player
11
+ def initialize(name, kind = :human)
12
+ super(name, kind)
13
+ clear_cards
14
+ end
15
+
16
+ # Empty the players cards
17
+ def clear_cards
18
+ @cards_in_hand = {}
19
+ end
20
+
21
+ # Adds a card to the players deck.
22
+ # hidden is a flag to display the card as not visible to the players
23
+ # representing a facing down card.
24
+ def add_card(card, hidden = false)
25
+ @cards_in_hand[card] = hidden
26
+ end
27
+
28
+ # Sum of card numeric values
29
+ # If there's an ace. Will see if flipping its value from 1 to 11 brings the deck closer to 21.
30
+ # counting 2(or more) aces as 11 won't work here as the deck goes over to 22.
31
+ def hand_value
32
+ hand_value = 0
33
+ has_ace = false
34
+
35
+ @cards_in_hand.keys.each do |c|
36
+ case c.type
37
+ when :ace
38
+ has_ace = true
39
+ hand_value += 1
40
+ when :king, :queen, :jack
41
+ hand_value += 10
42
+ else
43
+ hand_value += c.value
44
+ end
45
+ end
46
+
47
+ if has_ace and (hand_value + 10) <= 21
48
+ hand_value += 10
49
+ end
50
+ hand_value
51
+ end
52
+
53
+ # Checks if the hand contains a blackjack
54
+ # which is a combo of 2 cards: Ace plus a figure
55
+ def blackjack_in_hand?
56
+ blackjack = false
57
+ if @cards_in_hand.count == 2
58
+ pair = []
59
+ pair.push @cards_in_hand.keys.first.type
60
+ pair.push @cards_in_hand.keys.last.type
61
+
62
+ if pair.include?(:ace) and [:jack, :king, :queen].any? { |i| pair.include?(i) }
63
+ blackjack = true
64
+ end
65
+ end
66
+ blackjack
67
+ end
68
+
69
+ # Makes the whole deck visible.
70
+ def reveal_deck
71
+ @cards_in_hand.keys.each do |c|
72
+ @cards_in_hand[c] = false
73
+ end
74
+ end
75
+
76
+ # Flip visibility of all cards on black jack
77
+ def blackjack!
78
+ @cards_in_hand.keys do |c|
79
+ @cards_in_hand[c] = false
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: UTF-8
2
+ class Dealer < BlackJackPlayer
3
+ # Handles the extra logic of being a Dealer
4
+
5
+ # Initializes a new Dealer
6
+ def initialize(name)
7
+ super(name, :dealer)
8
+ end
9
+
10
+
11
+ # Super simple logic.
12
+ # Dealer keeps hitting until bust or won the game
13
+ # Hits on hard 17
14
+ #
15
+ # Soft 17 contains ace
16
+ # Hard 17 has no ace
17
+ def should_hit?(player_against)
18
+ score_to_beat = 0
19
+
20
+ if blackjack_in_hand?
21
+ blackjack!
22
+ return false
23
+ end
24
+
25
+ player_against.each do |p|
26
+ puts p.hand_value
27
+ if p.kind == :human and p.hand_value > score_to_beat and p.hand_value <= 21
28
+ score_to_beat = p.hand_value
29
+ end
30
+ end
31
+
32
+ if hand_value < score_to_beat and hand_value <= 17
33
+ return true
34
+ else
35
+ return false
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ class Player
3
+ # Base abstraction for a game player
4
+
5
+ #Kinds of Player
6
+ KIND =
7
+ {
8
+ :dealer => 0,
9
+ :player => 1
10
+ }
11
+
12
+ # Generic player methods.
13
+ attr_accessor :name
14
+ attr_accessor :kind
15
+ attr_accessor :games_won
16
+ attr_accessor :games_played
17
+
18
+ # Creates a new player, initializes it's name.
19
+ def initialize(name, kind = :player)
20
+ @name = name
21
+ @kind = kind
22
+ @games_won = 0
23
+ @games_played = 0
24
+ end
25
+
26
+ # Returns the percent of games won by this player
27
+ def win_ratio_in_percent
28
+ win_ratio = @games_won.to_f / @games_played.to_f
29
+ return win_ratio * 100
30
+ end
31
+
32
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ module BlackJack
3
+ VERSION = "0.1.0"
4
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simpleblackjack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ivan Marcin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - '>='
23
+ - !ruby/object:Gem::Version
24
+ version: '0'
25
+ prerelease: false
26
+ type: :runtime
27
+ description: Black Jack card game
28
+ email:
29
+ - ivanmarcin@gmail.com
30
+ executables:
31
+ - blackJack
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - bin/blackjack
36
+ - lib/blackjack.rb
37
+ - lib/blackjack/version.rb
38
+ - lib/blackjack/cards/card.rb
39
+ - lib/blackjack/cards/card_types.rb
40
+ - lib/blackjack/cards/deck.rb
41
+ - lib/blackjack/game/board.rb
42
+ - lib/blackjack/game/game_logic.rb
43
+ - lib/blackjack/players/blackjack_player.rb
44
+ - lib/blackjack/players/dealer.rb
45
+ - lib/blackjack/players/player.rb
46
+ - bin/blackJack
47
+ homepage: https://github.com/ivanmarcin/BJG
48
+ licenses: []
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '>='
62
+ - !ruby/object:Gem::Version
63
+ version: 1.3.5
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.1.9
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: Simple Black Jack Game
70
+ test_files: []