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