On Sunday 05 December 2004 05:53 pm, Pit Capitain wrote:
| Hi all,
|
| here's another solution. When I read the quiz my first thought was about
| using regular expressions. So I first tried to extend gsub! to work both
| horizontally as well as vertically through a multi-line string. As others,
| I too had to solve some unexpected hurdles. I hope you find this version
| interesting.

Very intersting approach, Capitain. I had thought something like this would be 
but wasn't sure how to approach. In general a 2d "Sheet of Paper" String 
would be a useful class in general. I'd like to take your beginnings of such  
and build a dedicated class. Are you interested?

T.

| Regards,
| Pit
|
|
| class Array
|
|    # converts a two-dimensional array into a multi-line string
|    def to_s2
|      map { |row| "#{row}\n" }.join
|    end
|
|    # inserts successive elements from other array between every two
|    # elements of this array
|    def weave other
|      inject [] do |array, element|
|        array << other.shift unless array.empty?
|        array << element
|      end
|    end
|
|    # weaves the rows of two two-dimensional arrays, see weave
|    def weave2 other
|      zip( other ).map { |row1, row2| row1.weave row2 }
|    end
|
| end
|
|
| class String
|
|    # splits a multi-line string into a two-dimensional array of
|    # character strings
|    def to_a2
|      map { |row| row.chomp.split // }
|    end
|
|    # transposes a multi-line string like a two-dimensional array
|    def transpose
|      to_a2.transpose.to_s2
|    end
|
|    # in-place form of transpose
|    def transpose!
|      replace transpose
|    end
|
|    # like gsub!, but works both horizontally and vertically in a
|    # multi-line string
|    def gsub2! re, subst
|      result1 = gsub! re, subst
|      transpose!
|      result2 = gsub! re, subst
|      transpose!
|      self if result1 || result2
|    end
|
|    # like Array#weave2, using multi-line strings
|    def weave other
|      to_a2.weave2( other.to_a2 ).to_s2
|    end
|
| end
|
|
| # input patterns
| FILLED = "X"
| LETTER = "_"
|
| # intermediate patterns
| NUMBER = "N"
| OUTSIDE = "O"
| LINE = "#"
| EMPTY = " "
|
| # search patterns
| OUT_OR_EDGE = /^|#{OUTSIDE}|$/
| BEFORE_NEW_WORD = /^|#{OUTSIDE}|#{FILLED}/
| WORD = /#{LETTER}|#{NUMBER}/
|
|
| # removes spaces from input
| def remove_spaces
|    @s.gsub!( / /, "" )
| end
|
| # marks outside cells (filled cells adjacent to edges or outside cells)
| def mark_outside_cells
|    nil while \
|      @s.gsub2!( /#{FILLED}(#{OUT_OR_EDGE})/, "#{OUTSIDE}\\1" ) or \
|      @s.gsub2!( /(#{OUT_OR_EDGE})#{FILLED}/, "\\1#{OUTSIDE}" )
| end
|
| # marks beginnings of words
| def number_beginnings
|    @s.gsub2! /(#{BEFORE_NEW_WORD})#{LETTER}(#{WORD})/, "\\1#{NUMBER}\\2"
| end
|
| # creates a pattern of delimiters between non-outside cells
| def delimiters s, delimiter, space, gsub_method = :gsub!
|    r = s.dup
|    r.send gsub_method, /^/, OUTSIDE
|    r.send gsub_method, /[^#{OUTSIDE}\n]/, delimiter
|    r.send gsub_method, /#{OUTSIDE}(?=#{delimiter})/, delimiter
|    r.send gsub_method, OUTSIDE, space
|    r
| end
|
| # duplicates every cell line, removing number marks
| def duplicate_cell_lines
|    index = 0
|    @s = @s.inject do |result, row|
|      index += 1
|      result << row
|      result << row.gsub( NUMBER, LETTER ) if index % 2 == 1
|      result
|    end
| end
|
|
| # read layout
| @s = ARGF.read
|
| # process the layout
| remove_spaces
| mark_outside_cells
| number_beginnings
|
| # delimiting lines and corners
| v = delimiters @s, LINE, EMPTY
| h = delimiters( @s.transpose, FILLED, LETTER ).transpose
| c = delimiters @s, LINE, EMPTY, :gsub2!
|
| # combine layout and delimiters
| vs = v.weave @s
| ch = c.weave h
| @s = ch.transpose.weave( vs.transpose ).transpose
|
| # format the result
| duplicate_cell_lines
| num = 0
| @s.gsub! /./ do |char|
|    case char
|    when OUTSIDE, LETTER then "    "
|    when FILLED then "####"
|    when NUMBER then "%-4i" % ( num += 1 )
|    else char
|    end
| end
|
| # output the result
| puts @s

-- 
( o _  елеще┴
 //    trans.
/ \    transami / runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

[8,16,20,29,78,65,2,14,26,12,12,28,71,114,12,13,12,82,72,21,17,4,10,2,95].
each_with_index{|x,i| $><<(x^'Begin landing your troops'[i]).chr}
-Tadayoshi Funaba