APL Quizzes

  • If you know APL, challenge yourself to solve the little APL Quiz problems
    Try to resist clicking the Solution button until you've found your own solution.
    Note that each Quiz has a solution in just 2 APL instructions (or less!).
    Please Email me your solutions at eric @ lescasse.com!
  • If you do not know APL, think how you would solve the problems in your own language, then inspect the APL Solution
    and even if you do not understand the APL code, see why APL is a so powerful computer language!
  • If you want to use the latest APL+Win version to try solving the APL Quizzes, download and install LearnAPL (free).
  • See Solutions in APL (also in C# and Excel) sent by other developers.

Note, that due to wide APL output, it is recommended to see this page in landscape mode on mobiles.

The following set of APL Quizzes are to be taken in order.

They all relate to an interesting little problem that a former APL customer of mine, who's become a friend now, and who is interested in playing Bridge has submitted to me.

I found them a good way to let you have fun, or if you do not know APL, to let you discover the incredible power of this unfortunately not enough known and not enough used computer language.

They all assume the index origin (⎕io) is 1.

A little background on Bridge and conventions for the Quizzes:

  • There are 4 players
  • Each player receives 13 cards (one fourth of the total 52 existing cards)
  • A set of 13 cards received by a given player is called a hand
  • The different suits or pips (♠, ♥, ♦, ♣) will be saved in an APL variable called pips and defined as pips←'SHDC' ⍝ S=Spades, H=Hearts, D=Diamonds, C=Clubs
  • The different card types will be saved in an APL variable called crds and defined as crds←'AKQJX98765432' ⍝ A=Ace, K=King, Q=Queen, J=Jack, X=10, 9=9, ...
  • A 10 will be represented by the X symbol.
  • A given card will be represented by its pip followed by the card type. For example: SA represents a Spides Ace while CX represent a Clubs 10.

Quiz # 1: Compute a Bridge random cards distribution

Write an APL function called Dist that returns the 4 hands of a random Bridge cards distribution.

You should make use of the following global variables:

      pips←'SHDC'  ⍝ S=Spades, D=Diamonds, H=Hearts, C=Clubs
      crds←'AKQJX98765432'    ⍝ A=Ace, K=King, Q=Queen, J=Jack, X=10, 9=9, ...

and you can use the following constants in your code:

      52    ⍝ total number of cards
      13    ⍝ number of cards per player
       4    ⍝ number of players

The result must be a 4-element nested vector, representing the 4 hands, such as:

      ⎕←aaa←Dist
  DJ S8 CK DX S3 S6 HQ S2 HA C2 D6 C9 SJ   D8 D3 C5 CJ DQ C6 S4 C8 H7 D9 H8 H2 CA   HK H6 C7 SK SQ S7 D5 CQ HX DK HJ S5 C3   SA H9 D2 D7 H5 C4 D4 H3 SX S9 CX DA H4

      ⍝ which you can look at in matrix form
      ⍝ as follows:

      ⊃aaa
 DJ S8 CK DX S3 S6 HQ S2 HA C2 D6 C9 SJ
 D8 D3 C5 CJ DQ C6 S4 C8 H7 D9 H8 H2 CA
 HK H6 C7 SK SQ S7 D5 CQ HX DK HJ S5 C3
 SA H9 D2 D7 H5 C4 D4 H3 SX S9 CX DA H4

      ⍴aaa
4
      ⍴¨aaa
 13  13  13  13
      ⍴¨¨aaa
  2  2  2  2  2  2  2  2  2  2  2  2  2   2  2  2  2  2  2  2  2  2  2  2  2  2   2  2  2  2  2  2  2  2  2  2  2  2  2   2  2  2  2  2  2  2  2  2  2  2  2  2

Each card in the result is represented by the pip character (S,H,D or C) followed by the card letter (A,K,Q,J,X,9,8,7,6,5,4,3 or 2)

One solution is:

    ∇ r←Dist
[1]   ⍝∇ r←Dist
[2]   ⍝∇ r ←→ 4-element nested vector
[3]   ⍝∇      each element contains 13 cards,
[4]   ⍝∇      each represented by 2 letters
[5]   ⍝∇ Example:
[6]   ⍝∇       ⊃Dist
[7]   ⍝∇ DJ S8 CK DX S3 S6 HQ S2 HA C2 D6 C9 SJ
[8]   ⍝∇ D8 D3 C5 CJ DQ C6 S4 C8 H7 D9 H8 H2 CA
[9]   ⍝∇ HK H6 C7 SK SQ S7 D5 CQ HX DK HJ S5 C3
[10]  ⍝∇ SA H9 D2 D7 H5 C4 D4 H3 SX S9 CX DA H4
[11]
[12]  r←⊂[2](,pips∘.,crds)[4 13⍴52?52]
    ∇

Explanations

      ⍝ The following expression:

      pips∘.,crds
 
      ⍝ catenates each pip character
      ⍝ to each card character, returning
      ⍝ a 4x13 nested matrix of all
      ⍝ existing cards:

 SA SK SQ SJ SX S9 S8 S7 S6 S5 S4 S3 S2
 HA HK HQ HJ HX H9 H8 H7 H6 H5 H4 H3 H2
 DA DK DQ DJ DX D9 D8 D7 D6 D5 D4 D3 D2
 CA CK CQ CJ CX C9 C8 C7 C6 C5 C4 C3 C2

      ⍝ We now need to randomize the cards

      ⍝ First, we ravel the previous result
      ⍝ with the ravel (,) primitive:

      ,pips∘.,crds
 SA SK SQ SJ SX S9 S8 S7 S6 S5 S4 S3 S2 HA HK HQ HJ HX H9 H8 H7 H6 H5 H4 H3 H2 DA DK DQ DJ DX D9 D8 D7 D6 D5 D4 D3 D2 CA CK CQ CJ CX C9 C8 C7 C6 C5 C4 C3 C2

      ⍝ This gives us a nested vector of 
      ⍝ the 52 cards in the game

      ⍝ Next we create a permutation of
      ⍝ the 52 first integers with the APL
      ⍝ Deal (?) primitive:

      52?52
51 34 47 23 25 52 35 26 16 30 42 2 36 27 41 48 31 1 40 32 38 7 24 39 21 44 20 18 11 3 4 50 9 5 33 49 22 12 46 10 8 15 17 14 37 29 13 6 28 19 45 43

      ⍝ So we can create a matrix of indices:

      4 13⍴52?52
 51 34 47 23 25 52 35 26 16 30 42  2 36
 27 41 48 31  1 40 32 38  7 24 39 21 44
 20 18 11  3  4 50  9  5 33 49 22 12 46
 10  8 15 17 14 37 29 13  6 28 19 45 43

      ⍝ APL is array oriented and allows
      ⍝ us to index a vector by a matrix.
      ⍝ so we can index our cards by this
      ⍝ matrix:

      (,pips∘.,crds)[4 13⍴52?52]
 C3 D7 C7 H5 H3 C2 D6 H2 HQ DJ CQ SK D5
 DA CK C6 DX SA CA D9 D3 S8 H4 D2 H7 CX
 H8 HX S4 SQ SJ C4 S6 SX D8 C5 H6 S3 C8
 S5 S7 HK HJ HA D4 DQ S2 S9 DK H9 C9 CJ

      ⍝ Finally we use the ⎕split APL System
      ⍝ function or ⊂[2] to return the result
      ⍝ as a 4-element nested vector (with
      ⍝ one row of the above matrix per 
      ⍝ element)

      ⊂[2](,pips∘.,crds)[4 13⍴52?52]
  C3 D7 C7 H5 H3 C2 D6 H2 HQ DJ CQ SK D5   DA CK C6 DX SA CA D9 D3 S8 H4 D2 H7 CX   H8 HX S4 SQ SJ C4 S6 SX D8 C5 H6 S3 C8   S5 S7 HK HJ HA D4 DQ S2 S9 DK H9 C9 CJ

Quiz # 2: Sort a Bridge random cards distribution

Write an APL function called SortDist that takes the result of the APL Dist function (see Quiz # 1 above) and sorts each of its 4 hands elements separately by pip and by card.

So, if we had the following cards: CX CK DX S6 D7, they would be sorted by the SortDist to: S6 DX D7 CK CX because of the major order of SHDC in pips and minor order of AKQJX98765432 in crds

Thus, if we cature the result of the Dist function in a variable:

      aaa←Dist

      ⊃aaa
 H5 C2 D4 CX CK DX S6 D7 D5 H2 HK H8 D3
 H7 H4 C9 H9 C7 DA C5 D2 SA SJ D8 HQ S9
 D6 HX S4 CA DQ C3 D9 C4 HJ HA H3 S5 C8
 CQ C6 SK S7 CJ S3 DK SX DJ S2 S8 SQ H6

we want the SortDist function to return:

      ⊃SortDist aaa
 S6 HK H8 H5 H2 DX D7 D5 D4 D3 CK CX C2
 SA SJ S9 HQ H9 H7 H4 DA D8 D2 C9 C7 C5
 S5 S4 HA HJ HX H3 DQ D9 D6 CA C8 C4 C3
 SK SQ SX S8 S7 S3 S2 H6 DK DJ CQ CJ C6

The result must be a 4-element nested vector just like the result of Dist.

One solution is:

    ∇ dist←SortDist dist
[1]   ⍝∇ dist←SortDist dist
[2]   ⍝∇ dist(argument) ←→ the result of Dist
[3]   ⍝∇ dist(result) ←→ the argument, sorted
[4]   ⍝∇ Example:
[5]   ⍝∇      ⊃aaa←Dist
[6]   ⍝∇ D7 S7 DJ C5 SX SK H8 SA DA HX S6 H3 D2
[7]   ⍝∇ CJ C2 HQ C7 S3 CX HK S9 H6 H7 C9 DQ D6
[8]   ⍝∇ CA D3 H5 C6 C3 CQ D4 C8 H9 S2 HJ SJ D5
[9]   ⍝∇ SQ S4 S5 DX H2 D8 H4 DK CK HA D9 C4 S8
[10]  ⍝∇      ⊃SortDist aaa
[11]  ⍝∇ SA SK SX S7 S6 HX H8 H3 DA DJ D7 D2 C5
[12]  ⍝∇ S9 S3 HK HQ H7 H6 DQ D6 CJ CX C9 C7 C2
[13]  ⍝∇ SJ S2 HJ H9 H5 D5 D4 D3 CA CQ C8 C6 C3
[14]  ⍝∇ SQ S8 S5 S4 HA H4 H2 DK DX D9 D8 CK C4
[15]
[16]  ⍝ dist←(⊂⍋crds⍳2⊃¨dist)⌷dist
[17]  ⍝ dist←(⊂⍋pips⍳1⊃¨dist)⌷dist
[18]
[19]  dist←(⊂¨⍋¨(⊂crds)⍳¨2⊃¨¨dist)⌷¨dist
[20]  dist←(⊂¨⍋¨(⊂pips)⍳¨1⊃¨¨dist)⌷¨dist
    ∇

Explanations

      ⍝ This Quiz is much harder than Quiz #1!

      ⍝ We need to sort each element of the
      ⍝ result of Dist, i.e. each set of 13 
      ⍝ cards, i.e. each hand, all at once!

      ⍝ When having a complex problem like
      ⍝ this one it is always good to first
      ⍝ reduce it to a simpler problem and
      ⍝ then try to see if we can generalize
      ⍝ the solution.

      ⍝ So let's try to sort a single hand
      ⍝ first.  Here is our hand:

      dist←1⊃aaa
      dist
 D7 S7 DJ C5 SX SK H8 SA DA HX S6 H3 D2

      ⍝ We must do 2 sorts:
      ⍝ - a minor sort on the crds
      ⍝ - a major sort on the pips

      ⍝ So let's see how we can sort on
      ⍝ the crds sequence (AKQJX98765432)

      ⍝ We can use the Each (¨) and the Pick (⊃)
      ⍝ APL primitives to extract the "crds"
      ⍝ element of each card:

      2⊃¨dist
77J5XK8AAX632

      ⍝ We can find the position of each
      ⍝ of these in the crds sequence,
      ⍝ using the dyadic Iota (⍳) primitive:

      crds⍳2⊃¨dist
8 8 4 10 5 2 7 1 1 5 9 12 13

      ⍝ We can then grade these indices
      ⍝ using the GradeUp (⍋) APL primitive:

      ⍋crds⍳2⊃¨dist
8 9 6 3 5 10 7 1 2 11 4 12 13

      ⍝ This gives us the indices with which
      ⍝ we must do the indexing to perform
      ⍝ the minor sort, and we
      ⍝ can use the Indexing (⌷) primitive
      ⍝ to perform this indexing:

      (⊂⍋crds⍳2⊃¨dist)⌷dist
 SA DA SK DJ SX HX H8 D7 S7 S6 C5 H3 D2

      ⍝ Note the necessay use of the
      ⍝ Enclose (⊂) primitive to enclose
      ⍝ the ⌷ left argument.

      ⍝ Now, we need to store the result
      ⍝ and perform the second sort:

      dist←(⊂⍋crds⍳2⊃¨dist)⌷dist

      ⍝ The second sort should be done 
      ⍝ according to the "pips"
      ⍝ sequence.

      ⍝ So the principle is exactly the
      ⍝ same as exposed above, except
      ⍝ that we need to extract the first
      ⍝ letter with 1⊃¨ and we need to
      ⍝ search the index in "pips"
      ⍝ instead of in "crds", hence:

      dist←(⊂⍋pips⍳1⊃¨dist)⌷dist

      ⍝ Let's check:

      dist
 SA SK SX S7 S6 HX H8 H3 DA DJ D7 D2 C5

      ⍝ The cards are now perfectly sorted,
      ⍝ according to the "pips"
      ⍝ sequence (SHDC) first and among
      ⍝ a given "pip", according to the 
      ⍝ "crds" sequence (AKQX98765432).

      ⍝ To sum up, we have solved the
      ⍝ problem of sorting one set of
      ⍝ 13 cards, i.e. one hand with the 
      ⍝ following 2 APL instructions:

      dist←(⊂⍋crds⍳2⊃¨dist)⌷dist
      dist←(⊂⍋pips⍳1⊃¨dist)⌷dist

      ⍝ Now, the problem is to generalize
      ⍝ our solution to work on all hands
      ⍝ at once.

      ⍝ This is much simpler than what you
      ⍝ would think.  Basically, we need to
      ⍝ add one more level of Each (¨) to
      ⍝ each primitive in our solution.

      ⍝ Example:

      dist←(⊂⍋crds⍳2⊃¨dist)⌷dist

      ⍝ should become:

      dist←(⊂¨⍋¨(⊂crds)⍳¨2⊃¨¨dist)⌷¨dist

      ⍝ Hence the final 2 instructions
      ⍝ solution to perform the 2 sorts
      ⍝ on all hands at once:

      dist←(⊂¨⍋¨(⊂crds)⍳¨2⊃¨¨dist)⌷¨dist
      dist←(⊂¨⍋¨(⊂pips)⍳¨1⊃¨¨dist)⌷¨dist

Quiz # 3: Split the Bridge cards distribution

Write an APL function called Split that takes the result of the SortDist APL function (see Quiz #1 and Quiz #2 and returns a more readable cards distribution.

The result should be a nested vector of 4 4-rows matrices (one per player): each matrix should have the "pip" in its first column followed by the cards.

Example:

      aaa←SortDist Dist
      ⊃aaa
 HA HK HJ H6 H3 DK DQ D9 CQ C8 C5 C3 C2
 SX S9 S6 HX H9 H8 DA DX D8 D7 D4 CX C9
 SA SQ S7 S4 S3 S2 H5 H2 D6 D2 CK CJ C6
 SK SJ S8 S5 HQ H7 H4 DJ D5 D3 CA C7 C4

      bbb←Split aaa

      bbb
  S             S X 9 6       S A Q 7 4 3 2   S K J 8 5
  H A K J 6 3   H X 9 8       H 5 2           H Q 7 4
  D K Q 9       D A X 8 7 4   D 6 2           D J 5 3
  C Q 8 5 3 2   C X 9         C K J 6         C A 7 4
      
      ⍴bbb
4

      ⍴¨bbb
 4 6  4 6  4 7  4 5

      ⍴¨¨bbb
    1  1  1  1  1     1  1  1  1  1     1  1  1  1  1  1     1  1  1  1
    1  1  1  1  1     1  1  1  1  1     1  1  1  1  1  1     1  1  1  1
    1  1  1  1  1     1  1  1  1  1     1  1  1  1  1  1     1  1  1  1
    1  1  1  1  1     1  1  1  1  1     1  1  1  1  1  1     1  1  1  1

We can now much more easily see what cards each player has got.

Be careful: your solution must take in account the fact that one or more players may not have ANY card of a given "pip" as it is the case in the above example where Player #1, does not have any Spades.

One solution is:

    ∇ dist←Split dist;expm
[1]   ⍝∇ dist←Split dist
[2]   ⍝∇ dist(argument) ←→ result of SortDist Dist
[3]   ⍝∇ dist(result) ←→ a 4-element nested vector
[4]   ⍝∇                 of 4-rows matrices with
[5]   ⍝∇                 the "pips" (SHDC) in first
[6]   ⍝∇                 column and "cards" in subsequent
[7]   ⍝∇                 columns
[8]   ⍝∇ Example:
[9]   ⍝∇      aaa←SortDist Dist
[10]  ⍝∇      ⊃aaa
[11]  ⍝∇  HA HK HJ H6 H3 DK DQ D9 CQ C8 C5 C3 C2
[12]  ⍝∇  SX S9 S6 HX H9 H8 DA DX D8 D7 D4 CX C9
[13]  ⍝∇  SA SQ S7 S4 S3 S2 H5 H2 D6 D2 CK CJ C6
[14]  ⍝∇  SK SJ S8 S5 HQ H7 H4 DJ D5 D3 CA C7 C4
[15]  ⍝∇
[16]  ⍝∇      Split aaa
[17]  ⍝∇   S S X 9 6       S A Q 7 4 3 2   S K J 8 5
[18]  ⍝∇   H A K J 6 3   H X 9 8       H 5 2           H Q 7 4
[19]  ⍝∇   D K Q 9       D A X 8 7 4   D 6 2           D J 5 3
[20]  ⍝∇   C Q 8 5 3 2   C X 9         C K J 6         C A 7 4
[21]
[22]  ⍝∇ dist←pips,(pips∊∪↑¨dist)⍀⊃1↓¨¨(pips⍳↑¨dist)⊂dist
[23]
[24] expm←(⊂pips)∊¨∪¨↑¨¨dist
[25] dist←(⊂pips),¨expm⎕expand[1]¨⊃¨1↓¨¨¨((⊂pips)⍳¨↑¨¨dist)⊂¨dist
    ∇

Explanations

      ⍝ Just as we did in Quiz #2, let's
      ⍝ start by trying to solve a
      ⍝ simpler problem:  do the work
      ⍝ for one player. We will then
      ⍝ try to generalize our solution
      ⍝ to apply it to all players at
      ⍝ once.

      ⍝ So lets take the first player:

      dist←1⊃SortDist Dist
      dist
 SK SQ HA HK HQ H7 H4 H3 DK D6 CX C6 C2

      ⍝ Our first task is to split this
      ⍝ nested vector by "pip" in 4
      ⍝ groups (one per "pip")

      ⍝ The following instruction:

      ↑¨dist
SSHHHHHHDDCCC

      ⍝ returns the "pip" for each of
      ⍝ the 13 cards in the hand.
      ⍝ We can then find the position of
      ⍝ these in the "pips" variable
      ⍝ (SHDC) using the Iota (⍳)
      ⍝ primitive:

            pips⍳↑¨dist
1 1 2 2 2 2 2 2 3 3 4 4 4

      ⍝ This gives us a perfect left
      ⍝ argument to use with the dyadic
      ⍝ Partition (⊂) APL primitive to
      ⍝ split the dist variable per
      ⍝ "pip":

      (pips⍳↑¨dist)⊂dist
  SK SQ   HA HK HQ H7 H4 H3   DK D6   CX C6 C2

      ⍝ We now have a nested vector of nested 
      ⍝ nested vectors.

      ⍝ We want to remove the "pip"
      ⍝ character(i.e.the 1st character)
      ⍝ of each card to keep only the
      ⍝ card information for now.
      ⍝ We can use 1↓¨¨ for that.
      ⍝ Note that since we want to apply
      ⍝ 1↓ at the 2nd level of nesting,
      ⍝ we must use 2 Each (¨¨):

      1↓¨¨(pips⍳↑¨dist)⊂dist
  K Q   A K Q 7 4 3   K 6   X 6 2

      ⍝ We get closer to the solution!

      ⍝ The Disclose (⊃) primitive allows
      ⍝ us to transform the previous
      ⍝ result into a matrix:

      ⊃1↓¨¨(pips⍳↑¨dist)⊂dist
 K Q
 A K Q 7 4 3
 K 6
 X 6 2

      ⍝ All we have to do now, is to
      ⍝ catenate the "pip" characters
      ⍝ using the Catenate (,) APL primitive:

      pips,⊃1↓¨¨(pips⍳↑¨dist)⊂dist
 S K Q
 H A K Q 7 4 3
 D K 6
 C X 6 2

      ⍝ Solving the missing "pip" problem
      ⍝ ------------------------------------

      ⍝ However, it may happen that a hand
      ⍝ does not include any card of a 
      ⍝ given "pip".

      ⍝ For example:

      dist←1⊃SortDist Dist
 SK SQ S9 S7 S6 S4 HA HQ HJ H2 C9 C6 C4

      ⍝ There are no "diamonds" (D) in this
      ⍝ set of 13 cards:  only S H and C.

      ⍝ Let's try to apply our solution:

      pips,⊃1↓¨¨(pips⍳↑¨dist)⊂dist
LENGTH ERROR
      pips,⊃1↓¨¨(pips⍳↑¨dist)⊂dist 
           ^

      ⍝ Unfortunately, we get a LENGTH ERROR
      ⍝ because:

      ⊃1↓¨¨(pips⍳↑¨dist)⊂dist 
 K Q 9 7 6 4
 A Q J 2
 9 6 4

      ⍝ returns only 3 rows (no row for
      ⍝ the diamonds as there are none!)
      ⍝ while "pips" contains 4 elements

      pips
SHDC

      ⍝ APL does not allow us to catenate
      ⍝ a 4-element vector 'SHDC' to a
      ⍝ 3-row matrix, which makes sense!

      ⍝ How can we solve this problem?

      ⍝ Well, by calculating an expansion
      ⍝ mask and using the Expand (⍀) APL
      ⍝ primitive to insert a blank row
      ⍝ at the right location in the 3
      ⍝ rows above matrix:

      ⍝ To compute the expansion mask
      ⍝ we must first find the unique
      ⍝ "pips" elements in our hand

      ⍝ Let's get all the "pip"
      ⍝ characters first, using the
      ⍝ First (↑) APL primitive:

      ↑¨dist
SSSSSSHHHHCCC

      ⍝ Let's find the unique elements
      ⍝ using the Unique (∪) APL primitive:

      ∪↑¨dist
SHC

      ⍝ As we expect, no D here.
      ⍝ To build the expansion mask we
      ⍝ can use the Member Of (∊)
      ⍝ APL primitive:

      pips∊∪↑¨dist
1 1 0 1

      ⍝ This tells us if any of SHDC
      ⍝ in this order belongs to SHC

      ⍝ We can now simply apply our
      ⍝ expansion mask with the Expand (⍀)
      ⍝ primitive to get the
      ⍝ desired result:

      (pips∊∪↑¨dist)⍀⊃1↓¨¨(pips⍳↑¨dist)⊂dist
 K Q 9 7 6 4
 A Q J 2

 9 6 4

      ⍝ A blank row has been inserted
      ⍝ at the right location and we
      ⍝ can now catenate the "pips"
      ⍝ variable:

      pips,(pips∊∪↑¨dist)⍀⊃1↓¨¨(pips⍳↑¨dist)⊂dist
 S K Q 9 7 6 4
 H A Q J 2
 D
 C 9 6 4

      ⍝ Line 22 in the Split function contains 
      ⍝ this solution for one player.

      ⍝ Generalization
      ⍝ --------------

      ⍝ Generalizing our solution and
      ⍝ being able to apply it to all
      ⍝ players at once, is relatively
      ⍝ easy (as in Quiz #2).

      ⍝ It suffices to recognize that
      ⍝ for all players, we have one 
      ⍝ more level of nesting in the
      ⍝ dist variable

      dist←SortDist Dist

      dist
  SX HX H9 H4 D9 D7 D5 D3 CK CJ CX C3 C2   SK SQ S9 S7 S6 S4 HA HQ HJ H2 C9 C6 C4   SA S5 S3 H8 H7 H6 DK DJ D4 CA CQ C8 C7   SJ S8 S2 HK H5 H3 DA DQ DX D8 D6 D2 C5

      ⍝ Therefore, it should be enough
      ⍝ to add one more Each (¨) to
      ⍝ each primitive used in our 
      ⍝ solution

      ⍝ Our solution for one player was:

      pips,(pips∊∪↑¨dist)⍀⊃1↓¨¨(pips⍳↑¨dist)⊂dist

      ⍝ so for all players, it must be:

      (⊂pips),¨((⊂pips)∊¨∪¨↑¨¨dist)⎕expand[1]¨⊃¨1↓¨¨¨((⊂pips)⍳¨↑¨¨dist)⊂¨dist
  S X           S K Q 9 7 6 4   S A 5 3     S J 8 2
  H X 9 4       H A Q J 2       H 8 7 6     H K 5 3
  D 9 7 5 3     D               D K J 4     D A Q X 8 6 2
  C K J X 3 2   C 9 6 4         C A Q 8 7   C 5

      ⍝ A few notes about what we did
      ⍝ to generalize the solution:
      ⍝ 1. The left argument of each
      ⍝    primitive must now be 
      ⍝    enclosed with (⊂)
      ⍝ 2. The APL ⍀ primitive cannot
      ⍝    be applied with ¨
      ⍝    We must use the ⎕expand
      ⍝    System Function instead of ⍀
      ⍝    and specify the dimension
      ⍝    ([1]) along which the
      ⍝    expansion must take place
      ⍝ 3. Although the solution to
      ⍝    the problem is just one
      ⍝    APL instruction (who could
      ⍝    believe that!) it is
      ⍝    best to keep APL instructions
      ⍝    short enough for easier
      ⍝    maintenance, so we will
      ⍝    rather use 2 instructions
      ⍝    in our solution:
      ⍝    - one to compute the
      ⍝      expansion mask
      ⍝    - one to apply it

      ⍝ So, our final proposed 
      ⍝ solution is:

      expm←(⊂pips)∊¨∪¨↑¨¨dist   ⍝ expansion mask
      dist←(⊂pips),¨expm⎕expand[1]¨⊃¨1↓¨¨¨((⊂pips)⍳¨↑¨¨dist)⊂¨dist



       

Quiz # 4: Properly display the Bridge cards distribution

Write an APL function called Display that takes the result of the Split APL function (see Quiz #3) and display the player cards at the 4 cardinal directions (North, South, East, West).

      aaa←Split SortDist Dist
      aaa
  S 9 5         S A J X 3   S Q 8 2     S K 7 6 4
  H J 9 8 6 5   H A 4 3 2   H K X       H Q 7
  D K J 8 7     D X 9 4 3   D A Q 6 2   D 5
  C 5 2         C A         C K Q X 6   C J 9 8 7 4 3

      Display aaa
                 S 9 5
                 H J 9 8 6 5
                 D K J 8 7
                 C 5 2
  S A J X 3                      S Q 8 2
  H A 4 3 2                      H K X
  D X 9 4 3                      D A Q 6 2
  C A                            C K Q X 6
                 S K 7 6 4
                 H Q 7
                 D 5
                 C J 9 8 7 4 3

One solution is:

    ∇ dist←Display dist
[1]   ⍝∇ dist←Display dist
[2]   ⍝∇ dist(argument) ←→ result of Split SortDist Dist
[3]   ⍝∇ dist(result) ←→ a 3x3 nested matrix with
[4]   ⍝∇          the 4 player hands displayed
[5]   ⍝∇          at the 4 cardinal directions
[6]   ⍝∇ Example:
[7]   ⍝∇      aaa←Split SortDist Dist
[8]   ⍝∇      aaa
[9]   ⍝∇  S 9 5         S A J X 3   S Q 8 2     S K 7 6 4
[10]  ⍝∇  H J 9 8 6 5   H A 4 3 2   H K X       H Q 7
[11]  ⍝∇  D K J 8 7     D X 9 4 3   D A Q 6 2   D 5
[12]  ⍝∇  C 5 2         C A         C K Q X 6   C J 9 8 7 4 3
[13]  ⍝∇
[14]  ⍝∇      Display aaa
[15]  ⍝∇                 S 9 5
[16]  ⍝∇                 H J 9 8 6 5
[17]  ⍝∇                 D K J 8 7
[18]  ⍝∇                 C 5 2
[19]  ⍝∇  S A J X 3                      S Q 8 2
[20]  ⍝∇  H A 4 3 2                      H K X
[21]  ⍝∇  D X 9 4 3                      D A Q 6 2
[22]  ⍝∇  C A                            C K Q X 6
[23]  ⍝∇                 S K 7 6 4
[24]  ⍝∇                 H Q 7
[25]  ⍝∇                 D 5
[26]  ⍝∇                 C J 9 8 7 4 3
[27]
[28]  dist[1 4]←(⌈/⍴¨dist[1 4])↑¨dist[1 4]
[29]  dist←(dist,⊂'')[3 3⍴5,[1.5]⍳4]
    ∇

Explanations

      ⍝ This problem is much easier than
      ⍝ the previous ones.

      ⍝ First let's get some sample data:

      dist←Split SortDist Dist

      dist
  S 9 6         S 8 5       S 3             S A K Q J X 7 4 2
  H A 9         H Q X 3 2   H K J 8 7 5 4   H 6
  D A J X 9 6   D Q 8 5 3   D K 7 2         D 4
  C K Q 8 3     C X 7 2     C J 9 5         C A 6 4

      ⍝ We would like to display each
      ⍝ of these 4 matrices at the
      ⍝ following locations marked:
      ⍝ by a 1:

      0 1 0
      1 0 1
      0 1 0

      ⍝ So, if we append an empty 
      ⍝ element to dist:

      dist,⊂''
         
      ⍝ and then index this by the 
      ⍝ following matrix:

      5 1 5
      2 5 3
      5 4 5

      ⍝ which we can create with:

      3 3⍴5 1 5 2 5 3 5 4 5

      ⍝ or in a more APL'ish way with:

      3 3⍴5,[1.5]⍳4
 5 1 5
 2 5 3
 5 4 5

      ⍝ because:

      5,[1.5]⍳4
 5 1
 5 2
 5 3
 5 4

      ⍝ and 3 3⍴ will reuse the 
      ⍝ 1st element (5) as there
      ⍝ are only 8 elements in the
      ⍝ previous result!

      ⍝ So, we have our solution!
      ⍝ Proof:

      (dist,⊂'')[3 3⍴5,[1.5]⍳4]
                    S 9 6
                    H A 9
                    D A J X 9 6
                    C K Q 8 3
  S 8 5                           S 3
  H Q X 3 2                       H K J 8 7 5 4
  D Q 8 5 3                       D K 7 2
  C X 7 2                         C J 9 5
              S A K Q J X 7 4 2
              H 6
              D 4
              C A 6 4

      ⍝ However, if you try the
      ⍝ following instruction
      ⍝ several times:

      Display Split SortDist Dist

      ⍝ You'll see that North
      ⍝ and South hands are not
      ⍝ centered because they 
      ⍝ their longest sequence
      ⍝ of cards may be different

      ⍝ Examples:

      Display Split SortDist Dist
              S 5
              H X 7
              D A K Q J X 8 7 6
              C Q 9
  S A J 8 7                       S Q X 3
  H J 8 4 2                       H A Q 6
  D 2                             D 9 5 4 3
  C A K J 2                       C X 6 5
                    S K 9 6 4 2
                    H K 9 5 3
                    D
                    C 8 7 4 3

      Display Split SortDist Dist
                  S A Q 7 6
                  H A K J 4 3
                  D Q 5
                  C 6 5
  S X 5 4 2                     S 9 8 3
  H Q 8 7 5                     H X 9 6 2
  D 8 4                         D A 9 7 6 3
  C X 3 2                       C 8
              S K J
              H
              D K J X 2
              C A K Q J 9 7 4

      ⍝ To get a better display
      ⍝ we can find the longest
      ⍝ sequence of the North
      ⍝ and South hands:

      ⍝ First let's find their
      ⍝ dimensions:

      ⍴¨dist[1 4]
 4 6  4 9

      ⍝ and now applying the
      ⍝ Maximum Reduction (⌈/)
      ⍝ operator, let's find the
      ⍝ largest of the 2:

      ⌈/⍴¨dist[1 4]
 4 9

      ⍝ We can now apply the Take
      ⍝ primitive (↑) on each
      ⍝ of the North and South
      ⍝ hands to force them to
      ⍝ have the same dimensions:

      dist[1 4]←(⌈/⍴¨dist[1 4])↑¨dist[1 4]

      ⍝ So our final solution is:

      dist[1 4]←(⌈/⍴¨dist[1 4])↑¨dist[1 4]
      dist←(dist,⊂'')[3 3⍴5,[1.5]⍳4]

      ⍝ Let's try it:

      Display Split SortDist Dist
                    S Q J 2
                    H A 9 6 3
                    D K X 8 2
                    C Q 2
  S A X 9 8 5 4                     S K 7 6 3
  H Q X                             H
  D Q 9 3                           D 7 6
  C A 6                             C K J X 8 7 5 4
                  S
                  H K J 8 7 5 4 2
                  D A J 5 4
                  C 9 3

      Display Split SortDist Dist
                S K Q J X 9 6 4
                H 7 3
                D A 5
                C A 8
  S 2                             S A 7 5 3
  H 9 8 6 5 4                     H K J X 2
  D K Q 8 2                       D 7 4
  C J 9 5                         C K 3 2
                 S 8
                 H A Q
                 D J X 9 6 3
                 C Q X 7 6 4

Quiz # 5: Evaluate a Bridge cards distribution

The next challenge is to write an Eval APL function, as concise and efficient as possible, that computes the value of the 4 hands of a Bridge cards distribution.

The Eval function should take as its argument the result of the SortDist function (see Quiz #2), i.e. a sorted Bridge card distribution and return a 4-element integer vector containing the total value of each hand.

To evaluate a hand, the pip (or suit) is of no importance. The cards values are as follows:

  • A=4
  • K=3
  • Q=2
  • J=1
  • all other cards=0
      dist←SortDist Dist

      dist
  SQ S8 S6 S2 HA H6 H5 H3 DA DQ CK C9 C3   S5 S4 HK HJ HX D9 D7 D6 D5 D2 CA CJ C5   SA SK S9 S7 S3 H7 H4 H2 D3 CQ C8 C4 C2   SJ SX HQ H9 H8 DK DJ DX D8 D4 CX C7 C6

      ⊃dist
 SQ S8 S6 S2 HA H6 H5 H3 DA DQ CK C9 C3
 S5 S4 HK HJ HX D9 D7 D6 D5 D2 CA CJ C5
 SA SK S9 S7 S3 H7 H4 H2 D3 CQ C8 C4 C2
 SJ SX HQ H9 H8 DK DJ DX D8 D4 CX C7 C6

      Eval dist
15 9 9 7

      (Eval dist),⊃dist
 15 SQ S8 S6 S2 HA H6 H5 H3 DA DQ CK C9 C3
  9 S5 S4 HK HJ HX D9 D7 D6 D5 D2 CA CJ C5
  9 SA SK S9 S7 S3 H7 H4 H2 D3 CQ C8 C4 C2
  7 SJ SX HQ H9 H8 DK DJ DX D8 D4 CX C7 C6

One solution is:

    ∇ r←Eval a
[1]   ⍝∇ r←Eval a -- Computes the value of each hand of a Bridge cards distribution
[2]   ⍝∇ a ←→ result of the SortDist function (see Quiz 2)
[3]   ⍝∇ r ←→ 4-element integer vector containing each hand total value
[4]   ⍝∇ Note: cards values are: A=4, K=3, Q=2, J=1
[5]   ⍝∇       all other cards=0
[6]   ⍝∇ Example:
[7]   ⍝∇       dist←SortDist Dist
[8]   ⍝∇       ⊃dist
[9]   ⍝∇  SQ S8 S6 S2 HA H6 H5 H3 DA DQ CK C9 C3  ⍝ 15 = 2(Q)+4(A)+4(A)+2(Q)+3(K)
[10]  ⍝∇  S5 S4 HK HJ HX D9 D7 D6 D5 D2 CA CJ C5  ⍝  9 = 3(K)+1(J)+4(A)+1(J)
[11]  ⍝∇  SA SK S9 S7 S3 H7 H4 H2 D3 CQ C8 C4 C2  ⍝  9 = 4(A)+3(K)+2(Q)
[12]  ⍝∇  SJ SX HQ H9 H8 DK DJ DX D8 D4 CX C7 C6  ⍝  7 = 1(J)+2(Q)+3(K)+1(J)
[13]  ⍝∇       Eval dist
[14]  ⍝∇ 15 9 9 7
[15]
[16]  r←+/0⌈5-crds⍳⊃∊¨a
[17]
    ∇

Explanations

      ⍝ This problem is easy to solve
      ⍝ but the challenge is to
      ⍝ find the shortest and fastest
      ⍝ possible solution.

      ⍝ Of course shortest does not
      ⍝ necessarily means fastest
      ⍝ though!

      ⍝ Let's get our data:

      a←SortDist Dist

      ⊃a
 SQ S8 S6 S2 HA H6 H5 H3 DA DQ CK C9 C3
 S5 S4 HK HJ HX D9 D7 D6 D5 D2 CA CJ C5
 SA SK S9 S7 S3 H7 H4 H2 D3 CQ C8 C4 C2
 SJ SX HQ H9 H8 DK DJ DX D8 D4 CX C7 C6

      ⍝ Let's start by applying
      ⍝ the Enlist primitive (∊)
      ⍝ to each hand:


      ∊¨a
 SQS8S6S2HAH6H5H3DADQCKC9C3 S5S4HKHJHXD9D7D6D5D2CACJC5 SASKS9S7S3H7H4H2D3CQC8C4C2 SJSXHQH9H8DKDJDXD8D4CXC7C6

      ⍝ Make it a matrix with
      ⍝ Disclose (⊃):

      ⊃∊¨a
SQS8S6S2HAH6H5H3DADQCKC9C3
S5S4HKHJHXD9D7D6D5D2CACJC5
SASKS9S7S3H7H4H2D3CQC8C4C2
SJSXHQH9H8DKDJDXD8D4CXC7C6

      ⍝ Now find the position of
      ⍝ those cards in crds:

      crds⍳⊃∊¨a
 14  3 14  7 14 9 14 13 14  1 14 9 14 10 14 12 14  1 14  3 14 2 14  6 14 12
 14 10 14 11 14 2 14  4 14  5 14 6 14  8 14  9 14 10 14 13 14 1 14  4 14 10
 14  1 14  2 14 6 14  8 14 12 14 8 14 11 14 13 14 12 14  3 14 7 14 11 14 13
 14  4 14  5 14 3 14  6 14  7 14 2 14  4 14  5 14  7 14 11 14 5 14  8 14  9

      ⍝ We are interested by the
      ⍝ 1's, 2's, 3's and 4's in
      ⍝ this result because the 
      ⍝ first 4 elements of crds
      ⍝ are:  AKQJ

      ⍝ However a 1 means an A
      ⍝ and should return 4,
      ⍝ a 2 means a K and should
      ⍝ return 3, etc.

      ⍝ So we can subtract the
      ⍝ above matrix from 5 using
      ⍝ the APL scalar extension:

      5-crds⍳⊃∊¨a
 ¯9  2 ¯9 ¯2 ¯9 ¯4 ¯9 ¯8 ¯9  4 ¯9 ¯4 ¯9 ¯5 ¯9 ¯7 ¯9  4 ¯9  2 ¯9  3 ¯9 ¯1 ¯9 ¯7
 ¯9 ¯5 ¯9 ¯6 ¯9  3 ¯9  1 ¯9  0 ¯9 ¯1 ¯9 ¯3 ¯9 ¯4 ¯9 ¯5 ¯9 ¯8 ¯9  4 ¯9  1 ¯9 ¯5
 ¯9  4 ¯9  3 ¯9 ¯1 ¯9 ¯3 ¯9 ¯7 ¯9 ¯3 ¯9 ¯6 ¯9 ¯8 ¯9 ¯7 ¯9  2 ¯9 ¯2 ¯9 ¯6 ¯9 ¯8
 ¯9  1 ¯9  0 ¯9  2 ¯9 ¯1 ¯9 ¯2 ¯9  3 ¯9  1 ¯9  0 ¯9 ¯2 ¯9 ¯6 ¯9  0 ¯9 ¯3 ¯9 ¯4

      ⍝ Now, the 1's, 2's, 3s and 4's
      ⍝ do represent the cards values

      ⍝ We just need to replace all
      ⍝ the negative values by 0 
      ⍝ which we can do with the
      ⍝ Maximum (⌈) primitive:

      0⌈5-crds⍳⊃∊¨a
 0 2 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 2 0 3 0 0 0 0
 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 1 0 0
 0 4 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0
 0 1 0 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0

      ⍝ And we finally just need
      ⍝ to sum each line with the
      ⍝ Sum (+/) operator:

      +/0⌈5-crds⍳⊃∊¨a
15 9 9 7

      ⍝ That was easy: it is also a
      ⍝ good example of the way
      ⍝ one should approach and
      ⍝ solve a problem in APL:
      ⍝ thinking globally, not cell
      ⍝ by cell, and making best
      ⍝ possible use of the APL
      ⍝ primitives and operators!

      ⍝ 15 characters to solve this
      ⍝ little problem!

      ⍝ Which other language can do
      ⍝ better than APL?

Quiz # 6: Find a Bridge cards distribution under constraint

The next challenge is to write a Find APL function, as concise and efficient as possible, that finds a random Bridge cards distribution where the North hand (i.e. the first element of the Dist result) has a value of at least a given number.

The Find function should take a single integer (between 0 and 37 inclusive) as its argument. It must find a Bridge cards distribution where the North hand has at least this value.

It should use all the other functions developed in the previous quizzes, i.e. the Eval, Display, Split, SortDist and Dist functions (see Quiz #1 to Quiz #5) to return and display the first random Bridge cards distribution you find that matches the constraint.

      Find 15
                 S K 9 3
                 H A K J 9
                 D A 7 2
                 C A X 9
  S A J X 6 2                   S Q 8 7 4
  H X 6 5 2                     H 7 4 3
  D Q                           D X 8 4
  C Q J 3                       C K 8 4
                S 5
                H Q 8
                D K J 9 6 5 3
                C 7 6 5 2

      Find 28
                S A Q 7
                H A K 6
                D A Q
                C A K Q 3 2
  S K 8 2                     S 5 4 3
  H J X 9 4 2                 H 7
  D J X 8 3                   D 9 7 6 5 4
  C 6                         C X 8 5 4
                S J X 9 6
                H Q 8 5 3
                D K 2
                C J 9 7

One solution is:

    ∇ r←Find a
[1]   ⍝∇ r←Find a -- Finds and displays a Bridge
[2]   ⍝∇             cards distribution where
[3]   ⍝∇             the North hand has a value
[4]   ⍝∇             at least equal to "a"
[5]   ⍝∇ a ←→ an integer scalar between 0 and 37
[6]   ⍝∇      the minimum value for the North hand
[7]   ⍝∇ r ←→ the result of the Display function
[8]   ⍝∇      to show the found Bridge cards
[9]   ⍝∇      distribution that matches the
[10]  ⍝∇      constraint
[11]
[12]  :while a>↑Eval r←Dist ⋄ :endwhile
[13]  r←Display Split SortDist r
    ∇

Explanations

      ⍝ Not much to say!

      ⍝ Yes, APL+Win also has all the
      ⍝ traditional Control Structures
      ⍝ and yes, you can also write 
      ⍝ loops in APL, if you really
      ⍝ want to (or if you need to)!

      ⍝ This solution simply runs 
      ⍝ Eval Dist in a "while" loop
      ⍝ and exits the loop as soon as a
      ⍝ solution meeting the constraint
      ⍝ has been found.

      ⍝ It then displays it using the 
      ⍝ Display Split and SortDist
      ⍝ functions.