Here's my first shot at implementing Tic Tac Toe in Ruby. After watching Gary Bernhardt's Functional Core, Imperative Shell, I thought this would be a great exercise in trying out the ideology presented in that screencast. Tear my code apart.
Link to GitHub repo (includes video of usage)
tic_tac_toe.rb -- the procedural shell
require_relative "board"
require_relative "cell"
require "pry"
def initialize_board
@board = Board.new
end
def choose_characters
puts "X or O?"
@player_character = gets.chomp
@computer_character = case @player_character
when "X" then "O"
when "O" then "X"
end
end
def start_game
initialize_board
choose_characters
play
end
def play
loop do
puts "Make a move: "
move = gets.chomp
board_index = Board::POSITIONS[move]
winner = @player_character
@board.board[board_index].value = @player_character
if [email protected]?
@board.available_cells.sample.value = @computer_character
winner = @computer_character if @board.winner?
end
if @board.winner?
p "#{winner.upcase} WINS!!!"
@board.display
puts "Do you want to play again?"
start_game if gets.chomp == "Yes"
else
@board.display
play
end
break if @board.winner?
end
end
start_game
board.rb
class Board
attr_accessor :board
WINNING_COMBINATIONS = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
]
POSITIONS = {
"top left" => 0,
"top middle" => 1,
"top right" => 2,
"middle left" => 3,
"center" => 4,
"middle right" => 5,
"bottom left" => 6,
"bottom middle" => 7,
"bottom right" => 8
}
def initialize
@board = Array.new(9) { Cell.new }
end
def winner?
winner = false
WINNING_COMBINATIONS.each do |combination|
first_cell = board[combination[0]].value
second_cell = board[combination[1]].value
third_cell = board[combination[2]].value
consideration = [first_cell, second_cell, third_cell]
if consideration.uniq.length == 1 && first_cell.is_a?(String)
winner = true
end
end
winner
end
def available_cells
board.select { |cell| cell.value == :blank }
end
def display
rows = board.each_slice(3).to_a
rows.each do |row|
p row.map(&:value)
end
end
end
cell.rb
class Cell
attr_accessor :value
def initialize(options = {})
@value = options.fetch(:value, :blank)
end
end