# 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   |   #   |
-------------------------

• Why the too-broad close-vote? Mar 24 '16 at 17:59
• Erm... hardcoding output alert! Mar 24 '16 at 18:18
• This output seems very well-chosen for a fixed-output challenge. There's geometric structure, the numbers are ordered, the letters are alphabetized and chunks -- lots of possible tradeoffs for hardcoding versus generating. I think the length is high enough that hardcoding will lose out, but we'll see.
– xnor
Mar 25 '16 at 3:19
• An old-style phone without Q or Z would be easier to generate. Mar 25 '16 at 16:16
• I'm not a code golfer myself (more interested challenge ideas) but would certain languages benefit from removing P and W from an alphabet array and then adding them in manually? Since they are the only two out of place. Mar 25 '16 at 20:49

# pb, 240 bytes

<[8]^w[Y!14]{w[X!24]{>[8]b[124]^b[124]v}vw[X!-8]{b[45]<}vv}>[12]^[12]b[49]>[12]w[T!8]{<[4]b[T+50]^<w[X%8!6]{b[65+T*3+X%8%3]>}>[10]vw[B!124]{<[24]vvv}t[T+1]}<[4]b[42]>[8]b[48]>[8]b[35]^[4]>w[B!0]{b[B+2]<}b[87]w[X!2]{<[5]w[B!0]{b[B+1]<}}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]
^<w[X%8!6]{b[65+T*3+X%8%3]>}
t[T+1]


Even knowing that b is the command to write a character, ^v<> 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<> 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'
^<                            # 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.
]
>                           # 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:

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


# Brainfuck, 565 characters (212 bytes)

 1 +++++[>+++++>>>>+++++++++>>>>+++++++++++++<<<<<<<<<-]    //initialize
2 >[->>+++++>>>>+++++<<<<<<]                               //initialize
3 >>>++++++++[-<<<++++++>++++>>>>>>++++<<<<]               //initialize
4 ++++++++++<->>>>-<<                                      //initialize
5
6 //print first block (123)
7 >+++++[-<.....>]<<.>>>.>.......<.<++[->>..>.+.+.+<..<.<]<<.<.>>>+++[-<<<<...<+.>...>.>>>]<<.
8 //print second block (456)
9 >>+++++[-<.....>]<<.>>>.<+++[->>..>.+.+.+<..<.<]<<.<.>>>+++[-<<<<...<+.>...>.>>>]<<.
10 //print third block (789)
11 >>+++++[-<.....>]<<.>>>.>.>.+.+.+.+<..<.>..>.+.+.+<..<.>.>.+.+.+.+<..<.<<<.<.>>>+++[-<<<<...<+.>...>.>>>]<<.
12 //print fourth block (*0#)
13 >>+++++[-<.....>]<<.>>>.<+++[->>.......<.<]<<.<.<...<---------------.>...>.<...<++++++.>...>.<...<-------------.>...>.>>><<.
14 //print last block (the remaining dashes)
15 >>+++++[-<.....>]


Plain code:

+++++[>+++++>>>>+++++++++>>>>+++++++++++++<<<<<<<<<-]>[->>+++++>>>>+++++<<<<<<]>>>++++++++[-<<<++++++>++++>>>>>>++++<<<<]++++++++++<->>>>-<<>+++++[-<.....>]<<.>>>.>.......<.<++[->>..>.+.+.+<..<.<]<<.<.>>>+++[-<<<<...<+.>...>.>>>]<<.>>+++++[-<.....>]<<.>>>.<+++[->>..>.+.+.+<..<.<]<<.<.>>>+++[-<<<<...<+.>...>.>>>]<<.>>+++++[-<.....>]<<.>>>.>.>.+.+.+.+<..<.>..>.+.+.+<..<.>.>.+.+.+.+<..<.<<<.<.>>>+++[-<<<<...<+.>...>.>>>]<<.>>+++++[-<.....>]<<.>>>.<+++[->>.......<.<]<<.<.<...<---------------.>...>.<...<++++++.>...>.<...<-------------.>...>.>>><<.>>+++++[-<.....>]


## Bubblegum, 103 bytes

Hexdump:

00000000: d3d5 c501 b86a 1420 0048 3b3a 3983 6917  .....j. .H;:9.i.
00000010: 5737 200d 9631 84c8 2818 4169 6310 cd85  W7 ..1..(.Aic...
00000020: cb30 b069 ee1e 9e60 b55e de3e 60da d7cf  .0.i....^.>...
00000030: 1f66 9a09 d414 5328 6d46 d0b4 80c0 a060  .f....S(mF.....
00000040: b0da 90d0 3010 1d1e 1119 0533 cd1c 6a8a  ....0......3..j.
00000050: 0594 b624 ec36 984f 5169 b08c 1654 c400  ...$.6.OQi...T.. 00000060: 4a2b e337 0d00 04 J+.7...  Boring and practical. • "Boring and practical" like a phone keypad :) Mar 24 '16 at 16:18 ## Python 2, 147 bytes print(("|%s"*3+"|\n")*2).join(["-"*25+"\n"]*5)%tuple(x.center(7)for x in" ABC DEF 1 2 3 GHI JKL MNO 4 5 6 PQRS TUV WXYZ 7 8 9 * 0 #".split(' '))  A quick draft of a basic strategy. Uses string formatting to insert the labels, which are hardcoded in a long string. # C,160 bytes j,k,l,m,n=65;main(i){for(i=325;i--;i%25||puts(""))l=i-139,putchar((k=i/25%3)?(j=i%25%8)?k-2?j-4?32:"123456789*0#"[m++]:j/3-1&&l*l!=64||i%290<75?32:n++:'|':45);}  It makes sense to take avantage of the fact that the letters are in sequence. This code runs through the 325 characters of the keypad, and prints either a space or the next letter as needed. Ungolfed i, //main loop variable j, //x position within key k, //y position within key l, //distance from character 139 (the space immediately left of T) m, //symbol counter n='A';//letter counter main(){ for(i=325;i--;i%25||puts("")) //loop through 325 characters. puts() adds a newline at the end of each line of 25 l=i-139, //calculate l. if it is 8, we need to print P or W putchar((k=i/25%3)? //if row not divisible by 3 (j=i%25%8)? //if position on row not a | k-2? //if row mod 3 = 1 j-4?' ':"123456789*0#"[m++] //print a space or a character from the string (increment m for next time) : //else row mod 3 must = 2 j/3-1&&l*l!=64||i%290<75?' ':n++ //print a space or a letter according to formula (increment n to the next letter) :'|' //else print | : '-') //else print - ;} // j/3-1 returns a 0 when in any of the three columns where letters are generally found // l*l!=64 returns a 0 at the correct place fo P and W // i%290<75 returns a 1 for keys 1,*,0,#, supressing the printing of letters/symbols  # Java, 296 bytes Golfed: class a{static void main(String[]a){System.out.println("-\n|&| ABC | DEF |\n|$1$|$2$|$3$|\n-\n| GHI | JKL | MNO |\n|$4$|$5$|$6$|\n-\n| PQRS | TUV | WXYZ |\n|$7$|$8$|$9$|\n-\n|&|&|&|\n|$*$|$0$|$#$|\n-".replace("&"," ").replace("$","   ").replace("-","--------------------"));}}


Ungolfed:

public class AsciiPhoneKeypad{
public static void main(String []args){
// - for twenty-five dashes
// $for three spaces // & for seven spaces System.out.println("-\n|&| ABC | DEF |\n|$1$|$2$|$3$|\n-\n| GHI | JKL | MNO |\n|$4$|$5$|$6$|\n-\n| PQRS | TUV | WXYZ |\n|$7$|$8$|$9$|\n-\n|&|&|&|\n|$*$|$0$|$#$|\n-" .replace("&"," ").replace("$","   ").replace("-","--------------------"));
}
}

• 283 bytes (does have a single trailing new-line, but this is allowed by default), without is still 289 bytes, though. Oct 27 '17 at 11:58

# Lua, 209 bytes

Golfed:

a=("-\n|&|  ABC  |  DEF  |\n123|\n-\n|  GHI  |  JKL  |  MNO  |\n456|\n-\n| PQRS  |  TUV  | WXYZ  |\n789|\n-\n|&|&|&|\n*0#|\n-"):gsub("&","       "):gsub("([0-9*#])","|   %1   "):gsub("-",("-"):rep(25))print(a)


Ungolfed:

-- "&" for seven spaces
-- "1" -> "|   1   "
-- "-" -> twenty-five dashes

a="-\n|&|  ABC  |  DEF  |\n123|\n-\n|  GHI  |  JKL  |  MNO  |\n456|\n-\n| PQRS  |  TUV  | WXYZ  |\n789|\n-\n|&|&|&|\n*0#|\n-"

a = a:gsub("&","       ")

a = a:gsub("([0-9*#])","|   %1   ")

a = a:gsub("-",("-"):rep(25))

print(a)


## JavaScript (ES6), 184 182 bytes

f=
_=>-
! |  ABC  |  DEF  |
!1!2!3|
-
|  GHI  |  JKL  |  MNO  |
!4!5!6|
-
| PQRS  |  TUV  | WXYZ  |
!7!8!9|
-
! ! ! |
!*!0!#|
-.replace(/-|!./g,s=>s<-?|   ${s[1]} :s.repeat(25)) ;document.write('<pre>'+f()); The rows of dashes are obviously compressible and the digits were too but I couldn't do anything with the letters. Edit: Saved 1 of 2 bytes thanks to @Shaggy. • Save a byte with: replace(/-|!./g,s=>s=="-"?s.repeat(25):"|${s[1]} ") - replacing quotation marks with backticks. I tried a few things to pad out the letter groups but the best I could do was 194 bytes. Apr 25 '17 at 8:17
• @Shaggy Thanks, and I managed to shave another byte off that too!
– Neil
Apr 25 '17 at 8:51

## CJam, 128 bytes

'-25*N+:A" ABC DEF GHI JKL MNO PQRS TUV WXYZ   "S/3/{['|\{_,5\-S*\"  |"}%N]:+:+}%"123456789*0#"1/3/{['|\{S3*_@@'|}%N]:+:+}%.+A*A


Try it online.

## Perl, 142+1 = 143 bytes

$perl -MCompress::Zlib x.pl$ cat x.pl
print uncompress(<DATA>)
__DATA__
x<9c><d3><d5><c5>^A<b8>j^T ^@H;:9<83>i^WW7 ^M<96>1<84><c8>(^XAic<10><cb>0<b0>i<ee>^^<9e><b5>^<de>><da><d7><cf>^_f<9a> <d4>^TS(mFд<80> <b0>ڐ<d0>0^P^]^^^Q^Y^E3<cd>^\j<8a>^E<94><b6>$<ec>6<98>OQi<b0><8c>^VT<c4>^@J+<e3>7^M^@^D:@k  Unprintable characters, so uuencoded version is below. $ cat x.pl.uue
begin 664 x.pl
M<')I;G1?=6YC;VUP<F5S<R@\1$%403XI"E]?1$%405]?"GB<T]7%;AJ%"
M2#LZ.8-I%U<W(V6,83(*!A!:6,0S87+,+!I[AZ>8+5>WCY@VM?/'V::"=04
M4RAM1M"T@,"@8+#:D-P$!T>$1D%,\T<:HH%E+8D[#:83U%IL(P65,02BOC
(-PT!#I:PH

end
$ • Wait, shouldn't -M... be counted as well? – Ven Mar 29 '16 at 17:02 # Python 3.5 - 240 bytes: k=' ABC DEF 1 2 3 GHI JKL MNO 4 5 6 PQRS TUV WXYZ 7 8 9 * 0 #'.split(' ') for _ in range(8): print('\n',end='') if _%2==0:print("-"*27+'\n',end='') [print('|{}|'.format(g.center(7)),end='')for g in k[:3:1]];del k[:3:1] print('\n'+"-"*27)  Prints just what the OP wants, although it may be a bit long. # Python 2, 200 r=str.replace;print r(r(r(r(r("""-.| ABCDEF ,1=,2=,3 -| GHIJKLMNO ,4=,5=,6 -| PQRSTUVWXYZ | ,7=,8=,9 -...| ,*=,0=,# -""","-","\n"+"-"*25+"\n"),".",",= "),",","|="),""," | "),"="," ")  Simple replacing strategy. ## Python 2, 168 bytes A straightforward method using no built-in compression: for i in range(13):print['-'*25,'|'+'|'.join(["123456789*0#"," ABC DEF GHI JKL MNO PQRS TUV WXYZ ".split(' ')][i%3%2][i/3%4*3+m].center(7)for m in[0,1,2])+'|'][i%3>0]  # ///, 154 characters /%/=====//=/-----//?/ ! //!/} //{/ }//}/ |//(/| /% ( !ABC!DEF} (1?2?3{ % | GHI!JKL!MNO} (4?5?6{ % | PQRS!TUV} WXYZ} (7?8?9{ % ( ! ! } (*?0?#{ %  # GML (Game Maker Language) 8.0, 269 bytes a='-------------------------'b=' | 'c=' |#| 'draw_text(0,0,a+"#| | ABC | DEF"+c+"1"+b+"2"+b+"3 |#"+a+"#| GHI | JKL | MNO"+c+"4"+b+"5"+b+"6 |#"+a+"#| PQRS | TUV | WXYZ"+c+"7"+b+"8"+b+"9 |#"+a+"#| "+b+" "+b+" "+c+"*"+b+"0"+b+"\# |#"+a)  In Game Maker, # is the newline character and it can be escaped by \# # Python 2, 134 bytes This source contains non-printable characters, so it is presented as a hexdump that can be decoded with xxd -r. 00000000: efbb bf70 7269 6e74 2778 01d3 c505 b86a ...print'x.....j 00000010: 1420 5c30 483b 3a39 8369 1757 3720 5c72 . \0H;:9.i.W7 \r 00000020: 9631 84c8 2818 4169 6310 cd85 d734 770f .1..(.Aic....4w. 00000030: 4fb0 5a2f 6f1f 30ed ebe7 0f33 cd04 6a8a O.Z/o.0....3..j. 00000040: 2994 3623 685a 4060 5030 586d 4868 1888 ).6#hZ@P0XmHh.. 00000050: 0e8f 888c 8299 660e 35c5 024a 5b12 345c ......f.5..J[.4\ 00000060: 7202 3068 b08c 1654 c45c 304a 2be3 375c r.0h...T.\0J+.7\ 00000070: 725c 3004 3a40 6b27 2e64 6563 6f64 6528 r\0.:@k'.decode( 00000080: 277a 6970 2729 'zip')  # 05AB1E, 91 bytes (non-competing) •O«ò•3B7ô'-7×.ø'|ìε3×}'|«D¦Ð)˜»A3ô5£ðý"pqrs tuvwxyz"‚J5úR12úRv0y.;}1ð:2'A:9LJ"*0#"«v'Ay.;}u  Try it online! # J, 105 103 bytes 9!:7'|'9}11#'-' echo'PW'(7 2;7 18)}":_3;/\(12{.'',8 3$65{26-.&'PW'\a.),:&(5|.7{.])"1' ',.'123456789*0#'
`

Try it online!