usable in any place a human can be used

20091002

ruby koans

EdgeCase's Ruby Koans are a great way to get started with the Ruby programming language. I've worked through them once before and have had some free time at work so decided to work through them again.


The quality of the koans are normally excellent, there are a few times where a comment is left in the code to make you think, and you really wish that there was an answer key somewhere. There are also what look like a few errors in the code


In about_sandwich_code.rb, the find_line and find_line2 functions don't seem to make much sense. You would imagine a function would find a line matching a given regular expression, but the regular expression is hardcoded to /e/ which doesn't seem very realistic. This is the original.


[ruby]
def find_line(file_name)
file = open(file_name)
while line = file.gets
return line if line.match(/e/)
end
ensure
file.close if file
end
[/ruby]

A more realistic function would be


[ruby]
def find_line(file_name, regex)
file = open(file_name)
while line = file.gets
return line if line.match(regex)
end
ensure
file.close if file
end
[/ruby]

I'm sure this was done to simplify the exercise, but it violates the rule of least surprise by adding magic functionality to the function.


In the last function of about_scoring_project.rb, named test_score_of_mixed_is_sum, the first assert reads


[ruby] assert_equal 50, score([2, 5, 2, 2, 3]) [/ruby]

The rules of the game clearly specify that


[ruby]
# * A set of three numbers (other than ones) is worth 100 times thenumber. (e.g. three fives is 500 points).
# ...
# * A five (that is not part of a set of three) is worth 50 points.
[/ruby]

This means that the score should be 200 (for the set of three 2's) + 50 (for the 5) = 250. The first assert should be changed to


[ruby] assert_equal 250, score([2, 5, 2, 2, 3]) [/ruby]

If you are interested in learning ruby, this is an indispensable way to learn not just the syntax, but to get the flavor, and to start thinking in ruby.


Expand this block of source to see my solution


[ruby collapse="true"]
def score(dice)
result = 0
counter = {}
(1..6).each { |x| counter[x] = 0 }
dice.each { |d| counter[d] += 1 }
if counter[1] >= 3
result += 1000
counter[1] -= 3
end

(2..6).each do |x|
if counter[x] >= 3
result += (100 * x)
counter[x] -= 3
end
end

result += (counter[1] * 100)
result += (counter[5] * 50)
end
[/ruby]


5 comments:

  1. [...] Post about things you’ve actually done, that’s how this blog started wanting to share my experiences doing ruby [...]

    ReplyDelete
  2. [...] a few times before, but nothing too serious (if you look back in the archives you will see that my first post was on ruby [...]

    ReplyDelete
  3. My impression is that is a set of three numbers in a row.
    In the case of this Koan the three 2 are not in a row and that is why they have no value.

    ReplyDelete
  4. [...] had my first post back on October 2nd of last year, as of writing this 112 days ago. At that point I didn’t [...]

    ReplyDelete
  5. Nice solution! My only suggestion is this:

    counter = Hash.new(0)

    ... so that you don't need the next line of setting them all to 0.

    ReplyDelete