Monthly Archives: December 2015

Black jack OOP

Another basic OOP ruby program, this time twenty-one or blackjack.  Come try it out on your console!

class Card
FACES = (2..10).to_a + [‘J’, ‘Q’, ‘K’, ‘A’]
SUITS = [‘H’, ‘D’, ‘S’, ‘C’]

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

def to_s
“The #{face} of #{suit}”
end

def face
case @face
when ‘J’ then ‘Jack’
when ‘Q’ then ‘Queen’
when ‘K’ then ‘King’
when ‘A’ then ‘Ace’
else
@face
end
end

def suit
case @suit
when ‘H’ then ‘Hearts’
when ‘D’ then ‘Diamonds’
when ‘S’ then ‘Spades’
when ‘C’ then ‘Clubs’
end
end

def ace?
face == ‘Ace’
end

def king?
face == ‘King’
end

def queen?
face == ‘Queen’
end

def jack?
face == ‘Jack’
end
end

class Deck
attr_accessor :cards

def initialize
@cards = []
Card::SUITS.each do |suit|
Card::FACES.each do |face|
@cards << Card.new(suit, face)
end
end
scramble!
end

def scramble!
cards.shuffle!
end

def deal_one
cards.pop
end
end

module Hand
def show_hand
puts “—-#{name}’s Hand —-”
cards.each do |card|
puts “=> #{card}”
end
puts “=> Total: #{total}”
puts “”
end

def total
total = 0
cards.each do |card|
if card.ace?
total += 11
elsif card.jack? || card.queen? || card.king?
total += 10
else
total += card.face.to_i
end
end

# correct for aces
cards.select(&:ace?).count.times do
break if total <= 21
total -= 10
end
total
end

def add_card(new_card)
cards << new_card
end

def busted?
total > 21
end
end

class Participant
include Hand

attr_accessor :name, :cards
def initialize
@cards = []
set_name
end
end

class Player < Participant
def set_name
name = ”
loop do
puts “What’s your name?”
name = gets.chomp
break unless name.empty?
puts “Sorry, must enter a value.”
end
self.name = name
end

def show_flop
show_hand
end
end

class Dealer < Participant
ROBOTS = [‘R2D2’, ‘Hal’, ‘Chappie’, ‘Sonny’, ‘Number 5’]

def set_name
self.name = ROBOTS.sample
end

def show_flop
puts “—- #{name}’s Hand —-”
puts “#{cards.first}”
puts ” ?? ”
puts “”
end
end

class TwentyOne
attr_accessor :deck, :player, :dealer

def initialize
@deck = Deck.new
@player = Player.new
@dealer = Dealer.new
end

def reset
self.deck = Deck.new
player.cards = []
dealer.cards = []
end

def deal_cards
2.times do
player.add_card(deck.deal_one)
dealer.add_card(deck.deal_one)
end
end

def show_flop
player.show_flop
dealer.show_flop
end

def player_turn
puts “#{player.name}’s turn…”

loop do
puts “Would you like to (h)it or (s)tay?”
answer = nil
loop do
answer = gets.chomp.downcase
break if [‘h’, ‘s’].include?(answer)
puts “Sorry, must enter ‘h’ or ‘s’.”
end

if answer == ‘s’
puts “#{player.name} stays!”
break
elsif player.busted?
break
else
# show update for hit
player.add_card(deck.deal_one)
puts “#{player.name} hits!”
player.show_hand
break if player.busted?
end
end
end

def dealer_turn
puts “#{dealer.name}’s turn…”

loop do
if dealer.total >= 17 && !dealer.busted?
puts “#{dealer.name} stays!”
break
elsif dealer.busted?
break
else
puts “#{dealer.name} hits!”
dealer.add_card(deck.deal_one)
end
end
end

def show_busted
if player.busted?
puts “It looks like #{player.name} busted! #{dealer.name} wins!”
elsif dealer.busted?
puts “It looks like #{dealer.name} busted! #{player.name} wins!”
end
end

def show_cards
player.show_hand
dealer.show_hand
end

def show_result
if player.total > dealer.total
puts “It looks like #{player.name} wins!”
elsif player.total < dealer.total
puts “It looks like #{dealer.name} wins!”
else
puts “It’s a tie!”
end
end

def play_again?
answer = nil
loop do
puts “Would you like to play again? (y/n)”
answer = gets.chomp.downcase
break if [‘y’, ‘n’].include? answer
puts “Sorry, must be y or n.”
end

answer == ‘y’
end

def start
loop do
system ‘clear’
deal_cards
show_flop

player_turn
if player.busted?
show_busted
if play_again?
reset
next
else
break
end
end

dealer_turn
if dealer.busted?
show_busted
if play_again?
reset
next
else
break
end
end

# both stayed
show_cards
show_result
play_again? ? reset : break
end

puts “Thank you for playing Twenty-One. Goodbye!”
end
end

game = TwentyOne.new
game.start

An object oriented tictactoe game

Just doing a basic Ruby tictactoe game using some basic oop.  Feel free to copy and paste this code and give it a go.

# tic tac is a 2 player board game played on 3 x 3 grid.
# players take turns marking a square, the 1st player to mark 3 in a row
# wins.

# Nouns: player, board, square, grid
# Verbs: play, mark

# board
# square
# player
# – mark
# – play
require ‘pry’

class Board
attr_accessor :board, :squares, :marker
WINNING_LINES = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +
[[1, 4, 7], [2, 5, 8], [3, 6, 9]] +
[[1, 5, 9], [3, 5, 7]]

def initialize
@squares = {}
reset
end

def reset
(1..9).each { |key| @squares[key] = Square.new }
end

def get_square_at(key)
@squares[key]
end

def set_square_at(key, marker)
@squares[key].marker = marker
end

def []=(num, marker)
@squares[num].marker = marker
end

def unmarked_keys
@squares.keys.select { |key| @squares[key].unmarked? }
end

def marked_keys
@squares.keys.select { |key| @squares[key].marked? }
end

def full?
unmarked_keys.empty?
end

def someone_won?
!!winning_marker
end

def count_human_marker(squares)
squares.collect(&:marker).count(TTTGame::HUMAN_MARKER)
end

def count_computer_marker(squares)
squares.collect(&:marker).count(TTTGame::COMPUTER_MARKER)
end

def three_identical_markers?(squares)
markers = squares.select(&:marked?).collect(&:marker)
return false if markers.size != 3
markers.min == markers.max
end

def winning_marker
WINNING_LINES.each do |line|
squares = @squares.values_at(*line)
if three_identical_markers?(squares)
return squares.first.marker
end
end
nil
end

# rubocop:disable Metrics/AbcSize
def draw
puts “”
puts ” | |”
puts ” #{@squares[1]} | #{@squares[2]} | #{@squares[3]}”
puts ” | |”
puts “—–+—–+—–”
puts ” | |”
puts ” #{@squares[4]} | #{@squares[5]} | #{@squares[6]}”
puts ” | |”
puts “—–+—–+—–”
puts ” | |”
puts ” #{@squares[7]} | #{@squares[8]} | #{@squares[9]}”
puts ” | |”
end
end

class Square
attr_accessor :marker
INITIAL_VALUE = ‘ ‘

def initialize(marker=INITIAL_VALUE)
@marker = marker
end

def to_s
@marker
end

def unmarked?
marker == INITIAL_VALUE
end

def marked?
marker != INITIAL_VALUE
end
end

class Player
attr_accessor :marker, :player_win_count, :computer_win_count

def initialize(marker)
@marker = marker
@player_win_count = 0
@computer_win_count = 0
end
end

class TTTGame
HUMAN_MARKER = “X”
COMPUTER_MARKER = “O”
FIRST_TO_MOVE = HUMAN_MARKER

attr_reader :board, :human, :computer

def initialize
@board = Board.new
@human = Player.new(HUMAN_MARKER)
@computer = Player.new(COMPUTER_MARKER)
@current_marker = FIRST_TO_MOVE
end

def game_winner_found
if human.player_win_count == 5
puts “Congrats, you won against the machine!”
elsif computer.computer_win_count == 5
puts “Skynet wins.”
end
end

def play
clear
display_welcome_message

loop do
display_board

loop do
current_player_moves
break if board.someone_won? || board.full?
clear_screen_and_display_board
end
display_result
break if game_winner_found
break unless play_again?
reset
display_play_again_message
end

display_goodbye_message
end

private

def display_welcome_message
puts “Welcome to tic tac toe!”
puts “”
end

def display_goodbye_message
puts “Thanks for playing Tic tac toe! Goodbye!”
end

def clear
system ‘clear’
end

def clear_screen_and_display_board
clear
display_board
end

def display_board
puts “You’re a #{human.marker}. Computer is a #{computer.marker}”
puts “”
board.draw
puts “”
end

def joinor(arr, delimiter, word = “or”)
arr[-1] = “#{word} #{arr.last}” if arr.size > 1
arr.join(delimiter)
end

def human_moves
puts “Choose a square (#{joinor(board.unmarked_keys, ‘, ‘)}):”
square = nil
loop do
square = gets.chomp.to_i
break if board.unmarked_keys.include?(square)
puts “Sorry, that’s not a valid choice.”
end
board.[]=(square, HUMAN_MARKER)
end

def defense(line)
if board.squares.values_at(*line).join(‘, ‘).count(‘X’) == 2
board.squares.select{ |k,v| line.include?(k) && v.marker == ‘ ‘ }.keys.first
else
nil
end
end

def offense(line)
if board.squares.values_at(*line).join(‘, ‘).count(‘O’) == 2
board.squares.select{ |k,v| line.include?(k) && v.marker == ‘ ‘ }.keys.first
else
nil
end
end

def computer_moves
square = false

# defense
Board::WINNING_LINES.each do |line|
square = defense(line)
break if square
end

# offense
# if !square
# Board::WINNING_LINES.each do |line|
# square = offense(line)
# break if square
# end
# end

if !square
# square = board.[]=(board.unmarked_keys.sample, COMPUTER_MARKER)
square = board.unmarked_keys.sample
end

# board.squares[square].marker = COMPUTER_MARKER
board.[]=(square, COMPUTER_MARKER)
end

def current_player_moves
if @current_marker == HUMAN_MARKER
human_moves
@current_marker = COMPUTER_MARKER
else
computer_moves
@current_marker = HUMAN_MARKER
end
end

def reset
board.reset
@current_marker = FIRST_TO_MOVE
clear
end

def display_result
binding.pry
clear_screen_and_display_board
case board.winning_marker
when human.marker
puts “You won!”
human.player_win_count += 1
when computer.marker
puts “Computer won!”
computer.computer_win_count += 1
else
puts “It’s a tie”
end
end

def play_again?
answer = ”
loop do
puts “Would you like to play again? (y/n)”
answer = gets.chomp.downcase
break if %w(y n).include? answer
puts “Sorry, must be y or n”
end

answer == ‘y’
end

def display_play_again_message
puts “Let’s play again!”
puts “”
end
end

game = TTTGame.new
game.play