1/*
2    Sjeng - a chess variants playing program
3    Copyright (C) 2000 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: seval.c
20    Purpose: functions for evaluating positions (suicide chess)
21
22*/
23
24#include "sjeng.h"
25#include "extvars.h"
26#include "protos.h"
27
28static int scentral[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,-10,-10,-10,-10,-10,-10,-20,0,0,
320,0,-10,0,3,5,5,3,0,-10,0,0,
330,0,-10,2,15,15,15,15,2,-10,0,0,
340,0,-10,7,15,25,25,15,7,-10,0,0,
350,0,-10,7,15,25,25,15,7,-10,0,0,
360,0,-10,2,15,15,15,15,2,-10,0,0,
370,0,-10,0,3,5,5,3,0,-10,0,0,
380,0,-20,-10,-10,-10,-10,-10,-10,-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 const int rook_o[4] = {12, -12, 1, -1};
43static const int bishop_o[4] = {11, -11, 13, -13};
44static const int knight_o[8] = {10, -10, 14, -14, 23, -23, 25, -25};
45
46static int s_bishop_mobility(int square)
47{
48  register int l;
49  register int m = 0;
50
51  for (l = square-13; board[l] == npiece; l-=13)
52    m++;
53  for (l = square-11; board[l] == npiece; l-=11)
54    m++;
55  for (l = square+11; board[l] == npiece; l+=11)
56    m++;
57  for (l = square+13; board[l] == npiece; l+=13)
58    m++;
59
60  return m << 2;
61}
62
63static int s_rook_mobility(int square)
64{
65  register int l;
66  register int m = 0;
67
68  for (l = square-12; board[l] == npiece; l-=12)
69    m++;
70  for (l = square-1; board[l] == npiece; l-=1)
71    m++;
72  for (l = square+1; board[l] == npiece; l+=1)
73    m++;
74  for (l = square+12; board[l] == npiece; l+=12)
75    m++;
76
77  return m << 2;
78}
79
80static int s_knight_mobility(int square)
81{
82  static const int knight_o[8] = {10, -10, 14, -14, 23, -23, 25, -25};
83  register int d, m = 0;
84
85  for (d = 0; d < 8; d++)
86    {
87      if (board[square + knight_o[d]] == npiece) m++;
88    }
89
90  return m << 2;
91}
92
93static int s_pawn_mobility(int square)
94{
95  register int m = 0;
96
97  if (board[square] == wpawn)
98    {
99      if (board[square + 12] == npiece) m++;
100    }
101  else
102    {
103      if (board[square - 12] == npiece) m++;
104    }
105
106  return m << 3;
107}
108
109static int s_king_mobility(int square)
110{
111  static const int king_o[8] = {13, 12, 11, 1, -1, -11, -12, -13};
112  register int d, m = 0;
113
114  for (d = 0; d < 8; d++)
115    {
116      if (board[square + king_o[d]] == npiece) m++;
117    }
118
119  return m << 2;
120}
121
122static int black_saccers(int square)
123{
124  register int ndir, a_sq;
125  register int basq, i;
126  register int f = FALSE;
127
128  /* for white pawn on square, any black
129   * pieces that can sac themselves to it? */
130
131  /* check for case where is_attacked fails
132     because pawns dont move to their attacks */
133
134  if (board[square + 24] == bpawn ||
135      board[square + 22] == bpawn ||
136      board[square + 26] == bpawn)
137    {
138      return 0;
139    }
140
141  /* ok, now check pawn moves */
142
143  if ((rank(square) < 6)
144      && (board[square + 25] == bpawn
145	  ||
146	  board[square + 23] == bpawn))
147    {
148      f = TRUE;
149    }
150  else if (rank(square) == 4 &&
151	   (board[square + 35] == bpawn ||
152	   board[square + 37] == bpawn))
153    {
154      f = TRUE;
155    }
156
157  if (!f)
158    {
159      f = (is_attacked(square + 11, 0) ? 1 : 0);
160    }
161  if (!f)
162    {
163      f = (is_attacked(square + 13, 0) ? 2 : 0);
164    }
165
166  if (!f)
167    {
168      return 0;
169    }
170  else
171    {
172      /* black can sac, but is the saccer defended ? */
173
174      if (f == 1)
175	{
176	  if (calc_attackers(square + 11, 0) > 1)
177	    {
178	      /* yep */
179	      return 0;
180	    }
181	  else
182	    {
183	      /* nope */
184	      return 30;
185	    }
186	}
187      else
188	{
189	  if (calc_attackers(square + 13, 0) > 1)
190	    {
191	      return 0;
192	    }
193	  else
194	    {
195	      return 30;
196	    }
197
198	}
199    }
200
201}
202
203static int white_saccers(int square)
204{
205  /* for black pawn on square, any black
206   * pieces that can sac themselves to it? */
207
208  register int ndir, a_sq;
209  register int basq, i;
210  register int f = FALSE;
211
212  /* for white pawn on square, any black
213   * pieces that can sac themselves to it? */
214
215  /* check for case where is_attacked fails
216     because pawns dont move to their attacks */
217
218  if (board[square - 24] == wpawn ||
219      board[square - 22] == wpawn ||
220      board[square - 26] == wpawn)
221    {
222      return 0;
223    }
224
225  /* ok, now check pawn moves */
226
227  if ((rank(square) > 3)
228      && (board[square - 25] == wpawn
229	  ||
230	  board[square - 23] == wpawn))
231    {
232      f = TRUE;
233    }
234  else if (rank(square) == 5 &&
235	   (board[square - 35] == wpawn ||
236	   board[square - 37] == wpawn))
237    {
238      f = TRUE;
239    }
240
241  if (!f)
242    {
243      f = (is_attacked(square - 11, 1) ? 1 : 0);
244    }
245  if (!f)
246    {
247      f = (is_attacked(square - 13, 1) ? 2 : 0);
248    }
249
250  if (!f)
251    {
252      return 0;
253    }
254  else
255    {
256      /* black can sac, but is the saccer defended ? */
257
258      if (f == 1)
259	{
260	  if (calc_attackers(square - 11, 1) > 1)
261	    {
262	      /* yep */
263	      return 0;
264	    }
265	  else
266	    {
267	      /* nope */
268	      return 30;
269	    }
270	}
271      else
272	{
273	  if (calc_attackers(square - 13, 1) > 1)
274	    {
275	      return 0;
276	    }
277	  else
278	    {
279	      return 30;
280	    }
281
282	}
283    }
284
285}
286
287int32_t suicide_eval (void) {
288
289  /* select the appropriate eval() routine: */
290  return (suicide_mid_eval ());
291}
292
293int32_t suicide_mid_eval (void) {
294
295  /* return a score for the current middlegame position: */
296
297  int srank, pawn_file, pawns[2][11], white_back_pawn[11], black_back_pawn[11];
298  int isolated, backwards, i, a, j;
299  int32_t score = 0;
300  int in_cache;
301  int wb = 0, bb = 0, wbc = 0, bbc = 0;
302  int wk = 0, bk = 0, wr = 0, br = 0;
303  int wn = 0, bn = 0, wp = 0, bp = 0;
304
305  in_cache = 0;
306
307  checkECache(&score, &in_cache);
308
309  if(in_cache)
310    {
311      if (white_to_move == 1) return score;
312      return -score;
313    }
314
315  score = Material;
316
317  /* initialize the pawns array, (files offset by one to use dummy files in
318     order to easier determine isolated status) and also initialize the
319     arrays keeping track of the rank of the most backward pawn: */
320  memset (pawns, 0, sizeof (pawns));
321  for (i = 0; i < 11; i++) {
322    white_back_pawn[i] = 7;
323    black_back_pawn[i] = 2;
324  }
325  for (j = 1, a = 1; (a <= piece_count); j++) {
326     i = pieces[j];
327
328    if (!i)
329      continue;
330    else
331      a++;
332
333    assert((i > 0) && (i < 145));
334
335    pawn_file = file (i)+1;
336    srank = rank (i);
337    if (board[i] == wpawn) {
338      pawns[1][pawn_file]++;
339      if (srank < white_back_pawn[pawn_file]) {
340	white_back_pawn[pawn_file] = srank;
341      }
342    }
343    else if (board[i] == bpawn) {
344      pawns[0][pawn_file]++;
345      if (srank > black_back_pawn[pawn_file]) {
346	black_back_pawn[pawn_file] = srank;
347      }
348    }
349  }
350
351  /* loop through the board, adding material value, as well as positional
352     bonuses for all pieces encountered: */
353  for (j = 1, a = 1; (a <= piece_count); j++) {
354    i = pieces[j];
355
356    if (!i)
357      continue;
358    else
359      a++;
360
361    pawn_file = file (i)+1;
362    srank = rank (i);
363    switch (board[i]) {
364      case (wpawn):
365	score += scentral[i];
366	score += s_pawn_mobility(i);
367        score -= black_saccers(i);
368	wp++;
369	isolated = FALSE;
370	backwards = FALSE;
371
372	/* check for backwards pawns: */
373	if (white_back_pawn[pawn_file+1] > srank
374	    && white_back_pawn[pawn_file-1] > srank) {
375	  score -= 8;
376	  backwards = TRUE;
377	  /* check to see if it is furthermore isolated: */
378	  if (!pawns[1][pawn_file+1] && !pawns[1][pawn_file-1]) {
379	    score -= 12;
380	    isolated = TRUE;
381	  }
382	}
383
384	/* give weak, exposed pawns a penalty (not as much as in the midgame,
385	   since there may be no pieces to take advantage of it): */
386	if (!pawns[0][pawn_file]) {
387	  if (backwards) score -= 5;
388	  if (isolated) score -= 8;
389	}
390
391	/* give doubled, trippled, etc.. pawns a penalty (bigger in the
392	   endgame, since they will become big targets): */
393	if (pawns[1][pawn_file] > 1)
394	  score -= 15*(pawns[1][pawn_file]-1);
395
396	/* give bonuses for passed pawns (bigger in the endgame since passed
397	   pawns are what wins the endgame): */
398	if (!pawns[0][pawn_file] && srank >= black_back_pawn[pawn_file-1] &&
399	    srank >= black_back_pawn[pawn_file+1]) {
400	  score += 30 + 3*(rank(i)-2);
401
402	  /* outside passer ? */
403	  if (file(i) == 1 || file(i) == 8)
404	    score += 4 + 2*(rank(i)-2);
405
406	  /* give an extra bonus if a connected, passed pawn: */
407	  if (!isolated)
408	    {
409	      score += 6;
410	    }
411	}
412
413	/* check for pawn islands */
414	if (!pawns[1][pawn_file-1])
415	  score -= 20;
416
417	break;
418
419     case (bpawn):
420	score -= scentral[i];
421	score -= s_pawn_mobility(i);
422	score += white_saccers(i);
423	isolated = FALSE;
424	backwards = FALSE;
425        bp++;
426
427	/* in general, bonuses/penalties in the endgame evaluation will be
428	   higher, since pawn structure becomes more important for the
429	   creation of passed pawns */
430
431	/* check for backwards pawns: */
432	if (black_back_pawn[pawn_file+1] < srank
433	    && black_back_pawn[pawn_file-1] < srank) {
434	  score += 8;
435	  backwards = TRUE;
436	  /* check to see if it is furthermore isolated: */
437	  if (!pawns[0][pawn_file+1] && !pawns[0][pawn_file-1]) {
438	    score += 12;
439	    isolated = TRUE;
440	  }
441	}
442
443	/* give weak, exposed pawns a penalty (not as much as in the midgame,
444	   since there may be no pieces to take advantage of it): */
445	if (!pawns[1][pawn_file]) {
446	  if (backwards) score += 5;
447	  if (isolated) score += 8;
448	}
449
450	/* give doubled, trippled, etc.. pawns a penalty (bigger in the
451	   endgame, since they will become big targets): */
452	if (pawns[0][pawn_file] > 1)
453	  score += 15*(pawns[0][pawn_file]-1);
454
455	/* give bonuses for passed pawns (bigger in the endgame since passed
456	   pawns are what wins the endgame): */
457	if (!pawns[1][pawn_file] && srank <= white_back_pawn[pawn_file-1] &&
458	    srank <= white_back_pawn[pawn_file+1]) {
459	  score -= 30 + 3*(7-rank(i));
460
461	  /* outside passer ? */
462	  if (file(i) == 1 || file(i) == 8)
463	    score -= 4 + 2*(7-rank(i));
464
465	  /* give an extra bonus if a connected, passed pawn: */
466	  if (!isolated)
467	    {
468	      score -= 6;
469	    }
470	}
471
472	if (!pawns[0][pawn_file-1])
473	  score += 20;
474
475	break;
476
477      case (wrook):
478	score += scentral[i];
479	score += s_rook_mobility(i);
480	wr++;
481	break;
482
483      case (brook):
484	score -= scentral[i];
485	score -= s_rook_mobility(i);
486	br++;
487	break;
488
489      case (wbishop):
490	score += scentral[i];
491	score += s_bishop_mobility(i);
492	if (wb)
493	{
494	  if (sqcolor[i] != wbc)
495	    wb = 99;
496	}
497	wb++;
498	wbc = sqcolor[i];
499	break;
500
501      case (bbishop):
502	score -= scentral[i];
503	score -= s_bishop_mobility(i);
504	if (bb)
505	{
506	  /* two bishops, check for same color */
507          if (sqcolor[i] != bbc)
508	    bb = 99;
509	}
510	bb++;
511	bbc = sqcolor[i];
512	break;
513
514      case (wknight):
515	score += scentral[i];
516	score += s_knight_mobility(i);
517	wn++;
518	break;
519
520      case (bknight):
521	score -= scentral[i];
522	score -= s_knight_mobility(i);
523	bn++;
524	break;
525
526      case (wqueen):
527	score += scentral[i];
528	score += s_rook_mobility(i);
529	score += s_bishop_mobility(i);
530	break;
531
532      case (bqueen):
533	score -= scentral[i];
534	score -= s_rook_mobility(i);
535	score -= s_bishop_mobility(i);
536	break;
537
538      case (wking):
539	score += scentral[i] >> 1;
540	score += s_king_mobility(i);
541	wk++;
542	break;
543
544      case (bking):
545	score -= scentral[i] >> 1;
546	score -= s_king_mobility(i);
547	bk++;
548	break;
549    }
550  }
551
552  /* opposite color bishops */
553  if ((wb < 99) && (bb < 99) && (wbc != bbc) && (piece_count < 32))
554    {
555	score = (int)((float)score * (float)((float)piece_count / 32.0));
556    }
557
558  storeECache(score);
559
560  /* adjust for color: */
561  if (white_to_move == 1) {
562    return score;
563  }
564  else {
565    return -score;
566  }
567
568}
569