1 /*
2 Sjeng - a chess variants playing program
3 Copyright (C) 2000-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: leval.c
20 Purpose: functions for evaluating positions in losers chess
21
22 */
23
24 #include "sjeng.h"
25 #include "extvars.h"
26 #include "protos.h"
27
28 static int lcentral[144] = {
29 0,0,0,0,0,0,0,0,0,0,0,0,
30 0,0,0,0,0,0,0,0,0,0,0,0,
31 0,0,-20,-15,-15,-15,-15,-15,-15,-20,0,0,
32 0,0,-15,0,3,5,5,3,0,-15,0,0,
33 0,0,-15,0,15,15,15,15,0,-15,0,0,
34 0,0,-15,0,15,30,30,15,0,-15,0,0,
35 0,0,-15,0,15,30,30,15,0,-15,0,0,
36 0,0,-15,0,15,15,15,15,0,-15,0,0,
37 0,0,-15,0,3,5,5,3,0,-15,0,0,
38 0,0,-20,-15,-15,-15,-15,-15,-15,-20,0,0,
39 0,0,0,0,0,0,0,0,0,0,0,0,
40 0,0,0,0,0,0,0,0,0,0,0,0};
41
l_bishop_mobility(int square)42 static int l_bishop_mobility(int square)
43 {
44 register int l;
45 register int m = 0;
46
47 for (l = square-13; board[l] == npiece; l-=13)
48 m++;
49 for (l = square-11; board[l] == npiece; l-=11)
50 m++;
51 for (l = square+11; board[l] == npiece; l+=11)
52 m++;
53 for (l = square+13; board[l] == npiece; l+=13)
54 m++;
55
56 return m;
57 }
58
l_rook_mobility(int square)59 static int l_rook_mobility(int square)
60 {
61 register int l;
62 register int m = 0;
63
64 for (l = square-12; board[l] == npiece; l-=12)
65 m++;
66 for (l = square-1; board[l] == npiece; l-=1)
67 m++;
68 for (l = square+1; board[l] == npiece; l+=1)
69 m++;
70 for (l = square+12; board[l] == npiece; l+=12)
71 m++;
72
73 return m;
74 }
75
76
l_knight_mobility(int square)77 static int l_knight_mobility(int square)
78 {
79 static const int knight_o[8] = {10, -10, 14, -14, 23, -23, 25, -25};
80 register int d, m = 0;
81
82 for (d = 0; d < 8; d++)
83 {
84 if (board[square + knight_o[d]] == npiece) m++;
85 }
86
87 return m;
88 }
89
l_pawn_mobility(int square)90 static int l_pawn_mobility(int square)
91 {
92 register int m = 0;
93
94 if (board[square] == wpawn)
95 {
96 if (board[square + 12] == npiece) m++;
97 }
98 else
99 {
100 if (board[square - 12] == npiece) m++;
101 }
102
103 return m;
104 }
105
l_king_mobility(int square)106 static int l_king_mobility(int square)
107 {
108 static const int king_o[8] = {13, 12, 11, 1, -1, -11, -12, -13};
109 register int d, m = 0;
110
111 for (d = 0; d < 8; d++)
112 {
113 if (board[square + king_o[d]] == npiece) m++;
114 }
115
116 return m;
117 }
118
119
losers_eval(void)120 long int losers_eval (void) {
121
122 /* return a score for the current middlegame position: */
123 int srank, pawn_file, pawns[2][11], white_back_pawn[11], black_back_pawn[11];
124 int isolated, backwards;
125 int i, a, j;
126 long int score = 0;
127 int in_cache;
128 int wp = 0, bp = 0;
129 int wks, bks;
130 int wpassp = 0, bpassp = 0;
131 int wpawns = 0, bpawns = 0;
132
133 in_cache = 0;
134
135 checkECache(&score, &in_cache);
136
137 if(in_cache)
138 {
139 if (white_to_move == 1) return score;
140 return -score;
141 }
142
143 /* initialize the pawns array, (files offset by one to use dummy files in
144 order to easier determine isolated status) and also initialize the
145 arrays keeping track of the rank of the most backward pawn: */
146 memset (pawns, 0, sizeof (pawns));
147 for (i = 0; i < 11; i++) {
148 white_back_pawn[i] = 7;
149 black_back_pawn[i] = 2;
150 }
151 for (j = 1, a = 1; (a <= piece_count); j++) {
152 i = pieces[j];
153
154 if (!i)
155 continue;
156 else
157 a++;
158
159 assert((i > 0) && (i < 145));
160
161 pawn_file = file (i)+1;
162 srank = rank (i);
163 if (board[i] == wpawn) {
164 pawns[1][pawn_file]++;
165 if (srank < white_back_pawn[pawn_file]) {
166 white_back_pawn[pawn_file] = srank;
167 }
168 }
169 else if (board[i] == bpawn) {
170 pawns[0][pawn_file]++;
171 if (srank > black_back_pawn[pawn_file]) {
172 black_back_pawn[pawn_file] = srank;
173 }
174 }
175 }
176
177 /* loop through the board, adding material value, as well as positional
178 bonuses for all pieces encountered: */
179 for (j = 1, a = 1; (a <= piece_count); j++) {
180 i = pieces[j];
181
182 if (!i)
183 continue;
184 else
185 a++;
186
187 switch (board[i]) {
188 case (wpawn):
189 wp++;
190 wpawns++;
191 score += lcentral[i];
192 score += l_pawn_mobility(i) << 2;
193 score += (rank(i) - 2) * 8;
194 isolated = FALSE;
195 backwards = FALSE;
196
197 /* check for backwards pawns: */
198 if (white_back_pawn[pawn_file+1] > srank
199 && white_back_pawn[pawn_file-1] > srank) {
200 score -= 8;
201 backwards = TRUE;
202 /* check to see if it is furthermore isolated: */
203 if (!pawns[1][pawn_file+1] && !pawns[1][pawn_file-1]) {
204 score -= 12;
205 isolated = TRUE;
206 }
207 }
208
209 /* give weak, exposed pawns a penalty (not as much as in the midgame,
210 since there may be no pieces to take advantage of it): */
211 if (!pawns[0][pawn_file]) {
212 if (backwards) score -= 5;
213 if (isolated) score -= 8;
214 }
215
216 /* give doubled, trippled, etc.. pawns a penalty (bigger in the
217 endgame, since they will become big targets): */
218 if (pawns[1][pawn_file] > 1)
219 score -= 8*(pawns[1][pawn_file]-1);
220
221 /* give bonuses for passed pawns (bigger in the endgame since passed
222 pawns are what wins the endgame): */
223 if (!pawns[0][pawn_file] && srank >= black_back_pawn[pawn_file-1] &&
224 srank >= black_back_pawn[pawn_file+1]) {
225 score += 25 + 10*(rank(i)-2);
226
227 if (rank(i) == 7) score += 50;
228
229 wpassp++;
230
231 /* outside passer ? */
232 if (file(i) == 1 || file(i) == 8)
233 score += 4 + 2*(rank(i)-2);
234
235 /* give an extra bonus if a connected, passed pawn: */
236 if (!isolated)
237 {
238 score += 24;
239 }
240 }
241
242 /* check for pawn islands */
243 if (!pawns[1][pawn_file-1])
244 score -= 5;
245
246 break;
247
248 case (bpawn):
249 bp++;
250 bpawns++;
251 score -= lcentral[i];
252 score -= l_pawn_mobility(i) << 2;
253 score -= (7 - rank(i)) * 8;
254 isolated = FALSE;
255 backwards = FALSE;
256
257 /* in general, bonuses/penalties in the endgame evaluation will be
258 higher, since pawn structure becomes more important for the
259 creation of passed pawns */
260
261 /* check for backwards pawns: */
262 if (black_back_pawn[pawn_file+1] < srank
263 && black_back_pawn[pawn_file-1] < srank) {
264 score += 8;
265 backwards = TRUE;
266 /* check to see if it is furthermore isolated: */
267 if (!pawns[0][pawn_file+1] && !pawns[0][pawn_file-1]) {
268 score += 12;
269 isolated = TRUE;
270 }
271 }
272
273 /* give weak, exposed pawns a penalty (not as much as in the midgame,
274 since there may be no pieces to take advantage of it): */
275 if (!pawns[1][pawn_file]) {
276 if (backwards) score += 5;
277 if (isolated) score += 8;
278 }
279
280 /* give doubled, trippled, etc.. pawns a penalty (bigger in the
281 endgame, since they will become big targets): */
282 if (pawns[0][pawn_file] > 1)
283 score += 8*(pawns[0][pawn_file]-1);
284
285 /* give bonuses for passed pawns (bigger in the endgame since passed
286 pawns are what wins the endgame): */
287 if (!pawns[1][pawn_file] && srank <= white_back_pawn[pawn_file-1] &&
288 srank <= white_back_pawn[pawn_file+1]) {
289 score -= 25 + 10*(7-rank(i));
290
291 if (rank(i) == 2) score -= 50;
292
293 bpassp++;
294
295 /* outside passer ? */
296 if (file(i) == 1 || file(i) == 8)
297 score -= 4 + 2*(7-rank(i));
298
299 /* give an extra bonus if a connected, passed pawn: */
300 if (!isolated)
301 {
302 score -= 24;
303 }
304 }
305
306 if (!pawns[0][pawn_file-1])
307 score += 5;
308
309 break;
310
311 case (wrook):
312 wp++;
313 score += l_rook_mobility(i) << 2;
314 score += lcentral[i];
315 break;
316
317 case (brook):
318 bp++;
319 score -= l_rook_mobility(i) << 2;
320 score -= lcentral[i];
321 break;
322
323 case (wbishop):
324 wp++;
325 score += l_bishop_mobility(i) << 2;
326 score += lcentral[i];
327 break;
328
329 case (bbishop):
330 bp++;
331 score -= l_bishop_mobility(i) << 2;
332 score -= lcentral[i];
333 break;
334
335 case (wknight):
336 wp++;
337 score += lcentral[i] << 1;
338 score += l_knight_mobility(i) << 2;
339 break;
340
341 case (bknight):
342 bp++;
343 score -= lcentral[i] << 1;
344 score -= l_knight_mobility(i) << 2;
345 break;
346
347 case (wqueen):
348 wp++;
349 score += l_bishop_mobility(i) << 1;
350 score += l_rook_mobility(i) << 1;
351 score += lcentral[i];
352 break;
353
354 case (bqueen):
355 bp++;
356 score -= l_bishop_mobility(i) << 1;
357 score -= l_rook_mobility(i) << 1;
358 score -= lcentral[i];
359 break;
360
361 case (wking):
362 /* being in center is BAD */
363 wks = lcentral[i] << 1;
364 score += l_king_mobility(i);
365 break;
366
367 case (bking):
368 /* being in center is BAD */
369 bks = lcentral[i] << 1;
370 score -= l_king_mobility(i);
371 break;
372 }
373 }
374
375 if (wp + bp > 10)
376 {
377 score -= wks - bks;
378 }
379
380 if (abs(Material) <= 900)
381 {
382 score += Material;
383 }
384 else
385 {
386 /* one side has a huge advantage, which could
387 * become problematic */
388 /* only apply this to self, we assume somebody
389 * else can handle this just fine */
390
391 /* I would swear the colors are reversed here,
392 * but it works this way and not otherwise :) */
393
394 /* disable this if we have passers...else they'll
395 just sit on last rank */
396
397 if (Material > 0 && comp_color == !WHITE && !wpassp)
398 {
399 score += 1800 - Material;
400 }
401 else if (Material < 0 && comp_color == !BLACK && !bpassp)
402 {
403 score += -(1800 + Material);
404 }
405 else
406 {
407 score += Material;
408 }
409 }
410
411 if (!wpawns) score += 200;
412 else if (!bpawns) score -= 200;
413
414 if (!wp) score = INF;
415 else if (!bp) score = -INF;
416
417 storeECache(score);
418
419 /* adjust for color: */
420 if (white_to_move == 1) {
421 return score;
422 }
423 else {
424 return -score;
425 }
426
427 }
428