Last active
December 17, 2015 11:29
-
-
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 :)
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
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think there may be a better way to implement the winner algorithm, but the preset winners works fine for this exercise.