Score a Cribbage Hand
C, 364 388 chars

It's big and ugly (though not as big as it once was):

char*L="CA23456789TJQKDHS",b[20],p[15],r[5],s[5],v,i=4,t,m,q;
g(j){++p[r[i]=strchr(L,b[j])-L];s[i]=strchr(L,b[j+1])-L;}
f(j,u){u==15?v+=2:++j&lt;5&amp;&amp;f(j,u,f(j,u+(r[j]&gt;9?10:r[j])));}
main(){gets(b);for(g(14);i--;r[i]^11|s[i]^s[4]||++v)g(i*3);
for(f(i,0);++i&lt;15;v+=q?q*q-q:t&gt;2?t*m:0,t=q?t+1:0,m=q?m*q:1)q=p[i];
while(++t&lt;5&amp;&amp;s[t]==*s);v+=t&gt;4-!b[16]?t:0;printf("%d\n",v?v:19);}


(Line breaks were added to make it easier to read; those aren't included in the above tally.)

The problem description didn't specify if the code needed to check for invalid input, so naturally I assumed that the program was free to misbehave at will if the input, say, contained extra whitespace.

Here's the ungolfed version:

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

/* A-K correspond to values 1-13. Suit values are arbitrary.
 */
static char const *symbols="CA23456789TJQKDHS";

/* Used as both an input buffer and to bucket cards by rank.
 */
static char buf[20];

/* The cards.
 */
static int rank[5], suit[5];

/* The cards broken down by rank.
 */
static int buckets[15];

static int score;
static int touching, matching, i;

/* Read card number i from buf at position j.
 */
static void getcard(int j)
{
    rank[i] = strchr(symbols, buf[j]) - symbols;
    suit[i] = strchr(symbols, buf[j+1]) - symbols;
    ++buckets[rank[i];
}

/* Recursively find all combinations that add up to fifteen.
 */
static void fifteens(int j, int total)
{
    for ( ; j &lt; 5 ; ++j) {
        int subtotal = total + (rank[j] &gt; 9 ? 10 : rank[j]);
        if (subtotal == 15)
            score += 2;
        else if (subtotal &lt; 15)
            fifteens(j + 1, subtotal);
    }
}

int main(void)
{
    fgets(buf, sizeof buf, stdin);
    score = 0;

    /* Read cards from buf */
    for (i = 0 ; i &lt; 4 ; ++i)
        getcard(i * 3);
    getcard(14);

    /* Score fifteens */
    fifteens(0, 0);

    /* Score any runs and/or pairs */
    touching = 0;
    matching = 1;
    for (i = 1 ; i &lt; 15 ; ++i) {
        if (buckets[i]) {
            score += buckets[i] * (buckets[i] - 1);
            ++touching;
            matching *= buckets[i];
        } else {
            if (touching &gt; 2)
                score += touching * matching;
            touching = 0;
            matching = 1;
        }
    }

    /* Check for flush */
    for (i = 1 ; i &lt; 5 &amp;&amp; suit[i] == suit[0] ; ++i) ;
    if (i &gt;= (buf[17] == '!' ? 5 : 4))
        score += i;

    /* Check for hisnob */
    for (i = 0 ; i &lt; 4 ; ++i)
        if (rank[i] == 11 &amp;&amp; suit[i] == suit[4])
            ++score;

    printf("%d\n", score ? score : 19);
    return 0;
}