Fun with Letter Diamonds

A recent programming challenge appeared on The Social Programmer blog: http://www.craigmurphy.com/blog/?p=1417. The idea is to create a letter 'diamond' from any given starting letter. For example the diamonds for 'D' and 'E' are:

   A
  B B
 C   C
D     D
 C   C
  B B
   A

    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B
    A

So far there have been entries in a number of computer languages, some of which run to many lines of code. In APL, the solution can be done in a single line:

      mat⍪1 0↓⊖mat←(⌽mat),0 1↓mat←⊃(-⍳⍴letters)↑¨letters←(⎕A⍳'E')↑⎕A
    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B
    A

I'm hoping that programmers new to APL will be intrigued and will want to explore further. You may not have an APL font installed, so here is a screenshot. If the code above doesn't look like the blue line in this screenshot you need to install a Unicode APL font before you can read the rest of this Wiki page.

LetterDiamond.jpg

To see how this works, it might be clearer to re-cast the code as a function returning an explicit result R:

      ∇R←LetterDiamond A;letters
[1]   letters←(⎕A⍳A)↑⎕A          ⍝ Get letters, e.g. A-E
[2]   R←⊃(-⍳⍴letters)↑¨letters   ⍝ Form upper-right side
[3]   R←R⍪1 0↓⊖R←(⌽R),0 1↓R      ⍝ Reflect to get whole diamond

      LetterDiamond 'E'
    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B
    A

Line [1] just gets the letters from 'A' to 'E' (say):

      letters←(⎕A⍳'E')↑⎕A
      letters
ABCDE

⎕A is the alphabet, ⎕A⍳'E' finds the position of 'E' in the alphabet (5) and 5↑⎕A gives the first five letters of the alphabet.

Line [2] forms the top right quadrant of the diamond:

      R←⊃(-⍳⍴letters)↑¨letters
      R
A
 B
  C
   D
    E

To break this down further, the expression -⍳⍴letters just produces the following negative numbers:

      -⍳⍴letters
¯1 ¯2 ¯3 ¯4 ¯5

These numbers are used to perform a take () on the letters, producing a nested vector in which each element is a character padded at the left by 0 to 4 spaces:

      (-⍳⍴letters)↑¨letters
 A  B   C    D     E
      ⎕DISPLAY (-⍳⍴letters)↑¨letters
┌→──────────────────────────────┐
│ ┌→┐ ┌→─┐ ┌→──┐ ┌→───┐ ┌→────┐ │
│ │A│ │ B│ │  C│ │   D│ │    E│ │
│ └─┘ └──┘ └───┘ └────┘ └─────┘ │
└∊──────────────────────────────┘
      
      ⍝ This is the equivalent to doing:
      (¯1↑'A')(¯2↑'B')(¯3↑'C')(¯4↑'D')(¯5↑'E')
 A  B   C    D     E

Finally the disclose function converts this into a matrix.

Line [3] is responsible for forming the final diamond. First we use the reverse function to flip the array horizontally:

      ⌽R
    A
   B
  C
 D
E
      (⌽R),R
    AA
   B  B
  C    C
 D      D
E        E
      (⌽R),0 1↓R
    A
   B B
  C   C
 D     D
E       E

Finally we repeat the process to flip the array vertically using the first axis rotate and form the final result:

      R⍪1 0↓⊖R←(⌽R),0 1↓R
    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B
    A

If you want to learn more about APL or try running the code in an APL interpreter, see the APL Tutorial on this Wiki.

Author: SimonMarsden

Studio/LetterDiamonds (last edited 2009-04-17 09:01:46 by SimonMarsden)