Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created September 2, 2012 23:15
Show Gist options
  • Save JoshCheek/3605530 to your computer and use it in GitHub Desktop.
Save JoshCheek/3605530 to your computer and use it in GitHub Desktop.
Tic Tac Toe - procedural with few abstractions, ~110 loc
UNMARKED = ' '
def board_to_s board
board.each_slice(3).map { |a, b, c| " #{a} | #{b} | #{c} " }.join("\n---|---|---\n")
end
def display board, after_board = nil
puts board_to_s board
puts after_board if after_board
end
def display_buffer
puts
end
def valid_move?(board, input)
return false unless input.to_i.to_s == input.chomp
available_moves(board).include? input.to_i
end
def get_move(board)
print "move> "
move = gets
return move.to_i if valid_move? board, move
get_move board
end
def human_turn board, marker, opponent_marker
display board
board[get_move board] = marker
display_buffer
end
def temporary_move board, marker, move
board[move] = marker
return yield
ensure
board[move] = UNMARKED
end
# it must be opponent_marker's turn on board
def rate board, marker, opponent_marker
if game_over? board
return 1 if winner(board) == marker
return -1 if winner(board) == opponent_marker
return 0
end
opponent_move = find_best_move board, opponent_marker, marker
temporary_move board, opponent_marker, opponent_move do
-1 * rate(board, opponent_marker, marker)
end
end
def find_best_move board, marker, opponent_marker
available_moves(board).sort_by { |potential_move|
temporary_move(board, marker, potential_move) { rate board, marker, opponent_marker }
}.last
end
def computer_turn board, marker, opponent_marker
if board.all? { |player| player == UNMARKED }
board[0] = marker # optimize first move
else
board[find_best_move board, marker, opponent_marker] = marker
end
end
def available_moves board
board.each_index.select { |index| board[index] == UNMARKED }.shuffle
end
def winning_positions
[ [0,1,2], [3,4,5], [6,7,8], # horizontal
[0,3,6], [1,4,7], [2,5,8], # vertical
[0,4,8], [2,4,6], ] # diagonal
end
def winner board
positions = winning_positions.find do |a, b, c|
board[a] != UNMARKED && board[a] == board[b] && board[a] == board[c]
end
positions && board[positions.first]
end
def game_over? board
available_moves(board).empty? || winner(board)
end
def prompt_player_type n
print "Player#{n} (h)uman or (c)omputer? "
gets.chomp == 'h' ? method(:human_turn) : method(:computer_turn)
end
board, player1_turn, player2_turn = [UNMARKED]*9, prompt_player_type(1), prompt_player_type(2)
both_computers = (player1_turn == player1_turn && player1_turn == method(:computer_turn))
loop do
break if game_over? board
player1_turn[board, 'X', 'O']
display board, "\n" if both_computers
break if game_over? board
player2_turn[board, 'O', 'X']
display board, "\n" if both_computers
end
puts (marker = winner(board)) ? "#{marker} won the game" : "Game over, no winner"
display board
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment