Monday, April 18

(I started this entry with little time, because of a short lunch meeting, and am coming back to it after a weekend, I hope it's not too disjointed. Not that I necessarily need any help, in being disjointed...)

In TDD bowling, and J, revised, part3..., I had said that I wanted to come back and write up something about how J interprets some of that code. But I have had some other thoughts since then, and let's see how this comes out.

First off, here is the code:
 nextFrameIndex=: ] + 1 + 10 > {.@{~
 limitSpares=: ] * 1,.1,.10 <: +/ .*&1 1 0
 bowlingScores=: limitSpares@({~ nextFrameIndex^:(i.10)&0)@(3 ]\ ])@{.~&21

 isScore=: -:&(+/@,) , (10 3 >: $@]) , 2 -: #@$@]
 assert 300 isScore bowlingScores 12#10
 assert 190 isScore bowlingScores 21$9 1
 assert 0 isScore bowlingScores 20$0
 assert 90 isScore bowlingScores 20$8 1

So, here is the vocabulary:

# $ & ( ) * + , ,. -: . / 0 1 1 1 0 10 10 3 12 190 2 20 21 3 300 8 1 9 1 90 <: =: > >: @ \ ] ^: assert bowlingScores i. isScore limitSpares nextFrameIndex { {. ~

That's a bit mixed up though, because a sequence of numbers in J counts as one word. And, yes, this means that you can have a word in J which contains a space. But that in and of itself is not very novel -- most languages will treat a quoted string as a single "token". But in J, you need other words to separate numeric lists. 1 2 + 3 4 would be three words. And, my presentation, above, does not really show word boundaries for numbers (but I have played with bold, to help mark off the different numbers that I used).

Anyways, numbers just represent themselves.

Next, here is an informal rundown on the words as used here. Feel free to skip over it -- it's for referring back to, when I get into examples, in case you feel lost.

This initial summary will be a bit ambiguous, to keep from getting bogged down in details. I will give some examples (later) and references to hopefully help deal with the ambiguities. I will also include links into J's dictionary that might also help.

