#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "TicTacToe.h"
#include "patterns.h"



#if 0
//985125
int main()
{
  int winner,x;
  unsigned long totalDraws = 0;
  unsigned long totalXWins = 0;
  unsigned long totalYWins = 0;
  unsigned long totalScore = 0;

  TicTacToeGame * ttt = new TicTacToeGame();

//  while (1)
  for (x=0; x<100000; x++)
  {
    ttt->SetWinPatterns(winPatterns, almostWinPatterns);
    winner = ttt->PlayTicTacToeGame();
    
    
    if (winner == TIE)
      totalScore+=5;
    if (winner == X)
      totalScore+=10;

//    printf("TotalScore: %ld\n", totalScore);
    
    
    /*
    if (winner == TIE)
      totalDraws ++;
    if (winner == X)
      totalXWins++;
    if (winner == Y)
      totalYWins++;

    printf("Draws: %ld\n", totalDraws);
    printf("XWins: %ld\n", totalXWins);
    printf("OWins: %ld\n\n", totalYWins);
*/
  
  }
  printf("TotalScore: %ld\n", totalScore);

  return 0;
}

#endif


#if 1
//86320
#define getrandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

//vec size = 9*24 + 9*8 = 288
#define VECSIZE 288

#define POPULATION 50 



double eval(int *pj);
int FindMaxFitness (double * _fitness);
void CombineVecs(int * _vecA, int *_vecB);
void initVecs(int * _vec);
void DumpTopFitness(double _topFitness, unsigned long _count, 
                    unsigned long _topFitnessCount, int * _vec);
void FindMates(double * _fitness, int *_mates);
void GenerateWinPatterns(int *pj, unsigned long * _almostWinPatterns, 
                                  unsigned long * _winPatterns);



int main()
{
  int vec[POPULATION][VECSIZE];
  int tempVec[POPULATION][VECSIZE];
  int topVec[VECSIZE];
  double fitness[POPULATION], topFitness;
  int mates[POPULATION]; 

 
  int i,x;
  unsigned long count = 0;
  unsigned long topFitnessCount=0;

  srand(time(NULL));
  topFitness = 0;
  
  for(i = 0; i < POPULATION; i++)
  { 
    initVecs(vec[i]);
  }
  while (1)
//  for (x = 0; x< 100; x++)
  {
    for (int x = 0; x < VECSIZE; x++)
      printf("%d ", vec[0][x]);
    printf("\n\n");
    for (i=0; i < POPULATION; i++)
    {
      fitness[i] = eval(vec[i]);
//      printf(" %lf ", fitness[i]);
    }
//    printf("\n");
    int maxFitness = FindMaxFitness (fitness);
    memcpy(vec[POPULATION-1],vec[maxFitness],VECSIZE * sizeof(int)); 
    FindMates(fitness, mates);
    for (int x = 0; x< POPULATION; x++)
    {
      memcpy(tempVec[x], vec[x], VECSIZE*sizeof(int));
    }
//    printf("Combining 0 with: %d\n", mates[0]);
    for (i = 0; i< POPULATION -1; i++)
    {
//      printf("Combining %d and %d\n", i, mates[i]);
//      printf("old: ");
//      for (int y = 0; y< VECSIZE; y++)
//        printf("%d ",vec[i][y]);
//      printf("\n");
//      printf("Combining %d\n", i);
      CombineVecs(vec[i], tempVec[mates[i]]);
//      printf("new: ");
//      for (int y = 0; y< VECSIZE; y++)
//        printf("%d ",vec[i][y]);
//      printf("\n");
    }
//    printf("combining finished\n");
    count++;    
    if (fitness[maxFitness] > topFitness)
    {
      topFitness = fitness[maxFitness];
      topFitnessCount = count;
    }
    DumpTopFitness(topFitness, count, 
                    topFitnessCount, vec[POPULATION-1]);
//    for (int x = 0; x< POPULATION; x++)
//    {
//      for (int y = 0; y<VECSIZE; y++)
//      {
//        printf("%d ", vec[x][y]);
//      }
 //     printf("\n\n");
 //   }
  }
}

