Thursday, February 17

Spares vs. strikes (take 2)

So... spares vs. strikes is a hot issue for some people, in bowling.  So how about if we make tracking them be a requirement?

Now, instead of being some kind of strange coding artifact, they need to be a part of the result.  This also means that our previous result (the total score) is no longer an acceptable result.  Instead, let's say that we need a running total of the score for each frame, along with an indication of whether the frame was open, a spare, or a strike.

Now, I could start over from scratch here, but I am not inclined to do so.  This seems like an easy change to make, so let's just jump right in:

assert (10#"0 'open';0) -: bowlingScores 20#0

In other words, I want
   bowlingScores 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
to give me the result
+----+----+----+----+----+----+----+----+----+----+
|open|open|open|open|open|open|open|open|open|open|
+----+----+----+----+----+----+----+----+----+----+
|0   |0   |0   |0   |0   |0   |0   |0   |0   |0   |
+----+----+----+----+----+----+----+----+----+----+

(Note that I am using ascii boxes here, rather than line drawing characters, because in my experience some browser implementations do the wrong thing with line drawing characters. Yes, ascii is ugly. But it is ubiquitous.)

  bowlingScores=:3 :0
   i=.0
   frameType=.frameScore=.''
   while.(i<#y) *. 10>#frameScore do.
    bonus=. 10 = +/\ 2{.i}. y
    frameType=.frameType, #.bonus
    frameScore=.frameScore ,+/(2++./bonus){.i}.y
    i=. i+2-10=i}y
   end.
   (frameType { ;:'open spare strike') ,: ]&.> +/\frameScore
  )

This next test also succeeds, so that is probably good enough?

assert ((,: +each/\)/10#"0'strike';30) -: bowlingScores 12#10

Here, I was looking for:

   (,: +each/\)/10#"0'strike';30
+------+------+------+------+------+------+------+------+------+------+
|strike|strike|strike|strike|strike|strike|strike|strike|strike|strike|
+------+------+------+------+------+------+------+------+------+------+
|30    |60    |90    |120   |150   |180   |210   |240   |270   |300   |
+------+------+------+------+------+------+------+------+------+------+

Since that test all by itself is getting a bit complicated (and because @RonJefferies suggested it might be a good idea), I should take time here to explain what I am doing:

The phrase 10#"0'strike';30 works the same way that the previous phrase (10#"0'strike';30) worked.  I am just replicating each item into a list of ten copies.  Meanwhile the / operator puts the verb on its left between each item of the array on its right.  In this case that means:

   (10#<'strike')  (,: +each/\) (10#<30)

That (,: +each/\) is a hook, which means that the left verb combines the left argument (10 copies of the box containing the word 'strike') with the result of the right verb on the right argument (the individually boxed running sum of 10 copies of the number 30).

And, no, that implementation of bowlingScores was not quite good enough:

   bowlingScores 10 1 0 6 3 10 0 6 4 2 10 6 4 1 0 1 3
|index error: bowlingScores

The problem, here, is that when i=5, I am computing 10=+/\10 0 which is equivalent to 10=10 10 which gives me a result of 1 1, and #. 1 1 is 3.  But my list of frame types only has 3 elements: 0: open, 1: spare, 2: strike.

I could deal with this by adding a fourth 'strike' element to that list.  Or, I could deal with it by preventing the result obtained from #.bonus from ever being larger than 2.

But, also, my implementation of bowlingScores was a bit unwieldy, with no modularity between the (hypothetically useful) computational code and the (perhaps dubious) presentation code.  So perhaps I should refactor it:

 bScores=:3 :0
  i=.0
  frames=.i.0 2
  while.(i<#y) *. 10>#frames do.
   bonus=. 10 = +/\ 2{.i}. y
   frames=. frames, (2<.#.bonus) ,+/(2++./bonus){.i}.y
   i=. i+2-10=i}y
  end.
  (,: +/\)/|:frames
 )

 bowlingScores=:3 :0
   types=. ;:'open spare strike'
   ((types{~{.),: [:]&.>{:) bScores y
 )

Here, bScores does all the work, and bowlingScores just repackages that to match my (somewhat arbitrary) test oriented representation.  And, it also works when I have a strike followed by a gutter ball:

   bScores 10 1 0 6 3 10 0 6 4 2 10 6 4 1 0 1 3
 2  0  0  2  0  0  2  1  0  0
11 12 21 41 47 53 73 84 85 89

   bowlingScores 10 1 0 6 3 10 0 6 4 2 10 6 4 1 0 1 3
+------+----+----+------+----+----+------+-----+----+----+
|strike|open|open|strike|open|open|strike|spare|open|open|
+------+----+----+------+----+----+------+-----+----+----+
|11    |12  |21  |41    |47  |53  |73    |84   |85  |89  |
+------+----+----+------+----+----+------+-----+----+----+

I did not have an explicit test result I was checking here -- just running the code was test enough.  I think that that is an appropriate test, sometimes.

Perhaps next up would be to track down a full set of specifications about how scoring machines work, in bowling alleys, and add requirements so that the scoring routine could represent game progress at any point in a game.  In other words, we would want an adjacent turky count, a done indicator, as well as indicators for incomplete spares and incomplete spikes, and perhaps other requirements.  (But probably leave out the timer that shuts down your lanes if you take too long, since that can be imposed independently of the scoring system.)

Tuesday, February 15

spares vs. strikes

One objection that apparently is significant, in the context of bowling scorers, is the "spares" vs. "strikes" issue.  Some people are taught that the rule for how you score spares is different from the rule for how you score strikes.

And, in fact, it is different, though the difference is entirely superficial:

With a spare, your score is the score of a two ball frame and the ball after it.  With a strike, your score is the score of a one ball frame and the two balls after it.  In both cases, the complete frame has a score of 10.  In both cases, the relevant score is the total score of three balls.

In other words, instead of:

score=:3 :0
i=.0
score=.''
while.(i<#y) *. 10>#score do.
bonus=. 10 e. +/\ 2{.i}. y
score=.score, +/(2+bonus){.i}.y
i=. i+2-10=i}y
end.
+/score
)

apparently, some people would prefer:

score=:3 :0
i=.0
score=.''
while.(i<#y) *. 10>#score do.
if.    10= i{y       do. score=. score,+/3{.i}.y
elseif.10= +/2{.i}.y do. score=. score,+/3{.i}.y
elseif.1             do. score=. score,+/2{.i}.y
end.
i=. i+2-10=i}y
end.
+/score
)

Now... I have seen a lot of code messed up by micro-management specifications from people that did not understand what they were asking.  So I am wary of a process which allows for these kinds of changes.

Nevertheless, "the customer is always right", so if someone pays extra, I can see writing code like this.

But coding to address someone else's lack of understanding is probably the wrong approach. We have better ways of helping people understand, starting with documentation.

Also, do you change the code again, when the person understands it?  How do you deal with a different person with different misunderstandings?  How do you deal with harsh misunderstandings, which will not allow correctly functioning code?

These are not non-issues, not by any means.  But just because we have a hammer does not mean we need to treat all issues like nails.

TDD Bowling and J


Intro: This was written in response to a suggestion by (@RonJeffries) that someone present a test driven design example in J. I doubt I am the best person to be writing such things, but I thought I would give it a shot.

Using http://xprogramming.com/articles/scala-bowling-i-think/ as a pattern, the implementation code follows the tests which the code is expected to satisfy, and each implementation should satisfy all of the preceding tests.

assert 0 -: score 20$0

assert 90 -: score 20$4 5

score=: +/


In other words, for simple games, we just add up the scores from each ball.

assert 22 -: score 20$6 4 5 2

spareBonus=: 0 0, _1}. 10= 2 +/\ ]
score=: +/ .* (1 + spareBonus)


In other words:



   (2 +/\ ]) 6 4 5 2 0 0
