We just did our third coding dojo today. Just to keep things interesting, we did it in Ruby this time. The whole thing has been done on a Mac with TextMate.
The topic we set off to implement was a game of darts. More specifically, what combination of throws gets you to win if you have to throw a 2, or a 3, or a 4, ...
The constraints are:
- a single throw can score 1..20 singled, doubled or tripled. Center is 50.
- you can only throw 3 darts
- the last throw has to be a double or a 50
Keep in mind that (except for me) noone had ever written any Ruby. Noone had ever programmed on a mac (that means there is no HOME, INSERT, CTRL-C/V working). Even with these limitations, within 1h30, we got a good parial solution working:
- single throw solutions up to 40 (double 1 for 2, double 2 for 4, double 3 for 6, ... double 20 for 40).
- two darts thrown with a single score on the first throw.
These are the tests we got working.
A game of darts with a remainig score of 2
- has 1 winning combination
- wins with 'dubbel 1'
A game of darts with a remaining score of 3
- has 1 winning combination
- wins with '1, dubbel 1'
A game of darts with a remaining score of 4
- has 2 winning combinations
- wins with 'dubbel 2'
- wins with '2, dubbel 1'
A game of darts with a remaining score of 6
- has 3 winning combinations
- wins with '2, dubbel 2'
- wins with '4, dubbel 1'
- wins with '2, dubbel 2'
A game of darts with a remaining score of 40
- wins with 'dubbel 20'
A game of darts with a remaining score of 41
- wins with '1, dubbel 20'
A game of darts with a remaining score of 42
- wins with '2, dubbel 20'
A game of darts with a remaining score of 60
- wins with '20, dubbel 20'
The tests were written in RSpec, and run with autotest. Everyone agreed that autotest is really a fun way to get instant feedback on what effect you're having on the code every time you change a tiny amount of code.
This is what a typical test would look like:
describe "A game of darts" do
before(:each) do
@game = GameOfDarts.new
end
context "with a remainig score of 2" do
before(:each) do
@game.score 2
end
it "has 1 winning combination" do
@game.winning_combinations.length.should == 1
end
it "wins with 'dubbel 1'" do
@game.winning_combinations.should include "dubbel 1"
end
...
And this is what our implementation looks like (after some cleaning up):
class GameOfDarts
def score value
@score = value
@combinations = []
calculate_combinations
end
def winning_combinations
@combinations
end
def calculate_combinations
half_score = @score / 2
(1..half_score).each{ |double_throw| add_combination_for(double_throw) }
end
def add_combination_for double_throw
single_throw = @score - 2 * double_throw
@combinations << format_score(single_throw, double_throw)
end
def format_score first_throw, last_throw
return "dubbel #{last_throw}" if first_throw == 0
"#{first_throw}, dubbel #{last_throw}"
end
end
After the dojo, we held a little retrspective. This is what came out of it:
Keep doing
- Switch programmer every 5 min
- Test driven implementation
- To the audience: SHUT UP!
- 9 of us showed up
- Discovered a new feature of rspec: @game.winning_combinations.should include "dubbel 1"
- booze and food were on site ;-)
- good location
- retrospective
Start doing
- think about the choosen algorithm BEFORE the choice. This excercise was perceived as being too hard for a dojo where both the language, the OS and the editor were new
- doodle the meeting before choosing a date
- invite aliens (java devs typically don't seem to show up)
- do a Prepared Kata for max 15 mins
- timebox the whole session to end at 20:00
- timebox the retrospective
- hand out stickies during the session to prepare retrospective remarks
Stop doing
- going overtime on the 5 minutes limit per developer
