Draw an ASCII art phone keypad Draw the following in the fewest bytes possible:

-------------------------
|       |  ABC  |  DEF  |
|   1   |   2   |   3   |
-------------------------
|  GHI  |  JKL  |  MNO  |
|   4   |   5   |   6   |
-------------------------
| PQRS  |  TUV  | WXYZ  |
|   7   |   8   |   9   |
-------------------------
|       |       |       |
|   *   |   0   |   #   |
-------------------------
pb, 240 bytes

&lt;[8]^w[Y!14]{w[X!24]{&gt;[8]b[124]^b[124]v}vw[X!-8]{b[45]&lt;}vv}&gt;[12]^[12]b[49]&gt;[12]w[T!8]{&lt;[4]b[T+50]^&lt;w[X%8!6]{b[65+T*3+X%8%3]&gt;}&gt;[10]vw[B!124]{&lt;[24]vvv}t[T+1]}&lt;[4]b[42]&gt;[8]b[48]&gt;[8]b[35]^[4]&gt;w[B!0]{b[B+2]&lt;}b[87]w[X!2]{&lt;[5]w[B!0]{b[B+1]&lt;}}b[80]


(This program will prompt for input in the current version of pbi, because it goes to Y=-1 and the B variable tries to update itself. Even if you do enter input, nothing will break. It's annoying but it's better than the old version that prompted for input no matter what.)

pb is a language all about treating the terminal as a 2D canvas. To output, you have to move the "brush" (a point represented by the current values of the X and Y variables) to where you want that character to go and put it there. It's cumbersome for things like printing out a word but for art it's often convenient.

This program doesn't actually draw exactly what the question specifies. (Wait, don't downvote me yet! Let me explain!)

Drawing boxes with loops is pretty easy, but there's a catch. If you repeat the following shape:

--------
|
|


You do get boxes, but the right and bottom ones will be open. You can manually draw the extra sides, but that costs bytes. To get around this, my program actually draws this, with the open edges on the left and top:

        |       |       |       |
        |       |       |       |
 --------------------------------
        |       |  ABC  |  DEF  |
        |   1   |   2   |   3   |
 --------------------------------
        |  GHI  |  JKL  |  MNO  |
        |   4   |   5   |   6   |
 --------------------------------
        | PQRS  |  TUV  | WXYZ  |
        |   7   |   8   |   9   |
 --------------------------------
        |       |       |       |
        |   *   |   0   |   #   |
 --------------------------------



  But monorail! That's not what the spec says! You can't just draw something else because it's easier and you feel like it! Also, while I have your attention, you are very smart and cute.


Shh, shh, it's okay. pb allows you to "write" to a point on the canvas with one or more negative values in its coordinates. The value is stored while the program runs, but only points where X and Y are both >= 0 are actually written to the screen. This program positions the brush so that areas that are tinted in this image have a negative X or Y:



Although extra lines are "drawn", they're never printed.

After looping through and creating the grid, this program fills in the top nine boxes. The first is hardcoded, a 1 is written and the program moves on. The other eight are generated programmatically. Ignoring code for moving to the next box, noticing when the row is empty, etc (assume the brush always starts on the bottom row of the box and in the middle column), this is what is run eight times:

b[T+50]
^&lt;w[X%8!6]{b[65+T*3+X%8%3]&gt;}
t[T+1]


Even knowing that b is the command to write a character, ^v&lt;&gt; move the brush and w[a!b]{} runs the code in curly braces until a != b, this is hard to follow. The first important thing to note is that you can't define variables in pb. There are six in every program and you have to learn to live with them. Second, T is the only variable that you can actually use the way you're used to using variables; assigning a value and then reading it later. Every other variable either can't be set and just tells you something about the point in the canvas you're on or can only be set indirectly and with side effects (^v&lt;&gt; change X and Y, which also changes the brush location. c sets P to (P+1)%8, which also changes the output colour). Keeping a counter for what number needs to be written and which letters is simply impossible. Instead, this code only keeps track of the number and figures out the letters based on it. Here's how:

b[T+50]                       # We start printing at box 2 with T==0, 0+50=='2'
^&lt;                            # Go up and to the left of the number
w[X%8!6]{                     # Take the X coordinate mod 8 so it's like we're in
                              # the leftmost box. Until hitting the sixth cell:
    b[                          # Write this character:
      65                          # 'A'
      + T * 3                     # Number of current box - 2 (letters start at
                                  # 2) * 3 (3 letters per box)
      + X % 8 % 3                 # X % 8 makes every box behave like it's on the
                                  # left, % 3 puts 0 at the point where the first
                                  # letter goes, then 1, then 2. This is how each
                                  # letter is made different in a box.
    ]
    &gt;                           # Move to the right
}
t[T+1]                        # Box is done, increase counter


This is imperfect, as only 3 letters are put into boxes 7 and 9. So, after filling the bottom row (simple hardcoding), each letter in box 9 is increased by 2 and the W is placed manually. Similarly, every letter in boxes 7 and 8 are increased by 1 and the P is placed manually.

Ungolfed:

&lt;[8]^                         # Go to (-8, -1)
w[Y!14]{                      # While the brush is not on Y=14:
    w[X!24]{                      # While the brush is not on X=24:
        &gt;[8]                          # Go right 8
        b[124]^b[124]v                # Draw a pipe at the current location and above it
    }
    vw[X!-8]{b[45]&lt;}              # Go down and draw hyphens all the way until X=-8
    vv                            # Go down by 2 to start drawing next row
}
&gt;[12]^[12]b[49]               # Write a 1 in the first box
&gt;[12]                          # Go to the bottom pipe on the right of box 2       
w[T!8]{                       # While T is not 8:
    &lt;[4]                          # Go to center cell of the box
    b[T+50]                       # Write the number that belongs there
    ^&lt;w[X%8!6]{b[65+T*3+X%8%3]&gt;}  # Write the letters
    &gt;[10]v                        # Go to the next box
    w[B!124]{                     # If the next box isn't there:
        &lt;[24]vvv                      # Go down a row
    }
    t[T+1]                        # Increase counter
}
&lt;[4]b[42]&gt;[8]b[48]&gt;[8]b[35]   # Put the asterisk, 0 and hash in their boxes
^[4]&gt;w[B!0]{b[B+2]&lt;}          # Increase all letters in the 9th box by 2
b[87]                         # Put a W in the 9th box
w[X!2]{&lt;[5]w[B!0]{b[B+1]&lt;}}   # Increase all letters in the 7th/8th box by 1
b[80]                         # Put a P in the 7th box