/////////////////////////////////////////////////////////////////////////
// Game Playing using Minimax                                          //
// By: Nick Cash                                                       //
//                                                                     //
// Fall 2007                                                           //
// 810:161 - Aritifical Intelligence                                   //
//                                                                     //
// game.cpp - Class implementations and game functions                 //
/////////////////////////////////////////////////////////////////////////

// Local Includes
#include "game.h"

/////////////////////////////////
// cBoard class implementation //
/////////////////////////////////

// constructor
cBoard::cBoard()
{
  // initailize entire board to neutral state
  for ( int x = 0; x <= MAX_CELL; x++ )
   board[x] = Neutral;
}

// constructor
cBoard::cBoard(const char *s)
{
  int len = strlen(s);

  if ( len != 9 )
   Error( "cBoard::cBoard(const char*) -> String length not 9." );

  // fill our board based on string contents
  for ( int i = 0; i <= MAX_CELL; i++ )
  {
    // initialize board via string
    switch( tolower(s[i]) ) // smash case
    {
       case 'o': // O - letter
       case '0': // 0 - zero
            board[i] = O;
            break;

       case ' ':
       case '-':
            board[i] = Neutral;
            break;
            
       case 'x':
       case '1':
            board[i] = X;
            break;
            
       default:
            Error( "cBoard::cBoard(char*) -> Default case reached." );
            break;
    }
  }
}

// destructor
cBoard::~cBoard()
{
}

// member functions
void cBoard::SetCell( int index, CellState value )
{
  if ( index < 0 || index > MAX_CELL )
   Error( "cBoard::SetCell -> Invalid index." );
   
  board[index] = value;
}

CellState cBoard::GetCell( int index )
{
  if ( index < 0 || index > MAX_CELL )
   Error( "cBoard::GetCell -> Invalid index." );
   
  return board[index];
}

string cBoard::GetBoard( void )
{
  string s;
  
  // setup a board string based on board settings
  for ( int i = 0; i <= MAX_CELL; i++ )
   switch( board[i] )
   {
     case X:
          s += 'x';
          break;
          
     case O:
          s += 'o';
          break;
          
     default:
     case Neutral:
          s += ' ';
          break;
   }
   
   return s;
}

// Print out the board
void cBoard::PrintBoard( void )
{
  // Print the board
  for ( int i = 0; i <= MAX_CELL; i++ )
  {
    switch( board[i] )
    {
      case X:
           cout << 'X';
           break;

      case O:
           cout << 'O';
           break;

      case Neutral:
           cout << ' ';
           break;

      default:
           cout << "DEFAULT";
           break;
    }

    // Add newlines to make the board appear 3x3
    if ( i == 2 || i == 5 )
     cout << "\n------\n";
    else if ( i != 8 )
     cout << "|";
  }
  
  cout << endl << endl;
}

/////////////////////////////////
// cNode class implementation  //
/////////////////////////////////

// constructor
cNode::cNode(cNode *p, short m, short d, const char * s ) : cBoard( s )
{
  parent = p;
  
  // if we have a null parent this is the root. Root has move of -1
  if ( parent == NULL )
   move = m;
  else if ( m < 0 || m > MAX_CELL )
   Error( "cNode::cNode(cNode, short) -> Bad move." );

  move = m;
  depth = d;
  end_game_value = None;
  type = Unknown;
}

// destructor
cNode::~cNode()
{
}

// member functions
// Print out the board
void cNode::Print( void )
{
  cout << endl;

  // Print the board
  PrintBoard();

  // print our type
#ifdef PRINT_ALL
  cout << endl << "Type: ";
  
  if ( type == Min )
   cout << "Min\n";
  else if ( type == Max )
   cout << "Max\n";
  else
   cout << "Unknown\n";
#endif
   
   // print our value
   cout << endl << "End Game Value: ";
   
   switch ( end_game_value )
   {
     case Win:
          if ( type == Max ) // if the end game node is a max node, Max loses
           cout << "Lose";   // since it is Min's move
          else
           cout << "Win";
          break;
          
     case Draw:
          cout << "Draw";
          break;
          
     case None:
     default:
          cout << "None";
          break;
   }

#ifdef PRINT_ALL
   cout << endl << "Nodal Value: " << value;
#endif

   if ( move == -1 ) // root
    cout << endl << "Move: No move required.\n\n";
   else
    cout << endl << "Move: " << (board[move] == X ? 'X' : 'O' )  << " in cell " << move << endl << endl;
}

// A very bulky and ugly version of tic-tac-toe AI
NodeEndGameValue cNode::CheckEndGame( void )
{
  // check for wins
    // check rows
  if ( (((board[0] == board[1]) && (board[0] == board[2])) && board[0] != Neutral ) ||
       (((board[3] == board[4]) && (board[3] == board[5])) && board[3] != Neutral ) ||
       (((board[6] == board[7]) && (board[6] == board[8])) && board[6] != Neutral ))
       return Win;

    // check columns
  if ( (((board[0] == board[3]) && (board[0] == board[6])) && board[0] != Neutral ) ||
       (((board[1] == board[4]) && (board[1] == board[7])) && board[1] != Neutral ) ||
       (((board[2] == board[5]) && (board[2] == board[8])) && board[2] != Neutral ))
       return Win;

    // check diagnals
  if ( board[4] != Neutral &&
    (((board[0] == board[4]) && (board[0] == board[8])) ||
     ((board[6] == board[4]) && (board[6] == board[2]))))
       return Win;

  // check for nondraw by finding neutral cells
  for ( int i = 0; i <= MAX_CELL; i++ )
   if ( board[i] == Neutral )
      return None;
     
  return Draw;
}