[QUIZ] Tiling Turmoil (#33)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Greg Brown

This weeks quiz is based off of a mathematical proof we were taught in my
discrete mathematics class a few weeks ago. Though I can already hear some of
you running for the hills at the mention of the four letter word that is math, I
can assure you that this is more of a thinking problem than it is number
crunching. The basic idea is pretty simple.

You're going to tile L-trominos on a 2**n by 2**n board that is missing a single
square. What's an L-tromino? It's simply a 2 by 2 square with a corner missing
that looks like an L.

For further clarification, this is what they look like:

  #
  # #

Well, I guess it's time to stop being vague and give you the problem definition.

For any 2**n by 2**n board with a single square missing in a random location,
you must write a program that will tile L-trominos in such a way that the grid
is completely filled in.

Your program should take the value for n as the input, and somehow display the
board with the trominos properly laid out as the output. It should place the
missing square at random each time the board is generated. (Otherwise this would
be too easy!)

For example, the empty board of n = 2 would be something like this:

  _ _ _ _
  _ _ X _
  _ _ _ _
  _ _ _ _

The solution for that might look like:

  1 1 2 2
  1 5 X 2
  3 5 5 4
  3 3 4 4

As you can see, all squares are completely filled with the exception of the
empty square which was randomly placed.

It may look simple on a 4 by 4 board, but once you get up to a 128 by 128 or
even 4096 by 4096, it becomes more and more obvious that guess and check is just
not going to work.

The level of difficulty of this problem depends entirely on how much you already
know about it. If you want an easy ride, look for the proof and just implement
it.

If you want more of a challenge, avoid Googling the topic and try to find clever
ways to actually show how your program solves the problem.

Hope you have fun with this quiz, and if you write a really good one, you can
help me tile my bathroom floor next week as a prize. :slight_smile:

For any 2**n by 2**n board with a single square missing in a random location,
you must write a program that will tile L-trominos in such a way that the grid
is completely filled in.

Your program should take the value for n as the input, and somehow display the
board with the trominos properly laid out as the output. It should place the
missing square at random each time the board is generated. (Otherwise this would
be too easy!)

[snip]

The level of difficulty of this problem depends entirely on how much you already
know about it. If you want an easy ride, look for the proof and just implement
it.

Yeah. I knew the problem, I didn't need google.

So I decided to
- generate* all (sub)tiles and
- have only that part of the board in memory that needs to be printed
   (quadtree into details for current line, by using the Ruby stack;
   If anyone knows how to keep less administration, let me know :slight_smile:

Hope you have fun with this quiz, and if you write a really good one, you can
help me tile my bathroom floor next week as a prize. :slight_smile:

Not a chance :slight_smile:

Besides I fear my code is more cryptic than it could be.

Bye,
Kero.

+--- Kero ------------------------- kero@chello@nl ---+

all the meaningless and empty words I spoke |
                      Promises -- The Cranberries |

+--- M38c --- http://members.chello.nl/k.vangelder ---+

# 1) There is no regular coverage of trominos over a 2**n square board (3 does
# not divide 2**n)
# 2) however, tromino's can cover 3/4 of such a board. the factor three has
# been introduced. Which three quarters? Let me show you:

···

#
# +---+ Which in itself is a tromino-shaped area, but twice as big.
# | | You can't miss the factor 2 which also appears in 2**n, so
# | +-+ this basically gives the algorithm for the solution away.
# | | |
# +-+ +-+-+ 3) We shall display the board. I'm going to try to use the
# | | | | recursion efficiently and not keep the entire board in
# | +---+ | memory.
# | | |
# +---+---+ 4) Line-by-line we see one or two squares of a tromino that we
# must know. Three squares, four orientations, twelve ids.

# F T L J, clockwise numbered :F1 :F2 :F3 etc
# We would have, from the above shape
# :L => [
# [ :F2, :F3, 0, 0 ],
# [ :F1, :L3, 0, 0 ],
# [ :L3, :L2, :L1, :J1 ],
# [ :L2, :L1, :J3, :J2 ]
# ],
# but that's not recursive, so we get (clockwise):
# :L1 => [:L1, :J1, :J2, :J3],
# :L2 => [:L3, :L2, :L1, :L2],
# :L3 => [:F2, :F3, :L3, :F1],
# We're lazy (and we hate typos) so we'll generate this

class Array
  # shift element and append it again, name from CPU registers
  def rotate!()
    push(shift)
  end
  # substitute first occurrence of +orig+
  def sub(orig, replace)
    result = dup
    result[index(orig)] = replace
    result
  end
end

Trominos = [ :J0, :T0, :F0, :L0 ] # rotating J counterclockwise gives T, F, L
Sub = {}

# Set tromino in 2x2 square, clockwise, using :X0 as 'empty'
# With only these set, the script already works for n==1 :slight_smile:
a = (0..3).to_a # clockwise numbering of :J, 0 being 'empty' (excluded square)
Trominos.each { |sym|
  str = (0..3).collect { |i| ":#{sym}#{a[i]}".sub(/0/, "") }.join(", ")
  Sub[sym] = eval("[#{str}]")
  a.rotate! # rotate counterclockwise
}

# For all 12 possibilities, set subsquare, clockwise
(0..3).each { |i|
  counter = Trominos[(i+1) % 4]
  sym = Trominos[i]
  clockwise = Trominos[(i+3) % 4]
  first = eval(":#{sym}".sub(/0/, "1"))
  Sub[first] = Sub[counter].sub(counter, first)
  second = eval(":#{sym}".sub(/0/, "2"))
  Sub[second] = Sub[sym].sub(sym, second)
  third = eval(":#{sym}".sub(/0/, "3"))
  Sub[third] = Sub[clockwise].sub(clockwise, third)
}

def base(n, x, y)
  case [x>>(n-1), y>>(n-1)]
    when [0, 0]; Sub[:J0]
    when [1, 0]; Sub[:L0]
    when [1, 1]; Sub[:F0]
    when [0, 1]; Sub[:T0]
  end
end

def solve(n, x, y, *fields)
  if n == 1
    puts fields.join(" ").sub(/.0/, " ")
  else
    n = n - 1
    nn = 2 ** n
    x, y = x % nn, y % nn
    subs = fields.collect { |f|
      # subsquares can be looked up, for :X0 we need proper tromino
      Trominos.include?(f) ? base(n, x, y) : Sub[f]
    }
    solve(n, x, y, *subs.collect { |s0, s1, s2, s3| [s0, s1] }.flatten)
    solve(n, x, y, *subs.collect { |s0, s1, s2, s3| [s3, s2] }.flatten)
  end
end

if ARGV[0].to_i == 0
  STDERR.puts "Usage: #{$0} n # where the field is 2**n square"
else
  n = ARGV[0].to_i
  size = 2 ** n
  x, y = rand(size), rand(size)
  puts "Hole at (#{x}, #{y}) # note that (0, 0) is top left"
  b = base(n, x, y)
  solve(n, x, y, *b.values_at(0, 1))
  solve(n, x, y, *b.values_at(3, 2))
end

Hallo,

here is my solution. I didn't know this problem and I didn't google :wink:
It works recursive:

For n=1 it is easy: just place one tromino, so that the empty square is empty.

For bigger n, divide the problem into four n-1 sub problems. For example:

···

________
_____x__
________

This can be solved by solving the following problems:

____
___o

____
_x__
____

___o
____

o___
____

Putting their solutions together we get:

11112222
11112x22
111o2222
333oo444
33334444

So the last missing tromino can easily be placed.

The program accepts one optional argument (n), it defaults to 3.
It outputs solutions for all possible empty squares.

Dominik

#######################################################

# A simple 2D array, the width and height are immutable once it is created.
# #to_s accepts an optional block that can format the elements.
class Array2D
         attr_reader :w, :h
         def initialize(w, h, defel=nil)
                 @w, @h=w, h
                 @array=Array.new(w*h, defel)
         end
         def [](x, y)
                 @array[(y%h)*w+(x%w)]
         end
         def []=(x, y, v)
                 @array[(y%h)*w+(x%w)]=v
         end

         def to_s
                 (0...h).collect { |y|
                         (0...w).collect { |x|
                                 v=self[x, y]
                                 block_given? ? yield(v) : v
                         }.join " "
                 }.join "\n"
         end
end

class TrominoTiler
         def initialize(n)
                 n=[1, n].max
                 # initialize the working array
                 @a=Array2D.new(1 << n, 1 << n)
         end

         def tile_with_empty(x, y)
                 @tilenum=0 # counter
                 tile_recursive(0, @a.w, 0, @a.h, x, y)
                 @a
         end

         private

         # tiles the area of @a determined by xb,xe and yb,ye (b is begin, e is
         # end, so xb,xe is like the range xb...xe) with trominos, leaving
         # empty_x,empty_y empty
         def tile_recursive(xb, xe, yb, ye, empty_x, empty_y)
                 half=(xe-xb)/2
                 if half==1
                         # easy, just one tromino
                         @tilenum+=1
                         # set all 4 squares, empty is fixed below
                         @a[xb , yb ]=@tilenum
                         @a[xb+1, yb ]=@tilenum
                         @a[xb , yb+1]=@tilenum
                         @a[xb+1, yb+1]=@tilenum
                 else
                         # tile recursive
                         mytile=(@tilenum+=1)
                         # where to split the ranges
                         xh, yh=xb+half, yb+half
                         [ # the 4 sub parts:
                         [xb, xh, yb, yh, xh-1, yh-1],
                         [xh, xe, yb, yh, xh , yh-1],
                         [xb, xh, yh, ye, xh-1, yh ],
                         [xh, xe, yh, ye, xh , yh ]
                         ].each { |args|
                                 # if empty_x,empty_y is in this part, we have
                                 # to adjust the last two arguments
                                 if (args[0]...args[1]).member?(empty_x) &&
                                    (args[2]...args[3]).member?(empty_y)
                                         args[4]=empty_x
                                         args[5]=empty_y
                                 end
                                 tile_recursive(*args)
                                 @a[args[4], args[5]]=mytile
                         }

                 end
                 # fix empty square
                 @a[empty_x, empty_y]=nil
         end
end

if $0 == __FILE__
         n=(ARGV[0] || 3).to_i
         d=1 << n
         maxw=((d*d-1)/3).to_s.size
         tiler=TrominoTiler.new(n)
         # show solutions for all possible empty squares
         d.times { |y|
                 d.times { |x|
                         puts tiler.tile_with_empty(x, y).to_s { |v|
                                 v.to_s.rjust(maxw)
                         }, ""
                 }
         }
end

The algorithm I use is the result of 5 (successful) min trying to fill an
16x1 square with pencil and paper.

It use the fact that 4 Ls can create a new L with the size doubled:

1 1
1 4
2 4 4 3
2 2 3 3

I use this to create Ls in any n**2 size.

Example of the algorithm:

Board:

. . . . . . . .
. . . X . . . .
. . . . . . . .

The first step is to apply a 2x2 grid to the board:

. .|. .|. .|. .
.".|.".|.".|.".
. .|. .|. .|. .
.".|.".|.".|.".
. .|. X|. .|. .
.".|.".|.".|.".
. .|. .|. .|. .

Now if fill the square with the X:

. .|. .|. .|. .
.".|.".|.".|.".
. .|. .|. .|. .
.".|1"1|.".|.".
. .|1 X|. .|. .
.".|.".|.".|.".
. .|. .|. .|. .

I repeat the steps with an 4x4 and 8x8 grid:
4x4:
. . . .|. . . .
2"2 1"1|.". .".
2 5 1 X|. . . .
3 5 5 4|. . . .
3 3 4 4|. . . .
8x8:
7 7 8 8 a a b b
7 9 9 8 a d d b
6 9 i i j j d c
6 6 i l l j c c
2 2 1 1 l k e e
2 5 1 X k k h e
3 5 5 4 g h h f
3 3 4 4 g g f f

My solution does the same thing but instead of applying a grid to the board it
uses some bit shifting and multiplication. The Ls are created using a recursive
method.

It generates HTML output (tested with Safari and Firefox)

tiling.rb (5.23 KB)

···

--
Jannis Harder

Here's my solution, and without googling!.

I'm new in Ruby, and I have a little doubt in my solution. The to_s method is too slow in the way I implemented it, Is there any better approach?.

class Board
    def initialize(n)
        @w = 2**n;
        @tiles = Array.new(4**n, '0')
    end
       # Solve a board indicating row and column of the missing tile
       def solve(xm, ym)
        @count = 0
        @tiles[getPos(xm, ym)] = 'X'
        solve_r(0, 0, xm, ym, @w)
    end
       # n: position of the tromino (upper left corner)
    # miss: tile shouldn't be marked
    # code: character writed in each position, but in miss.
       def setTromino(n, miss, code)
        [0, 1, @w, @w+1].each { |i|
            @tiles[n+i] = code if miss!=n+i
        }
    end

···

#
    # Transform coordinates
    #
    def getPos(i, j)
        return i*@w+j
    end

    # Warning: this is too slow (Why?)
    # Avoid this method in benchmarks

    def to_s
        cad = ''
        @tiles.each_index { |i|
            cad += @tiles[i] + ' '
            cad += "\n" if i%@w==@w-1
        }
        return cad
    end
       private
=begin
    This is a Divide and Conquer solution.
    Base case: 2x2 board. Solution is trivial in this case
       0 X
    0 0
       General case: NxN board. We solve the 4 subboards following this scheme:
       p.e: 4x4
       0 0 0 X
    0 S 0 0
    0 S S 0
    0 0 0 0
       We solve 4 2x2 boards.
    If the selected tile X is in the subboard, we solve it normally.
    If not, we solve supossing selected tiles are the marked as S.
    Finally, in the place of S, we put another tromino, and the board is solved.
=end
    def solve_r(x0, y0, xm, ym, n)
        if(n==2)
            setTromino(getPos(x0, y0), getPos(xm, ym), @count.to_s)
            @count += 1
            return
        end
        n/=2
        s = [] # Position for missing tile in the S tromino
        [[0, 0], [0, n], [n, 0], [n, n]].each { |d|
            # (x1, y1): upper left corner of the subboard
            # (dx, dy): position of S in the subboard
            x1, y1, dx, dy = x0+d[0], y0+d[1], x0+(d[0]==0 ? n-1:n), y0+(d[1]==0 ? n-1:n)
            if((x1...x1+n).include?(xm) && (y1...y1+n).include?(ym))
                s = [dx, dy]
                solve_r(x1, y1, xm, ym, n)
            else
                solve_r(x1, y1, dx, dy, n)
            end
        }
               setTromino(getPos(x0+n-1, y0+n-1), getPos(s[0], s[1]), @count.to_s)
        @count += 1
    end

end

if ARGV.length == 2
    b = Board.new(3)
    b.solve(ARGV[0].to_i, ARGV[1].to_i)
    puts b.to_s
end

Here's my solution. It defines a class called Square to represent the
board. Most of the work is done in the recursive #do_tile function.

The algorithm works by breaking down a board into four quadrants and
determining which of these quadrants has a non-empty square. It then
places a tile so that the tile will bracket the edge of the quadrant
with the non-empty square. It then recursively tiles these quadrants.
Each of these quadrants will have an empty space because the tile
placed in the last step has one square in each of the three quadrants
that didn't already have a non-empty square.

I didn't google, but I did have this problem in my Discrete Structures
class earlier in the year. :stuck_out_tongue:

class Square
  def initialize n
    raise "n must be > 0" unless n > 0

    # create a 2**n x 2**n board filled with dashes
    @size = 2 ** n
    @board = Array.new @size do
      Array.new @size do
  "-"
      end
    end
    
    # a randomly-placed X indicates the hole
    @board[ rand(@size) ][ rand(@size) ] = "X"
    @cur_tile = 1
  end

  def to_s
    @board.collect { |row| row.collect { |item|
  "%#{Math.log(@size).to_i}s" % [item] }.join " " }.join "\n"
  end
  
  def tile!
    # (0, 0, @size) means the @size x @size square extending to the right and
    # downward from (0, 0)
    do_tile 0, 0, @size
  end

  def do_tile row, col, size
    # base case
    if size < 2
      return
    end

    sub_size = size / 2

    # define each quadrant
    top_left = [row, col, sub_size]
    top_right = [row, col + sub_size, sub_size]
    bottom_left = [row + sub_size, col, sub_size]
    bottom_right = [row + sub_size, col + sub_size, sub_size]

    # one of the quadrants will have a non-empty tile; bracket that quadrant
    # with a tile
    if has_filled_tile? *top_left
      @board[row + sub_size - 1] [col + sub_size] = @cur_tile
      @board[row + sub_size] [col + sub_size] = @cur_tile
      @board[row + sub_size] [col + sub_size - 1] = @cur_tile
    elsif has_filled_tile? *top_right
      @board[row + sub_size - 1] [col + sub_size - 1] = @cur_tile
      @board[row + sub_size] [col + sub_size - 1] = @cur_tile
      @board[row + sub_size] [col + sub_size] = @cur_tile
    elsif has_filled_tile? *bottom_left
      @board[row + sub_size - 1] [col + sub_size - 1] = @cur_tile
      @board[row + sub_size - 1] [col + sub_size] = @cur_tile
      @board[row + sub_size] [col + sub_size] = @cur_tile
    elsif has_filled_tile? *bottom_right
      @board[row + sub_size - 1] [col + sub_size - 1] = @cur_tile
      @board[row + sub_size] [col + sub_size - 1] = @cur_tile
      @board[row + sub_size - 1] [col + sub_size] = @cur_tile
    else
      raise "broken"
    end

    @cur_tile += 1

    # recursively tile the quadrants
    do_tile *top_left
    do_tile *top_right
    do_tile *bottom_left
    do_tile *bottom_right
  end
  private :do_tile
  
  def has_filled_tile? row, col, size
    size.times do |r|
      size.times do |c|
  if @board[row + r] [col + c] != "-"
    return true
  end
      end
    end
    false
  end
end

s = Square.new 2
s.tile!
puts s.to_s

···

On 5/20/05, Ruby Quiz <james@grayproductions.net> wrote:

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Greg Brown

This weeks quiz is based off of a mathematical proof we were taught in my
discrete mathematics class a few weeks ago. Though I can already hear some of
you running for the hills at the mention of the four letter word that is math, I
can assure you that this is more of a thinking problem than it is number
crunching. The basic idea is pretty simple.

You're going to tile L-trominos on a 2**n by 2**n board that is missing a single
square. What's an L-tromino? It's simply a 2 by 2 square with a corner missing
that looks like an L.

For further clarification, this is what they look like:

        #
        # #

Well, I guess it's time to stop being vague and give you the problem definition.

For any 2**n by 2**n board with a single square missing in a random location,
you must write a program that will tile L-trominos in such a way that the grid
is completely filled in.

Your program should take the value for n as the input, and somehow display the
board with the trominos properly laid out as the output. It should place the
missing square at random each time the board is generated. (Otherwise this would
be too easy!)

For example, the empty board of n = 2 would be something like this:

        _ _ _ _
        _ _ X _
        _ _ _ _
        _ _ _ _

The solution for that might look like:

        1 1 2 2
        1 5 X 2
        3 5 5 4
        3 3 4 4

As you can see, all squares are completely filled with the exception of the
empty square which was randomly placed.

It may look simple on a 4 by 4 board, but once you get up to a 128 by 128 or
even 4096 by 4096, it becomes more and more obvious that guess and check is just
not going to work.

The level of difficulty of this problem depends entirely on how much you already
know about it. If you want an easy ride, look for the proof and just implement
it.

If you want more of a challenge, avoid Googling the topic and try to find clever
ways to actually show how your program solves the problem.

Hope you have fun with this quiz, and if you write a really good one, you can
help me tile my bathroom floor next week as a prize. :slight_smile:

--
Bill Atkins

Here's my solution (and my first attempt at a Ruby Quiz) - also completed without googling.

The distinguishing feature here compared to the other solutions posted so far, is that I'm doing the recursion by creating a tree of Square objects beforehand, in an effort to make it more OOPish.

#!/usr/bin/ruby

# Proof by induction
# Base case: a 2x2 board with one missing square.
# Trivially, the remaining 3 squares form an L-tromino.
# Step:
# Assume that any (2**(n-1) x 2**(n-1)) board with a square missing can be solved.
# A (2**n x 2**n) board can be divided into four (2**(n-1) x 2**(n-1)) quadrants.
# One of these quadrants contains the missing square.
# An L-tromino can be placed in the centre of the board, rotated such that it occupies
# one square of each of the other three quadrants.
# The result of this is four quadrants, each of which has one square missing.
# By our original assumption, each of these can be solved.

# Note that at each stage of subdivision, each quadrant contains precisely one
# square that is either 1) the missing square, or 2) occupied by an L-tromino
# that overlaps onto other quadrants.

class Square
  # Represents a square portion of the board.
  
  attr_reader :central_corner_x, :central_corner_y
  
  def initialize(size, left = 0, top = 0, central_corner_x = nil, central_corner_y = nil)
    @size = size # Size of this square
    @left = left # X coordinate of leftmost point
    @top = top # Y coordinate of topmost point
    @central_corner_x = central_corner_x
    @central_corner_y = central_corner_y
      # Coordinates of the corner closest to the middle
      # of the parent square (or nil if the square has no parent)
      
    if size > 1
      # divide into quadrants
      quad_size = @size / 2
      @quadrants = [
        Square.new(quad_size, @left, @top, @left + quad_size - 1, @top + quad_size - 1),
        Square.new(quad_size, @left + quad_size, @top, @left + quad_size, @top + quad_size - 1),
        Square.new(quad_size, @left, @top + quad_size, @left + quad_size - 1, @top + quad_size),
        Square.new(quad_size, @left + quad_size, @top + quad_size, @left + quad_size, @top + quad_size)
      ]
    end
  end
  
  def contains?(x, y)
    # Determine whether this square contains the given point
    (@left...(@left+@size)) === x && (@top...(@top+@size)) === y
  end
  
  def solve(board, missing_x, missing_y, count = 1)
    # board = a board which is to have the portion indicated by this Square object filled with L-trominos
    # missing_x, missing_y - the coordinates of a square not to be filled
    # count = the current L-tromino number
    # Returns the next available unused L-tromino number
    if @size == 1
      board[@top][@left] = count unless contains?(missing_x, missing_y)
      count
    else
      next_count = count + 1
      @quadrants.each { |quadrant|
        if quadrant.contains?(missing_x, missing_y)
          # a square in this quadrant is already missing - can solve the quadrant straight off
          next_count = quadrant.solve(board, missing_x, missing_y, next_count)
        else
          # artificially 'create' a missing square before solving the quadrant
          board[quadrant.central_corner_y][quadrant.central_corner_x] = count
          next_count = quadrant.solve(board, quadrant.central_corner_x, quadrant.central_corner_y, next_count)
        end
      }
      next_count
    end
  end
end

puts "Board magnitude? (1 = 2x2, 2 = 4x4, 3 = 8x8, 4 = 16x16...)"
n = gets.to_i
size = 2**n
digits = (n*2) / 5 + 1 # how many base-32 digits we need to give each L-tromino its own ID

board = (0...size).collect{ (0...size).collect { 0 } }
Square.new(size).solve(board, rand(size), rand(size))

board.each do |row|
  puts row.map{ |i| i.to_s(32).rjust(digits) }.join(' ')
end

* Pedro <pedro.wotan@mundo-r.com> [2005-05-25 06:33:24 +0900]:

Here's my solution, and without googling!.

I'm new in Ruby, and I have a little doubt in my solution. The to_s
method is too slow in the way I implemented it, Is there any better
approach?.

Yes. There are a couple of things you can do.

   def to_s
       cad = ''
       @tiles.each_index { |i|
# cad += @tiles[i] + ' '

              cad << @tiles[i] << ' '

# cad += "\n" if i%@w==@w-1

              cad << "\n" if i%@w==@w-1

       }
       return cad
   end

The other thing you can do (with some extra modification) is start with:

    cad =

and when you are done, do
     cad.join("\n")

···

--
Jim Freeze
Ruby: I can explain it to ya but I can't understand it fer ya.

Here's my solution, and without googling!.

Nice job.

I'm new in Ruby,

Welcome!

and I have a little doubt in my solution. The to_s method is too slow in the way I implemented it, Is there any better approach?.

[snip]

   def to_s
       cad = ''
       @tiles.each_index { |i|
           cad += @tiles[i] + ' '
           cad += "\n" if i%@w==@w-1
       }
       return cad
   end

I haven't tested or timed it, but one way might be:

def to_s
     @tiles.join(" ").sub!(/((?:[0-9X]+\s+){#{@w}})/, "\\1\n") + "\n"
end

Hope that helps.

James Edward Gray II

···

On May 24, 2005, at 4:33 PM, Pedro wrote: