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

/*--------------------- setup.cpp ------------------------*/
//
//  This file contains setup routines for EXchess.  These
//  routines are run when EXchess first starts up.
//

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

#include "define.h"
#include "chess.h"
#include "const.h"
#include "funct.h"
#include "hash.h"
#include "extern.h"

/* Simple tables for quick in_check? tests */
int check_table[64][64];
int rook_check_table[64][64];
int bishop_check_table[64][64];
int knight_check_table[64][64];
int slide_check_table[64][64];

/* flag for logging */
int logging = 0;

/* taxi-cab distance between squares */
int taxi_cab[64][64];

char SCORES_FILE[100] = "score.par";

/*-------- Set search and scoring parameters ------------*/
//
// This function sets certain search and scoring parameters.
// It is part of the initialization startup of EXchess.
//
//

void set_search_param()
{

 char dummy[50], line[200], parameter_file[100];
 int HASH;

 // look for the search parameter file in the
 // executable directory and in the current directory

 strcpy(parameter_file, exec_path);
 strcat(parameter_file, "search.par");

 ifstream parfile(parameter_file, IOS_IN_TEXT);
 if(!parfile) parfile.open("search.par", IOS_IN_TEXT);
 if(!parfile) { cout << "Error(NoParFile)"; return; }

 // Read through search parameter file, setting
 // values as appropriate.

 while(!parfile.eof()) {
  parfile >> dummy;
  if(dummy[0] == '#') {
    parfile.getline(line, 199);
    continue;
  }

  if(!strcmp(dummy, "CHECK_EXTENSION")) {
    parfile >> CHECK_EXT;
  } else if(!strcmp(dummy, "ONE_REPLY_TO_CHECK")) {
    parfile >> ONE_REPLY_TO_CHECK;
  } else if(!strcmp(dummy, "PAWN_PUSH_EXTENSION")) {
    parfile >> PAWN_EXT;
  } else if(!strcmp(dummy, "RECAPTURE_EXTENSION")) {
    parfile >> RE_CAPT_EXT;
  } else if(!strcmp(dummy, "SINGULAR_EXTENSION")) {
    parfile >> SINGULAR_EXT;
  } else if(!strcmp(dummy, "MATE_EXTENSION")) {
    parfile >> MATE_EXT;
  } else if(!strcmp(dummy, "INITIAL_EXTENSION")) {
    parfile >> INIT_EXT;
#if TABLEBASES     
  } else if(!strcmp(dummy, "EGTB_PATH")) {
    parfile >> EGTB_PATH;
  } else if(!strcmp(dummy, "EGTB_CACHE_SIZE")) {
    parfile >> CACHE_SIZE;
#endif
  } else if(!strcmp(dummy, "LOG")) {
    parfile >> logging;
  } else if(!strcmp(dummy, "GAMBIT_SCORE")) {
    parfile >> GAMBIT_SCORE;
  } else if(!strcmp(dummy, "MAX_LOGS")) {
    parfile >> MAX_LOGS;
  } else if(!strcmp(dummy, "BOOK_FILE")) {
    parfile >> BOOK_FILE;
  } else if(!strcmp(dummy, "SCORES_FILE")) {
    parfile >> SCORES_FILE;
  } else if(!strcmp(dummy, "START_BOOK")) {
    parfile >> START_BOOK;
  } else if(!strcmp(dummy, "TD_ALPHA")) {
    parfile >> TD_ALPHA;
  } else if(!strcmp(dummy, "TD_LAMBDA")) {
    parfile >> TD_LAMBDA;
  } else if(!strcmp(dummy, "HASH")) {
    parfile >> HASH; set_hash_size(ABS(HASH));
  } else if(!strcmp(dummy, "BOOK_LEARNING")) {
    parfile >> BOOK_LEARNING;
  } else if(!strcmp(dummy, "SCORE_LEARNING")) {
    parfile >> SCORE_LEARNING;
  } else if(!strcmp(dummy, "XBOARD")) {
    parfile >> xboard; 
  } else if(!strcmp(dummy, "CHESS_SKILL")) {
    parfile >> CHESS_SKILL; 
  } else if(!strcmp(dummy, "EARLY_EXIT")) {
    parfile >> EARLY_EXIT; 
  } else parfile.getline(line, 199);

 }


}

/* Function to generate check tables */
//
//  Simply sets a "1" if a given FROM-TO attack
//  combination is at all possible.  Sets a "0" if
//  such a combination is not possible.
//
//  These tables help to quickly rule out certain
//  kinds of attacks which could generate a check.
//
//  Function also generates the 'taxi-cab' distance
//  table used in the scoring functions

void gen_check_table()
{

  int i, j;
  for(i = 0; i < 64; i++) {
   for(j = 0; j < 64; j++) {
     // setup the taxi-cab distance table
     taxi_cab[i][j] = MAX((ABS(FILE(i)-FILE(j))),(ABS(RANK(i)-RANK(j))));
     if(FILE(i)==FILE(j) || RANK(i)==RANK(j)) {
      rook_check_table[i][j] = 1;
      slide_check_table[i][j] = 1;
      check_table[i][j] = 1;
     } else { 
      rook_check_table[i][j] = 0;
      slide_check_table[i][j] = 0;
      check_table[i][j] = 0;
     }
     bishop_check_table[i][j] = 0;
     knight_check_table[i][j] = 0;
   }
  }

  for(i = 0; i < 64; i++) {
    j = i; while(RANK(j) && FILE(j) && j >= 0)
	     { j -= 9; bishop_check_table[i][j] = 1; slide_check_table[i][j] = 1; check_table[i][j] = 1; }
    j = i; while(RANK(j) && FILE(j) < 7 && j >= 0)
	     { j -= 7; bishop_check_table[i][j] = 1; slide_check_table[i][j] = 1; check_table[i][j] = 1; }
    j = i; while(RANK(j) < 7 && FILE(j) && j <= 63)
	     { j += 7; bishop_check_table[i][j] = 1; slide_check_table[i][j] = 1; check_table[i][j] = 1; }
    j = i; while(RANK(j) < 7 && FILE(j) < 7 && j <= 63)
	     { j += 9; bishop_check_table[i][j] = 1; slide_check_table[i][j] = 1; check_table[i][j] = 1; }
    if(FILE(i) < 6 && RANK(i) < 7) { knight_check_table[i][i+10] = 1; }
    if(FILE(i) < 6 && RANK(i)) { knight_check_table[i][i-6] = 1; }
    if(FILE(i) > 1 && RANK(i) < 7) { knight_check_table[i][i+6] = 1; }
    if(FILE(i) > 1 && RANK(i)) { knight_check_table[i][i-10] = 1; }
    if(FILE(i) < 7 && RANK(i) < 6) { knight_check_table[i][i+17] = 1; }
    if(FILE(i) && RANK(i) < 6) { knight_check_table[i][i+15] = 1; }
    if(FILE(i) < 7 && RANK(i) > 1) { knight_check_table[i][i-15] = 1; }
    if(FILE(i) && RANK(i) > 1) { knight_check_table[i][i-17] = 1; }
  }

}

/* function to fill in learning scores array if
   no score.par file is present */

void fill_pars()
{

 int m, n, pp;

 // set values of scoring parameters

 scores[0] = 10*value[PAWN];
 scores[1] = 10*value[KING];
 scores[2] = 10*value[KNIGHT];
 scores[3] = 10*value[BISHOP];
 scores[4] = 10*value[ROOK];
 scores[5] = 10*value[QUEEN];
 scores[6] = 10*DOUBLED_PAWN;
 scores[7] = 10*WEAK_PAWN;
 scores[8] = 10*BACKWARD_PAWN;
 scores[9] = 10*PAWN_ISLAND;
 scores[10] = 10*PASSED_PAWN;
 scores[11] = 10*BISHOP_PAIR;
 scores[12] = 10*ROOK_CONN_OPEN;
 scores[13] = 10*ROOK_CONN_HALF_OPEN;
 scores[14] = 10*CON_PASSED_PAWNS;
 scores[15] = 10*OUTSIDE_PASSED_PAWN;
 scores[16] = 10*FREE_PASSED_PAWN;
 scores[17] = 10*CASTLED;
 scores[18] = 10*NO_POSSIBLE_CASTLE;
 scores[19] = 10*ROOK_MOBILITY;
 scores[20] = 10*QUEEN_MOBILITY;
 scores[21] = 10*KNIGHT_MOBILITY;
 scores[22] = 10*PAWN_DUO;
 scores[23] = 10*BOXED_IN_ROOK;
 scores[24] = 10*KNIGHT_OUTPOST;
 scores[25] = 10*BISHOP_OUTPOST;
 scores[26] = 10*KING_SIDE_DEFECTS;
 scores[27] = 10*QUEEN_SIDE_DEFECTS;
 scores[28] = 10*ROOK_OPEN_FILE;
 scores[29] = 10*ROOK_HALF_OPEN_FILE;
 scores[30] = 10*KING_ATTACKS;
 scores[31] = 10*outpost_score[0];
 scores[32] = 10*outpost_score[1];
 scores[33] = 10*outpost_score[2];
 scores[34] = 10*outpost_score[3];
 scores[35] = 10*outpost_score[4];
 scores[36] = 10*outpost_score[5];
 scores[37] = 10*outpost_score[6];
 scores[38] = 10*outpost_score[7];
 scores[39] = 10*SIDE_ON_MOVE;
 scores[40] = 10*BISHOP_MOBILITY;

 lscores[0] = 0;
 for(m = 1; m < 41; m++) lscores[m] = 1;

 // 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++) {
      scores[41+64*(4*pp+m)+n] = 10*piece_sq[m][pp+1][n];
      lscores[41+64*(4*pp+m)+n] = 1;
     } 
   }
 }

}

/* function to set a single score value */

void set_score_value(char dummy[50], int value) 
{

   if(!strcmp(dummy, "PAWN_VALUE")) {
     scores[0] = value;
   } else if(!strcmp(dummy, "KING_VALUE")) {
     scores[1] = value;
   } else if(!strcmp(dummy, "KNIGHT_VALUE")) {
     scores[2] = value;
   } else if(!strcmp(dummy, "BISHOP_VALUE")) {
     scores[3] = value;
   } else if(!strcmp(dummy, "ROOK_VALUE")) {
     scores[4] = value;
   } else if(!strcmp(dummy, "QUEEN_VALUE")) {
     scores[5] = value;
   } else if(!strcmp(dummy, "DOUBLED_PAWN")) {
     scores[6] = value;
   } else if(!strcmp(dummy, "WEAK_PAWN")) {
     scores[7] = value;
   } else if(!strcmp(dummy, "BACKWARD_PAWN")) {
     scores[8] = value;
   } else if(!strcmp(dummy, "PAWN_ISLAND")) {
     scores[9] = value;
   } else if(!strcmp(dummy, "PASSED_PAWN")) {
     scores[10] = value;
   } else if(!strcmp(dummy, "BISHOP_PAIR")) {
     scores[11] = value;
   } else if(!strcmp(dummy, "ROOK_CONN_OPEN")) {
     scores[12] = value;
   } else if(!strcmp(dummy, "ROOK_CONN_HALF_OPEN")) {
     scores[13] = value;
   } else if(!strcmp(dummy, "CON_PASSED_PAWNS")) {
     scores[14] = value;
   } else if(!strcmp(dummy, "OUTSIDE_PASSED_PAWN")) {
     scores[15] = value;
   } else if(!strcmp(dummy, "FREE_PASSED_PAWN")) {
     scores[16] = value;
   } else if(!strcmp(dummy, "CASTLED")) {
     scores[17] = value;
   } else if(!strcmp(dummy, "NO_POSSIBLE_CASTLE")) {
     scores[18] = value;
   } else if(!strcmp(dummy, "ROOK_MOBILITY")) {
     scores[19] = value;
   } else if(!strcmp(dummy, "QUEEN_MOBILITY")) {
     scores[20] = value;
   } else if(!strcmp(dummy, "KNIGHT_MOBILITY")) {
     scores[21] = value;
   } else if(!strcmp(dummy, "PAWN_DUO")) {
     scores[22] = value;
   } else if(!strcmp(dummy, "BOXED_IN_ROOK")) {
     scores[23] = value;
   } else if(!strcmp(dummy, "KNIGHT_OUTPOST")) {
     scores[24] = value;
   } else if(!strcmp(dummy, "BISHOP_OUTPOST")) {
     scores[25] = value;
   } else if(!strcmp(dummy, "KING_SIDE_DEFECTS")) {
     scores[26] = value;
   } else if(!strcmp(dummy, "QUEEN_SIDE_DEFECTS")) {
     scores[27] = value;
   } else if(!strcmp(dummy, "ROOK_OPEN_FILE")) {
     scores[28] = value;
   } else if(!strcmp(dummy, "ROOK_HALF_OPEN_FILE")) {
     scores[29] = value;
   } else if(!strcmp(dummy, "KING_ATTACKS")) {
     scores[30] = value;
   } else if(!strcmp(dummy, "OUTPOST_0")) {
     scores[31] = value;
   } else if(!strcmp(dummy, "OUTPOST_1")) {
     scores[32] = value;
   } else if(!strcmp(dummy, "OUTPOST_2")) {
     scores[33] = value;
   } else if(!strcmp(dummy, "OUTPOST_3")) {
     scores[34] = value;
   } else if(!strcmp(dummy, "OUTPOST_4")) {
     scores[35] = value;
   } else if(!strcmp(dummy, "OUTPOST_5")) {
     scores[36] = value;
   } else if(!strcmp(dummy, "OUTPOST_6")) {
     scores[37] = value;
   } else if(!strcmp(dummy, "OUTPOST_7")) {
     scores[38] = value;
   } else if(!strcmp(dummy, "SIDE_ON_MOVE")) {
     scores[39] = value;
   } else if(!strcmp(dummy, "BISHOP_MOBILITY")) {
     scores[40] = value;
   } else { 
     cout << "Score label " << dummy << " is not found!\n"; 
     cout.flush();
   }

   //--------------------------------------------------
   // set the values actually used in scoring position
   //--------------------------------------------------
   set_scores(scores);

}

/* function to read scores from the scoring file */

void read_scores()
{
  int m, p, n; float version = 0.0;
  char dummy[50], line[200], parameter_file[100];
  char in1[50], in2[50], in3[50];

  // fill in pre-programmed parameters before
  // looking in the scores file
  fill_pars();

  // look for the score file in the
  // executable directory and in the current directory

  strcpy(parameter_file, exec_path);
  strcat(parameter_file, SCORES_FILE);

  ifstream parfile(parameter_file, IOS_IN_TEXT);
  if(!parfile) parfile.open(SCORES_FILE, IOS_IN_TEXT);
  if(!parfile) { 
    cout << "Error(No SCORES_FILE file, using defaults and creating a new one)\n"; 
    cout.flush();
    write_scores();
    return;
  } else { 
    // Read through search parameter file, setting
    // values as appropriate.
    while(!parfile.eof()) {
      parfile >> dummy;
      if(dummy[0] == '#') {
	parfile.getline(line, 199);
	continue;
      }
    
      if(!strcmp(dummy, "VERSION")) {
	parfile >> version;
      } else if(!strcmp(dummy, "PAWN_VALUE")) {
	parfile >> scores[0] >> lscores[0];
      } else if(!strcmp(dummy, "KING_VALUE")) {
	parfile >> scores[1] >> lscores[1];
      } else if(!strcmp(dummy, "KNIGHT_VALUE")) {
	parfile >> scores[2] >> lscores[2];
      } else if(!strcmp(dummy, "BISHOP_VALUE")) {
	parfile >> scores[3] >> lscores[3];
      } else if(!strcmp(dummy, "ROOK_VALUE")) {
	parfile >> scores[4] >> lscores[4];
      } else if(!strcmp(dummy, "QUEEN_VALUE")) {
	parfile >> scores[5] >> lscores[5];
      } else if(!strcmp(dummy, "DOUBLED_PAWN")) {
	parfile >> scores[6] >> lscores[6]; 
      } else if(!strcmp(dummy, "WEAK_PAWN")) {
	parfile >> scores[7] >> lscores[7];
      } else if(!strcmp(dummy, "BACKWARD_PAWN")) {
	parfile >> scores[8] >> lscores[8];
      } else if(!strcmp(dummy, "PAWN_ISLAND")) {
	parfile >> scores[9] >> lscores[9];
      } else if(!strcmp(dummy, "PASSED_PAWN")) {
	parfile >> scores[10] >> lscores[10];
      } else if(!strcmp(dummy, "BISHOP_PAIR")) {
	parfile >> scores[11] >> lscores[11];
      } else if(!strcmp(dummy, "ROOK_CONN_OPEN")) {
	parfile >> scores[12] >> lscores[12];
      } else if(!strcmp(dummy, "ROOK_CONN_HALF_OPEN")) {
	parfile >> scores[13] >> lscores[13];
      } else if(!strcmp(dummy, "CON_PASSED_PAWNS")) {
	parfile >> scores[14] >> lscores[14];
      } else if(!strcmp(dummy, "OUTSIDE_PASSED_PAWN")) {
	parfile >> scores[15] >> lscores[15];
      } else if(!strcmp(dummy, "FREE_PASSED_PAWN")) {
	parfile >> scores[16] >> lscores[16];
      } else if(!strcmp(dummy, "CASTLED")) {
	parfile >> scores[17] >> lscores[17];
      } else if(!strcmp(dummy, "NO_POSSIBLE_CASTLE")) {
	parfile >> scores[18] >> lscores[18];
      } else if(!strcmp(dummy, "ROOK_MOBILITY")) {
	parfile >> scores[19] >> lscores[19];
      } else if(!strcmp(dummy, "QUEEN_MOBILITY")) {
	parfile >> scores[20] >> lscores[20];
      } else if(!strcmp(dummy, "KNIGHT_MOBILITY")) {
	parfile >> scores[21] >> lscores[21];
      } else if(!strcmp(dummy, "PAWN_DUO")) {
	parfile >> scores[22] >> lscores[22];
      } else if(!strcmp(dummy, "BOXED_IN_ROOK")) {
	parfile >> scores[23] >> lscores[23];
      } else if(!strcmp(dummy, "KNIGHT_OUTPOST")) {
	parfile >> scores[24] >> lscores[24];
      } else if(!strcmp(dummy, "BISHOP_OUTPOST")) {
	parfile >> scores[25] >> lscores[25];
      } else if(!strcmp(dummy, "KING_SIDE_DEFECTS")) {
	parfile >> scores[26] >> lscores[26];
      } else if(!strcmp(dummy, "QUEEN_SIDE_DEFECTS")) {
	parfile >> scores[27] >> lscores[27];
      } else if(!strcmp(dummy, "ROOK_OPEN_FILE")) {
	parfile >> scores[28] >> lscores[28];
      } else if(!strcmp(dummy, "ROOK_HALF_OPEN_FILE")) {
	parfile >> scores[29] >> lscores[29];
      } else if(!strcmp(dummy, "KING_ATTACKS")) {
	parfile >> scores[30] >> lscores[30];
      } else if(!strcmp(dummy, "OUTPOST_0")) {
	parfile >> scores[31] >> lscores[31];
      } else if(!strcmp(dummy, "OUTPOST_1")) {
	parfile >> scores[32] >> lscores[32];
      } else if(!strcmp(dummy, "OUTPOST_2")) {
	parfile >> scores[33] >> lscores[33];
      } else if(!strcmp(dummy, "OUTPOST_3")) {
	parfile >> scores[34] >> lscores[34];
      } else if(!strcmp(dummy, "OUTPOST_4")) {
	parfile >> scores[35] >> lscores[35];
      } else if(!strcmp(dummy, "OUTPOST_5")) {
	parfile >> scores[36] >> lscores[36]; 
      } else if(!strcmp(dummy, "OUTPOST_6")) {
	parfile >> scores[37] >> lscores[37];
      } else if(!strcmp(dummy, "OUTPOST_7")) {
	parfile >> scores[38] >> lscores[38];
      } else if(!strcmp(dummy, "SIDE_ON_MOVE")) {
	parfile >> scores[39] >> lscores[39];
      } else if(!strcmp(dummy, "BISHOP_MOBILITY")) {
	parfile >> scores[40] >> lscores[40];
      } else if(!strcmp(dummy, "PIECE_TABLES")) {
	parfile >> lscores[41];
	// loop over piece first: pawn - king (0-5)
	for(p = 0; p < 6; p++) {
	  // loop over stage next
	  for(m = 0; m < 4; m++) {
	    parfile >> in1 >> in2 >> in3;    // comment
	    // loop over square last
	    for(n = 0; n < 64; n++) {
	      parfile >> scores[41+64*(4*p+m)+n];
	      lscores[41+64*(4*p+m)+n] = lscores[41];   
	    } 
	  }      
	}
      } 

    }  /* end while loop */
  }   /* end of 'else' part of above if statement */

  if(version != SCORE_PAR_VERSION) {
    cout << "Error(Wrong version of SCORES_FILE, using defaults; delete file and restart to have new version created)\n";
    cout.flush();
    fill_pars();
  } else {
    //-----------------------------------------------------
    // set the variables actually used in scoring position
    //-----------------------------------------------------
    set_scores(scores);
  }

}

/* Function to write learned scores to the scoring file */

void write_scores()
{
 int p, m, n;
 char parameter_file[100];

 // look for the score file in the
 // executable directory and in the current directory

 strcpy(parameter_file, exec_path);
 strcat(parameter_file, SCORES_FILE);

 ofstream parfile(parameter_file);
 if(!parfile) parfile.open(SCORES_FILE);
 if(!parfile) { cout << "Error(NoScoreFile)"; return; }

 // writing explain information on learning
 parfile << "# Scoring parameters file, for use with TD learning \n";
 parfile << "#\n";
 parfile << "# Scores are given in 1/1000 of a pawn.  The second number\n"
         << "# is either a 1 or 0.  1 = learn this parameter. 0 = don't learn.\n"
         << "# For the program to work properly, PAWN_VALUE must stay 1000\n"
         << "# Updates are roughly 10 points each, so learning piece values\n"
         << "# from zero will take a very long time\n"
         << "#\n"
         << "# If this file is deleted, a new one will be created with the defaults\n"
         << "#\n"
         << "# See search.par for a global variable to turn learning on/off\n\n";

 // print a version number to use in indentifying this version of score.par
 parfile << "VERSION " << SCORE_PAR_VERSION << "\n";

 // write the scoring parameter file
 parfile << "PAWN_VALUE " << scores[0] << " " << lscores[0];
 parfile << "\nKING_VALUE " << scores[1] << " " << lscores[1];
 parfile << "\nKNIGHT_VALUE " << scores[2] << " " << lscores[2];
 parfile << "\nBISHOP_VALUE " << scores[3] << " " << lscores[3];
 parfile << "\nROOK_VALUE " << scores[4] << " " << lscores[4];
 parfile << "\nQUEEN_VALUE " << scores[5] << " " << lscores[5];
 parfile << "\nDOUBLED_PAWN " << scores[6] << " " << lscores[6];
 parfile << "\nWEAK_PAWN " << scores[7] << " " << lscores[7];
 parfile << "\nBACKWARD_PAWN " << scores[8] << " " << lscores[8];
 parfile << "\nPAWN_ISLAND " << scores[9] << " " << lscores[9];
 parfile << "\nPASSED_PAWN " << scores[10] << " " << lscores[10];
 parfile << "\nBISHOP_PAIR " << scores[11] << " " << lscores[11];
 parfile << "\nROOK_CONN_OPEN " << scores[12] << " " << lscores[12];
 parfile << "\nROOK_CONN_HALF_OPEN " << scores[13] << " " << lscores[13];
 parfile << "\nCON_PASSED_PAWNS " << scores[14] << " " << lscores[14];
 parfile << "\nOUTSIDE_PASSED_PAWN " << scores[15] << " " << lscores[15];
 parfile << "\nFREE_PASSED_PAWN " << scores[16] << " " << lscores[16];
 parfile << "\nCASTLED " << scores[17] << " " << lscores[17];
 parfile << "\nNO_POSSIBLE_CASTLE " << scores[18] << " " << lscores[18];
 parfile << "\nROOK_MOBILITY " << scores[19] << " " << lscores[19];
 parfile << "\nQUEEN_MOBILITY " << scores[20] << " " << lscores[20];
 parfile << "\nKNIGHT_MOBILITY " << scores[21] << " " << lscores[21];
 parfile << "\nPAWN_DUO " << scores[22] << " " << lscores[22];
 parfile << "\nBOXED_IN_ROOK " << scores[23] << " " << lscores[23];
 parfile << "\nKNIGHT_OUTPOST " << scores[24] << " " << lscores[24];
 parfile << "\nBISHOP_OUTPOST " << scores[25] << " " << lscores[25];
 parfile << "\nKING_SIDE_DEFECTS " << scores[26] << " " << lscores[26];
 parfile << "\nQUEEN_SIDE_DEFECTS " << scores[27] << " " << lscores[27];
 parfile << "\nROOK_OPEN_FILE " << scores[28] << " " << lscores[28];
 parfile << "\nROOK_HALF_OPEN_FILE " << scores[29] << " " << lscores[29];
 parfile << "\nKING_ATTACKS " << scores[30] << " " << lscores[30];
 parfile << "\nOUTPOST_0 " << scores[31] << " " << lscores[31];
 parfile << "\nOUTPOST_1 " << scores[32] << " " << lscores[32];
 parfile << "\nOUTPOST_2 " << scores[33] << " " << lscores[33];
 parfile << "\nOUTPOST_3 " << scores[34] << " " << lscores[34];
 parfile << "\nOUTPOST_4 " << scores[35] << " " << lscores[35];
 parfile << "\nOUTPOST_5 " << scores[36] << " " << lscores[36];
 parfile << "\nOUTPOST_6 " << scores[37] << " " << lscores[37];
 parfile << "\nOUTPOST_7 " << scores[38] << " " << lscores[38];
 parfile << "\nSIDE_ON_MOVE " << scores[39] << " " << lscores[39];
 parfile << "\nBISHOP_MOBILITY " << scores[40] << " " << lscores[40];
 parfile << "\nPIECE_TABLES " << lscores[41];
 // loop over piece first: pawn - king (0-5)
 for(p = 0; p < 6; p++) {
   // loop over stage next
   for(m = 0; m < 4; m++) {
     parfile << "\n#PIECE_TAB: " << pstring[p+1] << " STAGE_" << m << "\n";   // put comment
     // loop over square distance last
     for(n = 0; n < 64; n++) {
       parfile << setw(4) << scores[41+64*(4*p+m)+n] << " ";
       if(((n+1)%8) == 0) parfile << "\n"; 
     } 
   }      
 }
 

}

