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

static int debug = 0;

TicTacToeGame::TicTacToeGame()
{
  bIGoFirst = false;
  srand(time(NULL));

//  printf("TicTacToeGame Created\n");
}
TicTacToeGame::~TicTacToeGame()
{
  
}

void TicTacToeGame::PlaceToken(unsigned long * _playerPos, unsigned long _oppPos)
{
  unsigned long myPos = *_playerPos;
  int x,y;
  int boardLayout[9][2];  //position, score
  int bestMove = -1;
  unsigned long bestScore = 0;
  int bestMoves[9];
  int bestMoveCount = 0;
  for (x = 0; x< 9; x++)
  {
    for (y = 0; y < 2; y++)
    {
      boardLayout[x][y] = 0;
    }
  }
  for (x = 0; x<9; x++)
  {
    if (myPos & 1<<x) //Have I alread put something there?
      continue;
    if (_oppPos & 1<<x) //Is my opponent there?
      continue;
    // Now need to find the best place.. eval and what not..
    boardLayout [x][VALID] = 1;
    if (turn == opp)
      boardLayout [x][SCORE] = CheckOppMove(x,myPos, _oppPos);
    else
      boardLayout [x][SCORE] = CheckMove(x,myPos, _oppPos);
    if (boardLayout[x][VALID] && (boardLayout [x][SCORE] > bestScore))
    {
      bestMove = x; 
      bestMoves[bestMoveCount] = x;
      bestMoveCount++;
      bestScore = boardLayout [x][SCORE];
    }
  }
  if (bestMove > -1)
  { 

    bestMove = bestMoves[getrandom(0,bestMoveCount-1)];

    myPos |= 1<<bestMove;
  }
  else
  {
    printf("ERRoR\n");
    DumpBoard(myPos, _oppPos);
    exit(0);
  }
  *_playerPos = myPos;
}
void TicTacToeGame::DumpBoard(unsigned long _myPos, unsigned long _oppPos)
{

  for (int x = 0; x < 9; x ++)
  {
    if (1<<x & _myPos == 1<<x)
      printf("x");
    else if (1<<x & _oppPos == 1<<x)
      printf("O");
    else
      printf(" ");

  }
  printf("\n\n");

}

void TicTacToeGame::PlaceRandomToken(unsigned long * _playerPos, unsigned long _oppPos)
{
  unsigned long myPos = *_playerPos;
  int x,y;
  int boardLayout[9];
  int totalSpacesAvailable = 0;
  for (x = 0; x< 9; x++)
  {
    boardLayout[x] = 0;
  }
  for (x = 0; x<9; x++)
  {
    if (myPos & 1<<x) //Have I alread put something there?
      continue;
    if (_oppPos & 1<<x) //Is my opponent there?
      continue;

    boardLayout[totalSpacesAvailable] = x;
    totalSpacesAvailable ++;
  }
  if (totalSpacesAvailable == 0)
  {
    printf("PlaceRandomToken: Error Full Board\n");
  }
  myPos |= 1<< boardLayout[getrandom(0,totalSpacesAvailable)];
  *_playerPos = myPos;
}

unsigned long TicTacToeGame::CheckMove (int _newPos, unsigned long _myPos, unsigned long _oppPos)
{
  int x,y;
  _myPos |= 1<<_newPos;
  _oppPos |= 1<<_newPos;
  for (x = 0; x< TOTAL_WIN_PATTERNS; x++)
  {
    if ((_myPos & endPatterns[x]) == endPatterns[x])
    {
//      return WINNER;
      return xWin;
    } 
  }
  for (x = 0; x< TOTAL_WIN_PATTERNS; x++)
  {
    if ((_oppPos & endPatterns[x]) == endPatterns[x])
    {
//      return BLOCK;
      return xBlock;
    }
  }

  for (x = 0; x < TOTAL_WIN_PATTERNS; x++)
  {
    int winLocations[3];
    int matches = 0;
    for (y = 0; y < 9; y++)
    {
      if (endPatterns[x] & 1<<y)
      {
        winLocations[matches] = y;
        matches++;
      }
    }
    if (matches !=3)
    {
      printf("ERROR FINDING WINNING PATTERN\n");
    }
//Attention sloppy code...
    unsigned long tempPatterns[3][2];
    tempPatterns[0][0] = 1<<winLocations[0] | 1<<winLocations[1];
    tempPatterns[0][1] = 1<<winLocations[2];
    tempPatterns[1][0] = 1<<winLocations[0] | 1<<winLocations[2];
    tempPatterns[1][1] = 1<<winLocations[1];
    tempPatterns[2][0] = 1<<winLocations[1] | 1<<winLocations[2];
    tempPatterns[2][1] = 1<<winLocations[0] ;
    for (int y = 0; y < 3; y++)
    {
      if ((tempPatterns[y][0] & _myPos) == tempPatterns[y][0])
      {
        if (!(_myPos & tempPatterns[y][1]) && !(_oppPos & tempPatterns[y][1]))
        {
          //We are 1 spot away from a win!
   
//          return ALMOST_WIN;
          return xAlmostWin;

        }
      }
    } 
//end of sloppy code

  }
  return 1;
}


unsigned long int TicTacToeGame::CheckOppMove (int _newPos, unsigned long _myPos, unsigned long _oppPos)
{
  int x,y;
  _myPos |= 1<<_newPos;
  _oppPos |= 1<<_newPos;
  for (x = 0; x< TOTAL_WIN_PATTERNS; x++)
  {
    if ((_myPos & endPatterns[x]) == endPatterns[x])
    {
//      return WINNER;
      return oWin;
    } 
  }
  for (x = 0; x< TOTAL_WIN_PATTERNS; x++)
  {
    if ((_oppPos & endPatterns[x]) == endPatterns[x])
    {
//      return BLOCK;
      return oBlock;
    }
  }

//Go through each win pattern, check it 2 at a time.
//Does it match any of my patterns? No continue
//Does the remaining position contain a token? No? return almost win


  for (x = 0; x < TOTAL_WIN_PATTERNS; x++)
  {
    int winLocations[3];
    int matches = 0;
    for (y = 0; y < 9; y++)
    {
      if (endPatterns[x] & 1<<y)
      {
        winLocations[matches] = y;
        matches++;
      }
    }
    if (matches !=3)
    {
      printf("ERROR FINDING WINNING PATTERN\n");
    }
//Attention sloppy code...
    unsigned long tempPatterns[3][2];
    tempPatterns[0][0] = 1<<winLocations[0] | 1<<winLocations[1];
    tempPatterns[0][1] = 1<<winLocations[2];
    tempPatterns[1][0] = 1<<winLocations[0] | 1<<winLocations[2];
    tempPatterns[1][1] = 1<<winLocations[1];
    tempPatterns[2][0] = 1<<winLocations[1] | 1<<winLocations[2];
    tempPatterns[2][1] = 1<<winLocations[0] ;
    for (int y = 0; y < 3; y++)
    {
      if ((tempPatterns[y][0] & _myPos) == tempPatterns[y][0])
      {
        if (!(_myPos & tempPatterns[y][1]) && !(_oppPos & tempPatterns[y][1]))
        {
          //We are 1 spot away from a win!
   
//          return ALMOST_WIN;
           return oAlmostWin;

        }
      }
    } 
//end of sloppy code

  }

  return 1;
}



int TicTacToeGame::CheckForWinner (unsigned long _xLoc, unsigned long _yLoc)
{
  int x;
  for (x = 0; x< TOTAL_WIN_PATTERNS; x++)
  {
    if ((_xLoc & WINPATTERNS[x]) == WINPATTERNS[x])
    {
//      printf("X WINS: %d:%ld\n", WINPATTERNS[x], xLoc);
      return X; //X wins
    }
  }

  for (x = 0; x< TOTAL_WIN_PATTERNS; x++)
  {
    if ((_yLoc & WINPATTERNS[x]) == WINPATTERNS[x])
    {
//      printf("Y WINS: %d\n", WINPATTERNS[x]);
      return Y; //y Wins
    }
  }
  if ( (_xLoc | yLoc) == FULL_CARD)
    return 0;  //DRAW
  return -1;
}

int TicTacToeGame::PlayTicTacToeGame()
{
  winner = -1;
  xLoc = 0;
  yLoc = 0;

  bIGoFirst = ! bIGoFirst;
  while (winner == -1)
  {
    if (bIGoFirst)
    {
      turn = me;
      PlaceToken(&xLoc,yLoc);
      winner = CheckForWinner(xLoc,yLoc);
      if (winner == -1)
      {
        turn = opp;
        PlaceToken(&yLoc,xLoc);
  //      PlaceRandomToken(&yLoc,xLoc);
        winner = CheckForWinner(xLoc,yLoc);
      }
    }
    else 
    {
      turn = opp;
      PlaceToken(&yLoc,xLoc);
      winner = CheckForWinner(xLoc,yLoc);
      if (winner == -1)
      {
        turn = me;
        PlaceToken(&yLoc,xLoc);
  //      PlaceRandomToken(&yLoc,xLoc);
        winner = CheckForWinner(xLoc,yLoc);
      }
    }


  }
  if (debug)
  {
    for (int x = 0; x < 9; x++)
    {
      if (xLoc & 1<<x)
        printf("X");
      else if (yLoc & 1<<x)
        printf("O");
      else
        printf(" ");
      if (x==2 || x==5)
        printf("\n");
    }
    printf("\n: %d:%ld:%ld\n", winner, xLoc, yLoc);
  }
//  char a;
//  scanf(&a,"%c");
//  exit(0);
  return winner;
}
void TicTacToeGame::SetXWinPatterns(unsigned long * _winPatterns, 
                                   unsigned long * _almostWinPatterns)
{
  xWinPatterns = _winPatterns;
  xAlmostWinPatterns = _almostWinPatterns;
}

void TicTacToeGame::SetOWinPatterns(unsigned long * _winPatterns, 
                                   unsigned long * _almostWinPatterns)
{
  oWinPatterns = _winPatterns;
  oAlmostWinPatterns = _almostWinPatterns;
}

void TicTacToeGame::SetXValues(unsigned long _xWin, unsigned long _xBlock,
                           unsigned long _xAlmostWin)
{
  xWin = _xWin;
  xBlock = _xBlock;
  xAlmostWin = _xAlmostWin;

}
void TicTacToeGame::SetOValues(unsigned long _oWin, unsigned long _oBlock,
                           unsigned long _oAlmostWin)
{
  oWin = _oWin;
  oBlock = _oBlock;
  oAlmostWin = _oAlmostWin;

}

bool TicTacToeGame::DidIGoFirst()
{
  return bIGoFirst;

}

