Created
September 2, 2012 23:15
-
-
Save JoshCheek/3605530 to your computer and use it in GitHub Desktop.
Tic Tac Toe - procedural with few abstractions, ~110 loc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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