Skip to content

Instantly share code, notes, and snippets.

@whudgins
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save whudgins/afe1c44a3cb0b6af00b5 to your computer and use it in GitHub Desktop.
Save whudgins/afe1c44a3cb0b6af00b5 to your computer and use it in GitHub Desktop.
Tic Tac Toe
#########################################
# A simple Tic-Tac-Toe game in Ruby
# Author: Will Hudgins
#########################################
#### Todos:
# => Abstract out methods, refactor, clean up
# => Clean up AI code: Definitely a more beautiful way to elaborate the strategies
# => Implement something based on this: http://www.neverstopbuilding.com/minimax
@board_position = {"1" => [0,0], "2" => [0,1], "3" => [0,2], "4" => [1,0], "5" => [1,1], "6" => [1,2], "7" => [2,0], "8" => [2,1], "9" => [2,2]}
@move_message = ["Good move.", "Well played, sir or madam.", "Bold strategy Cotton, we'll see how that one plays out for them.", "Bravo.", "Are you sure about that?", "Not what I would have done...", "Well that's certainly one way of going about it."]
@lose_message = ["Baha! You lost to a machine.", "Better luck next time, I guess.", "Is that how it feels to lose? I wouldn't know.", "Amateur.", "Try again... if you dare."]
@win_message = ["What! I never lose. Must be a bug...", "You win. This must be a mistake...", "Game, set, match. Well done", "Well then... Hail to my human overlord.", "Enjoy your victory, it'll be your last."]
@ai_play_message = ["Here goes nothing.", "Prepare for domination.", "Feast your eyes upon this beauty.", "Well then, here's my move."]
def start_game
board = [[" "," "," "],[" "," "," "],[" "," "," "]]
print_board(board)
puts "Welcome to Tic-Tac-Toe!"
return board
end
def play_game(board)
if check_winning_board(board)
puts @lose_message.sample
return
end
if !check_winning_board(board) and !board_full(board)
print "Make a move by entering a position on the board 1-9: "
move = gets.chomp
board = do_turn(move.to_i, board)
if board_full(board)
return
end
board = make_AI_move(board, move.to_i)
print_board(board)
puts @move_message.sample
puts @ai_play_message.sample
play_game(board)
end
end
def do_turn(move, board)
# error catching
if move < 1 or move > 9
puts "You've made an invalid move. Try again!"
play_game(board)
end
x_spots = get_spots(board, "X")
o_spots = get_spots(board, "O")
if x_spots.include?(move.to_s) or o_spots.include?(move.to_s)
puts "You've made an invalid move. Try again!"
play_game(board)
end
position = get_board_position(move)
board = place_move(position, board, "X")
if check_winning_board(board)
puts @win_message.sample
end
if board_full(board)
print_board(board)
puts "Game over. Until we meet again."
end
return board
end
def make_AI_move(board, move)
puts
puts @ai_play_message.sample
ai_move = get_optimal_move(board)
position = get_board_position(ai_move)
board = place_move(position, board, "O")
return board
end
def get_spots(board, char)
spots = []
i = 0
while i < 3
j = 0
while j < 3
if board[i][j] == char.to_s
spots.push(@board_position.key([i,j]))
end
j += 1
end
i += 1
end
return spots
end
def place_move(position, board, char)
x = position[0]
y = position[1]
board[x][y] = char.to_s
return board
end
def get_board_position(move)
position = @board_position[move.to_s]
return position
end
def print_board(board)
system "clear"
print board[0]
puts
print board[1]
puts
print board[2]
puts
puts
end
def blank_board(board)
empty_spots = get_spots(board, " ")
return empty_spots == ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
end
def board_full(board)
empty_spots = get_spots(board, " ")
if empty_spots.any?
return false
end
return true
end
def check_winning_board(board)
if !blank_board(board)
if check_horizontal_win(board)
return true
elsif check_vertical_win(board)
return true
elsif check_diagonal_win(board)
return true
end
end
return false
end
def check_diagonal_win(board)
x_spots = get_spots(board, "X")
o_spots = get_spots(board, "O")
if x_spots.include?("1") and x_spots.include?("5") and x_spots.include?("9")
return true
elsif x_spots.include?("3") and x_spots.include?("5") and x_spots.include?("7")
return true
end
if o_spots.include?("1") and o_spots.include?("5") and o_spots.include?("9")
return true
elsif o_spots.include?("3") and o_spots.include?("5") and o_spots.include?("7")
return true
end
return false
end
def check_horizontal_win(board)
i = 0
while i < 3
if board[i][0] != " " and board[i][0] == board[i][1] and board[i][1] == board[i][2]
return true
end
i += 1
end
return false
end
def check_vertical_win(board)
i = 0
while i < 3
if board[0][i] != " " and board[0][i] == board[1][i] and board[1][i] == board[2][i]
return true
end
i += 1
end
return false
end
def get_optimal_move(board)
empty_spots = get_spots(board, " ")
x_spots = get_spots(board, "X")
o_spots = get_spots(board, "O")
defensive_move = search_move(x_spots, empty_spots)
if defensive_move != nil
return defensive_move
end
offensive_move = search_move(o_spots, empty_spots)
if offensive_move != nil
return offensive_move
end
# best move in the game. if its open, take it!
if empty_spots.include?("5")
return "5"
# none met. pick a random empty spot.
else
ai_move = empty_spots.sample
return ai_move
end
end
def search_move(spots, empty_spots)
# clean this up!
# all the horizontal cases.
if spots.include?("1") and spots.include?("2") and empty_spots.include?("3")
return "3"
elsif spots.include?("1") and spots.include?("3") and empty_spots.include?("2")
return "2"
elsif spots.include?("2") and spots.include?("3") and empty_spots.include?("1")
return "1"
elsif spots.include?("4") and spots.include?("5") and empty_spots.include?("6")
return "6"
elsif spots.include?("4") and spots.include?("6") and empty_spots.include?("5")
return "5"
elsif spots.include?("5") and spots.include?("6") and empty_spots.include?("4")
return "4"
elsif spots.include?("7") and spots.include?("8") and empty_spots.include?("9")
return "9"
elsif spots.include?("7") and spots.include?("9") and empty_spots.include?("8")
return "8"
elsif spots.include?("8") and spots.include?("9") and empty_spots.include?("7")
return "7"
# vertical cases
elsif spots.include?("1") and spots.include?("4") and empty_spots.include?("7")
return "7"
elsif spots.include?("1") and spots.include?("7") and empty_spots.include?("4")
return "4"
elsif spots.include?("4") and spots.include?("7") and empty_spots.include?("1")
return "1"
elsif spots.include?("2") and spots.include?("5") and empty_spots.include?("8")
return "8"
elsif spots.include?("2") and spots.include?("8") and empty_spots.include?("5")
return "5"
elsif spots.include?("5") and spots.include?("8") and empty_spots.include?("2")
return "2"
elsif spots.include?("3") and spots.include?("6") and empty_spots.include?("9")
return "9"
elsif spots.include?("3") and spots.include?("9") and empty_spots.include?("6")
return "6"
elsif spots.include?("6") and spots.include?("9") and empty_spots.include?("3")
return "3"
# diagonal cases
elsif spots.include?("1") and spots.include?("5") and empty_spots.include?("9")
return "9"
elsif spots.include?("9") and spots.include?("5") and empty_spots.include?("1")
return "1"
elsif spots.include?("3") and spots.include?("5") and empty_spots.include?("7")
return "7"
elsif spots.include?("7") and spots.include?("5") and empty_spots.include?("3")
return "3"
end
end
play_game(start_game)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment