La Clase Row

Como se ve, hemos delegado en la clase Row la tarea de contar el número de marcas. La clase Row representa a un objeto fila del tablero, incluyendo las diagonales. Sólo tiene dos métodos porque los dema´s los obtiene del módulo SquaresContainer:
  class Board
    class Row
      def initialize( squares, names )
        @squares  = squares
        @names    = names
      end
      
      include SquaresContainer
      
      def to_board_name( index ) 
        Board.index_to_name(@names[index]) 
      end
    end
    .... 
end
El método auxiliar to_board_name recibe un índice de la fila, columna o diagonal que representa el objeto Row (supongamos que por ejemplo @squares = ["X","O"," "], @names = [2, 4, 6] y index = 2 y devuelve la notación jugada ("c2") que define a esa casilla.

En realidad todos los métodos de conteo xs, os, blanks son proveídos por el módulo SquaresContainer:

module TicTacToe
  module SquaresContainer
    def []( index ) @squares[index] end

    def blanks()  @squares.find_all { |s| s == " " }.size end
    def os()      @squares.find_all { |s| s == "O" }.size end
    def xs()      @squares.find_all { |s| s == "X" }.size end
  end
  .... 
end
Este mixin es incluído por Rows para proveer los contadores para las filas, columnas y diagonales. Pero es también incluído/reutilizado por la clase Board para comprobar cuando no hay casillas en blanco y ha habido un empate:
    def won?
      each_row do |row|
        return "X" if row.xs == 3 # "X" wins
        return "O" if row.os == 3 # "O" wins
      end
      return " " if blanks == 0   # Aqui self es el objeto Board.
      false                       # Reutilizamos blanks
    end

Casiano Rodriguez León 2015-01-07