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
 190

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
   end.
   (i.#y) e. valid
 )

That implementation seems overly complicated, but it works:

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

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

No comments:

Post a Comment