Marhjong win check: ver 0.2

%a.out 1112345678999
[23](111)(456)(789)(99)
(123)[11](456)(789)(99)
(111)(345)(678)(999)[2]
(123)[45](678)(999)(11)
(111)(234)[56](789)(99)
(111)(234)(678)(999)[5]
(123)(456)[78](999)(11)
(111)(234)(567)[89](99)
(111)(234)(567)(999)[8]
(123)(456)(789)[99](11)
#include <stdio.h>
#include <stdlib.h>

#define PIECE_KINDS 9
#define PIECE_CHAR(id) ('1'+(id))
// place sentinel value -1 at the end margin
typedef int Hand[PIECE_KINDS+2];

// 111-type triplet id
#define TRIPLET_ID_111(i) ((i)|0x1000)
// 123-type triplet id
#define TRIPLET_ID_123(i) ((i)|0x2000)
// hack: also print a pair
#define TRIPLET_ID_PAIR(i) ((i)|0x4000)

#define TRIPLET_IS_111(t) ((t)&0x1000)
#define TRIPLET_IS_123(t) ((t)&0x2000)
#define TRIPLET_IS_PAIR(t) ((t)&0x4000)
#define TRIPLET_FLAG_MASK 0xfff

// hypothesical draw
int one_drawn;

static void print_triplets(int ntriplet, int *triplets);

// Check if given hand has one pair plus (4-ntriplet) triplets
//  May call itself recursively.
//
//  input:
//  Hand hand: hand data to check
//  int start: hand has no triplets nor pair in a range 0 .. start-1
//  int pair_idx: -1 if pair is needed. pair_idx!=-1. When we already have a pair, pair_idx= piece id
//  int ntriplet: number of triplets we already have
//  int *triplets: id's of triplets we already have
bool Win(Hand hand, int start, int pair_idx,int ntriplet, int *triplets)
{
    int i=start;
    bool result = false;

    if(ntriplet==4 && pair_idx !=-1)
    {
	// Win!
	triplets[4] = TRIPLET_ID_PAIR(pair_idx);
	print_triplets(5, triplets);
	return true;
    }

    while(hand[i] ==0)
    { 
	// no more pieces in hand
	if (hand[i] == -1) return false;
	i++;
    }

    //fork: possible pair found
    //  hand[i]=3, 4 case is handled after 123-type is removed
    if(hand[i] ==2 && pair_idx == -1) 
    {
	hand[i]-=2;
	result |= Win(hand, i+1, i, ntriplet, triplets);
	hand[i]+=2;
    }

    //fork: possible 111-type found
    //  hand[i]=4 case is handled after 123-type is removed
    if(hand[i]==3)
    {
	hand[i]-=3;
	triplets[ntriplet] = TRIPLET_ID_111(i);
	result |= Win(hand, i+1, pair_idx, ntriplet+1, triplets);
	hand[i]+=3;
    }

    //fork: possible 123-type found
    if(hand[i+1]>0 && hand[i+2]>0 )
    {
	hand[i]--;
	hand[i+1]--;
	hand[i+2]--;
	triplets[ntriplet] = TRIPLET_ID_123(i);
	result |= Win(hand, i, pair_idx, ntriplet+1, triplets);
	hand[i]++;
	hand[i+1]++;
	hand[i+2]++;
    }
    return result;

}

// I/O routnes

void print_hand(Hand hand)
{
    int i,j;
    for(i=0;i<PIECE_KINDS;i++)
    {
	for(j=0;j<hand[i];j++) putchar(PIECE_CHAR(i));
    }
    printf("\n");
}

int triplet_has_id(int tid, int id)
{
    int id0 = tid & TRIPLET_FLAG_MASK;
    if(id0 == id) return 1;
    if(TRIPLET_IS_123(tid))
    {
	//  id * * : return 1
	//  * id * : return 2
	//  * * id : return 3
	if(id0+1 == id) return 2;
	//Hack: special value for 12(3) type
	if(id0+2 == id && id==0) return 4;
	if(id0+2 == id) return 3;
    }
    return 0;
}

void print_triplet(int id, int omit_id)
{
    if(omit_id ==-1)
	putchar('(');
    else
	putchar('[');
    int id0 = id&TRIPLET_FLAG_MASK;

    if(TRIPLET_IS_PAIR(id))
    {
	putchar(PIECE_CHAR(id0));
	if(omit_id != id0) putchar(PIECE_CHAR(id0));
    }
    else if(TRIPLET_IS_123(id))
    {
	if(omit_id != id0) putchar(PIECE_CHAR(id0));
	if(omit_id != id0+1) putchar(PIECE_CHAR(id0+1));
	if(omit_id != id0+2) putchar(PIECE_CHAR(id0+2));
    }
    else
    {
	if(omit_id != id0) putchar(PIECE_CHAR(id0));
	putchar(PIECE_CHAR(id0));
	putchar(PIECE_CHAR(id0));
    }

    if(omit_id ==-1)
	putchar(')');
    else
	putchar(']');
}

void print_triplets(int ntriplet, int *triplets)
{
    int i,j;

    for(i=0;i<5;i++)
    {
	int f=triplet_has_id(triplets[i], one_drawn);
	if(f!=0 && f!=3)
	{
	    for(j=0;j<5;j++) print_triplet(triplets[j], (i==j) ? one_drawn:-1);
	    printf("\n");
	}
    }

}

int main(int argc, char **argv)
{

    int i;
    if(argc!=2)exit(1);
    Hand hand;
    for(i=0;i<PIECE_KINDS;i++)hand[i]=0;

    // place sentinel
    hand[PIECE_KINDS]=hand[PIECE_KINDS+1]=-1;

    // input
    for(i=0;i<13;i++)
    {
	if(argv[1][i]==0)exit(1);
	int kind=argv[1][i]-'0';
	if(kind<1 || kind>9)exit(1);
	hand[kind-1]++;
    }

    int triplets[5];
    // hypothesical one draw loop
    for(i=0;i<PIECE_KINDS;i++)
    {
	one_drawn=i;
	int j;
	// hypothesical one draw
	hand[i]++;

	//start from 0, pair= -1, triplets=0
	Win(hand, 0, -1, 0, triplets);
	hand[i]--;
    }
}