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