void FindMates(double * _fitness, int *_mates)
{
  double totalFitness = 0;
  int ranges[POPULATION];

  for (int x = 0; x< POPULATION-1; x++)
  {
    totalFitness += _fitness[x];
    ranges[x] = (int)totalFitness;
  }
//  printf("TOTALFITNESS = %d ", (int)totalFitness);
  for (int x = 0; x< POPULATION-1; x++)
  {
    int location = getrandom(0,(int)totalFitness);
    _mates[x] = POPULATION-1;
//    printf(" location : %d\n", location);
    for (int y = 0; y< POPULATION -1; y++)
    {
//      printf("%d %d\n", location, ranges[y]);
      if (location <= ranges[y])
      {
        _mates[x] = y;
        break;
      }
    }
  }
}
int FindMaxFitness (double  * _fitness)
{
  double maxFitness = 0;
  int maxLoc = 0;
  for (int x = 0; x< POPULATION; x++)
  {
    if ( _fitness[x] > maxFitness)
      maxLoc = x;
  }
  return maxLoc;
}

void CombineVecs(int * _vecA, int *_vecB)
{
  int totalHits = 0;
  int hits[VECSIZE];

  for (int x = 0; x < VECSIZE; x++)
  {
    hits[x] = 0;
  }
  while (totalHits < (int) (VECSIZE / 2))
  {
    int temp = getrandom(0, VECSIZE-1);
    if (hits[temp] == 0)
    {
      hits[temp] = 1;
      totalHits ++;
    }
  }
  for (int x = 0; x< VECSIZE; x++)
  {
    if (hits[x])
    {
//      printf("Setting %d\n", x);
      _vecA[x] = _vecB[x];
    }
  }

}


void initVecs(int * _vec)
{
  for (int x = 0; x < VECSIZE; x++)
  {
    _vec[x] = getrandom(0,1);
  }
}
void DumpTopFitness(double _topFitness, unsigned long _count, 
                    unsigned long _topFitnessCount, int * _vec)
{
  unsigned long winPatterns[8];
  unsigned long almostWinPatterns[24];
  int x,y;

  memset(winPatterns, 0, 8 * sizeof (unsigned long));
  memset(almostWinPatterns, 0, 24 * sizeof (unsigned long));



  for (x = 0; x < 24; x ++)
  {
    for (y=0; y<9; y++)
    {
      if (_vec[x*9+y])
      {
        almostWinPatterns[x] |= 1<<y;
      }

    }
  }
//  for (x = 217; x < 288; x++)
  for (x = 0; x < 8; x++)
  {
    for (y=0; y<9; y++)
    {
      if (_vec[217+x*9+y])
      {
        winPatterns[x] |= 1<<y;
      }

    }

  }

  for (x = 0; x<24;x++)
  {
    printf ("  %ld,\n", almostWinPatterns[x]);
  }
  printf("\n");
  for (x = 0; x<8;x++)
  {
    printf ("  %ld,\n", winPatterns[x]);
  }
  printf("\n");

  printf("Top Fitness after %ld iterations: %lf [%ld]\n", _count, _topFitness,
              _topFitnessCount);
  for(int i = 0; i < VECSIZE; i++)
    printf("%d ", _vec[i]);
  printf("\n");

}

double eval(int *pj)
{
  int totalScore = 0;
  int winner;
  int x;
  
  unsigned long almostWinPatterns[24];
  unsigned long winPatterns[8];

  memset(almostWinPatterns, 0, 24 * sizeof(unsigned long));
  memset(almostWinPatterns, 0, 8 * sizeof(unsigned long));
  GenerateWinPatterns (pj, almostWinPatterns, winPatterns);

  TicTacToeGame * ttt = new TicTacToeGame();

  for (x = 0; x < 10000; x++)
  {
    ttt->SetWinPatterns(winPatterns, almostWinPatterns);
    winner = ttt->PlayTicTacToeGame();

    if (winner == TIE)
      totalScore += 5;;
    if (winner == X)
      totalScore += 10;
  }
//  printf("TOTALSCORE: %ld\n", totalScore);
  delete (ttt);
  return double(totalScore);


}

void GenerateWinPatterns(int *pj, unsigned long * _almostWinPatterns, 
                                  unsigned long * _winPatterns)
{
  int x,y;

  for (x = 0; x < 24; x ++)
  {
    for (y=0; y<9; y++)
    {
      if (pj[x*9+y])
      {
        _almostWinPatterns[x] |= 1<<y;
      }

    }
  }
//  for (x = 217; x < 288; x++)
  for (x = 0; x < 8; x++)
  {
    for (y=0; y<9; y++)
    {
      if (pj[217+x*9+y])
      {
        _winPatterns[x] |= 1<<y;
      }

    }
  }
}
#endif