// EXchess source code, (c) Daniel C. Homan  1997-2011
// Released under the GNU public license, see file license.txt


#include "define.h"
#include "chess.h"
#include "funct.h"
#include "score.h"
#include "hash.h"
#include "extern.h"
#include <cmath>
#include <iostream>
using namespace std;

//------------------------------------------------------------
// Function to set the score values from the score array which
//  is used for TD leaf learning
//------------------------------------------------------------

void set_scores(int *sc)
{

 int m, n, pp;

 // set values of scoring parameters

 value[PAWN] = sc[0]/10;
 value[KING] = sc[1]/10;
 value[KNIGHT] = sc[2]/10;
 value[BISHOP] = sc[3]/10;
 value[ROOK] = sc[4]/10;
 value[QUEEN] = sc[5]/10;
 DOUBLED_PAWN = sc[6]/10;
 WEAK_PAWN = sc[7]/10;
 BACKWARD_PAWN = sc[8]/10;
 PAWN_ISLAND = sc[9]/10;
 PASSED_PAWN = sc[10]/10;
 BISHOP_PAIR = sc[11]/10;
 ROOK_CONN_OPEN = sc[12]/10;
 ROOK_CONN_HALF_OPEN = sc[13]/10;
 CON_PASSED_PAWNS = sc[14]/10;
 OUTSIDE_PASSED_PAWN = sc[15]/10;
 FREE_PASSED_PAWN = sc[16]/10;
 CASTLED = sc[17]/10;
 NO_POSSIBLE_CASTLE = sc[18]/10;
 ROOK_MOBILITY = sc[19]/10;
 QUEEN_MOBILITY = sc[20]/10;
 KNIGHT_MOBILITY = sc[21]/10;
 PAWN_DUO = sc[22]/10;
 BOXED_IN_ROOK = sc[23]/10;
 KNIGHT_OUTPOST = sc[24]/10;
 BISHOP_OUTPOST = sc[25]/10;
 KING_SIDE_DEFECTS = sc[26]/10;
 QUEEN_SIDE_DEFECTS = sc[27]/10;
 ROOK_OPEN_FILE = sc[28]/10;
 ROOK_HALF_OPEN_FILE = sc[29]/10;
 KING_ATTACKS = sc[30]/10;
 outpost_score[0] = sc[31]/10;
 outpost_score[1] = sc[32]/10;
 outpost_score[2] = sc[33]/10;
 outpost_score[3] = sc[34]/10;
 outpost_score[4] = sc[35]/10;
 outpost_score[5] = sc[36]/10;
 outpost_score[6] = sc[37]/10;
 outpost_score[7] = sc[38]/10;
 SIDE_ON_MOVE = sc[39]/10;
 BISHOP_MOBILITY = sc[40]/10;
 // setup piece_square tables
 for(m = 0; m < 4; m++) {
   for(pp=0; pp < 6; pp++) {  
     // loop over squares last
     for(n = 0; n < 64; n++) {
      piece_sq[m][pp+1][n] = sc[41+64*(4*pp+m)+n]/10;
     } 
   }
 }
   
}

/* variables to set learning rate - set externally in search.par */
double TD_ALPHA = 10.0;
double TD_LAMBDA = 0.7;

void score_learning(int T, int stm, game_rec *gr)
{

 int s[MAX_GAME_PLY], n, i;
 int splus, j, m, adjust;
 double ds, sum1[LEARN_PARAMETERS], sum2, d[MAX_GAME_PLY];
 double alpha = TD_ALPHA, Lambda = TD_LAMBDA;
 position lp[MAX_GAME_PLY];

 /* initial loop to setup scores and positions for learning */
 for(n = 0; 2*n+1+(stm^1) < T; n++) {
   lp[n] = gr->learn_positions[2*n+(stm^1)];
   if(!lp[n].hcode || !lp[n].plist[0][6][0] 
       || !lp[n].plist[1][6][0]) {
    s[n] = -123456;
    continue;
   }
   s[n] = lp[n].score_pos(-MATE,+MATE, gr);
   if(stm != lp[n].wtm) s[n] = -s[n];
   // check leaf score against root score, the >>2 is a divide by
   //  four which accounts for the fact that during the game 
   //  (when the root score is stored) the scores are rounded to
   //  the nearest 4% of a pawn value.
   if((s[n]/4) != (gr->learn_root_scores[2*n+(stm^1)]/4) && 2*n+1+(stm^1) < T-1) {
     // PV used to create leaf position must have been wrong
     s[n] = -123456;   // don't use this position
     continue;
   }
 }

 /* next loop to set up score difference between positions */
 for(i = 0; i <= n-1; i++) {
  if(s[i] == -123456) { d[i] = 0.0; continue; }
  if(i==n-1) { 
    //if(s[i] < -500) d[i] = -1.0 - tanh(0.00255*double(s[i]));
    //else if(s[i] > +500)  d[i] = +1.0 - tanh(0.00255*double(s[i]));
    //else d[i] = 0.0;
    d[i] = 0.0;
  } else {
    if(s[i+1] == -123456) { d[i] = 0.0; continue; }
    d[i] = tanh(0.00255*double(s[i+1]))-tanh(0.00255*double(s[i]));
    // avoid blunders
    if(d[i] > 0 && !gr->predicted[2*i+(stm^1)]) d[i] = 0;
  }
 }

 /* now loop over parameters and do a double sum */
 for(j = 1; j < LEARN_PARAMETERS; j++) {
  sum1[j] = 0.0;
  if(!lscores[j]) continue;
  if(scores[j] < 0 && scores[j] > -10) adjust = 20;
  else adjust = 10;
  scores[j] += adjust;
  set_scores(scores);
  for(i = 0; i < n-1; i++) {
   // finding derivative versus score parameter s
   if(s[i] == -123456) continue;
   // recompute material score if necessary
   if(j < 6) {
     if(j > 1)
      lp[i].material += lp[i].plist[lp[i].wtm][j][0] - lp[i].plist[!lp[i].wtm][j][0];
     else
      lp[i].material += lp[i].plist[lp[i].wtm][6][0] - lp[i].plist[!lp[i].wtm][6][0];
   }
   splus = lp[i].score_pos(-MATE,+MATE, gr);
   if(stm != lp[i].wtm) splus = -splus;
   if(splus == s[i]) ds = 0.0;
   else ds = (tanh(0.00255*double(splus)) - tanh(0.00255*double(s[i])))
	    /(double(adjust)/1000.0);
   // For debugging
   if(j == 1 && splus != s[i]) {
     char outline[200];
     sprintf(outline, "Error(KING_SCORE_CHANGE: splus=%i s[i]=%i\n", splus, s[i]);
     write_out(outline);
   }   
   //calculating sum2
   sum2 = 0.0;
   for(m = i; m < n-1; m++)
    sum2 += pow(Lambda,(m-i))*d[m];
   // adding to sum1
   sum1[j] += alpha*ds*sum2;
   // reset material score if necessary
   if(j < 6) {
     if(j > 1)
      lp[i].material -= lp[i].plist[lp[i].wtm][j][0] - lp[i].plist[!lp[i].wtm][j][0];
     else
      lp[i].material -= lp[i].plist[lp[i].wtm][6][0] - lp[i].plist[!lp[i].wtm][6][0];
   }
  }
  scores[j] -= adjust;
 }

 for(j = 1; j < LEARN_PARAMETERS; j++) {
   if(sum1[j] >= 0 && scores[j] >= 0) 
     scores[j] += int(MIN(sum1[j],0.1*double(scores[j])+1.0)); 
   if(sum1[j] < 0 && scores[j] >= 0) 
     scores[j] += int(MAX(sum1[j],-0.1*double(scores[j])-1.0)); 
   if(sum1[j] >= 0 && scores[j] < 0) 
     scores[j] += int(MIN(sum1[j],-0.1*double(scores[j])+1.0)); 
   if(sum1[j] < 0 && scores[j] < 0) 
     scores[j] += int(MAX(sum1[j],0.1*double(scores[j])-1.0));     		    
 }

 set_scores(scores);
 write_scores();
}


