[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[SOLUTION] Ruby Quiz #33 Tiling Turmoil

email55555 email55555

5/22/2005 3:35:00 PM

Here is my solution, it is kind of short ...

#--------------------------------------------------------------------
# Program : Solution for Ruby Quiz #33 Tiling Turmoil
# Author : David Tran
# Date : 2005-05-20
# Version : 1.0
#--------------------------------------------------------------------
def tile(a, n, m, s, x)
@count += 1
h = m/2
new_s = [s, s+h, s+h*n, s+h*n+h]
new_x = [s+(h-1)*n+(h-1), s+(h-1)*n+h, s+h*n+h-1, s+h*n+h]
p = ((x-s) / n < h) ? ((x-s) % n < h) ? 0 : 1 : ((x-s) % n < h) ? 2 : 3
new_x.each_index{ |i| a[new_x[i]] = @count if i != p }
return if h == 1
new_x[p] = x
new_s.each_with_index { |e, i| tile(a, n, h, e, new_x[i]) }
end

(puts "Usage: #$0 n"; exit) if (ARGV.size != 1 || ARGV[0].to_i <= 0)
n = 2 ** ARGV[0].to_i
@count = 0
a = Array.new(n*n)
x = rand(a.size)
a[x] = 'X'
tile(a, n, n, 0, x)
format = "%#{2 + Math.log10(a.size).to_i}s"
a.each_with_index {|e, i| print(format % e); puts if (i+1)%(n) == 0}
# End of Program------------------------------------------------------

=======================================================================
It is base on S. Golomb gave an inductive proof :
http://www.cut-the-knot.com/Curriculum/Geometry/Tro...
Here is some explanation for my program about tile method:
a - is a dimension one array of n x n ( flat of orign dimension 2 array)
n - is the number side ( 2 ** input number )
m - is the number side of sub square
s - is the start point index ( top-left corner index for sub square )
x - is the missing cell index
=======================================================================

Base on The four color theorem, we could color the tile by using max 4 colors.
http://www.math.gatech.edu/~thomas/FC/four...

So, I modified again my solution to show by using 4 color codes:
http://mathworld.wolfram.com/Four-ColorTh...

#--------------------------------------------------------------------
# Program : Solution for Ruby Quiz #33 Tiling Turmoil
# Author : David Tran
# Date : 2005-05-20
# Version : Using 4 color codes
#--------------------------------------------------------------------
def tile(a, n, m, s, x)
h = m/2
new_s = [s, s+h, s+h*n, s+h*n+h]
new_x = [s+(h-1)*n+(h-1), s+(h-1)*n+h, s+h*n+h-1, s+h*n+h]
around_tile = [new_x[0]%n == 0 ? nil : new_x[0]-1,
new_x[0] < n ? nil : new_x[0]-n,
new_x[1] < n ? nil : new_x[1]-n,
(new_x[1]+1)%n == 0 ? nil : new_x[1]+1,
new_x[2]%n == 0 ? nil : new_x[2]-1,
new_x[2]/n + 1 >= n ? nil : new_x[2]+n,
new_x[3]/n + 1 >= n ? nil : new_x[3]+n,
(new_x[3]+1)% n == 0 ? nil : new_x[3]+1]

p = ((x-s)/ n < h) ? ((x-s)% n < h) ? 0 : 1 : ((x-s)% n < h) ? 2 : 3

around_tile[p*2, 2] = new_x[p]
(1..4).each do |color|
use = false
around_tile.each do |i|
next if i.nil?
(use = true; break) if a[i] == color
end
if (!use)
new_x.each_index{ |i| a[new_x[i]] = color if i != p }
break;
end
end

return if h == 1
new_x[p] = x
new_s.each_with_index { |e, i| tile(a, n, h, e, new_x[i]) }
end

(puts "Usage: #$0 n"; exit) if (ARGV.size != 1 || ARGV[0].to_i <= 0)
n = 2 ** ARGV[0].to_i
a = Array.new(n*n)
x = rand(a.size)
a[x] = 0
tile(a, n, n, 0, x)
colorCode = [' ', '*', 'o', '+', '-']
a.each_with_index { |e, i| print(" #{colorCode[e]}"); puts if (i+1)%n == 0 }
# End of Program------------------------------------------------------
=======================================================================

This gives a solution presents like:

$> tiling2.rb 4

o o + + o o + + o o + + o o + +
o * * + o * * + o * * + o * * +
+ * o o + + * o + * o o + + * o
+ + o * * + o o + + o * * + o o
o o + * o o + + o o + + * o + +
o * + + o * * + o * * + o o * +
+ * * o + * o o + + * o + * * o
+ + o o + + o * * + o o + + o o
o o + + o o + * o o + + o o + +
o * * + o * + + o * * + o * * +
+ * o o + * * o + * o o + + * o
+ + o * + + o o + + o * + o o
o o + * * o + + o o + * * o + +
o * + + o o * + o * + + o o * +
+ * * o + * * o + * * o + * * o
+ + o o + + o o + + o o + + o o

=======================================================================

My first and second solution always recalculation next "missing" cell
possition, it is kind of waste time, because, except the "missing" cell
all will be one of top-left, top-right, bottom-left, bottom-right
coner "missing"
on next iteration and so on.

So, one ugly and quickly improve is like:

#--------------------------------------------------------------------
# Program : Solution for Ruby Quiz #33 Tiling Turmoil
# Author : David Tran
# Date : 2005-05-20
# Version : Without always recalculate "missing" cell
#--------------------------------------------------------------------

DIRECTION = [ [ 0, 3, 0, 1],
[ 2, 1, 0, 1],
[ 2, 3, 2, 1],
[ 2, 3, 0, 3] ]

def tile(a, n, m, s, x, p)
@count += 1
h = m/2
new_s = [s, s+h, s+h*n+h, s+h*n]
new_x = [s+(h-1)*n+(h-1), s+(h-1)*n+h, s+h*n+h, s+h*n+h-1]

if p < 0
pp = ((x-s) / n < h) ? ((x-s) % n < h) ? 0 : 1 : ((x-s) % n < h) ? 3 : 2
else
pp = p
end

new_x.each_index{ |i| a[new_x[i]] = @count if i != pp }
return if h == 1
dir = DIRECTION[pp]
if p < 0
dir = dir.dup
dir[pp] = -1
end
new_s.each_with_index { |e, i| tile(a, n, h, e, x, dir[i]) }
end

(puts "Usage: #$0 n"; exit) if (ARGV.size != 1 || ARGV[0].to_i <= 0)
n = 2 ** ARGV[0].to_i
a = Array.new(n*n)
x = rand(a.size)
a[x] = 'X'
@count = 0
tile(a, n, n, 0, x, -1)
format = "%#{2 + Math.log10(a.size).to_i}s"
a.each_with_index {|e, i| print(format % e); puts if (i+1)%(n) == 0}

# End of Program------------------------------------------------------

=======================================================================

Anyway, I still like my first short solution even it seems waste time to
recalculate "missing" cell ...


2 Answers

email55555 email55555

5/23/2005 5:50:00 PM

0

The solution for 2x2 and 4x4 is unique.
But start from 8x8, the solution is no more unique.

Here is my other version to solve this puzzle.
It uses simple back-tracking to find all possible solution.
It is not efficient at all, but it can find all solutions.

I am not sure is there a math formula to find all solution number.
Base on my program, I found, for example, for 8x8 and
missing cell at (0,0), there are total 30355 possible solutions.

Because it is not efficient, I will not try board big then 8x8 :-)

# ------------------------------------------------------------------------------
# Program : Solution for Ruby Quiz Tiling Turmoil (#33)
# Author : David Tran
# Date : 2005-05-23
# Vesion : Use Simple Backtracking to compute all solutions
# Note : Simple backtracking, no use any math theorem or
# pattern analyse. It is not efficient at all!
# BTW. The total solution for 8x8 and missing cell at [0,0] is 30355.
# ------------------------------------------------------------------------------

def help
puts "Usage: #$0 n [sol]"
puts " Tiling Turmoil for board of 2^n x 2^n cases with one random
missing case"
puts " sol: Optional."
puts " Number solution desire. Default value equals 1."
puts " Equals to zero : Compute total solution number without
print solutions."
puts " Less then zero : Print all possible solutions."
exit
end

# To make sure back tracking all possible solutions, the tiling order
is important.
# This program will tile trimino from top to bottom and left to right.
#
# So, the 4 possible L-tromino will have this relation coordination (x, y):
TROMINOS = [ [ [1, 0], [0, 1] ], # o*
# *
#
[ [1, 0], [1, 1] ], # o*
# *
#
[ [0, 1], [1, 1] ], # o
# **
#
[ [0, 1], [-1,1] ] ] # o
# **


def tile_next(a, n, count)
(0...n).each do |y|
(0...n).each do |x|
next if a[y][x]
TROMINOS.each do |tromino|
x1 = x + tromino[0][0]
y1 = y + tromino[0][1]
x2 = x + tromino[1][0]
y2 = y + tromino[1][1]
next if ( x1 < 0 || x1 >= n ||
y1 < 0 || y1 >= n ||
x2 < 0 || x2 >= n ||
y2 < 0 || y2 >= n ||
a[y1][x1] || a[y2][x2] )
a[y][x] = a[y1][x1] = a[y2][x2] = count
tile_next(a, n, count+1)
a[y][x] = a[y1][x1] = a[y2][x2] = nil # back tracking
end
return
end
end
print_solution(a)
end


def print_solution(a)
@solutions += 1
if @show_solution
puts "solution ##@solutions"
a.each {|row| puts row.inject('') {|s, e| s + e.to_s.rjust(@digits+1) } }
puts
end
exit if @num_solutions != nil && @solutions >= @num_solutions
end


help if ARGV.size <= 0 || ARGV[0].to_i <= 0
n = 2 ** ARGV[0].to_i
option = ARGV[1] ? ARGV[1].to_i : 1
@num_solutions = (option <= 0) ? nil : option
@show_solution = (option != 0)
@digits = (n*n).to_s.size
@solutions = 0
a = Array.new(n) { Array.new(n) }
a[rand(n)][rand(n)] = 'X'
tile_next(a, n, 1)
puts "Total possible solutions = #@solutions" if @num_solutions.nil?


email55555 email55555

5/25/2005 9:21:00 PM

0

=begin

* Program : Solution for Ruby Quiz #33 Tiling Turmoil
* Author : David Tran
* Date : 2005-05-25
* Version : Fast, less iteration version

Here is my other solution.

Below note is only apply for n >= 3 ( start from 8x8 )
for n =1 (2x2) and n=2 (4x4) the solution is unique.

It still has a special case need to solve.
(Do not want google to find solution for the special case)

The small rectangle form by tromino is 2x3 (or 3x2) note as R(2,3).
Below, it discuss only for 2x3 case. (for 3x2, just rotate it)

This means all area of 2nx3m can tile by the small rectangle of 2 tromino