#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <math.h>


// Simplification:	No Jokers
//			assume "most off" as optimal strategy
// Generalisation:	Any number of melds per cycle
#define cPlayers	 2
#define	cHandSize	12
#define cFirstMeld	30



#define ErrMax 1
void Error(int n)
{
 char *ErrMsg[ErrMax] = {
  "Insufficient memory" };

 if(n==101)
  fprintf(stderr,"The stack is empty !!!\nProgram aborted.\n\n");
 else if(n>=100)
  fprintf(stderr,"Internal program error (%d) !\nProgram aborted.\n\n",n);
 else
  fprintf(stderr,"Error %d: %s !\n",n,(n<=ErrMax)?ErrMsg[n-1]:"unknown error");
 exit(n);
}


//**********************************************************************//
//************************  basic help routines  ***********************//
//**********************************************************************//

#define  MaxRand 2147483647.0
int Random(int max)
{ return (int) (((double)rand()/MaxRand)* max ); }


//**********************************************************************//
//***********************  card  representation  ***********************//
//**********************************************************************//

// C(lub), S(pade), H(eart), D(iamond)
#define DIAMOND	0x00
#define DIAM	DIAMOND
#define HEART	0x10
#define SPADE	0x20
#define CLUB	0x30

// a(ce), 2, 3, 4, 5, 6, 7, 8, 9, (1)0, j(ack), q(ueen), k(ing)
#define ACE	1
#define JACK	11
#define QUEEN	12
#define KING	13

char ReprBuf[20];
char *c2r(char card)
{
 const char *val="a234567890jqk";
 const char *dhsc="DHSC";

 card&=0xFF;
 if( (card&0xF0)>CLUB || (card&0x0F)==0 || (card&0x0F)>KING) return NULL;
 char c1=val[(card&0x0F)-1], c2=dhsc[(card&0xF0)>>4];

 if(card>SPADE) sprintf(ReprBuf,"%c[00;01m%c%c%c[00m",27,c1,c2,27);
 else sprintf(ReprBuf,"%c%c",c1,c2);
 return ReprBuf;
}

char r2c(char *r)
{
 if(!r || strlen(r)<2) return 0;
 char c=0;
 switch(r[0]) {
  case 'a':	 c+=ACE;	break;
  case '2': case '3': case '4': case '5': case '6': case '7': case '8':
  case '9':	 c+=r[0]-'0';	break;
  case '0':	 c+=10;		break;
  case 'j':	 c+=JACK;	break;
  case 'q':	 c+=QUEEN;	break;
  case 'k':	 c+=KING;	break;
  default:	 return 0;
 }
 switch(r[1]) {
  case 'C':	c+=CLUB;	break;
  case 'S':	c+=SPADE;	break;
  case 'H':	c+=HEART;	break;
  case 'D':	c+=DIAMOND;	break;
  default:	return 0;
 }
 return c;
}

int IsLegalCard(char c) { return (c2r(c)!=NULL); }



//**********************************************************************//
//************************  set representation  ************************//
//**********************************************************************//

typedef char* tSet;
typedef tSet* tSets;

int Size(tSet s)
{ int i=0; while(s[i]) i++; return i; }

int IsLegal(tSet s)
{
 char c,diff; int i;

 if(Size(s)<3) return 0;
 diff=s[1]-s[0];
 switch(diff) {
  case 0x01:
   for(i=2;c=s[i];i++) if(c-s[i-1]!=0x01) return 0;
   break;
  case 0x10:
   if(s[4]) return 0;
   if(s[3]) { if(s[2]-s[1]!=0x10 || s[3]-s[2]!=0x10) return 0; }
   else     { if(s[2]-s[1]!=0x10 && s[2]-s[1]!=0x20) return 0; }
   break;
  case 0x20:
   if(s[3]) return 0;
   if(s[2]-s[1]!=0x10)  return 0;
   break;
  default:
   return 0;
 }
 return 1;
}

int Value(tSet s)
{
 if(!s) return 0;
 int sum=0;
 for(int i=0;s[i];i++) sum+=s[i]&0x0F;
 if(IsLegal(s)) { return sum; }	// hand-to-table-value (>0)
 else { return -sum; }		// on-hand-at-finish-cost (<0)
}

int ValueSets(tSets s)
{
 int sum=0;
 for(int n=0;s[n];n++) {
  if(!IsLegal(s[n])) return 0;
  for(int i=0;s[n][i];i++) sum+=s[n][i]&0x0F;
 }
 return sum;
}

int NumSets(tSets s)
{ int i=0; while(s[i]) i++; return i; }

void Kill(tSet *s) { free(*s); *s=NULL; }

void KillSets(tSets *s)
{ for(int n=0;(*s)[n];n++) Kill(&((*s)[n])); }

/* only indirectly called by "Insert" */
tSet NewSet()
{
 tSet ns=(tSet)malloc(KING<<3+2);
 if(!ns) Error(1);
 ns[0]=0;
 return ns;
}

void Insert(char c, tSet *s)
{
 int i;
 if(!(*s)) *s=NewSet();
 for(i=0;(*s)[i];i++); (*s)[i+1]=0;
 while((i>0) && ((*s)[i-1]>c)) { (*s)[i]=(*s)[i-1]; i--; }
 (*s)[i]=c;
}

int Emit(char c, tSet *s)
{
 int i;
 if(!(*s)) return 0;
 for(i=0;(*s)[i] && (*s)[i]<c;i++);
 if((*s)[i]!=c) return 0;
 while((*s)[i]=(*s)[i+1]) i++;
 if(!i) Kill(s);
 return 1;
}

void Move(char c, tSet *to, tSet *from)
{ if(!Emit(c,from)) Error(100); Insert(c,to); }

char EmitRandomly(tSet *set)
{
 tSet s=*set;			if(!s) return 0;
 int i,c,idx=Random(Size(s)); 
 for(i=0;i<idx;i++);		if(!s[i]) Error(101);
 c=s[i];
 while(s[i]=s[i+1]) i++;	if(!i) Kill(set);
 return c;
}

void Show(tSet s)
{
 if(!s) printf("<<empty>>"); else {
  printf("%s",c2r(s[0]));
  for(int i=1;s[i];i++) printf(", %s",c2r(s[i]));
 }
 printf("\n");
}

int ShowSets(tSets s)
{
 int n;
 printf("{ ");
 for(n=0;s[n];n++) {
  printf("%s",c2r(s[n][0]));
  for(int i=1;s[n][i];i++) printf(", %s",c2r(s[n][i]));
  if(s[n+1]) printf(" ; ");
 }
 printf(" }\n");
 return n;
}

void AddSet(tSets sets, tSet set)
{
 int n,i;
 for(i=0;sets[i];i++);
 sets[i]=(tSet)malloc((Size(set)+1)*sizeof(tSet));
 if(!sets[i]) Error(1);
 for(n=0;set[n];n++) sets[i][n]=set[n];
 sets[i][n]=0;
 sets[i+1]=NULL;
}

tSet RemoveLastSet(tSets sets)
{
 int i; tSet res;
 for(i=0;sets[i];i++);
 if(!i) Error(102);
 res=sets[--i]; sets[i]=NULL;
 return res;
}

tSet RemoveSet(tSets sets, int idx)
{
 int i; tSet res;
 for(i=0;sets[i] && i<idx;i++);
 if(!sets[i]) return NULL;
 res=sets[i];
 while(sets[i]=sets[i+1]) i++;
 return res;
}

tSets ConstructAllValidSubsets(tSet s)
{
 tSet h=NULL;
 int j,LastCard;
 tSets Collection=(tSets)malloc(100*sizeof(tSet));
 if(!Collection) Error(1); Collection[0]=NULL;

 for(int i=0;s[i];i++) {
  if(s[i]==s[i+1]) i++;
  j=i;		// rows
  do {
   LastCard=s[j]; Insert(LastCard,&h);
   if(Size(h)>=3) AddSet(Collection,h);
   j++; if(s[j]==LastCard) j++;
  } while(s[j]==LastCard+1);
  Kill(&h);
  j=i;		// sets
  do {
   LastCard=s[j]; Insert(LastCard,&h);
   if(Size(h)>=3) AddSet(Collection,h);
   if(Size(h)==4) { //special cases: DHC and DSC
    int lc=LastCard&0x0F;
    Emit(lc|SPADE,&h); AddSet(Collection,h); Insert(lc|SPADE,&h);
    Emit(lc|HEART,&h); AddSet(Collection,h); Insert(lc|HEART,&h);
   }
   j++; if(s[j]==LastCard) j++;
   LastCard&=0x0F;
   while( s[j] && ((s[j]&0x0F)!=LastCard) ) j++;
  } while((s[j]&0x0F)==LastCard);
  Kill(&h);
 }
 return Collection;
}


