/* set up the evaluation tables */

#include "globals.h"
#include "ppeval.h"

/* #define T_DEBUG		/* used for degugging the table fit code */
#define OLD_PAWN		/* use original pawn eval stuff */
#define OLD_PPA			/* use original Pawn advance stuff */
#define FIT_MODE		/* enables fit-interface */

#include "ev_fit.h"

#include "eval.h"

#define EDEBUG 0	/* check if incremental update of tables
			is working : ie if no update was scheduled, update
			anyway and print out any changes to table entries */

#define FALSE 0
#define TRUE -1

#define min(x,y) ((x) < (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))

#define WHITE 0
#define BLACK 1

/*
 * possible choices of king shelter
 */
#define NEITHER 0
#define KINGSIDE 1
#define QUEENSIDE 2
#define EITHER 3

#define fileof(x) ((x) & 07)
#define rankof(x) ((x) >> 3)
#define dark(sq) ((sq & 01) == ((sq >> 3) & 01))
#define light(sq) ((sq & 01) != ((sq >> 3) & 01))

#define A1 0
#define B1 1
#define C1 2
#define D1 3
#define E1 4
#define F1 5
#define G1 6
#define H1 7

#define A2 8
#define B2 9
#define C2 10
#define D2 11
#define E2 12
#define F2 13
#define G2 14
#define H2 15

#define A3 16
#define B3 17
#define C3 18
#define D3 19
#define E3 20
#define F3 21
#define G3 22
#define H3 23

#define A4 24
#define B4 25
#define C4 26
#define D4 27
#define E4 28
#define F4 29
#define G4 30
#define H4 31

#define A5 32
#define B5 33
#define C5 34
#define D5 35
#define E5 36
#define F5 37
#define G5 38
#define H5 39

#define A6 40
#define B6 41
#define C6 42
#define D6 43
#define E6 44
#define F6 45
#define G6 46
#define H6 47

#define A7 48
#define B7 49
#define C7 50
#define D7 51
#define E7 52
#define F7 53
#define G7 54
#define H7 55

#define A8 56
#define B8 57
#define C8 58
#define D8 59
#define E8 60
#define F8 61
#define G8 62
#define H8 63

#define MAXMATERIAL 62
#define MAXMATERIALSQ (MAXMATERIAL * MAXMATERIAL)
#define MAXPCOUNT 16
#define MAXWPCOUNT 8
#define MAXBPCOUNT 8
#define MAXCENTRALITY 3
#define MAXADVANCEMENT 5

/*
 * Note: the ..._A and ..._B versions seperate numerator and denominator 
 *       for use with the fit interface (scale macro)
 */
#define fmat(x) ((x * material) / MAXMATERIAL)
#define fmat_A  material
#define fmat_B  MAXMATERIAL

#define fmatsq(x) ((x * materialsq) / MAXMATERIALSQ)
#define fmatsq_A materialsq
#define fmatsq_B MAXMATERIALSQ

#define fpc(x) ((x * pcount) / MAXPCOUNT)
#define fpc_A  pcount
#define fpc_B  MAXPCOUNT

#define fwpc(x) ((x * wpcount) / MAXWPCOUNT)
#define fwpc_A  wpcount
#define fwpc_B  MAXWPCOUNT

#define fbpc(x) ((x * bpcount) / MAXBPCOUNT)
#define fbpc_A  bpcount
#define fbpc_B  MAXBPCOUNT

#define fmca(x) ((x * material * pcentrality * padvancement) / (MAXMATERIAL * MAXCENTRALITY * MAXADVANCEMENT))
#define fmca_A  (material * pcentrality * padvancement)
#define fmca_B  (MAXMATERIAL * MAXCENTRALITY * MAXADVANCEMENT)

#define fmc(x) ((x * material * pcentrality) / (MAXMATERIAL * MAXCENTRALITY))
#define fmc_A  (material * pcentrality)
#define fmc_B  (MAXMATERIAL * MAXCENTRALITY)

#define fma(x) ((x * material * padvancement) / (MAXMATERIAL * MAXADVANCEMENT))
#define fma_A  (material * padvancement)
#define fma_B  (MAXMATERIAL * MAXADVANCEMENT)

#define fca(x) ((x * pcentrality * padvancement) / (MAXCENTRALITY * MAXADVANCEMENT))
#define fca_A  (pcentrality * padvancement)
#define fca_B  (MAXCENTRALITY * MAXADVANCEMENT)

#define fcent(x) ((x * pcentrality) / MAXCENTRALITY)
#define fcent_A  (pcentrality)
#define fcent_B  (MAXCENTRALITY)

#define fadv(x) ((x * padvancement) / MAXADVANCEMENT)
#define fadv_A  (padvancement)
#define fadv_B  (MAXADVANCEMENT)

#define maxblocked (20)

/*
 * pieceplacement - macro was moved to ev_fit.h
 */
static int *Lsq = sq;

#define LIGHT 1
#define DARK 2
#define NOBISHOPS 0
#define LIGHTBISHOP 1
#define DARKBISHOP 2
#define TWOBISHOPS 3

#define PCPLACESIZE (1 << 10)

#define PAWNTABLESIZE (1 << 13)

#define PPTABLESIZE (1 << 13)

#define ROOKTABLESIZE (1 << 11)

/*
 * The fixed gradients
 */
int centergradient[] = {
    0, 1, 2, 3, 3, 2, 1, 0,
    1, 3, 4, 5, 5, 4, 3, 1,
    2, 4, 6, 7, 7, 6, 4, 2,
    3, 5, 7, 9, 9, 7, 5, 3,
    3, 5, 7, 9, 9, 7, 5, 3,
    2, 4, 6, 7, 7, 6, 4, 2,
    1, 3, 4, 5, 5, 4, 3, 1,
    0, 1, 2, 3, 3, 2, 1, 0,
};
int bishopgradient[] = {
    3, 2, 1, 0, 0, 1, 2, 3,
    2, 4, 5, 5, 5, 5, 4, 2,
    1, 5, 8, 10, 10, 8, 5, 1,
    0, 5, 10, 11, 11, 10, 5, 0,
    0, 5, 10, 11, 11, 10, 5, 0,
    1, 5, 8, 10, 10, 8, 5, 1,
    2, 4, 5, 5, 5, 5, 4, 2,
    3, 2, 1, 0, 0, 1, 2, 3,
};

int ppadvgradient[] = {
    1, 2, 4, 8, 20, 40
};

int ppcentgradient[] = {
    1, 2, 3, 4, 4, 3, 2, 1
};

/*
 * The effect of blocked pawns on bishops is greater on central files
 */
int blockdebit[] = {
    1, 2, 3, 4, 4, 3, 2, 1
};

extern int loadmask;

int firsttime = TRUE;

eval() 
{
    /*
     * This routine builds the evaluation function for Deep Thought. This is
     * done by filling in the values in the PiecePlacement table, the pawn
     * structure tables, and the open file table. There are a large number of
     * parameters for this evaluation function, given in eval.h. Many of the
     * values depend on the current material on the board. This is on the
     * scale Q=9,R=5,BN=3,P=1. Thus the maximum value for material as found
     * the starting position is 2 * (9 + 10 + 12 + 8) = 78. 
     *
     * In order to allow the evaluation function parameters to be integers, it
     * is necessary to normalize the values.  See the f macros. 
     */
    register int i;

    extern int sunboard[];
    int     sq;

    int     material,
            wpcount,
            bpcount,
            wkfile,
            bkfile,
            wksq,
            bksq,
            wkshelter,
            bkshelter,
            wminorstatus,
            bminorstatus,
	    wlightblocked,
	    wdarkblocked,
	    blightblocked,
	    bdarkblocked;

    static int oldmaterial,
            oldwpcount,
            oldbpcount,
            oldwkfile,
            oldbkfile,
            oldwksq,
            oldbksq,
            oldwkshelter,
            oldbkshelter,
            oldwminorstatus,
            oldbminorstatus,
	    oldwlightblocked,
	    oldwdarkblocked,
	    oldblightblocked,
	    oldbdarkblocked;
     static int oldsunboard[64];

    /*
     * Scan the board to generate values for the parameters.  If they have
     * changed from the last time the particular functions were called, that
     * component must be recalculated. 
     */
#ifndef FIT_MODE
    loadmask = 0x10000000;
#endif
    material = 0;
    wpcount = bpcount = 0;
    wlightblocked = wdarkblocked = blightblocked = bdarkblocked = 0;
    wminorstatus = bminorstatus = NOBISHOPS;

    for (sq = A1; sq <= H8; sq++) {
	switch (sunboard[sq]) {
	case EMPTY:
	    break;
	case WP:
	    if (sunboard[sq+8] == BP) {
	        if (dark(sq))
		    wdarkblocked += blockdebit[fileof(sq)];
		else
		    wlightblocked += blockdebit[fileof(sq)];
	    }
	    wpcount += 1;
	    break;
	case BP:
	    if (sunboard[sq-8] == WP) {
	        if (dark(sq))
		    bdarkblocked += blockdebit[fileof(sq)];
		else
		    blightblocked += blockdebit[fileof(sq)];
	    }
	    bpcount += 1;
	    break;
	case WN:
	    material += 3;
	    break;
	case BN:
	    material += 3;
	    break;
	case WB:
	    material += 3;
	    if (dark(sq))
		wminorstatus |= DARK;
	    else
		wminorstatus |= LIGHT;
	    break;
	case BB:
	    material += 3;
	    if (dark(sq))
		bminorstatus |= DARK;
	    else
		bminorstatus |= LIGHT;
	    break;
	case WR:
	case BR:
	    material += 5;
	    break;
	case WQ:
	case BQ:
	    material += 9;
	    break;
	case WK:
	    wksq = sq;
	    wkfile = fileof(sq);
	    break;
	case BK:
	    bksq = sq;
	    bkfile = fileof(sq);
	    break;
	}
    }

    wkshelter = getwkshelter(wksq);
    bkshelter = getbkshelter(bksq);

#ifndef FIT_MODE
    if ((material != oldmaterial) || (wksq != oldwksq) ||
	(bksq != oldbksq) || (wkshelter != oldwkshelter) ||
	(bkshelter != oldbkshelter) || firsttime ||
	sunboard[D2]!= oldsunboard[D2] || sunboard[E2] != oldsunboard[E2] ||
	sunboard[D7]!= oldsunboard[D7] || sunboard[E7] != oldsunboard[E7] ||
	wdarkblocked != oldwdarkblocked || wlightblocked != oldwlightblocked ||
	bdarkblocked != oldbdarkblocked || blightblocked != oldblightblocked) {
	pcplace(material, wpcount, bpcount, wkfile, rankof(wksq), bkfile, rankof(bksq), wkshelter, bkshelter, wdarkblocked, wlightblocked, bdarkblocked, blightblocked);
    } else if (EDEBUG) {
	int     oldPieceTable[1024];

	for (i = 1024; --i >= 0;)
	    oldPieceTable[i] = PieceTable[i];
	pcplace(material, wpcount, bpcount, wkfile, rankof(wksq), bkfile, rankof(bksq), wkshelter, bkshelter, wdarkblocked, wlightblocked, bdarkblocked, blightblocked);
	for (i = 1024; --i >= 0;)
	    if (oldPieceTable[i] != PieceTable[i]) {
		printf("pcplace() would have changed Piecetable[%d] %x->%x\n", i, oldPieceTable[i], PieceTable[i]);
		printpos(0, 0);
		printf("lastmove=%s\n", unparse(stack[movesmade + 1].move));
	    }
    }
    if ((material != oldmaterial) || (wkshelter != oldwkshelter) ||
	(bkshelter != oldbkshelter) || firsttime) {
	pawneval(material, wkshelter, bkshelter);
    } else if (EDEBUG) {
	int     oldWPTable[8192],
	        oldBPTable[8192];

	for (i = 8192; --i >= 0;) {
	    oldWPTable[i] = WPTable[i];
	    oldBPTable[i] = BPTable[i];
	}
	pawneval(material, wkshelter, bkshelter);
	for (i = 8192; --i >= 0;) {
	    if (oldWPTable[i] != WPTable[i]) {
		printf("pawneval() would have changed WPTable[%d] %x->%x\n", i, oldWPTable[i], WPTable[i]);
		printpos(0, 0);
		printf("lastmove=%s\n", unparse(stack[movesmade + 1].move));
	    }
	    if (oldBPTable[i] != BPTable[i]) {
		printf("pawneval() would have changed BPTable[%d] %x->%x\n", i, oldBPTable[i], BPTable[i]);
		printpos(0, 0);
		printf("lastmove=%s\n", unparse(stack[movesmade + 1].move));
	    }
	}
    }
    if ((material != oldmaterial) || firsttime) {
	ppeval(material);
    } else if (EDEBUG) {
	int     oldWPPTable[8192],
	        oldBPPTable[8192];

	for (i = 8192; --i >= 0;) {
	    oldWPPTable[i] = WPPTable[i];
	    oldBPPTable[i] = BPPTable[i];
	}
	ppeval(material);
	for (i = 8192; --i >= 0;) {
	    if (oldWPPTable[i] != WPPTable[i]) {
		printf("pawneval() would have changed WPPTable[%d] %x->%x\n", i, oldWPPTable[i], WPPTable[i]);
		printpos(0, 0);
		printf("lastmove=%s\n", unparse(stack[movesmade + 1].move));
	    }
	    if (oldBPPTable[i] != BPPTable[i]) {
		printf("pawneval() would have changed BPPTable[%d] %x->%x\n", i, oldBPPTable[i], BPPTable[i]);
		printpos(0, 0);
		printf("lastmove=%s\n", unparse(stack[movesmade + 1].move));
	    }
	}
    }
    if ((wpcount != oldwpcount) || (bpcount != oldbpcount) ||
	(wkfile != oldwkfile) || (bkfile != oldbkfile) ||
	(material != oldmaterial) || (wminorstatus != oldwminorstatus) ||
	(bminorstatus != oldbminorstatus) || firsttime) {
	rookeval(wpcount, bpcount, wkfile, bkfile, material, wminorstatus, bminorstatus);
    } else if (EDEBUG) {
	int     oldRookTable[2048];

	for (i = 2048; --i >= 0;)
	    oldRookTable[i] = RookTable[i];
	rookeval(wpcount, bpcount, wkfile, bkfile, material, wminorstatus, bminorstatus);
	for (i = 2048; --i >= 0;)
	    if (oldRookTable[i] != RookTable[i]) {
		printf("rookeval() would have changed RookTable[%d] %x->%x\n", i, oldRookTable[i], RookTable[i]);
		printpos(0, 0);
		printf("lastmove=%s\n", unparse(stack[movesmade + 1].move));
	    }
    }
#else
    pcplace(material, wpcount, bpcount, wkfile, rankof(wksq), bkfile, rankof(bksq), wkshelter, bkshelter, wdarkblocked, wlightblocked, bdarkblocked, blightblocked);
    pawneval(material, wkshelter, bkshelter);
    ppeval(material);
    rookeval(wpcount, bpcount, wkfile, bkfile, material, wminorstatus, bminorstatus);
#endif
    firsttime = FALSE;
    oldmaterial = material;
    oldwpcount = wpcount;
    oldbpcount = bpcount;
    oldwksq = wksq;
    oldbksq = bksq;
    oldwkfile = wkfile;
    oldbkfile = bkfile;
    oldwkshelter = wkshelter;
    oldbkshelter = bkshelter;
    oldwminorstatus = wminorstatus;
    oldbminorstatus = bminorstatus;
    oldwdarkblocked = wdarkblocked;
    oldwlightblocked = wlightblocked;
    oldbdarkblocked = bdarkblocked;
    oldblightblocked = blightblocked;
    for(i=64;--i>=0;)
	oldsunboard[i] = sunboard[i];
}
/*
 * these need work
 */
getwkshelter(wksq)
  register int wksq;
{
    register int    ktotal = 0,
		    qtotal = 0;

    if (fileof(wksq) > 4)
	return KINGSIDE;
    if (fileof(wksq) < 4)
	return QUEENSIDE;
    if (fileof(wksq) == 4) {
	/*
	 * have to evaluate the relative goodness of the pawn shelters 
	 */
	if ((sunboard[G2] == WP) || (sunboard[G3] == WP))
	    ktotal += 5;
	if ((sunboard[H2] == WP) || (sunboard[H3] == WP))
	    ktotal += 3;
	if ((sunboard[F2] == WP) || (sunboard[F3] == WP) ||
	    (sunboard[F4] == WP))
	    ktotal += 2;
	if ((sunboard[G4] == WP) || (sunboard[H4] == WP))
	    ktotal += 1;
	if (!(stack[movesmade+2].castle_status & WSCastle))
	    ktotal -= 5;
	if ((sunboard[B2] == WP) || (sunboard[B3] == WP))
	    qtotal += 5;
	if ((sunboard[A2] == WP) || (sunboard[A3] == WP))
	    qtotal += 3;
	if ((sunboard[C2] == WP) || (sunboard[C3] == WP) ||
	    (sunboard[C4] == WP))
	    qtotal += 2;
	if ((sunboard[B4] == WP) || (sunboard[A4] == WP))
	    qtotal += 1;
	if (!(stack[movesmade+2].castle_status & WLCastle))
	    qtotal -= 5;
	if ((ktotal >= 8) && (qtotal >= 8))
	    return EITHER;
	if (ktotal >= 8)
	    return KINGSIDE;
	if (qtotal >= 8)
	    return QUEENSIDE;
	if ((ktotal >= qtotal) && (ktotal >= 4))
	    return KINGSIDE;
	if ((qtotal > ktotal) && (qtotal >= 4))
	    return QUEENSIDE;
	return NEITHER;
    }
    return NEITHER;
}
getbkshelter(bksq)
  register int bksq;
{
    register int ktotal = 0, qtotal = 0;
    if (fileof(bksq) > 4)
        return KINGSIDE;
    if (fileof(bksq) < 4)
        return QUEENSIDE;
    if (fileof(bksq) == 4) {
	if ((sunboard[G7] == BP) || (sunboard[G6] == BP))
	    ktotal += 5;
	if ((sunboard[H7] == BP) || (sunboard[H6] == BP))
	    ktotal += 3;
	if ((sunboard[F7] == BP) || (sunboard[F6] == BP) ||
	    (sunboard[F5] == BP))
	    ktotal += 2;
	if ((sunboard[G5] == BP) || (sunboard[H5] == BP))
	    ktotal += 1;
	if (!(stack[movesmade+2].castle_status & BSCastle))
	    ktotal -= 5;
	if ((sunboard[B7] == BP) || (sunboard[B6] == BP))
	    qtotal += 5;
	if ((sunboard[A7] == BP) || (sunboard[A6] == BP))
	    qtotal += 3;
	if ((sunboard[C7] == BP) || (sunboard[C6] == BP) ||
	    (sunboard[C5] == BP))
	    qtotal += 2;
	if ((sunboard[B5] == BP) || (sunboard[A5] == BP))
	    qtotal += 1;
	if (!(stack[movesmade+2].castle_status & BLCastle))
	    qtotal -= 5;
	if ((ktotal >= 8) && (qtotal >= 8))
	    return EITHER;
	if (ktotal >= 8)
	    return KINGSIDE;
	if (qtotal >= 8)
	    return QUEENSIDE;
	if ((ktotal >= qtotal) && (ktotal >= 4))
	    return KINGSIDE;
	if ((qtotal > ktotal) && (qtotal >= 4))
	    return QUEENSIDE;
	return NEITHER;
    }
    return NEITHER;
}


int bitcount[32] = {
    0, 1, 1, 2, 1, 2, 2, 3,
    1, 2, 2, 3, 2, 3, 3, 4,
    1, 2, 2, 3, 2, 3, 3, 4,
    2, 3, 3, 4, 3, 4, 4, 5
};

#define pmap(x) (x & 037)
#define padjmap(x) ((x >> 5) & 017)
#define popp(x) ((x >> 9) & 01)
#define file(x) ((x >> 10) & 07)

#define pcount(x) (bitcount[pmap(x)])
#define isolated(x) (padjmap(x) == 0)
#define backward(x) (popp(x) && back[pmap(x)][padjmap(x)])

pawneval(material,wkshelter,bkshelter)
  int material;
  int wkshelter;
  int bkshelter;
{
    /*
     * The pawn tables: used to detect multipled and isolated pawns on closed
     * or semi-open files.  There are separate tables for white and black,
     * with a 13 bit index for each. The index has several subfields: pmap
     * (pawns from 2 through 6), padjmap (ORed bitmap of adjacent pawns,
     * ranks 2 through 5), popp (1 if no black pawns), and the file number.
     * Give penalties for different combinations of these features, all
     * modulated by material. 
     */
    register int index;
    register wval, bval;

#ifndef FIT_MODE
    register int *rWPTable = WPTable;
    register int *rBPTable = BPTable;

    int     SIO = ((SingleIsoOpen1 * fmat_A) << 8) / fmat_B +
    (SingleIsoOpen0 << 8);
    int     SIC = ((SingleIsoClosed1 * fmat_A) << 8) / fmat_B +
    (SingleIsoClosed0 << 8);
    int     DIO = ((DoubleIsoOpen1 * fmat_A) << 8) / fmat_B +
    (DoubleIsoOpen0 << 8);
    int     DIC = ((DoubleIsoClosed1 * fmat_A) << 8) / fmat_B +
    (DoubleIsoClosed0 << 8);
    int     DO = ((DoubleOpen1 * fmat_A) << 8) / fmat_B +
    (DoubleOpen0 << 8);
    int     DC = ((DoubleClosed1 * fmat_A) << 8) / fmat_B +
    (DoubleClosed0 << 8);
    int     TIO = ((TripleIsoOpen1 * fmat_A) << 8) / fmat_B +
    (TripleIsoOpen0 << 8);
    int     TIC = ((TripleIsoClosed1 * fmat_A) << 8) / fmat_B +
    (TripleIsoClosed0 << 8);
    int     TOp = ((TripleOpen1 * fmat_A) << 8) / fmat_B +
    (TripleOpen0 << 8);
    int     TC = ((TripleClosed1 * fmat_A) << 8) / fmat_B +
    (TripleClosed0 << 8);
    int     Back = ((Backward1 * fmat_A) << 8) / fmat_B +
    (Backward0 << 8);
    int     NBP = ((NoBishopPawn1 * fmat_A) << 8) / fmat_B +
    (NoBishopPawn0 << 8);
    int     NKP = ((NoKnightPawn1 * fmat_A) << 8) / fmat_B +
    (NoKnightPawn0 << 8);
    int     NRP = ((NoRookPawn1 * fmat_A) << 8) / fmat_B +
    (NoRookPawn0 << 8);

    loadmask |= 0x3;

    for (index = 0; index < PAWNTABLESIZE; index++) {
	wval = bval = 0;
	switch (pcount(index)) {
	case 0:
	    break;
	case 1:
	    if (isolated(index)) {
		if (popp(index)) {
		    wval -= SIO;
		    bval += SIO;
		} else {
		    wval -= SIC;
		    bval += SIC;
		}
	    }
	    break;
	case 2:
	    if (isolated(index)) {
		if (popp(index)) {
		    wval -= DIO;
		    bval += DIO;
		} else {
		    wval -= DIC;
		    bval += DIC;
		}
	    } else {
		if (popp(index)) {
		    wval -= DO;
		    bval += DO;
		} else {
		    wval -= DC;
		    bval += DC;
		}
	    }
	    break;
	case 3:
	default:
	    if (isolated(index)) {
		if (popp(index)) {
		    wval -= TIO;
		    bval += TIO;
		} else {
		    wval -= TIC;
		    bval += TIC;
		}
	    } else {
		if (popp(index)) {
		    wval -= TOp;
		    bval += TOp;
		} else {
		    wval -= TC;
		    bval += TC;
		}
	    }
	    break;
	}
	if (backward(index)) {
	    wval -= Back;
	    bval += Back;
	}
	if ((wkshelter == KINGSIDE) || (wkshelter == EITHER)) {
	    switch (file(index)) {
	    case 5:
		if (!(pmap(index) & 07))
		    wval -= NBP;
		break;
	    case 6:
		if (!(pmap(index) & 03))
		    wval -= NKP;
		break;
	    case 7:
		if (!(pmap(index) & 03))
		    wval -= NRP;
		break;
	    default:
		break;
	    }
	}
	if ((wkshelter == QUEENSIDE) || (wkshelter == EITHER)) {
	    switch (file(index)) {
	    case 0:
		if (!(pmap(index) & 03))
		    wval -= NRP;
		break;
	    case 1:
		if (!(pmap(index) & 03))
		    wval -= NKP;
		break;
	    case 2:
		if (!(pmap(index) & 07))
		    wval -= NBP;
		break;
	    default:
		break;
	    }
	}
	if ((bkshelter == KINGSIDE) || (bkshelter == EITHER)) {
	    switch (file(index)) {
	    case 5:
		if (!(pmap(index) & 07))
		    bval += NBP;
		break;
	    case 6:
		if (!(pmap(index) & 03))
		    bval += NKP;
		break;
	    case 7:
		if (!(pmap(index) & 03))
		    bval += NRP;
		break;
	    default:
		break;
	    }
	}
	if ((bkshelter == QUEENSIDE) || (bkshelter == EITHER)) {
	    switch (file(index)) {
	    case 0:
		if (!(pmap(index) & 03))
		    bval += NRP;
		break;
	    case 1:
		if (!(pmap(index) & 03))
		    bval += NKP;
		break;
	    case 2:
		if (!(pmap(index) & 07))
		    bval += NBP;
		break;
	    default:
		break;
	    }
	}
	rWPTable[index] = unscale(wval);
	rBPTable[index] = unscale(bval);
    }
#else
    scan_wpawn_tab(index) {
	switch (pcount(index)) {
	case 0:
	    break;
	case 1:
	    if (isolated(index)) {
		if (popp(index)) {
		    addto_WPT(index, scale(SingleIsoOpen1, fmat_A, -fmat_B) PLUS scale(SingleIsoOpen0, 1, -1));
		} else {
		    addto_WPT(index, scale(SingleIsoClosed1, fmat_A, -fmat_B) PLUS scale(SingleIsoClosed0, 1, -1));
		}
	    }
	    break;
	case 2:
	    if (isolated(index)) {
		if (popp(index)) {
		    addto_WPT(index, scale(DoubleIsoOpen1, fmat_A, -fmat_B) PLUS scale(DoubleIsoOpen0, 1, -1));
		} else {
		    addto_WPT(index, scale(DoubleIsoClosed1, fmat_A, -fmat_B) PLUS scale(DoubleIsoClosed0, 1, -1));
		}
	    } else {
		if (popp(index)) {
		    addto_WPT(index, scale(DoubleOpen1, fmat_A, -fmat_B) PLUS scale(DoubleOpen0, 1, -1));
		} else {
		    addto_WPT(index, scale(DoubleClosed1, fmat_A, -fmat_B) PLUS scale(DoubleClosed0, 1, -1));
		}
	    }
	    break;
	case 3:
	default:
	    if (isolated(index)) {
		if (popp(index)) {
		    addto_WPT(index, scale(TripleIsoOpen1, fmat_A, -fmat_B) PLUS scale(TripleIsoOpen0, 1, -1));
		} else {
		    addto_WPT(index, scale(TripleIsoClosed1, fmat_A, -fmat_B) PLUS scale(TripleIsoClosed0, 1, -1));
		}
	    } else {
		if (popp(index)) {
		    addto_WPT(index, scale(TripleOpen1, fmat_A, -fmat_B) PLUS scale(TripleOpen0, 1, -1));
		} else {
		    addto_WPT(index, scale(TripleClosed1, fmat_A, -fmat_B) PLUS scale(TripleClosed0, 1, -1));
		}
	    }
	    break;
	}
	if (backward(index)) {
	    addto_WPT(index, scale(Backward1, fmat_A, -fmat_B) PLUS scale(Backward0, 1, -1));
	}
	if ((wkshelter == KINGSIDE) || (wkshelter == EITHER)) {
	    switch (file(index)) {
	    case 5:
		if (!(pmap(index) & 07))
		    addto_WPT(index, scale(NoBishopPawn1, fmat_A, -fmat_B) PLUS scale(NoBishopPawn0, 1, -1));
		break;
	    case 6:
		if (!(pmap(index) & 03))
		    addto_WPT(index, scale(NoKnightPawn1, fmat_A, -fmat_B) PLUS scale(NoKnightPawn0, 1, -1));
		break;
	    case 7:
		if (!(pmap(index) & 03))
		    addto_WPT(index, scale(NoRookPawn1, fmat_A, -fmat_B) PLUS scale(NoRookPawn0, 1, -1));
		break;
	    default:
		break;
	    }
	}
	if ((wkshelter == QUEENSIDE) || (wkshelter == EITHER)) {
	    switch (file(index)) {
	    case 0:
		if (!(pmap(index) & 03))
		    addto_WPT(index, scale(NoRookPawn1, fmat_A, -fmat_B) PLUS scale(NoRookPawn0, 1, -1));
		break;
	    case 1:
		if (!(pmap(index) & 03))
		    addto_WPT(index, scale(NoKnightPawn1, fmat_A, -fmat_B) PLUS scale(NoKnightPawn0, 1, -1));
		break;
	    case 2:
		if (!(pmap(index) & 07))
		    addto_WPT(index, scale(NoBishopPawn1, fmat_A, -fmat_B) PLUS scale(NoBishopPawn0, 1, -1));
		break;
	    default:
		break;
	    }
	}
    }

    scan_bpawn_tab(index) {
	switch (pcount(index)) {
	case 0:
	    break;
	case 1:
	    if (isolated(index)) {
		if (popp(index)) {
		    addto_BPT(index, scale(SingleIsoOpen1, fmat_A, fmat_B) PLUS scale(SingleIsoOpen0, 1, 1));
		} else {
		    addto_BPT(index, scale(SingleIsoClosed1, fmat_A, fmat_B) PLUS scale(SingleIsoClosed0, 1, 1));
		}
	    }
	    break;
	case 2:
	    if (isolated(index)) {
		if (popp(index)) {
		    addto_BPT(index, scale(DoubleIsoOpen1, fmat_A, fmat_B) PLUS scale(DoubleIsoOpen0, 1, 1));
		} else {
		    addto_BPT(index, scale(DoubleIsoClosed1, fmat_A, fmat_B) PLUS scale(DoubleIsoClosed0, 1, 1));
		}
	    } else {
		if (popp(index)) {
		    addto_BPT(index, scale(DoubleOpen1, fmat_A, fmat_B) PLUS scale(DoubleOpen0, 1, 1));
		} else {
		    addto_BPT(index, scale(DoubleClosed1, fmat_A, fmat_B) PLUS scale(DoubleClosed0, 1, 1));
		}
	    }
	    break;
	case 3:
	default:
	    if (isolated(index)) {
		if (popp(index)) {
		    addto_BPT(index, scale(TripleIsoOpen1, fmat_A, fmat_B) PLUS scale(TripleIsoOpen0, 1, 1));
		} else {
		    addto_BPT(index, scale(TripleIsoClosed1, fmat_A, fmat_B) PLUS scale(TripleIsoClosed0, 1, 1));
		}
	    } else {
		if (popp(index)) {
		    addto_BPT(index, scale(TripleOpen1, fmat_A, fmat_B) PLUS scale(TripleOpen0, 1, 1));
		} else {
		    addto_BPT(index, scale(TripleClosed1, fmat_A, fmat_B) PLUS scale(TripleClosed0, 1, 1));
		}
	    }
	    break;
	}
	if (backward(index)) {
	    addto_BPT(index, scale(Backward1, fmat_A, fmat_B) PLUS scale(Backward0, 1, 1));
	}
	if ((bkshelter == KINGSIDE) || (bkshelter == EITHER)) {
	    switch (file(index)) {
	    case 5:
		if (!(pmap(index) & 07))
		    addto_BPT(index, scale(NoBishopPawn1, fmat_A, fmat_B) PLUS scale(NoBishopPawn0, 1, 1));
		break;
	    case 6:
		if (!(pmap(index) & 03))
		    addto_BPT(index, scale(NoKnightPawn1, fmat_A, fmat_B) PLUS scale(NoKnightPawn0, 1, 1));
		break;
	    case 7:
		if (!(pmap(index) & 03))
		    addto_BPT(index, scale(NoRookPawn1, fmat_A, fmat_B) PLUS scale(NoRookPawn0, 1, 1));
		break;
	    default:
		break;
	    }
	}
	if ((bkshelter == QUEENSIDE) || (bkshelter == EITHER)) {
	    switch (file(index)) {
	    case 0:
		if (!(pmap(index) & 03))
		    addto_BPT(index, scale(NoRookPawn1, fmat_A, fmat_B) PLUS scale(NoRookPawn0, 1, 1));
		break;
	    case 1:
		if (!(pmap(index) & 03))
		    addto_BPT(index, scale(NoKnightPawn1, fmat_A, fmat_B) PLUS scale(NoKnightPawn0, 1, 1));
		break;
	    case 2:
		if (!(pmap(index) & 07))
		    addto_BPT(index, scale(NoBishopPawn1, fmat_A, fmat_B) PLUS scale(NoBishopPawn0, 1, 1));
		break;
	    default:
		break;
	    }
	}
    }
#endif
}

pcplace(material, wpcount, bpcount, wkfile, wkrank, bkfile, bkrank, wkshelter, bkshelter, wdarkblocked, wlightblocked, bdarkblocked, blightblocked)
  int material, wpcount, bpcount, wkfile, wkrank,
      bkfile, bkrank, wkshelter, bkshelter, wdarkblocked,
      wlightblocked, bdarkblocked, blightblocked;
{
    register int sq;
    register int materialsq = material * material;
    register int bonus;
#ifndef FIT_MODE
    loadmask |= 0x20;
#else
    register int i;
#endif

    /*
     * Basic piece values 
     */
    for (sq = A1; sq <= H8; sq++) {
	pieceplacement(WK, sq) = 0;
        pieceplacement(BK, sq) = 0;
	assign_pcpl_tab(WQ, sq, scale(QueenValue, 1, 1));
	assign_pcpl_tab(BQ, sq, scale(QueenValue, 1, -1));
	assign_pcpl_tab(WR, sq, scale(RookValue, 1, 1));
	assign_pcpl_tab(BR, sq, scale(RookValue, 1, -1));
	assign_pcpl_tab(WB, sq, scale(BishopValue, 1, 1));
	assign_pcpl_tab(BB, sq, scale(BishopValue, 1, -1));
	assign_pcpl_tab(WN, sq, scale(KnightValue, 1, 1));
	assign_pcpl_tab(BN, sq, scale(KnightValue, 1, -1));
    }
    for (sq = A2; sq <= H7; sq++) {
	assign_pcpl_tab(WP, sq, scale(PawnValue0, 1, 1) PLUS scale(PawnValue1, fwpc_A, fwpc_B));
	assign_pcpl_tab(BP, sq, scale(PawnValue0, 1, -1) PLUS scale(PawnValue1, fbpc_A, -fbpc_B));
    }

    /*
     * King, Queen and Knight all have a centrality bonus/penalty which is a
     * function of material on board.  Bishops have a somewhat different
     * centrality gradient. 
     */

    for (sq = A1; sq <= H8; sq++) {
	i = centergradient[sq];

	addto_pcpl_tab(WK, sq, scale(KingCentrality2, i * fmatsq_A, fmatsq_B) PLUS
			       scale(KingCentrality1, i * fmat_A, fmat_B) PLUS
		               scale(KingCentrality0, i, 1)                        );
	addto_pcpl_tab(BK, sq, scale(KingCentrality2, i * fmatsq_A, -fmatsq_B) PLUS
			       scale(KingCentrality1, i * fmat_A, -fmat_B) PLUS
		               scale(KingCentrality0, i, -1)                       );

	addto_pcpl_tab(WQ, sq, scale(QueenCentrality2, i * fmatsq_A, fmatsq_B) PLUS
			       scale(QueenCentrality1, i * fmat_A, fmat_B) PLUS
		               scale(QueenCentrality0, i, 1)                        );
	addto_pcpl_tab(BQ, sq, scale(QueenCentrality2, i * fmatsq_A, -fmatsq_B) PLUS
			       scale(QueenCentrality1, i * fmat_A, -fmat_B) PLUS
		               scale(QueenCentrality0, i, -1)                       );

	addto_pcpl_tab(WN, sq, scale(KnightCentrality2, i * fmatsq_A, fmatsq_B) PLUS
			       scale(KnightCentrality1, i * fmat_A, fmat_B) PLUS
		               scale(KnightCentrality0, i, 1)                        );
	addto_pcpl_tab(BN, sq, scale(KnightCentrality2, i * fmatsq_A, -fmatsq_B) PLUS
			       scale(KnightCentrality1, i * fmat_A, -fmat_B) PLUS
		               scale(KnightCentrality0, i, -1)                       );

	i = bishopgradient[sq];
	
	addto_pcpl_tab(WB, sq, scale(BishopPlacement2, i * fmatsq_A, fmatsq_B) PLUS
			       scale(BishopPlacement1, i * fmat_A, fmat_B) PLUS
		               scale(BishopPlacement0, i, 1)                        );
	addto_pcpl_tab(BB, sq, scale(BishopPlacement2, i * fmatsq_A, -fmatsq_B) PLUS
			       scale(BishopPlacement1, i * fmat_A, -fmat_B) PLUS
		               scale(BishopPlacement0, i, -1)                       );
    }

    /*
     * give bonus for castled king position
     */
    if ((wkshelter == KINGSIDE) || (wkshelter == EITHER)) {
	if (wkfile == 4)
	    assign_WSbonus(scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1))
	else {
	    addto_pcpl_tab(WK, G1, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, H1, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, G2, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, H2, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	}
    }
    if ((wkshelter == QUEENSIDE) || (wkshelter == EITHER)) {
	if (wkfile == 4)
	    assign_WLbonus(scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1))
	else {
	    addto_pcpl_tab(WK, A1, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, B1, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, A2, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, B2, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, C1, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	    addto_pcpl_tab(WK, C2, scale(KingShelter1, fmat_A, fmat_B) PLUS scale(KingShelter0, 1, 1));
	}
    }
    if ((bkshelter == KINGSIDE) || (bkshelter == EITHER)) {
	if (bkfile == 4)
	    assign_BSbonus(scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1))
	else {
	    addto_pcpl_tab(BK, G8, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, H8, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, G7, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, H7, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	}
    }
    if ((bkshelter == QUEENSIDE) || (bkshelter == EITHER)) {
	if (bkfile == 4)
	    assign_BLbonus(scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1))
	else {
	    addto_pcpl_tab(BK, A8, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, B8, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, A7, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, B7, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, C8, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	    addto_pcpl_tab(BK, C7, scale(KingShelter1, fmat_A, -fmat_B) PLUS scale(KingShelter0, 1, -1));
	}
    }
	
    /*
     * Penalty for bad bishops
     */
    for (sq = A1; sq <= H8; sq++) {
	if (dark(sq)) {
	    addto_pcpl_tab(WB, sq, scale(BadBishop0, wdarkblocked, maxblocked));
	    addto_pcpl_tab(BB, sq, scale(BadBishop0, bdarkblocked, -maxblocked));
	} else {
	    addto_pcpl_tab(WB, sq, scale(BadBishop0, wlightblocked, maxblocked));
	    addto_pcpl_tab(BB, sq, scale(BadBishop0, blightblocked, -maxblocked));
	}
    }
	
    /*
     * Give credit for enemy king tropism 
     */
    for (sq = A1; sq <= H8; sq++) {
	addto_pcpl_tab(WN, sq, scale(KnightTropism1, (5 - (abs(fileof(sq) - bkfile) + abs(rankof(sq) - bkrank))) * fmat_A, fmat_B) PLUS
			       scale(KnightTropism0, (5 - (abs(fileof(sq) - bkfile) + abs(rankof(sq) - bkrank))), 1));
	addto_pcpl_tab(BN, sq, scale(KnightTropism1, (5 - (abs(fileof(sq) - bkfile) + abs(rankof(sq) - wkrank))) * fmat_A, -fmat_B) PLUS
			       scale(KnightTropism0, (5 - (abs(fileof(sq) - bkfile) + abs(rankof(sq) - wkrank))), -1));

	addto_pcpl_tab(WQ, sq, scale(QueenTropism1, min(abs(fileof(sq) - bkfile), abs(rankof(sq) - bkrank)) * fmat_A, fmat_B) PLUS
			       scale(QueenTropism0, min(abs(fileof(sq) - bkfile), abs(rankof(sq) - bkrank)), 1));
	addto_pcpl_tab(BQ, sq, scale(QueenTropism1, min(abs(fileof(sq) - wkfile), abs(rankof(sq) - wkrank)) * fmat_A, -fmat_B) PLUS
			       scale(QueenTropism0, min(abs(fileof(sq) - wkfile), abs(rankof(sq) - wkrank)), -1));
    }

    /*
     * Give credit for defending minor pieces when king has left center 
     */
    if ((wkfile != 4) && (wkrank != 0)) {
	for (sq = A1; sq <= H8; sq++) {
	    addto_pcpl_tab(WN, sq, scale(KnightDefense1, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - wkrank))) * fmat_A, fmat_B) PLUS
	                           scale(KnightDefense0, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - wkrank))), 1));
	    addto_pcpl_tab(WB, sq, scale(BishopDefense1, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - wkrank))) * fmat_A, fmat_B) PLUS
	                           scale(BishopDefense0, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - wkrank))), 1));
	}
    }
    if ((bkfile != 4) && (bkrank != 7)) {
	for (sq = A1; sq <= H8; sq++) {
	    addto_pcpl_tab(BN, sq, scale(KnightDefense1, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - bkrank))) * fmat_A, -fmat_B) PLUS
	                           scale(KnightDefense0, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - bkrank))), -1));
	    addto_pcpl_tab(BB, sq, scale(BishopDefense1, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - bkrank))) * fmat_A, -fmat_B) PLUS
	                           scale(BishopDefense0, (5 - (abs(fileof(sq) - wkfile) + abs(rankof(sq) - bkrank))), -1));
	}
    }

    /*
     * Give a bonus for rooks on the 7th as a function of pawn count 
     */
    for (sq = A7; sq <= H7; sq++)
	addto_pcpl_tab(WR, sq, scale(RookOnSeventh1, fbpc_A, fbpc_B) PLUS scale(RookOnSeventh0, 1, 1));

    for (sq = A2; sq <= H2; sq++)
	addto_pcpl_tab(BR, sq, scale(RookOnSeventh1, fwpc_A, -fwpc_B) PLUS scale(RookOnSeventh0, 1, -1));


    /*
     * Give credit for advancing pawns.  Also give extra credit for central
     * pawns 
     */
    for (sq = A2; sq <= H7; sq++) {
	int pcentrality, padvancement;
	pcentrality = fileof(sq);
	if (pcentrality > MAXCENTRALITY)
	    pcentrality = 7 - pcentrality;
	padvancement = rankof(sq) - 1;
#ifdef OLD_PAWN
	addto_pcpl_tab(WP, sq, scale(PawnPlaceMCA, fmca_A, fmca_B) PLUS
			       scale(PawnPlaceMC, fmc_A, fmc_B)    PLUS 
			       scale(PawnPlaceMA, fma_A, fma_B)    PLUS
			       scale(PawnPlaceCA, fca_A, fca_B)    PLUS
	                       scale(PawnPlaceM, fmat_A, fmat_B)   PLUS
		               scale(PawnPlaceC, fcent_A, fcent_B) PLUS
                               scale(PawnPlaceA, fadv_A, fadv_B)   PLUS
	                       scale(PawnPlaceK, 1, 1)			);
#else
	addto_pcpl_tab(WP, sq, add_3tab(PawnPlace, pcentrality, padvancement, material));
#endif
    }

    for (sq = A2; sq <= H7; sq++) {
	int pcentrality, padvancement;
	pcentrality = fileof(sq);
	if (pcentrality > MAXCENTRALITY)
	    pcentrality = 7 - pcentrality;
	padvancement = 6 - rankof(sq);
#ifdef OLD_PAWN
	addto_pcpl_tab(BP, sq, scale(PawnPlaceMCA, fmca_A, -fmca_B) PLUS
			       scale(PawnPlaceMC, fmc_A, -fmc_B)    PLUS
			       scale(PawnPlaceMA, fma_A, -fma_B)    PLUS
			       scale(PawnPlaceCA, fca_A, -fca_B)    PLUS
	                       scale(PawnPlaceM, fmat_A, -fmat_B)   PLUS
			       scale(PawnPlaceC, fcent_A, -fcent_B) PLUS
			       scale(PawnPlaceA, fadv_A, -fadv_B)   PLUS
			       scale(PawnPlaceK, 1, -1)                  );
			       
#else
	addto_pcpl_tab(BP, sq, sub_3tab(PawnPlace, pcentrality, padvancement, material));
#endif
    }

    /*
     * Pawns on the 7th must be given the passed pawn bonus here, since they
     * do not get included in the passed pawn tables 
     */

#ifdef OLD_PPA
    for (sq = A7; sq <= H7; sq++)
	addto_pcpl_tab(WP, sq, scale(PPAdvance2, ppadvgradient[5] * fmatsq_A, fmatsq_B) PLUS 
			       scale(PPAdvance1, ppadvgradient[5] * fmat_A, fmat_B)     PLUS
			       scale(PPAdvance0, ppadvgradient[5], 1)                       );

    for (sq = A2; sq <= H2; sq++)
	addto_pcpl_tab(BP, sq, scale(PPAdvance2, ppadvgradient[5] * fmatsq_A, -fmatsq_B) PLUS 
			       scale(PPAdvance1, ppadvgradient[5] * fmat_A, -fmat_B)     PLUS
			       scale(PPAdvance0, ppadvgradient[5], -1)                       );
#else
    addto_pcpl_tab(WP, A7, add_3tab(PPAdvance, 0, 5, material));    /* I think this is simpler than using a loop -- agn */
    addto_pcpl_tab(WP, B7, add_3tab(PPAdvance, 1, 5, material));
    addto_pcpl_tab(WP, C7, add_3tab(PPAdvance, 2, 5, material));
    addto_pcpl_tab(WP, D7, add_3tab(PPAdvance, 3, 5, material));
    addto_pcpl_tab(WP, E7, add_3tab(PPAdvance, 3, 5, material));
    addto_pcpl_tab(WP, F7, add_3tab(PPAdvance, 2, 5, material));
    addto_pcpl_tab(WP, G7, add_3tab(PPAdvance, 1, 5, material));
    addto_pcpl_tab(WP, H7, add_3tab(PPAdvance, 0, 5, material));

    addto_pcpl_tab(BP, A2, sub_3tab(PPAdvance, 0, 5, material));
    addto_pcpl_tab(BP, B2, sub_3tab(PPAdvance, 1, 5, material));
    addto_pcpl_tab(BP, C2, sub_3tab(PPAdvance, 2, 5, material));
    addto_pcpl_tab(BP, D2, sub_3tab(PPAdvance, 3, 5, material));
    addto_pcpl_tab(BP, E2, sub_3tab(PPAdvance, 3, 5, material));
    addto_pcpl_tab(BP, F2, sub_3tab(PPAdvance, 2, 5, material));
    addto_pcpl_tab(BP, G2, sub_3tab(PPAdvance, 1, 5, material));
    addto_pcpl_tab(BP, H2, sub_3tab(PPAdvance, 0, 5, material));
#endif

    /*
     * Pawns on the 8th must be given the same value as a queen 
     */
#ifndef FIT_MODE			/* there are no pawns on 8th in fit mode, so don't bother */
    for (sq = A8; sq <= H8; sq++)
	pieceplacement(WP, sq) = pieceplacement(WQ, sq);
    for (sq = A1; sq <= H1; sq++)
	pieceplacement(BP, sq) = pieceplacement(BQ, sq);
#endif

    /*
     * Penalty for bishops on d3,e3 if corresponding pawns still there
     */
    if (sunboard[D2] == WP)
        addto_pcpl_tab(WB, D3, scale(BishopBlock0, 1, -1));
    if (sunboard[E2] == WP)
        addto_pcpl_tab(WB, E3, scale(BishopBlock0, 1, -1));
    if (sunboard[D7] == BP)
        addto_pcpl_tab(WB, D6, scale(BishopBlock0, 1, 1));
    if (sunboard[E7] == BP)
        addto_pcpl_tab(WB, E6, scale(BishopBlock0, 1, 1));

    /*
     * Penalty for knight on R8
     */
     addto_pcpl_tab(WN, A8, scale(KnightInCorner1, fmat_A, -fmat_B) PLUS scale(KnightInCorner0, 1, -1));
     addto_pcpl_tab(WN, H8, scale(KnightInCorner1, fmat_A, -fmat_B) PLUS scale(KnightInCorner0, 1, -1));
     addto_pcpl_tab(BN, A1, scale(KnightInCorner1, fmat_A, fmat_B) PLUS scale(KnightInCorner0, 1, 1));
     addto_pcpl_tab(BN, H1, scale(KnightInCorner1, fmat_A, fmat_B) PLUS scale(KnightInCorner0, 1, 1));

#ifndef FIT_MODE			/* round piece/placement table to proper values */
    for (sq = PCPLACESIZE; sq--;)
	PieceTable[sq] = unscale(PieceTable[sq]);
#endif

}

#define pmap(x) (x & 037)
#define pmapadj(x) ((x >> 5) & 037)
#define file(x) ((x >> 10) & 07)

#define haspp(x) (pp[pmap(x)][pmapadj(x)])
#define ppadvancement(x) (advancement[pmap(index)])


ppeval(material)
  int material;
{
    /*
     * The passed pawn tables.  There are separate tables for white and
     * black, with a 13 bit index for each.  The index has 3 subfields:  wp
     * (white pawns from 2 through 6), bp (ORed bitmap of adjacent black
     * pawns, 2 through 6) and the file number.  Give credit for advancement,
     * and allow for variation by file.  Bonus is modulated by material. 
     */
    register int index;
    register int materialsq = material * material;

#ifndef FIT_MODE
    register int *rWPPTable = WPPTable;
    register int *rBPPTable = BPPTable;

    register int r1,
            r2,
            value,
	    Cr2,Cr1;

    int PPA2 = ((PPAdvance2 * fmatsq_A)<<8)/fmatsq_B;
    int PPA1 = ((PPAdvance1 * fmat_A)<<8)/fmat_B;
    int PPC1 = ((PPCentral1 * fmat_A)<<8)/fmat_B;
    int PPA0 = PPAdvance0<<8;
    int PPC0 = PPCentral0<<8;
    Cr2 = (PPA2+PPA0+PPA1);
    Cr1 = (PPC0+PPC1);

    loadmask |= 0xc;

    for (index = 0; index < PPTABLESIZE; index++) {
	if (haspp(index)) {
	    r1 = ppcentgradient[file(index)];
	    r2 = ppadvgradient[ppadvancement(index)];
	    value = Cr2 * r2 + Cr1*r1;
	    rWPPTable[index] = value = unscale(value);
	    rBPPTable[index] = -value;
	} else {
		rWPPTable[index] = 0;
		rBPPTable[index] = 0;
	}
    }
#else
    register int i, j;
    
    scan_wpp_tab(index) {
	/*
	 * white table 
	 */
	if (haspp(index)) {
#ifdef OLD_PPA
	    i = ppadvgradient[ppadvancement(index)];

	    addto_WPPT(index, scale(PPAdvance2, i * fmatsq_A, fmatsq_B) PLUS
			      scale(PPAdvance1, i * fmat_A, fmat_B) PLUS
			      scale(PPAdvance0, i, 1));

	    i = ppcentgradient[file(index)];
	    
	    addto_WPPT(index, scale(PPCentral1, i * fmat_A, fmat_B) PLUS
			      scale(PPCentral0, i, 1));
#else
	    i = ppadvancement(index);
	    j = file(index);
	    if (j > 3)
		j = 7 - j;			/* centrality: 0,1,2,3,3,2,1,0 for A..H */

	    addto_WPPT(index, add_3tab(PPAdvance, j, i, material));
#endif
	}
    }

    scan_bpp_tab(index) {
	/*
	 * white table 
	 */
	if (haspp(index)) {

#ifdef OLD_PPA
	    i = ppadvgradient[ppadvancement(index)];

	    addto_BPPT(index, scale(PPAdvance2, i * fmatsq_A, -fmatsq_B) PLUS
			      scale(PPAdvance1, i * fmat_A, -fmat_B) PLUS
			      scale(PPAdvance0, i, -1));

	    i = ppcentgradient[file(index)];

	    addto_BPPT(index, scale(PPCentral1, i * fmat_A, -fmat_B) PLUS
			      scale(PPCentral0, i, -1));
#else
	    i = ppadvancement(index);
	    j = file(index);
	    if (j > 3)
		j = 7 - j;			/* centrality: 0,1,2,3,3,2,1,0 for A..H */

	    addto_BPPT(index, sub_3tab(PPAdvance, j, i, material));
#endif
	}
    }
#endif
}

#undef file()
#undef pcount()

#define wrcount(x) (x & 03)
#define brcount(x) ((x >> 2) & 03)
#define file(x) ((x >> 4) & 07)
#define wp(x) (!((x >> 7) & 01))
#define bp(x) (!((x >> 8) & 01))
#define oddblocked(x) (!((x >> 9) & 01))
#define evenblocked(x) (!((x >> 10) & 01))

rookeval(wpcount,bpcount,wkfile,bkfile,material,wminorstatus,bminorstatus)
  int wpcount, bpcount, wkfile, bkfile, material, wminorstatus, bminorstatus;
{
    /*
     * Fill in the values for the rooktable. This table deals with rooks on
     * open files and minor piece/blocked pawn interactions.  Additional
     * bonuses are given for blocked pawns in front of kings and rooks on
     * open files near enemy king.  The rooktable index has 11 bits, and has
     * 7 fields: white rook count (2), black rook count(2), file(3), white
     * pawn(1), black pawn(1), odd blocked(1), and even blocked(1) 
     */
    register int index;
    register int pcount = wpcount + bpcount;

#ifndef FIT_MODE
    register int *rRookTable = RookTable;
    loadmask |= 0x10;
#endif

    scan_rook_tab(index) {
#ifndef FIT_MODE
	rRookTable[index] = 0;
#endif
	if ((wrcount(index) > 0) && !wp(index)) {
	    /*
	     * bonus depends on number of pawns remaining, closeness to enemy
	     * king, semi-open or open.  could also include a bonus for
	     * doubled rooks 
	     */
	    if (bp(index)) {	/* semi-open */
		addto_RookT(index, scale(RookSemi1, wrcount(index) * fbpc_A, fbpc_B) PLUS
				   scale(RookSemi0, wrcount(index), 1));
		if (abs(file(index) - bkfile) < 2)
		    addto_RookT(index, scale(RookSemiTrop1, wrcount(index) * fmat_A, fmat_B) PLUS
				       scale(RookSemiTrop0, wrcount(index), 1));
	    } else {
		addto_RookT(index, scale(RookOpen1, wrcount(index) * fbpc_A, fbpc_B) PLUS
			           scale(RookOpen0, wrcount(index), 1));
		if (abs(file(index) - bkfile) < 2)
		    addto_RookT(index, scale(RookOpenTrop1, wrcount(index) * fmat_A, fmat_B) PLUS
				       scale(RookOpenTrop0, wrcount(index), 1));
	    }
	}
	if ((brcount(index) > 0) && !bp(index)) {
	    if (wp(index)) {	/* semi-open */
		addto_RookT(index, scale(RookSemi1, brcount(index) * fwpc_A, -fwpc_B) PLUS
			           scale(RookSemi0, brcount(index), -1));
		if (abs(file(index) - wkfile) < 2)
		    addto_RookT(index, scale(RookSemiTrop1, brcount(index) * fmat_A, fmat_B) PLUS
				       scale(RookSemiTrop0, brcount(index), 1));
	    } else {
		addto_RookT(index, scale(RookOpen1, brcount(index) * fwpc_A, -fwpc_B) PLUS
			           scale(RookOpen0, brcount(index), -1));
		if (abs(file(index) - wkfile) < 2)
		    addto_RookT(index, scale(RookOpenTrop1, brcount(index) * fmat_A, fmat_B) PLUS
				       scale(RookOpenTrop0, brcount(index), 1));
	    }
	}
	/*
	 * Give penalties for having bishops on the same color as blocked
	 * pawns.  The penalty should be more severe on central files, and
	 * vary with the total number of pawns on the board. 
	 */
	if (oddblocked(index) || evenblocked(index)) {
	    /*
	     * value depends on number of pawns, file 
	     */
	    switch (wminorstatus) {
	    case TWOBISHOPS:
		addto_RookT(index, scale(TwoBishop1, blockdebit[file(index)] * fpc_A, -fpc_B) PLUS
			           scale(TwoBishop0, blockdebit[file(index)], -1));
		break;
	    case LIGHTBISHOP:
		if ((oddblocked(index) && ((file(index) & 1) == 1)) ||
		    (evenblocked(index) && ((file(index) & 1) == 0)))
		    addto_RookT(index, scale(OneBishop1, blockdebit[file(index)] * fpc_A, -fpc_B) PLUS
			               scale(OneBishop0, blockdebit[file(index)], -1));
		break;
	    case DARKBISHOP:
		if ((oddblocked(index) && ((file(index) & 1) == 0)) ||
		    (evenblocked(index) && ((file(index) & 1) == 1)))
		    addto_RookT(index, scale(OneBishop1, blockdebit[file(index)] * fpc_A, -fpc_B) PLUS
			               scale(OneBishop0, blockdebit[file(index)], -1));
		break;
	    case NOBISHOPS:
		break;
	    }
	    switch (bminorstatus) {
	    case TWOBISHOPS:
		addto_RookT(index, scale(TwoBishop1, blockdebit[file(index)] * fpc_A, fpc_B) PLUS
			           scale(TwoBishop0, blockdebit[file(index)], 1));
		break;
	    case LIGHTBISHOP:
		if ((oddblocked(index) && ((file(index) & 1) == 0)) ||
		    (evenblocked(index) && ((file(index) & 1) == 1)))
		    addto_RookT(index, scale(OneBishop1, blockdebit[file(index)] * fpc_A, fpc_B) PLUS
			               scale(OneBishop0, blockdebit[file(index)], 1));
		break;
	    case DARKBISHOP:
		if ((oddblocked(index) && ((file(index) & 1) == 1)) ||
		    (evenblocked(index) && ((file(index) & 1) == 0)))
		    addto_RookT(index, scale(OneBishop1, blockdebit[file(index)] * fpc_A, fpc_B) PLUS
			               scale(OneBishop0, blockdebit[file(index)], 1));
		break;
	    case NOBISHOPS:
		break;
	    }
	    if (abs(file(index) - wkfile) <= 1) {
		/*
		 * bonus for blocked pawns in front of king 
		 */
		addto_RookT(index, scale(BlockedKingShelter1, fmat_A, fmat_B) PLUS scale(BlockedKingShelter0, 1, 1));
	    }
	    if (abs(file(index) - bkfile) <= 1) {
		addto_RookT(index, scale(BlockedKingShelter1, fmat_A, -fmat_B) PLUS scale(BlockedKingShelter0, 1, -1));
	    }
	}
#ifndef FIT_MODE
	rRookTable[index] = unscale(rRookTable[index]);
#endif
    }
}

#ifndef FIT_MODE
#define DUMPFILE "tabdump.mss"

printtables() {
    register FILE *fp;
    register int index;

    printf("WP");
    ptab(&pieceplacement(WP,0));
    printf("BP");
    ptab(&pieceplacement(BP,0));
    printf("WN");
    ptab(&pieceplacement(WN,0));
    printf("BN");
    ptab(&pieceplacement(BN,0));
    printf("WB");
    ptab(&pieceplacement(WB,0));
    printf("BB");
    ptab(&pieceplacement(BB,0));
    printf("WR");
    ptab(&pieceplacement(WR,0));
    printf("BR");
    ptab(&pieceplacement(BR,0));
    printf("WQ");
    ptab(&pieceplacement(WQ,0));
    printf("BQ");
    ptab(&pieceplacement(BQ,0));
    printf("WK");
    ptab(&pieceplacement(WK,0));
    printf("BK");
    ptab(&pieceplacement(BK,0));
    printf("see %s for slow eval tables\n",DUMPFILE);
    if((fp = fopen(DUMPFILE,"w"))==NULL)
		quit(-1,"cannot write %s\n",DUMPFILE);
	fprintf(fp,"WPTable,BPTable:\n");
    for(index = 0;index < PAWNTABLESIZE;index++)
	fprintf(fp,"%x : %x %x\n",index,WPTable[index],BPTable[index]);
	fprintf(fp,"WPPTable,BPPTable:\n");
    for(index = 0;index < PPTABLESIZE;index++)
	fprintf(fp,"%x : %x %x\n",index,WPPTable[index],BPPTable[index]);
    fprintf(fp,"Rooktable:\n");
    for(index=0;index<ROOKTABLESIZE;index++)
	fprintf(fp,"%x : %x\n",index,RookTable[index]);
    fclose(fp);
}

ptab(t)
  int *t;
{
    int i, j;

    printf("\n");
    for (i = 56; i >= 0; i -= 8) {
        for (j = 0; j < 8; j++)
	    printf("%d, ", *(t+Lsq[(i+j)]));
	printf("\n");
    }
    printf("\n");
}

#undef wp()
#undef bp()

softeval()
{
    register int i,
            j,
            evaluation,
            sq,
            tmp;
    int     wp,
            bp,
            lwp,
            lbp,
            rwp,
            rbp,
            wrcnt,
            brcnt,
            neblked,
            noblked;

    evaluation = 0;
    tmp = 0;
    for (sq = A1; sq <= H8; sq++)
	tmp += pieceplacement(sunboard[sq], sq);
    if (VERB && verb)
	printf("piece placement value is %d\n", tmp);

    evaluation += tmp;
    lwp = lbp = 0;
    wp = bp = 0;
    for (i = 6; i > 0; --i) {
	wp = (wp << 1) + ((sunboard[8 * i] == WP) ? 1 : 0);
    }
    for (i = 1; i < 7; ++i) {
	bp = (bp << 1) + ((sunboard[8 * i] == BP) ? 1 : 0);
    }
    if (VERB && verb)
	printf("\nfile\tWP\tBP\tWPP\tBPP\tRook\n");
    for (i = 0; i < 8; ++i) {
	if (VERB && verb)
	    printf("\n%c", i + 'a');
	rwp = rbp = 0;
	if (i != 7)
	    for (j = 6; j > 0; --j) {
		rwp = (rwp << 1) + ((sunboard[8 * j + i + 1] == WP) ? 1 : 0);
	    }
	if (i != 7)
	    for (j = 1; j < 7; ++j) {
		rbp = (rbp << 1) + ((sunboard[8 * j + i + 1] == BP) ? 1 : 0);
	    }
	wrcnt = brcnt = 0;
	for (j = 0; j < 8; ++j) {
	    wrcnt += (sunboard[8 * j + i] == WR) ? 1 : 0;
	    brcnt += (sunboard[8 * j + i] == BR) ? 1 : 0;
	}
	wrcnt %= 4;
	brcnt %= 4;

	tmp = WPTable[(i << 10) + ((bp == 0) ? 0x200 : 0) + (((lwp | rwp) & 0xf) << 5) + (wp & 0x1f)];
	if (VERB && verb)
	    printf("\t%d", tmp);
	evaluation += tmp;

	tmp = BPTable[(i << 10) + ((wp == 0) ? 0x200 : 0) + (((lbp | rbp) & 0xf) << 5) + (bp & 0x1f)];
	if (VERB && verb)
	    printf("\t%d", tmp);
	evaluation += tmp;

	tmp = WPPTable[(i << 10) + (((lbp | bp | rbp) & 0x1f) << 5) + (wp & 0x1f)];
	if (VERB && verb)
	    printf("\t%d", tmp);
	evaluation += tmp;

	tmp = BPPTable[(i << 10) + (((lwp | wp | rwp) & 0x1f) << 5) + (bp & 0x1f)];
	if (VERB && verb)
	    printf("\t%d", tmp);
	evaluation += tmp;

	if (((wp & 1) && (bp & 0x10)) || ((wp & 4) && (bp & 4)) || ((wp & 0x10) && (bp & 1))) {
	    neblked = 0;
	} else {
	    neblked = 0x400;
	}
	if (((wp & 2) && (bp & 8)) || ((wp & 8) && (bp & 2))) {
	    noblked = 0;
	} else {
	    noblked = 0x200;
	}
	tmp = RookTable[neblked + noblked + (bp ? 0 : 0x100) + (wp ? 0 : 0x80) + (i << 4) + (brcnt << 2) + wrcnt];
	if (VERB && verb)
	    printf("\t%d", tmp);
	evaluation += tmp;

	lwp = wp;
	lbp = bp;
	wp = rwp;
	bp = rbp;
    }
    if (VERB && verb)
	printf("\n");
    return evaluation;
/*    return (((evaluation << 22) >> 22) & 0xffff);*/
}

#endif

#define xscale(param, a, b) (((param.init * (a)) << 8) / (b))

pawn_lst()
{
    FILE           *fp,
                   *fopen();

    register int    pcentrality, i, mi = 0x7ffffff, ma =  0x80000000, 
                    padvancement, material;
    double t;

    for (pcentrality = 0; pcentrality < 4; pcentrality++) {
	for (padvancement = 0; padvancement < 6; padvancement++) {
	    for (material = 0; material < 72; material++) {
		i = xscale(PawnPlaceMCA, fmca_A, fmca_B) +
		    xscale(PawnPlaceMC, fmc_A, fmc_B) +
		    xscale(PawnPlaceMA, fma_A, fma_B) +
		    xscale(PawnPlaceCA, fca_A, fca_B) +
		    xscale(PawnPlaceM, fmat_A, fmat_B) +
		    xscale(PawnPlaceC, fcent_A, fcent_B) +
		    xscale(PawnPlaceA, fadv_A, fadv_B) +
		    xscale(PawnPlaceK, 1, 1);
		if (ma < i)
		    ma = i;
		if (mi > i)
		    mi = i;
	    }
	}
    }

    if (ma < 0) ma = -ma;
    if (mi < 0) mi = -mi;
    if (ma < mi) ma = mi;
    t = 256.0 / ma;

    fp = fopen ("pawn.h", "w");

    fprintf(fp, "(%.0f, ...) = {\n", 1.0 / t);
    for (material = 0; material < 72; material++) {
	fprintf(fp, "    {\n");
	for (padvancement = 0; padvancement < 6; padvancement++) {
	    fprintf(fp, "        {");
	    for (pcentrality = 0; pcentrality < 4; pcentrality++) {
		i = xscale(PawnPlaceMCA, fmca_A, fmca_B) +
		    xscale(PawnPlaceMC, fmc_A, fmc_B) +
		    xscale(PawnPlaceMA, fma_A, fma_B) +
		    xscale(PawnPlaceCA, fca_A, fca_B) +
		    xscale(PawnPlaceM, fmat_A, fmat_B) +
		    xscale(PawnPlaceC, fcent_A, fcent_B) +
		    xscale(PawnPlaceA, fadv_A, fadv_B) +
		    xscale(PawnPlaceK, 1, 1);
		if(!pcentrality)
		    fprintf(fp, "%.0f", t * i);
		else
		    fprintf(fp, ", %.0f", t * i);
	    }
	    if (padvancement < 5)
		fprintf(fp, "},\n");
	    else
		fprintf(fp, "}\n");
	}
	if (material < 71)
	    fprintf(fp, "    },\n");
	else
	    fprintf(fp, "    }\n");
    }
    fprintf(fp, "};\n");

    fclose(fp);
}

ppa_lst()
{
    FILE           *fp,
                   *fopen();

    register int    pcentrality,
                    i,
                    mi = 0x7ffffff,
                    ma = 0x80000000,
                    padvancement,
                    material,
                    materialsq;

    double          t;

    for (material = 0; material < 72; material++) {
	materialsq = material * material;
	for (padvancement = 0; padvancement < 6; padvancement++) {
	    for (pcentrality = 0; pcentrality < 4; pcentrality++) {
		i = xscale(PPAdvance2, ppadvgradient[padvancement] * fmatsq_A, fmatsq_B) +
		    xscale(PPAdvance1, ppadvgradient[padvancement] * fmat_A, fmat_B) +
		    xscale(PPAdvance0, ppadvgradient[padvancement], 1) +
		    xscale(PPCentral1, ppcentgradient[pcentrality] * fmat_A, fmat_B) +
		    xscale(PPCentral0, ppcentgradient[pcentrality], 1);

		if (ma < i)
		    ma = i;
		if (mi > i)
		    mi = i;
	    }
	}
    }

    if (ma < 0)
	ma = -ma;
    if (mi < 0)
	mi = -mi;
    if (ma < mi)
	ma = mi;
    t = 256.0 / ma;

    fp = fopen("ppa.h", "w");

    fprintf(fp, "(%.0f, ...) = {\n", 1.0 / t);
    for (material = 0; material < 72; material++) {
	    materialsq = material * material;
	fprintf(fp, "    {\n");
	for (padvancement = 0; padvancement < 6; padvancement++) {
	    fprintf(fp, "        {");
	    for (pcentrality = 0; pcentrality < 4; pcentrality++) {
		i = xscale(PPAdvance2, ppadvgradient[padvancement] * fmatsq_A, fmatsq_B) +
		    xscale(PPAdvance1, ppadvgradient[padvancement] * fmat_A, fmat_B) +
		    xscale(PPAdvance0, ppadvgradient[padvancement], 1) +
		    xscale(PPCentral1, ppcentgradient[pcentrality] * fmat_A, fmat_B) +
		    xscale(PPCentral0, ppcentgradient[pcentrality], 1);

		if(!pcentrality)
		    fprintf(fp, "%.0f", t * i);
		else
		    fprintf(fp, ", %.0f", t * i);
	    }
	    if (padvancement < 5)
		fprintf(fp, "},\n");
	    else
		fprintf(fp, "}\n");
	}
	if (material < 71)
	    fprintf(fp, "    },\n");
	else
	    fprintf(fp, "    }\n");
    }
    fprintf(fp, "};\n");

    fclose(fp);
}
