Fuit's pawn evaluation using 8-bits ?
Posted: 08 Aug 2005, 18:19
I remember past threads mentioning the pawns.c file of fruit's
with variables/pawn-array names with xxxG, xxxL, xxxGE, xxxLE etc.
I have just figured out that probably fruit is using some sort of 8-bits
bitboard (bitbase ?) to implement evaluation of pawn structure and pawns cover for king safety.I just finished emulating these same evaluation from
TSCP using 8-bit char, 8 bits to represent rank/file 0-7 with 1,2,4,8,...
The method I use is to collect for the least-advanced pawn of each file(and color) the remaining ranks(as bits) that it may pass through ahead. This bitbased method may be more efficient than the way done in TSCP as bitwise operators are used and the codes seems more compact.
I post my 2 files pawn.h and pawns.c and anyone may use them freely and consider them their own if they wish to. I have checked them fairly carefully but my programming skill is only so... so. I am not sure if it's buggy. So let me know if there are bugs.
Can such 8-bits be used for other things ?
Thanks
Rasjid
pawn.h -
#ifndef __pawn_h__
#define __pawn_h__
#define KS_SCORE_WT 64
#define KS_SCORE_DIV 48
#define P_COVER_CENTER_NULL 10
#define P_COVER_MOVED_1 10
#define P_COVER_MOVED_2 15
#define P_COVER_ZERO 24
// pawn storm
#define P_COVER_ZERO_XSIDE 15
#define PAWN_STORM_2 10
#define PAWN_STORM_1 5
// or 12/25
#define DOUBLED_PAWN 10
#define LONE_PAWN 20
#define BACKWARD_PAWN 8
#define PASS_PAWN_PER_RANK 3
typedef char _bb_t;
/*
(bitbase ?) for pawn structure eval :-
8 bits to represent rank/file 0-7 using 1, 2, 4, 8, ...
*/
#define bbE0 (_bb_t) 1
#define bbE1 (_bb_t) 2
#define bbE2 (_bb_t) 4
#define bbE3 (_bb_t) 8
#define bbE4 (_bb_t) 0x10
#define bbE5 (_bb_t) 0x20
#define bbE6 (_bb_t) 0x40
#define bbE7 (_bb_t) 0x80
#define bbG0 (_bb_t) 0376
#define bbG1 (_bb_t) 0374
#define bbG2 (_bb_t) 0370
#define bbG3 (_bb_t) 0360
#define bbG4 (_bb_t) 0340
#define bbG5 (_bb_t) 0300
#define bbG6 (_bb_t) 0200
#define bbG7 (_bb_t) 0
#define bbL0 (_bb_t) 0
#define bbL1 (_bb_t) 1
#define bbL2 (_bb_t) 3
#define bbL3 (_bb_t) 7
#define bbL4 (_bb_t) 017
#define bbL5 (_bb_t) 037
#define bbL6 (_bb_t) 077
#define bbL7 (_bb_t) 0177
//rank/file equal
extern const _bb_t bbE[8];
// bits ahead in rank for color
extern const _bb_t rankG[2][8];
extern _bb_t ladvPRankG[2][8]; //[col][file] for least advance pawns of color and file
extern _bb_t ladvPRankGSide[2][8];// OR of the 2 side files
extern int (*evalPawn[2])(PPC );
extern int max_pawn[2], p_score[2], ks_score[2];
int bPawn(PPC p);
int wPawn(PPC p);
int evalWking();
int evalBking();
#endif
end- pawn.h
pawn.c
Addition by moderator: Using the "Code" button makes source code a bit better readable IMO.
Regards
Volker
with variables/pawn-array names with xxxG, xxxL, xxxGE, xxxLE etc.
I have just figured out that probably fruit is using some sort of 8-bits
bitboard (bitbase ?) to implement evaluation of pawn structure and pawns cover for king safety.I just finished emulating these same evaluation from
TSCP using 8-bit char, 8 bits to represent rank/file 0-7 with 1,2,4,8,...
The method I use is to collect for the least-advanced pawn of each file(and color) the remaining ranks(as bits) that it may pass through ahead. This bitbased method may be more efficient than the way done in TSCP as bitwise operators are used and the codes seems more compact.
I post my 2 files pawn.h and pawns.c and anyone may use them freely and consider them their own if they wish to. I have checked them fairly carefully but my programming skill is only so... so. I am not sure if it's buggy. So let me know if there are bugs.
Can such 8-bits be used for other things ?
Thanks
Rasjid
pawn.h -
#ifndef __pawn_h__
#define __pawn_h__
#define KS_SCORE_WT 64
#define KS_SCORE_DIV 48
#define P_COVER_CENTER_NULL 10
#define P_COVER_MOVED_1 10
#define P_COVER_MOVED_2 15
#define P_COVER_ZERO 24
// pawn storm
#define P_COVER_ZERO_XSIDE 15
#define PAWN_STORM_2 10
#define PAWN_STORM_1 5
// or 12/25
#define DOUBLED_PAWN 10
#define LONE_PAWN 20
#define BACKWARD_PAWN 8
#define PASS_PAWN_PER_RANK 3
typedef char _bb_t;
/*
(bitbase ?) for pawn structure eval :-
8 bits to represent rank/file 0-7 using 1, 2, 4, 8, ...
*/
#define bbE0 (_bb_t) 1
#define bbE1 (_bb_t) 2
#define bbE2 (_bb_t) 4
#define bbE3 (_bb_t) 8
#define bbE4 (_bb_t) 0x10
#define bbE5 (_bb_t) 0x20
#define bbE6 (_bb_t) 0x40
#define bbE7 (_bb_t) 0x80
#define bbG0 (_bb_t) 0376
#define bbG1 (_bb_t) 0374
#define bbG2 (_bb_t) 0370
#define bbG3 (_bb_t) 0360
#define bbG4 (_bb_t) 0340
#define bbG5 (_bb_t) 0300
#define bbG6 (_bb_t) 0200
#define bbG7 (_bb_t) 0
#define bbL0 (_bb_t) 0
#define bbL1 (_bb_t) 1
#define bbL2 (_bb_t) 3
#define bbL3 (_bb_t) 7
#define bbL4 (_bb_t) 017
#define bbL5 (_bb_t) 037
#define bbL6 (_bb_t) 077
#define bbL7 (_bb_t) 0177
//rank/file equal
extern const _bb_t bbE[8];
// bits ahead in rank for color
extern const _bb_t rankG[2][8];
extern _bb_t ladvPRankG[2][8]; //[col][file] for least advance pawns of color and file
extern _bb_t ladvPRankGSide[2][8];// OR of the 2 side files
extern int (*evalPawn[2])(PPC );
extern int max_pawn[2], p_score[2], ks_score[2];
int bPawn(PPC p);
int wPawn(PPC p);
int evalWking();
int evalBking();
#endif
end- pawn.h
pawn.c
- Code: Select all
#include "defs.h"
#include "pawns.h"
#include "wts.h"
#include "data.h"
#include "eval.h"
#include "geval.h"
int max_pawn[2], p_score[2], ks_score[2];
//least advance pawn bitbase per file
_bb_t ladvPRankG[2][8];
_bb_t ladvPRankGSide[2][8];
int (*evalPawn[2])(PPC ) = {
wPawn, bPawn
};
const _bb_t bbE[8] = {
bbE0, bbE1, bbE2, bbE3,
bbE4, bbE5, bbE6, bbE7
};
// bits ahead in rank for color
const _bb_t rankG[2][8] = {
bbL0, bbL1, bbL2, bbL3,
bbL4, bbL5, bbL6, bbL7,
bbG0, bbG1, bbG2, bbG3,
bbG4, bbG5, bbG6, bbG7
};
int bPawn(PPC p){
int isq = p->isq, r = iGetRank(isq), f = iGetFile(isq), v = 0;
if (ladvPRankG[1][f]^rankG[1][r]){
v -= DOUBLED_PAWN;
}
if (ladvPRankGSide[1][f]){
//~ladvPRankGSide[1][f] == rankLE
if (rankG[1][r]&~ladvPRankGSide[1][f]){
v -= BACKWARD_PAWN;
}
}else{
v -= LONE_PAWN;
p->info |= INFO_PAWN_LONE;
}
if (!(bbE[r]&ladvPRankGSide[0][f]))//passed
if (bbE[r]&ladvPRankG[0][f]){
p->info |= INFO_PAWN_PASS;
v += r * PASS_PAWN_PER_RANK;
}else{
p->info |= INFO_PAWN_PASS_X;
v += pst_p_pass_x[1][isq];
if (max_pawn[1]){
if (r >= iGetRank(max_pawn[1])){
if (r > iGetRank(max_pawn[1])){
max_pawn[1] = isq;
}else{//check queening-sq when rank same, also consider lone (lesser priority)
if (imaxRF(112+f, ksq[0])
> imaxRF(112+iGetFile(max_pawn[1]), ksq[0])){
max_pawn[1] = isq;
}else if (brdPPC(max_pawn[1])->info&INFO_PAWN_LONE){
max_pawn[1] = isq;
}
}
}
}else {
max_pawn[1] = isq;
}
}
return v;
}
int wPawn(PPC p){
int isq = p->isq, r = iGetRank(isq), f = iGetFile(isq), v = 0;
if (ladvPRankG[0][f]^rankG[0][r]){
v -= DOUBLED_PAWN;
}
if (ladvPRankGSide[0][f]){
if (rankG[0][r]&~ladvPRankGSide[0][f]){
v -= BACKWARD_PAWN;
}
}else{
v -= LONE_PAWN;
p->info |= INFO_PAWN_LONE;
}
if (!(bbE[r]&ladvPRankGSide[1][f]))//passed
if (bbE[r]&ladvPRankG[1][f]){
p->info |= INFO_PAWN_PASS;
v += (7 - r) * PASS_PAWN_PER_RANK;
}else{
p->info |= INFO_PAWN_PASS_X;
v += pst_p_pass_x[0][isq];
if (max_pawn[0]){
if (r <= iGetRank(max_pawn[0])){
if (r < iGetRank(max_pawn[0])){
max_pawn[0] = isq;
}else{//check queening -sq when rank same
if (imaxRF(f, ksq[1]) > imaxRF(iGetFile(max_pawn[0]), ksq[1])){
max_pawn[0] = isq;
}else if (brdPPC(max_pawn[0])->info&INFO_PAWN_LONE){
max_pawn[0] = isq;
}
}
}
}else{
max_pawn[0] = isq;
}
}
return v;
}
static int bkf(int f){//per file, for king in corner
int v = 0;
if (ladvPRankG[1][f]){//has pawn
if (ladvPRankG[1][f]^rankG[1][1]){//file pawn moved
if (ladvPRankG[1][f]^rankG[1][2]){
v -= P_COVER_MOVED_2;// moved more than 1 sq
}else{
v -= P_COVER_MOVED_1;// moved 1 sq
}
}//else - file pawn not moved, ok
}else{
if (!ladvPRankG[0][f])// no oppn pawn, bad
v -= P_COVER_ZERO+P_COVER_ZERO_XSIDE;
else
v -= P_COVER_ZERO;
}
/*
pawn storm
=========
1)oppn pawn moved passed horizontal center divide
2) pawn storm - only when kings not in same side corner
3) strictly should use most advanced pawns as may have doubled pawns;
but a doubled has penalty;
*/
if (ladvPRankG[0][f]
//~ladvPRankG[1][f] == LE of least adv pawn
//oppn pawn moved passed horizontal center divide
&& bbE3&~ladvPRankG[0][f]//>= 5th rank
&& k_corner[0]^k_corner[1]){ //kings not same side corner
if (bbE2&~ladvPRankG[0][f]){
v -= PAWN_STORM_2;//6/7th rank
}else{//5th rank
v -= PAWN_STORM_1;
}
}
return v;
}
static int wkf(int f){//for king in corner
int v = 0;
//std 10/15/24/15
if (ladvPRankG[0][f]){//has pawn
if (ladvPRankG[0][f]^rankG[0][6]){
if (ladvPRankG[0][f]^rankG[0][5]){
v -= P_COVER_MOVED_2;// moved more than 1 sq
}else{
v -= P_COVER_MOVED_1;// moved 1 sq
}
}//else - pawn not moved
}else{
if (!ladvPRankG[1][f])// no oppn pawn
v -= P_COVER_ZERO+P_COVER_ZERO_XSIDE;
else
v -= P_COVER_ZERO;
}
//std 5 / 10
if (ladvPRankG[1][f]//file has b pawn
//~ladvPRankG[1][f] == LE of least adv pawn
//oppn pawn moved passed horizontal center divide
&& bbE4&~ladvPRankG[1][f]//>= 5th rank
&& k_corner[0]^k_corner[1]){ //kings not same side corner
if (bbE5&~ladvPRankG[1][f]){
v -= PAWN_STORM_2;//6/7th rank
}else{//5th rank
v -= PAWN_STORM_1;
}
}
return v;
}
int evalBking()
{
int v = 0;
if (k_corner[1]){
if (k_corner[1]&K_CORNER_A){
v += bkf(0);
v += bkf(1);
v += bkf(2)/2;
}else{
v += bkf(7);
v += bkf(6);
v += bkf(5)/2;
}
}else{
int i, f = iGetFile(ksq[1]);
for (i = f-1; i <= f+1; ++i)
if (!(ladvPRankG[0][i]|ladvPRankG[1][i]))//no pawns in file
v -= P_COVER_CENTER_NULL;
}
//used in ksafety()
ks_score[1] = v;
assert(ks_score[1] <= 0 && ks_score[1] >= -127);
return (v+PST_KING[1][ksq[1]])
*(MAX_NP_MTL+nonpawn_mtl[0])*KS_SCORE_WT
/KS_SCORE_DIV /MAX_NP_MTLx2;
}
int evalWking()
{
int v = 0;
//** max score < 40 x 2 + 20 + 30 = -130 ???
if (k_corner[0]){
if (k_corner[0]&K_CORNER_A){
v += wkf(0);
v += wkf(1);
v += wkf(2)/2;
}else{
v += wkf(7);
v += wkf(6);
v += wkf(5)/2;
}
}else{
int i, f = iGetFile(ksq[0]);
for (i = f-1; i <= f+1; ++i)
if (!(ladvPRankG[0][i]|ladvPRankG[1][i]))
v -= P_COVER_CENTER_NULL;
}
//used in ksafety()
ks_score[0] = v;
assert(ks_score[0] <= 0 && ks_score[0] >= -127);
return (v+PST_KING[0][ksq[0]])
*(MAX_NP_MTL+nonpawn_mtl[1])*KS_SCORE_WT
/KS_SCORE_DIV /MAX_NP_MTLx2;
// if least near endg, mtl factor is 0.45(r+q)
}
int eval(){
// initialize pawn arrays
// 8 files need be reset
*((U64 *)ladvPRankG[0]) = 0;
*((U64 *)ladvPRankG[1]) = 0;
*((U64 *)ladvPRankGSide[0]) = 0;
*((U64 *)ladvPRankGSide[1]) = 0;
for (i = 0; i <= 1; ++i)//2 colors
for (j = 0; j < pawn_count[i]; ++j){//list thru pawns
p = indPPC(i, j);
ladvPRankG[i][ii = iGetFile(p->isq)] |= rankG[i][iGetRank(p->isq)];
if (ii>0){
ladvPRankGSide[i][ii-1] |= ladvPRankG[i][ii];
}
if (ii<7){
ladvPRankGSide[i][ii+1] |= ladvPRankG[i][ii];
}
}
}
eg code:-
int eval_knight_w(isq){
if (!(bbE[iGetRank(isq)]&ladvPRankGSide[1][iGetFile(isq)])){//passed pawn
score += N_PASSED_PAWN;
}
}
Addition by moderator: Using the "Code" button makes source code a bit better readable IMO.
Regards
Volker