Doc/Articles/Play114

From J Wiki
Jump to navigation Jump to search

At Play With J ... Table of Contents ... Previous Chapter ... Next Chapter

6. Cribbage 15s

. By Eugene McDonnell. First published in Vector, 11, 4, (April 1995), 135-138.

Sir John Suckling (1609-1642) lived to just the age of 33, as you can see. He is supposed to have taken poison to avoid a life of penury, during the Civil War, in which he was a cavalier, not a roundhead. He was also a poet with an entrancing lyrical gift. He wrote:

Her lips were red, and one was thin
Compared to what was next her chin
(Some bee had stung it newly);

More to the point, John Aubrey, in his Brief Lives, tells us that Suckling also invented the game of cribbage, developing it from an earlier game, called noddy. I know nothing of noddy, but I was taught cribbage while I was in the army (1944-6) by a fellow soldier named Goman, who came from Duluth, Minnesota (named for a French explorer named Du Luht). According to Goman, Duluth was the cribbage capital of the world. The reason for this was that Duluth is at the very western end of the westernmost of the Great Lakes, Lake Superior, and in the winter, when lake traffic has stopped, there is nothing for people to do but go to their neighborhood pub and play cribbage while drinking beer. They also had the world's championship cribbage match, to which all of the best cribbage players in the world came. Most of them didn't have to come far, since many were from Duluth. This may have changed over the last 50 years.

Just recently, when our nightly double solitaire game palled, my wife and I decided to play cribbage, instead. I got out the cribbage board I had made, close to fifty years ago, and, with the aid of some wooden matches to use as pegs, we began to play. My wife hadn't played the game as much as I had, and it was clear that she was missing some opportunities to score because she didn't see some of the card combinations that added to 15. Such scores are a key part of the game.

To help her out, I decided to tabulate all the combinations of cards of length two through five that added to 15. This was easy enough for length two and three, but it became a little tedious and uncertain for greater lengths. I decided to take a few minutes longer and get it right by doing it with J.

Because I had been spending most of my time recently on studies involving Jane Austen, I hadn't been doing much programming, and I was a bit rusty. My first attempt used a technique which generated all of the representations of 2, 3, 4, and 5-digit decimal numbers, removed those which had more than four of any digit, sorted the rows that were left (so that 4 1 became 1 4 , for example), removed duplicates, and removed rows that didn't add to 15. This strategy foundered because I ran out of space.

I took a few more minutes to think of a more space-efficient strategy, and decided to use a program called part that had been communicated to me several years ago by Roger Hui, which allowed one to generate all the length k partitions of a positive integer n. For example,

   2 part 7
1 6
2 5
3 4

   3 part 6
1 1 4
1 2 3
2 2 2

Having this made it almost too easy. First I had to generate the partitions of 15 having length 2, 3, 4, and 5. Next, since in cribbage the card values are from 1 (for ace) to 10 (for 10, jack, queen, or king), I had to remove rows having elements greater than 10. Next, for the 5-partitions, I had to remove the last row, since this would consist of five threes (how did I know this?), and thus not be valid (there are only four threes in a deck of cards). Last, I wanted to box the results so they could be joined together.

To get rid of rows containing values beyond 10 I wrote:

   i=: *./"1@(10&>:) # ]

This takes as argument a table of numbers and produces a Boolean list by taking the and (*.) over (/) the rows ("1) of the conforming table having a 1 for values for which 10 (10) was greater than or equal (>:), and using this to copy (#) only those rows from the argument (]).

To get rid of the last row if the rows had length 5, I wrote:

   m=: }: ^: (5 = #@{.)

This curtails (}:) the table if (^:) 5 (5) is equal to (=) the length (#) of its first ({.) row.

Boxing is primitive, so the entire result could then be obtained by writing:

   ] p=: 2 3 4 5 <@m@i@part"(0) 15
+----+------+--------+----------+
|5 10|1 4 10|1 1 3 10|1 1 1 2 10|
|6  9|1 5  9|1 1 4  9|1 1 1 3  9|
|7  8|1 6  8|1 1 5  8|1 1 1 4  8|
|    |1 7  7|1 1 6  7|1 1 1 5  7|
|    |2 3 10|1 2 2 10|1 1 1 6  6|
|    |2 4  9|1 2 3  9|1 1 2 2  9|
|    |2 5  8|1 2 4  8|1 1 2 3  8|
|    |2 6  7|1 2 5  7|1 1 2 4  7|
|    |3 3  9|1 2 6  6|1 1 2 5  6|
|    |3 4  8|1 3 3  8|1 1 3 3  7|
|    |3 5  7|1 3 4  7|1 1 3 4  6|
|    |3 6  6|1 3 5  6|1 1 3 5  5|
|    |4 4  7|1 4 4  6|1 1 4 4  5|
|    |4 5  6|1 4 5  5|1 2 2 2  8|
|    |5 5  5|2 2 2  9|1 2 2 3  7|
|    |      |2 2 3  8|1 2 2 4  6|
|    |      |2 2 4  7|1 2 2 5  5|
|    |      |2 2 5  6|1 2 3 3  6|
|    |      |2 3 3  7|1 2 3 4  5|
|    |      |2 3 4  6|1 2 4 4  4|
|    |      |2 3 5  5|1 3 3 3  5|
|    |      |2 4 4  5|1 3 3 4  4|
|    |      |3 3 3  6|2 2 2 2  7|
|    |      |3 3 4  5|2 2 2 3  6|
|    |      |3 4 4  4|2 2 2 4  5|
|    |      |        |2 2 3 3  5|
|    |      |        |2 2 3 4  4|
|    |      |        |2 3 3 3  4|
+----+------+--------+----------+

To make this a bit more useful, I copied it to my text editor (!MacWrite Pro) and changed 10 to T and 1 to A, adjusted widths a bit, and added a few header and footer lines, giving:

Ways of counting fifteen with 2,3,4,5 cards in cribbage:

 +---+-----+-------+---------+
 |5 T|A 4 T|A A 3 T|A A A 2 T|
 |6 9|A 5 9|A A 4 9|A A A 3 9|
 |7 8|A 6 8|A A 5 8|A A A 4 8|
 |   |A 7 7|A A 6 7|A A A 5 7|
 |   |2 3 T|A 2 2 T|A A A 6 6|
 |   |2 4 9|A 2 3 9|A A 2 2 9|
 |   |2 5 8|A 2 4 8|A A 2 3 8|
 |   |2 6 7|A 2 5 7|A A 2 4 7|
 |   |3 3 9|A 2 6 6|A A 2 5 6|
 |   |3 4 8|A 3 3 8|A A 3 3 7|
 |   |3 5 7|A 3 4 7|A A 3 4 6|
 |   |3 6 6|A 3 5 6|A A 3 5 5|
 |   |4 4 7|A 4 4 6|A A 4 4 5|
 |   |4 5 6|A 4 5 5|A 2 2 2 8|
 |   |5 5 5|2 2 2 9|A 2 2 3 7|
 |   |     |2 2 3 8|A 2 2 4 6|
 |   |     |2 2 4 7|A 2 2 5 5|
 |   |     |2 2 5 6|A 2 3 3 6|
 |   |     |2 3 3 7|A 2 3 4 5|
 |   |     |2 3 4 6|A 2 4 4 4|
 |   |     |2 3 5 5|A 3 3 3 5|
 |   |     |2 4 4 5|A 3 3 4 4|
 |   |     |3 3 3 6|2 2 2 2 7|
 |   |     |3 3 4 5|2 2 2 3 6|
 |   |     |3 4 4 4|2 2 2 4 5|
 |   |     |       |2 2 3 3 5|
 |   |     |       |2 2 3 4 4|
 |   |     |       |2 3 3 3 4|
 +---+-----+-------+---------+

  T = 10, J, Q, or K
 The key to this is Roger Hui's partition function, part :
part=: 4 : 0
  if. (1<x)*:x<y do. (x,~(*y)*x<:y)$1>.y*1=x return. end.
  p=. x part&<: y
  s=. >:i.<.y%x
  t=. ({."1 p)<.-.-/@(_2&{.)"1 p
  b=. s<:/t
  i=. (+/"1 b)#s
  j=. (,b)#(*/$b)$i.{:$b
  m=. i,.j{p
  (}:"1 ,. 1: + {:"1 - {."1) m
)

partcheck=: 4 : 0
  t=. x part y
  assert. x={:$t
  assert. (i.#t) -: /: t
  assert. (i.x) -:"1 /:"1 t
  assert. (0=x)+.y=+/"1 t
)

All in all, I spent a happy half-hour at play with J, and my wife now beats me pretty regularly at cribbage.