Greed dice game exercise from Ruby Koans



One of the Learn Ruby Koans exercise is about implementing a method that calculate the score of the Greed dice game.



A friend reviewed my solution pointing out some conditional expressions that could be avoided (from 3 they are zero now), some state that could be removed (greed_roll_scores is calculated and never changed now), and in the way of the refactoring some duplication (2 similar rules of the games now are both applied with a unique common logic) become evident and I removed it.

Here is the resulting score method, I left also the comments with the Greed game description and the original tests:
- http://pastie.org/3146621


How good is this solution?
Again my friend suggested to see how easy is to read (you judge this then) and how easy is to extend with new features.
Well a good design, is emergent, is not required to and do not predict/anticipate future features (YAGNI).
Instead when a new rule is similar to the existing ones, it should be easier/faster then before to implement.
And when a new rule is completely different, well here is where you cannot and should not even try to predict and anticipate; the more you can add new unpredictable rules just adding/extending code and without throwing away the existing code, the more the design is good.


Here there are new rules that I didn't know when I implemented the code in the first place. I can try to add to the initial implementation of the score method:
- http://en.wikipedia.org/wiki/Greed_(dice_game)


The first 4 new rules (4-of-a-kind, 5-of-a-kind and 6-of-a-kind) are similar to the existing rules (3-of-a-kind), let see how easy is to extend the implementation:
- http://pastie.org/3146856
Quite well: only a small change of the existing score method implementation is needed.

The last 2 new rules (a straight and three couples) are quite different to the existing rules, let see how easy is to extend the implementation:
- http://pastie.org/3146991
Quite well: only a small addition of the previous score method implementation. No evidence from here that the design is bad.





Happy to hear your comments and see others solutions




Update: a reflection suggested by Riccardo while discussing off-line is about splitting the logic of each rule in a separate method and having the score method that apply the set of rules. This way make it easier to add a new rule: just define the new rule in a method and add it to the rules collection in score method.
This is the result: http://pastie.org/3151265

Update: a new version inspired by Matteo solution https://gist.github.com/1617603
and here the related unit tests https://gist.github.com/1725633

Ruby custom and automatic attribute accessors

The automatic one:

class Foo
  attr_accessor :name
 
  def initialize
    @name = "no name"
  end
end


The custom one:

class Foo
  def initialize
    @name = "no name"
  end

  def name
    @name
  end
 
  def name= value
    @name = value
  end
end



Ruby lambdas and each and enumerators


When I define and assign a lambda like this

my_lambda = lambda{ |key, value| puts key, value }

can I call an array or hash each method that return an enumerator and pass my lambda as body of the each,

{ :one=>1, :two=> 2 }.each my_lambda

like this ?


Honestly I felt the lack of an interactive debugger and of a tool/reflector to dig into the each method implementation here.
A more experienced Ruby programmer could tell me where to find them probably.


That call gave me an error, wrong number of parameters (1 for 0) in the each call.
With some memory of C++ syntax I tried this then

{ :one=>1, :two=> 2 }.each &my_lambda

This call gave me a new error, wrong number of parameters (1 for 2) in the block call.
Mmmh so maybe my_lambda need to fulfill a specific signature with one parameter, but what kind of parameter ?
So I tried to investigate it with this:

tell_me_who_you_are_lambda_parameter = lambda{ |arg| puts argarg.class }
{ :one=>1, :two=> 2 }.each &tell_me_who_you_are_lambda_parameter


And so I got the answer:  [:one, 1] Array [:two, 2] Array The parameter is a two element array that contains the key-value pair.
Enough to solve the initial problem, just need to rewrite my_lambda and call it properly like this:

my_lambda = lambda{ |pair| puts pair[0], pair[1] }
{ :one=>1, :two=> 2 }.each &my_lambda


One solution found. Are there more ?


Update: 
Jacopo comments made it clear that the call &my_lambda with 2 arguments work well in 1.8.7.
And Riccardo found and explained me off-line that in 19.3 it do not work because argument passing to blocks, lambdas in this case, has changed and become more strict.
This made it clear to me the source of the problem. Kristoffer suggested off-line to describe the problem with a test, what a great idea! So I did:  http://pastie.org/3149861

Thanks everyone for the precious help



Ruby Koans and Ruby idioms


At the http://www.ruby-lang.org/ have found funny ways to start learning Ruby with examples and small code exercises, a very practical approach.

Ruby in Twenty Minutes has been an enjoyable start, also Hackety Hack! that remember me ProfStef from Smalltalk land.

Then I was ready to start with The Ruby Koans, a way to look a little deeper in to the language driven by unit tests, great and funny !!!


After that I investigated more Ruby idioms, http://cbcg.net/talks/rubyidioms/ & http://stackoverflow.com/questions/613985/common-ruby-idioms, some of them related to more advanced or esoteric language features, that you would live perfectly without the 99.99% of the times and that can make the code hard to read and understand.
Still I feel the need to explore the boundaries of the territory to get more comfortable with a language and than stick with the easy to read features.



Update 18 August 2012
More Ruby idioms:
- http://renaud.waldura.com/doc/ruby/idioms.shtml
- http://devblog.avdi.org/2012/05/07/a-ruby-conversion-idiom/

Update 4 October 2012
Ruby conventions:
- http://rubyist.info/