Subversion Repositories Games.Chess Giants

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
112 pmbaty 1
/*
2
    Protector -- a UCI chess engine
3
 
4
    Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
5
 
6
    This program is free software: you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation, either version 3 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
19
*/
20
 
21
#include <stdio.h>
22
#include <string.h>
23
#include <assert.h>
24
#include "matesearch.h"
25
#include "io.h"
26
#include "movegeneration.h"
27
#include "hash.h"
28
#include "coordination.h"
29
 
30
static int searchMate(Variation * variation, int alpha, int beta,
31
                      const int ply, const int restDepth,
32
                      PrincipalVariation * pv)
33
{
34
   const int oldAlpha = alpha;
35
   Position *position = &variation->singlePosition;
36
   const bool check = activeKingIsSafe(position) == FALSE;
37
   int best = VALUE_MATED;
38
   Movelist movelist;
39
   Hashentry *tableHit = NULL;
40
   UINT8 hashentryFlag;
41
   int i, historyLimit;
42
   Move hashmove = NO_MOVE;
43
   Move bestMove = NO_MOVE;
44
   Move currentMove;
45
   PrincipalVariation newPv;
46
 
47
   newPv.length = pv->length = 0;
48
 
49
   historyLimit = POSITION_HISTORY_OFFSET + variation->ply -
50
      variation->singlePosition.halfMoveClock;
51
 
52
   assert(historyLimit >= 0);
53
 
54
   for (i = POSITION_HISTORY_OFFSET + variation->ply - 4;
55
        i >= historyLimit; i -= 2)
56
   {
57
      if (variation->singlePosition.hashKey == variation->positionHistory[i])
58
      {
59
         return 0;
60
      }
61
   }
62
 
63
   /* Probe the transposition table */
64
   /* ----------------------------- */
65
   tableHit = getHashentry(getSharedHashtable(),
66
                           variation->singlePosition.hashKey);
67
 
68
   if (tableHit != NULL)
69
   {
70
      const int importance = getHashentryImportance(tableHit);
71
 
72
      hashmove = (Move) getHashentryMove(tableHit);
73
 
74
      if (hashmove != NO_MOVE)
75
      {
76
         if (moveIsPseudoLegal(position, hashmove))
77
         {
78
            assert(moveIsLegal(position, hashmove));
79
 
80
            appendMoveToPv(&newPv, pv, hashmove);
81
         }
82
         else
83
         {
84
            hashmove = NO_MOVE;
85
         }
86
      }
87
 
88
      if (restDepth <= importance)
89
      {                         /* 99% */
90
         const int value = getHashentryValue(tableHit);
91
         const int hashValue = calcEffectiveValue(value, ply);
92
         const int flag = getHashentryFlag(tableHit);
93
 
94
         switch (flag)
95
         {
96
         case HASHVALUE_UPPER_LIMIT:
97
            if (hashValue <= alpha)
98
            {
99
               return hashValue;
100
            }
101
            break;
102
 
103
         case HASHVALUE_EXACT:
104
            return hashValue;
105
 
106
         case HASHVALUE_LOWER_LIMIT:
107
            if (hashValue >= beta)
108
            {
109
               return hashValue;
110
            }
111
            break;
112
 
113
         default:;
114
         }
115
      }
116
   }
117
 
118
   if (ply >= 2)
119
   {
120
      variation->plyInfo[ply].killerMove3 =
121
         variation->plyInfo[ply - 2].killerMove1;
122
      variation->plyInfo[ply].killerMove4 =
123
         variation->plyInfo[ply - 2].killerMove2;
124
   }
125
   else
126
   {
127
      variation->plyInfo[ply].killerMove3 = NO_MOVE;
128
      variation->plyInfo[ply].killerMove4 = NO_MOVE;
129
   }
130
 
131
   if (restDepth == 1)
132
   {
133
      initCheckMovelist(&movelist, position, &variation->historyValue[0]);
134
   }
135
   else
136
   {
137
      movelist.positionalGain = &(variation->positionalGain[0]);
138
      initStandardMovelist(&movelist, &variation->singlePosition,
139
                           &variation->plyInfo[ply],
140
                           &variation->historyValue[0], hashmove, check);
141
   }
142
 
143
   initializePlyInfo(variation);
144
 
145
   while ((currentMove = getNextMove(&movelist)) != NO_MOVE)
146
   {
147
      int value;
148
 
149
      variation->nodes++;
150
 
151
      if (makeMoveFast(variation, currentMove) != 0 ||
152
          passiveKingIsSafe(&variation->singlePosition) == FALSE ||
153
          (restDepth == 1 && activeKingIsSafe(&variation->singlePosition)))
154
      {
155
         unmakeLastMove(variation);
156
 
157
         continue;
158
      }
159
 
160
      if (restDepth > 0)
161
      {
162
         if (restDepth == 1)
163
         {
164
            if (kingCanEscape(position))
165
            {
166
               value = 0;
167
            }
168
            else
169
            {
170
               value = -(VALUE_MATED + ply + 1);
171
            }
172
         }
173
         else
174
         {
175
            value = -searchMate(variation, -beta, -alpha, ply + 1,
176
                                restDepth - 1, &newPv);
177
         }
178
      }
179
      else
180
      {
181
         value = 0;
182
      }
183
 
184
      unmakeLastMove(variation);
185
 
186
      if (value > best)
187
      {
188
         best = value;
189
         appendMoveToPv(&newPv, pv, currentMove);
190
 
191
         if (best > alpha)
192
         {
193
            alpha = best;
194
            bestMove = currentMove;
195
 
196
            if (ply == 0)
197
            {
198
               if (variation->threadNumber == 0 &&
199
                   variation->handleSearchEvent != 0)
200
               {
201
                  getGuiSearchMutex();
202
                  variation->handleSearchEvent(SEARCHEVENT_NEW_PV, variation);
203
                  releaseGuiSearchMutex();
204
               }
205
            }
206
 
207
            if (best >= beta)
208
            {
209
               goto finish;
210
            }
211
         }
212
      }
213
   }
214
 
215
   if (best == VALUE_MATED)
216
   {
217
      if (check)
218
      {
219
         /* mate */
220
 
221
         best = VALUE_MATED + ply;
222
      }
223
      else
224
      {
225
         /* stalemate */
226
 
227
         best = variation->drawScore[position->activeColor];
228
      }
229
   }
230
 
231
 finish:
232
 
233
   if (bestMove != NO_MOVE)
234
   {
235
      if (position->piece[getToSquare(bestMove)] == NO_PIECE &&
236
          getNewPiece(bestMove) == NO_PIECE &&
237
          (getToSquare(bestMove) != position->enPassantSquare ||
238
           pieceType(position->piece[getFromSquare(bestMove)]) != PAWN))
239
      {
240
         Move killerMove = bestMove;
241
         const Piece movingPiece = position->piece[getFromSquare(killerMove)];
242
         const int index = historyIndex(bestMove, position);
243
 
244
         setMoveValue(&killerMove, movingPiece);
245
         registerKillerMove(&variation->plyInfo[ply], killerMove);
246
 
247
         variation->historyValue[index] = (UINT16)
248
            (variation->historyValue[index] + (restDepth * restDepth));
249
 
250
         if (variation->historyValue[index] > HISTORY_MAX)
251
         {
252
            shrinkHistoryValues(variation);
253
         }
254
      }
255
   }
256
 
257
   /* Store the value in the transposition table. */
258
   /* ------------------------------------------- */
259
   if (best > oldAlpha)
260
   {
261
      hashentryFlag =
262
         (best >= beta ? HASHVALUE_LOWER_LIMIT : HASHVALUE_EXACT);
263
   }
264
   else
265
   {
266
      hashentryFlag = HASHVALUE_UPPER_LIMIT;
267
   }
268
 
269
   setHashentry(getSharedHashtable(), position->hashKey,
270
                calcHashtableValue(best, ply), (INT8) restDepth,
271
                packedMove(bestMove), hashentryFlag, 0);
272
 
273
   return best;
274
}
275
 
276
static int searchBaseMoves(Variation * variation, const int alpha,
277
                           const int beta, const int restDepth,
278
                           Movelist * solutions)
279
{
280
   Position *position = &variation->singlePosition;
281
   const bool check = activeKingIsSafe(position) == FALSE;
282
   int best = VALUE_MATED, ply = 0;
283
   Movelist movelist;
284
   Move hashmove = NO_MOVE;
285
   Move currentMove;
286
   PrincipalVariation pv;
287
 
288
   if (restDepth == 1)
289
   {
290
      initCheckMovelist(&movelist, position, &variation->historyValue[0]);
291
   }
292
   else
293
   {
294
      movelist.positionalGain = &(variation->positionalGain[0]);
295
      initStandardMovelist(&movelist, &variation->singlePosition,
296
                           &variation->plyInfo[ply],
297
                           &variation->historyValue[0], hashmove, check);
298
   }
299
 
300
   initializePlyInfo(variation);
301
 
302
   while ((currentMove = getNextMove(&movelist)) != NO_MOVE)
303
   {
304
      int value;
305
 
306
      variation->nodes++;
307
 
308
      if (makeMoveFast(variation, currentMove) != 0 ||
309
          passiveKingIsSafe(&variation->singlePosition) == FALSE ||
310
          (restDepth == 1 && activeKingIsSafe(&variation->singlePosition)))
311
      {
312
         unmakeLastMove(variation);
313
 
314
         continue;
315
      }
316
 
317
      value =
318
         -searchMate(variation, -beta, -alpha, ply + 1, restDepth - 1, &pv);
319
 
320
      unmakeLastMove(variation);
321
 
322
      if (value >= best)
323
      {
324
         best = variation->pv[0].score = value;
325
         setMoveValue(&currentMove, value);
326
         appendMoveToPv(&pv, &variation->pv[0], currentMove);
327
 
328
         if (best > alpha)
329
         {
330
            variation->bestBaseMove = currentMove;
331
            solutions->moves[solutions->numberOfMoves++] = currentMove;
332
 
333
            if (variation->threadNumber == 0 &&
334
                variation->handleSearchEvent != 0)
335
            {
336
               getGuiSearchMutex();
337
               variation->handleSearchEvent(SEARCHEVENT_NEW_PV, variation);
338
               releaseGuiSearchMutex();
339
            }
340
         }
341
      }
342
   }
343
 
344
   if (best == VALUE_MATED)
345
   {
346
      if (check)
347
      {
348
         /* mate */
349
 
350
         best = VALUE_MATED + ply;
351
      }
352
      else
353
      {
354
         /* stalemate */
355
 
356
         best = variation->drawScore[position->activeColor];
357
      }
358
   }
359
 
360
   return best;
361
}
362
 
363
void searchForMate(Variation * variation, Movelist * foundSolutions,
364
                   int numMoves)
365
{
366
   int numSolutions = 0, i;
367
 
368
   variation->startTime = getTimestamp();
369
   variation->startTimeProcess = getProcessTimestamp();
370
   variation->timestamp = variation->startTime + 1;
371
   resetHashtable(getSharedHashtable());
372
   getLegalMoves(variation, foundSolutions);
373
   variation->numberOfBaseMoves = foundSolutions->numberOfMoves;
374
   variation->searchStatus = SEARCH_STATUS_RUNNING;
375
 
376
   foundSolutions->numberOfMoves = 0;
377
   resetHistoryValues(variation);
378
 
379
   for (variation->iteration = 1; variation->iteration <= numMoves;
380
        variation->iteration++)
381
   {
382
      const int restDepth = 2 * variation->iteration - 1;
383
      const int beta = -VALUE_MATED - restDepth;
384
 
385
      searchBaseMoves(variation, beta - 1, beta, restDepth, foundSolutions);
386
   }
387
 
388
   variation->finishTime = getTimestamp();
389
   variation->finishTimeProcess = getProcessTimestamp();
390
   variation->searchStatus = SEARCH_STATUS_TERMINATE;
391
 
392
   for (i = 0; i < foundSolutions->numberOfMoves; i++)
393
   {
394
      if (getMoveValue(foundSolutions->moves[i]) >=
395
          -VALUE_MATED - 2 * numMoves + 1)
396
      {
397
         numSolutions++;
398
      }
399
   }
400
 
401
   foundSolutions->numberOfMoves = numSolutions;
402
 
403
   getGuiSearchMutex();
404
 
405
   if (variation->threadNumber == 0 &&
406
       variation->handleSearchEvent != 0 &&
407
       variation->searchStatus == SEARCH_STATUS_TERMINATE)
408
   {
409
      variation->handleSearchEvent(SEARCHEVENT_SEARCH_FINISHED, variation);
410
   }
411
 
412
   releaseGuiSearchMutex();
413
}
414
 
415
int initializeModuleMatesearch()
416
{
417
   return 0;
418
}
419
 
420
int testModuleMatesearch()
421
{
422
   return 0;
423
}