// P-4 MCS 360 due Mon 15 Nov 2010 : checkerboard.cpp

#include "checkerboard.h"
#include <iostream>
#include <sstream>
#include <ctime>
#include <cstdlib>

checkerboard::checkerboard()
{
   std::pair<int,int> h;
   h.first = 0; h.second = 1;
   hunters.push_back(h);
   h.first = 0; h.second = 3;
   hunters.push_back(h);
   h.first = 0; h.second = 5;
   hunters.push_back(h);
   h.first = 0; h.second = 7;
   hunters.push_back(h);
   srand(time(0));

   fox.first = 7;
   fox.second = 2*(rand() % 4);
}

std::string checkerboard::to_string()
{
   std::ostringstream s;

   for(int i=0; i<8; i++)
   {
      for(int j=0; j<8; j++)
         if((i+j) % 2 == 0)
            s << "X";
         else
            s << " ";
      s << std::endl;
   }
   s << "sum of distances : "
     << distances() << std::endl;

   std::string r = s.str();

   for(int i=0; i<hunters.size(); i++)
   {
      std::pair<int,int> p = hunters[i];
      r[p.first*9 + p.second] = 'O';
   }
   r[fox.first*9 + fox.second] = '*';

   return r;
}

int checkerboard::distances()
{
   int sum = 0;

   for(int i=0; i<hunters.size(); i++)
      if(fox.first <= hunters[i].first)
         sum += 100 + 10*(hunters[i].first - fox.first); // outfoxed
      else
         sum += fox.first - hunters[i].first;

   return sum;
}

bool checkerboard::fox_wins()
{
   return (fox.first == 0);
}

bool checkerboard::game_over()
{
   if(fox_wins())
      return true;
   else
   {
      if(fox.second > 0)
         if(free(fox.first-1,fox.second-1)) return false;
      if(fox.second < 7)
         if(free(fox.first-1,fox.second+1)) return false;

      if(fox.first < 7) // possible to back up ?
      {
         if(fox.second > 0)
            if(free(fox.first+1,fox.second-1)) return false;
         if(fox.second < 7)
            if(free(fox.first+1,fox.second+1)) return false;
      }
      return true;
   }
}

bool checkerboard::free( int row, int column )
{
   if((fox.first == row) && (fox.second == column))
      return false;

   for(int i=0; i<hunters.size(); i++)
      if((hunters[i].first == row)
         && (hunters[i].second == column)) return false;

   return true;
}

void checkerboard::random_move()
{
   bool fail = true;
   while(fail)
   {
      int h = rand() % 4;
      while(hunters[h].first >= 7)
         h = rand() % 4;

      int row = hunters[h].first+1;
      int col;

      if(hunters[h].second == 0)
         col = hunters[h].second+1;
      else if(hunters[h].second == 7)
         col = hunters[h].second-1;
      else
      {
         int r = rand() % 2;  
         if(r == 0)
            col = hunters[h].second-1;
         else
            col = hunters[h].second+1;
      }
      if(free(row,col))
      {
         hunters[h].first = row;
         hunters[h].second = col;
         fail = false;
      }
      else
         fail = true;
   }
}

int checkerboard::hunter_move( int k, int level ) 
{
   if(k == 0)
      return distances();
   else
   {
      if(k % 2 == 1)
      {
         int m_d = 1000; // optimal distance
         int min_h = 0; // which hunter will move
         bool plus = true; // add to column
         for(int i=0; i<4; i++)
         {
            int new_row = hunters[i].first + 1;
            if(new_row < 7)
            {
               int new_col = hunters[i].second - 1;
               if(new_col >= 0)
               {
                  if(free(new_row,new_col))
                  {
                     hunters[i].first = new_row;
                     hunters[i].second = new_col;
                     int d = hunter_move(k-1,level);
                     if(d < m_d)
                     {
                        m_d = d;
                        if(k == level) { min_h = i; plus = false; }
                     }
                     hunters[i].first = hunters[i].first - 1;
                     hunters[i].second = hunters[i].second + 1;
                  }
               }
               new_col = hunters[i].second + 1;
               if(new_col < 7)
               {
                  if(free(new_row,new_col))
                  {
                     hunters[i].first = new_row;
                     hunters[i].second = new_col;
                     int d = hunter_move(k-1,level);
                     if(d < m_d) 
                     {
                        m_d = d;
                        if(k == level) { min_h = i; plus = true; }
                     }
                     hunters[i].first = hunters[i].first - 1;
                     hunters[i].second = hunters[i].second - 1;
                  }
               }
            }
         }
         if(k == level) // make the move for the hunters
         {
            hunters[min_h].first++;
            if(plus)
               hunters[min_h].second++;
            else
               hunters[min_h].second--;
         }
         return m_d;
      }
      else // examine moves of the fox who maximes the distance
      {
         int new_row,new_col;
         int opt_d = 0;
         if(fox.first > 0)
         {
            if(fox.second > 0)
            {
               new_row = fox.first-1; new_col = fox.second-1;
               if(free(new_row,new_col))
               {
                  fox.first = new_row; fox.second = new_col;
                  int d = hunter_move(k-1,level);
                  if(d > opt_d) opt_d = d;
                  fox.first++; fox.second++;
               }
            }
            if(fox.second < 7)
            {
               new_row = fox.first-1; new_col = fox.second+1;
               if(free(new_row,new_col))
               {
                  fox.first = new_row; fox.second = new_col;
                  int d = hunter_move(k-1,level);
                  if(d > opt_d) opt_d = d;
                  fox.first++; fox.second--;
               }
            }
         }
         if(fox.first < 7)
         {
            if(fox.second > 0)
            {
               new_row = fox.first+1; new_col = fox.second-1;
               if(free(new_row,new_col))
               {
                  fox.first = new_row; fox.second = new_col;
                  int d = hunter_move(k-1,level);
                  if(d > opt_d) opt_d = d;
                  fox.first--; fox.second++;
               }
            }
            if(fox.second < 7)
            {
               new_row = fox.first+1; new_col = fox.second+1;
               if(free(new_row,new_col))
               {
                  fox.first = new_row; fox.second = new_col;
                  int d = hunter_move(k-1,level);
                  if(d > opt_d) opt_d = d;
                  fox.first--; fox.second--;
               }
            }
         }
         return opt_d;
      }
   }
}

void checkerboard::move(int level)
{ 
   if(level==0)
      random_move();
   else
      int d = hunter_move(level,level);
}

void checkerboard::go()
{
   int r = fox.first;
   int c = fox.second;
   do
   {
      std::cout << "your current coordinates are : ("
                << r << "," << c << ")" << std::endl;

      std::cout << "go left up (0), or down (2)," << std::endl;
      std::cout << "go right up (1), or down (3)" << std::endl;
      std::cout << "-> type 0, 1, 2, or 3 : ";

      int choice; std::cin >> choice;
      if(choice == 0){
         fox.first--; fox.second--;
      } else if(choice == 1) {
         fox.first--; fox.second++;
      } else if(choice == 2) {
         fox.first++; fox.second--;
      } else {
         fox.first++; fox.second++;
      }
      if((fox.first < 0) || (fox.first > 7)
         || (fox.second < 0) || (fox.second > 7))
         std::cout << "invalid move, please try again" << std::endl;
      else
      {
         std::cout << this->to_string();
         std::cout << "okay with this move ? (y/n) ";
         char ans;
         std::cin >> ans;
         if(ans == 'y') break;
      }
      fox.first = r; fox.second = c;
   }
   while(true);
}

