Skip to main content
1 of 3
tj63
  • 53
  • 1
  • 5

Simple blackjack program

I created this blackjack program as a first attempt at Ruby. Would appreciate a code review to see if I am doing things the ruby way (is there a better way to get user input?), using OOP correctly and anything else you want to point out.

            class Card

              def initialize(suit, face_value)
                @suit = suit
                @face_value = face_value
              end

              def get_value
                card_value = [@suit, @face_value]
              end
            end

            class Deck

              def initialize(number_of_decks = 1)
                @deck = create_deck(number_of_decks)
              end

              def draw(number_of_cards = 1)
                drawn_cards = []
                number_of_cards.times do
                  drawn_cards << @deck.pop()
                end
                return drawn_cards
              end

              def size
                @deck.size
              end

              private

              def create_deck(number_of_decks)
                suite = [:Spades, :Clubs, :Hearts, :Diamonds]
                face_value = (2..10).to_a
                face_value << :Jack << :Queen << :King << :Ace

                deck = []

                number_of_decks.times do
                  suite.each do |s|
                    face_value.each do |v|
                      card = Card.new(s, v)
                      deck << card
                    end
                  end
                end

                deck.shuffle!
                return deck
              end
            end

            class Player
              attr_reader :score
              attr_reader :funds
              attr_reader :bet
              attr_reader :hand

              def initialize
                @hand = [];
                @score = 0;
                @bet = 0;
                @funds = 1000;
              end

              def reset
                @hand = [];
                @score = 0;
                @bet = 0;
              end

              def hand(cards)
                @hand += cards
                calculate_score
              end

              def place_bet
                amount = 0
                while true
                  begin
                    amount = Integer(gets)
                    if amount <= @funds && amount > 0
                      @bet += amount
                      @funds -= amount
                      break
                    elsif amount > @funds
                      puts "Sadly, you don't have enough funds to place this bet. Please enter a lower bet."
                    else
                      puts "You cannot place a zero or negative bet."
                    end
                  rescue
                    puts "Please enter a valid whole amount."
                  end
                end
              end

              def update_funds(amount)
                @funds += amount
              end

              def calculate_score
                @score = 0
                ace_in_hand = false

                @hand.each do |h|
                 face_value = h.get_value[1]
                 if face_value.is_a? Integer
                   @score += face_value
                 elsif face_value != :Ace
                   @score += FACEVALUE
                 else
                    # Its an ace so could be 11 or 1?! However, only one ace could be counted as 11 (as 11 + 11 = 22 and would lose). Record if there is an ace in the hand and add one to the score.
                   @score += 1
                   ace_in_hand = true
                 end
                end

                if ace_in_hand
                  if @score + FACEVALUE <= BLACKJACK then @score += FACEVALUE end
                end
              end

              def print_hand
                hand_as_string = ""
                @hand.each do |card|
                  card_value = card.get_value
                  hand_as_string += "#{card_value[0]}, #{card_value[1]} | "
                end
                return hand_as_string
              end
            end

            def determine_winner(player, dealer)

              amount = 0

              if dealer.score > BLACKJACK && player.score > BLACKJACK
                puts "\n**No one wins!**\n"
              elsif player.score < dealer.score && dealer.score <= BLACKJACK || 
                player.score > BLACKJACK
                puts "\n***Dealer wins***\n"
              elsif dealer.score < player.score && player.score <= BLACKJACK ||
                dealer.score > BLACKJACK
                puts "\n****Player wins!****\n"
                # increase funds to player and check for blackjack
                if player.score == BLACKJACK && player.hand.size == 2
                  amount = player.bet + player.bet * 1.5
                else
                  amount = player.bet * 2
                end
              else
                puts "\nIt's a draw!\n"
                # return funds to player
                amount = player.bet
              end

              player.update_funds(amount)

            end

            # define blackjack winning score and value of face card
            BLACKJACK = 21;
            FACEVALUE = 10;
            DEALER_STANDS_AT = 17;

            puts "Welcome to blackjack!"
            puts "You currently have $1000 in funds. Blackjack pays 3:2"
            puts "How many decks should we use? (Integer between 1 and 10)"
            number_of_decks = -1
            while number_of_decks == -1
              begin
                number_of_decks = Integer(gets)
                if number_of_decks <= 0 || number_of_decks > 10
                  number_of_decks = -1
                  puts "The number of decks must be between 1 and 10."
                end
              rescue
                puts "Please enter a valid integer"
              end
            end

            keep_playing = true

            # Create the players and dealer
            player = Player.new
            dealer = Player.new

            while keep_playing

              # Create a new deck
              deck = Deck.new(number_of_decks)
              # Reset the players and dealers score and hand, and the players bet
              player.reset
              dealer.reset

              # Ask player to place bet
              puts "How much would you like to bet?"
              player.place_bet

              # Deal two cards to each player and one card to the dealer
              player.hand(deck.draw(2))
              dealer.hand(deck.draw)

              puts "\nYour current hand is: #{player.print_hand} \nYour score is: #{player.score}\n."

              puts "The dealer's hand is: #{dealer.print_hand}\nThe dealers score is: #{dealer.score}\n"

              # Deal the dealers second card (that is unknown to the player)
              dealer.hand(deck.draw)

              if dealer.score != BLACKJACK    
                # until player is not bust or stands
                until player.score > BLACKJACK do
                  puts "\nDo you want to hit (h) or stand (s)?"
                  players_move = String(gets)

                  case players_move[0].downcase
                  when "s"
                    # stand
                    break
                  when "h"
                    # hit
                    puts "\nYou decided to hit!\n"
                    player.hand(deck.draw)
                    puts "\nYour hand is #{player.print_hand}\nYour score is: #{player.score}."
                  else
                    puts "Unknow input. Please try again.\n"
                  end
                end

                puts "\nYour move has ended, resolving the dealers hand.\n"
                # Resolve the dealers hand (keep drawing cards until bust or >=17 reached)
                while dealer.score <= DEALER_STANDS_AT
                  dealer.hand(deck.draw)
                end

                puts "\nThe dealer's hand is #{dealer.print_hand} \nThe dealers score is: #{dealer.score}"
              end

              # Determine the winner(s) and resolve any ties and settle all the bets
              determine_winner(player, dealer)
              puts "At the end of the game your funds stand at $#{player.funds}."

              # Ask if player wants to play again?
              while true
                puts "Do you want to play again? (Y/N)"
                play_again = String(gets)
                case play_again[0].downcase
                when "y" 
                  break
                when "n"
                  keep_playing = false
                  break
                end
              end
            end
tj63
  • 53
  • 1
  • 5