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 28static int lcentral[144] = { 290,0,0,0,0,0,0,0,0,0,0,0, 300,0,0,0,0,0,0,0,0,0,0,0, 310,0,-20,-15,-15,-15,-15,-15,-15,-20,0,0, 320,0,-15,0,3,5,5,3,0,-15,0,0, 330,0,-15,0,15,15,15,15,0,-15,0,0, 340,0,-15,0,15,30,30,15,0,-15,0,0, 350,0,-15,0,15,30,30,15,0,-15,0,0, 360,0,-15,0,15,15,15,15,0,-15,0,0, 370,0,-15,0,3,5,5,3,0,-15,0,0, 380,0,-20,-15,-15,-15,-15,-15,-15,-20,0,0, 390,0,0,0,0,0,0,0,0,0,0,0, 400,0,0,0,0,0,0,0,0,0,0,0}; 41 42static 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 59static 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 77static 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 90static 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 106static 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 120int32_t 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 int32_t 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