I use Seb Rose description as it is simple and efficient.
Given a letter, print a diamond starting with ‘A’ with the supplied letter at the widest point.
For example: print-diamond ‘C’ prints
I heard a lot about this kata. Recently1, it was the main subject of a two hours workshop at the awesome NCrafts conference.
So long time after the initial battle2, I decided to give it a try.
Well, as usual, when I’m told that something is difficult or impossible, I just don’t care and do it as I will have if no one told me anything.
So I apply TDD as I usually do: red, green, refactor. And that’s all.
Write a test, make it pass, clean the code. One step at a time.
the first test
So let’s start with the first test.
Test is Red, it’s time to make it go to green :
Yep, that’s a stupid implementation. But it works :)
And quite clean by itself. So let’s add another test.
a second test
And make it pass stupidly.
And it’s green, so it’s time to refactor.
But I can’t see duplication yet.
Well, there are twice the same “ A “ line in the ‘B’ diamond. But I can’t give a meaning to it. I probably don’t have enough data.
So, I’ll keep things like that for now, and add a third test.
and the third
As I try to be coherent, my way to make it green won’t differ from the previous one :)
Yep, again that is a stupid implementation.
Because at this moment I don’t care being clever, doing nice, clean things. At this moment I just want to be sure that the test I wrote is the one I intended to write.
By making it goes green with a simple solution, there are very few risks I introduced a mistake in the implementation. So when I see the test goes from red to green, I can be confident on my test.
That’s my way to test my tests.
So now, I may have enough materials to see if I can make some interesting things appear.
time to start refactoring
There should be some logic in the letters and spaces distribution.
As I don’t understand it yet, I will artificially separate them. Yes, I’m going to create kind of artificial duplication.
Now I can notice that first and last lines are z spaces - A - z spaces.
If a diamond ‘A’ has a size of 1, ‘B’ of 2, ‘C’ 3 and so on, then z = (size - 1)
Great, lets put that logic in a method.
I also notice that other lines follow the same pattern : x spaces - a char - y spaces - same char - x spaces
So lets make that appear in the code.
There is definitely something that tie everything, but i don’t see it yet.
a fourth test
Let’s add the D diamond. I won’t show you the test, it the same than previous but with a D diamond.
Make it pass by adding this in our current solution.
From now, I will only show you the refactoring on the D diamond.
All those integers must have some kind of relationship. Maybe we can figure it by rearranging them.
Let’s introduce the width of the diamond: it’s the
I draw some diamond on a paper and manage to figure quite rapidly that the width is size * 2 - 1
Well, I think I got it. Let make appear a floor level.
Yes, every lines really look like the same now, we can give it a name.
That’s better, but we are not done yet.
There is a pattern in these calls. Let’s see what append if we renumber floors so they become a sequence, from +size to -size
Well, there seems to have a loop hidden there. The problem to introduce it are those characters in the parameters of diamondWall call.
But we can easily get rid of them as the character used in a floor can be compute from the size of the diamond and the current floor.
As I usually do I’ve made things with very small steps in order to keep my test green all the time.
I tried to let the algorithm emerge from the refactoring, and not the opposite.
Of course, it did not emerge by itself. With that kind of problem, I had in mind that there will be some kind of loop in the solution. So my refactorings aimed to make that loop appears: introducing deliberate duplication so that each line looks the same, then unifying indices.
Introducing one change at a time allow my test to be very efficient in helping me to find the errors I’ve made4.
The full code is available on my github. Look in the branches :)5
Once there, if it was real code, I will probably give name to size -2 and -(size - 2). Maybe attic and cellar to stick with the building metaphore. And size should probably become height.
I also don’t really like the use of a Character everywhere will in fact it is a kind of diamond. So i’ll introduce a DiamondKind class to hold the Character and size6, width calculation. Maybe other Character operations too7.