Author: Gian-Carlo Pascutto
Date: 07:29:42 04/01/01
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.