Author: Dan Homan
Date: 15:19:39 04/01/01
Go up one level in this thread
I wrote this pretty quickly (and a long time ago), so I'll need to look
at it carefully to be sure, but I think that the "bestval" variable takes
care of the stand-pat option. The algorithm keeps track of the best
achievable score and returns that rather than the score at the end of the
complete exchange.
- Dan
P.S. I've been very busy with work and haven't thought about computer chess in
months, so I am quite rusty -- even on my own code!
On April 01, 2001 at 10:29:42, Gian-Carlo Pascutto wrote:
>Hi all,
>
>in the process of using EXChess's source to design my SEE
>after, I ran into something which I suspect is either a bug
>in EXChess, or a misunderstanding from my part about how SEE
>works.
>
>Below is the critical section.
>
>int swap(int sq, position p, int side, int from)
>{
> int val = value[p.sq[sq].type], lsq;
>
> // initalize attackers arrays
> attackers[0][0].v = 0; attcks[0] = 0;
> attackers[1][0].v = 0; attcks[1] = 0;
>
> // put in the first capture
> attackers[side][0].v = value[p.sq[from].type];
> attcks[side]++;
> p.sq[from] = empty;
>
> // find all the attcks on sq
> dia_attcks(sq, 0, &p);
> knt_attcks(sq, &p);
> hor_attcks(sq, 0, &p);
>
> attackers[0][attcks[0]].v = 0;
> attackers[1][attcks[1]].v = 0;
>
> // swap off the attacks, starting with other side
> // and with the least value
> int swapside = side^1;
> int count[2] = { 0, 0 }, bestval;
>
> if(attcks[swapside]) bestval = val - attackers[side][0].v;
> else bestval = val;
>
> count[side]++; // for the first capture
>
> while(count[swapside] < attcks[swapside]) {
> SSort(&attackers[swapside][count[swapside]],
>&attackers[swapside][attcks[swapside]-1]);
> if(swapside == side) {
> val += attackers[swapside^1][count[swapside^1]-1].v;
> if(count[side^1] >= attcks[side^1] && val > bestval)
> bestval = val;
> } else {
> val -= attackers[swapside^1][count[swapside^1]-1].v;
> if(val > bestval)
> { bestval= val; }
> }
> // square from which the capture came
> lsq = attackers[swapside][count[swapside]].s;
> // add in any revealed attacks due to this capture
> if((FILE(lsq) == FILE(sq) || RANK(lsq) == RANK(sq)) && lsq)
> hor_attcks(sq, lsq, &p);
> else if(p.sq[lsq].type != KNIGHT && lsq) dia_attcks(sq, lsq, &p);
> count[swapside]++;
> swapside ^= 1;
> }
>
> return bestval;
>}
>
>If you look at this code you see the program keeps exchanging off
>attackers untill one side is exhausted. New best values are remembered
>if the side that was originally to move can stand pat either after
>a recapture by the opponent, or after a capture when we know the
>opponent has no more recaptures.
>
>I think this will cause problems when, for example, a bishop and a
>pawn are attacking a pawn defended by a queen.
>
>Correct would be:
>
>pawn takes pawn, standpat, score +100
>
>but I think the algorithm does:
>
>pawn takes pawn, queen takes pawn, bishop takes queen and standpat, score +900
>
>because it does not allow a standpat for the opponent.
>
>Am I missing something here? I added the (IMHO) corrected algorithm
>to Sjeng and the results aren't as good as I hoped they would be, even
>if using SEE to prune losing captures.
>
>My SEE function is below (note that I don't do Xray attacks yet):
>
>int see(int color, int square, int from)
>{
> int sside;
> int caps[2];
> int value;
> int origpiece;
> int ourbestvalue;
> int hisbestvalue;
>
> /* reset data */
> see_num_attackers[WHITE] = 0;
> see_num_attackers[BLACK] = 0;
>
> /* remove original capturer from board, exposing his first xray-er */
> origpiece = board[from];
> board[from] = npiece;
>
> see_num_attackers[color]++;
> see_attackers[color][0].piece = origpiece;
> see_attackers[color][0].square = from;
>
> /* calculate all attackers to square */
> setup_attackers(square);
>
> /* initially we gain the piece we are capturing */
> value = abs(material[board[square]]);
>
> /* free capture ? */
> if (!see_num_attackers[!color])
> {
> board[from] = origpiece;
> return value;
> }
> else
> {
> /* we can never get a higher SEE score than the piece we just captured */
> /* so that is the current best value for our opponent */
> /* we arent sure of anything yet, so -INF */
> hisbestvalue = value;
> ourbestvalue = -INF;
> }
>
> caps[color] = 1;
> caps[!color] = 0;
>
> /* start with recapture */
> sside = !color;
>
> /* continue as long as there are attackers */
> while (caps[sside] < see_num_attackers[sside])
> {
> /* resort capturelist of sside to put lowest attacker in next position */
> findlowest(sside, caps[sside]);
>
> if (sside == color)
> {
> /* capturing more */
> /* we capture the opponents recapturer */
> value += abs(material[see_attackers[!sside][caps[!sside]-1].piece]);
>
> /* if the opp ran out of attackers we can stand pat now! */
> if (see_num_attackers[!sside] <= caps[!sside] && value > ourbestvalue)
> ourbestvalue = value;
>
> /* our opponent can always stand pat now */
> if (value < hisbestvalue) hisbestvalue = value;
> }
> else
> {
> /* recapture by opp */
> /* we lose whatever we captured with in last iteration */
> value -= abs(material[see_attackers[!sside][caps[!sside]-1].piece]);
>
> /* we can stand pat if we want to now */
> /* our best score goes up, opponent is unaffected */
>
> if (value > ourbestvalue)
> {
> ourbestvalue = value;
> }
>
> if (see_num_attackers[!sside] <= caps[!sside] && value < hisbestvalue)
> hisbestvalue = value;
> }
>
> /* keep track of capture count */
> caps[sside]++;
>
> /* switch sides */
> sside ^= 1;
>
> }
>
> /* restore capturer */
> board[from] = origpiece;
>
> /* we return our best score now, keeping in mind that
> it can never we better than the best for our opponent */
> return (ourbestvalue > hisbestvalue) ? hisbestvalue : ourbestvalue;
>}
>
>--
>GCP
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.