/*--------------------------- Score position ------------------------*/
// Position is scored from point of view of white to move.  Score is
// currently based on a number of factors: Open files, king proximity,
// good/bad bishops, bishop pairs, pawn structure, king safety, etc....
extern unsigned int PAWN_SIZE;
extern pawn_rec *pawn_table;

int position::score_pos(int alpha, int beta, game_rec *gr)
{
  register int score = 0, rscore = 0, i, file, rank, sqr;
   register int wksq = plist[WHITE][KING][1];
   register int bksq = plist[BLACK][KING][1];
   pawn_rec *pawns;
   

/*+++++++++++++++++++++++++++++++
|
| Score the material on the board
|
+++++++++++++++++++++++++++++++++*/
   //score = (wtm ? (material+SIDE_ON_MOVE) : -(material+SIDE_ON_MOVE));
   score = (wtm ? (material) : -(material));

/*+++++++++++++++++++++++++++++++
|
| Probing Pawn Hash Table
|
+++++++++++++++++++++++++++++++++*/
   pawns = pawn_table+(pcode&(PAWN_SIZE-1));
   if(pawns->key == pcode && !gr->learn_scores) {
    score += pawns->score;
    gr->ts.phash_count++;
   } else {
    pawns->key = pcode;
    score += score_pawns(pawns);
   } 

   score += (wtm ? ((SIDE_ON_MOVE*(13-pawns->pstage))/11) : -((SIDE_ON_MOVE*(13-pawns->pstage))/11));


/*+++++++++++++++++++++++++++++++
|
| Examining Passed Pawns
|
+++++++++++++++++++++++++++++++++*/
   // For White
   if(pawns->passed_w) {
    for(file=0;file<8;file++) {
     if(bitmask[file]&pawns->passed_w) { 
      for(i=file+48;i>7;i-=8) {
       if(sq[i].type==PAWN) {
        rank = RANK(i);
	/*+++++++++++++++++++++++++++++++++
        |
        | Outside passed pawns
        |
        +++++++++++++++++++++++++++++++++++*/ 
        if(file > FILE(bksq)+3 || file < FILE(bksq)-3)
	      score += OUTSIDE_PASSED_PAWN*(rank-1)*pawns->pstage/4;
    	/*+++++++++++++++++++++++++++++++++
        |
        | If no material: Can King Catch?
        |
        +++++++++++++++++++++++++++++++++++*/ 
        if(pieces[BLACK] == 1) {
         if((7-rank < taxi_cab[file+56][bksq]+1 && wtm)
            || (7-rank < taxi_cab[file+56][bksq]+2))
	       score += FREE_PASSED_PAWN*(rank-1)*pawns->pstage/4;
        }           
        break;      
       }
      }
     }
    }
   } 
   // For Black
   if(pawns->passed_b) {
    for(file=0;file<8;file++) {
     if(bitmask[file]&pawns->passed_b) {
      for(i=file+8;i<56;i+=8) {
       if(sq[i].type==PAWN) {
        rank = RANK(i);
     	/*+++++++++++++++++++++++++++++++++
        |
        | Outside passed pawns
        |
        +++++++++++++++++++++++++++++++++++*/ 
        if(file > FILE(wksq)+3 || file < FILE(wksq)-3)
	      score -= OUTSIDE_PASSED_PAWN*(6-rank)*pawns->pstage/4;
    	/*+++++++++++++++++++++++++++++++++
        |
        | If no material: Can King Catch?
        |
        +++++++++++++++++++++++++++++++++++*/ 
        if(pieces[WHITE] == 1) {
         if((rank < taxi_cab[file][wksq]+1 && (wtm^1))
            || (rank < taxi_cab[file][wksq]+2))
	       score -= FREE_PASSED_PAWN*(6-rank)*pawns->pstage/4; 
        }   
        break;      
       }
      }
     }
    }
   }    

/*+++++++++++++++++++++++++++++++
|
| Evaluate Bishop Trap
|
+++++++++++++++++++++++++++++++++*/
    if(ID(sq[48]) == WBISHOP 
       && ID(sq[41]) == BPAWN && ID(sq[50]) == BPAWN)
       score -= value[BISHOP] - 100;
    if(ID(sq[55]) == WBISHOP 
       && ID(sq[46]) == BPAWN && ID(sq[53]) == BPAWN)
       score -= value[BISHOP] - 100;
    if(ID(sq[8]) == BBISHOP 
       && ID(sq[17]) == WPAWN && ID(sq[10]) == WPAWN)
       score += value[BISHOP] - 100;
    if(ID(sq[15]) == BBISHOP 
       && ID(sq[22]) == WPAWN && ID(sq[13]) == WPAWN)
       score += value[BISHOP] - 100;

/*+++++++++++++++++++++++++++++++
|
| Examining King Safety
|
+++++++++++++++++++++++++++++++++*/
    // for debugging king safety
    //if(wtm) return(score_king(pawns,gr));
    //else return -score_king(pawns,gr);
  
    score += score_king(pawns, gr);



/*+++++++++++++++++++++++++++++++
|
| Early Exit ?
|
+++++++++++++++++++++++++++++++++*/

   rscore = score;
   if(pieces[WHITE] < 3 && !plist[WHITE][PAWN][0] && !plist[WHITE][QUEEN][0]
      && !plist[WHITE][ROOK][0]) rscore = MIN(rscore,0);
   if(pieces[BLACK] < 3 && !plist[BLACK][PAWN][0] && !plist[BLACK][QUEEN][0]
      && !plist[BLACK][ROOK][0]) rscore = MAX(rscore,0);  

   /*
   if(score > 9999 || score < -9999) { 
     cout << "Anomolous Score1!" << score <<"\n";  cout.flush();
     logfile << "Anomolous Score1!" << score <<"\n";  logfile.flush();
   }
   */

  /* make a knowledge adjustment to weaken play */
  if(gr->knowledge_scale < 100) {
    int nscore = (gr->knowledge_scale*rscore)/100;
    if(pcode&1) nscore -= int(float(rscore)*(100.0-float(gr->knowledge_scale))/100.0);
    else nscore += int(float(rscore)*(100.0-float(gr->knowledge_scale))/100.0);
    if(pcode&2) nscore -= int(float(rscore)*(100.0-float(gr->knowledge_scale))/100.0);
    else nscore += int(float(rscore)*(100.0-float(gr->knowledge_scale))/100.0);
    if(pcode&4) nscore -= int(float(rscore)*(100.0-float(gr->knowledge_scale))/100.0);
    else nscore += int(float(rscore)*(100.0-float(gr->knowledge_scale))/100.0);
    rscore = nscore;
    if(rscore > 9999) rscore = 9999;
    if(rscore < -9999) rscore = -9999;
  }

  rscore = (rscore/4);
  rscore = (rscore*4);

  if(wtm) { 
    if(beta < rscore-EARLY_EXIT) return(rscore);
    else if(alpha  > rscore+EARLY_EXIT) return(rscore);   
  } else {
    if(beta < -rscore-EARLY_EXIT) return(-rscore);
    else if(alpha > -rscore+EARLY_EXIT) return(-rscore); 
  }

/*+++++++++++++++++++++++++++++++
|
| Evaluate Knights
|
+++++++++++++++++++++++++++++++++*/
   for(i=1;i<=plist[WHITE][KNIGHT][0];i++) {
    sqr = plist[WHITE][KNIGHT][i]; 
    if(pawns->pstage < 12) { 	
      score += ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][KNIGHT][whitef[sqr]]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][KNIGHT][whitef[sqr]])/4;
    } else {
      score += piece_sq[3][KNIGHT][whitef[sqr]];
    }
    score += (KNIGHT_MOBILITY*knight_mobility(sqr))/16;
   }
   for(i=1;i<=plist[BLACK][KNIGHT][0];i++) { 
    sqr = plist[BLACK][KNIGHT][i];
    if(pawns->pstage < 12) { 	
      score -= ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][KNIGHT][sqr]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][KNIGHT][sqr])/4;
    } else {
      score -= piece_sq[3][KNIGHT][sqr];
    }
    score -= (KNIGHT_MOBILITY*knight_mobility(sqr))/16;
   }

/*+++++++++++++++++++++++++++++++
|
| Evaluate Bishops
|
+++++++++++++++++++++++++++++++++*/
   for(i=1;i<=plist[WHITE][BISHOP][0];i++) {
    sqr = plist[WHITE][BISHOP][i];
    if(pawns->pstage < 12) { 	
      score += ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][BISHOP][whitef[sqr]]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][BISHOP][whitef[sqr]])/4;
    } else {
      score += piece_sq[3][BISHOP][whitef[sqr]];
    }
    if(i==2) score += BISHOP_PAIR;
    score += (BISHOP_MOBILITY*bishop_mobility(sqr))/16;    
   }
   for(i=1;i<=plist[BLACK][BISHOP][0];i++) {
    sqr = plist[BLACK][BISHOP][i];
    if(pawns->pstage < 12) { 	
      score -= ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][BISHOP][sqr]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][BISHOP][sqr])/4;
    } else {
      score -= piece_sq[3][BISHOP][sqr];
    }
    if(i==2) score -= BISHOP_PAIR;
    score -= (BISHOP_MOBILITY*bishop_mobility(sqr))/16;
   }

/*+++++++++++++++++++++++++++++++
|
| Evaluate Outposts for Knights
|                   and Bishops
|  - Outposts are stored as bits
|    of a character.  Specific bits
|    correspond to particular useful
|    outpost squares.
|
+++++++++++++++++++++++++++++++++*/
   if(pawns->wposts) {
     for(i=0;i<8;i++) {
       if(pawns->wposts&bitmask[i]) {
         if(ID(sq[white_outpost[i]]) == WKNIGHT) 
          score += KNIGHT_OUTPOST*outpost_score[i];
         else if(ID(sq[white_outpost[i]]) == WBISHOP) 
          score += BISHOP_OUTPOST*outpost_score[i];
         pawns->wposts ^= bitmask[i];
         if(!pawns->wposts) i=8;
       }
     }
   }  
   if(pawns->bposts) {
     for(i=0;i<8;i++) {
       if(pawns->bposts&bitmask[i]) {
         if(ID(sq[black_outpost[i]]) == BKNIGHT) 
          score -= KNIGHT_OUTPOST*outpost_score[i];
         else if(ID(sq[black_outpost[i]]) == BBISHOP) 
          score -= BISHOP_OUTPOST*outpost_score[i]; 
         pawns->bposts ^= bitmask[i];
         if(!pawns->bposts) i=8;
       }
     }
   }

/*+++++++++++++++++++++++++++++++
|
| Evaluate Rooks
|
+++++++++++++++++++++++++++++++++*/
   
   for(i=1;i<=plist[WHITE][ROOK][0];i++) {
    sqr = plist[WHITE][ROOK][i]; 
    if(pawns->pstage < 12) { 	
      score += ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][ROOK][whitef[sqr]]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][ROOK][whitef[sqr]])/4;
    } else {
      score += piece_sq[3][ROOK][whitef[sqr]];
    }
    rank = RANK(sqr); file = FILE(sqr);
    score += (ROOK_MOBILITY*rook_mobility(sqr))/16;
    /*+++++++++++++++++++++++++++++++
    |
    | Rooks on open and half-open files
    |
    +++++++++++++++++++++++++++++++++*/
    if(pawns->open_files&bitmask[file]) {
     score += ROOK_OPEN_FILE; 
     // Are the rooks connected?
     if(plist[WHITE][ROOK][0] > i && i == 1 &&
         FILE(plist[WHITE][ROOK][i+1])==file) {
      score += ROOK_CONN_OPEN;
     }
    } else if(pawns->half_open_files_w&bitmask[file]) {
     score += ROOK_HALF_OPEN_FILE;
     // Are the rooks connected?
     if(plist[WHITE][ROOK][0] > i && i == 1 &&
         FILE(plist[WHITE][ROOK][i+1])==file) {
      score += ROOK_CONN_HALF_OPEN; 
     }
    }
    /*+++++++++++++++++++++++++++++++
    |
    | Rooks boxed in by the king
    |
    +++++++++++++++++++++++++++++++++*/
    if(pawns->pstage < 10 && rank < 2 && !RANK(wksq) 
        &&((file > 4 && FILE(wksq) > 4 && FILE(wksq) < file)
           || (file < 3 && FILE(wksq) < 3 && FILE(wksq) > file))) 
     score -= BOXED_IN_ROOK;
   }

   for(i=1;i<=plist[BLACK][ROOK][0];i++) {
    sqr = plist[BLACK][ROOK][i]; 
    if(pawns->pstage < 12) { 	
      score -= ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][ROOK][sqr]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][ROOK][sqr])/4;
    } else {
      score -= piece_sq[3][ROOK][sqr];
    }
    rank = RANK(sqr); file = FILE(sqr);
    score -= (ROOK_MOBILITY*rook_mobility(sqr))/16;
    /*+++++++++++++++++++++++++++++++
    |
    | Rooks on open and half-open files
    |
    +++++++++++++++++++++++++++++++++*/
    if(pawns->open_files&bitmask[file]) {
     score -= ROOK_OPEN_FILE;
     // Are the rooks connected?
     if(plist[BLACK][ROOK][0] > i && i == 1 &&
         FILE(plist[BLACK][ROOK][i+1])==file) {
      score -= ROOK_CONN_OPEN;
     }
    } else if(pawns->half_open_files_b&bitmask[file]) {
     score -= ROOK_HALF_OPEN_FILE;
     // Are the rooks connected?
     if(plist[BLACK][ROOK][0] > i && i == 1 &&
         FILE(plist[BLACK][ROOK][i+1])==file) {
      score -= ROOK_CONN_HALF_OPEN;
     }
    }
    /*+++++++++++++++++++++++++++++++
    |
    | Rooks boxed in by the king
    |
    +++++++++++++++++++++++++++++++++*/
    if(pawns->pstage < 10 && rank > 5 && RANK(bksq) == 7 
        &&((file > 4 && FILE(bksq) > 4 && FILE(bksq) < file)
           || (file < 3 && FILE(bksq) < 3 && FILE(bksq) > file))) 
     score += BOXED_IN_ROOK;
   }

/*+++++++++++++++++++++++++++++++
|
| Evaluate Queens
|
+++++++++++++++++++++++++++++++++*/
   for(i=1;i<=plist[WHITE][QUEEN][0];i++) {
    sqr = plist[WHITE][QUEEN][i]; 
    if(pawns->pstage < 12) { 	
      score += ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][QUEEN][whitef[sqr]]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][QUEEN][whitef[sqr]])/4;
    } else {
      score += piece_sq[3][QUEEN][whitef[sqr]];
    }
    score += (QUEEN_MOBILITY*(bishop_mobility(sqr)+rook_mobility(sqr)))/16;
   }
   for(i=1;i<=plist[BLACK][QUEEN][0];i++) { 
    sqr = plist[BLACK][QUEEN][i];
    if(pawns->pstage < 12) { 	
      score -= ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][QUEEN][sqr]
		+(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][QUEEN][sqr])/4;
    } else {
      score -= piece_sq[3][QUEEN][sqr];
    }
    score -= (QUEEN_MOBILITY*(bishop_mobility(sqr)+rook_mobility(sqr)))/16;
   }

   if(pieces[WHITE] < 3 && !plist[WHITE][PAWN][0] && !plist[WHITE][QUEEN][0]
      && !plist[WHITE][ROOK][0]) score = MIN(score,0);
   if(pieces[BLACK] < 3 && !plist[BLACK][PAWN][0] && !plist[BLACK][QUEEN][0]
      && !plist[BLACK][ROOK][0]) score = MAX(score,0);  

   /*    
   if(score > 9999 || score < -9999) { 
     cout << "Anomolous Score2!" << score <<"\n";  cout.flush();
     logfile << "Anomolous Score2!" << score <<"\n";  logfile.flush();
   }
   */


  /* make a knowledge adjustment to weaken play */
  if(gr->knowledge_scale < 100) {
    int nscore = (gr->knowledge_scale*score)/100;
    if(pcode&1) nscore -= int(float(score)*(100.0-float(gr->knowledge_scale))/100.0);
    else nscore += int(float(score)*(100.0-float(gr->knowledge_scale))/100.0);
    if(pcode&2) nscore -= int(float(score)*(100.0-float(gr->knowledge_scale))/100.0);
    else nscore += int(float(score)*(100.0-float(gr->knowledge_scale))/100.0);
    if(pcode&4) nscore -= int(float(score)*(100.0-float(gr->knowledge_scale))/100.0);
    else nscore += int(float(score)*(100.0-float(gr->knowledge_scale))/100.0);
    score = nscore;
    if(score > 9999) score = 9999;
    if(score < -9999) score = -9999;
  }

   // round output of score to the nearest 4% of a PAWN
   //  -- unless we are learning, then we need the full 
   //     precision
   if(!gr->learn_scores) {
    score = (score/4);
    score = (score*4);
   }
  

   if(wtm) return(score);
   else return(-score);

}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|  Score King:  Function to Examine the King and King Safety 
|
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
//unsigned char king_file_attack_mask[8] = {3,7,14,28,56,112,224,192};
int attack_scale[16] = { 0, 1, 2, 4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 57, 60 }; 

int position::score_king(pawn_rec *pawns, game_rec *gr)
{
   register int score = 0, wattacks = 0, battacks = 0, wdefects = 0, bdefects = 0;
   register int wksq = plist[WHITE][KING][1];
   register int bksq = plist[BLACK][KING][1];

   unsigned char black_queen_rook_files = 0;
   unsigned char white_queen_rook_files = 0;

   /*+++++++++++++++++++++++++++++++
   |
   | Add values from piece-square table
   |
   +++++++++++++++++++++++++++++++++*/   
   if(pawns->pstage < 12) { 	
     score += ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][KING][whitef[wksq]]
	       +(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][KING][whitef[wksq]])/4;
     score -= ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][KING][bksq]
	       +(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][KING][bksq])/4;
   } else {
     score += piece_sq[3][KING][whitef[wksq]];
     score -= piece_sq[3][KING][bksq];
   }

   /*+++++++++++++++++++++++++++++++
   |
   | Examine King Safety
   |
   +++++++++++++++++++++++++++++++++*/   

   if(pawns->pstage < 8) {

     /*+++++++++++++++++++++++++++++++
     |
     | Examine White Castling Structure 
     |
     +++++++++++++++++++++++++++++++++*/
     if(!((FILE(wksq) > 5 && ID(sq[7]) != WROOK) || 
	  (FILE(wksq) < 4 && ID(sq[0]) != WROOK && ID(sq[1]) != WROOK))) {
       score -= CASTLED;      
       if(pawns->pstage < 6 && !(castle&3)) score -= NO_POSSIBLE_CASTLE;
     } else {
       if(FILE(wksq) >= 4) {
	 score -= (pawns->ks_defects_w*KING_SIDE_DEFECTS*pieces[BLACK])/6;
	 //wdefects += pawns->ks_defects_w;
      }
       if(FILE(wksq) < 4) {  
	 score -= (pawns->qs_defects_w*QUEEN_SIDE_DEFECTS*pieces[BLACK])/6;
	 //wdefects += pawns->qs_defects_w;
       } 
     }
     /*+++++++++++++++++++++++++++++++
     |
     | Examine Black Castling Structure 
     |
     +++++++++++++++++++++++++++++++++*/   
     if(!((FILE(bksq) > 5 && ID(sq[63]) != BROOK) || 
	  (FILE(bksq) < 4 && ID(sq[56]) != BROOK && ID(sq[57]) != BROOK))) {
       score += CASTLED;
       if(pawns->pstage < 6 && !(castle&12)) score += NO_POSSIBLE_CASTLE;
     }  else {
       if(FILE(bksq) >= 4) {
	 score += (pawns->ks_defects_b*KING_SIDE_DEFECTS*pieces[WHITE])/6;
	 //bdefects += pawns->ks_defects_b;
       }
       if(FILE(bksq) < 4) {  
	 score += (pawns->qs_defects_b*QUEEN_SIDE_DEFECTS*pieces[WHITE])/6;
	 //bdefects += pawns->qs_defects_b;
       } 
     }

   }
   
   

    /*+++++++++++++++++++++++++++++++
    |
    | Attacks Near King
    |
    +++++++++++++++++++++++++++++++++*/

#define KING_SAFETY_STAGE 6
   
   if(pawns->pstage < KING_SAFETY_STAGE+4) {

     // simple form of king tropism scoring

     register int i,j, white_tropism = 0, black_tropism = 0, attack_score = 0;
     for(j=KNIGHT; j <= QUEEN; j++) {
       for(i=1; i<=plist[BLACK][j][0];i++) {
	 if(taxi_cab[plist[BLACK][j][i]][wksq] < 4) { 
	   white_tropism++;
	   if(j == QUEEN) white_tropism++;
	 }
	 if(taxi_cab[plist[BLACK][j][i]][bksq] < 3) black_tropism--;
       }
       for(i=1; i<=plist[WHITE][j][0];i++) {
	 if(taxi_cab[plist[WHITE][j][i]][bksq] < 4) { 
	   black_tropism++;
	   if(j == QUEEN) black_tropism++;
	 }
	 if(taxi_cab[plist[WHITE][j][i]][wksq] < 3) white_tropism--;
       }
     }


     if(white_tropism > 1 && plist[BLACK][QUEEN][0]) { // && taxi_cab[plist[BLACK][QUEEN][1]][wksq] < 4) {
       
       if(RANK(wksq)) {
	 wattacks += attacks(wksq-8,BLACK,0);
	 if(FILE(wksq)) 
	   wattacks += attacks(wksq-9,BLACK,0);
	 if(FILE(wksq)< 7)
	   wattacks += attacks(wksq-7,BLACK,0);
       }
       if(RANK(wksq) < 7) {
	 wattacks += attacks(wksq+8,BLACK,0);
	 if(FILE(wksq)) 
	   wattacks += attacks(wksq+7,BLACK,0);
	 if(FILE(wksq) < 7) 
	   wattacks += attacks(wksq+9,BLACK,0);
       }
       if(FILE(wksq) < 7) 
	 wattacks += attacks(wksq+1,BLACK,0);
       if(FILE(wksq))  
	 wattacks += attacks(wksq-1,BLACK,0);

     } else white_tropism = MAX(0, white_tropism);
   
     if(black_tropism > 1 && plist[WHITE][QUEEN][0]) { // && taxi_cab[plist[WHITE][QUEEN][1]][bksq] < 4) {
       
       if(RANK(bksq)) {
	 battacks += attacks(bksq-8,WHITE,0);
	 if(FILE(bksq)) 
	   battacks += attacks(bksq-9,WHITE,0);
	 if(FILE(bksq)< 7)
	   battacks += attacks(bksq-7,WHITE,0);
       }
       if(RANK(bksq) < 7) {
	 battacks += attacks(bksq+8,WHITE,0);
	 if(FILE(bksq)) 
	   battacks += attacks(bksq+7,WHITE,0);
	 if(FILE(bksq) < 7) 
	   battacks += attacks(bksq+9,WHITE,0);
       }
       if(FILE(bksq) < 7) 
	 battacks += attacks(bksq+1,WHITE,0);
       if(FILE(bksq))  
	 battacks += attacks(bksq-1,WHITE,0);
       
     } else black_tropism = MAX(0, black_tropism);

    //
    // asymmetric king safety attack term (testing)
    // 
    //if(gr->p_side) wattacks *= 2;
    //else battacks *= 2;
     wattacks = MIN((wattacks+white_tropism),15);
     battacks = MIN((battacks+black_tropism),15);
     
     // attack score from white point of view
     attack_score = (-attack_scale[wattacks]+attack_scale[battacks])*KING_ATTACKS;

     // scaling if we are near the stage of the game where we no longer account for this   
     if(pawns->pstage < KING_SAFETY_STAGE) score += attack_score;
     else if(pawns->pstage < KING_SAFETY_STAGE+4) {
       score += ((attack_score*(KING_SAFETY_STAGE+4 - pawns->pstage))/4);
    }

   }


   return score;

}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|  Score Pawns:  Function to Examine Pawn structure 
|                and hash the results. 
|
|
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#define wpawn  plist[WHITE][PAWN]
#define bpawn  plist[BLACK][PAWN]

int position::score_pawns(pawn_rec *pawns)
{
   register int score = 0, i, j;
   register int wpawn_count = plist[WHITE][PAWN][0];
   register int bpawn_count = plist[BLACK][PAWN][0];
   register int psq, psq2, file, rank;
   register int weak, isle, passed, last_passed;

/*+++++++++++++++++++++++++++++++
|
| Setting the pawn hash parameters
|
+++++++++++++++++++++++++++++++++*/
   pawns->wposts = 0;
   pawns->bposts = 0;
   pawns->ks_defects_w = 0;
   pawns->qs_defects_w = 0;
   pawns->ks_defects_b = 0;
   pawns->qs_defects_b = 0;
   pawns->open_files = 255;
   pawns->half_open_files_w = 255;
   pawns->half_open_files_b = 255;
   pawns->passed_w = 0;
   pawns->passed_b = 0;
   pawns->pstage = 16;

   // compute the pawn stage  12=endgame, 0=start of game
   //  -- for accessing piece square tables these are divided by 4
   //    which corresponds roughly to old idea of the game stage
   for(i=1; i<=wpawn_count;i++) {
     if(RANK(wpawn[i]) <= 3 && pawns->pstage > 0) pawns->pstage--;
   }
   for(i=1; i<=bpawn_count;i++) {
     if(RANK(bpawn[i]) >= 4 && pawns->pstage > 0) pawns->pstage--;
   }
   if(pawns->pstage > 12) pawns->pstage = 12;

/*+++++++++++++++++++++++++++++++
|
| First Loop Through White Pawns
|
+++++++++++++++++++++++++++++++++*/
    last_passed = 0;
    for(i = 1; i <= wpawn_count; i++) {
      /*+++++++++++++++++++++++++++++++
      |
      | Setting up variables and flags
      | -General strategy with the flags
      |  is to assume that a pawn is weak,
      |  on an island, or passed until
      |  proven otherwise.
      |
      +++++++++++++++++++++++++++++++++*/
      psq = wpawn[i];
      file = FILE(psq); rank = RANK(psq);
      isle = 1; passed = 1; weak = 1;     
      /*+++++++++++++++++++++++++++++++
      |
      | Add value from piece-square table
      |  -- interpolate values
      |
      +++++++++++++++++++++++++++++++++*/
      if(pawns->pstage < 12) { 	
	score += ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][PAWN][whitef[psq]]
		   +(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][PAWN][whitef[psq]])/4;
      } else {
	score += piece_sq[3][PAWN][whitef[psq]];
      }
      /*+++++++++++++++++++++++++++++++
      |
      | This file is not open.
      |  - It is also not half-open for white
      |
      +++++++++++++++++++++++++++++++++*/
      if(pawns->open_files&bitmask[file])
        pawns->open_files ^= bitmask[file];
      if(pawns->half_open_files_w&bitmask[file])
        pawns->half_open_files_w ^= bitmask[file];
      /*+++++++++++++++++++++++++++++++
      |
      | Look for an immediate neighbor 
      | If one exists, add a bonus for
      | a pawn duo.
      |
      +++++++++++++++++++++++++++++++++*/
      if(file < 7 && ID(sq[psq+1]) == WPAWN) score += PAWN_DUO;
      /*+++++++++++++++++++++++++++++++
      |
      | Look at my own pawns to see if we 
      | are doubled or have an island
      | also look for weak pawns 
      |
      +++++++++++++++++++++++++++++++++*/
      for(j = 1; j <= wpawn_count; j++) {
       psq2 = wpawn[j];
       if(j > i) {
        if(FILE(psq2) == file) { 
         score -= DOUBLED_PAWN; 
         if(file < 4) pawns->qs_defects_w++;
         else pawns->ks_defects_w++;
        }
       }
       if(j != i) {
         if(RANK(psq2) <= rank && (FILE(psq2) == file-1 || FILE(psq2) == file+1)) {
	   weak = 0;
	 }
         if(isle && (FILE(psq2) == file+1 || FILE(psq2) == file-1)) isle = 0;
       }
      }
      /*+++++++++++++++++++++++++++++++
      |
      | If the pawn is weak, score it
      | and see if it is backward. 
      |  - Note: I need to think about
      |          doubled pawn case.
      |  - Note: Open files are automatically
      |           half open - take care with
      |           this in scoring them
      |
      +++++++++++++++++++++++++++++++++*/
      if(weak) {
       score -= WEAK_PAWN;
       if(file < 4) pawns->qs_defects_w++;
       else pawns->ks_defects_w++;
       if((rank < 6 && file && ID(sq[psq+15]) == BPAWN) || 
          (rank < 6 && file < 7 && ID(sq[psq+17]) == BPAWN)
           || ID(sq[psq+8]) == BPAWN) {
          score -= BACKWARD_PAWN;
          if(file < 4) pawns->qs_defects_w++;
          else pawns->ks_defects_w++;
       }
      } else {   // not half open for black
	if(pawns->half_open_files_b&bitmask[file])
	  pawns->half_open_files_b ^= bitmask[file];
      }
      /*+++++++++++++++++++++++++++++++
      |
      | If the pawn is isolated, score it
      |
      +++++++++++++++++++++++++++++++++*/
      if(isle) {
        score -= PAWN_ISLAND;
        if(file < 4) pawns->qs_defects_w++;
        else pawns->ks_defects_w++;
      }
      /*+++++++++++++++++++++++++++++++
      |
      | Look at enemy pawns to see if 
      | this pawn is passed.
      |
      +++++++++++++++++++++++++++++++++*/
      for(j = 1; j <= bpawn_count; j++) {
       if(RANK(bpawn[j]) > rank && (FILE(bpawn[j]) == file ||
           FILE(bpawn[j]) == file-1 || FILE(bpawn[j]) == file+1))
         { passed = 0; break; }
      }
      /*+++++++++++++++++++++++++++++++
      |
      | If the pawn is passed, score it
      | and look for connected passers.
      | Add the file of this pawn to 
      | the passed pawn list.
      |
      +++++++++++++++++++++++++++++++++*/
      if(passed) {
        score += PASSED_PAWN*(rank-1)*pawns->pstage/4;
        pawns->passed_w |= bitmask[file];
        // is it protected? - if so, score as if stage = 3
        if(pawns->pstage < 12) {
         if((file < 7 && ID(sq[psq-7]) == WPAWN) ||
            (file && ID(sq[psq-9]) == WPAWN))
           score += PASSED_PAWN*(rank-1)*(12-pawns->pstage)/4; 
        } 
        // detect connected passers
        if(pawns->pstage > 6) {
          if(rank > 4) {
           if(last_passed) {
             if((file && (bitmask[file-1]&last_passed)) ||
                (file < 7 && (bitmask[file+1]&last_passed)))
               score += CON_PASSED_PAWNS*(pawns->pstage - 6)/4;
           }
           last_passed |= bitmask[file];
          }
        }
      }
    }

/*+++++++++++++++++++++++++++++++
|
| Loop Through Black Pawns
|
+++++++++++++++++++++++++++++++++*/
    last_passed = 0;
    for(i = 1; i <= bpawn_count; i++) {
      /*+++++++++++++++++++++++++++++++
      |
      | Setting up variables and flags
      | -General strategy with the flags
      |  is to assume that a pawn is weak,
      |  on an island, or passed until
      |  proven otherwise.
      |
      +++++++++++++++++++++++++++++++++*/
      psq = bpawn[i];
      file = FILE(psq); rank = RANK(psq);
      isle = 1; passed = 1; weak = 1;     
      /*+++++++++++++++++++++++++++++++
      |
      | Add value from piece-square table, interpolate between stages
      |
      +++++++++++++++++++++++++++++++++*/
      if(pawns->pstage < 12) { 	
	score -= ((4-(pawns->pstage&3))*piece_sq[(pawns->pstage/4)][PAWN][psq]
		   +(pawns->pstage&3)*piece_sq[(pawns->pstage/4)+1][PAWN][psq])/4;
      } else {
	score -= piece_sq[3][PAWN][psq];
      }
      /*+++++++++++++++++++++++++++++++
      |
      | This file is not open
      |  - It is also not half open for black
      |
      +++++++++++++++++++++++++++++++++*/
      if(pawns->open_files&bitmask[file])
       pawns->open_files ^= bitmask[file];
      if(pawns->half_open_files_b&bitmask[file])
        pawns->half_open_files_b ^= bitmask[file];
      /*+++++++++++++++++++++++++++++++
      |
      | Look for an immediate neighbor 
      | If one exists, add a bonus for
      | a pawn duo.
      |
      +++++++++++++++++++++++++++++++++*/
      if(file < 7 && ID(sq[psq+1]) == BPAWN) score -= PAWN_DUO;
      /*+++++++++++++++++++++++++++++++
      |
      | Look at my own pawns to see if we 
      | are doubled or have an island
      | also look for weak pawns 
      |
      +++++++++++++++++++++++++++++++++*/
      for(j = 1; j <= bpawn_count; j++) {
       psq2 = bpawn[j];
       if(j > i) {
        if(FILE(psq2) == file) { 
         score += DOUBLED_PAWN; 
         if(file < 4) pawns->qs_defects_b++;
         else pawns->ks_defects_b++;
        }
       }
       if(j != i) {
         if(RANK(psq2) >= rank && (FILE(psq2) == file-1 || FILE(psq2) == file+1)) {
	   weak = 0;
	 }
         if(isle && (FILE(psq2) == file+1 || FILE(psq2) == file-1)) 
               isle = 0;
       }
      }
      /*+++++++++++++++++++++++++++++++
      |
      | If the pawn is weak, score it
      | and see if it is backward. 
      |  - Note: Think about doubled
      |          pawn case.
      |
      +++++++++++++++++++++++++++++++++*/
      if(weak) {
       score += WEAK_PAWN;
       if(file < 4) pawns->qs_defects_b++;
       else pawns->ks_defects_b++;
       if((rank > 1 && file < 7 && ID(sq[psq-15]) == WPAWN) || 
          (rank > 1 && file && ID(sq[psq-17]) == WPAWN)
           || ID(sq[psq-8]) == WPAWN) {
          score += BACKWARD_PAWN;
          if(file < 4) pawns->qs_defects_b++;
          else pawns->ks_defects_b++;
       }
      } else {  // not half open for white
	if(pawns->half_open_files_w&bitmask[file])
	  pawns->half_open_files_w ^= bitmask[file];
      }
      /*+++++++++++++++++++++++++++++++
      |
      | If the pawn is isolated, score it
      |
      +++++++++++++++++++++++++++++++++*/
      if(isle) {
        score += PAWN_ISLAND;
        if(file < 4) pawns->qs_defects_b++;
        else pawns->ks_defects_b++;
      }
      /*+++++++++++++++++++++++++++++++
      |
      | Look at enemy pawns to see if 
      | this pawn is passed.
      |
      +++++++++++++++++++++++++++++++++*/
      for(j = 1; j <= wpawn_count; j++) {
       if(RANK(wpawn[j]) < rank && (FILE(wpawn[j]) == file ||
           FILE(wpawn[j]) == file-1 || FILE(wpawn[j]) == file+1))
         { passed = 0; break; }
      }
      /*+++++++++++++++++++++++++++++++
      |
      | If the pawn is passed, score it
      | and look for connected passers.
      | Add the file of this pawn to 
      | the passed pawn list.
      |
      +++++++++++++++++++++++++++++++++*/
      if(passed) {
        score -= PASSED_PAWN*(6-rank)*pawns->pstage/4;
        pawns->passed_b |= bitmask[file];
        // is it protected? - if so, score as if stage = 3
        if(pawns->pstage < 12) {
         if((file < 7 && ID(sq[psq+9]) == BPAWN) ||
            (file && ID(sq[psq+7]) == BPAWN))
           score -= PASSED_PAWN*(6-rank)*(12-pawns->pstage)/4; 
        } 
        // detect connected passers
        if(pawns->pstage > 6) {
          if(rank < 3) {
           if(last_passed) {
             if((file && (bitmask[file-1]&last_passed)) ||
                (file < 7 && (bitmask[file+1]&last_passed)))
               score -= CON_PASSED_PAWNS*(pawns->pstage - 6)/4;
           }
           last_passed |= bitmask[file];
          }
        }
      }
    }

    // Set possible outpost squares for white

    for(i = 0; i < 8; i++) {
     if(sq[white_outpost[i]].type == PAWN) continue;
     file = FILE(white_outpost[i]);
     if((file && ID(sq[white_outpost[i]-9]) == WPAWN) ||
        (file < 7 && ID(sq[white_outpost[i]-7]) == WPAWN)) {
      passed = 1;
      for(j = 1; j <= bpawn_count; j++) {
         if(RANK(bpawn[j]) > RANK(white_outpost[i]) &&
            (FILE(bpawn[j]) == file-1 || FILE(bpawn[j]) == file+1))
           { passed = 0; break; }
      }
      if(passed) pawns->wposts |= bitmask[i];
     }
    }

    // Set possible outpost squares for black

    for(i = 0; i < 8; i++) {
     if(sq[black_outpost[i]].type == PAWN) continue;
     file = FILE(black_outpost[i]);
     if((file && ID(sq[black_outpost[i]+7]) == BPAWN) ||
        (file < 7 && ID(sq[black_outpost[i]+9]) == BPAWN)) {
      passed = 1;
      for(j = 1; j <= wpawn_count; j++) {
         if(RANK(wpawn[j]) < RANK(black_outpost[i]) &&
            (FILE(wpawn[j]) == file-1 || FILE(wpawn[j]) == file+1))
           { passed = 0; break; }
      }
      if(passed) pawns->bposts |= bitmask[i];
     }
    }

   if(pawns->pstage < 8) {
     /*+++++++++++++++++++++++++++++++
     |
     | Examine White Castling Structure 
     |
     +++++++++++++++++++++++++++++++++*/
      // King Side
       if(ID(sq[13]) != WPAWN) { 
         pawns->ks_defects_w++; // F_PAWN
         if(ID(sq[21]) != WPAWN) {
	   pawns->ks_defects_w++;
         }
       } 
       if(ID(sq[14]) != WPAWN) { 
         pawns->ks_defects_w++; //_G_PAWN;
         if(ID(sq[22]) != WPAWN) {
	   pawns->ks_defects_w++; //_G_PAWN
         }
       } 
       if(ID(sq[15]) != WPAWN) { 
         pawns->ks_defects_w++; //_H_PAWN;
         if(ID(sq[23]) != WPAWN) {
	   pawns->ks_defects_w++; //_H_PAWN
         }
       } 
      // Queen Side  
       if(ID(sq[8]) != WPAWN) { 
         pawns->qs_defects_w++; //_A_PAWN;
         if(ID(sq[16]) != WPAWN) {
	   pawns->qs_defects_w++; //_A_PAWN
         }
       } 
       if(ID(sq[10]) != WPAWN) { 
         pawns->qs_defects_w++; //_C_PAWN;
         if(ID(sq[18]) != WPAWN) {
	   pawns->qs_defects_w++; //_C_PAWN
         }
       } 
       if(ID(sq[9]) != WPAWN) { 
         pawns->qs_defects_w++; //_B_PAWN;
         if(ID(sq[17]) != WPAWN) {
	   pawns->qs_defects_w++; //_B_PAWN
         }
       }       
     /*+++++++++++++++++++++++++++++++
     |
     | Examine Black Castling Structure 
     |
     +++++++++++++++++++++++++++++++++*/   
      // King Side 
       if(ID(sq[53]) != BPAWN) { 
         pawns->ks_defects_b++; //_F_PAWN;
         if(ID(sq[45]) != BPAWN) {
	   pawns->ks_defects_b++; //_F_PAWN
         }
       } 
       if(ID(sq[54]) != BPAWN) { 
         pawns->ks_defects_b++; //_G_PAWN;
         if(ID(sq[46]) != BPAWN) {
	   pawns->ks_defects_b++; //_G_PAWN
         }
       } 
       if(ID(sq[55]) != BPAWN) { 
         pawns->ks_defects_b++; //_H_PAWN;
         if(ID(sq[47]) != BPAWN) {
	   pawns->ks_defects_b++; //_H_PAWN
         }
       } 
      // Queen Side 
       if(ID(sq[48]) != BPAWN) { 
         pawns->qs_defects_b++; //_A_PAWN;
         if(ID(sq[40]) != BPAWN) {
	   pawns->qs_defects_b++; //_A_PAWN
         }
       } 
       if(ID(sq[50]) != BPAWN) { 
         pawns->qs_defects_b++; //_C_PAWN;
         if(ID(sq[42]) != BPAWN) {
	   pawns->qs_defects_b++; //_C_PAWN
         }
       } 
       if(ID(sq[49]) != BPAWN) { 
         pawns->qs_defects_b++; //_B_PAWN;
         if(ID(sq[41]) != BPAWN) {
	   pawns->qs_defects_b++; //_B_PAWN
         }
       } 
      
   }

   pawns->score = score;

   return score;

}

