bitboard position evaluations

68 views
Skip to first unread message

Robert Hyatt

unread,
Nov 17, 1994, 9:43:29 AM11/17/94
to

I am initiating this "bitboard position evaluations" thread as a
complement to the "bitboard move generation" thread to continue
discussions about the "new and improved Cray (Sparc/PeeCee/whatever)
Blitz.

The intent of this thread is to discuss evaluation ideas as I work
on them, while the other thread is still concerned with the idea of
bitboards in general and how they are/can be used for many different
things.

In any case, my plan for this thread is to (a) explain what we "used"
to do (for specific topics in evaluation); (b) describe what I am now
trying to do; and, (c) solicit discussion about anything that I say
where you might have better ideas or else simply disagree with what
I think is the way to go. I hope to partially eliminate the "cloud
of secrecy" that has been the standard for many years now, by (for my
part, at least) completely disclosing what I am doing or planning on
doing. If you want to discuss/explain something, but want to keep it
confidential for whatever reason, I have had many such discussions via
email, and am still willing to continue these, although it would seem
to serve computer chess better if we were open so that everyone doesn't
have to continually reinvent the wheel. I can only guarantee that what
I am doing will be completely explained unless it conflicts with a request
by someone else to try something confidentially. I propose that, for this
discussion, we simply "bare all" and see if we can help each other out,
rather than worrying about next year's tournament...

Todays topic: isolated and backward pawns.

What we used to do (isolated pawns):

isolated pawns are simply pawns with no friendly pawns on adjacent files,
making them more difficult to defend. In the past, if they were on a file
with no enemy pawns in front of them, they were considered even worse since
it was easy for rooks/queen to pile up on them from the front. We would
then encourage rooks to move to this file since they would obviously be
attacking a weak enemy piece, making him (or her, no piggish stuff here!)
have to defend it in response.

possible new ideas:

same definition of an isolani. The question now concerns the "open file"
(really half-open, but no quibbling). There appear to be two schools of
thought: (1) an isolani on an open file is bad if my opponent has rooks,
since he may (sooner or later) attack the pawn along the file; (2) an
isolani of any sort is bad, and attacking it is good (since such attack
detection is now trivial, thanks to bitboards).

The interesting problem is this: It is obvious that attacks on a weak
pawn are a good idea; however, if that is all you evaluate, then if the
pawn is not attacked at the instant it becomes isolated, you won't know
that its becoming isolated is bad.

My current thinking is something like this: (a) penalty for isolated, no
matter what the circumstance; (b) more penalty for being on an open file,
if and only if my opponent has rooks; [question: penalty should vary if I
have one rook vs if I have two?]; (c) more penalty for attack on this pawn
by my opponent.

what we used to do (backward pawns):

a pawn is backward if (a) neighboring pawns are missing or at least one rank
ahead of this pawn; (b) neighboring opponent pawns are preventing this pawn
from advancing (1 neighboring opponent pawn is bad, two (one on each adjacent
file) is much worse since pushing my backward pawn would let my opponent
capture and get a protected passer.

we then did the same thing about the open file, as discussed above.

possible new ideas:

basically the same idea as for isolated pawns above, since a backward pawn
and an isolated pawn are basically the same type of weakness - a pawn that
requires protection by pieces, which tends to restrict piece movement for
the defending side.

I am interested in ideas, particularly from strong chess players, as to how
*you* decide if your isolated/backward pawn is bad or ok. Just remember that
I haven't yet discovered how to program your "it feels like the pawn is o.k."
so be prepared to offer semi-precise reasons "why"..

Bob


--
Robert Hyatt Computer and Information Sciences
hy...@cis.uab.edu University of Alabama at Birmingham
(205) 934-2213 115A Campbell Hall, UAB Station
(205) 934-5473 FAX Birmingham, AL 35294-1170

Jon Dart

unread,
Nov 22, 1994, 4:15:16 PM11/22/94
to
In article <3afq6h$j...@pelham.cis.uab.edu> hy...@willis.cis.uab.edu (Robert Hyatt) writes:
> ...

>
>My current thinking is something like this: (a) penalty for isolated, no
>matter what the circumstance; (b) more penalty for being on an open file,
>if and only if my opponent has rooks; [question: penalty should vary if I
>have one rook vs if I have two?]; (c) more penalty for attack on this pawn
>by my opponent.
>

My program gives a little more penalty for a central isolani (one
on files 3..6) than one on the edge of the board. The theory is that
the former is generally weaker than the latter. I think I got this
idea from Kmoch, but I'm not sure.

>what we used to do (backward pawns):
>
>a pawn is backward if (a) neighboring pawns are missing or at least one rank
>ahead of this pawn; (b) neighboring opponent pawns are preventing this pawn
>from advancing (1 neighboring opponent pawn is bad, two (one on each adjacent
>file) is much worse since pushing my backward pawn would let my opponent
>capture and get a protected passer.
>
>we then did the same thing about the open file, as discussed above.
>

IMO, a backward pawn on an open file is a liability even if it can be
advanced and made non-backward. It costs you a tempo to do this.

I have been meaning to experiment with a bonus for attacking the base
of a pawn chain (special case of a backward pawn). Currently I don't
have this factor.

I'm curious how you mean to test modifications to the positional code.
One approach is to play the program against an earlier version
of itself. There are also some test suites that measure positional
judgement (especially the Brato-Kopec lever positions), but I don't
know of any that are very extensive.

B.t.w. I tried converting my evaluation function to using bitboards
for detecting isolated and passed pawns, and got a 10% speedup in
the evaluation code. Not bad for a very little effort.

--Jon
--
--
-- Jon Dart, Rational Software Corp., jd...@rational.com
-- 2800 San Tomas Expy., Santa Clara CA 95051 tel: (408)-496-3656

Robert Hyatt

unread,
Nov 23, 1994, 10:30:56 AM11/23/94
to
In article <3atn14$j...@rational.rational.com>,

Jon Dart <jd...@NETSYS.COM> wrote:
>
>My program gives a little more penalty for a central isolani (one
>on files 3..6) than one on the edge of the board. The theory is that
>the former is generally weaker than the latter. I think I got this
>idea from Kmoch, but I'm not sure.

makes sense. it can be attacked from more directions. of course, it can
also be defended easier, but defending is weakening in most respects.

>
>
>IMO, a backward pawn on an open file is a liability even if it can be
>advanced and made non-backward. It costs you a tempo to do this.
>
>I have been meaning to experiment with a bonus for attacking the base
>of a pawn chain (special case of a backward pawn). Currently I don't
>have this factor.
>
>I'm curious how you mean to test modifications to the positional code.
>One approach is to play the program against an earlier version
>of itself. There are also some test suites that measure positional
>judgement (especially the Brato-Kopec lever positions), but I don't
>know of any that are very extensive.
>

What we usually do is play games against humans, other programs, etc. and
then, without looking at who won/lost, analyze (to the best of our *human*
ability, anyway) each position/move to see if we see something clearly wrong
with a move or something it overlooked. I don't think much of playing a
against b when a and b are the same program with a minor difference. this
seems to exaggerate the differences between the two and can lead to a wrong
impression of the new change...


>B.t.w. I tried converting my evaluation function to using bitboards
>for detecting isolated and passed pawns, and got a 10% speedup in
>the evaluation code. Not bad for a very little effort.
>
>--Jon

I'm still happy with what I'm getting too. I am going to have to re-think
certain parts of make_move() so that they will vectorize on the Cray, but
it's running really well right now. The new version is normally winning
material from the old in most every game since the new one is a ply +
faster (roughly a factor of 10.) I am currently working on the evaluation,
but I'm not really in a hurry as I am trying to think of (a) what I want to
do; (b) what I really can do; (c) what I ought to do; and then combining
these into ideas that fit the new data structures. So far, I haven't had to
compromise *anywhere* in the evaluation, which is a pleasant change from
years past where *everything* was the result of a compromise.

Bob

BTW, for those that are interested, there follows a copy of the current
make_move() routine. It is currently working correctly. Testing has
been done by playing many games (automatically) and validating all of the
attack stuff, bitboards, etc., after each and every move. Very slow, but
it caught a lot of funny things early on.

Note that I have not cleaned this up, and, in fact, am not sure just how
the code looks. I have tried to follow normal C indenting protocols to
make it easier to read, and have included many comments to help me figure
out what's going on where. There may well be redundant code, or even
duplicated code (I've found a couple of those made in the wee hours of the
night when the old mind isn't functioning particularly efficiently...)

One request: if you want to play around with "tweaks", don't change anything
format-wise (ie, don't run it through cb are something similar.) This will
make it easier for me to "diff" and find out what you did. After it has been
worked on, I'll continue to re-post the latest for anyone to make use of if
they are interested.

Bob

---------------------------------cut here------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include "types.h"
#include "function.h"
#include "data.h"
#include "evaluate.h"
/*
********************************************************************************
* *
* make_move() is responsible for updating the position database whenever a *
* piece is moved. it performs the following operations: (1) update the *
* board structure itself by moving the piece and removing any captured *
* piece. before moving a piece, clear the from.attacks[..] structure where *
* this piece used to attack other squares. after moving the piece, set the *
* appropriate to.attacks values and then set from.attacks based on this new *
* to.attacks[] data. *
* *
********************************************************************************
*/
void make_move(int ply, CHESS_MOVE move, int wtm)
{
BITBOARD temp_attacks;
BITBOARD occupied_squares;
BITBOARD occupied, temp, temp1, temp7, temp8, temp9;
BITBOARD changed;
int plus1_piece,minus1_piece;
int plus1dir,plus7dir,plus8dir,plus9dir;
int minus1dir,minus7dir,minus8dir,minus9dir;
int setbit;
/*
----------------------------------------------------------
| |
| first, clear the enpassant_target bit-mask. moving a |
| pawn two ranks will set it later in make_move(). next, |
| clear the from.attacks database for squares attacked |
| from this square since it is fixing to be empty. |
| |
----------------------------------------------------------
*/
position[ply+1]=position[ply];
position[ply+1].board.enpassant_target=mask(128);
if (move.bit_move.captured_piece) {
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
}
switch (move.bit_move.moving_piece) {
/*
********************************************************************************
* *
* make pawn moves. there are two special cases: (a) enpassant captures *
* where the captured pawn is not on the "to" square and must be removed in *
* a different way since the attack vector will change in an unusual way as *
* a result of the capture; (2) pawn promotions (where the "promote_to" *
* variable is non-zero requires updating the appropriate bit boards and the *
* computing the new piece's attack vector from scratch. *
* *
********************************************************************************
*/
case pawn:
if (wtm) {
position[ply+1].board.w_pawn=and(position[ply+1].board.w_pawn,clear_mask[move.bit_move.from]);
position[ply+1].board.w_pawn=or(position[ply+1].board.w_pawn,set_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_pawn_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_pawn_random[move.bit_move.to]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,w_pawn_random[move.bit_move.from]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,w_pawn_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=1;
if (move.bit_move.captured_piece == 1) {
if(!and(position[ply+1].board.b_pawn,set_mask[move.bit_move.to])) {
position[ply+1].board.b_pawn=and(position[ply+1].board.b_pawn,clear_mask[move.bit_move.to-8]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.to-8]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_pawn_random[move.bit_move.to-8]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,b_pawn_random[move.bit_move.to-8]);
position[ply+1].board.board[move.bit_move.to-8]=0;
temp=position[ply+1].to.attacks[move.bit_move.to-8];
position[ply+1].board.material_evaluation+=PAWN_VALUE;
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.to-8]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.to-8]=mask(128);
move.bit_move.captured_piece=0;
/*
----------------------------------------------------------
| |
| now determine if removing this pawn will alter any of |
| the attack boards for sliding pieces that were blocked |
| at this square. if so, correct to.attacks[]. |
| |
----------------------------------------------------------
*/
occupied_squares=or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied);
temp_attacks=and(or(bishop_attacks[move.bit_move.to-8],rook_attacks[move.bit_move.to-8]),occupied_squares);
if (testv(temp_attacks)) {
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to-8]);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to-8]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to-8]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to-8]);
plus1dir=first_one(temp1);
plus7dir=first_one(temp7);
plus8dir=first_one(temp8);
plus9dir=first_one(temp9);
if (!tand(set_mask[plus1dir],position[ply+1].board.rooks_queens)) plus1dir=64;
if (!tand(set_mask[plus7dir],position[ply+1].board.bishops_queens)) plus7dir=64;
if (!tand(set_mask[plus8dir],position[ply+1].board.rooks_queens)) plus8dir=64;
if (!tand(set_mask[plus9dir],position[ply+1].board.bishops_queens)) plus9dir=64;
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to-8]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to-8]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to-8]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to-8]);
minus1dir=last_one(temp1);
minus7dir=last_one(temp7);
minus8dir=last_one(temp8);
minus9dir=last_one(temp9);
if (!tand(set_mask[minus1dir],position[ply+1].board.rooks_queens)) minus1dir=64;
if (!tand(set_mask[minus7dir],position[ply+1].board.bishops_queens)) minus7dir=64;
if (!tand(set_mask[minus8dir],position[ply+1].board.rooks_queens)) minus8dir=64;
if (!tand(set_mask[minus9dir],position[ply+1].board.bishops_queens)) minus9dir=64;
/*
----------------------------------------------------------
| |
| update attacks[plus1dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (plus1dir < 64) {
changed=and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=or(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
temp_attacks=and(position[ply+1].to.attacks[plus1dir],occupied_squares);
temp1=and(temp_attacks,mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=xor(position[ply+1].to.attacks[plus1dir],
mask_minus1dir[last_one(temp1)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus7dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (plus7dir < 64) {
changed=and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=or(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
temp_attacks=and(position[ply+1].to.attacks[plus7dir],occupied_squares);
temp7=and(temp_attacks,mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=xor(position[ply+1].to.attacks[plus7dir],
mask_minus7dir[last_one(temp7)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus8dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (plus8dir < 64) {
changed=and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=or(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
temp_attacks=and(position[ply+1].to.attacks[plus8dir],occupied_squares);
temp8=and(temp_attacks,mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=xor(position[ply+1].to.attacks[plus8dir],
mask_minus8dir[last_one(temp8)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus9dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (plus9dir < 64) {
changed=and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=or(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
temp_attacks=and(position[ply+1].to.attacks[plus9dir],occupied_squares);
temp9=and(temp_attacks,mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=xor(position[ply+1].to.attacks[plus9dir],
mask_minus9dir[last_one(temp9)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus1dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (minus1dir < 64) {
changed=and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=or(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
temp_attacks=and(position[ply+1].to.attacks[minus1dir],occupied_squares);
temp1=and(temp_attacks,mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=xor(position[ply+1].to.attacks[minus1dir],
mask_plus1dir[first_one(temp1)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus7dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (minus7dir < 64) {
changed=and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=or(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
temp_attacks=and(position[ply+1].to.attacks[minus7dir],occupied_squares);
temp7=and(temp_attacks,mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=xor(position[ply+1].to.attacks[minus7dir],
mask_plus7dir[first_one(temp7)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus8dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (minus8dir < 64) {
changed=and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=or(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
temp_attacks=and(position[ply+1].to.attacks[minus8dir],occupied_squares);
temp8=and(temp_attacks,mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=xor(position[ply+1].to.attacks[minus8dir],
mask_plus8dir[first_one(temp8)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus9dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (minus9dir < 64) {
changed=and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=or(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
temp_attacks=and(position[ply+1].to.attacks[minus9dir],occupied_squares);
temp9=and(temp_attacks,mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=xor(position[ply+1].to.attacks[minus9dir],
mask_plus9dir[first_one(temp9)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
}
}
}
/*
----------------------------------------------------------
| |
| if this is a pawn promotion, remove the pawn from the |
| pawn board. then update the correct piece board to |
| reflect piece just created. |
| |
----------------------------------------------------------
*/
if (move.bit_move.promote_to) {
position[ply+1].board.material_evaluation-=PAWN_VALUE;
position[ply+1].board.w_pawn=and(position[ply+1].board.w_pawn,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_pawn_random[move.bit_move.to]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,w_pawn_random[move.bit_move.to]);
switch (move.bit_move.promote_to) {
case knight:
position[ply+1].board.w_knight=or(position[ply+1].board.w_knight,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_knight_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=2;
position[ply+1].board.white_pieces+=3;
position[ply+1].board.material_evaluation+=KNIGHT_VALUE;
break;
case bishop:
position[ply+1].board.w_bishop=or(position[ply+1].board.w_bishop,set_mask[move.bit_move.to]);
position[ply+1].board.bishops_queens=or(position[ply+1].board.bishops_queens,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_bishop_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=3;
position[ply+1].board.white_pieces+=3;
position[ply+1].board.material_evaluation+=BISHOP_VALUE;
break;
case rook:
position[ply+1].board.w_rook=or(position[ply+1].board.w_rook,set_mask[move.bit_move.to]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=4;
position[ply+1].board.white_pieces+=5;
position[ply+1].board.material_evaluation+=ROOK_VALUE;
break;
case queen:
position[ply+1].board.w_queen=or(position[ply+1].board.w_queen,set_mask[move.bit_move.to]);
position[ply+1].board.bishops_queens=or(position[ply+1].board.bishops_queens,set_mask[move.bit_move.to]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_queen_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=5;
position[ply+1].board.white_pieces+=9;
position[ply+1].board.material_evaluation+=QUEEN_VALUE;
break;
}
}
else
if (move.bit_move.to-move.bit_move.from == 16) position[ply+1].board.enpassant_target=set_mask[move.bit_move.to-8];
}
else {
position[ply+1].board.b_pawn=and(position[ply+1].board.b_pawn,clear_mask[move.bit_move.from]);
position[ply+1].board.b_pawn=or(position[ply+1].board.b_pawn,set_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_pawn_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_pawn_random[move.bit_move.to]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,b_pawn_random[move.bit_move.from]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,b_pawn_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=-1;
if (move.bit_move.captured_piece == 1) {
if(!and(position[ply+1].board.w_pawn,set_mask[move.bit_move.to])) {
position[ply+1].board.w_pawn=and(position[ply+1].board.w_pawn,clear_mask[move.bit_move.to+8]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.to+8]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_pawn_random[move.bit_move.to+8]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,w_pawn_random[move.bit_move.to+8]);
position[ply+1].board.board[move.bit_move.to+8]=0;
temp=position[ply+1].to.attacks[move.bit_move.to+8];
position[ply+1].board.material_evaluation-=PAWN_VALUE;
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.to+8]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.to+8]=mask(128);
move.bit_move.captured_piece=0;
/*
----------------------------------------------------------
| |
| now determine if removing this pawn will alter any of |
| the attack boards for sliding pieces that were blocked |
| at this square. if so, correct to.attacks[]. |
| |
----------------------------------------------------------
*/
occupied_squares=or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied);
temp_attacks=and(or(bishop_attacks[move.bit_move.to+8],rook_attacks[move.bit_move.to+8]),occupied_squares);
if (testv(temp_attacks)) {
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to+8]);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to+8]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to+8]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to+8]);
plus1dir=first_one(temp1);
plus7dir=first_one(temp7);
plus8dir=first_one(temp8);
plus9dir=first_one(temp9);
if (!tand(set_mask[plus1dir],position[ply+1].board.rooks_queens)) plus1dir=64;
if (!tand(set_mask[plus7dir],position[ply+1].board.bishops_queens)) plus7dir=64;
if (!tand(set_mask[plus8dir],position[ply+1].board.rooks_queens)) plus8dir=64;
if (!tand(set_mask[plus9dir],position[ply+1].board.bishops_queens)) plus9dir=64;
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to+8]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to+8]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to+8]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to+8]);
minus1dir=last_one(temp1);
minus7dir=last_one(temp7);
minus8dir=last_one(temp8);
minus9dir=last_one(temp9);
if (!tand(set_mask[minus1dir],position[ply+1].board.rooks_queens)) minus1dir=64;
if (!tand(set_mask[minus7dir],position[ply+1].board.bishops_queens)) minus7dir=64;
if (!tand(set_mask[minus8dir],position[ply+1].board.rooks_queens)) minus8dir=64;
if (!tand(set_mask[minus9dir],position[ply+1].board.bishops_queens)) minus9dir=64;
/*
----------------------------------------------------------
| |
| update attacks[plus1dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (plus1dir < 64) {
changed=and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=or(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
temp_attacks=and(position[ply+1].to.attacks[plus1dir],occupied_squares);
temp1=and(temp_attacks,mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=xor(position[ply+1].to.attacks[plus1dir],
mask_minus1dir[last_one(temp1)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus7dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (plus7dir < 64) {
changed=and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=or(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
temp_attacks=and(position[ply+1].to.attacks[plus7dir],occupied_squares);
temp7=and(temp_attacks,mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=xor(position[ply+1].to.attacks[plus7dir],
mask_minus7dir[last_one(temp7)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus8dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (plus8dir < 64) {
changed=and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=or(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
temp_attacks=and(position[ply+1].to.attacks[plus8dir],occupied_squares);
temp8=and(temp_attacks,mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=xor(position[ply+1].to.attacks[plus8dir],
mask_minus8dir[last_one(temp8)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus9dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (plus9dir < 64) {
changed=and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=or(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
temp_attacks=and(position[ply+1].to.attacks[plus9dir],occupied_squares);
temp9=and(temp_attacks,mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=xor(position[ply+1].to.attacks[plus9dir],
mask_minus9dir[last_one(temp9)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus1dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (minus1dir < 64) {
changed=and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=or(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
temp_attacks=and(position[ply+1].to.attacks[minus1dir],occupied_squares);
temp1=and(temp_attacks,mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=xor(position[ply+1].to.attacks[minus1dir],
mask_plus1dir[first_one(temp1)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus7dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (minus7dir < 64) {
changed=and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=or(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
temp_attacks=and(position[ply+1].to.attacks[minus7dir],occupied_squares);
temp7=and(temp_attacks,mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=xor(position[ply+1].to.attacks[minus7dir],
mask_plus7dir[first_one(temp7)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus8dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (minus8dir < 64) {
changed=and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=or(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
temp_attacks=and(position[ply+1].to.attacks[minus8dir],occupied_squares);
temp8=and(temp_attacks,mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=xor(position[ply+1].to.attacks[minus8dir],
mask_plus8dir[first_one(temp8)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus9dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (minus9dir < 64) {
changed=and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=or(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
temp_attacks=and(position[ply+1].to.attacks[minus9dir],occupied_squares);
temp9=and(temp_attacks,mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=xor(position[ply+1].to.attacks[minus9dir],
mask_plus9dir[first_one(temp9)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
}
}
}
/*
----------------------------------------------------------
| |
| if this is a pawn promotion, remove the pawn from the |
| pawn board. then update the correct piece board to |
| reflect piece just created. |
| |
----------------------------------------------------------
*/
if (move.bit_move.promote_to) {
position[ply+1].board.material_evaluation+=PAWN_VALUE;
position[ply+1].board.b_pawn=and(position[ply+1].board.b_pawn,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_pawn_random[move.bit_move.to]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,b_pawn_random[move.bit_move.to]);
switch (move.bit_move.promote_to) {
case knight:
position[ply+1].board.b_knight=or(position[ply+1].board.b_knight,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_knight_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=-2;
position[ply+1].board.black_pieces+=3;
position[ply+1].board.material_evaluation-=KNIGHT_VALUE;
break;
case bishop:
position[ply+1].board.b_bishop=or(position[ply+1].board.b_bishop,set_mask[move.bit_move.to]);
position[ply+1].board.bishops_queens=or(position[ply+1].board.bishops_queens,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_bishop_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=-3;
position[ply+1].board.black_pieces+=3;
position[ply+1].board.material_evaluation-=BISHOP_VALUE;
break;
case rook:
position[ply+1].board.b_rook=or(position[ply+1].board.b_rook,set_mask[move.bit_move.to]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=-4;
position[ply+1].board.black_pieces+=5;
position[ply+1].board.material_evaluation-=ROOK_VALUE;
break;
case queen:
position[ply+1].board.b_queen=or(position[ply+1].board.b_queen,set_mask[move.bit_move.to]);
position[ply+1].board.bishops_queens=or(position[ply+1].board.bishops_queens,set_mask[move.bit_move.to]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_queen_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.to]=-5;
position[ply+1].board.black_pieces+=9;
position[ply+1].board.material_evaluation-=QUEEN_VALUE;
break;
}
}
else
if (move.bit_move.from-move.bit_move.to == 16) position[ply+1].board.enpassant_target=set_mask[move.bit_move.to+8];
}
/*
----------------------------------------------------------
| |
| after updating the board, the next operation is to |
| remove all attacks from square [from] since the piece |
| is gone. do this before to.attacks[from] is lost. |
| then, update the to.attacks[] array to reflect the |
| new board position. for pawns, it's easy: simply |
| zero to.attacks[from] and copy pawn_attacks[to] into |
| to.attacks[to]. after computing a new to.attacks[to] |
| this information has to be propagated to from.attacks |
| to reflect the attacks on other squares attacked by |
| this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
if (wtm) {
position[ply+1].to.attacks[move.bit_move.from]=mask(128);
position[ply+1].to.attacks[move.bit_move.to]=w_pawn_attacks[move.bit_move.to];
}
else {
position[ply+1].to.attacks[move.bit_move.from]=mask(128);
position[ply+1].to.attacks[move.bit_move.to]=b_pawn_attacks[move.bit_move.to];
}
/*
----------------------------------------------------------
| |
| if we just promoted a pawn, then the attack boards |
| must be updated to reflect the attacks from the newly |
| created piece. |
| |
----------------------------------------------------------
*/
if (move.bit_move.promote_to) {
switch (move.bit_move.promote_to) {
case knight:
position[ply+1].to.attacks[move.bit_move.to]=knight_attacks[move.bit_move.to];
break;
case bishop:
occupied=or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied);
position[ply+1].to.attacks[move.bit_move.to]=bishop_attacks[move.bit_move.to];
temp_attacks=and(position[ply+1].to.attacks[move.bit_move.to],occupied);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus7dir[first_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus9dir[first_one(temp9)]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus7dir[last_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus9dir[last_one(temp9)]);
break;
case rook:
occupied=or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied);
position[ply+1].to.attacks[move.bit_move.to]=rook_attacks[move.bit_move.to];
temp_attacks=and(position[ply+1].to.attacks[move.bit_move.to],occupied);
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus1dir[first_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus8dir[first_one(temp8)]);
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus1dir[last_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus8dir[last_one(temp8)]);
break;
case queen:
occupied=or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied);
position[ply+1].to.attacks[move.bit_move.to]=or(bishop_attacks[move.bit_move.to],rook_attacks[move.bit_move.to]);
temp_attacks=and(position[ply+1].to.attacks[move.bit_move.to],occupied);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus7dir[first_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus9dir[first_one(temp9)]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus7dir[last_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus9dir[last_one(temp9)]);
temp_attacks=and(position[ply+1].to.attacks[move.bit_move.to],occupied);
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus1dir[first_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus8dir[first_one(temp8)]);
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus1dir[last_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus8dir[last_one(temp8)]);
break;
}
}
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
break;
/*
********************************************************************************
* *
* make knight moves. *
* *
********************************************************************************
*/
case knight:
if (wtm) {
position[ply+1].board.w_knight=and(position[ply+1].board.w_knight,clear_mask[move.bit_move.from]);
position[ply+1].board.w_knight=or(position[ply+1].board.w_knight,set_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_knight_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_knight_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=2;
}
else {
position[ply+1].board.b_knight=and(position[ply+1].board.b_knight,clear_mask[move.bit_move.from]);
position[ply+1].board.b_knight=or(position[ply+1].board.b_knight,set_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_knight_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_knight_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=-2;
}
/*
----------------------------------------------------------
| |
| after updating the board, the next operation is to |
| remove all attacks from square [from] since the piece |
| is gone. do this before to.attacks[from] is lost. |
| then, update the to.attacks[] array to reflect the |
| new board position[ply+1]. for knights, it's easy: |
| zero to.attacks[from] and copy knight_attacks[to] into |
| to.attacks[to]. after computing a new to.attacks[to] |
| this information has to be propagated to from.attacks |
| to reflect the attacks on other squares attacked by |
| this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.from]=mask(128);
position[ply+1].to.attacks[move.bit_move.to]=knight_attacks[move.bit_move.to];
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
break;
/*
********************************************************************************
* *
* make bishop moves. *
* *
********************************************************************************
*/
case bishop:
position[ply+1].board.bishops_queens=or(and(position[ply+1].board.bishops_queens,
clear_mask[move.bit_move.from]),set_mask[move.bit_move.to]);
if (wtm) {
position[ply+1].board.w_bishop=and(position[ply+1].board.w_bishop,clear_mask[move.bit_move.from]);
position[ply+1].board.w_bishop=or(position[ply+1].board.w_bishop,set_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_bishop_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_bishop_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=3;
}
else {
position[ply+1].board.b_bishop=and(position[ply+1].board.b_bishop,clear_mask[move.bit_move.from]);
position[ply+1].board.b_bishop=or(position[ply+1].board.b_bishop,set_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_bishop_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_bishop_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=-3;
}
/*
----------------------------------------------------------
| |
| after updating the board, the next operation is to |
| remove all attacks from square [from] since the piece |
| is gone. do this before to.attacks[from] is lost. |
| first, initialize to.attacks[to] to the squares that |
| are attacked by a bishop on an open board. use this |
| same bit-mask anded with the complement of the |
| occupied squares which placed zeros on those squares |
| that "block" the bishop from moving in that direction. |
| then, we and this mask with the complement of the |
| squares attacked by a bishop which produces a bit mask |
| with ones in every position except for these squares |
| which "block" the bishop. By complementing this mask, |
| we now have ones on the blocking squares and zeros |
| everywhere else which lets us use the leading_zeros |
| instruction (or function) to locate these squares. |
| after identifying these blocking squares, it is then |
| trivial to use a pre-computed mask to "lop off" each |
| diagonal beyond the point where it is first blocked. |
| after computing a new to.attacks[to] this information |
| has to be propagated to from.attacks to reflect the |
| attacks on other squares attacked by this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.from]=mask(128);
position[ply+1].to.attacks[move.bit_move.to]=bishop_attacks[move.bit_move.to];
temp_attacks=and(bishop_attacks[move.bit_move.to],
or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied));
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus7dir[first_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus9dir[first_one(temp9)]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus7dir[last_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus9dir[last_one(temp9)]);
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
break;
/*
********************************************************************************
* *
* make rook moves. the only special case handling required is to determine *
* if x_castle is non-zero [x=w or b based on side to move]. if it is non- *
* zero, the value must be corrected if either rook is moving from its *
* original square, so that castling with that rook becomes impossible. *
* *
********************************************************************************
*/
case rook:
position[ply+1].board.rooks_queens=or(and(position[ply+1].board.rooks_queens,
clear_mask[move.bit_move.from]),set_mask[move.bit_move.to]);
if (wtm) {
position[ply+1].board.w_rook=and(position[ply+1].board.w_rook,clear_mask[move.bit_move.from]);
position[ply+1].board.w_rook=or(position[ply+1].board.w_rook,set_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=4;
if (position[ply+1].board.w_castle) {
if (!move.bit_move.from)
position[ply+1].board.w_castle=position[ply+1].board.w_castle & 1;
else if (move.bit_move.from == 7)
position[ply+1].board.w_castle=position[ply+1].board.w_castle & 2;
}
}
else {
position[ply+1].board.b_rook=and(position[ply+1].board.b_rook,clear_mask[move.bit_move.from]);
position[ply+1].board.b_rook=or(position[ply+1].board.b_rook,set_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=-4;
if (position[ply+1].board.b_castle) {
if (move.bit_move.from == 56)
position[ply+1].board.b_castle=position[ply+1].board.b_castle & 1;
else if (move.bit_move.from == 63)
position[ply+1].board.b_castle=position[ply+1].board.b_castle & 2;
}
}
/*
----------------------------------------------------------
| |
| after updating the board, the next operation is to |
| remove all attacks from square [from] since the piece |
| is gone. do this before to.attacks[from] is lost. |
| first, initialize to.attacks[to] to the squares that |
| are attacked by a rook on an open board. use this |
| same bit-mask anded with the complement of the |
| occupied squares which placed zeros on those squares |
| that "block" the rook from moving in that direction. |
| then, we and this mask with the complement of the |
| squares attacked by a rook which produces a bit mask |
| with ones in every position except for these squares |
| which "block" the rook. By complementing this mask, |
| we now have ones on the blocking squares and zeros |
| everywhere else which lets us use the leading_zeros |
| instruction (or function) to locate these squares. |
| after identifying these blocking squares, it is then |
| trivial to use a pre-computed mask to "lop off" each |
| ray beyond the point where it is first blocked. |
| after computing a new to.attacks[to] this information |
| has to be propagated to from.attacks to reflect the |
| attacks on other squares attacked by this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.from]=mask(128);;
position[ply+1].to.attacks[move.bit_move.to]=rook_attacks[move.bit_move.to];
temp_attacks=and(rook_attacks[move.bit_move.to],
or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied));
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus1dir[first_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus8dir[first_one(temp8)]);
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus1dir[last_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus8dir[last_one(temp8)]);
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
break;
/*
********************************************************************************
* *
* make queen moves *
* *
********************************************************************************
*/
case queen:
position[ply+1].board.bishops_queens=or(and(position[ply+1].board.bishops_queens,
clear_mask[move.bit_move.from]),set_mask[move.bit_move.to]);
position[ply+1].board.rooks_queens=or(and(position[ply+1].board.rooks_queens,
clear_mask[move.bit_move.from]),set_mask[move.bit_move.to]);
if (wtm) {
position[ply+1].board.w_queen=and(position[ply+1].board.w_queen,clear_mask[move.bit_move.from]);
position[ply+1].board.w_queen=or(position[ply+1].board.w_queen,set_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_queen_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_queen_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=5;
}
else {
position[ply+1].board.b_queen=and(position[ply+1].board.b_queen,clear_mask[move.bit_move.from]);
position[ply+1].board.b_queen=or(position[ply+1].board.b_queen,set_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_queen_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_queen_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=-5;
}
/*
----------------------------------------------------------
| |
| after updating the board, the next operation is to |
| remove all attacks from square [from] since the piece |
| is gone. do this before to.attacks[from] is lost. |
| first, initialize to.attacks[to] to the squares that |
| are attacked by a queen on an open board. use this |
| same bit-mask anded with the complement of the |
| occupied squares which placed zeros on those squares |
| that "block" the queen from moving in that direction. |
| then, we and this mask with the complement of the |
| squares attacked by a bishop which produces a bit mask |
| with ones in every position except for these squares |
| which "block" the queen. By complementing this mask, |
| we now have ones on the blocking squares and zeros |
| everywhere else which lets us use the leading_zeros |
| instruction (or function) to locate these squares. |
| after identifying these blocking squares, it is then |
| trivial to use a pre-computed mask to "lop off" each |
| ray beyond the point where it is first blocked. |
| after computing a new to.attacks[to] this information |
| has to be propagated to from.attacks to reflect the |
| attacks on other squares attacked by this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.from]=mask(128);;
position[ply+1].to.attacks[move.bit_move.to]=or(bishop_attacks[move.bit_move.to],
rook_attacks[move.bit_move.to]);
temp_attacks=and(position[ply+1].to.attacks[move.bit_move.to],
or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied));
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to]);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus1dir[first_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus7dir[first_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus8dir[first_one(temp8)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus9dir[first_one(temp9)]);
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus1dir[last_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus7dir[last_one(temp7)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus8dir[last_one(temp8)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus9dir[last_one(temp9)]);
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
break;
/*
********************************************************************************
* *
* make king moves. the only special case is castling, which is indicated *
* by from=4, to=6 for o-o as an example. the king is moving from e1-g1 *
* which is normally illegal. in this case, the correct rook is also moved. *
* the to.attacks update is simple also, we simply re-compute the attack *
* vector for the rook on its new square. since both pieces are on the edge *
* of the board and other pieces can only exist on the side where the rook *
* moves to, updating the attack vector for other pieces is also trivial. *
* *
* note that moving the king in any direction resets the x_castle [x=w or b] *
* flag indicating that castling is no longer possible in *this* position. *
* *
********************************************************************************
*/
case king:
if (wtm) {
position[ply+1].board.w_king=and(position[ply+1].board.w_king,clear_mask[move.bit_move.from]);
position[ply+1].board.w_king=or(position[ply+1].board.w_king,set_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_king_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_king_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=6;
position[ply+1].board.w_castle=0;
if (abs(move.bit_move.to-move.bit_move.from) == 2) {
if (move.bit_move.to == 6) {
position[ply+1].board.w_rook=and(position[ply+1].board.w_rook,clear_mask[7]);
position[ply+1].board.w_rook=or(position[ply+1].board.w_rook,set_mask[5]);
position[ply+1].board.rooks_queens=and(position[ply+1].board.rooks_queens,
clear_mask[7]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,
set_mask[5]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[7]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[5]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[7]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[5]);
position[ply+1].board.board[7]=0;
position[ply+1].board.board[5]=4;
}
else {
position[ply+1].board.w_rook=and(position[ply+1].board.w_rook,clear_mask[0]);
position[ply+1].board.w_rook=or(position[ply+1].board.w_rook,set_mask[3]);
position[ply+1].board.rooks_queens=and(position[ply+1].board.rooks_queens,
clear_mask[0]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,
set_mask[3]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[0]);
position[ply+1].board.w_occupied=or(position[ply+1].board.w_occupied,set_mask[3]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[0]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[3]);
position[ply+1].board.board[0]=0;
position[ply+1].board.board[3]=4;
}
}
}
else {
position[ply+1].board.b_king=and(position[ply+1].board.b_king,clear_mask[move.bit_move.from]);
position[ply+1].board.b_king=or(position[ply+1].board.b_king,set_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.from]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_king_random[move.bit_move.from]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_king_random[move.bit_move.to]);
position[ply+1].board.board[move.bit_move.from]=0;
position[ply+1].board.board[move.bit_move.to]=-6;
position[ply+1].board.b_castle=0;
if (abs(move.bit_move.to-move.bit_move.from) == 2) {
if (move.bit_move.to == 62) {
position[ply+1].board.b_rook=and(position[ply+1].board.b_rook,clear_mask[63]);
position[ply+1].board.b_rook=or(position[ply+1].board.b_rook,set_mask[61]);
position[ply+1].board.rooks_queens=and(position[ply+1].board.rooks_queens,
clear_mask[63]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,
set_mask[61]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[63]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[61]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[63]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[61]);
position[ply+1].board.board[63]=0;
position[ply+1].board.board[61]=-4;
}
else {
position[ply+1].board.b_rook=and(position[ply+1].board.b_rook,clear_mask[56]);
position[ply+1].board.b_rook=or(position[ply+1].board.b_rook,set_mask[59]);
position[ply+1].board.rooks_queens=and(position[ply+1].board.rooks_queens,
clear_mask[56]);
position[ply+1].board.rooks_queens=or(position[ply+1].board.rooks_queens,
set_mask[59]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[56]);
position[ply+1].board.b_occupied=or(position[ply+1].board.b_occupied,set_mask[59]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[56]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[59]);
position[ply+1].board.board[56]=0;
position[ply+1].board.board[59]=-4;
}
}
}
/*
----------------------------------------------------------
| |
| after updating the board, the next operation is to |
| remove all attacks from square [from] since the piece |
| is gone. do this before to.attacks[from] is lost. |
| then, update the to.attacks[] array to reflect the |
| new board position. for normal king moves, it's easy: |
| zero to.attacks[from] and copy king_attacks[to] into |
| to.attacks[to]. after computing a new to.attacks[to] |
| this information has to be propagated to from.attacks |
| to reflect the attacks on other squares attacked by |
| this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.from]=mask(128);
position[ply+1].to.attacks[move.bit_move.to]=king_attacks[move.bit_move.to];
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
if(abs(move.bit_move.to-move.bit_move.from) != 2) break;
/*
----------------------------------------------------------
| |
| got a castling move. since we moved a rook as well, |
| we need to update its to.attacks[] value also. |
| |
----------------------------------------------------------
*/
if (wtm)
if (move.bit_move.to == 6) {
move.bit_move.from=7;
move.bit_move.to=5;
}
else {
move.bit_move.from=0;
move.bit_move.to=3;
}
else
if(move.bit_move.to == 62){
move.bit_move.from=63;
move.bit_move.to=61;
}
else{
move.bit_move.from=56;
move.bit_move.to=59;
}
/*
----------------------------------------------------------
| |
| first, initialize to.attacks[to] to the squares that |
| are attacked by a rook on an open board. use this |
| same bit-mask anded with the complement of the |
| occupied squares which placed zeros on those squares |
| that "block" the rook from moving in that direction. |
| then, we and this mask with the complement of the |
| squares attacked by a rook which produces a bit mask |
| with ones in every position except for these squares |
| which "block" the rook. By complementing this mask, |
| we now have ones on the blocking squares and zeros |
| everywhere else which lets us use the leading_zeros |
| instruction (or function) to locate these squares. |
| after identifying these blocking squares, it is then |
| trivial to use a pre-computed mask to "lop off" each |
| ray beyond the point where it is first blocked. |
| after computing a new to.attacks[to] this information |
| has to be propagated to from.attacks to reflect the |
| attacks on other squares attacked by this [to] square. |
| |
----------------------------------------------------------
*/
temp=position[ply+1].to.attacks[move.bit_move.from];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[move.bit_move.from]);
temp=and(temp,clear_mask[setbit]);
}
position[ply+1].to.attacks[move.bit_move.from]=mask(128);;
position[ply+1].to.attacks[move.bit_move.to]=rook_attacks[move.bit_move.to];
temp_attacks=and(position[ply+1].to.attacks[move.bit_move.to],
or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied));
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to]);
plus1_piece=first_one(temp1);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus1dir[first_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_plus8dir[first_one(temp8)]);
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to]);
minus1_piece=last_one(temp1);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus1dir[last_one(temp1)]);
position[ply+1].to.attacks[move.bit_move.to]=xor(position[ply+1].to.attacks[move.bit_move.to],
mask_minus8dir[last_one(temp8)]);
if (tand(position[ply+1].board.rooks_queens,set_mask[plus1_piece])) {
changed=and(position[ply+1].to.attacks[plus1_piece],mask_minus1dir[plus1_piece]);
position[ply+1].to.attacks[plus1_piece]=or(position[ply+1].to.attacks[plus1_piece],mask_minus1dir[plus1_piece]);
position[ply+1].to.attacks[plus1_piece]=xor(position[ply+1].to.attacks[plus1_piece],mask_minus1dir[move.bit_move.to]);
changed=xor(changed,and(position[ply+1].to.attacks[plus1_piece],mask_minus1dir[plus1_piece]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus1_piece]);
changed=and(changed,clear_mask[setbit]);
}
}
else if (tand(position[ply+1].board.rooks_queens,set_mask[minus1_piece])) {
changed=and(position[ply+1].to.attacks[minus1_piece],mask_plus1dir[minus1_piece]);
position[ply+1].to.attacks[minus1_piece]=or(position[ply+1].to.attacks[minus1_piece],mask_plus1dir[minus1_piece]);
position[ply+1].to.attacks[minus1_piece]=xor(position[ply+1].to.attacks[minus1_piece],mask_plus1dir[move.bit_move.to]);
changed=xor(changed,and(position[ply+1].to.attacks[minus1_piece],mask_plus1dir[minus1_piece]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus1_piece]);
changed=and(changed,clear_mask[setbit]);
}
}
temp=position[ply+1].to.attacks[move.bit_move.to];
while (testv(temp)) {
setbit=first_one(temp);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[move.bit_move.to]);
temp=and(temp,clear_mask[setbit]);
}
break;
/*
********************************************************************************
* *
* if moving_piece > 6, then this is a "null" move that needs no updating *
* of any attack information. *
* *
********************************************************************************
*/
case null_piece:
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,null_random);
return;
}
/*
********************************************************************************
* *
* now it is time to "gracefully" remove a piece from the game board since it *
* is being captured. this includes updating the board structure. note that *
* to.attacks[] and from.attacks[] have already been updated and that nothing *
* needs to be done to them here. *
* *
********************************************************************************
*/
if(move.bit_move.captured_piece) {
if (move.bit_move.promote_to) move.bit_move.moving_piece=move.bit_move.promote_to;
switch (move.bit_move.captured_piece) {
/*
----------------------------------------------------------
| |
| remove a captured pawn. |
| |
----------------------------------------------------------
*/
case pawn:
if (wtm) {
position[ply+1].board.b_pawn=and(position[ply+1].board.b_pawn,clear_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_pawn_random[move.bit_move.to]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,b_pawn_random[move.bit_move.to]);
position[ply+1].board.material_evaluation+=PAWN_VALUE;
}
else {
position[ply+1].board.w_pawn=and(position[ply+1].board.w_pawn,clear_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_pawn_random[move.bit_move.to]);
position[ply+1].board.pawn_hash_key=xor(position[ply+1].board.pawn_hash_key,w_pawn_random[move.bit_move.to]);
position[ply+1].board.material_evaluation-=PAWN_VALUE;
}
break;
/*
----------------------------------------------------------
| |
| remove a captured knight. |
| |
----------------------------------------------------------
*/
case knight:
if (wtm) {
position[ply+1].board.b_knight=and(position[ply+1].board.b_knight,clear_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_knight_random[move.bit_move.to]);
position[ply+1].board.black_pieces-=3;
position[ply+1].board.material_evaluation+=KNIGHT_VALUE;
}
else {
position[ply+1].board.w_knight=and(position[ply+1].board.w_knight,clear_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_knight_random[move.bit_move.to]);
position[ply+1].board.white_pieces-=3;
position[ply+1].board.material_evaluation-=KNIGHT_VALUE;
}
break;
/*
----------------------------------------------------------
| |
| remove a captured bishop. |
| |
----------------------------------------------------------
*/
case bishop:
if ((move.bit_move.moving_piece != bishop) && (move.bit_move.moving_piece != queen))
position[ply+1].board.bishops_queens=and(position[ply+1].board.bishops_queens,clear_mask[move.bit_move.to]);
if (wtm) {
position[ply+1].board.b_bishop=and(position[ply+1].board.b_bishop,clear_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_bishop_random[move.bit_move.to]);
position[ply+1].board.black_pieces-=3;
position[ply+1].board.material_evaluation+=BISHOP_VALUE;
}
else {
position[ply+1].board.w_bishop=and(position[ply+1].board.w_bishop,clear_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_bishop_random[move.bit_move.to]);
position[ply+1].board.white_pieces-=3;
position[ply+1].board.material_evaluation-=BISHOP_VALUE;
}
break;
/*
----------------------------------------------------------
| |
| remove a captured rook. |
| |
----------------------------------------------------------
*/
case rook:
if ((move.bit_move.moving_piece != rook) && (move.bit_move.moving_piece != queen))
position[ply+1].board.rooks_queens=and(position[ply+1].board.rooks_queens,clear_mask[move.bit_move.to]);
if (wtm) {
position[ply+1].board.b_rook=and(position[ply+1].board.b_rook,clear_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_rook_random[move.bit_move.to]);
if (move.bit_move.to == 56) position[ply+1].board.b_castle=position[ply+1].board.b_castle&1;
if (move.bit_move.to == 63) position[ply+1].board.b_castle=position[ply+1].board.b_castle&2;
position[ply+1].board.black_pieces-=5;
position[ply+1].board.material_evaluation+=ROOK_VALUE;
}
else {
position[ply+1].board.w_rook=and(position[ply+1].board.w_rook,clear_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_rook_random[move.bit_move.to]);
if (move.bit_move.to == 0) position[ply+1].board.w_castle=position[ply+1].board.w_castle&1;
if (move.bit_move.to == 7) position[ply+1].board.w_castle=position[ply+1].board.w_castle&2;
position[ply+1].board.white_pieces-=5;
position[ply+1].board.material_evaluation-=ROOK_VALUE;
}
break;
/*
----------------------------------------------------------
| |
| remove a captured queen. |
| |
----------------------------------------------------------
*/
case queen:
if ((move.bit_move.moving_piece != bishop) && (move.bit_move.moving_piece != queen))
position[ply+1].board.bishops_queens=and(position[ply+1].board.bishops_queens,clear_mask[move.bit_move.to]);
if ((move.bit_move.moving_piece != rook) && (move.bit_move.moving_piece != queen))
position[ply+1].board.rooks_queens=and(position[ply+1].board.rooks_queens,clear_mask[move.bit_move.to]);
if (wtm) {
position[ply+1].board.b_queen=and(position[ply+1].board.b_queen,clear_mask[move.bit_move.to]);
position[ply+1].board.b_occupied=and(position[ply+1].board.b_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,b_queen_random[move.bit_move.to]);
position[ply+1].board.black_pieces-=9;
position[ply+1].board.material_evaluation+=QUEEN_VALUE;
}
else {
position[ply+1].board.w_queen=and(position[ply+1].board.w_queen,clear_mask[move.bit_move.to]);
position[ply+1].board.w_occupied=and(position[ply+1].board.w_occupied,clear_mask[move.bit_move.to]);
position[ply+1].board.hash_key=xor(position[ply+1].board.hash_key,w_queen_random[move.bit_move.to]);
position[ply+1].board.white_pieces-=9;
position[ply+1].board.material_evaluation-=QUEEN_VALUE;
}
break;
/*
----------------------------------------------------------
| |
| remove a captured king. [this is an error condition] |
| |
----------------------------------------------------------
*/
case king:
printf("captured a king\n");
printf("piece=%d,from=%d,to=%d,captured=%d\n",move.bit_move.moving_piece,move.bit_move.from,move.bit_move.to,move.bit_move.captured_piece);
printf("ply=%d\n",ply);
exit(101);
}
}
/*
********************************************************************************
* *
* we get here after we have completely cleaned up the moving piece. now we *
* are ready to update the to.attacks[sq] values for any sliding piece that *
* directly attacks either [from] or [to]. the algorithm is both simple and *
* fast. for the [from] square, pretend to be a queen and look down each of *
* the 8 move directions (or rays). for diagonals, if we encounter a bishop *
* or queen, then we need to fix its to.attacks[] value since it was *
* unblocked by vacating the [from] square. *
* *
* [to] is handled exactly the same way unless the move is a capture. if so, *
* no action is required since [to] is still occupied, just by a different *
* piece of the opposite side. *
* *
********************************************************************************
*/
/*
----------------------------------------------------------
| |
| the first step is to determine if a sliding piece on |
| [from] would attack a sliding piece. if so, then a |
| sliding piece is attacking this square and needs to |
| have its corresponding to.attacks[] adjusted, but only |
| on the diagonal that radiates toward [from] rather |
| than re-computing all diagonals. |
| |
----------------------------------------------------------
*/
occupied_squares=or(position[ply+1].board.w_occupied,position[ply+1].board.b_occupied);
temp_attacks=and(or(bishop_attacks[move.bit_move.from],rook_attacks[move.bit_move.from]),occupied_squares);
if (testv(temp_attacks)) {
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.from]);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.from]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.from]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.from]);
plus1dir=first_one(temp1);
plus7dir=first_one(temp7);
plus8dir=first_one(temp8);
plus9dir=first_one(temp9);
if (!tand(set_mask[plus1dir],position[ply+1].board.rooks_queens)) plus1dir=64;
if (!tand(set_mask[plus7dir],position[ply+1].board.bishops_queens)) plus7dir=64;
if (!tand(set_mask[plus8dir],position[ply+1].board.rooks_queens)) plus8dir=64;
if (!tand(set_mask[plus9dir],position[ply+1].board.bishops_queens)) plus9dir=64;
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.from]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.from]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.from]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.from]);
minus1dir=last_one(temp1);
minus7dir=last_one(temp7);
minus8dir=last_one(temp8);
minus9dir=last_one(temp9);
if (!tand(set_mask[minus1dir],position[ply+1].board.rooks_queens)) minus1dir=64;
if (!tand(set_mask[minus7dir],position[ply+1].board.bishops_queens)) minus7dir=64;
if (!tand(set_mask[minus8dir],position[ply+1].board.rooks_queens)) minus8dir=64;
if (!tand(set_mask[minus9dir],position[ply+1].board.bishops_queens)) minus9dir=64;
/*
----------------------------------------------------------
| |
| update attacks[plus1dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (plus1dir < 64) {
changed=and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=or(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
temp_attacks=and(position[ply+1].to.attacks[plus1dir],occupied_squares);
temp1=and(temp_attacks,mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=xor(position[ply+1].to.attacks[plus1dir],
mask_minus1dir[last_one(temp1)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus7dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (plus7dir < 64) {
changed=and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=or(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
temp_attacks=and(position[ply+1].to.attacks[plus7dir],occupied_squares);
temp7=and(temp_attacks,mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=xor(position[ply+1].to.attacks[plus7dir],
mask_minus7dir[last_one(temp7)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus8dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (plus8dir < 64) {
changed=and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=or(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
temp_attacks=and(position[ply+1].to.attacks[plus8dir],occupied_squares);
temp8=and(temp_attacks,mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=xor(position[ply+1].to.attacks[plus8dir],
mask_minus8dir[last_one(temp8)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus9dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (plus9dir < 64) {
changed=and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=or(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
temp_attacks=and(position[ply+1].to.attacks[plus9dir],occupied_squares);
temp9=and(temp_attacks,mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=xor(position[ply+1].to.attacks[plus9dir],
mask_minus9dir[last_one(temp9)]);
changed=xor(changed,and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[plus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus1dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (minus1dir < 64) {
changed=and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=or(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
temp_attacks=and(position[ply+1].to.attacks[minus1dir],occupied_squares);
temp1=and(temp_attacks,mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=xor(position[ply+1].to.attacks[minus1dir],
mask_plus1dir[first_one(temp1)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus7dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (minus7dir < 64) {
changed=and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=or(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
temp_attacks=and(position[ply+1].to.attacks[minus7dir],occupied_squares);
temp7=and(temp_attacks,mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=xor(position[ply+1].to.attacks[minus7dir],
mask_plus7dir[first_one(temp7)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus8dir] since the rook/queen on |
| that square now attacks more squares because the piece |
| blocking that ray has moved away. |
| |
----------------------------------------------------------
*/
if (minus8dir < 64) {
changed=and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=or(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
temp_attacks=and(position[ply+1].to.attacks[minus8dir],occupied_squares);
temp8=and(temp_attacks,mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=xor(position[ply+1].to.attacks[minus8dir],
mask_plus8dir[first_one(temp8)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus9dir] since the bishop/queen on |
| that square now attacks more squares because the piece |
| blocking that diagonal has moved away. |
| |
----------------------------------------------------------
*/
if (minus9dir < 64) {
changed=and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=or(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
temp_attacks=and(position[ply+1].to.attacks[minus9dir],occupied_squares);
temp9=and(temp_attacks,mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=xor(position[ply+1].to.attacks[minus9dir],
mask_plus9dir[first_one(temp9)]);
changed=xor(changed,and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=or(position[ply+1].from.attacks[setbit],set_mask[minus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
}
/*
----------------------------------------------------------
| |
| the first step is to determine if a sliding piece on |
| [to] would attack a sliding piece. if so, then a |
| sliding piece is attacking this square and needs to |
| have its corresponding to.attacks[] adjusted, but only |
| on the diagonal that radiates toward [to] rather than |
| re-computing all diagonals. |
| |
----------------------------------------------------------
*/
if (!move.bit_move.captured_piece) {
temp_attacks=and(or(bishop_attacks[move.bit_move.to],rook_attacks[move.bit_move.to]),occupied_squares);
if (testv(temp_attacks)) {
temp1=and(temp_attacks,mask_plus1dir[move.bit_move.to]);
temp7=and(temp_attacks,mask_plus7dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_plus8dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_plus9dir[move.bit_move.to]);
plus1dir=first_one(temp1);
plus7dir=first_one(temp7);
plus8dir=first_one(temp8);
plus9dir=first_one(temp9);
if (!tand(set_mask[plus1dir],position[ply+1].board.rooks_queens)) plus1dir=64;
if (!tand(set_mask[plus7dir],position[ply+1].board.bishops_queens)) plus7dir=64;
if (!tand(set_mask[plus8dir],position[ply+1].board.rooks_queens)) plus8dir=64;
if (!tand(set_mask[plus9dir],position[ply+1].board.bishops_queens)) plus9dir=64;
temp1=and(temp_attacks,mask_minus1dir[move.bit_move.to]);
temp7=and(temp_attacks,mask_minus7dir[move.bit_move.to]);
temp8=and(temp_attacks,mask_minus8dir[move.bit_move.to]);
temp9=and(temp_attacks,mask_minus9dir[move.bit_move.to]);
minus1dir=last_one(temp1);
minus7dir=last_one(temp7);
minus8dir=last_one(temp8);
minus9dir=last_one(temp9);
if (!tand(set_mask[minus1dir],position[ply+1].board.rooks_queens)) minus1dir=64;
if (!tand(set_mask[minus7dir],position[ply+1].board.bishops_queens)) minus7dir=64;
if (!tand(set_mask[minus8dir],position[ply+1].board.rooks_queens)) minus8dir=64;
if (!tand(set_mask[minus9dir],position[ply+1].board.bishops_queens)) minus9dir=64;
/*
----------------------------------------------------------
| |
| update attacks[plus1dir] since the rook/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (plus1dir < 64) {
changed=and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]);
position[ply+1].to.attacks[plus1dir]=and(position[ply+1].to.attacks[plus1dir],
compl(mask_minus1dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[plus1dir],mask_minus1dir[plus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[plus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus7dir] since the bishop/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (plus7dir < 64) {
changed=and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]);
position[ply+1].to.attacks[plus7dir]=and(position[ply+1].to.attacks[plus7dir],
compl(mask_minus7dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[plus7dir],mask_minus7dir[plus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[plus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus8dir] since the rook/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (plus8dir < 64) {
changed=and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]);
position[ply+1].to.attacks[plus8dir]=and(position[ply+1].to.attacks[plus8dir],
compl(mask_minus8dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[plus8dir],mask_minus8dir[plus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[plus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[plus9dir] since the bishop/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (plus9dir < 64) {
changed=and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]);
position[ply+1].to.attacks[plus9dir]=and(position[ply+1].to.attacks[plus9dir],
compl(mask_minus9dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[plus9dir],mask_minus9dir[plus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[plus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus1dir] since the rook/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (minus1dir < 64) {
changed=and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]);
position[ply+1].to.attacks[minus1dir]=and(position[ply+1].to.attacks[minus1dir],
compl(mask_plus1dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[minus1dir],mask_plus1dir[minus1dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[minus1dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus7dir] since the bishop/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (minus7dir < 64) {
changed=and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]);
position[ply+1].to.attacks[minus7dir]=and(position[ply+1].to.attacks[minus7dir],
compl(mask_plus7dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[minus7dir],mask_plus7dir[minus7dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[minus7dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus8dir] since the rook/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (minus8dir < 64) {
changed=and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]);
position[ply+1].to.attacks[minus8dir]=and(position[ply+1].to.attacks[minus8dir],
compl(mask_plus8dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[minus8dir],mask_plus8dir[minus8dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[minus8dir]);
changed=and(changed,clear_mask[setbit]);
}
}
/*
----------------------------------------------------------
| |
| update attacks[minus9dir] since the bishop/queen now |
| located on that square now attacks fewer squares |
| because a piece is now blocking that ray. |
| |
----------------------------------------------------------
*/
if (minus9dir < 64) {
changed=and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]);
position[ply+1].to.attacks[minus9dir]=and(position[ply+1].to.attacks[minus9dir],
compl(mask_plus9dir[move.bit_move.to]));
changed=xor(changed,and(position[ply+1].to.attacks[minus9dir],mask_plus9dir[minus9dir]));
while (testv(changed)) {
setbit=first_one(changed);
position[ply+1].from.attacks[setbit]=and(position[ply+1].from.attacks[setbit],clear_mask[minus9dir]);
changed=and(changed,clear_mask[setbit]);
}
}
}
}
return;
}
/*
********************************************************************************
* *
* make_move_root() is used to make a move at the root of the game tree, *
* before any searching is done. it uses make_move() to execute the move, *
* but then copies the resulting position back to position[0], the actual *
* board position. it handles the special-case of the draw-by-repetition *
* rule by maintaining a list of previous positions, which is reset each time *
* a non-reversible (pawn move or capture move) is made. *
* *
********************************************************************************
*/
void make_move_root(int ply, CHESS_MOVE move, int wtm)
{
/*
----------------------------------------------------------
| |
| first, make the move and replace position[0] with the |
| new position. |
| |
----------------------------------------------------------
*/
make_move(0,move,wtm);
/*
----------------------------------------------------------
| |
| now, if this is a non-reversible move, reset the |
| repetition list pointer to start the count over. |
| |
----------------------------------------------------------
*/
if ((move.bit_move.moving_piece == 1) ||
(move.bit_move.captured_piece) ||
(position[0].board.w_castle != position[1].board.w_castle) ||
(position[0].board.b_castle != position[1].board.b_castle)) {
if (wtm)
last_irreversible_move=-1;
else {
last_irreversible_move=0;
repetition_list[0]=mask(128);
}
}
position[0]=position[1];
repetition_list[++last_irreversible_move]=position[0].board.hash_key;

Reply all
Reply to author
Forward
0 new messages