Skip to content

Instantly share code, notes, and snippets.

@thebugcatcher
Created January 9, 2024 23:14
Show Gist options
  • Save thebugcatcher/ef94e3803021f7295e5cb58df604d45c to your computer and use it in GitHub Desktop.
Save thebugcatcher/ef94e3803021f7295e5cb58df604d45c to your computer and use it in GitHub Desktop.
Tic Tac Toe Terminal Game in Ruby (mentorship)
class Board
# Grid is 2D array
attr_accessor :grid
X_VALUE = "x"
O_VALUE = "o"
EMPTY_VALUE = " "
def initialize(board_dimension)
grid = []
bound = board_dimension - 1
(0..bound).each do |row|
grid[row] = []
(0..bound).each do |col|
grid[row][col] = EMPTY_VALUE
end
end
@grid = grid
end
def add_to_grid(row, col, value)
grid[row - 1][col - 1] = value
end
def display
str = "-------------\n"
grid.each do |row|
str += "| "
row.each do |value|
str += value
str += " | "
end
str += "\n"
str += "-------------\n"
end
str
end
end
class User
attr_accessor :name
def initialize(name)
@name = name
end
end
class Game
attr_accessor :user_1, :user_2, :board, :current_turn, :turns
def initialize(user_1, user_2, board_dimension)
@user_1 = user_1
@user_2 = user_2
@board = Board.new(board_dimension)
@current_turn = [user_1, user_2].sample()
@turns = []
end
def add_turn(row, col)
if board.grid[row - 1][col - 1] == Board::EMPTY_VALUE
value = value_from_user(current_turn)
board.add_to_grid(row, col, value)
update_current_turn
else
raise "Bad user input"
end
end
def display
<<~HEREDOC
X: #{user_1.name} O: #{user_2.name}
Current Turn: #{current_turn.name}
#{board.display}
HEREDOC
end
private
def value_from_user(user)
if user.name == user_1.name
Board::X_VALUE
elsif user.name == user_2.name
Board::O_VALUE
else
raise "Bad user input"
end
end
def update_current_turn
if current_turn.name == user_1.name
@current_turn = user_2
elsif current_turn.name == user_2.name
@current_turn = user_1
else
raise "Bad user"
end
end
end
module GameRunner
def self.call(game)
puts game.display
puts "____\n\n"
puts "#{game.current_turn.name} input: "
row, col = gets.chomp.split(",").map(&:to_i)
game.add_turn(row, col)
check_state(game)
puts `clear`
call(game)
end
def self.check_state(game)
x_wins = winning_criteria(game.board.grid, Board::X_VALUE)
o_wins = winning_criteria(game.board.grid, Board::O_VALUE)
if x_wins && o_wins
raise "Error"
elsif x_wins
puts `clear`
puts game.display
puts "Winner #{game.user_1.name}!"
exit
elsif o_wins
puts `clear`
puts game.display
puts "Winner #{game.user_2.name}!"
exit
elsif check_draw(game.board.grid)
puts `clear`
puts game.display
puts "Draw!"
exit
end
end
def self.winning_criteria(grid, value)
winning_criteria_row(grid, value) ||
winning_criteria_col(grid, value) ||
winning_criteria_diag_1(grid, value) ||
winning_criteria_diag_2(grid, value)
end
def self.winning_criteria_row(grid, value)
grid.any? do |row|
row.all? { |cell| cell == value }
end
end
def self.winning_criteria_col(grid, value)
dimension = grid.size - 1
(0..dimension).any? do |index|
grid.all? do |row|
row[index] == value
end
end
end
def self.winning_criteria_diag_1(grid, value)
index = 0
grid.all? do |row|
result = row[index] == value
index += 1
result
end
end
def self.winning_criteria_diag_2(grid, value)
index = grid.size - 1
grid.all? do |row|
result = row[index] == value
index -= 1
result
end
end
def self.check_draw(grid)
grid.all? do |row|
row.all? do |cell|
cell != Board::EMPTY_VALUE
end
end
end
private_class_method :check_state,
:winning_criteria,
:winning_criteria_row,
:winning_criteria_col,
:winning_criteria_diag_1,
:winning_criteria_diag_2
end
user_1 = User.new("User 1")
user_2 = User.new("User 2")
game = Game.new(user_1, user_2, 3)
puts `clear`
GameRunner.call(game)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment