[QUIZ] One-Liners (#113)

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!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

···

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

This week's Ruby Quiz is in pop quiz format. For each of the scenarios below,
send in a one line (80 characters or less) solution that performs the task. You
may use any legal Ruby syntax including require statements and semicolons, but
the goal in finesse more than golfing.

Any input described in the problem is in a local variable called quiz.
Assigning to this variable is assumed to have happened earlier in the program
and is not part of your submitted solution.

Your line just needs to evaluate to the expected result. You do not have to
store the result in a variable or create any output.

Any edge cases not covered by the provided examples are left to your best
judgement.

* Given a Numeric, provide a String representation with commas inserted between
each set of three digits in front of the decimal. For example, 1999995.99
should become "1,999,995.99".

* Given a nested Array of Arrays, perform a flatten()-like operation that
removes only the top level of nesting. For example, [1, [2, [3]]] would become
[1, 2, [3]].

* Shuffle the contents of a provided Array.

* Given a Ruby class name in String form (like
"GhostWheel::Expression::LookAhead"), fetch the actual class object.

* Insert newlines into a paragraph of prose (provided in a String) so lines will
wrap at 40 characters.

* Given an Array of String words, build an Array of only those words that are
anagrams of the first word in the Array.

* Convert a ThinkGeek t-shirt slogan (in String form) into a binary
representation (still a String). For example, the popular shirt "you are dumb"
is actually printed as:

  111100111011111110101
  110000111100101100101
  1100100111010111011011100010

* Provided with an open File object, select a random line of content.

* Given a wondrous number Integer, produce the sequence (in an Array). A
wondrous number is a number that eventually reaches one, if you apply the
following rules to build a sequence from it. If the current number in the
sequence is even, the next number is that number divided by two. When the
current number is odd, multiply that number by three and add one to get the next
number in the sequence. Therefore, if we start with the wondrous number 15, the
sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2,
1].

* Convert an Array of objects to nested Hashes such that %w[one two three four
five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.

Sounds like fun,
Now the stupid question of the day: will a comment before the line be a
problem for your tools, I guess they are counting :wink:

Cheers
Robert

···

On 2/9/07, Ruby Quiz <james@grayproductions.net> wrote:

The three rules of Ruby Quiz:

<snip>

--
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important
things.
-Anonymous

So, does the quiz variable that we're getting have to remain unmodified, or
does it matter?

* Given a wondrous number Integer, produce the sequence (in an Array). A
wondrous number is a number that eventually reaches one, if you apply the
following rules to build a sequence from it. If the current number in the
sequence is even, the next number is that number divided by two. When the
current number is odd, multiply that number by three and add one to get
the next
number in the sequence. Therefore, if we start with the wondrous number
15, the
sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8,
4, 2,
1].

One final question: you say "given a wondrous number"... does this mean that
the input is guaranteed to be wondrous, and we therefore don't need to check
it, or does the solution need to include a check to make sure that it is
indeed a wondrous number?

Here are a few more test cases, both to help others and to be sure
that mine is right:

def test_wondrous( str )
  maps = [
    [1, [1]],
    [3,[3,10,5,16,8,4,2,1]],
    [5,[5,16,8,4,2,1]],
    [8,[8,4,2,1]],
    [15,[15,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]],
    [31,
[31,94,47,142,71,214,107,322,161,484,242,121,364,182,91,274,137,412,206,103,310,155,466,233,700,350,175,526,263,790,395,1186,593,1780,890,445,1336,668,334,167,502,251,754,377,1132,566,283,850,425,1276,638,319,958,479,1438,719,2158,1079,3238,1619,4858,2429,7288,3644,1822,911,2734,1367,4102,2051,6154,3077,9232,4616,2308,1154,577,1732,866,433,1300,650,325,976,488,244,122,61,184,92,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]]
  ]
  raise "Solution too long (#{str.length} characters)" unless
str.length <= 80
  maps.each{ |pair|
    quiz = pair[0]
    expected = pair[1]
    output = eval( str )
    unless expected==output
      raise "quiz=#{quiz}; expected #{expected.inspect}, got
#{output.inspect}"
    end
  }
end

···