int Substract(tSet *s1, tSet s2)
{
 int ok=1;
 for(int i=0;s2[i];i++) if(!Emit(s2[i],s1)) ok=0;
 return ok;
}

void Add(tSet *s1, tSet s2)
{ if(s2) for(int i=0;s2[i];i++) Insert(s2[i],s1); }

int IsEqual(tSet s1, tSet s2)
{
 int i;
 if(!s1 || !s2) return (s1==s2);
 for(i=0;s1[i] && s2[i];i++) if(s1[i]!=s2[i]) return 0;
 return (s1[i]==s2[i]);
}

int IsIn(tSet s, char c)
{
 if(!s) return 0;
 for(int i=0;s[i];i++) if(s[i]==c) return 1;
 return 0;
}

int IsInSets(tSets sets, tSet set)
{ for(int i=0;sets[i];i++) if(IsEqual(sets[i],set)) return 1; return 0; }

int pow2(int n)
{ return (1<<n); }


double Coherence(tSet s)
{	// works perfectly well for double cards, too !!
 double value=0.0;
 int i;
 if(!s) return 0;
 for(i=0;s[i];i++) {
  double val=0.0;
  if(i) {
   if(s[i-1]==s[i]-1) val+=(1.0/2.0);
   else if(s[i-1]==s[i]-2) val+=(1.0/3.0);
   else if(s[i-1]==s[i]-3) val+=(1.0/6.0);
  }
  if(s[i+1]) {
   if(s[i+1]==s[i]+1) val+=(1.0/2.0);
   else if(s[i+1]==s[i]+2) val+=(1.0/3.0);
   else if(s[i+1]==s[i]+3) val+=(1.0/6.0);
  }
  for(int c=DIAMOND;c<=CLUB;c+=0x10)
   if(c!=(s[i]&0xF0) && IsIn(s, c|(s[i]&0x0F) )) val+=(1.0/2.0);
  if(val>1.0) val=1.0;
  value+=val;
 }
 return value/i;
}


int PickOne(tSet *to, tSet from)
{
 int Card=EmitRandomly(&from);
 if(!Card) Error(103);
 Insert(Card,to);
 return Card;
}

void EmitSets(tSets what, tSet *from)
{
 for(int s=0;what[s];s++) for(int c=0;what[s][c];c++)
  if(!Emit(what[s][c],from)) Error(104);
}
void InsertSets(tSets what, tSets to)
{
 int toIdx;
 for(toIdx=0;to[toIdx];toIdx++);
 for(int s=0;what[s];s++,toIdx++)
  for(int c=0;what[s][c];c++) Insert(what[s][c],&(to[toIdx]));
}

void TakeUp(tSets what, tSet *to, tSets from)
{
 int cmp;
 for(int s=0;what[s];s++) {
  for(cmp=0;from[cmp] && !IsEqual(from[cmp],what[s]);cmp++);
  if(!from[cmp]) Error(105);
  for(int c=0;what[s][c];c++) Move(what[s][c],to,&(from[cmp]));
  while(from[cmp]=from[cmp+1]) cmp++; //remove one set from a tSets
 }
}
void TakeUpAll(tSet *to, tSets from)
{
 for(int i=0;from[i];i++)
  while(from[i]) { int c=from[i][0]; Move(c,to,&(from[i])); }
}


void GetBestCombination(int level, tSet Set, tSets AllSubSets, tSets *Current,
			tSets *BestSolution, double *BestEval)
{
 tSet curr;
 tSets StoredSubSets=(tSets)malloc(100*sizeof(tSet));
 if(!StoredSubSets) Error(1); StoredSubSets[0]=NULL;

 //move all now blocked ones from AllSubSets to StoredSubSets
 if(level) {
  for(int j=0;AllSubSets[j];) {
   int ok=1;
   for(int i=0;AllSubSets[j][i];i++) if(!IsIn(Set,AllSubSets[j][i])) ok=0;
   if(ok) j++;
   else {
    curr=RemoveSet(AllSubSets,j);
    AddSet(StoredSubSets,curr);
    Kill(&curr);
   }
  }
 }

 if(AllSubSets[0]) {
  curr=RemoveLastSet(AllSubSets);

  // AddSet curr to Current and remove the cards from Set
  AddSet(*Current,curr);
  if(!Substract(&Set,curr)) Error(106);
  // Recurse for reduced AllSubSets
  GetBestCombination(level+100,Set,AllSubSets,Current,BestSolution,BestEval);
  // Re-add curr to Set and remove from Current
  Add(&Set,curr);
  Kill(&curr);
  curr=RemoveLastSet(*Current);

  //Recurse for reduced AllSubSets
  GetBestCombination(level+1,Set,AllSubSets,Current,BestSolution,BestEval);
  AddSet(AllSubSets,curr);
  Kill(&curr);

 } else {
  //compare Current to BestSolution,
  if(Value(Set)+Coherence(Set) > *BestEval) {
   //replace if better
   *BestEval=Value(Set)+Coherence(Set);
   KillSets(BestSolution);
   for(int k=0;(*Current)[k];k++) AddSet(*BestSolution,(*Current)[k]);   
  }
 }

 //move all of StoredSubSets back to AllSubSets
 while(StoredSubSets[0]) {
  curr=RemoveLastSet(StoredSubSets);
  AddSet(AllSubSets,curr);
  Kill(&curr);
 }

 free(StoredSubSets);
}


int IsRow(tSet meld)
{ return (meld[1]-meld[0]==1); }

void CutRowIn(tSets s, int n, char c)
{
 int i;
 tSet EndRow=NULL;
 for(i=0;s[n][i]<=c;i++);
 Insert(c,&EndRow);
 while(c=s[n][i]) Move(c,&EndRow,&(s[n]));
 AddSet(s,EndRow);
 Kill(&EndRow);
}

void CutRowOut(tSets s, int n, char c, tSet *to)
{
 int i;
 tSet EndRow=NULL;
 for(i=0;s[n][i]<c;i++);
 Move(s[n][i],to,&(s[n]));
 while(c=s[n][i]) Move(c,&EndRow,&(s[n]));
 AddSet(s,EndRow);
 Kill(&EndRow);
}


int LookFor(int level, char c, tSet *constr, tSets tbl, tSet *hand,
	    unsigned short *r, int *rIdx)
{
 tSet ToGetRidOff=NULL;
 // try melds with 3 cards only, if none of longer ones worked out
 for(int m=0;tbl[m];m++) if(tbl[m]!=(char *)-1 && tbl[m][3]) {
  if(IsRow(tbl[m])) {
   if((tbl[m][0]&0xF0)==(c&0xF0)) {
    if(tbl[m][0]<=c) {
     int l=Size(tbl[m])-1;
     if(tbl[m][0]==c) {
      Move(c,constr,&(tbl[m])); r[(*rIdx)++]=(m<<8)|c; return 1;
     } else if(tbl[m][l]>=c) {
      if(tbl[m][l]==c) {
       Move(c,constr,&(tbl[m])); r[(*rIdx)++]=(m<<8)|c; return 1;
      } else {
       if(tbl[m][l]-c>=3 && c-tbl[m][0]>=3) {
        CutRowOut(tbl,m,c,constr);
        for(int rr=0;rr<*rIdx;rr++) {
         if((r[rr]>>8)==m) {
          int card=r[rr]&0xFF;
          if(card>c) r[rr]=((NumSets(tbl)-1)<<8)|card;
         }
        }
        r[(*rIdx)++]=(m<<8)|c;
       }
      }
     }
    }
   }
  } else if((tbl[m][0]&0x0F)==(c&0x0F)) {
   Move(c,constr,&(tbl[m])); r[(*rIdx)++]=(m<<8)|c; return 1;
  }
 }

 // the rows with more than 3 cards could not provide c,
 // so now try those with only 3
 //
 // ...

 // c can not be provided
 return 0;
}


int GetRid(int level, char card, tSet *hand, tSets table)
{
 unsigned short reminder[100]; int remidx=0;
 char color=card&0xF0,value=card&0x0F;
 int last;
 tSet build=NULL;

 //printf("trying to get rid of %s.\n",c2r(card));
 Move(card,&build,hand);
 // possibility 1: make it a row
 // look on hand first (there cannot be more than one that matches !):
 if(IsIn(*hand,card+1)) Move(card+1,&build,hand);
 if(IsIn(*hand,card-1)) Move(card-1,&build,hand);

 // then on the table:
 // try to get next-higher card
 last=build[1]?1:0;
 int ret=1;
 while( ret && Size(build)<3 && (build[last]&0x0F)<KING ) {
  ret=LookFor(level,build[last]+1,&build,table,hand,reminder,&remidx);
  if(ret) {
   last++; // try if it can be added to a row on the table now
   for(int t=0;table[t];t++) if(IsRow(table[t]))
   if(table[t][0]==build[last]+1) {
    Add(&(table[t]),build); Kill(&build); return 1;
   }
  }
 }
 while(IsIn(*hand,build[last]+1)) { Move(build[last]+1,&build,hand); last++; }
 // try to get next-lower card
 ret=1;
 while( ret && Size(build)<3 && (build[0]&0x0F)>ACE ) {
  ret=LookFor(level,build[0]-1,&build,table,hand,reminder,&remidx);
  if(ret) {
   last++; // try if it can be added to a row on the table now
   for(int t=0;table[t];t++) if(IsRow(table[t]))
   if(table[t][Size(table[t])-1]==build[0]-1) {
    Add(&(table[t]),build); Kill(&build); return 1;
   }
  }
 }
 while(IsIn(*hand,build[0]-1)) { Move(build[0]-1,&build,hand); last++; }

 unsigned short v;
 if(Size(build)<3) {
  // making it a row did not work, i.e.:
  // put back the cards you took from hand or table
  while(remidx) { v=reminder[--remidx]; Move(v&0xFF,&(table[v>>8]),&build); }
  Add(hand,build);
  Kill(&build);
  Move(card,&build,hand);

  // possibility 2: make it a set
  // look on hand first:
  for(int c=DIAMOND;c<=CLUB;c+=0x10) if(c!=color)
   if(IsIn(*hand,c|value)) Move(c|value,&build,hand);
  // then on table (see above)
  for(int c=DIAMOND;c<=CLUB && Size(build)<3;c+=0x10) if(!IsIn(build,c|value))
   /*ret=*/LookFor(level,c|value,&build,table,hand,reminder,&remidx);
 }

 if(Size(build)<3) {	// it did not work, take back this card, try next
  while(remidx) { v=reminder[--remidx]; Move(v&0xFF,&(table[v>>8]),&build); }
  Add(hand,build); ret=0;
 } else {		// great, got rid of it !
  AddSet(table,build); ret=1;
 }
 Kill(&build);
 return ret;
}



