Skip to content
Permalink
Browse files

Break down procedure into several helper functions.

At this point, reading Game#play is much more revealing than before, and the
general structure of the application has improved.  It is possible to try out
some of these features in isolation and is now easier to do manual testing.  But
this is still essentially procedural code in an object oriented technicolor
dream coat.

Automated testing would be tedious as-is because of the mixture of presentation
/ control code and logic.  A re-design of the code is in order, replacing the
many procedures that operate on data such as the board with single purpose
objects.  That's what we'll start on next.
  • Loading branch information...
practicingruby committed Dec 3, 2010
1 parent 2579626 commit 286724de5328fda779caa500ccc76a0ad5de2bd7
Showing with 65 additions and 39 deletions.
  1. +65 −39 lib/tictactoe/game.rb
@@ -1,6 +1,5 @@
module TicTacToe
class Game

def initialize
@board = [[nil,nil,nil],
[nil,nil,nil],
@@ -9,59 +8,86 @@ def initialize
@players = [:X, :O].cycle
end

attr_reader :board, :players
attr_reader :board, :players, :current_player

def play
left_diagonal = [[0,0],[1,1],[2,2]]
right_diagonal = [[2,0],[1,1],[0,2]]

current_player = players.next
start_new_turn

loop do
puts board.map { |row| row.map { |e| e || " " }.join("|") }.join("\n")
print "\n>> "
row, col = gets.split.map { |e| e.to_i }
puts

begin
cell_contents = board.fetch(row).fetch(col)
rescue IndexError
puts "Out of bounds, try another position"
next
end

if cell_contents
puts "Cell occupied, try another position"
next
end
display_board

row, col = move_input
next unless valid_move?(row,col)

board[row][col] = current_player

lines = []
if winning_move?(row, col)
puts "#{current_player} wins!"
return
end

[left_diagonal, right_diagonal].each do |line|
lines << line if line.include?([row,col])
if draw?
puts "It's a draw!"
return
end

lines << (0..2).map { |c1| [row, c1] }
lines << (0..2).map { |r1| [r1, col] }
start_new_turn
end
end

win = lines.any? do |line|
line.all? { |row,col| board[row][col] == current_player }
end
def start_new_turn
@current_player = @players.next
end

if win
puts "#{current_player} wins!"
exit
end
def display_board
puts board.map { |row| row.map { |e| e || " " }.join("|") }.join("\n")
end

if board.flatten.compact.length == 9
puts "It's a draw!"
exit
end
def winning_move?(row, col)
left_diagonal = [[0,0],[1,1],[2,2]]
right_diagonal = [[2,0],[1,1],[0,2]]

lines = []

[left_diagonal, right_diagonal].each do |line|
lines << line if line.include?([row,col])
end

lines << (0..2).map { |c1| [row, c1] }
lines << (0..2).map { |r1| [r1, col] }

lines.any? do |line|
line.all? { |row,col| board[row][col] == current_player }
end
end

def draw?
board.flatten.compact.length == 9
end

current_player = players.next
def valid_move?(row,col)
begin
cell_contents = board.fetch(row).fetch(col)
rescue IndexError
puts "Out of bounds, try another position"
return false
end

if cell_contents
puts "Cell occupied, try another position"
return false
end

true
end

def move_input
print "\n>> "
row, col = gets.split.map { |e| e.to_i }
puts

[row, col]
end

end
end

0 comments on commit 286724d

Please sign in to comment.
You can’t perform that action at this time.