# Draw ASCII Playing Cards

Consider these 15 ASCII playing card patterns (ace through Joker, and the back side), where X is a placeholder for the suit symbol: (they look better with less line spacing)

 -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------
|AX           | |2X           | |3X           | |4X           | |5X           | |6X           | |7X           | |8X           | |9X           | |10X          | |JX           | |QX           | |KX           | |J            | |* * * * * * *|
|   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |O  -------   | | * * * * * * |
|  |       |  | |  |       |  | |  |       |  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X      |  | |  |X      |  | |  |X      |  | |K |       |  | |* * * * * * *|
|  |       |  | |  |   X   |  | |  |   X   |  | |  |       |  | |  |       |  | |  |       |  | |  |   X   |  | |  |   X   |  | |  |       |  | |  |   X   |  | |  |       |  | |  |       |  | |  |       |  | |E | J     |  | | * * * * * * |
|  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |X     X|  | |  |X     X|  | |  |       |  | |  |       |  | |  |       |  | |R |  O    |  | |* * * * * * *|
|  |   X   |  | |  |       |  | |  |   X   |  | |  |       |  | |  |   X   |  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |   X   |  | |  |       |  | |  |   J   |  | |  |   Q   |  | |  |   K   |  | |  |   K   |  | | * * * * * * |
|  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |X     X|  | |  |X     X|  | |  |       |  | |  |       |  | |  |       |  | |  |    E  | J| |* * * * * * *|
|  |       |  | |  |   X   |  | |  |   X   |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |   X   |  | |  |       |  | |  |   X   |  | |  |       |  | |  |       |  | |  |       |  | |  |     R | O| | * * * * * * |
|  |       |  | |  |       |  | |  |       |  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |X     X|  | |  |      X|  | |  |      X|  | |  |      X|  | |  |       | K| |* * * * * * *|
|   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------  E| | * * * * * * |
|           XA| |           X2| |           X3| |           X4| |           X5| |           X6| |           X7| |           X8| |           X9| |          X10| |           XJ| |           XQ| |           XK| |            R| |* * * * * * *|
-------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------


Write a program that takes in a string denoting a space separated sequence of cards using...

• A 2 3 4 5 6 7 8 9 10 J Q K followed by one of C D H S (for clubs, diamonds, hearts, and spades) for the 52 standard cards.
• A single R for a Joker.
• A single B for the back side (a face down card).

So the string B AS KH 10C R JD denotes a face down card, followed by an ace of spades, followed by a king of hearts, followed by a ten of clubs, followed by a Joker, followed by a jack of diamonds.

Your program needs to print the corresponding ASCII playing cards to stdout, replacingX with the appropriate suit symbol.

For example, the output for B AS KH 10C R JD would be

 -------------   -------------   -------------   -------------   -------------   -------------
|* * * * * * *| |AS           | |KH           | |10C          | |J            | |JD           |
| * * * * * * | |   -------   | |   -------   | |   -------   | |O  -------   | |   -------   |
|* * * * * * *| |  |       |  | |  |H      |  | |  |C     C|  | |K |       |  | |  |D      |  |
| * * * * * * | |  |       |  | |  |       |  | |  |   C   |  | |E | J     |  | |  |       |  |
|* * * * * * *| |  |       |  | |  |       |  | |  |C     C|  | |R |  O    |  | |  |       |  |
| * * * * * * | |  |   S   |  | |  |   K   |  | |  |       |  | |  |   K   |  | |  |   J   |  |
|* * * * * * *| |  |       |  | |  |       |  | |  |C     C|  | |  |    E  | J| |  |       |  |
| * * * * * * | |  |       |  | |  |       |  | |  |   C   |  | |  |     R | O| |  |       |  |
|* * * * * * *| |  |       |  | |  |      H|  | |  |C     C|  | |  |       | K| |  |      D|  |
| * * * * * * | |   -------   | |   -------   | |   -------   | |   -------  E| |   -------   |
|* * * * * * *| |           SA| |           HK| |          C10| |            R| |           DJ|
-------------   -------------   -------------   -------------   -------------   -------------


You can take the input from stdin or write a function that takes a string.

The submission with the shortest number of characters wins.

Bonus: Subtract 30 from your character count if you use the black Unicode suit symbols ♣ ♦ ♥ ♠ instead of C D H S in your output. (The input always uses C D H S.)

# Notes

• There may be more than 54 cards in the input string and there may be duplicates of any card.
• There should be no output if the input is the empty string.
• There should be no trailing spaces besides (optionally) the two that make up the right corners of the last card.
• You may assume the input is valid.
• Update: The lower right label on standard cards has been reversed so the value is in the corner. The lower right Joker label hasn't changed.
• Can we assume the input string is valid ? Sep 29, 2014 at 8:17
• @VisualMelon I tried that but it looks funny. It will stay upright. Sep 29, 2014 at 8:22
• @Optimizer I would do that if there were designated upsidedown characters for what I need but I don't think there are and I don't want it all wonky. Sep 29, 2014 at 8:31
• @VisualMelon I know that realistically half of the labels would be upside down, but since there aren't upside down characters for that I'm ignoring that fact (besides that I wanted the values in the corner). Sep 29, 2014 at 9:18
• If you're only going to subtract 10 points for properly Unicoding the symbols, it's never going to be worth it because you need more than that just to write them (6 characters per symbol, 24 overall). Even if you got a unicode-compliant language, the unicode symbols are in the reverse order from your input when alphabetical. I think only something like CJAM, APL or Golfscript would be able to do that. Sep 29, 2014 at 13:48

# JavaScript (E6) 542 (572 - bonus 30) 553 564 576

3 kinds of shapes:

1. Back and Joker: more or less literal
2. JQK: mark at topleft and rightbottom, inner frame and 3 kind of rows inside, always the same structure
3. A...10: mark at topleft and rightbottom, inner frame with 3 kind of rows inside, variable with the numeric value. Taken care of with lookup using array and q variable

The z string (compressed) contains the basic building blocks for

• numeric cards - 3 blocks, 7 chars each
• joker - 11 blocks, 13 char each, used simply in sequence

Bonus note The code for winning the 30 points bonus is 29 chars.

F=c=>(
p='|',b=' ',d=b+b,t=d+b,
S='substr',
z="9J2J4J55O102K |6|1E | J4|1R |1O3|3|2K2|3|3E1| J1|4R | O1|6| K201E55R".replace(/\d/g,n=>n++?b.repeat(n):l='-------'),
i=7,
console.log([c.split(b).map(c=>
m<d
?b+l+l[S](1)+b
:p+(c=='B'
?'* '.repeat(i)[S](i,13)
:c=='R'
?z[S](i,13)
:(
[,h,k]=c.match(/(.+)(.)/),
k='♣♦♥♠'['CDHS'.search(k)], //comment to avoid the unicode symbols
n=h-1|0,
s=t+t+t+(n>8?b:d),
m-7
?m-8
?m-9
?d+p+(h>'A'
?-m?m-6?m-3?t+b+t:t+h+t:t+t+k:k+t+t
:z[S](([64,1028,1092,8194,8258,8322,8326,9350,8802,9766][n]>>m*2&3)*7,7).replace(/J/g,k)
)+p+d
:t+l+t
:s+k+h
:h+k+s
)
)+p
).join(b,i+=13)
for(m of ' 79012345698 ')].join('\n'))
)


Test In FireFox/FireBug console

F('10C JD QH KS AC B R')

F('2C 3D 4H 5S 6C 7D 8H 9S')


Output

 -------------   -------------   -------------   -------------   -------------   -------------   -------------
|10♣          | |J♦           | |Q♥           | |K♠           | |A♣           | |* * * * * * *| |J            |
|   -------   | |   -------   | |   -------   | |   -------   | |   -------   | | * * * * * * | |O  -------   |
|  |♣     ♣|  | |  |♦      |  | |  |♥      |  | |  |♠      |  | |  |       |  | |* * * * * * *| |K |       |  |
|  |   ♣   |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | | * * * * * * | |E | J     |  |
|  |♣     ♣|  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |* * * * * * *| |R |  O    |  |
|  |       |  | |  |   J   |  | |  |   Q   |  | |  |   K   |  | |  |   ♣   |  | | * * * * * * | |  |   K   |  |
|  |♣     ♣|  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |* * * * * * *| |  |    E  | J|
|  |   ♣   |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | | * * * * * * | |  |     R | O|
|  |♣     ♣|  | |  |      ♦|  | |  |      ♥|  | |  |      ♠|  | |  |       |  | |* * * * * * *| |  |       | K|
|   -------   | |   -------   | |   -------   | |   -------   | |   -------   | | * * * * * * | |   -------  E|
|          ♣10| |           ♦J| |           ♥Q| |           ♠K| |           ♣A| |* * * * * * *| |            R|
-------------   -------------   -------------   -------------   -------------   -------------   -------------

-------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------
|2♣           | |3♦           | |4♥           | |5♠           | |6♣           | |7♦           | |8♥           | |9♠           |
|   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   |
|  |       |  | |  |       |  | |  |♥     ♥|  | |  |♠     ♠|  | |  |♣     ♣|  | |  |♦     ♦|  | |  |♥     ♥|  | |  |♠     ♠|  |
|  |   ♣   |  | |  |   ♦   |  | |  |       |  | |  |       |  | |  |       |  | |  |   ♦   |  | |  |   ♥   |  | |  |       |  |
|  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |♠     ♠|  |
|  |       |  | |  |   ♦   |  | |  |       |  | |  |   ♠   |  | |  |♣     ♣|  | |  |♦     ♦|  | |  |♥     ♥|  | |  |   ♠   |  |
|  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |♠     ♠|  |
|  |   ♣   |  | |  |   ♦   |  | |  |       |  | |  |       |  | |  |       |  | |  |       |  | |  |   ♥   |  | |  |       |  |
|  |       |  | |  |       |  | |  |♥     ♥|  | |  |♠     ♠|  | |  |♣     ♣|  | |  |♦     ♦|  | |  |♥     ♥|  | |  |♠     ♠|  |
|   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   | |   -------   |
|           ♣2| |           ♦3| |           ♥4| |           ♠5| |           ♣6| |           ♦7| |           ♥8| |           ♠9|
-------------   -------------   -------------   -------------   -------------   -------------   -------------   -------------


Not golfed code

F=c=>
{
p='|',b=' ',d=b+b,t=d+b;
l='------';
z="9X2X4XJ55O10-2K |6|1E | J4|1R |1O3|3|2K2|3|3E1| J1|4R | O1|6| K20-1E55R".replace(/\d/g,n=>-n?b.repeat(-~n):l);
c=c.split(b);
for(o=i=''; c[0]&&i<13; i++)
{
o+=c.map(c => {
if (i==0 || i==12) r=' -'+l+l+b;
else
{
if (c=='B') r=' *'.repeat(7).substr(i&1,13);
else if (c=='R') r=z.substr(i*13+8,13);
else {
[,h,k]=c.match(/(.+)(.)/),n=h-1|0,
k='♣♦♥♠'[{C:0,D:1,H:2,S:3}[k]],
r=t+t+t+(n>8?b:d);
if(i==1)r=h+k+r;
else if(i==11)r+=k+h;
else if(i==2||i==10)r=t+'-'+l+t;
else {
if (h>'A')
{
if(i==3)r=k+t+t;
else if(i==9)r=t+t+k;
else if(i==6)r=t+h+t;
else r=t+b+t
}
else
{
q=[64,1028,1092,8194,8258,8322,8326,9350,8802,9766][n]>>(i+i-6)&3,
r=z.substr(q*7,7).replace(/X/g,k)
}
r=d+p+r+p+d
}
}
r=p+r+p
}
return r
}).join(' ')+'\n'
}
console.log(o);
}

