~ubuntu-branches/debian/sid/chessx/sid

« back to all changes in this revision

Viewing changes to src/guess/guessengine.h

  • Committer: Package Import Robot
  • Author(s): Niklas Fiekas
  • Date: 2013-10-31 17:02:37 UTC
  • Revision ID: package-import@ubuntu.com-20131031170237-wghf5j9jlv28gmls
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//////////////////////////////////////////////////////////////////////
 
2
//
 
3
//  FILE:       guessengine.h
 
4
//              Engine class
 
5
//
 
6
//  Part of:    Scid (Shane's Chess Information Database)
 
7
//  Version:    3.5
 
8
//
 
9
//  Notice:     Copyright (c) 2002-2003 Shane Hudson.  All rights reserved.
 
10
//
 
11
//  Author:     Shane Hudson (sgh@users.sourceforge.net)
 
12
//
 
13
//////////////////////////////////////////////////////////////////////
 
14
 
 
15
// The Engine class provides a simple chess position evaluator
 
16
// based on negamax with quiescent search and alpha/beta pruning.
 
17
// It is used in Scid for doing small quick searches to determine
 
18
// which of the possible legal moves to or from a particular square
 
19
// to suggest as the best move for faster mouse input.
 
20
 
 
21
#ifndef SCID_GUESSENGINE_H
 
22
#define SCID_GUESSENGINE_H
 
23
 
 
24
#include <stdarg.h>
 
25
 
 
26
#include "position.h"
 
27
 
 
28
#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0))
 
29
#include <QTime>
 
30
typedef QTime QElapsedTimer;
 
31
#else
 
32
#include <QElapsedTimer>
 
33
#endif
 
34
 
 
35
namespace Guess
 
