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.01 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.