
 // Playfair solving by Simulated Annealing, written by ANCHISES.
 

 #include <iostream>
 #include <condefs.h>
 #include <conio.h>
 #include <fstream.h>

  char codex[3000],code[2000],plain[2000],ian[500];
  char alphabet[30],alpha[30],primus;
  char base[30],ma[30];

  int plainex[2000];
  int r[30];
  int len,flag,buff;
  int run,timer;
  int score,parentscore,bestscore;

  short a[26][26][26][26];

  float e=2.718;
  float ratio,ds,temp,prob,limit;


  trans[4][25] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // norm
                  0,5,10,15,20,1,6,11,16,21,2,7,12,17,22,3,8,13,18,23,4,9,14,19,24,//NW-SE
                  20,21,22,23,24,15,16,17,18,19,10,11,12,13,14,5,6,7,8,9,0,1,2,3,4,//top-bot
                  4,3,2,1,0,9,8,7,6,5,14,13,12,11,10,19,18,17,16,15,24,23,22,21,20 //l to r
                 };


  FILE *InFile;


  void tetragraphs(void);
  void randomise_alpha(void);
  void test_transforms(void);
  void decrypt(void);
  void get_score(void);


 int main()
 {
    int j,k,m,p,q,t,x,y,z;
    int start1,start2,store[5];


    strcpy(alphabet,"ABCDEFGHIKLMNOPQRSTUVWXYZ");
    tetragraphs();  // load log tetragraphs

    strcpy(codex,"LB IN BC RB MO FW FD OF TK OC QU EO KO AW EO RM FO TK OC RE XV BT IV PL RB OI OA NQ EA DM FT NQ NR OZ FO FO FM HT CM RE AE KM ME OM OC WA OT MF NV KO EO FO FO FM HT CM RE OF MF CV QC BK MN RB");
    len=strlen(codex);
    t=-1;
    for(j=0;j<len;j++)
      if(codex[j]>32)
        { t++;code[t]=codex[j]; }
    len=t+1;

    randomize();
    bestscore=0;
    for(run=0;run<1000;run++)
      {

          //...make first parent.............
        randomise_alpha();
        for(j=0;j<25;j++) ma[j]=base[j]=alphabet[r[j]];

        decrypt();
        get_score();
        parentscore=score;
        for(temp=15;temp>4;temp=temp-1)
          {
           timer=0;
           do{
               //...make the child...
               x=random(50)+1; // integer from 1 to 51

               switch(x)
                 {
                  case 1: for(m=0;m<25;m++) ma[m]=base[trans[x][m]]; break;
                  case 2: for(m=0;m<25;m++) ma[m]=base[trans[x][m]]; break;
                  case 3: for(m=0;m<25;m++) ma[m]=base[trans[x][m]]; break;
                  case 4: for(m=0;m<25;m++) ma[m]=base[m];     // swap 2 rows
                        start1=random(5)*5; start2=random(5)*5;
                        for(m=0;m<5;m++) store[m]=ma[start1+m];
                        for(m=0;m<5;m++) ma[start1+m]=ma[start2+m];
                        for(m=0;m<5;m++) ma[start2+m]=store[m];
                        break;
                  case 5: for(m=0;m<25;m++) ma[m]=base[m];   //swap 2 columns
                        start1=random(5); start2=random(5);
                        for(m=0;m<5;m++) store[m]=ma[start1+m*5];
                        for(m=0;m<5;m++) ma[start1+m*5]=ma[start2+m*5];
                        for(m=0;m<5;m++) ma[start2+m*5]=store[m];
                        break;
                  default:
                             for(m=0;m<25;m++) ma[m]=base[m];
                             p=random(25);q=random(25);
                             buff=ma[p];ma[p]=ma[q];ma[q]=buff;
                 }
            //...decrypt & score the child...
               decrypt();
               get_score();
               ds=score-parentscore;    //cout<<ds<<" ";
               flag=0;
               if(ds>0) flag=1; //child is better than parent
               else   // ds is negative, so child worse than parent
                 {
                  ratio=ds/temp;
                  prob=pow(e,ratio);
                  limit=1+random(1000);limit=limit/1000;
                  if(prob>limit) flag=1; // child passes test
                 }

               if(flag==1) //child > parent, or is worse
                      {    // but passes test
                       for(m=0;m<25;m++) base[m]=ma[m]; // new parent
                       parentscore=score;

                      }

             timer++;
           }while(timer<50000); //drop temp after 50000

        }     // end for temp

     
  }  //end for run


  cout<<endl<<"End ";
  getch();
  return 0;
  }

 /*------------------------------------------------------------------------*/

  void randomise_alpha(void)

   {
      int i,j,Used[30];

      for ( i = 0; i < 25; i++ )  Used[i] = 0;
      for ( i = 0; i < 25; i++ )
          {
            j = rand( ) % 25;

            while ( Used[j] )  j = rand( ) % 25;

            r[i] = j;
            Used[j] = 1;
          }
   }

 void decrypt(void)
  {
    int pos1,pos2,rf,rs,cf,cs,c1,c2,r1,r2,x,y;
    int j,k,m;

    for(j=0;j<len;j=j+2)
      {
       for(k=0;k<25;k++) if(code[j]==ma[k]) {pos1=k;break;}
       for(k=0;k<25;k++) if(code[j+1]==ma[k]) {pos2=k;break;}

       rf=pos1/5; rs=pos2/5;   //rf,cf are row & col of first code letter
       cf=pos1%5; cs=pos2%5;

       flag=0;
       if(rf==rs) {            // if same row
          flag=1;
          c1=cf-1;c2=cs-1;     // c1,c2 are columns of 1st & 2nd decodes
          if(c1<0) c1=4;
          if(c2<0) c2=4;
          r1=rf; r2=rs;
         }

        if(cf==cs) {         //  if same column
          flag=1;
          r1=rf-1; r2=rs-1;   // r1,r2 are rows of 1st & 2nd decodes
          if(r1<0) r1=4;
          if(r2<0) r2=4;
          c1=cf; c2=cs;
         }

        if(flag==0) {          // rectangle
          r1=rf;c1=cs;r2=rs;c2=cf;
          }

        pos1=r1*5+c1; pos2=r2*5+c2;
        plain[j]=ma[pos1]+32;
        plain[j+1]=ma[pos2]+32;
       }

  }
 void get_score(void)
   {
    int j,m;

    for(j=0;j<len;j++) plainex[j]=plain[j]-97;
    score=0;
    for(j=0;j<len-3;j++)
      score=score+a[plainex[j]][plainex[j+1]][plainex[j+2]][plainex[j+3]];

    if(score>bestscore)
        {
          bestscore=score;
          cout<<"bestscore="<<bestscore<<"  temp="<<temp<<"  mixed alphabet= ";
          for(m=0;m<25;m++) cout<<ma[m]; cout<<endl;
          for(m=0;m<len;m++) cout<<plain[m];
          cout<<endl<<endl;
        }
   }

 void tetragraphs(void)
   {
      InFile = fopen( "C:\\C++\\TetraLog_hank.bin", "rb" ); //GIZMO's log tetragraphs
      //...Read 456976 values, 2 bytes each, to array a[26][26][26][26]..
      fread( a, 2, 456976, InFile );    fclose( InFile );
   }


=