On Feb 9, 10:00 am, Ruby Quiz <j...@grayproductions.net> wrote:

* Given a wondrous number Integer, produce the sequence (in an Array). A
wondrous number is a number that eventually reaches one, if you apply the
following rules to build a sequence from it. If the current number in the
sequence is even, the next number is that number divided by two. When the
current number is odd, multiply that number by three and add one to get the next
number in the sequence. Therefore, if we start with the wondrous number 15, the
sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2,
1].

More test cases:
def test_commify( str )
  maps = [
    [1, "1"],
    [-1, "-1"],
    [0.001, "0.001"],
    [-0.001, "-0.001"],
    [999, "999"],
    [-999, "-999"],
    [999.1, "999.1"],
    [-999.1, "-999.1"],
    [999.12, "999.12"],
    [-999.12, "-999.12"],
    [999.123, "999.123"],
    [-999.123, "-999.123"],
    [9999, "9,999"],
    [-9999, "-9,999"],
    [9999.1, "9,999.1"],
    [-9999.1, "-9,999.1"],
    [9999.12, "9,999.12"],
    [-9999.12, "-9,999.12"],
    [9999.123, "9,999.123"],
    [-9999.123, "-9,999.123"],
    [12, "12"],
    [123, "123"],
    [1234, "1,234"],
    [12345, "12,345"],
    [123456, "123,456"],
    [1234567, "1,234,567"],
    [12345678, "12,345,678"],
    [-12, "-12"],
    [-123, "-123"],
    [-1234, "-1,234"],
    [-12345, "-12,345"],
    [-123456, "-123,456"],
    [-1234567, "-1,234,567"],
    [-12345678, "-12,345,678"]
  ]
  raise "Solution too long (#{str.length} characters)" unless
str.length <= 80
  maps.each{ |pair|
    quiz = pair[0]
    expected = pair[1]
    output = eval( str )

    unless expected==output
      raise "quiz=#{quiz}; expected #{expected.inspect}, got
#{output.inspect}"
    end
  }
end

···

On Feb 9, 10:00 am, Ruby Quiz <j...@grayproductions.net> wrote:

* Given a Numeric, provide a String representation with commas inserted between
each set of three digits in front of the decimal. For example, 1999995.99
should become "1,999,995.99".

