1 /*
2     Sjeng - a chess variants playing program
3     Copyright (C) 2001 Gian-Carlo Pascutto
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19     File: see.c
20     Purpose: do static exchange evaluation
21 
22 */
23 
24 #include "sjeng.h"
25 #include "extvars.h"
26 
27 typedef struct
28 {
29   int piece;
30   int square;
31 } see_data;
32 
33 see_data see_attackers[2][16];
34 int see_num_attackers[2];
35 
setup_attackers(int square)36 void setup_attackers (int square) {
37 
38   /* this function calculates attack information for a square */
39 
40   static const int rook_o[4] = {12, -12, 1, -1};
41   static const int bishop_o[4] = {11, -11, 13, -13};
42   static const int knight_o[8] = {10, -10, 14, -14, 23, -23, 25, -25};
43   register int a_sq, b_sq, i;
44   int numw = see_num_attackers[WHITE], numb = see_num_attackers[BLACK];
45 
46   /* rook-style moves: */
47   for (i = 0; i < 4; i++)
48     {
49       a_sq = square + rook_o[i];
50       b_sq = board[a_sq];
51 
52       /* the king can attack from one square away: */
53       if (b_sq == wking)
54 	{
55 	  see_attackers[WHITE][numw].piece = b_sq;
56 	  see_attackers[WHITE][numw].square = a_sq;
57 	  numw++;
58 	  break;
59 	}
60       else if (b_sq == bking)
61 	{
62 	  see_attackers[BLACK][numb].piece = b_sq;
63 	  see_attackers[BLACK][numb].square = a_sq;
64 	  numb++;
65 	  break;
66 	}
67       else
68 	{
69 	  /* otherwise, check for sliding pieces: */
70 	  while (b_sq != frame)
71 	    {
72 	      if (b_sq == wrook || b_sq == wqueen)
73 		{
74 		  see_attackers[WHITE][numw].piece = b_sq;
75 		  see_attackers[WHITE][numw].square = a_sq;
76 		  numw++;
77 		  break;
78 		}
79 	      else if (b_sq == brook || b_sq == bqueen)
80 		{
81 		  see_attackers[BLACK][numb].piece = b_sq;
82 		  see_attackers[BLACK][numb].square = a_sq;
83 		  numb++;
84 		  break;
85 		}
86 	      else if (b_sq != npiece) break;
87 	      a_sq += rook_o [i];
88 	      b_sq = board[a_sq];
89 	    }
90 	}
91     }
92 
93   /* bishop-style moves: */
94   for (i = 0; i < 4; i++)
95     {
96       a_sq = square + bishop_o[i];
97       b_sq = board[a_sq];
98       /* check for pawn attacks: */
99       if (b_sq == wpawn && i%2)
100 	{
101 	  see_attackers[WHITE][numw].piece = b_sq;
102 	  see_attackers[WHITE][numw].square = a_sq;
103 	  numw++;
104 	  break;
105 	}
106       else if (b_sq == bpawn && !(i%2))
107 	{
108 	  see_attackers[BLACK][numb].piece = b_sq;
109 	  see_attackers[BLACK][numb].square = a_sq;
110 	  numb++;
111 	  break;
112 	}
113       /* the king can attack from one square away: */
114       else if (b_sq == wking)
115 	{
116 	  see_attackers[WHITE][numw].piece = b_sq;
117 	  see_attackers[WHITE][numw].square = a_sq;
118 	  numw++;
119 	  break;
120 	}
121       else if (b_sq == bking)
122 	{
123 	  see_attackers[BLACK][numb].piece = b_sq;
124 	  see_attackers[BLACK][numb].square = a_sq;
125 	  numb++;
126 	  break;
127 	}
128       else
129 	{
130 	  while (b_sq != frame) {
131 	    if (b_sq == wbishop || b_sq == wqueen)
132 	      {
133 	        see_attackers[WHITE][numw].piece = b_sq;
134 	        see_attackers[WHITE][numw].square = a_sq;
135 		numw++;
136 		break;
137 	      }
138 	    else if (b_sq == bbishop || b_sq == bqueen)
139 	      {
140 	        see_attackers[BLACK][numb].piece = b_sq;
141 		see_attackers[BLACK][numb].square = a_sq;
142 		numb++;
143 		break;
144 	      }
145 	    else if (b_sq != npiece) break;
146 	    a_sq += bishop_o [i];
147 	    b_sq = board[a_sq];
148 	  }
149 	}
150     }
151 
152   /* knight-style moves: */
153   for (i = 0; i < 8; i++)
154     {
155       a_sq = square + knight_o[i];
156       b_sq = board[a_sq];
157       if (b_sq == wknight)
158 	{
159 	  see_attackers[WHITE][numw].piece = b_sq;
160 	  see_attackers[WHITE][numw].square = a_sq;
161 	  numw++;
162 	}
163       else if (b_sq == bknight)
164 	{
165 	  see_attackers[BLACK][numb].piece = b_sq;
166 	  see_attackers[BLACK][numb].square = a_sq;
167 	  numb++;
168 	}
169     }
170 
171   see_num_attackers[WHITE] = numw;
172   see_num_attackers[BLACK] = numb;
173 }
174 
findlowest(int color,int next)175 void findlowest(int color, int next)
176 {
177   int lowestp;
178   int lowestv;
179   see_data swap;
180   int i;
181 
182   lowestp = next;
183   lowestv = abs(material[see_attackers[color][next].piece]);
184 
185   for (i = next; i < see_num_attackers[color]; i++)
186     {
187       if (abs(material[see_attackers[color][i].piece]) < lowestv)
188 	{
189 	  lowestp = i;
190 	  lowestv = abs(material[see_attackers[color][i].piece]);
191 	}
192     }
193 
194   /* lowestp now points to the lowest attacker, which we swap with next */
195   swap = see_attackers[color][next];
196   see_attackers[color][next] = see_attackers[color][lowestp];
197   see_attackers[color][lowestp] = swap;
198 }
199 
200 
see(int color,int square,int from)201 int see(int color, int square, int from)
202 {
203   int sside;
204   int caps[2];
205   int value;
206   int origpiece;
207   int ourbestvalue;
208   int hisbestvalue;
209 
210   /* reset data */
211   see_num_attackers[WHITE] = 0;
212   see_num_attackers[BLACK] = 0;
213 
214   /* remove original capturer from board, exposing his first xray-er */
215   origpiece = board[from];
216   board[from] = npiece;
217 
218   see_num_attackers[color]++;
219   see_attackers[color][0].piece = origpiece;
220   see_attackers[color][0].square = from;
221 
222   /* calculate all attackers to square */
223   setup_attackers(square);
224 
225   /* initially we gain the piece we are capturing */
226   value = abs(material[board[square]]);
227 
228   /* free capture ? */
229   if (!see_num_attackers[!color])
230     {
231       board[from] = origpiece;
232       return value;
233     }
234   else
235     {
236       /* we can never get a higher SEE score than the piece we just captured */
237       /* so that is the current best value for our opponent */
238       /* we arent sure of anything yet, so -INF */
239       hisbestvalue = value;
240       ourbestvalue = -INF;
241     }
242 
243   caps[color] = 1;
244   caps[!color] = 0;
245 
246   /* start with recapture */
247   sside = !color;
248 
249   /* continue as long as there are attackers */
250   while (caps[sside] < see_num_attackers[sside])
251     {
252       /* resort capturelist of sside to put lowest attacker in next position */
253       findlowest(sside, caps[sside]);
254 
255       if (sside == color)
256 	{
257 	  /* capturing more */
258 	  /* we capture the opponents recapturer */
259 	  value += abs(material[see_attackers[!sside][caps[!sside]-1].piece]);
260 
261 	  /* if the opp ran out of attackers we can stand pat now! */
262 	   if (see_num_attackers[!sside] <= caps[!sside] && value > ourbestvalue)
263 	    ourbestvalue = value;
264 
265 	  /* our opponent can always stand pat now */
266 	  if (value < hisbestvalue) hisbestvalue = value;
267 	}
268       else
269 	{
270 	  /* recapture by opp */
271 	  /* we lose whatever we captured with in last iteration */
272 	  value -= abs(material[see_attackers[!sside][caps[!sside]-1].piece]);
273 
274 	  /* we can stand pat if we want to now */
275 	  /* our best score goes up, opponent is unaffected */
276 
277 	  if (value > ourbestvalue)
278 	    {
279 	      ourbestvalue = value;
280 	    }
281 
282 	  if (see_num_attackers[!sside] <= caps[!sside] && value < hisbestvalue)
283 	    hisbestvalue = value;
284 	}
285 
286       /* keep track of capture count */
287       caps[sside]++;
288 
289       /* switch sides */
290       sside ^= 1;
291 
292     }
293 
294   /* restore capturer */
295   board[from] = origpiece;
296 
297   /* we return our best score now, keeping in mind that
298      it can never we better than the best for our opponent */
299   return (ourbestvalue > hisbestvalue) ? hisbestvalue : ourbestvalue;
300 }
301