Skip to content

Instantly share code, notes, and snippets.

@netsprout
Last active December 17, 2015 11:29
Show Gist options
  • Save netsprout/5602696 to your computer and use it in GitHub Desktop.
Save netsprout/5602696 to your computer and use it in GitHub Desktop.
Tic Tac Toe Command Line Game... who needs an iPhone when you can fire up a terminal window :)
# Command Line Tic Tac Toe Game
#
# On the command line:
#
# $ ruby tic_tac_toe.rb
# Class that controlls the game.
#
# Examples
#
# game = Game.new
# game.play
# # => ... Game command line output ...
#
# Returns game play output until winner.
class Game
attr_accessor :turns, :current_player, :moves
def initialize
@players = [Player.new('X'), Player.new('O')]
@current_player = @players.first
@board = Board.new
@player_index = 0
@turns = 0
@moves = []
end
# Public: Plays the game until someone wins
#
# Examples
#
# game = Game.new
# game.play
# # => Prompts user with instructions...
#
# Displays board results as you go
def play
loop do
display_board(@players)
## Is it a valid? (Did they choose an open space) .. if not, start over loop
next unless get_player_coordinates
## Is current player now a winner? If winner, break and announce winner
@turns += 1
if is_winner?
puts "#{@current_player.mark} wins!!! It took a total of #{@turns} turns to complete this game."
break
end
if @board.is_full? @turns
puts "It's a tie!"
break
end
next_player
end
display_board(@players)
end
private
# Private: Prompts the user to enter board space number.
#
# Examples
#
# get_player_coordinates
# # Player Aaron choose your space from 1-9: 1
# # => true
#
# Returns true or false based on validity of space number
def get_player_coordinates
puts "Player #{@current_player.mark} choose your space from 1-9: "
input = gets.strip.to_i
return false if invalid_move? input
@current_player.set_turn(input)
@moves << input
true
end
# Private: Tests to see if the chosen move is valid
#
# move - The Integer number board space
#
# Examples
#
# invalid_move? move
# # Sorry, that is not a valid space.
# # => true
#
# Returns false or true with an output message
def invalid_move? move
if @board.invalid_space? move
puts "Sorry, that is not a valid space."
return true
elsif @moves.include? move
puts "That space has been taken, please try a different space."
return true
end
false
end
# Private: Checks to see if there is a winner on the current board
#
# Examples
#
# is_winner?
# # => true
#
# Returns true or false.
def is_winner?
@board.winning_board? @current_player.moves
end
def display_board(players=[])
player1 = players[0]
player2 = players[1]
if !player1 || !player2
puts "You need 2 players to play."
return false
end
board = @board.display
@players.each do |player|
player.moves.each do |m|
board.gsub!(/[#{m}]/, player.mark)
end
end
puts board
end
def next_player
index = @turns % 2
@current_player = @players[index]
end
end
class Board
attr_accessor :gameboard
GAMEBOARD = <<EOB
1 | 2 | 3
--------------
4 | 5 | 6
--------------
7 | 8 | 9
EOB
SPACES = [1,2,3,4,5,6,7,8,9]
WINNING_SCENARIOS = [
[1,2,3],[4,5,6],[7,8,9], ## Win across
[1,4,7],[2,5,8],[3,6,9], ## Win down
[1,5,9],[3,5,7] ## Win diagonal
]
def initialize
@gameboard = GAMEBOARD
end
def display
@gameboard
end
def is_full? turns
turns >= SPACES.size ? true : false
end
def invalid_space? move
SPACES.include?(move) ? false : true
end
def winning_board? moves
won = false
WINNING_SCENARIOS.each do |s|
won = true if (s & moves).size == s.size
end
won
end
end
class Player
attr_accessor :mark, :moves, :current_move
def initialize(mark)
@mark = mark
@moves = []
end
def set_turn(move)
@moves << move
@current_move = move
end
end
game = Game.new
game.play
@netsprout
Copy link
Author

I think there may be a better way to implement the winner algorithm, but the preset winners works fine for this exercise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment