// Simple AI Draughts Program Draft8
// Author: Ken Chisholm
// Date: 17.09.20
// Chinook fudge factor now in.
// ----------------------------
// for efficiency all comp/opp[p] for loops checked for == 0. And various...
// v new version of Drafts with bigger board
// Changes:
// -------
// ValueOfSide fn now in. And KCentSQwt
// memcpy now in MiniMax search
// valueOfBd adds numPieces++ for better openings.
// PIECEwt and KINGwt changed to 100 150 with approp others
// theMOVEwt now in for <20 pieces
// New wts a la Chinook 10% of a piece in general. New DBLSsq wt always wks
// 0 for player to move first
// EXCHwt now in. New DBLS wt and Cramp and Randwt usage
//
// Future Ideas:
// ------------

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;

#define  BLACK      1
#define  WHITE      0

#define  FALSE  -1
#define  TRUE    0
#define  READBOARD     2

static int HUMAN []  = { WHITE, 11, 13, 15, 17, 22, 24, 26, 28, 31, 33, 35, 37,
                                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12 };   // 12 pieces at first held
static int COMPUTER[] = { BLACK, 88,86,84,82,77,75,73,71,68,66,64,62, 
                                    1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1,1, 12 };
static int centsq[] = { 33,35,44,46,53,55,64,66 };
static int backsq[] = { 11,13,15,17, 24, 82,84,86,88, 75 };
static int invsq[] = { 19,20,29,30,39,40,49,50,59,60,69,70,79,80};
static int DBLsq[] = { 17, 28, 71, 82};
static char computer[] = { ' ', 'b', 'B' };
static char human[]    = { ' ', 'w', 'W' };

static int numPIECES, numKINGS;                    // ** Globals used by valueOfSide and Eval Board **
static int numCOMPonBd, numOPPonBd;                // ditto.....
   
static  int CROWNwt    =  150;                   // the board wts
static  int PIECEwt     = 100;
static  int MOBwt        =  6;
static  int CENTSQwt      = 2;
static  int KCENTSQwt     = 2;
static  int ADV1wt  =       2;
static  int ADV2wt   =      1;
static  int BACKwt   =      3;
static  int APEXwt   =      3;
static  int CRAMPwt  =     28;             // was 6
static  int DBLSQwt   =    10;            // 120 works for dbl corner prob
static  int RANDOMwt    =   2;
static int  EXCHwt    =     5; 
static int  NEARwt    =    56;                  // 225 seems good?! 66 does cramp well and b/r dbls but not t/left dbl!
static int  theMOVEwt  =    6;

static int WON       = 28000;
static int LOST   =   -28000;
static int YES_A_TAKE=      0;
static int NO_WINNER  =    -1;
     
static int SEARCH_LIMIT1[] =  { 7, 9, 11 };                // 11, 12/13??, 15 works
static int SEARCH_LIMIT2[]  = { 9, 11, 13};                // was 13
static int SEARCH_LIMIT3[]  = {11, 13, 15};                // 15 works for both dbls
static int LEVEL = 0;

static int FEW       =      7;
static int FEWER      =     5;

static int MAX_DEPTH =     36;               // 36 used later in decls
static int LOUD       =     1;
static int QUIET       =    0;

static int CRAZY_MOVE   =    1;
static int NOT_BACKWARDS =   2;
static int INVALID_SQUARE =  3;

static char BOARD[] = { '+','-','-','-','-','-','-','-','-','+',
               '|',' ','%',' ','%',' ','%',' ','%','|',
               '|','%',' ','%',' ','%',' ','%',' ','|',
               '|',' ','%',' ','%',' ','%',' ','%','|',
               '|','%',' ','%',' ','%',' ','%',' ','|',
               '|',' ','%',' ','%',' ','%',' ','%','|',
               '|','%',' ','%',' ','%',' ','%',' ','|',
               '|',' ','%',' ','%',' ','%',' ','%','|',
               '|','%',' ','%',' ','%',' ','%',' ','|',
               '+','-','-','-','-','-','-','-','-','+' };

static char takenb[14];
static char takenw[14];
static int takenbp = 0;
static int takenwp = 0;

static int MOVES[] = { 9, 18, 11, 22, -9, -18, -11, -22 };
static int tk_move[] = { 18, 22, -18, -22 };

static int mini[36];
static int maxi[36];

static int OLD_POSITION, 
         NEW_POSITION, 
         MOVE_diff,
         PIECE,   
         BEST_PIECE_TO_MOVE,
         BEST_PIECE_TO_TAKE, 
         BEST_MOVE, 
         HIGHEST_VALUE_MOVE, 
         MOVES_CONSIDERED, 
         PLY,
         MAX_PLY, 
         MINI_MAX_VALUE,
         PIECE_SCORE,
         MOB_SCORE,
         ADV_SCORE,
         CRAMP_SCORE,
         SEARCH_LIMIT = SEARCH_LIMIT1[LEVEL],
         plynumber,
         taken_piece ,
         best_piece_to_move,
         best_move,
         best_taken_piece;

int move_winner = NO_WINNER, numBdEvals;

static void PrintHelp()
{
    cout <<  "\nDraft8 : An AI draughts program\n";
    cout <<  "Moves are input using a notation similar to that in chess:\n";
    cout <<  "a3-b4        An ordinary move\n";
    cout <<  "c3-e5        A take (jump) move. (Takes MUST be completed in full)\n";
    cout <<  "Note         You MUST take if such a move is available; ie NO 'huffing' allowed!\n";
    cout <<  "Opening number? 0 = You start. Or 1 - 7 = My start.\n";
    //cout <<  "Specials:    input, readx, savex";
    cout <<  "d1-d6        Alter search depth. (eg = 10 + 6)\n";
    cout <<  "quit.        To stop program\n";
}

int select(int argument)    // Returns a Random Integer between 0 and argument -1
{
   int b = 12;

   //a = clock();
   b = rand() % argument;
   //b = b % argument;

   return b;
}

static void newline()
{
   cout <<"\n";
}

int CrownTest(int side[], int piece)
{
   int pos = side[piece];

   if (side[0] == WHITE)
   {
      if (pos >= 82)           // effic: if (pos == 82 || pos == 84 || pos == 86 || pos == 88)
         return 2;
   else 
      return 1;
   } 
   else if (side[0] == BLACK)
   {
      if (pos <=17)             // effic : if (pos == 11 || pos == 13 || pos == 15 || pos == 17)
         return 2;
      else
         return 1;
   }
   return 0;
}

int convert_user_input(int user_input, int pos)
{
      int pp = 0;

    if (pos == 0)
       pp = user_input - 96;
    else
       pp = (user_input - 48) * 10;

    return pp;
}

int Valid_pos(int pos, int comp[],int opp[])
{
   int i, invalid_position = FALSE, valid_position = TRUE;

   if ( pos < 11 || pos > 88) return invalid_position;
   for (i=0; i<=13; i++)
   {
      if ( pos == invsq[i]) return invalid_position;
   }
   for (i=1; i<=12; i++)
   {
      if ( pos == comp[i] || pos == opp[i]) return invalid_position;
   }
   return valid_position;
}

int ValidMove(int PIECE, int MOVE_diff, int comp[], int opp[])
{
   int p, takesq, valid_move = TRUE, invalid_move = FALSE;

   if (comp[PIECE] == 0) return invalid_move;
   if ( (comp[0] == WHITE) && (MOVE_diff < 9) && (comp[PIECE+12] == 1) ) return invalid_move;
   if ( (comp[0] == BLACK) && (MOVE_diff > -9) && (comp[PIECE+12] == 1) )return invalid_move;
   if (MOVE_diff<-11 || MOVE_diff>11)
   {
      if ( Valid_pos( comp[PIECE] + MOVE_diff, comp, opp) != TRUE) return invalid_move;
      takesq = comp[PIECE] + MOVE_diff/2;
      taken_piece = 0;
      for (p = 1; p<=12; p++)
      { if (opp[p]==0) continue;                       // effic.
         if (takesq==opp[p]) { taken_piece = p; break; }
      }
      if ( taken_piece!=0) return valid_move ; 
      else return invalid_move;
   } else if (Valid_pos(comp[PIECE] + MOVE_diff, comp, opp)==TRUE)  return valid_move;
   return invalid_move;
}

void TROUT(int oldpos, int newpos, int mode)      // TRanslate & OUTput move
{
   if (mode==1)  cout <<  "\nDraft8 plays : "; else  cout <<  " , ";
   cout <<   (char) (oldpos-(oldpos/10) * 10 + 96);
   cout <<  oldpos/10 <<"-";
   cout <<  (char) (newpos-(newpos/10) * 10+ 96) ;
   cout <<   newpos/10;
}

int Pending(int comp[], int opp[])
{
   int p, m, v;

   for (p= 1; p<=12; p++)
   {   if (comp[p]==0) continue;                     // efficy
      for (m=0; m<=7; m++)
      {
         v = ValidMove(p, MOVES[m], comp, opp);
         if (v==TRUE) return TRUE;
      }
   }
   return FALSE;
}

int check_mobility(int comp[], int opp[])
{
   int p, move, mob, ustart, uend, start, end;

   if (comp[0]==WHITE) ustart = 0; else ustart = 4;
   mob = 0;
   end = 7;
   start = 0;
   uend = ustart + 3;
   for (p=1; p<=12; p++)
   {   if (comp[p]==0) continue;              // effic
       if (comp[p+12]==1) { start = ustart; end=uend;}
       for (move = start; move <= end; move ++)
       {    
           if (ValidMove(p, MOVES[move], comp, opp)==TRUE) mob = mob+MOBwt;
       }
   }
   return mob;
}

int valueOfSide(int comp[], int opp[])
{
   int i, p, who, valueSide,
       value1 = 0, 
       value2 = 0, 
       value3 = 0, 
       value4 = 0, 
       value5 = 0,
       value6 = 0, 
       value7 = 0,
       value8 = 0,
       value9 = 0,
       valuea = 0,
       valuec = 0,
       valueN = 0;

   who = comp[0];
   numPIECES = 0; numKINGS = 0;
   // Piece and crown count
   for (i=13; i<=24; i++)
   {
      if (comp[i] == 1) { value1 = value1 + PIECEwt; numPIECES++;}
      if (comp[i] == 2) { value2 = value2 + CROWNwt; numKINGS++;}
   }

   // Mobility
   value3 = check_mobility(comp, opp);

   // Centre sq control
   for (p=1; p<=12; p++)
   {
      if ( comp[p]==0) continue;               // no need to search efficiency
      for (i=0; i<=6; i++)
      {
         if ( comp[p] == centsq[i]) {
            if (comp[p+12]==1) value5 = value5 + CENTSQwt; else value4 = value4 + KCENTSQwt;
         }
      }
   }

   // Advancement
   if (who==BLACK) {
      for (p = 1; p<=12; p++)
    {  if (comp[p]==0 ) continue;      // efficy
       if ( (comp[p+12]==1) && (comp[p]<31)) value6 = value6 + ADV1wt;
      }
   }
   if (who==WHITE) {
      for (p = 1; p<=12; p++)           // efficy
      { if (comp[p]==0) continue;
        if ((comp[p+12]==1) && (comp[p]>68)) value6 = value6 + ADV1wt;
      }
   }

   // Back sq and Apex sq control
   if (numKINGS==0) {              // ie No king as yet, so back ctrl counts
      if (who==WHITE)
      {
         if ( comp[1] !=0 && comp[1]< 20 ) value7 = value7 + BACKwt;
         if ( comp[2] !=0 && comp[2]< 20 ) value7 = value7 + BACKwt;
         if ( comp[3] !=0 && comp[3]< 20 ) value7 = value7 + BACKwt;
         if ( comp[4] !=0 && comp[4]< 20 ) value7 = value7 + BACKwt;
         if ( comp[6]==24) value7 = value7 + APEXwt;
      }
      if (who==BLACK) 
      {
         if ( comp[1] > 70) value7 = value7 + BACKwt;
         if ( comp[2] > 70) value7 = value7 + BACKwt;
         if ( comp[3] > 70) value7 = value7 + BACKwt;
         if ( comp[4] > 70) value7 = value7 + BACKwt;
         if ( comp[6]== 75) value7 = value7 + APEXwt;
      }
   }

   if (who==BLACK) { int sw = numOPPonBd; numOPPonBd = numCOMPonBd; numCOMPonBd = sw; } 
   // DBL sq occ
   if (numKINGS>0 && numCOMPonBd > numOPPonBd) {                         // so kings are there so an end game position
      for ( p = 1; p<=12; p++ ) {
         if ( comp[p]==0) continue;              // effic        
         for (int sq =0; sq<4; sq++) {
            if (comp[p+12]==2 && comp[p]==DBLsq[sq]) { value9 = value9 + DBLSQwt + select(RANDOMwt); } // cout <<  "+D"); }
         }
      }
   }

   // NEAR wt
   if ((numCOMPonBd + numOPPonBd) <FEWER) {
   for (p=1; p<=12; p++)
      {  if (comp[p]==0) continue;               // effic
         for (int m=0; m<=7; m++)
         {
            int newpos = comp[p] + MOVES[m];
            if (Valid_pos(newpos, comp,opp)==FALSE) continue;     // effic
            for (int q = 1; q<=12; q++)
            {
               if (p==q || comp[q]==0) continue;                // same piece and effic
               for (int mm = 0; mm<=7; mm++)
               {  
                  if (comp[q]+MOVES[mm] == newpos && m&1==0) valueN = valueN + NEARwt+ select(RANDOMwt);
                  if (comp[q]+MOVES[mm] == newpos && m&1==1) valueN = valueN + NEARwt+ NEARwt + select(RANDOMwt);
               }
            }
         }
      }
   }

   // New CRAMP wt..     MUST  Only If ahead & Not if behind maybe??
   if ((numCOMPonBd + numOPPonBd) <FEWER) {
      for (p=1; p<=12; p++)
      {  if (comp[p]==0) continue;               // effic
         for (int m=1; m<=7; m=m+2)
         {
            int newpos = comp[p] + MOVES[m];
            if (Valid_pos(newpos, comp,opp)==FALSE) continue;     // effic
            for (int q = 1; q<=12; q++)
            {
               if (opp[q]==0) continue;                // same piece and effic
               for (int mm = 0; mm<=7; mm++)
               {  
                  if (opp[q]+MOVES[mm] == newpos) valuec = valuec + CRAMPwt + select(RANDOMwt);
               }
            }
         }
      }
   }

   valueSide = value1 + value2 + value3 + value5 + value6 + value7 + value8 + valuea + value9 + valueN + valuec;
   return valueSide;
}

int EvaluateBoard(int comp[], int opp[])
{
   int valuebd = 0;
   int who = comp[0];
   int numComp, numCompK, numPiecesOnBd, vc, vv, pos, col, numP=0, valueM = 0, valueX = 0;

   numBdEvals++;                   // for stats         
   int am = Pending(comp,opp);
   if (am==FALSE && who==BLACK) return LOST;
   if (am==FALSE & who==WHITE) return WON;
   am = Pending(opp, comp);
   if (am==FALSE && who==BLACK) return WON;
   if (am==FALSE && who==WHITE) return LOST;
   vc = valueOfSide(comp, opp);
   numComp = numPIECES; numCompK = numKINGS;                // Global vars from above fn
   vv = valueOfSide(opp, comp);
   numPiecesOnBd = numComp + numCompK + numPIECES + numKINGS;

   // theMOVEwt
   if (numPiecesOnBd < 16) {
      for (int p = 1; p<=12; p++)
      {
         pos = comp[p];
         if (pos==0) continue;
         col = pos % 10;
         if ( col==1 || col==2 || col==3 || col==4) numP++;
      }
      for (int p = 1; p<=12; p++)
      {
         pos = opp[p];
         if (pos==0) continue;
         col = pos % 10;
         if ( col==1 || col==2 || col==3 || col==4) numP++;
      }
      if (numP &1==1 )
        if ( who==BLACK) valueM = theMOVEwt;
        if ( who==WHITE) valueM = -theMOVEwt;
   }

   // EXCHwt
   int ewt = EXCHwt;
   if ( numPiecesOnBd < 14 ) {
     if (who==BLACK) ewt = EXCHwt; else ewt = -EXCHwt; 
        if (numCOMPonBd + numOPPonBd > numPiecesOnBd) valueX = valueX + ewt; else valueX = valueX - ewt;
   }    // above compares last #pcs with current #pcs

   valuebd = vc - vv + valueM + valueX + numPiecesOnBd + numPiecesOnBd + numPiecesOnBd/2;

   if (numPiecesOnBd >= 20) valuebd = valuebd + valuebd/3;          // Chinook-like fudge factor = *1.33
   if (numPiecesOnBd <= 12) valuebd = valuebd - valuebd/5;          // fudge   = *0.8
   if (who==WHITE) valuebd = -valuebd;

   return valuebd;
}

void take(int PIECE, int MOVE_diff, int comp[], int opp[], int mode, int takes)
{
   int i;

   if (mode==LOUD) TROUT(comp[PIECE], comp[PIECE]+MOVE_diff, takes+1);
   taken_piece = comp[PIECE] + MOVE_diff / 2;

   for ( i=1; i<=12; i++)
   {  if (opp[i]==0) continue;                      // effic do a swap and so first 0 means a break..
      if ( taken_piece == opp[i] )
      {
         opp[i] = 0;
         opp[i+12] = 0;
         break;
      }
   }
   comp[PIECE] = comp[PIECE] + MOVE_diff;
   i = comp[PIECE+12];
   if (comp[PIECE+12]!=2) comp[PIECE+12] = CrownTest(comp, PIECE);
   if (i!=comp[PIECE+12]) return;             // when crowning no further takes allowed

   for (i=1; i<=7; i= i + 2)
   {
      if (ValidMove(PIECE,MOVES[i], comp, opp)==TRUE)
      {
         take(PIECE, MOVES[i], comp, opp, mode, takes+1);
         return;
      }
   }
}

void make_move(int PIECE,int move_diff,int comp[],int opp[],int mode)
{
   MOVES_CONSIDERED++;                                       // for stats

   if (MOVE_diff<=11 && MOVE_diff>=-11) 
   {
      if (mode==LOUD) TROUT(comp[PIECE], comp[PIECE]+MOVE_diff, 1);
      comp[PIECE] = comp[PIECE] + MOVE_diff;
      if (comp[PIECE+12] != 2) comp[PIECE+12] = CrownTest(comp, PIECE);
      return;
   }
   else
   {  
      take(PIECE, MOVE_diff, comp, opp, mode, 0);
   }
}

static void print_message(int m)
{
   cout << "\nYou have entered an illegal move!\n";
}

void Title()
{
   cout <<  "The current board position is:\n";
}

void display_board()
{   
   int i,j,k;
   char s= ' ';

   Title();
   cout <<  "             a   b   c   d   e   f   g   h\n";
   cout <<  "          +----------------------------------+";
      
   for (i = 8; i>=1; i--)
   {
      for (int n = 0; n<=1; n++)
      {
         for (j=1; j<=8; j++)
         {
            if (j==1 && n==1)  cout <<  "\n        " << i<< " | ";
            else if (j==1 && n==0)  cout <<  "\n          | ";
                                 
            s = ' ';
            if ( (i&1)==0 && (j&1)==1) { cout <<  "%%%%"; s = '%';}
            if ( (i&1)==1 && (j&1)==0) { cout <<  "%%%%"; s ='%';}
            if ( (i&1)==0 && (j&0)==0 || (i&1)==1 && (j&1)==1) {
            for (k = 0; k<=12; k++) 
            {
               if (HUMAN[k]==i*10+j) { s = human[HUMAN[k+12]]; break; }
               if (COMPUTER[k]==i*10+j) { s = computer[COMPUTER[k+12]]; break; }
            }
         }                                    
                                  
            if (s==' ' || (s!='%'&&n==0))  cout <<  "    ";
            else if (n==1)
            {
               if (s=='w')  cout <<  " w  ";
               if (s=='W')  cout <<  " W  ";
               if (s=='b')  cout <<  " b  ";
               if (s=='B')  cout <<  " B  ";
            }                                    
         }                    
                        
         if (n==1)  cout <<  " | " << i;  else  cout <<  " |";   
       }
    }
    cout <<  "\n          +----------------------------------+      :";
    for (i=1; i<=12; i++) { if (COMPUTER[i+12]==1)  cout <<  "b"; if (COMPUTER[i+12]==2)  cout <<  "B"; }
    newline();
    cout <<  "             a   b   c   d   e   f   g   h          :";
    for (i=1; i<=12; i++) { if (HUMAN[i+12]==1)  cout <<  "w"; if (HUMAN[i+12]==2)  cout <<  "W"; }
    newline();
}

int NumberofPieces(int comp[], int opp[])
{
   int p, n = 0;

   for (p=1; p<=12; p++)
   {
      if (comp[p]!=0) n = n + 1;
      if (opp[p]!=0) n = n + 1;
   }
   return n;
}

int canTake(int comp[], int opp[])
{
   int p, m;

   for (p=1; p<=12; p++)
   {  if (comp[p]==0) continue;
      for (m = 1; m<=7; m = m + 2)
      {
         if (ValidMove(p,MOVES[m],comp, opp)==TRUE) return TRUE;
      }
   }
   return FALSE;
}

static int getOneSq()
{
   int pos = 0;
     char c3 =' ';

   char c1;
   char c2;

   cin >> c1; cin >> c2; cin >> c3;
   //if (s.length()==3) c3 = users_input[2];
   if (c1=='z') return 0;           // zzz = end of side

   pos = convert_user_input(c1, pos);
   pos = convert_user_input(c2, pos) + pos;
   if (c3=='k' || c3=='K') pos = pos + 100;       //  **  tells caller that it is a King!! ** 

      return pos;
}

int Valid_Square(int pos)
{
   return TRUE;                   // for now!
}

void inputBoard()
{
   int i,j,p,x;

   for (p = 1; p<=24; p++)
   {
      HUMAN[p] = 0;
      COMPUTER[p] = 0;
   }

   cout <<  "Where are YOUR pieces?\n";
   j = TRUE;
   i = 0;
   
    while(j==TRUE)
    {
       p = getOneSq();
       if (p>100) x = 2; else x = 1;
       if (p>100) p = p-100;
       if (p==0) j = FALSE;
       else 
       {
          if (Valid_Square(p)==TRUE)
          {
             i = i + 1;
             HUMAN[i] = p; HUMAN[i+12] =x;
         } else {  cout <<  "Invalid Square"; }
       }
    }
    HUMAN[25] = i;

    cout <<  "Where are MY pieces?\n";
    j = TRUE;
    i = 0;

    while(j==TRUE)
    {  
       p = getOneSq();
       if ( p>100) x = 2; else x = 1;
       if ( p>100) p = p-100;
       if (p==0) j = FALSE;
       else 
       {
          if (Valid_Square(p)==TRUE)
          {
             i = i + 1;
            COMPUTER[i] = p; COMPUTER[i+12] = x;
         } else { cout << "Invalid Square"; }
        }
    }
    COMPUTER[25] = i;
}

static void saveBoard(char c)
{
    ofstream bdfile;

    if (c=='1') bdfile.open("board1.dat");
    if (c=='2') bdfile.open("board2.dat");
    if (c=='3') bdfile.open("board3.dat");
    if (c=='4') bdfile.open("board4.dat");
    if (c=='5') bdfile.open("board5.dat");
    if (c=='6') bdfile.open("board6.dat");
    if (c=='7') bdfile.open("board7.dat");
    if (c=='8') bdfile.open("board8.dat");
    if (c=='9') bdfile.open("board9.dat");
    if (c=='a') bdfile.open("boarda.dat");
    if (c=='b') bdfile.open("boardb.dat");
    if (c=='c') bdfile.open("boardc.dat");
    if (c=='d') bdfile.open("boardd.dat");
    if (c=='e') bdfile.open("boarde.dat");
    if (c=='f') bdfile.open("boardf.dat");

    for (int x=0; x <25; x++) { bdfile << HUMAN[x]; bdfile << " "; }             // write human out
    for (int j=0; j <25; j++) { bdfile << COMPUTER[j]; bdfile << " ";}           // write Computer out
    bdfile.close();
}

static void readBoard(char c)
{
    ifstream bdfile;

    if (c=='1') bdfile.open("board1.dat");
    if (c=='2') bdfile.open("board2.dat");
    if (c=='3') bdfile.open("board3.dat");
    if (c=='4') bdfile.open("board4.dat");
    if (c=='5') bdfile.open("board5.dat");
    if (c=='6') bdfile.open("board6.dat");
    if (c=='7') bdfile.open("board7.dat");
    if (c=='8') bdfile.open("board8.dat");
    if (c=='9') bdfile.open("board9.dat");
    if (c=='a') bdfile.open("boarda.dat");
    if (c=='b') bdfile.open("boardb.dat");
    if (c=='c') bdfile.open("boardc.dat");
    if (c=='d') bdfile.open("boardd.dat");
    if (c=='e') bdfile.open("boarde.dat");
    if (c=='f') bdfile.open("boardf.dat");

    for (int i=0; i< 25; i++) bdfile >> HUMAN[i];
    for (int j=0; j <25; j++) bdfile >> COMPUTER[j];       
}

int GetUsersInput(char users_input[])
{
   int fifth_test = 0 ;
   int convert, pos = 0;

   for (pos = 0; pos<5; pos++) cin >> users_input[pos];
   pos = 0;

   if (users_input[0] =='q')
   {
          cout <<  "\nQuiting Draft8...\n";
        exit(0);
   }   
      if (users_input[0]=='r')            // readX gets saved board from file boardX.dat
      {
         readBoard(users_input[4]);
         cout <<  "Board" << users_input[4] <<" now re-input\n";
         display_board();
         return READBOARD;
       }
       if (users_input[0]=='s') {
          saveBoard(users_input[4]);
           cout <<  "Saving board to board" << users_input[4] <<".dat";
           exit(0);
       }  
       if (users_input[0]=='i')          // input board from keybd
       {
          inputBoard();
        display_board();
          return READBOARD;              // must deal with this later...
       }                                

     fifth_test = 0;
     convert = users_input[0]; 

     if ((convert >= 'a') && (convert <='h'))                
        fifth_test ++;
     else    
         cout <<  "\nFirst co-ordinate range must be : a..h";

     convert = users_input[1];
     if ((convert >= '1') && (convert <= '8'))
       fifth_test ++;
     else
         cout <<  "\nSecond co-ordinate range must be : 1..8";

     convert =  users_input[3];
     if ((convert >='a') && (convert <='h'))
        fifth_test ++;
     else
         cout <<  "\nThird co-ordinate range must be : a..h";

     convert =  users_input[4];
     if ((convert >='1') && (convert <='8'))
        fifth_test ++;
     else
         cout <<  "\nFourth co-ordinate range must be : 1..8";

     if (fifth_test == 4)
     {      
        convert = (int) users_input[0];
        pos = convert_user_input(convert ,pos);      

        convert = (int) users_input[1];
        pos = convert_user_input(convert,pos) + pos;
        OLD_POSITION = pos;
        pos = 0;

        convert = (int) users_input[3];
        pos = convert_user_input(convert ,pos);

       convert = (int) users_input[4];
       pos = convert_user_input(convert ,pos) + pos;
       NEW_POSITION = pos;

       // Special sqs for now!
       if ((OLD_POSITION==14))                   // d1 = set depth x + 16
       {
          SEARCH_LIMIT1[3] = pos/10 + 12; SEARCH_LIMIT2[3] = SEARCH_LIMIT1[3] + 1;
          SEARCH_LIMIT3[3] = SEARCH_LIMIT2[3] + 1; LEVEL = 3;
          SEARCH_LIMIT = SEARCH_LIMIT3[LEVEL];
          cout <<  "\nSearch limit now = " << SEARCH_LIMIT1[3]  << endl;
          return READBOARD;
       }

       return TRUE; 
    }
    else 
    {
       cout <<  "\n";
       display_board();
       return FALSE;   
    }       
}

int singleJumpForWhite(int p, int md, int player[], int opp[])
{
   int i,j, tp, tsq;

   tp = 0;
   tsq = player[p] + md/2;
   //Find which piece of opp is taken
   for ( i=1; i<= 12; i++)
   {
      if (tsq==opp[i]) tp = i;
   }

   player[p] = player[p] + md;
   j = player[p+12];
   if (player[p+12]!=2) player[p+12] = CrownTest(player, p);

   opp[tp] = 0; opp[tp+12] = 0;
   if (j!=player[p+12]) return 2;

   return 1;
}

int WhiteMoveProcess(char aPrompt, char users_input [])
{
   int valid_move = FALSE, 
       another_take = TRUE, 
       the_move, i;
   int result = FALSE;

   if (aPrompt=='M') cout << "Please input your move: ";     //cout <<  "\n" << aPrompt << ": ";
   if (aPrompt=='&') cout << "Please input next jump: ";

   int r = GetUsersInput(users_input);         // ** Uses OLD_POS and NEW_POS. **  
   if (r==READBOARD) return r;

   // while( )   here??       
   the_move = NEW_POSITION - OLD_POSITION;
   if (the_move<0) the_move= -the_move; 
   another_take = canTake(HUMAN, COMPUTER);
   if ((another_take==TRUE) && (the_move<=11))
   {
      cout <<  "\nYou MUST take - No 'huffing' allowed "; newline();
      return result; 
   }           
   MOVE_diff = NEW_POSITION - OLD_POSITION;
   PIECE = 0;
   for (i = 1; i <= 12; i ++) {
      if (OLD_POSITION == HUMAN[i]) { PIECE = i; break; }
   }
   if (PIECE==0)
   {
       cout <<  "No piece on that square?! "; newline();
      return result;
   }
   valid_move = FALSE;
   for ( i=0; i<=7; i++)
   {
         if (MOVE_diff==MOVES[i]) valid_move = TRUE;
      }                          
      if (valid_move==TRUE) valid_move = ValidMove(PIECE, MOVE_diff,HUMAN,COMPUTER);         
      if (valid_move == FALSE)                 
      {                
         cout <<  "Illegal move! "; newline();
         return FALSE;
      }
      int m = MOVE_diff;
      if (m<0) m = -m;
      if (m<=11) make_move(PIECE, MOVE_diff, HUMAN,COMPUTER, QUIET);
      else
      {  
         int crowning = singleJumpForWhite(PIECE, MOVE_diff, HUMAN, COMPUTER);
         if (crowning==2) return TRUE;                       // No more jumps after crowning
         another_take = FALSE;
         display_board();
         for (int mm = 1; mm<=7; mm  = mm + 2)
         {
            if (ValidMove(PIECE, MOVES[mm], HUMAN, COMPUTER)==TRUE) another_take = TRUE;
         }
         if (another_take==TRUE) { WhiteMoveProcess('&',users_input); return TRUE;}
      }
      display_board();
      result = TRUE;
      return result;
   }

int MiniMaxSearch(int ply, int depth, int comp[], int opp[])
{
    int piece, move, must_take, who, inc,hot,apt, valueb, start;
    int temp_comp[25];
    int temp_opp[25];

    inc = 1;
    start = 0;
    who = comp[0];
    temp_comp[0] = who;
    temp_opp[0] = opp[0];
    must_take = canTake(comp, opp);
    hot = 0;                                         //hot = pursuit_value(move, ply);
    if ( (ply>=SEARCH_LIMIT && (must_take==FALSE)) || (ply>= MAX_DEPTH))
    {
       plynumber = ply -1;
       if (ply > MAX_PLY) MAX_PLY = ply;                    // for stats
       return (EvaluateBoard(comp, opp) - plynumber);
    }
    if (must_take==TRUE) { start = 1; inc = 2; }
    mini[ply] =  WON - ply;
    maxi[ply] =  LOST + ply;

    for (piece = 1; piece <= 12; piece ++)
    {  if (comp[piece]==0) continue;                           // effic
       for (move = start; move <= 7; move = move + inc)
       {
          MOVE_diff = MOVES[move];
          PIECE = piece;
          apt = ValidMove(piece, MOVE_diff, comp, opp);
          if (apt==TRUE) 
          {
             memcpy(temp_comp, comp, sizeof(int)*25);   // = for (int pp = 1; pp<=24; pp++) temp_comp[pp] = comp[pp];
             memcpy(temp_opp, opp, sizeof(int)*25);     // = for (int pp = 1; pp<=24; pp++) temp_opp[pp]= opp[pp];
             // for all temp_comp = comp  
             MOVES_CONSIDERED++;
             make_move(PIECE, MOVE_diff, temp_comp,temp_opp, QUIET);
             valueb=MiniMaxSearch(ply+1,depth+hot,temp_opp, temp_comp);
             if ((who==BLACK) && ( valueb>maxi[ply]))
             {
                maxi[ply] = valueb;
                if (ply==1)
                { 
                   BEST_PIECE_TO_MOVE = piece; BEST_MOVE = MOVES[move];
                   best_taken_piece = taken_piece;
                 }
              }
          else if ((who==WHITE) && (valueb< mini[ply]))  mini[ply] = valueb;
          }
          // alpha-beta pruning
          if ((who==WHITE)&&( mini[ply]<=maxi[ply-1])) return  mini[ply];
          if ((ply!=1)&&(who==BLACK)&&(maxi[ply]>= mini[ply-1])) return maxi[ply];
       } 
    }
   // mini-maxing 
   if (who==BLACK) return maxi[ply]; else return  mini[ply];
}

void BlacksMoveProcess()
{
    int i, valuebd, 
        depth,
        value;

      MOVE_diff = 0;  
      PLY = 1;
      depth = 1;
      MOVES_CONSIDERED = 0;
      MINI_MAX_VALUE = 0;
      HIGHEST_VALUE_MOVE = 0;
      BEST_MOVE = 0;
      BEST_PIECE_TO_TAKE = 0;
      MAX_PLY = 0;
      numBdEvals = 0;

      cout <<  "Please wait, Draft8 is thinking ...\n";

      i = NumberofPieces(COMPUTER, HUMAN);
      if (i<FEW) SEARCH_LIMIT = SEARCH_LIMIT2[LEVEL] - select(3);
      if (i<FEWER) SEARCH_LIMIT = SEARCH_LIMIT3[LEVEL] - select(2);
      long t1 = clock();  //long t1 = System.currentTimeMillis();
      numCOMPonBd = valueOfSide(COMPUTER, HUMAN); numCOMPonBd = numPIECES + numKINGS;    // Use of GLOBAL vars.
      numOPPonBd = valueOfSide(HUMAN, COMPUTER);  numOPPonBd = numPIECES + numKINGS;

      valuebd = MiniMaxSearch(PLY, depth,COMPUTER,HUMAN);
      long t2 = clock()-t1;    //long t2 = System.currentTimeMillis(); 
      double secs = (double) t2/1000000.0;
      double pers = (int) MOVES_CONSIDERED/secs;
      if (valuebd>=WON-CROWNwt -CROWNwt)  cout <<  "\nHe-He! I am going to win!\n";
      if (valuebd<=LOST+CROWNwt+CROWNwt)  cout <<  "\nOh Dear! I am going to lose!\n";

      PIECE = BEST_PIECE_TO_MOVE;
      MOVE_diff = BEST_MOVE;

      double per = MOVES_CONSIDERED/secs;
      value = EvaluateBoard(COMPUTER, HUMAN);

      cout <<  "Moves considered : " << MOVES_CONSIDERED;
      cout <<  "  Mini-max Value of Board = " << valuebd;
      cout <<  "   Static board evaluation = " <<  value;
      cout <<  "\nSearch limit = " << SEARCH_LIMIT;
      cout <<  ".   Max ply = " << MAX_PLY << ".  Time = " << secs << " s.";
      cout << "  #moves per sec =  " << pers;
      cout << "  #Board evals = " << numBdEvals;

      make_move(PIECE, MOVE_diff, COMPUTER, HUMAN, LOUD);
      newline();
}

int ExtraTakeTest(int PIECE, int comp[], int opp[])
{
   int  j, extra_take_flag = FALSE, apt, btk_move = 0;

   for (j=0; j<=3; j++)                 
   {
      MOVE_diff = tk_move[j];
      apt = ValidMove(PIECE, MOVE_diff,comp,opp);
      if (apt == TRUE)
      {
         extra_take_flag = TRUE;
         btk_move = MOVE_diff;
         MOVES_CONSIDERED++;
      }
   }
   MOVE_diff = btk_move;
   return extra_take_flag;
}

int pursuit_value(int m, int at_ply)         // not used for now
{
   if (at_ply==1) return 1;                 // basically always 1 at ply 1
   m = m + 1;
   return m & 1;                           // and no inc for take moves
}

int checkAmob(int comp[], int opp[])
{
   int  mob=0;

   for (int p=1; p<=12; p++)
   { if (comp[p]==0) continue;              // effic
      for (int move = 0; move <= 7; move ++)
      {    
         if (ValidMove(p, MOVES[move], comp, opp)==TRUE) return 1;
      }
   }
      return mob;
   }

int check_for_winner()
{
   int piece, m, black=0, white=0;

   for (piece = 13; piece <= 24; piece ++)
   {
      white = white + HUMAN[piece];
      black = black + COMPUTER[piece];
   }

   if (white == 0)
   {
       cout <<  "\nDraft8 wins - better luck next time !\n";
      return 1;
   } 
   if (black == 0)
   {
       cout <<  "\nCongratulations, you win! Well played!\n";
      return 1;
   }

   m = checkAmob(HUMAN, COMPUTER);
   if (m==0) {
       cout <<  "\nYou cannot move any of your pieces so Draft8 wins. Better luck next time.\n";
      return 1;
   }
   m = checkAmob(COMPUTER, HUMAN);
   if (m==0) {
       cout <<  "\nDraft8 cannot move any pieces so you win! Well played!\n";
      return 1;
   }
   return NO_WINNER;
}

int main(int nargs, char *argv[])
{
   char userInput[12];
   int r;

   PrintHelp();
   cout << "Playing level?:";
   while ( cin && cin.peek() <'1' || cin.peek()>'3') 
   {  
     while( cin && cin.peek()!='\n') cin.ignore();          // skip to endl
     cin.ignore();                                          // skip the nl char
     cout << "Which playing level, 1, 2 or 3:"; 
   }
   cin >> LEVEL; LEVEL--; SEARCH_LIMIT = SEARCH_LIMIT1[LEVEL];
   cin.ignore();
   cout << "Which opening number?:";
   while ( cin && cin.peek() <'0' || cin.peek()>'7') 
   {  
     while( cin && cin.peek()!='\n') cin.ignore();          // skip to endl
     cin.ignore();                                          // skip the nl char
     cout << "Which opening NUMBER?:"; 
   }
   cin >> r; 
   if (r!=0) {
      //int  r = select(4);   // int r = ??             // Select a random opening move for variation. Maybe do more??
      // maybe do two-move ballot sometime?...
      if (r==1) { cout <<  "\nDraft8's opening move is b6-a5\n"; COMPUTER[12]=51; }
      if (r==2) { cout <<  "\nDraft8's opening move is b6-c5\n"; COMPUTER[12]=53; }
      if (r==3) { cout <<  "\nDraft8's opening move is d6-c5\n"; COMPUTER[11]=53; }
      if (r==4) { cout <<  "\nDraft8's opening move is d6-e5\n"; COMPUTER[11]=55; }
      if (r==5) { cout <<  "\nDraft8's opening move is f6-e5\n"; COMPUTER[10]=55; }
      if (r==6) { cout <<  "\nDraft8's opening move is f6-g5\n"; COMPUTER[10]=57; }
      if (r==7) { cout <<  "\nDraft8's opening move is h6-g5\n"; COMPUTER[ 9]=57; }
   }
   for (;;)
   {
      display_board();
      int cw = check_for_winner();
      if (cw==0 || cw==1) exit(0);
      for (;;)
      {
         r = WhiteMoveProcess('M', userInput);
         if (r==TRUE) break;
         if (r==READBOARD) {  cout <<  "Board input\n"; continue; }
         cout <<  "re-type that move\n";
      }
      cw = check_for_winner();
      if (cw==0 || cw==1) exit(0);
      BlacksMoveProcess();                               // Draft8 computer move
   }
}





