Skip to content

Instantly share code, notes, and snippets.

@gdakram
Created February 2, 2011 16:54
Show Gist options
  • Save gdakram/807979 to your computer and use it in GitHub Desktop.
Save gdakram/807979 to your computer and use it in GitHub Desktop.
The game in ruby via cli. Have fun.
# the anatomy of a slot
Slot = Struct.new(:row, :column, :value)
# The board has n x n slots
class Board
# Constants
X = "X"
O = "O"
# attr accessor
attr_accessor :grid, :slots, :game_over, :current_player, :winner
# constructor
def initialize(n)
# initialize the instance variables
@grid, @slots = Array.new(n), Hash.new
@game_over, @current_player, @winner = false, Board::X, nil
# build the board
slot_counter = 0
@grid.each_with_index do |row, i|
@grid[i] = Array.new(n)
@grid[i].each_with_index do |column, j|
@grid[i][j] = Slot.new(i, j, slot_counter)
@slots[slot_counter] = @grid[i][j]
slot_counter += 1
end
end
end
def draw
system("clear")
@grid.each_with_index do |row, i|
row_print = row.collect{ |s| s.value }.join(" | ")
puts row_print
puts "-" * row_print.length if @grid.length != (i + 1)
end
puts ""
end
def move
print "#{@current_player} -- Please enter a number from the board: "
slot_number = gets.chomp.to_i
if [email protected]_key?(slot_number)
move
elsif @slots[slot_number].value == Board::X || @slots[slot_number].value == Board::O
puts "Please enter a number that is not already marked!"
move
else
@board_updated = true
@slots[slot_number].value = @current_player
end
# post-move analysis.
if won?(@slots[slot_number])
@game_over = true
@winner = @current_player
elsif stalemate?
@game_over = true
else
switch_turn if @board_updated
end
end
def switch_turn
@current_player = (@current_player == Board::X) ? Board::O : Board::X
@board_updated = false
end
def won?(slot)
horizontal_win?(slot) ||
vertical_win?(slot) ||
diagonal_win?(:orientation => "l2r") ||
diagonal_win?(:orientation => "r2l")
end
def stalemate?
stalemate = true
@slots.each { |k,slot| stalemate = false if slot.value.is_a?(Fixnum) }
stalemate
end
def game_over?
@game_over
end
private
def horizontal_win?(slot)
slot_values = @grid[slot.row].collect{ |s| s.value == @current_player }
slot_values.length == @grid.length && slot_values.uniq.to_s == "true"
end
def vertical_win?(slot)
slot_values = @grid.collect{ |r| r[slot.column] }.collect { |s| s.value == @current_player }
slot_values.length == @grid.length && slot_values.uniq.to_s == "true"
end
def diagonal_win?(options = {})
slots = []
case options[:orientation]
when "l2r" then 0.upto(@grid.length - 1) { |i| slots << @grid[i][i] }
when "r2l" then (@grid.length - 1).downto(0) { |i| slots << @grid[i][@grid.length - 1 - i] }
end
slot_values = slots.collect { |s| s.value == @current_player }
slots.length == @grid.length && slot_values.uniq.to_s == "true"
end
end
# new game
board = Board.new(3)
while !board.game_over? do
board.draw
board.move
end
board.draw
# result
puts !board.winner.nil? ? "#{board.winner} won the game!" : "The game was a draw!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment