Draw ASCII Playing Cards

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);
}

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());
        }
    }
}