/* Outputs the equity of all unsuited triples, disregarding flushes */
/* A.P.Selby Oct 1999 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define CUTOFF 0.1
#define NT 129766
/* NT=(91+2 choose 3)=number of unsuited triples, 91=(13+1 choose 2) */
static int sc[91],h0[91],h1[91],sp[NT];
static char *cc="23456789TJQKA",*(td[9])={"High card ","Pair      ","Two pair  ","Trips     ","Straight  ","Flush     ","Full House","Quadzilla ","Str8 Flush"};
static int cmp(const void*,const void*),cmp1(const void*,const void*);
static void desc(int),desh(int);
main(){
 int str[1<<13],h,i,j,k,n,t,i0,i1,i2,b[5],
   id,bm,bm0,v,ml0[13],ml[13],nl[13],mf,ms,hf,hs,lx,ty,p0,p1,pp[91],bs,px,tm,tm0,tm1,tm2,
   h00,h01,h10,h11,h20,h21,nw,in,t0,t1,t2,t3,t4,tp[NT],s0,s1,s2,cn[NT][3],u0,u1;
 clock_t ti0;

 for(i=0;i<(1<<13);i++){
  bm=(i<<1)|(i>>12);
  for(v=9;v>=0 && (bm&(31<<v))!=(31<<v);v--);
  if(v==0)v=0x3210c; else if(v>0)v=(v-1)|v<<4|(v+1)<<8|(v+2)<<12|(v+3)<<16;
  str[i]=v;
 }
 for(i=0;i<13;i++)for(j=i;j<13;j++){id=i+(j*(j+1))/2;h0[id]=i;h1[id]=j;}
 for(i=0;i<NT;i++)for(j=0;j<3;j++)cn[i][j]=0;

 ti0=clock();
 px=0;
 /* Loop over unsuited boards */
 for(b[0]=0;b[0]<13;b[0]++)
 for(b[1]=b[0];b[1]<13;b[1]++)
 for(b[2]=b[1];b[2]<13;b[2]++)
 for(b[3]=b[2];b[3]<13;b[3]++)
 for(b[4]=b[3];b[4]<13;b[4]++){
  t0=12-b[4];t1=12-b[3];t2=12-b[2];t3=12-b[1];t4=12-b[0];
  in=t0+(t1*(t1+1))/2+(t2*(t2+1)*(t2+2))/6+(t3*(t3+1)*(t3+2)*(t3+3))/24+(t4*(t4+1)*(t4+2)*(t4+3)*(t4+4))/120;
  n=(13*14*15*16*17)/120;
  i=((n-in)*100)/n;
  if(i>=px){fprintf(stderr,"%c%c%c%c%c %3d%% %7.2fs\n",
		    cc[b[0]],cc[b[1]],cc[b[2]],cc[b[3]],cc[b[4]],
		    px++,(clock()-ti0)/(double)CLOCKS_PER_SEC);}
  bm=1<<b[0]|1<<b[1]|1<<b[2]|1<<b[3]|1<<b[4];
  for(i=0;i<13;i++)ml0[i]=0;bm0=0;
  for(i=0;i<5;i++){ml0[b[i]]++;bm0|=1<<b[i];}
  for(i=0;i<91;i++)sc[i]=-1;
  /* Work out the value of each unsuited hand */
  for(i0=0;i0<91;i0++){
   p0=h0[i0];p1=h1[i0];
   memcpy(ml,ml0,13*sizeof(int));
   ml[p0]++;ml[p1]++;bm=bm0|1<<p0|1<<p1;
   mf=0;ms=0;
   for(h=12;h>=0;h--){
    if(ml[h]>mf){hs=hf;ms=mf; hf=h;mf=ml[h]; continue;}
    if(ml[h]>ms){hs=h;ms=ml[h];}
   }
   if(mf>4)continue;
   lx=0;
   for(i=0;i<mf;i++)lx+=hf<<4*(4-i);
   if(mf<4)for(;i<mf+ms&&i<5;i++)lx+=hs<<4*(4-i); else hs=-1;
   for(j=12;i<5;j--)if(j!=hf&&j!=hs&&ml[j]>0)lx+=j<<4*(4-(i++));
   if(mf==4)ty=7;
   if(mf==3&&ms>=2)ty=6;
   if(mf==3&&ms==1)ty=3;
   if(mf==2&&ms==2)ty=2;
   if(mf==2&&ms==1)ty=1;
   if(mf==1)ty=0;
   if(ty<4&&str[bm]>=0){lx=str[bm];ty=4;}
   lx+=ty<<20;
   sc[i0]=lx;
  }
  /*
  for(i=0;i<91;i++)pp[i]=i;
  qsort(pp,91,sizeof(int),cmp);
  for(i=0;i<91;i++){k=pp[i];if(sc[k]<0)continue;
   for(j=0;j<5;j++)printf("%c",cc[b[j]]);printf(" %c%c",cc[h0[k]],cc[h1[k]]);
   lx=sc[k];printf("  %06x  ",lx);desc(lx);
  }
  */
#define PC(x) {int yy=nl[(x)];tm*=(yy-ml[(x)]);if(yy)tm/=yy;nl[(x)]=yy-1;}
  for(i=0;i<13;i++)ml[i]=0;for(i=0;i<5;i++)ml[b[i]]++;
  for(i=0;i<13;i++)nl[i]=4;
  for(i=0,tm=1;i<13;i++){
   j=ml[i];
   if(j==1||j==3)tm*=4;
   if(j==2)tm*=6;
  }
  /* Add in the equity of each triple, disregarding flushes, but counting suits */
  for(i0=0;i0<91;i0++){if((s0=sc[i0])==-1)continue; h00=h0[i0];h01=h1[i0];
   tm0=tm;PC(h00);PC(h01);
  for(i1=i0;i1<91;i1++){if((s1=sc[i1])==-1)continue; h10=h0[i1];h11=h1[i1];
   tm1=tm;PC(h10);PC(h11);
  for(i2=i1;i2<91;i2++){if((s2=sc[i2])==-1)continue; h20=h0[i2];h21=h1[i2];
   tm2=tm;PC(h20);PC(h21);
   in=i0+(i1*(i1+1))/2+(i2*(i2+1)*(i2+2))/6;
   bs=s0;if(s1>bs)bs=s1;if(s2>bs)bs=s2;
   nw=(s0==bs)+(s1==bs)+(s2==bs);j=(tm*6)/nw;
   if(s0==bs)cn[in][0]+=j;
   if(s1==bs)cn[in][1]+=j;
   if(s2==bs)cn[in][2]+=j;
  tm=tm2;nl[h20]++;nl[h21]++;}
  tm=tm1;nl[h10]++;nl[h11]++;}
  tm=tm0;nl[h00]++;nl[h01]++;}
 }
 for(i=0,j=0;i<NT;i++){
  u0=cn[i][0];u1=cn[i][0];
  if(cn[i][1]>u0)u0=cn[i][1];
  if(cn[i][1]<u1)u1=cn[i][1];
  if(cn[i][2]>u0)u0=cn[i][2];
  if(cn[i][2]<u1)u1=cn[i][2];
  t=cn[i][0]+cn[i][1]+cn[i][2];
  if(t!=0&&t!=6*1370754)exit(fprintf(stderr,"t=%d\n",t));
  if(t)sp[i]=u0-u1; else sp[i]=6*1370754+1;
 }
 for(i=0;i<NT;i++)tp[i]=i;
 qsort(tp,NT,sizeof(int),cmp1);
 for(i=0;i<NT;i++){
  j=tp[i];
  for(i2=90;i2>=0;i2--){k=(i2*(i2+1)*(i2+2))/6;if(k<=j)break;}j-=k;
  for(i1=i2;i1>=0;i1--){k=(i1*(i1+1))/2;if(k<=j)break;}j-=k;
  i0=j;
  j=tp[i];
  if(sp[j]>6*1370754)goto nl0;
  for(k=0;k<3;k++)if(cn[j][k]/(6*1370754.)<1/3.-CUTOFF)goto nl0;
  desh(i0);printf(" ");desh(i1);printf(" ");desh(i2);printf(" ");
  printf("%7d     %7d %7d %7d\n",sp[j],cn[j][0],cn[j][1],cn[j][2]);
 nl0:
 }
}
static int cmp(const void*x,const void*y){return sc[*(int*)x]-sc[*(int*)y];}
static int cmp1(const void*x,const void*y){return sp[*(int*)x]-sp[*(int*)y];}
static void desc(int lx){int i;
printf("%s ",td[lx>>20]);for(i=4;i>=0;i--)printf("%c",cc[(lx>>4*i)&15]);printf("\n");}
static void desh(int i){printf("%c%c",cc[h0[i]],cc[h1[i]]);}