• I think you swapped hearts and diamonds (in your example run anyway, I haven't been able to find the error in your code...). Sep 29, 2014 at 16:46
• @FryAmTheEggman thanks, fixed in golfed code and examples Sep 29, 2014 at 17:25
• great code! You can reduce your char count with this tool: xem.github.io/obfuscatweet (it only accepts ASCII though, so you have to escape the unicode chars before packing)
– xem
Sep 29, 2014 at 19:12
• (Your final result will then be around 328!)
– xem
Sep 29, 2014 at 19:18
• @xem The char count is low (337) but the byte count is high(1213) mothereff.in/byte-counter. Unless specified, you have to count bytes in code golf. Sep 29, 2014 at 19:51

# C# - 906

Rather large and simple C# program that takes command-line input and outputs to standard output. There is probably a lot that can still be golfed, I've spotted a few boring bytes while writing this, but that will have to wait. I don't think I will be going for the Unicode suit character bonus.

Golfed code:

class P{static void Main(string[]A){int O,i=0,L,n;for(;i<13;i++){var k="";foreach(var a in A){var R=new char[208];System.Action<int,int,string,int>P=(s,l,g,w)=>{for(O=0;O<l;s+=O%w<1?17-w:1)R[s]=g[O++%g.Length];};P(0,208," ",16);P(1,13,"-",13);P(193,13,"-",13);P(16,11,"|",1);P(30,11,"|",1);if(a=="B")P(17,143,"* ",13);else{P(36,7,"-",7);P(164,7,"-",7);P(51,7,"|",1);P(59,7,"|",1);if(a=="R"){P(17,5,"JOKER",1);P(125,5,"JOKER",1);P(69,25,"J     O     K     E     R",5);}else{L=a.Length;var S=a.Substring(L-1);var v=a.Substring(0,L-1);P(17,L,a,L);P(190-L,L,S+v,L);if(int.TryParse(v,out n)){var f=new string[]{S="HEHI",S+"HG",S="EDKDEJKJ",S+"HG",v=S+"EGKG",v+="HE",v+"HI",(S+="EFEHKFKH")+"HG",S+"HEHI",}[n-2];for(O=0;O<f.Length;)R[f[O++]+f[O++]*16-1105]=a[L-1];}else{if(v=="A"){P(103,1,S,1);}else{P(52,1,S,1);P(154,1,S,1);P(103,1,v,1);}}}}for(O=0;O<16;)k+=R[i*16+O++];}System.Console.WriteLine(k.TrimEnd());}}}


Example output for cardGolf.exe 7H QH 3S B R

 -------------   -------------   -------------   -------------   -------------
|7H           | |QH           | |3S           | |* * * * * * *| |J            |
|   -------   | |   -------   | |   -------   | | * * * * * * | |O  -------   |
|  |H     H|  | |  |H      |  | |  |       |  | |* * * * * * *| |K |       |  |
|  |   H   |  | |  |       |  | |  |   S   |  | | * * * * * * | |E | J     |  |
|  |       |  | |  |       |  | |  |       |  | |* * * * * * *| |R |  O    |  |
|  |H     H|  | |  |   Q   |  | |  |   S   |  | | * * * * * * | |  |   K   |  |
|  |       |  | |  |       |  | |  |       |  | |* * * * * * *| |  |    E  | J|
|  |       |  | |  |       |  | |  |   S   |  | | * * * * * * | |  |     R | O|
|  |H     H|  | |  |      H|  | |  |       |  | |* * * * * * *| |  |       | K|
|   -------   | |   -------   | |   -------   | | * * * * * * | |   -------  E|
|           H7| |           HQ| |           S3| |* * * * * * *| |            R|
-------------   -------------   -------------   -------------   -------------


Most of the rendering is done by the P anonymous method, which takes a position, length, string, and width, and renders a rectangle of the string end on end. For example, the back of the card is just "* " repeated. The T anonymous method is a modified version of one I used for a previous task, which renders lots of rectangles. It is, however, rather bulky, and would only allow me to render the borders and background in fewer bytes, which probably isn't worth it. A striped down version of T is W which renders cells rather than rectangles, and also isn't used, but an inlined version of it is used to render cards of value 2 through 10. Note that unused code was removed for the byte count, I'm leaving it in because I may end up using it, and I do use them for testing.

The program simply loops through each line of output (13 of them) and then renders each card in turn, and then extracts 1 slice from it, so each card is rendered in it's entirety 13 times. For the purpose of spacing them, each card is treated as a 16 by 13 block, and I trim each line of output to remove trailing spaces (the corner spaces are removed).

Formatted code, with comments and concept/testing code:

class P
{
static void Main(string[]A)
{
int O,J,i=0,L,n,r,z;

for(;i<13;i++)
{
var k="";
foreach(var a in A)
{
// got card a and line i

var R=new char[208];

System.Action<int,int,string,int>P=(s,l,g,w)=>
{
for(O=0;O<l;s+=O%w<1?17-w:1)
R[s]=g[O++%g.Length];
};

// not used
System.Action<string>T=f=>
{
f+="AAPM!";
for(J=64;J++<77;)
for(O=64;O++<80;R[z=O+J*16-1105]=f[r]=='!'?R[z]:f[r])
for(r=0;f[r++]>O|f[r++]>J|O>f[r++]|J>f[r++];r++);
};

// not used (derivative below)
System.Action<string>W=f=>
{
for(O=0;O<f.Length;)
R[f[O++]+f[O++]*16-1105]=f[O++];
};

// render

// outer

P(0,208," ",16); // fill
P(1,13,"-",13); // top
P(193,13,"-",13); // bottom
P(16,11,"|",1); // left
P(30,11,"|",1); // left

//T("BBNL BANM-ABOL|AAPM ");

if(a=="B") // back
P(17,143,"* ",13);
else
{
// inner

P(36,7,"-",7); // top
P(164,7,"-",7); // bottom
P(51,7,"|",1); // left
P(59,7,"|",1); // left

//T("EDKJ ECKK-DDLJ|");

// joker
if(a=="R")
{
P(17,5,"JOKER",1);
P(125,5,"JOKER",1);
P(69,25,"J     O     K     E     R",5);
//T("FEFEJGFGFOHGHGKIHIHEJIJIR");
}
else
{
L=a.Length;

// card
var S=a.Substring(L-1);
var v=a.Substring(0,L-1);

P(17,L,a,L);
P(190-L,L,S+v,L);

if(int.TryParse(v,out n))
{
// number card
var f=new string[]
{
S="HEHI",
S+"HG",
S="EDKDEJKJ",
S+"HG",
v=S+"EGKG",
v+="HE",
v+"HI",
(S+="EFEHKFKH")+"HG",
S+"HEHI",
}[n-2];
for(O=0;O<f.Length;)
R[f[O++]+f[O++]*16-1105]=a[L-1];
}
else
{
if(v=="A")
{
// ace
P(103,1,S,1);
}
else
{
// face card
P(52,1,S,1);
P(154,1,S,1);
P(103,1,v,1);
}
}
}
}

// write

for(O=0;O<16;)
k+=R[i*16+O++];
}
System.Console.WriteLine(k.TrimEnd());
}
}
}


# PowerShell, score 442 = (509495 472 bytes = (156 script + 316 archive) - 30 bonus)

param($s)tar xOf t|%{$l=$_ ($s-split'1| '-ne''|%{($l|% s*g(14*('A234567890JQKRB'|% i*f$_[0]))15)-replace'X','♣♦♥♠'[('CDHS'|% i*f $_[1])]})-join' '}  Try it online! Unrolled: # # the tar archive t should be in default folder param($s)
tar xOf t|%{ $line=$_
($s-split'1| '-ne''|%{$pos = 14*('A234567890JQKRB'|% indexOf $_[0])$x=$line|% SubString$pos 15

$suit = 'CDHS'|% indexOf$_[1]
$x-replace'X','♣♦♥♠'[$suit]
})-join' '                                          # implicit output
}


Powershell script to create the tar archive t (see TIO):

(
' ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ',
'|AX           |2X           |3X           |4X           |5X           |6X           |7X           |8X           |9X           |10X          |JX           |QX           |KX           |J            |* * * * * * *|',
'|   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |O  -------   | * * * * * * |',
'|  |       |  |  |       |  |  |       |  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X      |  |  |X      |  |  |X      |  |K |       |  |* * * * * * *|',
'|  |       |  |  |   X   |  |  |   X   |  |  |       |  |  |       |  |  |       |  |  |   X   |  |  |   X   |  |  |       |  |  |   X   |  |  |       |  |  |       |  |  |       |  |E | J     |  | * * * * * * |',
'|  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |X     X|  |  |X     X|  |  |       |  |  |       |  |  |       |  |R |  O    |  |* * * * * * *|',
'|  |   X   |  |  |       |  |  |   X   |  |  |       |  |  |   X   |  |  |X     X|  |  |X     X|  |  |X     X|  |  |   X   |  |  |       |  |  |   J   |  |  |   Q   |  |  |   K   |  |  |   K   |  | * * * * * * |',
'|  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |       |  |  |X     X|  |  |X     X|  |  |       |  |  |       |  |  |       |  |  |    E  | J|* * * * * * *|',
'|  |       |  |  |   X   |  |  |   X   |  |  |       |  |  |       |  |  |       |  |  |       |  |  |   X   |  |  |       |  |  |   X   |  |  |       |  |  |       |  |  |       |  |  |     R | O| * * * * * * |',
'|  |       |  |  |       |  |  |       |  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |X     X|  |  |      X|  |  |      X|  |  |      X|  |  |       | K|* * * * * * *|',
'|   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------   |   -------  E| * * * * * * |',
'|           XA|           X2|           X3|           X4|           X5|           X6|           X7|           X8|           X9|          X10|           XJ|           XQ|           XK|            R|* * * * * * *|',
' ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ------------- '
) | Set-Content f -Force
tar zcf t f -o
Get-ChildItem t # output info about archive size