Attached is my solution. It uses nested arrays to simulate the 3-d grid cells, and adds methods to Array to effect this. It handles arbitrary rectangles of 2**n by 2**m. The unit tests provided earlier pass.
I can't help feeling there should be a direct numerical way to calculate this sequence. To study the sequence, I wrote a second script, also attached, that prints the bits of the resulting sequence from any given rectangle dimensions and list of folds. (I subtract one from the sequence to make it zero-based.) However, even with a fair amount of studying lists of bit patterns I haven't cracked the code.
# Creates the grid, applies the folds to it def fold( v, h, folds ) grid = Array.new(v){|i|Array.new(h){|j|[j*v+i+1]}} s, c = StringScanner.new(folds), "" grid.send("fold_"+c+"!") while c=s.getch raise "Too few folds" if grid.size != 1 or grid[0].size != 1 grid[0][0] end
class Array # Slices self in half, yields removed and retained elements def fold!(forward) raise "Can't fold odd-sized array" if size[0] == 1 start = if forward then 0 else size/2 end a = slice! start, size/2 zip(a.reverse!){|e|yield e[1], e[0]} end
# Vertical fold, top to bottom or vice versa def fold_v!(down) each{|c|c.fold!(down){|a,b|b.unshift(*a.reverse!)}} end
# Horizontal fold, left to right or vice versa def fold_h!(left) fold!(left){|a,b|a.each_index{|i|b[i].unshift(*a[i].reverse!)}} end
def fold_T!; fold_v! true; end def fold_B!; fold_v! false; end def fold_L!; fold_h! true; end def fold_R!; fold_h! false; end end
# Parses ARGV, returns v, h, folds def get_args def usage puts "Usage: #{File.basename($0)} [<size>] <folds>\n"+ " where <size> is a power of 2 or a pair thereof separated by 'x', like 4x8\n"+ " and <folds> is a string of fold directions from T, L, R, B\n" exit end usage unless (1..2) === ARGV.size size, folds = [16, 16], ARGV[-1] usage unless folds =~ /^[TLRB]+$/ if ARGV.size == 2 size = ARGV[0].split('x').map{|s|s.to_i} usage unless (1..2) === size.size size = Array.new(2, size[0]) if size.size == 1 size.each{|i|raise "%d not a power of 2"%i unless i>0 and i&(i-1)==0} end v, h = *size return v, h, folds end
# Main program if $0 == __FILE__ p fold( *get_args ) end
And here's mine. I didn't use a grid at all - working it out a cell at a time.
One key difference is that mine works out the dimensions from the supplied folds. It checks that the grid to be square (raises an exception otherwise), but only to pass what might have been an over-zealous test case.
-----Original Message----- From: Luke Blanshard [mailto:l...@blanshard.us] Sent: 22 January 2006 13:56 To: ruby-talk ML Subject: [/QUIZ] #63: Grid Folding
Greetings all,
Attached is my solution. It uses nested arrays to simulate the 3-d grid cells, and adds methods to Array to effect this. It handles arbitrary rectangles of 2**n by 2**m. The unit tests provided earlier pass.
I can't help feeling there should be a direct numerical way to calculate this sequence. To study the sequence, I wrote a second script, also attached, that prints the bits of the resulting sequence from any given rectangle dimensions and list of folds. (I subtract one from the sequence to make it zero-based.) However, even with a fair amount of studying lists of bit patterns I haven't cracked the code.
Here's mine. I use arrays within arrays as well. I wrote my own loops to do the folding. I see now I could have done it much more succinctly. I went for all the extra credit. Can unfold by noticing the last element of the array hasn't been folded over and the first element was previously unfolded. The direction from the first to the last element gives the fold direction. Then just keep cutting off the first part of the array.
#! /usr/bin/env ruby -w
=begin Manages the matrix of values for folding: [[1], [2], [3], [4]]
left_fold returns new matrix: [[1, 2], [3, 4]] =end class FoldMatrix
# Fold left side of matrix over to right returning new FoldMatrix def left_fold fold(:left) end
# Fold right side of matrix over to left returning new FoldMatrix def right_fold fold(:right) end
# Fold top of matrix down and return new FoldMatrix def top_fold fold(:top) end
# Fold bottom of matrix up and return new FoldMatrix def bottom_fold fold(:bottom) end
# Return the result of folding in flattened array def result if (@rows != 1 && @cols != 1) raise ArgumentError, "Paper not completely folded" end
@values.flatten end
private
# Return a matrix element def array_element(i, j) @values[i*@cols + j] end
# Iterate through items in array by folded direction where direction # is one of :left, :right, :top, :bottom. Iterates going left to # right then down. Values are already in proper order top to # bottom. # Example: # each_by_fold do |top, bottom| # new_cell_value = top + bottom # end def each_by_fold(fold) # make sure there are enough rows or columns to fold case fold when :left, :right if @cols <= 1 raise ArgumentError, "Attemting to fold to #{fold.to_s} with only 1 column" end when :top, :bottom if @rows <= 1 raise ArgumentError, "Attemting to fold to #{fold.to_s} with only 1 row" end end
# setup loop boundaries to loop through unfolded part of page case fold when :left row_start = 0 row_end = @rows - 1 col_start = @cols/2 col_end = @cols - 1 when :right row_start = 0 row_end = @rows - 1 col_start = 0 col_end = @cols/2 - 1 when :top row_start = @rows/2 row_end = @rows - 1 col_start = 0 col_end = @cols - 1 when :bottom row_start = 0 row_end = @rows/2 - 1 col_start = 0 col_end = @cols - 1 end
# loop through row by row reversing items folded to top row_start.upto(row_end) do |i| col_start.upto(col_end) do |j| case fold when :left, :right top = array_element(i, @cols - j - 1).reverse bottom = array_element(i, j) when :top, :bottom top = array_element(@rows - i - 1, j).reverse bottom = array_element(i, j) end yield(top, bottom) end end end
# Return a new fold matrix by folding in direction where direction # is one of :left, :right, :top, :bottom. def fold(direction) new_values = [] each_by_fold(direction) do |top, bottom| new_values << top + bottom end
case direction when :left, :right new_cols = @cols/2 new_rows = @rows when :top, :bottom new_cols = @cols new_rows = @rows/2 end FoldMatrix.new(new_values, new_rows, new_cols) end end
# Determine if a number is a power of 2 def is_power_of_2(number) return false if number < 1
# keep on shifting left until number equals one (power of 2) or has # one bit set but isn't one (not power of 2) while number > 1 number >>= 1 return false if ((number & 1) == 1 && number != 1) end true end
# Get the direction from an unfolded matrix element to the one # just folded to the top. Both must be in same row or column. def direction_to(unfolded, folded, rows, cols) unfolded -= 1 unfolded_i = unfolded / cols unfolded_j = unfolded % cols
case when unfolded_i == folded_i && unfolded_j < folded_j :right when unfolded_i == folded_i && unfolded_j > folded_j :left when unfolded_j == folded_j && unfolded_i < folded_i :bottom when unfolded_j == folded_j && unfolded_i > folded_i :top else raise ArgumentError, "Values not in same row or column: " + "#{unfolded}, #{folded}, #{rows}x#{cols}" end end
def check_rows_and_cols(rows, cols) unless is_power_of_2(rows) raise ArgumentError, "Rows must be power of two" end unless is_power_of_2(cols) raise ArgumentError, "Cols must be power of two" end end
# Fold up matrix of numbers using given directions where directions # are in a string with T = top, B = bottom, L = left, R = right: # "TLBR". Throws ArgumentError on invalid direction or rows or cols # not a power of 2. def fold(directions, rows=16, cols=16) check_rows_and_cols(rows, cols)
# build array of values values = [] 1.upto(rows*cols) do |i| values << [i] end
fold_matrix = FoldMatrix.new(values, rows, cols)
directions.each_byte do |fold_direction| case fold_direction when ?T fold_matrix = fold_matrix.top_fold when ?B fold_matrix = fold_matrix.bottom_fold when ?L fold_matrix = fold_matrix.left_fold when ?R fold_matrix = fold_matrix.right_fold else raise ArgumentError, "Invalid direction #{fold_direction}" end end fold_matrix.result end
# Get the folding directions from a fold array. The item that has # never been folded over is at end of array. The item that wasn't # folded until the last fold and is now at at the first of array. # Therefore... # # while size of array is greater than 1 # get direction in original matrix from last item number # in folded array to first # push direction on front of directions # cut off front half of array # end # # Throws ArgumentError on array not in fold order or rows or cols not # power of 2. def check_fold(folded, rows=16, cols=16) check_rows_and_cols(rows, cols)
directions = "" while folded.size > 1 # get direction in original matrix from last to first direction = direction_to(folded.last, folded.first, rows, cols)
# and push it on front of directions case direction when :top directions = "T" + directions when :bottom directions = "B" + directions when :left directions = "L" + directions when :right directions = "R" + directions end
# cut array in half folded = folded[folded.size/2...folded.size] end directions end
if __FILE__ == $0 if (ARGV.size == 1 || ARGV.size == 3) if (ARGV.size == 3) rows = ARGV[1].to_i cols = ARGV[2].to_i else rows = 16 cols = 16 end p fold(ARGV[0], rows, cols) else puts "Usage: #$0 folds [rows cols]" end end
Of four solutions submitted so far, Luke's performs the best (2 times better than the nearest neighbour - mine) - and the code is very clear and easy to understand for a newbie like me. Great work!
On Sun, Jan 22, 2006 at 10:55:44PM +0900, Luke Blanshard wrote:
[...]
} I can't help feeling there should be a direct numerical way to } calculate this sequence. To study the sequence, I wrote a second } script, also attached, that prints the bits of the resulting sequence } from any given rectangle dimensions and list of folds. (I subtract one } from the sequence to make it zero-based.) However, even with a fair } amount of studying lists of bit patterns I haven't cracked the code.
In fact, there is a very nice direct numerical way to calculate it. There are a few key facts/insights:
1) Everything should be done zero-based (instead of one-based) until the final output.
2) Given a width 2**N, only the lowest N bits change as one moves across (horizontally) the grid.
3) Given a height 2**M, only the highest M bits change as one moves down (vertically) the grid.
4) With a current (i.e. after any folds) width 2**n, every newly-touching pair of numbers A and B are related by A == B ^ ((1<<n)-1) after a horizontal (L or R) fold
5) With a current (i.e. after any folds) height 2**m and initial width 2**N, every newly-touching pair of numbers A and B are related by A == B ^ (((1<<m)-1)<<N) after a vertical (T or B) fold.
6) The sequence of XOR operations that relate pairs of touching numbers is a palindrome at any given moment.
7) The XOR sequence generated by a fold is the old sequence, then the XOR value for the newest fold, then the old sequence again.
Thus, all we have to do is be able to generate the XOR value for a particular fold (#4 & #5), generate the new sequence from that and the old sequence (#7), keep track of where in the sequence the zero value is, and keep track of whether the zero value is "face up" or "face down."
You take the final sequence and generate the actual numbers by XORing along the sequence backward and forward from zero. Depending on whether zero is face up or not, you may have to reverse the list of numbers. You then add one to each number to get the one-based values instead of zero-based values.
Note that this solution works for any width and height that are powers of two, and need not be square. In addition, it could be trivially extended to three or more dimensions. The code is below.
} Luke Blanshard
--Greg P.S. Yes, I did add a method to the Enumerable module. It's unnecessary, but convenient and kind of cute.
def validate_dims(x, y) fail "x dimension must be at least 1" if x < 1 fail "y dimension must be at least 1" if y < 1 xbits = x.to_s(2).cdr ybits = y.to_s(2).cdr fail "x dimension must be a power of 2" if xbits.count("1") != 0 fail "y dimension must be a power of 2" if ybits.count("1") != 0 return [xbits.length, ybits.length] end
def validate_folds(folds) x_folds = folds.count("L") + folds.count("R") y_folds = folds.count("T") + folds.count("B") if folds.length != (x_folds + y_folds) fail "Invalid characters in fold string" else if x_folds < @x_foldable fail "Too few x folds" elsif x_folds > @x_foldable fail "Too many x folds" end if y_folds < @y_foldable fail "Too few y folds" elsif y_folds > @y_foldable fail "Too many y folds" end end return folds.split(//) end
end
class Grid
def initialize(x, y) @x_foldable, @y_foldable = validate_dims(x, y) end
def fold(fold_str) folds = validate_folds(fold_str.upcase) zero_corner = ["T", "L"] zero_slice = 0 operations = [] width = @x_foldable height = @y_foldable folds.each { |f| if not zero_dir(zero_corner) zero_slice += operations.length + 1 end if zero_corner[0] == f zero_corner[0] = Opposite[f] elsif zero_corner[1] == f zero_corner[1] = Opposite[f] end temp_ops = operations.clone() op = 0 if IsXFold[f] op = (1 << width) - 1 width -= 1 else op = ((1 << height) - 1) << @x_foldable height -= 1 end operations << op operations << temp_ops operations.flatten! } below_zero = operations[0...zero_slice].reverse above_zero = operations[zero_slice..-1] curval = 0 below_zero.map! { |n| (curval ^= n) + 1 } curval = 0 above_zero.map! { |n| (curval ^= n) + 1 } list = [] if zero_dir(zero_corner) list << above_zero.reverse list << 1 list << below_zero else list << below_zero.reverse list << 1 list << above_zero end return list.flatten! end
private include GridFolding
#true is up def zero_dir(zero_corner) not ((zero_corner[0]=="T") ^ (zero_corner[1]=="L")) end end
# vim:ts=2 sw=2 ai expandtab foldmethod=syntax foldcolumn=5
Attached is my solution--I wish very much that I knew about Array#transpose when I wrote this. Seems to work, though, although check_fold takes about 8 seconds on my zippy Pentium III 750MHz--some restructuring could improve that. From my observations, given a permutation of (1..256), there seems to be at most one sequence of folds that gives that result. i.e. there are never two sequences that give the same permutation. Does anybody know why this is? Seems like an interesting math problem.
I also really hacked together a get_dup method... how to you correctly tell classes how to make copies of themselves?
On Jan 22, 2006, at 10:45 AM, Gregory Seidman wrote:
> P.S. Yes, I did add a method to the Enumerable module. It's > unnecessary, > but convenient and kind of cute. > module Enumerable > # Lisp-y! > def cdr > return self[1..-1] > end > end
But it has the downside of making Enumerable depend on a []() method, which it normally doesn't require. ;)
Here's my solution. It's not terribly efficient (uses arrays of arrays), but the algorithm should be pretty easy to read.
Cheers,
-Nathan
module Folding
def fold(h, w, commands) page = Page.new_page_of_size(h, w) commands.downcase.scan(/./).each do |command| raise "Invalid input!" if page.invalid_command?(command) page = page.send("fold_#{command}".to_sym) end raise "Invalid input!" if !page.is_one_cell? page.first_cell end
end
class Page
def self.new_page_of_size(h, w) Page.new(create_page_map(h, w)) end
def height @page_map.size end
def width @page_map.first.size end
def fold_r new_map = (1..height).inject([]) {|r, i| r << [] } 0.upto(height - 1) do |r| 0.upto(width / 2 - 1) do |c| head = @page_map[r][c] tail = @page_map[r][width - c - 1].reverse new_map[r][c] = tail + head end end Page.new(new_map) end
def fold_l turn_180.fold_r.turn_180 end
def fold_t turn_cw.fold_r.turn_ccw end
def fold_b turn_ccw.fold_r.turn_cw end
def turn_cw new_map = (1..width).inject([]) {|r, i| r << [] } 0.upto(height - 1) do |r| 0.upto(width - 1) do |c| new_map[c][height - r - 1] = @page_map[r][c] end end Page.new(new_map) end
def turn_ccw turn_180.turn_cw end
def turn_180 turn_cw.turn_cw end
def invalid_command?(c) height == 1 && (c == 't' || c == 'b') || width == 1 && (c == 'l' || c == 'r') end
def is_one_cell? height == 1 && width == 1 end
def first_cell @page_map[0][0] end
private
def initialize(map) @page_map = map end
def self.create_page_map(h, w) (1..h).inject([]) do |page, i| page << (1..w).inject([]) do |row, j| row << [w*(i-1) + j] end end end
i hope there is something new in my solution. Rather than folding my solution unfolds and keeps track of the position of a certain layer. It starts with a 1x1 stack of paper and undos all cmds that leed to this stack (doubling the size of the paper each step). Doing this for every layer of the stack gives the solution to this quiz. (no arrays, matrixes, etc. needed except for returning the result)
cmds.unpack('C*').reverse_each do |cmd| x, xdim = x - xdim, xdim * 2 if cmd == ?R x, xdim = x + xdim, xdim * 2 if cmd == ?L y, ydim = y - ydim, ydim * 2 if cmd == ?B y, ydim = y + ydim, ydim * 2 if cmd == ?T
if z > (layer /= 2) z = 1 + (layer * 2) - z x = -x if cmd == ?R || cmd == ?L y = -y if cmd == ?B || cmd == ?T end end (xdim + x + 0.5 + (ydim + y - 0.5) * xdim * 2).to_i end
def fold xsize, ysize, cmds raise RuntimeError if cmds.scan(/[^RLBT]/).size.nonzero? raise RuntimeError if 2**cmds.scan(/[RL]/).size != xsize raise RuntimeError if 2**cmds.scan(/[BT]/).size != ysize
(1..(xsize * ysize)).map{|z| unfold(z, cmds)}.reverse end
def usage puts "Usage #{File.basename($0)} <grid sz> <fold list>" puts " grid sz must be power of 2" puts " valid fold are T, B, R, L" puts " you must have enough folds to get NxN to 1x1" exit end
That's a neat way to go about it. That's how I wrote my check_fold--exploring backwards from the final stack, and throwing out paths that were obviously wrong--but I never thought of implementing the entire thing using backwards folds.
On 1/22/06, Simon Kröger <SimonKroe...@gmx.de> wrote:
> i hope there is something new in my solution. Rather than folding my > solution unfolds and keeps track of the position of a certain layer. It > starts with a 1x1 stack of paper and undos all cmds that leed to this > stack (doubling the size of the paper each step). Doing this for every > layer of the stack gives the solution to this quiz. (no arrays, > matrixes, etc. needed except for returning the result)
It supports square grids of all size, the size is "autodetected" from the length of the fold string.
Dominik
# A simple 2D array, the width and height are immutable once it is created. class Array2D attr_reader :w, :h def initialize(w, h, init_array = nil) @w, @h=w, h @array = init_array || [] end def [](x, y) @array[(y%h)*w+(x%w)] end def []=(x, y, v) @array[(y%h)*w+(x%w)]=v end end
class GridFold attr_reader :grid
# the initial grid will be (2**n)x(2**n) def initialize(n = 4) d = 1 << n @grid = Array2D.new(d, d, (1..(d*d)).map { |i| [i] }) end
def fold_t fold_help(@grid.w, @grid.h / 2) { |x, y, _, nh| @grid[x, nh-1-y].reverse + @grid[x, nh+y] } end def fold_b fold_help(@grid.w, @grid.h / 2) { |x, y, _, _| @grid[x, @grid.h-1-y].reverse + @grid[x, y] } end def fold_l fold_help(@grid.w / 2, @grid.h) { |x, y, nw, _| @grid[nw-1-x, y].reverse + @grid[nw+x, y] } end def fold_r fold_help(@grid.w / 2, @grid.h) { |x, y, _, _| @grid[@grid.w-1-x, y].reverse + @grid[x, y] } end
def self.fold(folds_str) folds = folds_str.to_s.downcase n = folds.size / 2 unless folds =~ /\A[tblr]*\z/ && folds.size == n * 2 raise "invalid argument" end gf = self.new(n) folds.scan(/./) { |f| gf.send("fold_#{f}") } gf.grid[0, 0] end
Vladimir Agafonkin wrote: >Of four solutions submitted so far, Luke's performs the best (2 times >better than the nearest neighbour - mine) - and the code is very clear >and easy to understand for a newbie like me. Great work!
Wow, that's excellent. I would have thought that the prepending ("unshift") I do would have slowed things down. But I do reuse all the arrays wherever possible, and that probably makes the difference.
Now I'm working on a variant of Greg Seidman's approach. It should be lots faster yet, but the tradeoff is it's much less clear.
Good, though your solution is still not THAT slower then Greg's:
C:\eclipse\workspace\quizes\other>fold_luke.rb Each operation will run 1000 times. 2x2 sheet folding done in 0.2 seconds 4x4 sheet folding done in 0.491 seconds 8x8 sheet folding done in 1.282 seconds 16x16 sheet folding done in 3.915 seconds
C:\eclipse\workspace\quizes\other>fold_greg.rb Each operation will run 1000 times. 2x2 sheet folding done in 0.381 seconds 4x4 sheet folding done in 0.581 seconds 8x8 sheet folding done in 1.071 seconds 16x16 sheet folding done in 2.744 seconds
PS: I tried using memoize library to evaluate the performance boost, and the results are quite interesting:
(with memoize) Each operation will run 1000 times. 2x2 sheet folding done in 0.02 seconds 4x4 sheet folding done in 0.01 seconds 8x8 sheet folding done in 0.02 seconds 16x16 sheet folding done in 0.03 seconds 32x32 sheet folding done in 0.04 seconds 64x64 sheet folding done in 0.1 seconds 128x128 sheet folding done in 0.341 seconds 256x256 sheet folding done in 1.372 seconds
(without) Each operation will run 1000 times. 2x2 sheet folding done in 0.241 seconds 4x4 sheet folding done in 0.56 seconds 8x8 sheet folding done in 1.703 seconds 16x16 sheet folding done in 5.818 seconds (didn't go further, the things are already clear enough)
Gregory Seidman wrote: >On Sun, Jan 22, 2006 at 10:55:44PM +0900, Luke Blanshard wrote: >[...] >} I can't help feeling there should be a direct numerical way to >} calculate this sequence. To study the sequence, I wrote a second >} script, also attached, that prints the bits of the resulting sequence >} from any given rectangle dimensions and list of folds. (I subtract one >} from the sequence to make it zero-based.) However, even with a fair >} amount of studying lists of bit patterns I haven't cracked the code.
>In fact, there is a very nice direct numerical way to calculate it. There >are a few key facts/insights: ...
I see your insights, and raise you a couple.
* If you associate the XOR masks with the folds, ie arranging them in an array whose size is the number of folds, then you can choose which mask to use for a given output element by indexing into this array. The order of these indexes is like this: 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, ... If this looks familiar, it is because it is related to counting in binary arithmetic. * The folds quickly and easily determine the bottom grid square: just translate them to bits, with the forward folds (T and L) being 1 and backwards ones being 0, and then arrange the bits with the vertical folds' bits on top. * The XOR of the first and last elements of the answer is the last mask in our array of masks.
With all of this, I have a solution that generates the output in sequence without any simulation of folding, or generating extraneous arrays. And it was easy to turn this into an unfolder as well.
The downside is that it is just as long as my original solution, and it is completely incomprehensible. But I bet it's plenty fast!
# Creates XOR masks for the folds, generates the sequence directly. def fold2 h, v, folds hbits, vbits = folds.count("LR"), folds.count("TB") raise "Illegal folds #{folds}" unless hbits+vbits == folds.length raise "Folds imply #{1<<hbits}x#{1<<vbits}, not #{h}x#{v}" unless 1<<hbits == h && 1<<vbits == v hmask, vmask = (1 << hbits) - 1, (1 << vbits) - 1 masks, final_h, final_v = [], 0, 0 folds.split(//).each do |fold| if fold =~ /[LR]/ masks << hmask; hmask /= 2 final_h = final_h*2 + (fold=="L"?1:0) else masks << (vmask << hbits); vmask /= 2 final_v = final_v*2 + (fold=="T"?1:0) end end answer = [(n = (final_v<<hbits|final_h) ^ masks[-1]) + 1] while true i = answer.length.top_changed_bit return answer if i >= masks.length answer << (n ^= masks[i]) + 1 end end
# Takes a sequence generated by folding, reproduces the fold # instructions (as best as possible) by recreating the masks. def unfold seq nfolds = seq.size.log2 mask = (seq[0]-1) ^ (seq[1]-1) hbits = ((mask.odd??mask : mask^((1<<nfolds)-1)) + 1).log2 hfolds, vfolds = [], [] final = seq[-1] - 1 (0...hbits).each{|bit| hfolds.push(final[bit].odd?? "L":"R")} (hbits...nfolds).each{|bit| vfolds.push(final[bit].odd?? "T":"B")} folds = "" i = 1 while i < seq.size mask = (seq[i-1]-1) ^ (seq[i]-1) folds.insert( -1, (mask.odd??hfolds:vfolds).pop ) i *= 2 end folds end
class Integer # Returns the number of the top bit that changed from self-1 def top_changed_bit; (self^(self-1)).log2 end def log2 raise "Domain error" if (n=self) <= (answer=0) while n > 1: answer += 1; n /= 2 end answer end def odd?; return self[0] == 1 end end
require "fold"
# Main program if $0 == __FILE__ h, v, folds = get_args a2 = fold2 h, v, folds a = fold h, v, folds raise "New folder returned\n #{a2.inspect}\nwhile old one returned\n #{a.inspect}" unless a == a2 unfolds = unfold a raise "Unfolding returned #{unfolds}" unless unfolds == folds or unfolds.tr("TBLR","LRTB") == folds p a p unfolds end