10 9 7 2 0


we find the pairwise sums, then then we find the cases which are equal to ten, shift them over a bit, and use that to multiply the scores from balls that follow spare frames.

assert 31 -: score 20 {. 10 5 2 7

strikeBonus=: [: +/ _1 _2 |.!.0"0 1=&10
score=: +/ .* (1 + spareBonus + strikeBonus)


Here, we are doing something similar, but we do not need pairwise sums to find strikes, =&10 is good enough.  On the other hand, we need to give strikes two bonus balls, so we shift that result into two different positions:



   (_1 _2 |.!.0"0 1=&10) 10 5 2 7 0 0
0 1 0 0 0 0
0 0 1 0 0 0
   ([: +/ _1 _2 |.!.0"0 1=&10) 10 5 2 7 0 0
0 1 1 0 0 0


assert 300 -: score 12$10

Problem: we need a frame structure, and none of the implementations so far has cared about frames.  A simple way to implement frames involves a while loop.  Each time through the loop we can decide where the next frame starts:  

score=:3 :0
i=.0
score=.''
while.(i<#y) *. 10>#score do.
bonus=. 10 e. +/\ 2{.i}. y
score=.score, +/(2+bonus){.i}.y
i=. i+2-10=i}y
end.
+/score
)


Note that to determine if we have a spare or a strike we always examine two balls, looking for the possibility that all the pins got knocked down before the end of the frame.  Anyways, we wind up with three possibilities:


strike: first ball 10, frame size 1, frame score based on 3 balls
spare: first and second balls sum to 10, frame size 2, frame score based on 3 balls
open: first and second balls sum to less than 10, frame size 2, frame score based on 2 balls


But this code looks so very different from the previous iterations.  What happened here?

One issue, I think, is that the tests lead me to add features before developing the structure that was needed for those features to make sense. So, I was happily computing simple sums, when we all know that those would never be suitable. And then, when faced with a perfect game, I decided to bite the bullet write something to deal with the frames.

That said, this code does look cleaner than the implementation at https://docs.google.com/document/pub?id=16sicMNkODy-zeE1pkTtDWYd3x374g-Htx1XcXq96b9c and as an added bonus, it passes all my randomly selected tests there.

One of the benefits of using J, is that it’s fairly trivial to re-architect a program when the architecture is in expressions rather than in control structures. However, that benefit does not appear very useful here, and may even be something of a hazard for this style of development, but that could also be my lack of practice.

Nevertheless, the core "sum" mechanism is present, in some form, in all of these implementations.

Finally, if you were building a scoring machine, you would want an event driven scorer (though a variation on this monolith could work in the event handler, recomputing "the entire game so far" after each ball).

See also:


Well now...

I am dusting off this blog based on a suggestion by @angelaharms (see next entry). I have not taken a lot of time to study what I left here from earlier, but I hope its not too obnoxious or offensive.

Originally, this was just a bunch of impulsive rants, I just dusted this blog off because it was the easiest of my blogs for me to find.