Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: To bitboard or not to bitboard?

Author: Tord Romstad

Date: 07:37:41 09/01/03

Go up one level in this thread


On September 01, 2003 at 09:56:15, Uri Blass wrote:

>>Yes, that's a good start.  This is how my pawn hash table entries look
>>at the moment (I am constantly adding new fields).
>>
>>typedef struct {
>>  p_hashkey_t key;
>>  uint8 isolated_pawns[2][4]; /* Squares of isolated pawns for both sides */
>
>number of isolated pawns may be more than 4 for one side because it is possible
>that one side has more than one isolated pawn in the same file.
>What do you do in that case?

Only the frontmost isolated pawn on the file is stored in the array.  The
penalty for this pawn will usually be bigger than for an ordinary isolated
pawn, because it is an isolated *and* doubled pawn.

>>  uint8 double_pawns[2][4];   /* Squares of doubled pawns for both sides */
>
>again what you do in case that white has pawns at e2,e3,e4,a2,a3.

Same answer here, I only store the frontmost pawn.  I am too lazy to
check my source code now, but if I recall correctly tripled pawns are
considered to be two doubled pawns.  In your example, the
double_pawns[WHITE][] array would contain the squares e4, e3 and a3.

>>  uint8 backward_pawns[2][4]; /* Squares of backward pawns for both sides */
>
>I do not evaluate backward pawns.
>What is your definition?

I consider a pawn to be backward if *all* of the following conditions are
satisfied:

1. It is not an isolated pawn.
2. The friendly pawns on neighboring files are not beside or behind the
   pawn.
3. One or more of the opponent's pawns prevent the pawn from safely
   advancing until it is beside one of the friendly pawns.

As an example, if black has pawns on e6 and f5 and no pawn on the d file,
and white has a pawn on d4, the black pawn on e6 is a backward pawn.

>>  uint8 passed_pawns[2][8];   /* Squares of passed pawns for both sides */
>>  uint8 open_files[2];        /* Bitfields of open files for both sides */
>
>Do you define open file for white as file without white pawns?

Yes.

>>  uint8 ks_storm[2];          /* King side pawn storm eval for both sides */
>>  uint8 qs_storm[2];          /* Queen side pawn storm eval for both sides */
>
>How do you evaluate king side pawn storm and queen side pawn storm based on pawn
>structure?

This is used in positions with opposite castling.  I have four "pawn
square tables" (piece square tables which are only used with pawns).
called w_ks_storm_table[], w_qs_storm_table[], b_ks_storm_table[] and
b_qs_storm_table[].  When white has castled queenside and black kingside,
I use w_ks_storm_table[] to evaluate the proximity of white's kingside
pawns to black's king, and (similarly) b_qs_storm_table to evaluate
black's queenside pawns.

I have a function named analyse_pawn_structure() which computes all the
stuff in p_hashentry_t and stores it all in the pawn hash table.  Among
the many computations done, the ks_storm[] and qs_storm[] arrays are
filled with bonuses calculated from the above-mentioned pawn square tables.

Of course, I never use all the 4 entries in ks_storm[] and qs_storm[]
simultaneously in my evaluation function.  If the kings are castled to
the same side, I ignore all the values.  If white has castled queenside
and black kingside, I use ks_storm[WHITE] and qs_storm[BLACK].

There is great scope for improvement in this part of my program.  It
is rather primitive to use static pawn square tables for things like this.
It would be much better to take in consideration the defending side's
pawns in front of the king when computing ks_storm[] and qs_storm[].
One of the great things about pawn hash tables is that you can do very
time-consuming calculations at very little cost, because there are so
few different pawn structures in the search tree.

The above explanation is somewhat simplified, but I hope you get the idea.

>>  uint8 ks_rook_files[2];     /* Good files for rooks when ks pawn storm */
>>  uint8 qs_rook_files[2];     /* Good files for rooks when qs pawn storm */
>>  uint8 bad_bishop_colour[2]; /* Bad bishop colour for both sides */
>
>How do you evaluate it?

Basically, a bishop is bad if there are many friendly pawns on the same
colour.  I use a weighted sum of the number of friendly pawns on the
bishop's colour (where central squares have the biggest weight), and
decides that the bishop is bad if this number is bigger than some number.

Note that I do not store a bad bishop penalty in the pawn hash table,
just the bit of information that a bishop of this colour is bad.  The
penalty is computed in the evaluation function, where the penalty
depends on the bishop's mobility, the contents of blocked_pawns_on_b[]
and similar arrays, and probably something more which I don't remember
at the moment.

>>  int8 lpf[2];                /* Leftmost pawn file for both sides */
>>  int8 rpf[2];                /* Rightmost pawn file for both sides */
>>  int8 pchain_bonus[2];       /* Bonus for pawn chains and phalanxes */
>
>How do you evaluate pawn chains and what is phalanx?

I have very primitive definitions of these.  A pawn is member of a "pawn
chain" if it has a friendly pawn diagonally in front or behind itself.
It is member of a "phalanx" if it has a friendly pawn on one of the
neighboring squares.  I give a small bonus for pawns which are members
of a pawn chain or phalanx.

>>  int8 centre;                /* Type of centre */
>>  uint8 pawns_on_w[2];        /* Pawns on white squares for both sides */
>>  uint8 pawns_on_b[2];        /* Pawns on black squares for both sides */
>>  uint8 central_pawns_on_w[2];/* Central pawns on white squares, both sides */
>>  uint8 central_pawns_on_b[2];/* Central pawns on black squares, both sides */
>>  uint8 blocked_pawns_on_w[2];/* Blocked pawns on white squares, both sides */
>>  uint8 blocked_pawns_on_b[2];/* Blocked pawns on black squares, both sides */
>>  uint8 blocked_central_pawns_on_w[2];
>>      /* Blocked central pawns on white squares, both sides */
>>  uint8 foo[55];  /* This is only here to make the structure 128 bytes big */
>>} p_hashentry_t;
>>
>>The 'centre' field has a value which depends on the central pawn structure.
>>Possible values are OPEN, HALF_OPEN, HALF_CLOSED, CLOSED, TENSION,
>>UNRESOLVED, W_STONEWALL and B_STONEWALL.  For each type of centre I evaluate
>>the position slightly differently (for instance, the penalty for not having
>>a good pawn shelter in front of the king is much bigger when the centre
>>is open).  I plan to add many more types of central pawn structures in
>>the future.
>
>It seems that you are a very strong player.