Monadic verbs (traditional "functions" with their arguments on the right):

   #    Gives the number of items in a list
   +/  derived verb meaning "sum the items in a list"
   ,    Removes any extra structure from an array, turning it into a flat list
   ]    Identity function: its result is its argument
   i.   List of indices: 0 1 2 3 ... with size of result specified by argument
   {.  The first item of a list

   bowlingScores given a list of ball scores from a bowling game, arranges them in rows and columns, with one row for each frame, such that the sum of the entire result will be the score of the game.
   limitSpares given an array representing the frames from a bowling game, makes sure that only the first two balls count when the frame is neither a spare nor a strike (when you have a spare or a strike, you need a sequence of three balls to get the score)

Dyadic verbs (traditional "operations", like +, with arguments on left and right). I will use x as a placeholder for the left argument and y for the right argument.:

   #    Make x copies of y (if they both are sequences pair corresponding elements)
   $    make an x dimensional array from y (keep repeating y as many times as you need)
   *    x*y is x times y  (x1,x2,x3)*(y1,y2,y3) is ((x1*y1),(x2*y2),(x3*y3))
   ,    make a list with the elements from x followed by the elements from y
   ,.   like , but x and y represent columns
   -:    1 when x and y as a whole are identical, 0 otherwise
   <:   1 when an element of x is less than or equal to an element of y, 0 otherwise
   >    1 when an element of x is greater than an element of y, 0 otherwise
   >:   1 when an element of x is greater than or equal to an element of y, 0 otherwise
   ]    right identity: its result is its right argument
   {    elements from y indexed by x
   {.   the prefix of y selected by x (if x is greater than #y, pad the result)
   nextFrameIndex if x is a list of potential frames (or just a list of ball scores), and y is the index of one that we know is a valid frame, the result is the index of the frame after y. 

Adverbs (these modify a verb). I will use u as a placeholder for the verb (which always appears to the left of the adverb):

Adverbs used monadically:
   /    Insert verb between the items of y:  +/1 2 3 gives the result of evaluating 1+2+3

Adverbs used dyadically:
   \    apply u to each of the sublists of y which contain x elements
   ~    swap the arguments:  x u~ y is the same as y u x

Conjunctions (these are combining words that work on verbs, they bind very tightly). I will use u for the left verb and v for the right verb, here. But conjunctions can also consume a noun instead of a verb, so I will use m for a left noun and n for a right noun. Some conjunctions behave very differently with nouns.

   &    When given two verbs, the verb on the right (v) becomes the preprocessor for the verb on the left (u). In the dyadic case, v is used on each argument and those results are combined using u.
   &    When given a verb and a noun, the verb (u or v) is curried with that noun (n or m). The resulting monadic verb looks for its remaining argument on its right.

   .    This is a special conjunction for defining inner products. The usual matrix multiplication inner product is +/ .* (and you have to have a space to the left of the decimal).

   @    When given two verbs, the verb on the left (u) becomes the postprocessor for the verb on the right (v). In the dyadic case, v is used to combine the left and right arguments.

   ^:    The verb on the left (u) gets used repeatedly, the number of times it gets used is specified by the noun on the right (n). If n is 0, y is the result. If n is 1, the verb is used once, just like normal. If n is 2, the verb is used twice with the result of the first evaluation being the right argument for the second evaluation. (In a dyadic context, x will be used, unchanged, for each evaluation). f n is a list of numbers the result has an item corresponding to each element of n.

(Note, by the way, that adverbs and conjunctions in English also tend to be rather contextual in their meanings.)

But enough of this reference stuff, let's get to some examples (if you were skipping over the vocabulary material, here is a good place to stop skipping).

   nextFrameIndex=: ] + 1 + 10 > {.@{~

What does this look like, in action?

   (12$10) (] + 1 + 10 > {.@{~) 7

Um... ok, what did that tell us?

Here, the left argument represents ball scores and the right argument represents an index into them that marks the begining of a frame. The result will be an index either 1 or 2 greater than the right argument. It's 1 greater when the index selects a ball that knocked down 10 pins, otherwise it's 2 greater.

Let's break this down into simpler expressions:

   (12$10) ({~) 7

Here, we are selecting a ball which had a score of 10.

   (12$10) ({.@{~) 7

Here, we are selecting a ball which had a score of 10.

Hey, wait a minute!  What was the point of that extra stuff?

A problem here is that I gave the left argument in a form that the code did not actually use. In "real life" it would have looked more like this:

   (10 3$10) (] + 1 + 10 > {.@{~) 7

In other words, I would have given it 10 rows and each row would represent one frame. So, let's start over:

   (10 3$10) ({~) 7
10 10 10

The eighth frame had three balls and all of them were perfect scores. (As is usual for indices in most modern programming languages the first value is selected by the index 0. Here, "first" would be a cardinal number and "0" an ordinal number.)

   (10 3$10) ({.@{~) 7

The first ball of the eighth frame was a perfect 10.

   (10 3$10) (10 > {.@{~) 7

10 is not greater than the score of the first ball in the eighth frame

   (10 3$10) (1 + 10 > {.@{~) 7

The offset to the beginning of the next frame is 1.

   (10 3$10) (7 + 1 + 10 > {.@{~) 7

The index of the next frame is 1 (that's the ninth frame). Note that here I plugged in the value 7 for the current index. In the real code I instead used the function ] which always has as its value the value of its right argument. In other words:

   (10 3$10) (] + 1 + 10 > {.@{~) 7

The answer is: when we have an odd number of verbs arranged in a isolated train (and the parenthesis here are sufficient to isolate them), the odd ones get the same right argument as the train as a whole. And if the train has a whole has a left argument, all of the odd verbs get that for their left argument also where if the train as a whole has no left argument none of the odd verbs get a left argument.

Meanwhile, the even verbs are combining verbs. They combine the results from the odd verbs (working from right to left, just like J normally does -- and note also that arabic numbers are also designed to work from right to left with the least part on the right).

But wait, so how does that work when you have numbers like 1 and 10 in it?  Those are not verbs!  Those are nouns!!

The answer is:  if we use a noun in the odd positions in what would otherwise be a verb train, we treat them as verbs which always produce themselves as their result. The rightmost word has to be a verb, but the other odd positions can be nouns.

And yes, I can imagine some grumbling about how this odd and even business seems contrived. But it corresponds rather closely to some notation that winds up being used rather often in mathematics. Anyways, that's the way J works.

And, I am out of time again...

Thursday, April 14

r-nd-m: r-nd-m: TDD bowling, and J, revised, part3

This is a continuation of TDD bowling, and J, revised, part 1 and TDD bowling, and J, revised, part 2

I left off with:

 isScore=: -:&(+/@,) , (10 3 >: $@]) , 2 -: #@$@]
 F=: ] + 1 + 10 > {.@{~
 bowlingScores=: ({~ F^:(i.10)&0)@(3 ]\ ])

 assert 300 isScore bowlingScores 12#10
 assert 190 isScore bowlingScores 21$9 1

...and the first thing we need to do is find a better name for F, one that will be useful without having to go back and re-read yesterday's blog.  I'm going to go with nextFrameIndex.

 nextFrameIndex=: ] + 1 + 10 > {.@{~
 bowlingScores=: ({~ nextFrameIndex^:(i.10)&0)@(3 ]\ ])

and with that, I can get on to my next test:

 assert 0 isScore bowlingScores 20#0

This fails:

    assert 0 isScore bowlingScores 20#0
 |index error: bowlingScores
 |   assert 0 isScore     bowlingScores 20#0

My problem here is that I am indexing off the end of my array.  3 ]\ 20$0 has 18 elements but the ninth (and last) invocation of nextFrameIndex will give me 18 as its result, and the largest valid index is 17.

The simple solution here, I think, is to pad out my result so that 18 will always be a valid index.  Since I only have 10 frames (corresponding to 0 through 9 invocations of nextFrameIndex) that should be enough.  And, since I am ultimately adding up the results, padding with zeros will not change the ultimate score.  (And, in fact, I have been planning on using zeros, all along, to deal with an issue that I do not yet have a test for.)

 bowlingScores=: ({~ nextFrameIndex^:(i.10)&0)@(3 ]\ ])@{.~&21

That's good enough for now, though my definition is getting a bit long-winded.  I also have multiple "magic numbers" here.  I am not sure that that is bad, but here they are:

10:  The number of frames in a complete game
21:  The number of balls in the longest possible game
3:   The number of balls in the longest possible frame

I think that that information is interesting enough that I would leave it in a comment in the completed program.

But now we need another test:

   assert 90 isScore bowlingScores 20$8 1

And the current implementation of bowlingScores gives me a score of 162 -- it needs to deal with frame that are neither spares nor strikes.  In other words, if the sum of the first two elements of a frame is less than 10 the third element of my representation of that frame must be a zero.

One approach could be:
   (0&{, 1&{, 2&{ * 10 > 0&{ + 1&{)

For example:

    3 ]\ 7$8 1
 8 1 8
 1 8 1
 8 1 8
 1 8 1
 8 1 8
    (0&{, 1&{, 2&{ * 10 <: 0&{ + 1&{)"1 (3 ]\ 7$8 1)
 8 1 0
 1 8 0
 8 1 0
 1 8 0
 8 1 0

But that is long-winded for what seems like it ought to be a simple concept.  Can we do better?

Well.. one possbility involves multiplication.  From this point of view, we want to multiply each row by either 1 1 1 or 1 1 0, with that last bit depending on the sum of the previous two values.  That previous sum can be expressed as the inner product of 1 1 0 and the three numbers from my potential frame.

In other words, something like this:

    (3 ]\ 7$8 1) +/ .* 1 1 0
 9 9 9 9 9
    10 <: (3 ]\ 7$8 1) +/ .* 1 1 0
 0 0 0 0 0
    1,.1,.10 <: (3 ]\ 7$8 1) +/ .* 1 1 0
 1 1 0
 1 1 0
 1 1 0
 1 1 0
 1 1 0

    (3 ]\ 7$8 1) * 1,.1,.10 <: (3 ]\ 7$8 1) +/ .* 1 1 0
 8 1 0
 1 8 0
 8 1 0
 1 8 0
 8 1 0

    (] * 1,.1,.10 <: ] +/ .* 1 1 0"_) 3 ]\ 7$8 1
 8 1 0
 1 8 0
 8 1 0
 1 8 0
 8 1 0

Except, I have some bad experiences with how people react to expressions of the form: noun"_  Some people do not look at that and see the resemblance to diaeresis and realize that this is a variation on the old "each" operator from APL.  Instead, they see the double quotes and wonder why I have an unterminated string constant.

I could avoid that kind of reaction be rephrasing:

   (] * 1,.1,.10 <: +/ .*&1 1 0) 3 ]\ 7$8 1
8 1 0
1 8 0
8 1 0
1 8 0
8 1 0

Here, I have curried the inner product (+/ .*) with the vector 1 1 0 (on its right).  That derives a verb which only needs one argument, which will appear on the right. And, that is a slight be more concise than my previous expression so I think I will use this variation.

(People also react badly to my "unbalanced brackets".  They do not see them as left and right identity functions but as some unknown construct that would satisfy rules for some other programming language.  But I find myself often using them, with no better alternatives.)

   limitSpares=:  ] * 1,.1,.10 <: +/ .*&1 1 0
   bowlingScores=: limitSpares@({~ nextFrameIndex^:(i.10)&0)@(3 ]\ ])@{.~&21

And that satisfies my current set of tests

Is that getting too long?

   #'bowlingScores=: limitSpares@({~ nextFrameIndex^:(i.10)&0)@(3 ]\ ])@{.~&21'

I think I can live with a 73 character long line.  But if it were much longer, I would be feel I should refactor that definition.  As it is, I would not reject a refactoring.  But I do not feel like doing that right now.

So, here is my current set of definitions:

 NB. 10:  The number of frames in a complete game
 NB. 10:  The highest possible score with one ball
 NB. 21:  The number of balls in the longest possible game
 NB. 3:   The number of balls in the longest possible frame
 NB. 2:   The number of dimensions in the desired result (frames and balls)

 nextFrameIndex=: ] + 1 + 10 > {.@{~
 limitSpares=: ] * 1,.1,.10 <: +/ .*&1 1 0
 bowlingScores=: limitSpares@({~ nextFrameIndex^:(i.10)&0)@(3 ]\ ])@{.~&21

 isScore=: -:&(+/@,) , (10 3 >: $@]) , 2 -: #@$@]
 assert 300 isScore bowlingScores 12#10
 assert 190 isScore bowlingScores 21$9 1
 assert 0 isScore bowlingScores 20$0
 assert 90 isScore bowlingScores 20$8 1

And, I think that that I have an adequate set of definitions.  I have a slight temptation to try and distinguish between the two meanings for the number 10, but that is inherent in the context of bowling -- you do not know if a bowler saying "10" means "10 pins" or "10 frames" until you get a bit more information.

Next up:  I should perhaps go back and take some of these sentences and show how J evaluates them.  I think I did an ok job of illustrating "limitSpares", but some of the other lines I just kind of thew out there.  And, if in so doing I feel inspired to distinguish between the two meanings for "10", or if I think up better names for some of my words, ... well... it could happen.  And I hope my next post will not be too tedious.

Update: I could have defined:

   limitSpares=:  #"1~ 1,.1,.10 <: +/ .*&1 1 0

This would give me a two column result for games that had no spares nor strikes.  But  I do not see a use for that complication.

Wednesday, April 13

r-nd-m: TDD bowling, and J, revised, part 2

This is a continuation of r-nd-m: TDD bowling, and J, revised, part 1

    assert 300 isScore bowlingScores 12#10

This needs an implementation:

    bowlingScores=: 3 ]\ ]

Easy enough, and that works.

    assert 190 isScore bowlingScores 21$9 1

This fails with my current definition for bowlingScores. The problem is that my result has too many rows in it. If I had a way of eliminating them, I would have the right result:

    +/@,(#~ 9={."1) bowlingScores 21$9 1

But I don't want to use this technique because it is too closely tied to the example score. What I really need is a way of ignoring potential frames immediately after a frame that did not begin with a 10.

 validFrames=:3 :0
   valid=. 0  NB. first potential frame is always a valid frame
   while. (#y) > {: valid do.
     valid=. valid, ({:valid) + 1 + 10 ~: {. ({:valid) { y
   (i.#y) e. valid

That implementation seems overly complicated, but it works:

    +/, (#~ validFrames) 3 ]\ 21$9 1

Some issues here:
  1. I am repeatedly referring to the last element of valid.
  2. Each element of valid depends on all of the previous elements (and its first element is always 0).
  3. The last element of valid is not really valid (because it's an index off the end of the array), but that does not actually matter for well-formed games, since no valid index will ever match it.
  4. I have written this code so that it can work on a flat list of ball scores or an array of them.
  5. If a game goes too long, this code will not ignore irrelevant trailing ball scores.
Anyways, I would like to get rid of that while loop. One possibility might involve the use of prefix (\) but that turns out to not be useful. Yes, it gives me shorter instances of the game to work on, but that does not help me with issue 2.  I need an inductive approach here.

For an inductive approach, the initial value is always 0.  So I need a function that, given one value will give me the next value.

In other words, I need a function that adds 1 to an index if the value at that index is 10, and which otherwise adds 2 to that index.

But, I also need my function to not have problems from indexing off the end of my scores.

For example, if my potential frames are my left argument:
    F=: ] + 1 + 10 > {.@{~
    (19 3$9 1) F^:(i.10) 0
 0 2 4 6 8 10 12 14 16 18

This leaves me with my new definition:

    bowlingScores=: ({~ F^:(i.10)&0)@(3 ]\ ])

That satisfies both of my assertions so far, but lunch time is over so I need to put the rest of this off until later.

For now, here are my collected definitions and assertions:

 isScore=: -:&(+/@,) , (10 3 >: $@]) , 2 -: #@$@]
 F=: ] + 1 + 10 > {.@{~
 bowlingScores=: ({~ F^:(i.10)&0)@(3 ]\ ])

 assert 300 isScore bowlingScores 12#10
 assert 190 isScore bowlingScores 21$9 1

Monday, April 4

Bowling, revisited

I was going through and tagging blog entries and it looks like this one was a latent, unpublished draft.  It's probably best to ignore this post for now....  I am intending to leave this thread of thought alone, for now at least.  See also: which I hope will be a better approach.

I am currently writing for an audience of maybe four people, and quite possibly I have disappointed some of them.  Where is the elegance in the code I have been writing?  (Also there was a bug in the blog I posted last, I had 2 >. instead of 2 <. which was horrid.)

Anyways, let's re-invent the bowling scoring code, let's create an array which when all of its numbers have been summed gives us the total score.  In other words, let's have a ten row, three column list of numbers:

   assert 10 3 -: $ framesScore 20#0

   framesScore=: 10 {. 3 ]\ ]

"Now, wait", I can imagine someone saying how do we tell whether a frame is a complete frame or an incomplete frame?

And, the answer is: this function will not tell you that.  This function just gives you numbers you can total up.  And overloading its meaning to attempt to represent incomplete frames seems like bad modularity.  We can use a different function to determine which frames are complete frames -- that does not have to be represented in the scores themselves.

All we are doing here is finding some numbers to add up, let's not make that operation overly complicated.

   assert 0 -: +/, framesScore 20#0

Fine, so far.

   assert 30 -: +/, framesScore 19{.10 0 10

Now we need to identify where each frame starts.  Borrowing from <a href="">Henry</a>:

   framesStart=: 10 {. 0 {~^:a:~  _1 _1  ,~  #\ +  10&~:
   framesScore=: framesStart { 3 ]\ ,&0 0

Whoa... what happened here?

So, first off, I do not really know how test driven development is supposed to work for "enterprise" situations or really any situation where you have pre-existing code.  Are you allowed to just use the code, or are their preconditions?  But, also, I was pretending, in my earlier posts, that I did not understand how Henry's code worked (or even that it existed).  I was wondering if it would just jump out of the process (and it didn't).

But pretending ignorance was getting difficult for me...

So let's go over this code for a bit, since I expect at least one person that might read this blog might not have a computer handy.

   19 {. 10 0 10
10 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

That was just a concise way of expressing a game -- the first ball was a strike, the second was a gutter ball, the third ball turned that frame into a spare and then we gave up so the rest of the balls implicitly had a score of zero.

   10 ~: 10 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

This is marking balls where not all of the pins were knocked down all at once.

   (#\ + 10&~:) 19 {. 10 0 10
1 3 3 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

#\ is 1 2 3 4 5... and if we think in terms of indices it's the index of the next element in the array.  0 is the index of the first element, 1 is the value there and is the index of the second element.  This result 1 3 3 5 6 7.. is "the index of where the next frame starts for each ball if that ball were the start of a frame".  It has some junk values in it, but we do not have to use them (we can select just the useful values).

   (_1 _1,~#\ + 10&~:) 19 {. 10 0 10
1 3 3 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 _1 _1

We will need those negative values in just a moment.  But if we are thinking of indices, _1 is the index of the last value in an array.

Interlude: tennis scoring

Tracy Harms posted, and Ron Jeffries asked about how the J community perceived it.  I am not the J community, but I am a part of it, and maybe my perspectives can help express how I read J code.

So, first, here is the code as it is at the time of this writing:

firstPlayerName=: 'Alice'"_
secondPlayerName=: 'Bob'"_
ScoreMarks=: 'AB'

tellGameScoreSeries=: 3 :'tellSituation/&> ({.~ validLength) pair ScoreMarks, y'
pair   =: [: tally&.> situate
tally  =: 1 1 -~ [:+/"1 [:= ]
situate=: [: }. <\

tellSituation =: tellIncomplete ` tellFinal @. isFinal
tellIncomplete=:        tellLow ` tellHigh  @. isHigh
tellLow       =:       tellBoth ` tellTie   @. isTied
tellHigh      =:  tellAdvantage ` tellDeuce @. isTied

isFinal=: isHigh  *.  1 <  [: | -
isHigh=:  3 < >.
isTied=:  =

tellFinal=: 'game ', leadingPlayerName
tellAdvantage=: 'advantage ', leadingPlayerName
tellDeuce=: 'deuce'"_
tellBoth=:  firstPlayerName, ' ', tellNumber@[ , ', ',  secondPlayerName, ' ', tellNumber@] 
tellTie=: tellNumber,' all'"_ 
tellNumber=: [: > ] { (;:' love fifteen thirty forty ')"_
leadingPlayerName=: firstPlayerName ` secondPlayerName @. <

validLength=: ( {.@: ((1+I.),#) )@: (isFinal/&>)

And, here is an example use:

tellGameScoreSeries 'AABBBAABAABBBB'
love all                 
Alice fifteen, Bob love  
Alice thirty, Bob love   
Alice thirty, Bob fifteen
thirty all               
Alice thirty, Bob forty  
forty all                
advantage Alice          
advantage Alice          
game Alice 

So... impressions...

First off, this is a fairly big and ornate chunk of code -- displaying it takes a lot of screen real-estate, and it uses long names, and it seems involved.  The complications are probably inherent in the underlying scoring algorithm, the long names are probably a good way of telling me what the code is about, but I do not have an immediate sense of the structure of the sentences.

So, looking closer:

   tellGameScoreSeries 'AABBBAABAABBBB'

We are scoring based on a list of letters using tellGameScoreSeries, which has the definition:

   3 :'tellSituation/&> ({.~ validLength) pair ScoreMarks, y'

Looking at that through the lens of J's parser:

   13 :'tellSituation/&> ({.~ validLength) pair ScoreMarks, y'
[: tellSituation/&> [: ({.~ validLength) [: pair [: ScoreMarks ,

We prepend ScoreMarks ('AB') to the list, then use pair (whatever that does) and then do some other stuff.

(Edit: note that I am working with a different example here, than above.  I do not remember where this example came from.)

│0 0│1 0│1 1│2 1│3 1│3 2│3 3│3 4│4 4│5 4│5 5│6 5│

Ok... those are pairs, but pairs of what?

[: tally&.> situate

   situate 'ABABAABBBAABA'

Ok, I think I know what is going on here: the example showed game progress, so we build up a list of intermediate game states.  This means that pair is probably showing us the scores at each step of the game -- tally probably gives us the score for one of those steps.  But if we are just summing things, why not express that directly?

1 1 1 1 1 1 1 1 1 1 1
   NB. huh?
1 0 1 1 0 0 0 1 1 0 1
0 1 0 0 1 1 1 0 0 1 0
   NB. Oh! oops
6 5
  NB. but I wanted the running sum
1 0
1 1
2 1
3 1
3 2
3 3
3 4
4 4
5 4
5 5
6 5

There, that looks like the same information that pairs gives, though I leave off that initial 0 0.  I am not sure if I need to announce that before every game the players are tied.  But, if I did, it would be easy enough to include.

It's also not presented in quite the same fashion, but I prefer to avoid putting things in boxes when I do not need the boxes.  I think I would have named a routine that does this "runningTally' or 'runningScore' rather than 'pairs'.

   runningTally=: [: +/\ =/~

Or, maybe:

   runningScores=: 0 0, [: +/\ =/~

I had two alternative names and I am going to abuse that so that I can trivially distinguish between these two possible ways of presenting the progress of the game.

So.. I am already rewriting the code and I have barely gotten started.  I do not know if that is a comment on my personality or a comment on the code.  

Next up, we have validLength:

{.@:((1 + I.) , #)@:(isFinal/&>)
isHigh *. 1 < [: | -
3 < >.

So... isFinal goes between a score pair, and then we pick either the length of the argument or the length which includes the first final score...  And a score is final if it's greater than 3 and also exceeds the other score by more than 1.  Again, I am tempted to rewrite it... if nothing else, the results from my runningTally are not in quite the same format that validLength expects.  Also, this code is fundamentally scalar code -- it's array of structures rather than structure of arrays, and J works much better for me when I think in terms of structures of arrays.

The high score test could probably be any of (untested code):
   3 < >./"1 tallies
   3 < >./|: tallies
   >./"1 3:< tallies  NB. ugly and confusing, let's ignore the "1 3: thing
   >./|:3 < tallies
   *./|:3 < tallies

The score separation test could be any of (again, untested code):
   1 < | -/"1 tallies
   1 < | -/|: tallies
or... are there other good variations I should consider?  

Anyways, I am inclined to use transpose (rather than modify the rank of two reductions).  That leaves me with:

   (something *. otherthing) |: tallies

   ((3 < >./)  *. 1 <&| -/)@|: tallies

Let's try that:
   ((3 < >./)  *. 1 <&| -/)@|: 'AB' runningTally 'ABAABBBAABA'
0 0 0 0 0 0 0 0 0 0 0

Nope.. see? that's what I get for trying to do all of this in my head, without using any experiments.

No, wait... maybe this was an acceptable result?  After all, the original use had a specific allowance for the thing being all zeros.  Well... I do not know the rules of tennis so I am not in any position to judge.  But I think this thing is defective, because this logic would not complain if I added another 'B' to the end of the game.  But maybe my result is not what the original code would do?  (Edit: I was getting confused here.  For some reason, I was thinking that the example I was working with, here, was the original example of a complete game -- but it was not, and my cascade of confusion led to me to drift off (and stop this blog entry).)

   isFinal/"1 'AB' runningScores 'ABAABBBAABA'
0 0 0 0 0 0 0 0 0 0 0 0

   isFinal/"1 'AB' runningScores 'ABAABBBAABAB'
0 0 0 0 0 0 0 0 0 0 0 0 0

Hmm... so ok, let's come back to this later.  I will note, however, that the desired result, here would be i.1 of that bit vector.  There is no need to find all of the final scores, and i.1 will automatically give us the length if there are no 1s in the list.

At this point, I really need to understand the requirements, I think, and come at the problem afresh.  But a quick look at the code:

firstPlayerName=: 'Alice'"_
secondPlayerName=: 'Bob'"_
ScoreMarks=: 'AB'

why are we using constant verbs and not nouns here?  Looking at the code, I see one place where the syntax requires a verb:

leadingPlayerName=: firstPlayerName ` secondPlayerName @. <

but that could be rephrased to use { instead of @.

So... impressions...

My impression is that this code was developed using blinders -- the code was designed with a structure in mind (build up verbs that do some part of the phrasing) and that mold was given fairly high priority.  That is not how I work, though, and I am not particularly comfortable with the result.

Which, I suppose, explains my strong urges to rewrite the thing.

Also, the validation part needs a bit of thought, but I do not have enough time, right now, to be researching how tennis games work.

Or does it?  When I look at, the impression I get was that the example game ended early (with a score of 6-5, the game did not have to be over), and there is nothing wrong with the validator.

Sunday, April 3

TDD bowling, and J, revised, part 1

So, I implemented a bowling scorer, in J, using TDD, and I was not very satisfied with the result.  And I keep meaning to come back to it...

The problem, as it were, is that "you get what you test for".  And all I was testing for was a single numeric result that was the total score.  I left the expression of bowling score "frames" as extra credit work.  And then I went back and tried an extra credit exercise, but it had classic second system effects, and I was left feeling dissatisfied, and I am sure that both of the people that bothered to look at my posts were not particularly enthralled, either.

So... I need better tests.

In other words, instead of testing for "just the right score" I also need to test for "the right structure".   And that means that I need to design "the right structure".  So what is "the right structure"?

I am going to go with the structure proposed by Ron Jeffries:  An array with one row for each frame, padded out so that each row has 3 columns.  I am ambivalent about the third column, so I might come back and revise this to say that the number of columns can not exceed 3.   I am also ambivalent about requiring the thing always be 10 rows, so I am going to say that the number of rows cannot exceed 10.  I can come back and add tests requiring exactly 10 rows and exactly 3 columns if I later on decide that these are important.  So what can I test here?

Since this structure represents the game's score, I am going to require that +/@, on the structure gives me the right score.

   assert 0 -: +/@, 20#0

I also need to check that the result has rows and columns (and nothing else)

   assert 2 -: #$ 10 3$0

I also need to check that I have no more than 10 rows and no more than 3 columns:

   assert 10 3 >: 10 3$0

And, I these tests are fundamental, every test that I add needs to incorporate these tests.

   isScore=: -:&(+/@,)  (10 3 >: ]),  2 -: #@$@]
   assert 0 isScore 10 3$0
|length error: isScore
|   assert 0     isScore 10 3$0
   isScore=: -:&(+/@,)  (10 3 >: $@]),  2 -: #@$@]
   assert 0 isScore 10 3$0
|assertion failure: assert
|       assert 0 isScore 10 3$0
   isScore=: -:&(+/@,),  (10 3 >: $@]),  2 -: #@$@]
   assert 0 isScore 10 3$0

Ok, so now I have my test rig.  Part 2 will be to about writing the bowling scorer itself.

I want to stop here so this post remains bite, sized, and because I have already been working on this blog entry for half an hour. 

Hmm... and it looks like some whitespace has crept into the post itself which is not showing up in the blogger edit interface.  I will have to be cautious to avoid that in the future, but after fighting it for 10 minutes I have decided to give up on trying to get that whitespace out of this post.