/**********************************************************/
/*                                                        */
/*   Kniffel Version 1.1                                  */
/*   Autor: Felix Holderied                               */
/*                                                        */
/*   Die Weiterverwendung des Codes unter Angabe der      */
/*   Quelle http://www.holderied.de/kniffel/ und          */
/*   Benachrichtigung des Autors ist zulaessig.           */
/*                                                        */
/*   Datum:           29. Juli   1999                     */
/*   Letzte Aenderung 17. Januar 2002                     */
/*                                                        */
/*   Informationen: http://www.holderied.de/kniffel/      */
/*                                                        */
/**********************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "kniffel.h"

/**********************************************************/

int  Sort(int ziffern);              /* Ziffern sortieren */
int  Index(int auswahl);     /* Index einer Auswahl von 5 */
int  Index5(int wurf);           /* Index eines 5er-Wurfs */
int  IndexSpielstand(int ss[13]);     /* Index des Spiel- */
                               /* zustandes in restgewinn */

int  Wuerfle(int auswahl);   /* Ergaenze fehlende Wuerfel */
                             /*                zu Auswahl */
void AusgabeSpielstand(int ss[13]);        /* Ausgabe des */
            /* aktuellen Spielstandes, also des "Zettels" */
int  Summe(int ss[13], int von, int bis);      /* Bereits */
                          /* erzielte Punkte (ohne Bonus) */
int  LesePositivenInteger();      /* Eingabe des Spielers */
int  eingabe;

int  ReadRestgewinn();           /* Lese Datei restgewinn */
int  WriteRestgewinn();      /* Schreibe Datei restgewinn */

void BerechneEinenZustand(int index);      /* siehe unten */
void BerechneRestgewinn();                 /* siehe unten */
void Berechne_w3(int index);               /* siehe unten */
void Berechne_a2();                        /* siehe unten */
void Berechne_w2();                        /* siehe unten */
void Berechne_a1();                        /* siehe unten */
void Berechne_w1();                        /* siehe unten */

/**********************************************************/
/* Es gibt zwei Spielmodi                                 */
/**********************************************************/
void GanzesSpiel();
void EinzelAbfrage(int argc, char *argv[]);

/**********************************************************/
/* Globale Variablen                                      */
/**********************************************************/

double
  restgewinn[524288],     /* Einzulesende Erwartungswerte */
  w3[252],  /* Erwartungswerte nach drittem, letztem Wurf */
  a2[462],        /* Erwartungswerte nach zweiter Auswahl */
  w2[252],           /* Erwartungswerte nach zweitem Wurf */
  a1[462],         /* Erwartungswerte nach erster Auswahl */
  w1[252];            /* Erwartungswerte nach erstem Wurf */

int
  e3[252],          /* Beste Eintragung nach letztem Wurf */
  e2[252],             /* Beste Auswahl nach zweitem Wurf */
  e1[252];              /* Beste Auswahl nach erstem Wurf */

/**********************************************************/
/* Einlesen der Erwartungswerte                           */
/**********************************************************/

int ReadRestgewinn()
  {
  FILE *datei = NULL;
  if((datei = fopen("restgewinn", "r")) == NULL)
    return(0);
  if(fread(restgewinn,sizeof(double),524288,datei)!=524288)
    {
    fprintf(stderr,
      "Fehler in Datei restgewinn! Datei loeschen\n");
    exit(1);
    }
  fclose(datei);
  return(1);
  }

/**********************************************************/
/* Berechne Erwartungswerte fuer einen Zustand            */
/**********************************************************/

void BerechneEinenZustand(index)
  {
  Berechne_w3(index);
  Berechne_a2();
  Berechne_w2();
  Berechne_a1();
  Berechne_w1();
  }

/**********************************************************/
/* Berechnen der Erwartungswerte fuer alle Zustaende      */
/**********************************************************/

void BerechneRestgewinn()
  {
  double erwindex;
  int wurf;
  int zaehler;

  printf("Berechne Erwartungswerte, bitte warten\n");
  restgewinn[524287]=35;
  for(zaehler=524286;zaehler>524223;zaehler--)
    {
    restgewinn[zaehler]=0;
    }

  for(zaehler=524223;zaehler>=0;zaehler--)
    {
    BerechneEinenZustand(zaehler);
    erwindex=0;
    for(wurf=0;wurf<252;wurf++)
      {
      erwindex+=wk0[wurf]*w1[wurf];
      };
    restgewinn[zaehler]=erwindex;
    if(zaehler%1000==0)
      {
      printf("%d %f\n",zaehler,restgewinn[zaehler]);
      };
    };
  }

/**********************************************************/
/* Erwartungswerte in Datei schreiben                     */
/**********************************************************/

int WriteRestgewinn()
{
FILE *datei = NULL;
if ((datei = fopen("restgewinn", "w")) == NULL)
  {
  fprintf(stderr, "Fehler in WriteRestgewinn!\n");
  exit(1);
  }
if (fwrite(restgewinn, sizeof(double),524288,datei)!=524288)
  {
  fprintf(stderr,
    "Fehler in WriteRestgewinn: Falsche Datenanzahl!\n");
  exit(1);
  }
fclose(datei);
}

/**********************************************************/
/* Berechne Erwartungswerte nach letztem Wurf w3          */
/**********************************************************/

int IndexSpielstand(int ss[13])
  {
  int i;
  int tempindex=0;

  for(i=0; i<13; i++){
    if(ss[i]>=0) tempindex += zweihoch[i];}
  tempindex*=64;
  if(Summe(ss,0,5)>=63) tempindex+=63;
  else                  tempindex+=Summe(ss,0,5);
  return(tempindex);
  }

/**********************************************************/
/* Summenbildung (von, bis sind einschliessliche Grenzen) */
/**********************************************************/

int  Summe(int ss[13], int von, int bis)
  {
  int i;
  int s=0;
  for(i=von; i<=bis; i++) if(ss[i]>=0) s+=ss[i];
  return(s);
  }

/**********************************************************/
/* Berechne Erwartungswerte nach letztem Wurf w3          */
/**********************************************************/

void Berechne_w3(int index)
  {
  int wurfindex, platz;                        /* Zaehler */
  double erwartung, maxerwartung;    /* fuer Maximumsuche */
  int tempindex; /* Hilfsvariable zur Zustandsdekodierung */
  int summeoben, neuesummeoben, neuerzustand, zugewinn;
  int frei[13];
  int besterplatz=14;

  /* Dekodiere Zustand                                    */
  tempindex = index;
  summeoben = tempindex%64; tempindex/=64;
  for(platz=0;platz<13;platz++)
    {
    frei[platz]=(tempindex%2==0);
    tempindex/=2;
    }

  /* Berechne Erwartungswerte fuer alle 252 Wuerfe        */
  for(wurfindex=0; wurfindex<252; wurfindex++)
    {
    maxerwartung = 0;
    for(platz=0;platz<13;platz++)  /* Suche freie Plaetze */
      {
      if(frei[platz])
        {
        zugewinn     = bewertungen[wurfindex][platz];
        neuesummeoben = summeoben;
        if(platz<6)
          {
          neuesummeoben+=zugewinn;
          if(neuesummeoben>63){neuesummeoben=63;}
          };
        /* Kodiere Zustand                                */
        neuerzustand = ((index/64)+zweihoch[platz])*64+
                       neuesummeoben;

        erwartung = zugewinn+restgewinn[neuerzustand];

        if( erwartung >= maxerwartung)
          {
          maxerwartung = erwartung;
          besterplatz  = platz;
          }
        }
      }
      w3[wurfindex] = maxerwartung;
      e3[wurfindex] = besterplatz;
    }
  }

/**********************************************************/
/* Berechne Erwartungswerte nach zweiter Auswahl a2       */
/**********************************************************/
void Berechne_a2()
  {
  int z,i;                                     /* Zaehler */
  for(z=0; z<462; z++) a2[z]=0;
        for(i=0; i<252; i++) a2[0]+=wk0[i]*w3[i];
  for(z=  1; z<  7; z++)
        for(i=0; i<126; i++) a2[z]+=wk1[i]*w3[fz1[z- 1][i]];
  for(z=  7; z< 28; z++)
        for(i=0; i< 56; i++) a2[z]+=wk2[i]*w3[fz2[z- 7][i]];
  for(z= 28; z< 84; z++)
        for(i=0; i< 21; i++) a2[z]+=wk3[i]*w3[fz3[z-28][i]];
  for(z= 84; z<210; z++)
        for(i=0; i<  6; i++) a2[z]+=wk4[i]*w3[fz4[z-84][i]];
  for(z=210; z<462; z++)       a2[z] =       w3[z-210];
  }

/**********************************************************/
/* Berechne Erwartungswerte nach zweitem Wurf w2          */
/**********************************************************/
void Berechne_w2()
  {
  int z,i;                                     /* Zaehler */
  double maxerwartung;               /* fuer Maximumsuche */
  int besteauswahl = 14;

  for(z=0; z<252; z++)  /* Schleife ueber alle 252 Wuerfe */
    {
    maxerwartung = 0;
    for(i=maindex[z]; i<maindex[z+1]; i++)
      {
      if(a2[ma[i]]>=maxerwartung)
        {
        maxerwartung = a2[ma[i]];
        besteauswahl = ma[i];
        }
      }
      w2[z]=maxerwartung;
      e2[z]=besteauswahl;
    }
  }
/**********************************************************/
/* Berechne Erwartungswerte nach erster Auswahl a1        */
/**********************************************************/
void Berechne_a1()
  {
  int z,i;                                     /* Zaehler */
  for(z=0; z<462; z++) a1[z]=0;
        for(i=0; i<252; i++) a1[0]+=wk0[i]*w2[i];
  for(z=  1; z<  7; z++)
        for(i=0; i<126; i++) a1[z]+=wk1[i]*w2[fz1[z- 1][i]];
  for(z=  7; z< 28; z++)
        for(i=0; i< 56; i++) a1[z]+=wk2[i]*w2[fz2[z- 7][i]];
  for(z= 28; z< 84; z++)
        for(i=0; i< 21; i++) a1[z]+=wk3[i]*w2[fz3[z-28][i]];
  for(z= 84; z<210; z++)
        for(i=0; i<  6; i++) a1[z]+=wk4[i]*w2[fz4[z-84][i]];
  for(z=210; z<462; z++)       a1[z] =     w2[z-210];
  }

/**********************************************************/
/* Berechne Erwartungswerte nach erstem Wurf w1           */
/**********************************************************/
void Berechne_w1()
  {
  int z,i;                                     /* Zaehler */
  double maxerwartung;               /* fuer Maximumsuche */
  int besteauswahl = 14;

  for(z=0; z<252; z++)  /* Schleife ueber alle 252 Wuerfe */
    {
    maxerwartung = 0;
    for(i=maindex[z]; i<maindex[z+1]; i++)
      {
      if(a1[ma[i]]>=maxerwartung)
        {
        maxerwartung = a1[ma[i]];
        besteauswahl = ma[i];
        }
      }
      w1[z]=maxerwartung;
      e1[z]=besteauswahl;
    }
  }

/**********************************************************/
/* Sortiere die von Null verschiedenen Ziffern einer Zahl */
/**********************************************************/

int Sort(int ziffern)
  {
  int ziffer[10]={0,0,0,0,0,0,0,0,0,0};
  int temp=ziffern;
  int z;
  while(temp!=0){ziffer[temp%10]++;temp/=10;};
  for(z=1; z<10; z++)
    while(ziffer[z]>0){temp*=10;temp+=z;ziffer[z]--;};
  return(temp);
  }

/**********************************************************/
/* Index einer Auswahl von 5 Wuerfeln (unschoen)          */
/**********************************************************/

int Index(int auswahl)
  {
  int i, temp;
  temp = Sort(auswahl);
  for (i=0;i<462;i++) if(wuerfe[i]==temp) return(i);
  return(-1);
  }

/**********************************************************/
/* Einen positiven Integer von der Tastatur lesen,        */
/**********************************************************/

int LesePositivenInteger()
  {
  char tempzeile[100];
  int temp;
  temp = 0;
  gets(tempzeile);
  if(sscanf(tempzeile,"%d",&temp)) {
    if(temp==77) exit(0);
    return(temp);
    }
  else return(-1);
  }

/**********************************************************/
/* Index eines Wurfes mit 5 Wuerfeln (unschoen)           */
/**********************************************************/

int Index5(int wurf)
  {
  int i, temp;
  temp = Sort(wurf);
  for (i=0;i<252;i++) if(wuerfe[i+210]==temp) return(i);
  return(-1);
  }

/**********************************************************/
/* Wuerfle          */
/**********************************************************/

int  Wuerfle(int auswahl)
  {
  int i, temp;
  temp = auswahl;
  while(temp<=6666) temp=10*temp+(rand()%6+1);
  return(temp);
  }

/**********************************************************/
/* Ausgabe Spielstand  */
/**********************************************************/

void AusgabeSpielstand(int ss[13])
  {
  int feld;
  int bonus=0;

  printf(" ----------------------\n");
  for(feld=0; feld<6; feld++)
    {
    printf("|%2d %-14s ",feld+1,feldnamen[feld]);
    if(ss[feld]<0) printf("    |\n");
    else           printf("%3d |\n",ss[feld]);
    };

  printf("|----------------------|\n");
  if(Summe(ss,0,5)>=63) bonus=35;
  printf("|   Bonus          %3d |\n",bonus);
  printf("|----------------------|\n");
  for(feld=6; feld<13; feld++)
    {
    printf("|%2d %-14s ",feld+1,feldnamen[feld]);
    if(ss[feld]<0) printf("    |\n");
    else           printf("%3d |\n",ss[feld]);
    };
  printf("|----------------------|\n");
  printf("|   Summe        %3d   |\n", Summe(ss,0,12)+bonus);
  printf("|   Erwartung    %3.1f |\n",
    Summe(ss,0,12)+restgewinn[IndexSpielstand(ss)] );
  printf(" ----------------------\n");
  }

/**********************************************************/
/* Einzelabfrage                                          */
/**********************************************************/
void EinzelAbfrage(int argc, char *argv[])
  {
  int wurfnr;
  int i, summeoben, summeunten, aktuellerwurf;
  int temp, z, wurfindex, maxerwartung, erwartung;
  int spielstand[13]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

  if(argc<15) {printf("Falsche Eingaben \n");exit(1);}

  for(i=0; i<13; i++)
    if(*argv[i+1]!='-')
      spielstand[i] =  atoi(argv[i+1]);
    /******************************************************/
    /* Ausgabe Spielstand                                 */
    /******************************************************/
    AusgabeSpielstand(spielstand);

  wurfnr = atoi(argv[14]);

  summeoben=Summe(spielstand,0,5);
  summeunten=Summe(spielstand,6,12);

  /********************************************************/
  /* Berechne Erwartungswert falls wurfnr == 0    */
  /********************************************************/
  if (wurfnr==0)
    {
    printf("Punkterwartung: %f \n",
           summeoben+
           summeunten+
           restgewinn[IndexSpielstand(spielstand)]);
    exit(0);
    }

  /********************************************************/
  /* wurfnr>0: Wuerfel muessen uebergeben werden  */
  /********************************************************/
  if(argc<16) {printf("Falsche Eingaben \n");exit(0);}

  /********************************************************/
  /* Sortiere und Berechne Index des Wurfes               */
  /********************************************************/

  aktuellerwurf = atoi(argv[15]);
  wurfindex=Index5(Sort(aktuellerwurf));
  printf("%d. Wurf: %d: ",wurfnr,wuerfe[wurfindex+210]);

  /********************************************************/
  /* wurfnr == 3 Wo schreibt man's rein?                  */
  /********************************************************/

  Berechne_w3(IndexSpielstand(spielstand));
  if (wurfnr==3)
    {
    printf("Bester Eintrag: %s, Punkterwartung: %f \n",
            feldnamen[e3[wurfindex]],
            summeoben+summeunten+w3[wurfindex]
            );
    exit(0);
    };

  /********************************************************/
  /* wurfnr=2 Welche Auswahl?                             */
  /********************************************************/

  Berechne_a2();
  Berechne_w2();

  if (wurfnr==2)
    {
    printf("Beste Auswahl: %d, Punkterwartung: %f \n",
            wuerfe[e2[wurfindex]],
            summeoben+summeunten+w2[wurfindex]);
    exit(0);
  };

  /********************************************************/
  /* wurfnr == 1 Welche Auswahl?                  */
  /********************************************************/

  Berechne_a1();
  Berechne_w1();

  if (wurfnr==1)
    {
    printf("Beste Auswahl: %d, Punkterwartung: %f \n",
            wuerfe[e1[wurfindex]],
            summeoben+summeunten+w1[wurfindex]);
    exit(0);
    }
  }