I am not an active chess player at all.  I have no rating, and if I
started playing actively I think my rating would end up far below 2000.

>My rating is close to 2000 but I never thought about centre in these
>definitions.
>
>I do not consider myself to be good enough to know when to give a bonus and even
>if I know when to give a bonus I need to test first because even if something is
>good the bonus may be counter productive if it is too big
>or if this bonus is already calculated for different reasons.

I'm not saying that anything I do in my program is a good idea.  Unlike
you, I have no ambitions whatsoever in computer chess.  Rather than trying
to create the strongest possible program, I just do what I think is fun
at the moment.  Perhaps all the time and energy I spend on the evaluation
function is counter-productive for the program's strength, but it gives
the engine a personality which is different from most others.

>For example you may punish bad bishop not directly for mobility reasons and if
>you add special evaluation for bad bishop then it may be counter productive
>because your evaluation is too much when it punishes the bad bishop twice.
>
>>
>>>Should I have some global varaible
>>>int zobpawns for the key of the position in the board or maybe an array that
>>>tell me the zobrist key for every ply and local varaible is enough.
>>
>>I use an array (for pawn hash keys as well as for normal hash keys).  For
>>normal hash keys I use 64 bits, for pawn hash keys I use 32.
>>
>>Tord
>
>I guess that you update your hash key when you make move.
>How do you do it?
>
>Do you use your array or do you define a local varaible?
>
>Same question for using your hash key when you probe the hash tables or record
>position in the hash tables.

No local variables in either case.  But at least in my program, I don't
think this matters at all.

Tord



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.