Ruby Koans

Ben sent me a link to Ruby Koans today. These “Koans” are a kind of learn-by-doing approach to learning ruby.

Each problem is set up as part of a test-driven framework that requires you to make the tests pass by filling in the answers.

An example:

def test_combining_hashes
  hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
  new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })

  assert_not_equal hash, new_hash
    
  expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ }
  assert_equal expected, new_hash
end

This was a great way to spend a couple of hours and learn some of the deeper secrets of the ruby language.

Oh, and if you have a problem running the problems in 1.9.1, specifically the following:

C:\ruby_koans>rake
(in C:/ruby_koans)
cd koans
C:/Ruby19/bin/ruby.exe path_to_enlightenment.rb
C:/ruby_koans/koans/edgecase.rb:33:in `<class:Sensei>': uninitialized constant T
est::Unit::AssertionFailedError (NameError)
        from C:/ruby_koans/koans/edgecase.rb:30:in `<module:EdgeCase>'
        from C:/ruby_koans/koans/edgecase.rb:29:in `<top (required)>'
        from C:/ruby_koans/koans/about_asserts.rb:4:in `require'
        from C:/ruby_koans/koans/about_asserts.rb:4:in `<top (required)>'
        from path_to_enlightenment.rb:3:in `require'
        from path_to_enlightenment.rb:3:in `<main>'
rake aborted!
Command failed with status (1): [C:/Ruby19/bin/ruby.exe path_to_enlightenme...]

(See full trace by running task with --trace)

You need to run:

gem install test-unit

The test-unit gem is no longer included in the Ruby installer.

Euler Problem 17 in Ruby

After hearing about Ben’s motivation trouble with problem 17, I realized that I only had fun on that problem because I saw a rather fun algorithm. Since I’m rather proud of it, I’m going to show off the code here.

ones = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
tens = ["", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
hundred = "hundred"
and_ = "and"
thousand = "thousand"

sum = ""
1.upto(1000) do |i|
  curr = i
  out = ""
  if (curr > 999) then
    out += ones[curr/1000] + thousand
    curr = curr%1000
  end
  if (curr > 99) then
    out += ones[curr/100] + hundred
    curr = curr%100
    out += and_ if curr != 0
  end
  if (curr >= 20) then
    out += tens[curr/10]
    curr = curr%10
    out += ones[curr]
  else 
    out += ones[curr]
  end
  sum += out
end
puts sum.length

# Over 50 trials:
# Mean:	17.3689 ms
# Median: 16.5885 ms

I’m particularly proud of this code because I don’t have to convert the numbers into an array, and it’s blazing fast, even in ruby.

Code Club: Ruby Week 1

So my coworker Ben and I keep trying to keep people interested in learning and tinkering with languages.  So far we’ve explored python, scala, and f#.  Scala and F# seemed to have scared off most of our attendees, so we’re trying to reign it back into the mainstream by exploring Ruby.  For this first week, attendees are to do whatever Euler problems they are comfortable doing, as long as they do them in Euler.

Since I’ve done the first 20 or so Euler problems in all of the above languages, I was able to power through the first ten problems in Ruby pretty quickly.  I also used the opportunity to mess around with mercurial.  I originally wanted to use git and github, but the windows version of git is fairly opaque to me.  I set up an online repository for my Ruby exploration on intuxication. You can peer through the repository here: http://mercurial.intuxication.org/hg/rubyeuler/

I can’t wait until Wednesday to share how clever I feel, so I’m going to share a couple snippets that I feel especially pleased about.

maxprod = 0
999.downto(100) {|i| 
  999.downto(100) {|j|
    maxprod = [i * j, maxprod].max if ((i * j).to_s == (i * j).to_s.reverse)
  }}
puts maxprod

The whole creating an array of two items to grab the maximum is cool, but the if statement negating the previous expression makes things simultaneously easier to read and confusing to my traditional Java brain.

class Array
  def prod
    inject do |prod,x| prod ? prod * x : x end
  end
end

n = 2
arr = []

while (n <= 20)
  currn = n
  arr.each {|i| currn /= i if currn % i == 0}
  arr << currn
  n+=1
end

puts arr.prod

The real “wow” moment I had here was the fact that you could extend existing classes without actually creating a whole new class. “Redefining” a class just adds/overwrites the things that you put in your newly written class definition. Totally blew my mind.

jon.com.org.net is using WP-Gravatar