#undef wpawn
#undef bpawn

//-------------------------------------------
//
// Inline function to check a square is 
// guarded by a pawn.  returns 1 if true
//
//--------------------------------------------
inline int position::pawn_guard(int tsq, int side) {
  int file = FILE(tsq);
  if((!side && ((file && ID(sq[tsq+7]) == BPAWN) 
		|| (file < 7 && ID(sq[tsq+9]) == BPAWN))) 
     || 
     (side  && ((file && ID(sq[tsq-9]) == WPAWN) 
		|| (file < 7 && ID(sq[tsq-7]) == WPAWN))))
    return 1;
  else return 0;
}

// define a mobility array to transform the result to
// a smaller value appropriate for scoring.  Transformation
// is roughly 16 * sqrt(index) - 40
int mobility_transform[16] = { -40, -24, -17, -12, -8, -4, -1, 2, 5, 8, 11, 13, 15, 18, 20, 22 };

/*------------------------------- Bishop Mobility --------------------------*/
int position::bishop_mobility(int sqr)
{
  int mm, nn, ii, self, tsq, count = 0;

  mm = FILE(sqr); nn = RANK(sqr);
  self = sq[sqr].side;

  ii = 1;
  while (mm + ii <= 7 && nn + ii <= 7)
  {
   tsq = SQR((mm+ii),(nn+ii));
   if(sq[tsq].type != PAWN) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     if(sq[tsq].type && sq[tsq].side != self) break; 
   } else if(sq[tsq].side != self) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     break; 
   } else break;
   ii++;
  }

  ii = 1;
  while (mm - ii >= 0 && nn + ii <= 7)
  {
   tsq = SQR((mm-ii),(nn+ii));
   if(sq[tsq].type != PAWN) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     if(sq[tsq].type && sq[tsq].side != self) break; 
   } else if(sq[tsq].side != self) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     break; 
   } else break;
   ii++;
  }

  ii = 1;
  while(mm + ii <= 7 && nn - ii >= 0)
  {
   tsq = SQR((mm+ii),(nn-ii));
   if(sq[tsq].type != PAWN) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     if(sq[tsq].type && sq[tsq].side != self) break; 
   } else if(sq[tsq].side != self) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     break; 
   } else break;
   ii++;
  }

  ii = 1;
  while (mm - ii >= 0 && nn - ii >= 0)
  {
   tsq = SQR((mm-ii),(nn-ii));
   if(sq[tsq].type != PAWN) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     if(sq[tsq].type && sq[tsq].side != self) break; 
   } else if(sq[tsq].side != self) { 
     if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
     break; 
   } else break;
   ii++;
  }

  return mobility_transform[count];
  //return count;
}

/*------------------------------- Rook Mobility --------------------------*/
int position::rook_mobility(int sqr)
{
  int self, tsq, count = 0;

  self = sq[sqr].side;

  if(sqr+8 <= 63) 
    for(tsq = sqr+8; tsq <= 63; tsq += 8) {
      if(sq[tsq].type != PAWN) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	if(sq[tsq].type && sq[tsq].side != self) break; 
      } else if(sq[tsq].side != self) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	break; 
      } else break;
    }

  if(sqr-8 >= 0) 
    for(tsq = sqr-8; tsq >= 0; tsq -= 8) {
      if(sq[tsq].type != PAWN) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	if(sq[tsq].type && sq[tsq].side != self) break; 
	break;
      } else if(sq[tsq].side != self) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	break; 
      } else break;
    }

  if(FILE(sqr) < 7) 
    for(tsq = sqr+1; FILE(tsq) <= 7 && tsq <= 63 && FILE(tsq) > 0; tsq += 1) {
      if(sq[tsq].type != PAWN) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	if(sq[tsq].type && sq[tsq].side != self) break; 
      } else if(sq[tsq].side != self) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	break; 
      } else break;
    }

  if(FILE(sqr) > 0) 
    for(tsq = sqr-1; FILE(tsq) >= 0 && tsq >= 0 && FILE(tsq) < 7; tsq -= 1) {
      if(sq[tsq].type != PAWN) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	if(sq[tsq].type && sq[tsq].side != self) break; 
      } else if(sq[tsq].side != self) { 
	if(tsq > 55 || tsq < 8 || !pawn_guard(tsq,self)) count++; 
	break; 
      } else break;
    }

  //if(count > 15) cout << "count > 15!!" << sqr << " " << count << "\n";
  return mobility_transform[count];
  //return count;
}

/*------------------------------- Knight Mobility --------------------------*/
int position::knight_mobility(int sqr)
{
  int self, count = 0;
  int rank=RANK(sqr), file=FILE(sqr);

  self = sq[sqr].side;

  if(file < 6 && rank < 7) 
    if(!pawn_guard(sqr+10,self)) count++;

  if(file < 6 && rank) 
    if(!pawn_guard(sqr-6,self)) count++;

  if(file > 1 && rank < 7) 
    if(!pawn_guard(sqr+6,self)) count++;

  if(file > 1 && rank) 
    if(!pawn_guard(sqr-10,self)) count++;

  if(rank < 6 && file < 7) 
    if(!pawn_guard(sqr+17,self)) count++;

  if(rank < 6 && file) 
    if(!pawn_guard(sqr+15,self)) count++;

  if(rank > 1 && file < 7) 
    if(!pawn_guard(sqr-15,self)) count++;

  if(rank > 1 && file) 
    if(!pawn_guard(sqr-17,self)) count++;

  return mobility_transform[count];
  //return count;
}