void main(int argc, char *argv[])
{
 tSet stack=NULL;
 tSet (player[cPlayers]);
 char OnTable[cPlayers];
 for(int p=0;p<cPlayers;p++) player[p]=NULL,OnTable[p]=0;
 tSets table=(tSets)malloc(100*sizeof(tSet)); if(!table) Error(1);
 table[0]=NULL;


 int pid=getpid(); printf("%d\n",pid);
 //int pid=28669;
 srand(pid);


 // creating the stack
 for(int c=DIAMOND;c<=CLUB;c+=0x10) for(int f=ACE;f<=KING;f++)
  Insert(c|f,&stack),Insert(c|f,&stack);

 // giving out the cards
 for(int p=0;p<cPlayers;p++) for(int i=0;i<cHandSize;i++)
  PickOne(&(player[p]),stack);
 for(int p=0;p<cPlayers;p++)
 { printf("hand of player %d:\n",p); Show(player[p]); printf("\n"); }
 printf("\nrest stack:\n"); Show(stack); printf("\n\n\n");


 printf("Start of Game !\n\n\n");

 tSets buf= (tSets)malloc(100*sizeof(tSet)); if(!buf)  Error(1); buf[0]= NULL;
 tSets Tbuf=(tSets)malloc(100*sizeof(tSet)); if(!Tbuf) Error(1); Tbuf[0]=NULL;
 tSets best=(tSets)malloc(100*sizeof(tSet)); if(!best) Error(1); best[0]=NULL;

 int LastMove=-2*cPlayers;
 for(int ply=0; ply<100 ;ply++) {
//  getchar();
  printf("ply %d.\n",ply);
  for(int plIdx=0;plIdx<cPlayers;plIdx++) {
   printf("Table: "); ShowSets(table);
   printf("It is player %d's turn%s:\n",plIdx,OnTable[plIdx]?" (on table)":"");
   printf(" hand: "); Show(player[plIdx]);
   int OldHandValue=Value(player[plIdx]);

   double val=-1000000.0;
   if(ply*cPlayers+plIdx-LastMove==cPlayers) {
    val=OldHandValue;	// nothing changed since last move of this player
   } else {

    // first see, if hand contains melds
    tSets AllSubSets=ConstructAllValidSubsets(player[plIdx]);
    GetBestCombination(0, player[plIdx], AllSubSets, &buf, &best, &val);
    printf("Best melds from hand (hand-value=%0.2f): ",val); ShowSets(best);

    if(ValueSets(best)>=cFirstMeld) OnTable[plIdx]=1;

    if(OnTable[plIdx]) {

     if(best[0]) {
      // Get these melds of the hand, but to not yet put them on the table
      EmitSets(best,&(player[plIdx]));
      printf(" hand: "); Show(player[plIdx]);
     }

     // try other modifications now
     // 1. adding cards to ends of melds & cutting rows
     // 9,10,j,q + 10,j  -->  9,10,j + 10,j,q  handled below !
					// handle 5,6,7 + 3,4 's first !!!
     for(int p=0;player[plIdx] && player[plIdx][p];p++)
     if(player[plIdx][p+1]==player[plIdx][p]+1) {
      int done=0;
      for(int j=0;table[j] && !done;j++) if(IsRow(table[j])) {
       if(table[j][0]==player[plIdx][p]+2) {
        int _move=player[plIdx][p];
        Move(_move,&(table[j]),&(player[plIdx]));
        Move(_move+1,&(table[j]),&(player[plIdx]));
        done=1;
       }
       else if(table[j][Size(table[j])-1]==player[plIdx][p]-1) {
        int _move=player[plIdx][p];
        Move(_move,&(table[j]),&(player[plIdx]));
        Move(_move+1,&(table[j]),&(player[plIdx]));
        done=1;
       }
      }
     }
     for(int j=0;table[j];j++) if(IsRow(table[j])) {
      while(IsIn(player[plIdx],table[j][0]-1)) {
       Move(table[j][0]-1,&(table[j]),&(player[plIdx]));
      }
      int last=Size(table[j])-1; //printf("%s\n",c2r(table[j][last]));
      while(IsIn(player[plIdx],table[j][last]+1)) {
       Move(table[j][last]+1,&(table[j]),&(player[plIdx]));
       last++;
      }
      if(table[j][last]-table[j][0]>=4) {
       char help=table[j][0]+2; last-=2;
       while(help<=table[j][last]) {
        if(IsIn(player[plIdx],help))
        { CutRowIn(table,j,help); Emit(help,&(player[plIdx])); }
        help++;
       }
      }
     }
     for(int j=0;table[j];j++) if(!IsRow(table[j]) && Size(table[j])==3) {
      //printf("Trying meld "); Show(table[j]);
      char v=table[j][0]&0x0F;
      if((table[j][0]&0xF0)==DIAMOND) {
       if((table[j][1]&0xF0)==HEART) {
        if((table[j][2]&0xF0)==SPADE) v|=CLUB; else v|=SPADE;
       } else v|=HEART;
      } else v|=DIAMOND;
      if(IsIn(player[plIdx],v)) Move(v,&(table[j]),&(player[plIdx]));
     }

     if(best[0]) {
      // now put down the melds put aside first
      // (because now they have to be searchable)
      InsertSets(best,table);
      KillSets(&best);
     }

     // handling "get rid of jS,qS" as
     // "get rid of jS" -> look at hand for matches first -> "qS"
     if(player[plIdx]) {
      int i=0;
      do {
       char card=player[plIdx][i];
       GetRid(0,card,&(player[plIdx]),table);
       for(i=0;player[plIdx]&& player[plIdx][i] && player[plIdx][i]<=card;i++);
      } while(player[plIdx] && player[plIdx][i]);
     }

    }
   }

   if(OldHandValue==Value(player[plIdx])) {
    int c=PickOne(&(player[plIdx]),stack);
    printf("Pick one: %s\n",c2r(c));
   } else LastMove=ply*cPlayers+plIdx;

   printf(" hand: "); Show(player[plIdx]);
   printf("       (coherence=%6.4f)\n",Coherence(player[plIdx]));
   printf("\n");

   if(!player[plIdx]) {
    printf("\n\nFinal table: "); ShowSets(table);
    printf("\n\nG A M E   O V E R   !\n\n");
    printf("Winner: Player %d.\n",plIdx);
    for(int p=0;p<cPlayers;p++) if(p!=plIdx)
     printf("Loss of Player %d: %d\n",p,Value(player[p]));
    exit(0);
   }
  }
 }
 printf("\n\nFinal table: "); ShowSets(table);
}
