第五回オフラインリアルタイムどう書くの回答例(C99 でもう一度)

第五回オフラインリアルタイムどう書く( http://atnd.org/events/32979 )。
問題は下記 URL。
http://nabetani.sakura.ne.jp/hena/ord5dahimi/
で。
当日その場で書いたもの( http://qiita.com/items/6faf952a90659b736037 )があまりにもひどいので書きなおしたのがこれ。

```c
// use "-std=c99"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <math.h>

char const ORDER[]="3456789TJQKA2o";
enum{  JOKER = 13 };
int strength( char const * card )
{
    return strchr( ORDER, card[1] ) - ORDER;
}
int compareByStrength(const void *va, const void *vb)
{
    char const * a=va;
    char const * b=vb;
    return strength(a) - strength(b);
}
char const * firstCard( int s, char const * cards )
{
    for( char const * p=cards ; *p ; p+=2 ){
        if ( s==strength(p) ){
            return p;
        }
    }
    return 0;
}
int population( size_t bits ){
    int r=0;
    for( int b=1 ; b<=64 ; b<<=1 ){
        r+=!!(bits&b);
    }
    return r;
}
void addAvailables( char * result, int s, int count, char const * cards, char const * postfix )
{
    char const * begin = firstCard( s, cards );
    if ( ! begin ){
        return;
    }
    char const * end=begin;
    for( ; *end && s==strength( end ) ; end+=2 );
    int sample = ( end-begin ) / 2;
    if ( sample<count ){
        return;
    }
    for( size_t bits=1 ; bits<(1<<sample) ; ++bits ){
        if ( count != population( bits )){
            continue;
        }
        if ( * result ){
            strcat( result, "," );
        }
        strcat( result, postfix );
        for( int i=0 ; i<sample ; ++i ){
            if ( bits & (1<<i) ){
                strncat( result, begin+i*2, 2 );
            }
        }
    }
}
char const * solve( char const * input )
{
    char * f = strdup( input );
    char * inHand = strchr( f, ',')+1;
    inHand[-1]=0;
    int nofCardsInHand = strlen( inHand ) / 2;
    int nofCardsInPlay = strlen( f )/2;
    char * result = calloc( pow( nofCardsInHand+1, nofCardsInPlay+1 ), nofCardsInHand*2+1 );
    qsort( f, strlen( f )/2, 2, compareByStrength );
    qsort( inHand, strlen( inHand )/2, 2, compareByStrength );
    int jokerAsWildcard = 1<nofCardsInPlay && firstCard( JOKER, inHand );
    for( int r=strength( f )+1 ; r<14 ; ++r ){
        addAvailables( result, r, nofCardsInPlay, inHand, "" );
        if ( jokerAsWildcard && r!=JOKER ){
            addAvailables( result, r, nofCardsInPlay-1, inHand, "Jo" );
        }
    }
    free( f );
    if ( !*result ){
        *result='-';
    }
    return result;
}
int compare(const void *a, const void *b)
{
    return *(char*)a - *(char*)b;
}
int is_same( char const * a, char const * b )
{
    // いい加減だけど、だいぶ正しい。
    size_t len = strlen(a);
    if ( len != strlen(b) ){
        return 0;
    }
    char * a1 = strdup(a);
    char * b1 = strdup(b);
    qsort(a1, len, 1, compare );
    qsort(b1, len, 1, compare );
    int r = 0==strcmp( a1, b1 );
    free( a1 );
    free( b1 );
    return r;
}

void test( char const * in, char const * expected )
{
    char const * ac = solve( in );
    if ( ! is_same( ac, expected) ){
        puts( "**FAIL**");
    }
    printf( " : %s\n    %s\n    %s\n", in, ac, expected );
    free( ac );
}

int main()
{
// テストデータは大半を省略。
/*#1*/ test( "DJ,", "-" );
/*#7*/ test( "ST,D6S8JoC7HQHAC2CK", "Jo,C2,CK,HA,HQ" );
/*#10*/ test( "Jo,HAC8DJSJDTH2", "-" );
/*#30*/ test( "D4H4S4C4,S6SAH6HAD6DAC6CAJo", 
/*#32*/ test( "JoS8D8H8,S9DTH9CTD9STC9CAC2", "H9C9D9S9" ); 
   return 0;
}
```

再帰呼び出しを bit 演算で回避した。
テストが成功したかどうかの判断はまだ不完全だが、C99 なら 対費用効果としてこのあたりが落としどころかと。