Yet more test cases (and a new way that I'm testing them). Used like:
s = 'your 80 char solution here'
test_solution( :flatten_once, s )

def test_solution( map_set, str )
  raise "Solution too long (#{str.length} chars)" unless str.length <=
80
  maps = MAPS[ map_set ]
  maps.each{ |pair|
    quiz = pair[0]
    expected = pair[1]
    output = eval( str )

    unless expected==output
      raise "quiz=#{quiz}; expected #{expected.inspect}, got
#{output.inspect}"
    end
  }
end

MAPS = {
  :commify => [
    [1, "1"],
    [-1, "-1"],
    [0.001, "0.001"],
    [-0.001, "-0.001"],
    [999, "999"],
    [-999, "-999"],
    [999.1, "999.1"],
    [-999.1, "-999.1"],
    [999.12, "999.12"],
    [-999.12, "-999.12"],
    [999.123, "999.123"],
    [-999.123, "-999.123"],
    [9999, "9,999"],
    [-9999, "-9,999"],
    [9999.1, "9,999.1"],
    [-9999.1, "-9,999.1"],
    [9999.12, "9,999.12"],
    [-9999.12, "-9,999.12"],
    [9999.123, "9,999.123"],
    [-9999.123, "-9,999.123"],
    [12, "12"],
    [123, "123"],
    [1234, "1,234"],
    [12345, "12,345"],
    [123456, "123,456"],
    [1234567, "1,234,567"],
    [12345678, "12,345,678"],
    [-12, "-12"],
    [-123, "-123"],
    [-1234, "-1,234"],
    [-12345, "-12,345"],
    [-123456, "-123,456"],
    [-1234567, "-1,234,567"],
    [-12345678, "-12,345,678"]
  ],

  :flatten_once => [
    [ [], [] ],
    [ [1], [1] ],
    [ [1,2], [1,2] ],
    [ [1,[2]], [1,2] ],
    [ [[1],2], [1,2] ],
    [ [[1,2]], [1,2] ],
    [ [1,2,3], [1,2,3] ],
    [ [1,[2,3]], [1,2,3] ],
    [ [[1,2,3]], [1,2,3] ],
    [ [1, [2, [3]]], [1, 2, [3]] ],
    [ [1, [[2], 3]], [1, [2], 3] ],
    [ [1,[2,[3,[4]]]], [1, 2, [3,[4]]] ],
    [ [[[[[[6]]]]]], [[[[[6]]]]] ]
  ],

  :wondrous => [
    [1, [1]],
    [3,[3,10,5,16,8,4,2,1]],
    [5,[5,16,8,4,2,1]],
    [8,[8,4,2,1]],
    [15,[15,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]],
    [31,
[31,94,47,142,71,214,107,322,161,484,242,121,364,182,91,274,137,412,206,103,310,155,466,233,700,350,175,526,263,790,395,1186,593,1780,890,445,1336,668,334,167,502,251,754,377,1132,566,283,850,425,1276,638,319,958,479,1438,719,2158,1079,3238,1619,4858,2429,7288,3644,1822,911,2734,1367,4102,2051,6154,3077,9232,4616,2308,1154,577,1732,866,433,1300,650,325,976,488,244,122,61,184,92,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]]
  ]

}

···

On Feb 9, 10:00 am, Ruby Quiz <j...@grayproductions.net> wrote:

* Given a nested Array of Arrays, perform a flatten()-like operation that
removes only the top level of nesting. For example, [1, [2, [3]]] would become
[1, 2, [3]].

I wasn't able to get down to less than 80 chars on two of the items.
For commaizing numbers and getting a random line from a file (assuming
loading the whole file into memory is against the rules) I think I was
just barking up the wrong path. I like my nested hash solution (which
I wrote in both golf and non-golf modes.

# Commaize (works for both floats and integers)
a=quiz.to_s.split('.');a[0].reverse.gsub(/
(\d{3})/,'\1,').chomp(',').reverse+"#{'.'+a[1] if a[1]}"

# Flatten once
a=[];quiz.each{|i| if i.is_a? Array;i.each{|j| a<<j};else;a<<i;end};a

# Randomize array (the obvious way)
quiz.sort_by {rand}

# Class from String (fails for some)
begin eval "#{quiz}.allocate.class" rescue nil end

# Wrap lines (no newline at the end!)
a='';b=quiz;until b.size<=40;a<<b.slice!(0..b.rindex(' ',
40))<<"\n";end;a<<b

# Find anagrams
quiz.find_all {|x| x.split('').sort == quiz[0].split('').sort}

# Binarize
a=''; quiz.each_byte {|b| a << (b == 32 ? "\n" : "%b" % b)}; a

# Random line (kludge, reads the whole file twice)
f=quiz;c=0;f.each{c+=1};r=rand(c)+1;f.pos=0;c=0;a='';f.each{|line|c
+=1;a=line if c==r};a

# Wondrous sequence
b=quiz;a=[b];while b>1;if b%2==1;b=3*b+1;else;b=b/2;end;a<<b;end;a

# Nested hash (golf and non-golf, and my best answer (I think))
a=quiz.pop;quiz.reverse_each{|i|a={i=>a}};a
hash = quiz.pop; quiz.reverse_each { |item| hash = { item => hash } };
hash

Thanks for the good time.

Basic test case attached, code should be stuffed in one_liner.rb for
tests to pass. Solutions are class methods that take a parameter
usually not named 'quiz' :stuck_out_tongue:

I probably could have got smaller solutions with inject instead of
more manual iteration, but they are all under 80, so I'm happy leaving
them as is.

- Jamie

class OneLiner; class << self
  # Convert to string, work backwards from . (or end of string) to add commas
  def commaize(number)
    s = number.to_s; while s.gsub!(/^(-?\d+)(\d{3})([,.]\d+|$)/,
'\1,\2\3'); end; s
  end

  # Single elements appended to array, arrays added together
  def flatten_once(ary)
    a = []; ary.each{|e| e.kind_of?(Array) ? a += e : a << e }; a
  end

  # Random sort, block evaluates to 1, 0, or -1.
  def shuffle(ary)
    ary.sort{|a,b|1-rand(3)}
  end

  # Traverse class hierarchy looking up constant names
  def get_class(name)
    name.split("::").inject(Object){|klass, name| klass.const_get(name)}
  end

  # Find up to 40 chars including the space, and add a \n following.
  def wrap_text(paragraph)
    paragraph.gsub(/(.{1,39}( |$))/, "\\1\n")
  end

  # Sort the first word's chars, if current word's chars sort same, is anagram
  def find_anagrams(words)
    word = words.shift.split(//).sort; words.select{|w|w.split(//).sort == word}
  end

  # Unpack char as 8bit binary, but only grab the (important) last 7 bits
  # Would likely be easier with a sprintf %7b
  def binarize(slogan)
    slogan.split('
').map{|w|w.unpack('B8'*w.size).map{|b|b[1..7]}.join}.join("\n")
  end

  # Split lines, grab one at random
  def random_line(file)
    lines = file.read.split("\n"); lines[rand(lines.size)]
  end

  # Generate sequence, terminating on a 1
  def wondrous_sequence(n)
    a = [n]; while n != 1; n = (n%2>0) ? n*3+1 : n/2; a << n; end; a
  end
  # Recursive version, using a lambda for the recursive function
  def wondrous_sequence_r(n)
    r=lambda{|i| i==1 ? [1] : [i] + r.call((i%2>0) ? i*3+1 : i/2)}; r.call(n)
  end

  # Pop keys off the end of the array, create a new hash around it
  def nested_hash(ary)
    hsh = ary.pop; while key = ary.pop; hsh = {key => hsh}; end; hsh
  end
  # Recursive version, using a lambda for the recursive function
  def nested_hash_r(ary)
    r=lambda{|a|a.size == 1 ? a.first : {a.shift => r.call(a)}}; r.call(ary)
  end
end; end

test_one_liner.rb (4.08 KB)

#In all of this, +i+ is the input. Some solutions don't behave exactly the
same as the requested sample output, and some are too long. I think I
noted all such instances.

# * Given a Numeric, provide a String representation with commas inserted between
# each set of three digits in front of the decimal. For example, 1999995.99
# should become "1,999,995.99".

#this takes 83 characters
a=i.to_s.split('.');a[0]=a[0].reverse.scan(/.{1,3}/).join(',').reverse;a.join('.')

# * Given a nested Array of Arrays, perform a flatten()-like operation that
# removes only the top level of nesting. For example, [1, [2, [3]]] would become
# [1, 2, [3]].

i.inject([]){|cur,val| Array===val ? cur+val : cur << val}
#or
i.inject([]){|cur,val| cur+val rescue cur << val}
#(cur+val throws an error if val isn't an array)

# * Shuffle the contents of a provided Array.

i.inject([]){|cur,val| cur.insert(rand(cur.length+1),val)}

# * Given a Ruby class name in String form (like
# "GhostWheel::Expression::LookAhead"), fetch the actual class object.

eval(i)
#or
i.split("::").inject(Object){|c,v| c.const_get(v)}

# * Insert newlines into a paragraph of prose (provided in a String) so
# lines will wrap at 40 characters.

#clearly doesn't fit within 80 characters
i.split.inject([[]]){|r,w| (r[-1].inject(0){|a,b| a+b.size}+w.size)<40 ? r[-1] << w : r << [w]; r}.map{|x| x.join(' ')}.join("\n")

# * Given an Array of String words, build an Array of only those words
# that are anagrams of the first word in the Array.

i.select{|x| x.split(//).sort==i.first.split(//).sort}

# * Convert a ThinkGeek t-shirt slogan (in String form) into a binary
# representation (still a String). For example, the popular shirt "you are dumb"
# is actually printed as:

···

On Sat, 10 Feb 2007 02:00:03 +0900, Ruby Quiz wrote:
#
# 111100111011111110101
# 110000111100101100101
# 1100100111010111011011100010

i.unpack("B*")[0]
#this doesn't give me the same answer that you gave me though
#or
r="";i.each_byte{|x| r << x.to_s(2)};r

# * Provided with an open File object, select a random line of content.
x=i.readlines;x[rand(x.length)]
#or
i.find{rand<.0005 || i.eof?}
#the rules didn't say anything about the random distribution used.
#adjust the threshold as necessary

# * Given a wondrous number Integer, produce the sequence (in an Array). A
# wondrous number is a number that eventually reaches one, if you apply the
# following rules to build a sequence from it. If the current number in the
# sequence is even, the next number is that number divided by two. When the
# current number is odd, multiply that number by three and add one to get the next
# number in the sequence. Therefore, if we start with the wondrous number 15, the
# sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2,
# 1].

r=[i];while i!=1 do r << (i= i%2==0?i/2:i*3+1); end; r

#
# * Convert an Array of objects to nested Hashes such that %w[one two three four
# five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.

#neither of these gives the same answer asked for here
p=lambda{|h,k| h[k] = Hash.new(&p)};z=Hash.new(&p);i.inject(z){|ha,co|ha[co]};z
#or
z={};i.inject(z){|ha,co| ha[co]={}};z

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Hi,

I liked this quiz. Bite sized pieces I could attempt between chasing kids :slight_smile:

Here's what I came up with. Note that #6 is just a bit over the 80 char limit.

Cheers,
Dave

TEXT_FILE= '/Users/sharon/Documents/Dave/RubyQuiz/english.txt'

#* Given a Numeric, provide a String representation with commas inserted between
#each set of three digits in front of the decimal. For example, 1999995.99
#should become "1,999,995.99".
puts "-- 01 --"
quiz="1234567.89"
# soln
a=quiz.gsub(/(\d)(?=\d{3}+(\.\d*)?$)/,'\1,')
# \soln
puts a

#* Given a nested Array of Arrays, perform a flatten()-like operation that
#removes only the top level of nesting. For example, [1, [2, [3]]] would become
#[1, 2, [3]].
puts "\n-- 02 --"
quiz= [3, [4, 5], [2, [3]], [3, [4, 5]]]
# soln
a=quiz.inject([]){|a,q|a[a.size..a.size]=q;a}
# \soln
puts a.inspect

#* Shuffle the contents of a provided Array.
puts "\n-- 03 --"
quiz=(1..20).entries
# soln
1.upto(50){x=rand(quiz.size);quiz[x],quiz[0]=quiz[0],quiz[x]}
# \soln
puts quiz.inspect

#* Given a Ruby class name in String form (like
#"GhostWheel::Expression::LookAhead"), fetch the actual class object.
puts "\n-- 04 --"
require 'ostruct'
quiz= "OpenStruct"
# soln
a= eval(quiz).new
# \soln
puts a.class

#* Insert newlines into a paragraph of prose (provided in a String) so lines will
#wrap at 40 characters.
puts "\n-- 05 --"
puts "---------|---------|---------|---------|"

quiz= "* Insert newlines into a paragraph of prose (provided in a String) so lines will wrap at 40 characters."
# soln
a= quiz.gsub(/.{1,40}(?:\s|\Z)/){$&+"\n"}
# \soln
puts a

#* Given an Array of String words, build an Array of only those words that are
#anagrams of the first word in the Array.
puts "\n-- 06 --"
quiz= %w[cat dog tac act sheep cow]
# soln
a=[];quiz[1...quiz.size].each{|x|a<<x if quiz[0].split(//).sort==x.split(//).sort}
# /soln
puts a.inspect

#* Convert a ThinkGeek t-shirt slogan (in String form) into a binary
#representation (still a String). For example, the popular shirt "you are dumb"
#is actually printed as:

···

#
# 111100111011111110101
# 110000111100101100101
# 1100100111010111011011100010
puts "\n-- 07 --"
quiz= "you are dumb"
# soln
quiz.unpack('c*').each{|c| print c==32 ? "\n" : "%b"%[c]};
# /soln

#* Provided with an open File object, select a random line of content.
puts "\n\n-- 08 --"
quiz= File.open(TEXT_FILE)
# soln
x=[];quiz.each{|line|x<<line};puts x[rand(x.size)];quiz.close
# \soln

#* Given a wondrous number Integer, produce the sequence (in an Array). A
#wondrous number is a number that eventually reaches one, if you apply the
#following rules to build a sequence from it. If the current number in the
#sequence is even, the next number is that number divided by two. When the
#current number is odd, multiply that number by three and add one to get the next
#number in the sequence. Therefore, if we start with the wondrous number 15, the
#sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2,
#1].
puts "\n-- 09 --"
quiz=[15]
# soln
a=quiz.last; while a>1; quiz << (a=a%2==0 ? a/2 : a==1 ? 1 : a*3+1) end
# \soln
puts quiz.inspect

#* Convert an Array of objects to nested Hashes such that %w[one two three four
#five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.
puts "\n-- 10 --"
quiz= %w[one two three four five]
# soln
a=quiz.reverse[1...quiz.size].inject(quiz.last){|b,c| {c=> b}}
# \soln
puts a.inspect

My solutions. Be gentle, this is my first quiz :slight_smile: I haven't checked these against any of the test cases that were posted, but I think a couple of them are interesting.

# Commify numbers.
def one(quiz)
   quiz.to_s.reverse.gsub(/(\d{3})(?=\d)/,'\1,').reverse
end

# Commify numbers again, but ignore any before the decimal point.
def one_alternate(quiz)
a,b=quiz.to_s.split('.');[a.reverse.gsub(/(\d{3})(?=\d)/,'\1,').reverse,b].join('.')
end

# One-level flatten().
def two(quiz)
   r=[];quiz.each{|a|r+=[*a]};r
end

# Array shuffling the noddy way.
def three(quiz)
   r={};quiz.each{|a|r[a]=nil};r.keys
end

# Array shuffling the proper way.
def three_alternate(quiz)
   r=[];quiz.size.times{r<<quiz.delete_at(rand(quiz.size))};r
end

# Getting classes from strings.
def four(quiz)
   quiz.split('::').inject(Object){|m,r|m=m.const_get(r)}
end

# Line wrapping.
def five(quiz)
   r='';quiz.size.times{|i|r<<quiz[i].chr;i%40==39?r<<"\n":1};r
end

# Finding anagrams.
def six(quiz)
(c=quiz.map{|a|[a,a.split('').sort.join]}).select{|b|b[1]==c[0][1]}.map{|d|d[0]}
end

# Binary strings.
def seven(quiz)
   quiz.split(' ').map{|s|s.unpack('B*')[0][1..-1]}*$/
end

# Random lines.
def eight(quiz)
   (a=quiz.readlines)[rand(a.size)]
end

# Wondrous numbers
def nine(quiz)
   a=quiz;r=[a];r<<(a=a%2==0?a/2:1+a*3)while a!=1;r
end

# Hash construction
def ten(quiz)
   (a = quiz.pop;quiz).reverse.inject(a){|m,r| m = {r => m}}
end

···

--
Alex

class OneLiner
class << self
   def commaize(quiz)
     quiz.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/, '\1,').reverse
   end

   def flatten_once(quiz)
     t=[];quiz.each{|x|(Array===x)?x.each{|y|t<<y}:t<<x};t
   end

   def shuffle(quiz)
     quiz.sort{rand(2)}
   end

   def get_class(quiz) #this one was really hard to figure out.
     name.split("::").inject(Object){|klass, name|klass.const_get(name)}
   end

   def wrap_text(quiz)
     quiz.gsub(/(.{1,40})( +|$\n?)|(.{1,40})/, "\\1\\3\n")
   end

   def find_anagrams(quiz)
     t=[];quiz[1..-1].each{|v|(v.scan
(/./).sort==quiz[0].scan(/./).sort)?t<<v:nil};t
   end

   def binarize(quiz)
     s='';quiz.split.each{|v|v.each_byte{|x|s<<'%b'%x};s<<"\n"};s
   end

   def random_line(quiz)
     s='';quiz.readlines.each{|v|rand(2)==0?eval('s=v;break'):s=v};s
   end

   def wondrous_sequence(quiz)
     t=[quiz];until quiz==1;t<<(quiz=(quiz%2==0?quiz/2:quiz*3+1));end;t
   end

   def nested_hash(quiz)

h={};t=h;quiz[0..-3].each{|v|t[v]={};t=t[v]};t.store(quiz[-2],quiz[-1]);h
   end
end
end

I don't have any tools. Someone should build a test suite and post it though, if they feel motivated to do so.

For my solutions though, I put the questions as comments before each solution.

James Edward Gray II

···

On Feb 9, 2007, at 1:40 PM, Robert Dober wrote:

On 2/9/07, Ruby Quiz <james@grayproductions.net> wrote:

The three rules of Ruby Quiz:

<snip>

Sounds like fun,
Now the stupid question of the day: will a comment before the line be a
problem for your tools, I guess they are counting :wink:

Either way is fine with me.

James Edward Gray II

···

On Feb 9, 2007, at 3:01 PM, Luke Ivers wrote:

So, does the quiz variable that we're getting have to remain unmodified, or
does it matter?

Never mind.

···

On 2/9/07, Luke Ivers <technodolt@gmail.com> wrote:

>
> * Given a wondrous number Integer, produce the sequence (in an
Array). A
> wondrous number is a number that eventually reaches one, if you apply
the
> following rules to build a sequence from it. If the current number in
the
> sequence is even, the next number is that number divided by two. When
the
> current number is odd, multiply that number by three and add one to get
> the next
> number in the sequence. Therefore, if we start with the wondrous number
> 15, the
> sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8,
> 4, 2,
> 1].
>
One final question: you say "given a wondrous number"... does this mean
that
the input is guaranteed to be wondrous, and we therefore don't need to
check
it, or does the solution need to include a check to make sure that it is
indeed a wondrous number?

Correct.

James Edward Gray II

···

On Feb 9, 2007, at 3:10 PM, Luke Ivers wrote:

* Given a wondrous number Integer, produce the sequence (in an Array). A
wondrous number is a number that eventually reaches one, if you apply the
following rules to build a sequence from it. If the current number in the
sequence is even, the next number is that number divided by two. When the
current number is odd, multiply that number by three and add one to get
the next
number in the sequence. Therefore, if we start with the wondrous number
15, the
sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8,
4, 2,
1].

One final question: you say "given a wondrous number"... does this mean that
the input is guaranteed to be wondrous, and we therefore don't need to check
it...

MAPS = {
  :commify => [
    [1, "1"],
    [-1, "-1"],
    [0.001, "0.001"],
    [-0.001, "-0.001"],
    [999, "999"],
    [-999, "-999"],
    [999.1, "999.1"],
    [-999.1, "-999.1"],
    [999.12, "999.12"],
    [-999.12, "-999.12"],
    [999.123, "999.123"],
    [-999.123, "-999.123"],
    [9999, "9,999"],
    [-9999, "-9,999"],
    [9999.1, "9,999.1"],
    [-9999.1, "-9,999.1"],
    [9999.12, "9,999.12"],
    [-9999.12, "-9,999.12"],
    [9999.123, "9,999.123"],
    [-9999.123, "-9,999.123"],
    [12, "12"],
    [123, "123"],
    [1234, "1,234"],
    [12345, "12,345"],
    [123456, "123,456"],
    [1234567, "1,234,567"],
    [12345678, "12,345,678"],
    [-12, "-12"],
    [-123, "-123"],
    [-1234, "-1,234"],
    [-12345, "-12,345"],
    [-123456, "-123,456"],
    [-1234567, "-1,234,567"],
    [-12345678, "-12,345,678"]
  ],

  :flatten_once => [
    [ [], [] ],
    [ [1], [1] ],
    [ [1,2], [1,2] ],
    [ [1,[2]], [1,2] ],
    [ [[1],2], [1,2] ],
    [ [[1,2]], [1,2] ],
    [ [1,2,3], [1,2,3] ],
    [ [1,[2,3]], [1,2,3] ],
    [ [[1,2,3]], [1,2,3] ],
    [ [1, [2, [3]]], [1, 2, [3]] ],
    [ [1, [[2], 3]], [1, [2], 3] ],
    [ [1,[2,[3,[4]]]], [1, 2, [3,[4]]] ],
    [ [[[[[[6]]]]]], [[[[[6]]]]] ]
  ],

  :wondrous => [
    [1, [1]],
    [3,[3,10,5,16,8,4,2,1]],
    [5,[5,16,8,4,2,1]],
    [8,[8,4,2,1]],
    [15,[15,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]],
    [31,
[31,94,47,142,71,214,107,322,161,484,242,121,364,182,91,274,137,412,206,103,310,155,466,233,700,350,175,526,263,790,395,1186,593,1780,890,445,1336,668,334,167,502,251,754,377,1132,566,283,850,425,1276,638,319,958,479,1438,719,2158,1079,3238,1619,4858,2429,7288,3644,1822,911,2734,1367,4102,2051,6154,3077,9232,4616,2308,1154,577,1732,866,433,1300,650,325,976,488,244,122,61,184,92,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]]
  ]

}

  # Built-in classes for testing #4
  :class_from_string => [
    ["OpenSSL", OpenSSL ],
    ["OpenSSL::Digest", OpenSSL::Digest ],
    ["OpenSSL::Digest::DigestError", OpenSSL::Digest::DigestError ],
  ],

Some interesting edge cases, assuming that exactly 40 characters may
fit on a line:
(My one-liner still doesn't handle the 2nd and 3rd ones)

MAPS[ :paragraph_wrapping ] = [
  [ "One\nTwo\nThree", "One\nTwo\nThree" ],

  [ "It's the end of the world as we know it.",
    "It's the end of the world as we know it." ],

  [ "It is the end of the world as we know it",
    "It is the end of the world as we know it" ],

  [ "It is the end of the world as we know it and I feel fine.",
    "It is the end of the world as we know it\nand I feel fine." ],

  [ "It's the end of the world as we know it, and I feel fine.",
    "It's the end of the world as we know it,\nand I feel fine." ],

  [ "It is the end of the world as we know it, and I feel fine.",
    "It is the end of the world as we know\nit, and I feel fine." ],

  [ "It is not the end of the world as we know it, and I feel fine.",
    "It is not the end of the world as we\nknow it, and I feel
fine." ]
]

I wasn't able to get down to less than 80 chars on two of the items.
For commaizing numbers and getting a random line from a file (assuming
loading the whole file into memory is against the rules) I think I was
just barking up the wrong path. I like my nested hash solution (which
I wrote in both golf and non-golf modes.

# Commaize (works for both floats and integers)
a=quiz.to_s.split('.');a[0].reverse.gsub(/
(\d{3})/,'\1,').chomp(',').reverse+"#{'.'+a[1] if a[1]}"

Too long: 96 characters (but I couldn't get it under 80 either)

# Flatten once
a=[];quiz.each{|i| if i.is_a? Array;i.each{|j| a<<j};else;a<<i;end};a

# Randomize array (the obvious way)
quiz.sort_by {rand}

# Class from String (fails for some)
begin eval "#{quiz}.allocate.class" rescue nil end

# Wrap lines (no newline at the end!)
a='';b=quiz;until b.size<=40;a<<b.slice!(0..b.rindex(' ',
40))<<"\n";end;a<<b

# Find anagrams
quiz.find_all {|x| x.split('').sort == quiz[0].split('').sort}

# Binarize
a=''; quiz.each_byte {|b| a << (b == 32 ? "\n" : "%b" % b)}; a

# Random line (kludge, reads the whole file twice)
f=quiz;c=0;f.each{c+=1};r=rand(c)+1;f.pos=0;c=0;a='';f.each{|line|c
+=1;a=line if c==r};a

89 characters

···

On Sun, 11 Feb 2007 09:55:59 -0800, Chris Shea wrote:

# Wondrous sequence
b=quiz;a=[b];while b>1;if b%2==1;b=3*b+1;else;b=b/2;end;a<<b;end;a

# Nested hash (golf and non-golf, and my best answer (I think))
a=quiz.pop;quiz.reverse_each{|i|a={i=>a}};a
hash = quiz.pop; quiz.reverse_each { |item| hash = { item => hash } };
hash

Thanks for the good time.

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/