36
{
 
37
 
 
38
const unsigned int ENGINE_MAX_PLY =           40;  // Maximum search ply.
 
39
const int  ENGINE_MAX_HISTORY =   100000;  // Max accumulated history value.
 
40
const int  ENGINE_HASH_SCORE = 100000000;  // To order hash moves first.
 
41
const unsigned int ENGINE_HASH_KB =           32;  // Default hash table size in KB.
 
42
const unsigned int ENGINE_PAWN_KB =            1;  // Default pawn table size in KB.
 
43
 
 
44
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
45
// principalVarT
 
46
//   Stores the principal variation at one search Ply depth.
 
47
//
 
48
struct principalVarT
 
49
{
 
50
    unsigned int length;
 
51
    simpleMoveT move [ENGINE_MAX_PLY];
 
52
};
 
53
 
 
54
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
55
// scoreFlagT
 
56
//  Types of transposition table score and endgame recognition score.
 
57
//
 
58
typedef unsigned char scoreFlagT;
 
59
const scoreFlagT
 
60
SCORE_NONE  = 0,    // Not a useful score.
 
61
SCORE_EXACT = 1,    // Exact score.
 
62
SCORE_LOWER = 2,    // Lower bound, real score could be higher.
 
63
SCORE_UPPER = 3;    // Upper bound, real score could be lower.
 
64
 
 
65
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
66
// transTableEntryT
 
67
//   Transposition table entry.
 
68
//   Apart from the type flag, depth and score, it also stores the
 
69
//   hash codes and other position values for safety checks to avoid
 
70
//   a false hit.
 
71
//   The best move is also stored, in a compact format to save space.
 
72
//
 
73
struct transTableEntryT
 
74
{
 
75
    unsigned int    hash;              // Hash value.
 
76
    unsigned int    pawnhash;          // Pawn hash value, for extra safety check.
 
77
    short   score;             // Evaluation score.
 
78
    unsigned short  bestMove;          // Best move from/to/promote values.
 
79
    unsigned char    depth;             // Depth of evaulation.
 
80
    unsigned char    flags;             // Score type, side to move and castling flags.
 
81
    unsigned char    sequence;          // Sequence number, for detecting old entries.
 
82
    squareT enpassant;         // En passant target square.
 
83
};
 
84
 
 
85
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
86
// pawnTableEntryT
 
87
//   Pawn structure score hash table entry.
 
88
//
 
89
struct pawnTableEntryT
 
90
{
 
91
    unsigned int  pawnhash;           // Pawn hash value for this pawn structure.
 
92
    unsigned int  sig;                // Safety check value, to avoid false hits.
 
93
    short score;              // Positional score for pawn structure.
 
94
    short wLongbShortScore;   // Pawn storm score for wk on abc, bk on abc.
 
95
    short wShortbLongScore;   // Pawn storm score for wk on fgh, bk on fgh.
 
96
    unsigned char  fyleHasPassers[2];  // One bit per file, indicating passed pawns.
 
97
};
 
98
 
 
99
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
100
// repeatT
 
101
//   Repetition-detection stack entry.
 
102
//   An entry is pushed onto the stack when a move is made, and
 
103
//   popped off when the move is unmade.
 
104
//
 
105
struct repeatT
 
106
{
 
107
    unsigned int   hash;         // Position hash code.
 
108
    unsigned int   pawnhash;     // Position pawn-structure hash code.
 
109
    unsigned int   npieces;      // Total number of pieces in position.
 
110
    colorT stm;          // Side to move.
 
111
};
 
112
 
 
113
 
 
114
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
115
// Engine
 
116
//   Class representing a chess engine.
 
117
//
 
118
class Engine
 
119
{
 
120
private:
 
121
    Position RootPos;       // Position at start of search.
 
122
    Position Pos;           // Current position in search.
 
123
    unsigned int     MaxDepth;      // Search depth limit.
 
124
    int      SearchTime;    // Search time limit in milliseconds.
 
125
    int      MinSearchTime; // Minimum search time in milliseconds.
 
126
    int      MaxSearchTime; // Maximum search time in milliseconds.
 
127
    bool     Debug;         // If true, print debug info to stdout.
 
128
    bool     PostInfo;      // If true, print post info to stdout.
 
129
    bool     XBoardMode;    // If true, print info in xboard format.
 
130
    bool     Pruning;       // If true, do futility pruning.
 
131
    FILE *   LogFile;       // Output is to stdout and to this file.
 
132
 
 
133
    unsigned int     QNodeCount;    // Nodes examined in quiescent search.
 
134
    unsigned int     NodeCount;     // Nodes examined in total.
 
135
    QElapsedTimer    Elapsed;       // Timer for interrupting search.
 
136
    bool     IsOutOfTime;   // Becomes true when search is out of time.
 
137
    unsigned int     Ply;           // Current ply being examined.
 
138
    bool     EasyMove;      // True if the search indicates one move is
 
139
    //    far better than the others.
 
140
    bool     HardMove;      // True if failed low at root on current depth.
 
141
    unsigned int     InNullMove;    // If > 0, in null move search so no PV updates.
 
142
    unsigned int     RepStackSize;         // Repetition stack size.
 
143
    repeatT  RepStack [1024];      // Repetition stack.
 
144
    bool     InCheck [ENGINE_MAX_PLY];   // In-check at each ply.
 
145
    principalVarT PV [ENGINE_MAX_PLY];   // Principal variation at each ply.
 
146
    simpleMoveT KillerMove [ENGINE_MAX_PLY][2];  // Two killer moves per ply.
 
147
    int History[16][64];    // Success history of piece-to-square moves.
 
148
    unsigned char     TranTableSequence;    // Transposition table sequence number.
 
149
    unsigned int     TranTableSize;        // Number of Transposition table entries.
 
150
    transTableEntryT * TranTable;  // Transposition table.
 
151
    unsigned int     PawnTableSize;        // Number of Pawn structure table entries.
 
152
    pawnTableEntryT * PawnTable;   // Pawn structure score hash table.
 
153
    bool (*CallbackFunction)(Engine *, void *);  // Periodic callback.
 
154
    void *   CallbackData;
 
155
    simpleMoveT * GameMoves [1024];
 
156
    unsigned int      NumGameMoves;
 
157
 
 
158
private:
 
159
    int PieceValue(pieceT piece);
 
160
    int SearchRoot(int depth, int alpha, int beta, MoveList * mlist);
 
161
    int Search(int depth, int alpha, int beta, bool tryNullMove);
 
162
    int Quiesce(int alpha, int beta);
 
163
    int SEE(squareT from, squareT to);
 
164
    void ScoreMoves(MoveList * mlist);
 
165
    inline void DoMove(simpleMoveT * sm);
 
166
    inline void UndoMove(simpleMoveT * sm);
 
167
    inline void SetPVLength(void);
 
168
    inline void UpdatePV(simpleMoveT * sm);
 
169
    void Output(const char * format, ...);
 
170
    void PrintPV(unsigned int depth, int score)
 
171
    {
 
172
        PrintPV(depth, score, "");
 
173
    }
 
174
    void PrintPV(unsigned int depth, int score, const char * annotation);
 
175
    inline void PushRepeat(Position * pos);
 
176
    inline void PopRepeat(void);
 
177
    void StoreHash(int depth, scoreFlagT flag, int score,
 
178
                   simpleMoveT * bestmove, bool isOnlyMove);
 
179
    scoreFlagT ProbeHash(int depth, int * score, simpleMoveT * bestMove, bool * isOnlyMove);
 
180
 
 
181
    inline void ClearKillerMoves(void);
 
182
    inline void AddKillerMove(simpleMoveT * sm);
 
183
    inline bool IsKillerMove(simpleMoveT * sm);
 
184
 
 
185
    inline void ClearHistoryValues(void);
 
186
    inline void HalveHistoryValues(void);
 
187
    inline void IncHistoryValue(simpleMoveT * sm, int increment);
 
188
    inline int GetHistoryValue(simpleMoveT * sm);
 
189
 
 
190
    int Score(int alpha, int beta);
 
191
    inline int ScoreWhiteMaterial(void);
 
192
    inline int ScoreBlackMaterial(void);
 
193
    void ScorePawnStructure(pawnTableEntryT * pawnEntry);
 
194
    bool IsMatingScore(int score);
 
195
    bool IsGettingMatedScore(int score);
 
196
 
 
197
    bool OutOfTime(void);
 
198
    void AdjustTime(bool easyMove);
 
199
 
 
200
public:
 
201
    Engine()
 
202
    {
 
203
        MaxDepth = ENGINE_MAX_PLY;      // A large default search depth
 
204
        SearchTime = 1000;  // Default search time: 1000 ms = one second.
 
205
        MinSearchTime = MaxSearchTime = SearchTime;
 
206
        LogFile = NULL;
 
207
        Debug = false;
 
208
        PostInfo = false;
 
209
        XBoardMode = false;
 
210
        Pruning = false;
 
211
        RepStackSize = 0;
 
212
        TranTable = NULL;
 
213
        TranTableSize = 0;
 
214
        TranTableSequence = 0;
 
215
        PawnTable = NULL;
 
216
        PawnTableSize = 0;
 
217
        SetHashTableKilobytes(ENGINE_HASH_KB);
 
218
        SetPawnTableKilobytes(ENGINE_PAWN_KB);
 
219
        CallbackFunction = NULL;
 
220
        NumGameMoves = 0;
 
221
        RootPos.StdStart();
 
222
        Pos.StdStart();
 
223
        PV[0].length = 0;
 
224
    }
 
225
    ~Engine()
 
226
    {
 
227
        delete[] TranTable;
 
228
        delete[] PawnTable;
 
229
    }
 
230
 
 
231
    void SetSearchDepth(unsigned int ply)
 
232
    {
 
233
        if(ply < 1)
 
234
        {
 
235
            ply = 1;
 
236
        }
 
237
        if(ply > ENGINE_MAX_PLY)
 
238
        {
 
239
            ply = ENGINE_MAX_PLY;
 
240
        }
 
241
        MaxDepth = ply;
 
242
    }
 
243
    void SetSearchTime(unsigned int ms)
 
244
    {
 
245
        MinSearchTime = SearchTime = MaxSearchTime = ms;
 
246
    }
 
247
    void SetSearchTime(unsigned int min, unsigned int ms, unsigned int max)
 
248
    {
 
249
        MinSearchTime = min;
 
250
        SearchTime = ms;
 
251
        MaxSearchTime = max;
 
252
    }
 
253
    void SetDebug(bool b)
 
254
    {
 
255
        Debug = b;
 
256
    }
 
257
    void SetPostMode(bool b)
 
258
    {
 
259
        PostInfo = b;
 
260
    }
 
261
    bool InPostMode(void)
 
262
    {
 
263
        return PostInfo;
 
264
    }
 
265
    void SetXBoardMode(bool b)
 
266
    {
 
267
        XBoardMode = b;
 
268
    }
 
269
    bool InXBoardMode(void)
 
270
    {
 
271
        return XBoardMode;
 
272
    }
 
273
    void SetPruning(bool b)
 
274
    {
 
275
        Pruning = b;
 
276
    }
 
277
    void SetLogFile(FILE * fp)
 
278
    {
 
279
        LogFile = fp;
 
280
    }
 
281
    void SetHashTableKilobytes(unsigned int sizeKB);
 
282
    void SetPawnTableKilobytes(unsigned int sizeKB);
 
283
    unsigned int NumHashTableEntries(void)
 
284
    {
 
285
        return TranTableSize;
 
286
    }
 
287
    unsigned int NumPawnTableEntries(void)
 
288
    {
 
289
        return PawnTableSize;
 
290
    }
 
291
    void ClearHashTable(void);
 
292
    void ClearPawnTable(void);
 
293
    void ClearHashTables(void)
 
294
    {
 
295
        ClearHashTable();
 
296
        ClearPawnTable();
 
297
    }
 
298
 
 
299
    void SetCallbackFunction(bool (*fn)(Engine *, void *), void * data)
 
300
    {
 
301
        CallbackFunction = fn;
 
302
        CallbackData = data;
 
303
    }
 
304
 
 
305
    unsigned int GetNodeCount(void)
 
306
    {
 
307
        return NodeCount;
 
308
    }
 
309
 
 
310
    bool NoMatingMaterial(void);
 
311
    bool FiftyMoveDraw(void);
 
312
    unsigned int RepeatedPosition(void);
 
313
 
 
314
    void SetPosition(Position * pos);
 
315
    Position * GetPosition(void)
 
316
    {
 
317
        return &RootPos;
 
318
    }
 
319
    void PlayMove(simpleMoveT * move);
 
320
    void RetractMove(void);
 
321
    int Score(void);
 
322
    int ScoreMaterial(void);
 
323
    principalVarT * GetPV(void)
 
324
    {
 
325
        return &(PV[0]);
 
326
    }
 
327
    unsigned int PerfTest(unsigned int depth);
 
328
 
 
329
    int Think(MoveList * mlist);
 
330
};
 
331
 
 
332
 
 
333
inline void
 
334
Engine::SetPVLength(void)
 
335
{
 
336
    if(Ply < ENGINE_MAX_PLY - 1)
 
337
    {
 
338
        PV[Ply].length = Ply;
 
339
    }
 
340
}
 
341
 
 
342
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
343
// Engine::UpdatePV
 
344
//   Updates the principal variation at the current Ply to
 
345
//   include the specified move.
 
346
inline void
 
347
Engine::UpdatePV(simpleMoveT * sm)
 
348
{
 
349
    if(Ply >= ENGINE_MAX_PLY - 1)
 
350
    {
 
351
        return;
 
352
    }
 
353
    if(InNullMove > 0)
 
354
    {
 
355
        return;
 
356
    }
 
357
    // if (! Pos.IsLegalMove (sm)) { return; }
 
358
 
 
359
    PV[Ply].move[Ply] = *sm;
 
360
    for(unsigned int j = Ply + 1; j < PV[Ply + 1].length; j++)
 
361
    {
 
362
        PV[Ply].move[j] = PV[Ply + 1].move[j];
 
363
    }
 
364
    PV[Ply].length = PV[Ply + 1].length;
 
365
}
 
366
 
 
367
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
368
// Killer moves:
 
369
//   We keep track of two "killer" moves at each ply, moves which
 
370
//   are not captures or promotions (as they get ordered first) but
 
371
//   were good enough to cause a beta cutoff. Killer moves get
 
372
//   ordered after good captures but before non-killer noncaptures,
 
373
//   which are ordered using the history table (see below).
 
374
//
 
375
//   Only noncaptures and non-promotion moves can be killer moves, but
 
376
//   we make an exception for those that have a negative score (meaning
 
377
//   they lose material according to the static exchange evaluator),
 
378
//   since they would otherwise be searched last after all noncaptures.
 
379
 
 
380
inline void
 
381
Engine::ClearKillerMoves(void)
 
382
{
 
383
    for(unsigned int i = 0; i < ENGINE_MAX_PLY; i++)
 
384
    {
 
385
        KillerMove[i][0].from = NULL_SQUARE;
 
386
        KillerMove[i][1].from = NULL_SQUARE;
 
387
    }
 
388
}
 
389
 
 
390
inline void
 
391
Engine::AddKillerMove(simpleMoveT * sm)
 
392
{
 
393
    if(sm->capturedPiece != EMPTY  &&  sm->score >= 0)
 
394
    {
 
395
        return;
 
396
    }
 
397
    if(sm->promote != EMPTY  &&  sm->score >= 0)
 
398
    {
 
399
        return;
 
400
    }
 
401
    simpleMoveT * killer0 = &(KillerMove[Ply][0]);
 
402
    simpleMoveT * killer1 = &(KillerMove[Ply][1]);
 
403
    if(killer0->from == sm->from  &&  killer0->to == sm->to
 
404
            &&  killer0->movingPiece == sm->movingPiece)
 
405
    {
 
406
        return;
 
407
    }
 
408
    *killer1 = *killer0;
 
409
    *killer0 = *sm;
 
410
}
 
411
 
 
412
inline bool
 
413
Engine::IsKillerMove(simpleMoveT * sm)
 
414
{
 
415
    simpleMoveT * killer0 = &(KillerMove[Ply][0]);
 
416
    if(killer0->from == sm->from  &&  killer0->to == sm->to
 
417
            &&  killer0->movingPiece == sm->movingPiece)
 
418
    {
 
419
        return true;
 
420
    }
 
421
    simpleMoveT * killer1 = &(KillerMove[Ply][1]);
 
422
    if(killer1->from == sm->from  &&  killer1->to == sm->to
 
423
            &&  killer1->movingPiece == sm->movingPiece)
 
424
    {
 
425
        return true;
 
426
    }
 
427
    return false;
 
428
}
 
429
 
 
430
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
431
// History table:
 
432
//   This is a table of values indexed by moving piece and
 
433
//   target square, indicating the historical success of each move
 
434
//   as measured by the frequency of "good" (better than alpha)
 
435
//   scores. It is used to order non-capture moves after killers.
 
436
 
 
437
inline void
 
438
Engine::ClearHistoryValues(void)
 
439
{
 
440
    for(pieceT p = WK; p <= BP; p++)
 
441
    {
 
442
        for(squareT to = A1; to <= H8; to++)
 
443
        {
 
444
            History[p][to] = 0;
 
445
        }
 
446
    }
 
447
}
 
448
 
 
449
inline void
 
450
Engine::HalveHistoryValues(void)
 
451
{
 
452
    // Output("# Halving history values\n");
 
453
    for(pieceT p = WK; p <= BP; p++)
 
454
    {
 
455
        for(squareT to = A1; to <= H8; to++)
 
456
        {
 
457
            History[p][to] /= 2;
 
458
        }
 
459
    }
 
460
}
 
461
 
 
462
inline void
 
463
Engine::IncHistoryValue(simpleMoveT * sm, int increment)
 
464
{
 
465
    if(sm->capturedPiece != EMPTY  &&  sm->score >= 0)
 
466
    {
 
467
        return;
 
468
    }
 
469
    if(sm->promote != EMPTY  &&  sm->score >= 0)
 
470
    {
 
471
        return;
 
472
    }
 
473
    pieceT p = sm->movingPiece;
 
474
    squareT to = sm->to;
 
475
    ASSERT(p <= BP  &&  to <= H8);
 
476
    History[p][to] += increment;
 
477
    // Halve all history values if this one gets too large, to avoid
 
478
    // non-capture moves getting searched before captures:
 
479
    if(History[p][to] >= ENGINE_MAX_HISTORY)
 
480
    {
 
481
        HalveHistoryValues();
 
482
    }
 
483
}
 
484
 
 
485
inline int
 
486
Engine::GetHistoryValue(simpleMoveT * sm)
 
487
{
 
488
    pieceT p = sm->movingPiece;
 
489
    squareT to = sm->to;
 
490
    ASSERT(p <= BP  &&  to <= H8);
 
491
    return History[p][to];
 
492
}
 
493
 
 
494
} // End namespace Guess
 
495
 
 
496
#endif  // SCID_ENGINE_H
 
497
 
 
498
//////////////////////////////////////////////////////////////////////
 
499
//  EOF: guessengine.h
 
500
//////////////////////////////////////////////////////////////////////