/**********************************************************/
/* Ein ganzes Spiel spielen                               */
/**********************************************************/
void GanzesSpiel()
  {
  int
    runde, feld, wurfnr,
    aktuellerwurf, eingabe,
    i,ia,iaw, auswahlgueltig,
    spielstand[13]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
  double handicap=0;

  /* Init Zufallsgenerator */
  srand( (unsigned)time(NULL) );

  for(runde=0; runde<13; runde++)
    {
    BerechneEinenZustand(IndexSpielstand(spielstand));
    /******************************************************/
    /* Ausgabe Spielstand                                 */
    /******************************************************/
    AusgabeSpielstand(spielstand);
    eingabe = 0;

    for(wurfnr=1; wurfnr<=3; wurfnr++)
      {
      aktuellerwurf  = Wuerfle(eingabe);
      iaw=Index5(aktuellerwurf);
      auswahlgueltig = 0;
      while(auswahlgueltig==0)
        {
        if(wurfnr<3)
          {
          printf("%d. Wurf: %d Auswahl: ",wurfnr,Sort(aktuellerwurf));
          ia = -1;
          eingabe = LesePositivenInteger();
          if(eingabe>=0) ia=Index(eingabe);
          if(ia>=0)
            for(i=maindex[iaw]; i<maindex[iaw+1]; i++)
              if(ma[i]==ia) auswahlgueltig = 1;
          }
        if(wurfnr==3)
          {
          printf("3. Wurf: %d Wohin:   ",Sort(aktuellerwurf));
          eingabe = LesePositivenInteger();
          if(0<eingabe && eingabe<=13)
            if(spielstand[eingabe-1]==-1)
              {
              spielstand[eingabe-1]=bewertungen[iaw][eingabe-1];
              auswahlgueltig = 1;
              }
          }
        }
      /* Pruefe Entscheidung */
      if(wurfnr==1)
        {
        handicap+=a1[e1[iaw]]-a1[ia];
        printf("Beste Auswahl:    %-14d ",wuerfe[e1[iaw]]);
        printf("Handicap: %3.3f\n",handicap);
        }
      if(wurfnr==2)
        {
        handicap+=a2[e2[iaw]]-a2[ia];
        printf("Beste Auswahl:    %-14d ",wuerfe[e2[iaw]]);
        printf("Handicap: %3.3f\n",handicap);
        }
      if(wurfnr==3)
        {
        handicap+=w3[iaw]-
                  restgewinn[IndexSpielstand(spielstand)]-
                  bewertungen[iaw][eingabe-1];
        printf("Beste Eintragung: %-14s ",feldnamen[e3[iaw]]);
        printf("Handicap: %3.3f\n",handicap);
        }
      }
    }
  AusgabeSpielstand(spielstand);
  }

/**********************************************************/
/* Hier beginnt das Hauptprogramm                         */
/**********************************************************/

main(int argc, char *argv[])
  {
  /* Init Zufallsgenerator */
   srand( (unsigned)time(NULL) );
   printf("\n  Kniffel 1.1\n\n");
   printf("  Autor: Felix Holderied\n");
   printf("  http://www.holderied.de/kniffel/\n\n");
   sleep(2);
  /* Initialisierung */
  if(!ReadRestgewinn())   /* Lese restgewinn ein         */
    {                     /* Falls Datei nicht vorhanden */
    BerechneRestgewinn(); /* Berechne restgewinn         */
    WriteRestgewinn();    /* Speichern der Datei         */
    }
  /* Ganzes Spiel */
  if(argc==1)
    {
    GanzesSpiel();
    sleep(5);
    }
  /* Einzelabfrage */
  if(argc>1)
    {
    EinzelAbfrage(argc, argv);
    }
  }

/**********************************************************/
/* Ende                                                   */
/**********************************************************/




