summaryrefslogtreecommitdiff
path: root/src/save
diff options
context:
space:
mode:
Diffstat (limited to 'src/save')
-rwxr-xr-xsrc/save/._chess.hbin0 -> 4096 bytes
-rwxr-xr-xsrc/save/._main.cbin0 -> 4096 bytes
-rwxr-xr-xsrc/save/._root.cbin0 -> 4096 bytes
-rwxr-xr-xsrc/save/._util.cbin0 -> 4096 bytes
-rw-r--r--src/save/._vars.cbin0 -> 4096 bytes
-rwxr-xr-xsrc/save/chess.h2982
-rwxr-xr-xsrc/save/main.c745
-rwxr-xr-xsrc/save/root.c1462
-rwxr-xr-xsrc/save/util.c1254
-rw-r--r--src/save/vars.c483
10 files changed, 6926 insertions, 0 deletions
diff --git a/src/save/._chess.h b/src/save/._chess.h
new file mode 100755
index 0000000..c896cad
--- /dev/null
+++ b/src/save/._chess.h
Binary files differ
diff --git a/src/save/._main.c b/src/save/._main.c
new file mode 100755
index 0000000..405bb0d
--- /dev/null
+++ b/src/save/._main.c
Binary files differ
diff --git a/src/save/._root.c b/src/save/._root.c
new file mode 100755
index 0000000..99f2e5f
--- /dev/null
+++ b/src/save/._root.c
Binary files differ
diff --git a/src/save/._util.c b/src/save/._util.c
new file mode 100755
index 0000000..e0d6387
--- /dev/null
+++ b/src/save/._util.c
Binary files differ
diff --git a/src/save/._vars.c b/src/save/._vars.c
new file mode 100644
index 0000000..d436fe6
--- /dev/null
+++ b/src/save/._vars.c
Binary files differ
diff --git a/src/save/chess.h b/src/save/chess.h
new file mode 100755
index 0000000..e86911a
--- /dev/null
+++ b/src/save/chess.h
@@ -0,0 +1,2982 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ chess.h
+
+Abstract:
+
+Author:
+
+ Scott Gasch ([email protected]) 7 Apr 2004
+
+Revision History:
+
+ $Id: chess.h 350 2008-06-28 03:12:34Z scott $
+
+**/
+
+#ifndef CHESS_
+#define CHESS_
+
+#include "compiler.h"
+
+//
+// Datatype wrappers
+//
+#define MIN_CHAR (0x80)
+#define MAX_CHAR (0x7f)
+typedef char CHAR;
+
+#define MIN_BYTE (0x00)
+#define MAX_BYTE (0xff)
+typedef unsigned char BYTE;
+
+#define MIN_UCHAR (0x00)
+#define MAX_UCHAR (0xff)
+typedef unsigned char UCHAR;
+#define CAN_FIT_IN_UCHAR(x) ((x) <= MAX_UCHAR)
+
+#define MIN_SHORT (0x8000)
+#define MAX_SHORT (0x7fff)
+typedef signed short SHORT;
+
+#define MIN_USHORT (0x0000)
+#define MAX_USHORT (0xffff)
+typedef unsigned short USHORT;
+#define CAN_FIT_IN_USHORT(x) ((x) <= MAX_USHORT)
+
+#define MIN_WORD (0x0000)
+#define MAX_WORD (0xffff)
+typedef unsigned short WORD;
+
+#define MIN_INT (0x80000000)
+#define MAX_INT (0x7fffffff)
+typedef signed int INT;
+
+#define MIN_DWORD (0x00000000)
+#define MAX_DWORD (0xffffffff)
+typedef unsigned int DWORD;
+
+#define MIN_UINT (0x00000000)
+#define MAX_UINT (0xffffffff)
+typedef unsigned int UINT;
+
+#define MIN_ULONG (0x00000000)
+#define MAX_ULONG (0xffffffff)
+typedef unsigned int ULONG;
+
+#define MIN_INT64 (0x8000000000000000)
+#define MAX_INT64 (0x7fffffffffffffff)
+typedef signed COMPILER_LONGLONG INT64;
+
+#define MIN_UINT64 (0x0000000000000000)
+#define MAX_UINT64 (0xffffffffffffffff)
+typedef unsigned COMPILER_LONGLONG UINT64;
+
+#define MIN_BITBOARD (0x0000000000000000)
+#define MAX_BITBOARD (0xffffffffffffffff)
+typedef UINT64 BITBOARD;
+
+#define MIN_BITV MIN_UINT
+#define MAX_BITV MAX_UINT
+typedef unsigned int BITV;
+
+#define MIN_FLAG MIN_UINT
+#define MAX_FLAG MAX_UINT
+typedef unsigned int FLAG;
+#define IS_VALID_FLAG(x) (((x) == TRUE) || ((x) == FALSE))
+
+typedef unsigned int COOR;
+typedef unsigned int PIECE;
+typedef signed int SCORE;
+
+#define BIT1 (0x1)
+#define BIT2 (0x2)
+#define BIT3 (0x4)
+#define BIT4 (0x8)
+#define BIT5 (0x10)
+#define BIT6 (0x20)
+#define BIT7 (0x40)
+#define BIT8 (0x80)
+#define BIT9 (0x100)
+#define BIT10 (0x200)
+#define BIT11 (0x400)
+#define BIT12 (0x800)
+#define BIT13 (0x1000)
+#define BIT14 (0x2000)
+#define BIT15 (0x4000)
+#define BIT16 (0x8000)
+#define BIT17 (0x10000)
+#define BIT18 (0x20000)
+#define BIT19 (0x40000)
+#define BIT20 (0x80000)
+#define BIT21 (0x100000)
+#define BIT22 (0x200000)
+#define BIT23 (0x400000)
+#define BIT24 (0x800000)
+#define BIT25 (0x1000000)
+#define BIT26 (0x2000000)
+#define BIT27 (0x4000000)
+#define BIT28 (0x8000000)
+#define BIT29 (0x10000000)
+#define BIT30 (0x20000000)
+#define BIT31 (0x40000000)
+#define BIT32 (0x80000000)
+
+typedef struct _DLIST_ENTRY
+{
+ struct _DLIST_ENTRY *pFlink;
+ struct _DLIST_ENTRY *pBlink;
+} DLIST_ENTRY;
+
+//
+// Constants
+//
+#define YES (1)
+#define NO (0)
+#ifndef TRUE
+#define TRUE (YES)
+#endif
+#ifndef FALSE
+#define FALSE (NO)
+#endif
+
+//
+// Calculate the length of an array (i.e. number of elements)
+//
+#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
+#define COMMAND(x) \
+ void (x)(CHAR *szInput, ULONG argc, CHAR *argv[], POSITION *pos)
+#define MB (1024 * 1024)
+
+//
+// Calculate the address of the base of the structure given its type, and an
+// address of a field within the structure.
+//
+#ifndef OFFSET_OF
+#define OFFSET_OF(field, type) \
+ (ULONG)(&((type *)0)->field)
+#endif
+#ifndef CONTAINING_STRUCT
+#define CONTAINING_STRUCT(address, type, field) \
+ ((type *)((BYTE *)(address) - (BYTE *)(OFFSET_OF(field, type))))
+#endif
+
+#define WHITE (1)
+#define BLACK (0)
+#define BAD_COLOR (2)
+#define IS_VALID_COLOR(x) (((x) == WHITE) || ((x) == BLACK))
+#define FOREACH_COLOR(x) for((x) = BLACK; (x) < BAD_COLOR; (x)++)
+#define RANDOM_COLOR (rand() & 1)
+#define FLIP(color) ((color) ^ 1)
+#define COLOR_NAME(color) (((color) == WHITE) ? "white" : "black")
+
+#define MAX_MOVES_PER_PLY (218)
+#define MAX_PLY_PER_SEARCH (64)
+#define MAX_MOVES_PER_GAME (1024)
+#define SMALL_STRING_LEN_CHAR (256)
+#define MEDIUM_STRING_LEN_CHAR (8192)
+#define BIG_STRING_LEN_CHAR (16384)
+
+#define QUARTER_PLY 16
+#define HALF_PLY 32
+#define THREE_QUARTERS_PLY 48
+#define ONE_PLY 64
+#define TWO_PLY 128
+#define THREE_PLY 192
+#define FOUR_PLY 256
+#define MAX_DEPTH_PER_SEARCH (MAX_PLY_PER_SEARCH * ONE_PLY)
+
+#define IS_VALID_DEPTH(x) (((x) >= 0) && \
+ ((x) <= MAX_DEPTH_PER_SEARCH) && \
+ (((x) & 0xfffff00f) == 0))
+
+#define INFINITY (MAX_SHORT)
+#define INVALID_SCORE (INFINITY + 1)
+#define IS_VALID_SCORE(x) (((x) >= -INFINITY) && \
+ ((x) <= +INFINITY))
+#define NMATE (+INFINITY - 200)
+#define MATED_SCORE(ply) (-INFINITY + (ply))
+
+#define IS_A_POWER_OF_2(x) (((x) & (x - 1)) == 0)
+//
+// Program version number
+//
+#define VERSION "1.00"
+#define REVISION "$Id: chess.h 350 2008-06-28 03:12:34Z scott $\n"
+
+//
+// Function decorators
+//
+#define IN
+#define OUT
+#define INOUT
+#define UNUSED
+#define NOTHING
+
+// ----------------------------------------------------------------------
+//
+// PIECE:
+//
+// a piece (4 bits) = type (3 bits) + color (1 bit)
+//
+// 3 1 0
+// . . . .
+// | | |
+// type C
+//
+#define KING (6) // 110X
+#define QUEEN (5) // 101X
+#define ROOK (4) // 100X
+#define BISHOP (3) // 011X
+#define KNIGHT (2) // 010X
+#define PAWN (1) // 001X
+#define EMPTY (0) // 000X
+
+// (WHATEVER << 1)
+#define BLACK_PAWN (2) // 0010
+#define BLACK_KNIGHT (4) // 0100
+#define BLACK_BISHOP (6) // 0110
+#define BLACK_ROOK (8) // 1000
+#define BLACK_QUEEN (10) // 1010
+#define BLACK_KING (12) // 1100
+
+// (WHATEVER << 1) | WHITE
+#define WHITE_PAWN (3) // 0011
+#define WHITE_KNIGHT (5) // 0101
+#define WHITE_BISHOP (7) // 0111
+#define WHITE_ROOK (9) // 1001
+#define WHITE_QUEEN (11) // 1011
+#define WHITE_KING (13) // 1101
+
+#define PIECE_TYPE(p) ((p) >> 1)
+#define PIECE_COLOR(p) ((p) & WHITE)
+#define RANDOM_PIECE (rand() % 12) + 2;
+#define IS_PAWN(p) (((p) & 0xE) == BLACK_PAWN)
+#define IS_KNIGHT(p) (((p) & 0xE) == BLACK_KNIGHT)
+#define IS_BISHOP(p) (((p) & 0xE) == BLACK_BISHOP)
+#define IS_ROOK(p) (((p) & 0xE) == BLACK_ROOK)
+#define IS_QUEEN(p) (((p) & 0xE) == BLACK_QUEEN)
+#define IS_KING(p) (((p) & 0xE) == BLACK_KING)
+#define IS_KNIGHT_OR_KING(p) (((p) & 0x6) == 0x4)
+#define IS_VALID_PIECE(p) ((PIECE_TYPE((p)) >= PAWN) && \
+ (PIECE_TYPE((p)) <= KING))
+#define IS_WHITE_PIECE(p) ((p) & WHITE)
+#define IS_BLACK_PIECE(p) (!IS_WHITE(p))
+#define OPPOSITE_COLORS(p, q) (((p) ^ (q)) & WHITE)
+#define SAME_COLOR(p,q) (!OPPOSITE_COLORS(p, q))
+#define GET_COLOR(p) ((p) & WHITE)
+
+// ----------------------------------------------------------------------
+//
+// a coordinate (8 bits) = rank + file (0x88)
+//
+// 7 4 3 0
+// . . . . . . . .
+// | | |
+// rank file
+// | |
+// | +--- 0-7 = file A thru file H
+// |
+// +------------ 0-7 = rank 1 thru rank 8
+//
+// given a coordinate, C, if C & 0x88 then it is illegal (off board)
+//
+//
+// 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
+// +---------------------------------------+
+// 8 | 00 |:01:| 02 |:03:| 04 |:05:| 06 |:07:| 0x00
+// 7 |:10:| 11 |:12:| 13 |:14:| 15 |:16:| 17 | 0x10
+// 6 | 20 |:21:| 22 |:23:| 24 |:25:| 26 |:27:| 0x20
+// 5 |:30:| 31 |:32:| 33 |:34:| 35 |:36:| 37 | 0x30
+// 4 | 40 |:41:| 42 |:43:| 44 |:45:| 46 |:47:| 0x40
+// 3 |:50:| 51 |:52:| 53 |:54:| 55 |:56:| 57 | 0x50
+// 2 | 60 |:61:| 62 |:63:| 64 |:65:| 66 |:67:| 0x60
+// 1 |:70:| 71 |:72:| 73 |:74:| 75 |:76:| 77 | 0x70
+// +---------------------------------------+
+// A B C D E F G H
+//
+#define A (0)
+#define B (1)
+#define C (2)
+#define D (3)
+#define E (4)
+#define F (5)
+#define G (6)
+#define H (7)
+
+#define A8 (0x00)
+#define B8 (0x01)
+#define C8 (0x02)
+#define D8 (0x03)
+#define E8 (0x04)
+#define F8 (0x05)
+#define G8 (0x06)
+#define H8 (0x07)
+
+#define A7 (0x10)
+#define B7 (0x11)
+#define C7 (0x12)
+#define D7 (0x13)
+#define E7 (0x14)
+#define F7 (0x15)
+#define G7 (0x16)
+#define H7 (0x17)
+
+#define A6 (0x20)
+#define B6 (0x21)
+#define C6 (0x22)
+#define D6 (0x23)
+#define E6 (0x24)
+#define F6 (0x25)
+#define G6 (0x26)
+#define H6 (0x27)
+
+#define A5 (0x30)
+#define B5 (0x31)
+#define C5 (0x32)
+#define D5 (0x33)
+#define E5 (0x34)
+#define F5 (0x35)
+#define G5 (0x36)
+#define H5 (0x37)
+
+#define A4 (0x40)
+#define B4 (0x41)
+#define C4 (0x42)
+#define D4 (0x43)
+#define E4 (0x44)
+#define F4 (0x45)
+#define G4 (0x46)
+#define H4 (0x47)
+
+#define A3 (0x50)
+#define B3 (0x51)
+#define C3 (0x52)
+#define D3 (0x53)
+#define E3 (0x54)
+#define F3 (0x55)
+#define G3 (0x56)
+#define H3 (0x57)
+
+#define A2 (0x60)
+#define B2 (0x61)
+#define C2 (0x62)
+#define D2 (0x63)
+#define E2 (0x64)
+#define F2 (0x65)
+#define G2 (0x66)
+#define H2 (0x67)
+
+#define A1 (0x70)
+#define B1 (0x71)
+#define C1 (0x72)
+#define D1 (0x73)
+#define E1 (0x74)
+#define F1 (0x75)
+#define G1 (0x76)
+#define H1 (0x77)
+
+// TODO: if use this anywhere that matters, consider double loop
+// and unrolling the inside loop to prevent the multiple
+// continue for invalid squares
+#define FOREACH_SQUARE(x) for((x) = (A8); (x) <= (H1); (x)++)
+
+#define IS_ON_BOARD(c) (!((c) & 0x88))
+#define RANDOM_COOR (rand() & 0x77)
+#define FILE_RANK_TO_COOR(f, r) (((8 - (r)) << 4) | (f))
+#define RANK(c) (8 - ((c) >> 4))
+#define RANK1(c) (((c) & 0xF0) == 0x70)
+#define RANK2(c) (((c) & 0xF0) == 0x60)
+#define RANK3(c) (((c) & 0xF0) == 0x50)
+#define RANK4(c) (((c) & 0xF0) == 0x40)
+#define RANK5(c) (((c) & 0xF0) == 0x30)
+#define RANK6(c) (((c) & 0xF0) == 0x20)
+#define RANK7(c) (((c) & 0xF0) == 0x10)
+#define RANK8(c) (((c) & 0xF0) == 0x00)
+#define FILE(c) ((c) & 0x0F)
+#define FILEA(c) (((c) & 0x0F) == 0x00)
+#define FILEB(c) (((c) & 0x0F) == 0x01)
+#define FILEC(c) (((c) & 0x0F) == 0x02)
+#define FILED(c) (((c) & 0x0F) == 0x03)
+#define FILEE(c) (((c) & 0x0F) == 0x04)
+#define FILEF(c) (((c) & 0x0F) == 0x05)
+#define FILEG(c) (((c) & 0x0F) == 0x06)
+#define FILEH(c) (((c) & 0x0F) == 0x07)
+#define IS_WHITE_SQUARE_FR(f, r) (((f) + (r) - 1) & 1)
+#define IS_WHITE_SQUARE_COOR(c) (IS_WHITE_SQUARE_FR(FILE(c), RANK(c)))
+#define VALID_EP_SQUARE(c) (((c) == ILLEGAL_COOR) || ((c) == 0) || \
+ (RANK3(c)) || \
+ (RANK6(c)))
+
+// ----------------------------------------------------------------------
+//
+// a move (4 bytes) = from/to, moved, captured, promoted and special
+//
+// 31 24 23 16 15 12 11 8 7 4 3 0
+// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+// | from | to | moved | capt | prom | flags |
+// | | | | |
+// | | | | |
+// | | | | |
+// | | +-------+-------+-- type and
+// | | color of
+// | | piece moved
+// | | captured and
+// | | promote targ
+// +---------------+-- board location where
+// move begins and ends
+//
+//
+// Special flag asserted on special move types:
+//
+// if (special)
+// {
+// if (moved == PAWN)
+// {
+// if (promotion)
+// {
+// move is a promote (w/ or w/o capture)
+// }
+// else if (capture)
+// {
+// move is an en passant catpure
+// }
+// else
+// {
+// move is a double jump
+// }
+// }
+// else if (moved == KING)
+// {
+// move is a castle (long or short)
+// }
+// else
+// {
+// invalid use of special flag
+// }
+// }
+//
+typedef union _MOVE
+{
+ ULONG uMove;
+ struct
+ {
+ UCHAR cFrom : 8;
+ UCHAR cTo : 8;
+ UCHAR pMoved : 4;
+ UCHAR pCaptured : 4;
+ UCHAR pPromoted : 4;
+ UCHAR bvFlags : 4;
+ };
+} MOVE;
+
+#define IS_SAME_MOVE(a, b) \
+ (((a).uMove & 0x0FFFFFFF) == (((b).uMove & 0x0FFFFFFF)))
+
+#define MAKE_MOVE(from,to,piece,cap,prom,flags) \
+ (((ULONG)(from)) | \
+ ((ULONG)(to) << 8) | \
+ ((ULONG)(piece) << 16) | \
+ ((ULONG)(cap) << 20) | \
+ ((ULONG)(prom) << 24) | \
+ ((ULONG)(flags) << 28))
+
+#define MAKE_MOVE_WITH_NO_PROM_OR_FLAGS(from,to,piece,cap) \
+ (((ULONG)(from)) | \
+ ((ULONG)(to) << 8) | \
+ ((ULONG)(piece) << 16) | \
+ ((ULONG)(cap) << 20))
+
+//
+// Move flag values:
+//
+#define MOVE_FLAG_SPECIAL (1) // en pass, prom, castle, double
+#define IS_SPECIAL_MOVE(mv) \
+ ((mv).uMove & 0x10000000)
+
+#define IS_CASTLE(mv) \
+ (IS_SPECIAL_MOVE(mv) && IS_KING((mv).pMoved))
+
+#ifdef DEBUG
+#define IS_PROMOTION(mv) \
+ (IS_SPECIAL_MOVE(mv) && ((mv).pPromoted))
+#else
+#define IS_PROMOTION(mv) \
+ ((mv).pPromoted)
+#endif
+
+#define IS_CAPTURE_OR_PROMOTION(mv) \
+ ((mv).uMove & 0x0FF00000)
+
+#define IS_ENPASSANT(mv) \
+ (IS_SPECIAL_MOVE(mv) && (mv.pCaptured) && !IS_PROMOTION(mv))
+
+#define IS_DOUBLE_JUMP(mv) \
+ (IS_SPECIAL_MOVE(mv) && !IS_CAPTURE_OR_PROMOTION(mv))
+
+#define MOVE_FLAG_KILLERMATE (2) // killer mate
+#define IS_KILLERMATE_MOVE(mv) ((mv).uMove & 0x20000000)
+
+#define MOVE_FLAG_ESCAPING_CHECK (4) // escaping check
+#define IS_ESCAPING_CHECK(mv) ((mv).uMove & 0x40000000)
+
+#define MOVE_FLAG_CHECKING (8) // checking move
+#define IS_CHECKING_MOVE(mv) ((mv).uMove & 0x80000000)
+
+// ----------------------------------------------------------------------
+//
+// Move list
+//
+#define MAX_MOVE_LIST (MAX_MOVES_PER_GAME + MAX_PLY_PER_SEARCH)
+
+// ----------------------------------------------------------------------
+
+#pragma pack(1)
+typedef union _ATTACK_BITV
+{
+ ULONG uWholeThing;
+ struct
+ {
+ union
+ {
+ UCHAR uSmall;
+ struct
+ {
+ UCHAR uNumAttacks : 3; // 0..2
+ UCHAR uKing : 1; // 4..7
+ UCHAR uQueen : 1;
+ UCHAR uRook : 1;
+ UCHAR uMinor : 1;
+ UCHAR uPawn : 1;
+ } small;
+ };
+
+ // --------------------
+ union
+ {
+ USHORT uBig;
+ struct
+ {
+ USHORT uKing : 1; // 8..23
+ USHORT uQueens : 4;
+ USHORT uRooks : 4;
+ USHORT uMinors : 4;
+ USHORT uPawns : 2;
+ USHORT uUnusedFlag1 : 1;
+ } big;
+ };
+
+ // -------------------
+ union
+ {
+ UCHAR uXray;
+ struct
+ {
+ UCHAR uNumXrays : 3;
+ UCHAR uUnusedFlag2 : 1;
+ UCHAR uQueen : 1; // 24..28
+ UCHAR uRook : 1;
+ UCHAR uBishop : 1;
+ UCHAR uUnusedFlag3 : 1;
+ } xray;
+ };
+ };
+}
+ATTACK_BITV;
+
+#define UNSAFE_FOR_MINOR(x) ((ULONG)((x).uWholeThing) & 0x00000080UL)
+#define UNSAFE_FOR_ROOK(x) ((ULONG)((x).uWholeThing) & 0x000000C0UL)
+#define UNSAFE_FOR_QUEEN(x) ((ULONG)((x).uWholeThing) & 0x000000E0UL)
+
+#define PAWN_BIT 0x00000080UL
+#define MINOR_BIT 0x00000040UL
+#define MINOR_XRAY_BIT 0x40000000UL
+#define ROOK_BIT 0x00000020UL
+#define ROOK_XRAY_BIT 0x20000000UL
+#define QUEEN_BIT 0x00000010UL
+#define QUEEN_XRAY_BIT 0x10000000UL
+
+#define INVALID_PIECE_INDEX (17)
+#define IS_VALID_PIECE_INDEX(x) ((x) < INVALID_PIECE_INDEX)
+
+typedef union _SQUARE
+{
+ struct
+ {
+ PIECE pPiece;
+ ULONG uIndex;
+ };
+ ATTACK_BITV bvAttacks[2];
+}
+SQUARE;
+#pragma pack()
+
+//
+// POSITION
+//
+typedef struct _POSITION
+{
+ SQUARE rgSquare[128]; // where the pieces are,
+ // also, the attack table
+ UINT64 u64NonPawnSig; // hash signature
+ UINT64 u64PawnSig; // pawn hash signature
+ ULONG uToMove; // whose turn?
+ ULONG uFifty; // 50 moves w/o progress = draw
+ FLAG fCastled[2]; // record when sides have castled
+ BITV bvCastleInfo; // who can castle how?
+ COOR cEpSquare; // en-passant capture square
+
+ COOR cPawns[2][8]; // location of pawns on the board
+ ULONG uPawnMaterial[2]; // pawn material of each side
+ ULONG uPawnCount[2]; // number of pawns for each side
+
+ COOR cNonPawns[2][16]; // location of pieces on the board
+ ULONG uNonPawnMaterial[2]; // piece material of each side
+ ULONG uNonPawnCount[2][8]; // number of non-pawns / type
+ // 0 and 1 are the sum,
+ // 2..6 are per PIECE_TYPE
+
+ ULONG uWhiteSqBishopCount[2]; // num bishops on white squares
+ SCORE iMaterialBalance[2]; // material balance
+
+ // temporary storage space for use in eval
+ COOR cTrapped[2];
+ ULONG uArmyScaler[2];
+ ULONG uClosedScaler;
+ SCORE iScore[2];
+ SCORE iReducedMaterialDownScaler[2];
+ SCORE iTempScore;
+ ULONG uMinMobility[2];
+ COOR cPiece;
+ ULONG uMinorsAtHome[2];
+ BITBOARD bb;
+ ULONG uPiecesPointingAtKing[2];
+}
+POSITION;
+
+//
+// Castling permission bitvector flags.
+//
+#define CASTLE_WHITE_SHORT (1)
+#define CASTLE_WHITE_LONG (2)
+#define WHITE_CAN_CASTLE \
+ (CASTLE_WHITE_SHORT | CASTLE_WHITE_LONG)
+#define CASTLE_BLACK_SHORT (4)
+#define CASTLE_BLACK_LONG (8)
+#define BLACK_CAN_CASTLE \
+ (CASTLE_BLACK_SHORT | CASTLE_BLACK_LONG)
+#define CASTLE_NONE_POSSIBLE (0)
+#define CASTLE_ALL_POSSIBLE \
+ (WHITE_CAN_CASTLE | BLACK_CAN_CASTLE)
+
+// ----------------------------------------------------------------------
+//
+// Move stack
+//
+#define MAX_MOVE_STACK (MAX_PLY_PER_SEARCH * \
+ MAX_MOVES_PER_PLY)
+
+//
+// Main part of the move stack, triads of moves, their values and flags
+// that denote where the values came from
+//
+#define MVF_MOVE_SEARCHED (1)
+#define MVF_EXTEND_MOVE (2)
+#define MVF_REDUCE_MOVE (4)
+#define MVF_PRUNE_SUBTREE (8)
+
+typedef struct _MOVE_STACK_MOVE_VALUE_FLAGS
+{
+ SCORE iValue;
+ MOVE mv;
+ BITV bvFlags;
+}
+MOVE_STACK_MOVE_VALUE_FLAGS;
+
+typedef struct _KEY_POINTER
+{
+ int iPointer;
+ ULONG uKey;
+}
+KEY_POINTER;
+
+typedef union _GENERATOR_FLAGS
+{
+ struct {
+ UCHAR uMoveCount;
+ UCHAR uKingMoveCount;
+ UCHAR uCheckingPieces;
+ UCHAR uUnused;
+ };
+ ULONG uAllGenFlags;
+}
+GENERATOR_FLAGS;
+
+//
+// A move stack
+//
+typedef struct _MOVE_STACK
+{
+#ifdef DEBUG
+ POSITION board[MAX_PLY_PER_SEARCH];
+#endif
+ //
+ // Unblocked squares map, used for check detection
+ //
+ ULONG uUnblockedKeyValue[MAX_PLY_PER_SEARCH];
+ KEY_POINTER sUnblocked[MAX_PLY_PER_SEARCH][128];
+
+ //
+ // The main move list, a long series of moves, their values and some
+ // flag bits to tell search what the values are based upon.
+ //
+ MOVE_STACK_MOVE_VALUE_FLAGS mvf[MAX_MOVE_STACK];
+
+ //
+ // uBegin[ply] and uEnd[ply] specify the start and end of moves gen-
+ // erated for a position at ply distance from the root.
+ //
+ ULONG uPly;
+ ULONG uBegin[MAX_PLY_PER_SEARCH];
+ ULONG uEnd[MAX_PLY_PER_SEARCH];
+ MOVE mvHash[MAX_PLY_PER_SEARCH];
+ GENERATOR_FLAGS sGenFlags[MAX_PLY_PER_SEARCH];
+}
+MOVE_STACK;
+
+#define GENERATE_NO_MOVES \
+ ctx->sMoveStack.uEnd[ctx->uPly] = \
+ ctx->sMoveStack.uBegin[ctx->uPly] + 1; \
+ ctx->sMoveStack.uBegin[ctx->uPly + 1] = \
+ ctx->sMoveStack.uEnd[ctx->uPly]
+
+#define GENERATE_ALL_MOVES (1)
+#define GENERATE_ESCAPES (2)
+#define GENERATE_CAPTURES_PROMS_CHECKS (3)
+#define GENERATE_CAPTURES_PROMS (4)
+#define GENERATE_DONT_SCORE (5)
+#ifdef TEST
+#define GENERATE_ALL_MOVES_CHECK_OK (6)
+#endif
+
+#define MOVE_COUNT(ctx, x) \
+ (((ctx)->sMoveStack.uEnd[(x)]) - (ctx)->sMoveStack.uBegin[(x)])
+#define ONE_LEGAL_MOVE(ctx, x) \
+ (MOVE_COUNT(ctx, x) == 1)
+#define NUM_KING_MOVES(ctx, x) \
+ ((ctx)->sMoveStack.sGenFlags[(x)].uKingMoveCount)
+#define NUM_CHECKING_PIECES(ctx, x) \
+ ((ctx)->sMoveStack.sGenFlags[(x)].uCheckingPieces)
+
+
+// ----------------------------------------------------------------------
+//
+// Accumulators
+//
+typedef struct _COUNTERS
+{
+ struct
+ {
+ UINT64 u64Probes;
+ UINT64 u64OverallHits;
+ UINT64 u64UsefulHits;
+ UINT64 u64UpperBoundHits;
+ UINT64 u64LowerBoundHits;
+ UINT64 u64ExactScoreHits;
+ }
+ hash;
+
+ struct
+ {
+ UINT64 u64Probes;
+ UINT64 u64Hits;
+ }
+ pawnhash;
+
+ struct
+ {
+ UINT64 u64TotalNodeCount;
+ UINT64 u64QNodeCount;
+ UINT64 u64LeafCount;
+ UINT64 u64TerminalPositionCount;
+ UINT64 u64BetaCutoffs;
+ UINT64 u64BetaCutoffsOnFirstMove;
+ UINT64 u64NullMoves;
+ UINT64 u64NullMoveSuccess;
+#ifdef TEST_NULL
+ UINT64 u64QuickNullSuccess;
+ UINT64 u64QuickNullDeferredSuccess;
+ UINT64 u64QuickNullFailures;
+ UINT64 u64AvoidNullSuccess;
+ UINT64 u64AvoidNullFailures;
+#endif
+ UINT64 u64EvalHashHits;
+ UINT64 u64LazyEvals;
+ UINT64 u64FullEvals;
+ UINT64 u64CyclesInEval;
+ }
+ tree;
+
+ struct
+ {
+ ULONG uNumSplits;
+ ULONG uNumSplitsTerminated;
+ }
+ parallel;
+
+ struct
+ {
+ ULONG uPawnPush;
+ ULONG uCheck;
+ ULONG uMateThreat;
+ ULONG uRecapture;
+ ULONG uOneLegalMove;
+ ULONG uNoLegalKingMoves;
+ ULONG uMultiCheck;
+ ULONG uSingularMove;
+ ULONG uZugzwang;
+ ULONG uSingularReplyToCheck;
+ ULONG uEndgame;
+ ULONG uBotvinnikMarkoff;
+ ULONG uQExtend;
+ }
+ extension;
+
+ struct
+ {
+ ULONG uProbes;
+ ULONG uHits;
+ }
+ egtb;
+}
+COUNTERS;
+
+typedef struct _CUMULATIVE_SEARCH_FLAGS
+{
+ // search
+ ULONG uNumChecks[2]; // not used
+ FLAG fInSuspiciousBranch; // not used
+ FLAG fInReducedDepthBranch; // not used
+ FLAG fAvoidNullmove; // restore
+ FLAG fVerifyNullmove; // restore
+
+ // qsearch
+ ULONG uQsearchDepth; // restore
+ ULONG uQsearchNodes; // incremental
+ ULONG uQsearchCheckDepth; // restore
+ FLAG fCouldStandPat[2]; // restore
+}
+CUMULATIVE_SEARCH_FLAGS;
+
+// ----------------------------------------------------------------------
+//
+// Searcher thread record
+//
+typedef struct _SPLIT_INFO
+{
+ // locks / counters
+ volatile ULONG uLock; // lock for this split node
+ volatile ULONG uNumThreadsHelping; // num threads in this node
+ volatile FLAG fTerminate; // signal helpers to terminate
+
+ // moves in the split node
+ ULONG uRemainingMoves; // num moves remaining to do
+ ULONG uOnDeckMove; // next move to do
+ ULONG uNumMoves;
+ ULONG uAlreadyDone;
+ MOVE_STACK_MOVE_VALUE_FLAGS
+ mvf[MAX_MOVES_PER_PLY]; // the moves to search
+
+ // input to the split node
+ POSITION sRootPosition; // the root position
+ MOVE mvPathToHere[MAX_PLY_PER_SEARCH]; // path from root to split
+ MOVE mvLast; // last move before split
+ ULONG uDepth; // remaining depth at split
+ INT iPositionExtend; // positional extension
+ SCORE iAlpha; // original alpha at split
+ SCORE iBeta; // beta at split
+ ULONG uSplitPositional; // pos->uPositional at split
+ CUMULATIVE_SEARCH_FLAGS sSearchFlags; // flags at split time
+
+ // output from the split node
+ MOVE mvBest; // the best move
+ SCORE iBestScore; // it's score
+ COUNTERS sCounters; // updated counters
+ MOVE PV[MAX_PLY_PER_SEARCH];
+
+#ifdef DEBUG
+ ULONG uSplitPly;
+ POSITION sSplitPosition;
+#endif
+}
+SPLIT_INFO;
+
+typedef struct _PLY_INFO
+{
+#ifdef DEBUG
+ POSITION sPosition;
+ SCORE iAlpha;
+ SCORE iBeta;
+#endif
+ SCORE iEval;
+ INT iExtensionAmount;
+ FLAG fInCheck;
+ FLAG fInQsearch;
+ MOVE mv;
+ MOVE mvBest;
+ MOVE PV[MAX_PLY_PER_SEARCH];
+
+ SCORE iKingScore[2];
+ ULONG uMinMobility[2];
+ UINT64 u64NonPawnSig;
+ UINT64 u64PawnSig;
+ UINT64 u64Sig;
+ ULONG uFifty;
+ FLAG fCastled[2];
+ ULONG uTotalNonPawns;
+ BITV bvCastleInfo;
+ COOR cEpSquare;
+}
+PLY_INFO;
+
+#define EVAL_HASH
+#ifdef EVAL_HASH
+#define EVAL_HASH_TABLE_SIZE (2097152) // 32Mb (per thread)
+typedef struct _EVAL_HASH_ENTRY
+{
+ UINT64 u64Key;
+ SCORE iEval;
+ ULONG uPositional;
+ COOR cTrapped[2];
+
+} EVAL_HASH_ENTRY;
+#endif
+
+#define PAWN_HASH_TABLE_SIZE (131072) // 5.5Mb (per thread)
+typedef struct _PAWN_HASH_ENTRY
+{
+ UINT64 u64Key;
+ BITBOARD bbPawnLocations[2];
+ BITBOARD bbPasserLocations[2];
+ BITBOARD bbStationaryPawns[2];
+ SHORT iScore[2];
+ UCHAR uCountPerFile[2][10];
+ UCHAR uNumRammedPawns;
+ UCHAR uNumUnmovedPawns[2];
+}
+PAWN_HASH_ENTRY;
+
+#define NUM_SPLIT_PTRS_IN_CONTEXT (8)
+
+typedef struct _SEARCHER_THREAD_CONTEXT
+{
+ ULONG uPly; // its distance from root
+ ULONG uPositional; // positional component of score
+ POSITION sPosition; // the board
+ MOVE_STACK sMoveStack; // the move stack
+ CUMULATIVE_SEARCH_FLAGS sSearchFlags;
+ PLY_INFO sPlyInfo[MAX_PLY_PER_SEARCH+1];
+ MOVE mvKiller[MAX_PLY_PER_SEARCH][2];
+ MOVE mvKillerEscapes[MAX_PLY_PER_SEARCH][2];
+ MOVE mvNullmoveRefutations[MAX_PLY_PER_SEARCH];
+ COUNTERS sCounters;
+ ULONG uThreadNumber;
+ SPLIT_INFO *pSplitInfo[NUM_SPLIT_PTRS_IN_CONTEXT];
+ MOVE mvRootMove;
+ SCORE iRootScore;
+ ULONG uRootDepth;
+ PAWN_HASH_ENTRY rgPawnHash[PAWN_HASH_TABLE_SIZE];
+#ifdef EVAL_HASH
+ EVAL_HASH_ENTRY rgEvalHash[EVAL_HASH_TABLE_SIZE];
+#endif
+ CHAR szLastPV[SMALL_STRING_LEN_CHAR];
+}
+SEARCHER_THREAD_CONTEXT;
+
+//
+// When I added the pawn hash table and eval hash tables to searcher
+// thread contexts they became too heavy to just allocate on the fly
+// for things like checking the legality of SAN moves or seeing if an
+// opening book line leads to a draw. This
+// LIGHTWEIGHT_SEARCHER_CONTEXT structure can be cast into a full
+// SEARCHER_THREAD_CONTEXT and passed safely into the Generate,
+// MakeMove and UnMakeMove functions because they presently only
+// need:
+//
+// 1. uPly
+// 2. sPosition
+// 3. sPlyInfo
+// 4. sMoveStack
+//
+typedef struct _LIGHTWEIGHT_SEARCHER_CONTEXT
+{
+ ULONG uPly;
+ ULONG uPositional;
+ POSITION sPosition;
+ MOVE_STACK sMoveStack;
+ CUMULATIVE_SEARCH_FLAGS sSearchFlags;
+ PLY_INFO sPlyInfo[MAX_PLY_PER_SEARCH+1];
+}
+LIGHTWEIGHT_SEARCHER_CONTEXT;
+
+// ----------------------------------------------------------------------
+//
+// Global game options
+//
+typedef struct _GAME_OPTIONS
+{
+ ULONG uMyClock;
+ ULONG uOpponentsClock;
+ FLAG fGameIsRated;
+ FLAG fOpponentIsComputer;
+ ULONG uSecPerMove;
+ ULONG uMaxDepth;
+ UINT64 u64MaxNodeCount;
+ FLAG fShouldPonder;
+ FLAG fPondering;
+ FLAG fThinking;
+ FLAG fSuccessfulPonder;
+ MOVE mvPonder;
+ FLAG fShouldPost;
+ FLAG fForceDrawWorthZero;
+ ULONG uMyIncrement;
+ ULONG uMovesPerTimePeriod;
+ CHAR szAnalyzeProgressReport[SMALL_STRING_LEN_CHAR];
+ FLAG fShouldAnnounceOpening;
+ SCORE iLastEvalScore;
+ UINT64 u64NodesSearched;
+ CHAR szLogfile[SMALL_STRING_LEN_CHAR];
+ CHAR szEGTBPath[SMALL_STRING_LEN_CHAR];
+ CHAR szBookName[SMALL_STRING_LEN_CHAR];
+ ULONG uNumProcessors;
+ ULONG uNumHashTableEntries;
+ FLAG fNoInputThread;
+ FLAG fVerbosePosting;
+ FLAG fRunningUnderXboard;
+ FLAG fStatusLine;
+ FLAG fFastScript;
+ FLAG fShouldResign;
+
+ enum
+ {
+ CLOCK_NORMAL = 0,
+ CLOCK_FIXED,
+ CLOCK_INCREMENT,
+ CLOCK_NONE
+ }
+ eClock;
+
+ enum
+ {
+ GAME_UNKNOWN = 0,
+ GAME_BULLET,
+ GAME_BLITZ,
+ GAME_STANDARD
+ }
+ eGameType;
+
+ enum
+ {
+ I_PLAY_WHITE = 0,
+ I_PLAY_BLACK,
+ FORCE_MODE,
+ EDIT_MODE,
+ ANALYZE_MODE
+ }
+ ePlayMode;
+}
+GAME_OPTIONS;
+extern GAME_OPTIONS g_Options;
+
+// ----------------------------------------------------------------------
+//
+// Move timer
+//
+
+#define TIMER_SEARCHING_FIRST_MOVE (0x1)
+#define TIMER_SEARCHING_IMPORTANT_MOVE (0x2)
+#define TIMER_RESOLVING_ROOT_FL (0x4)
+#define TIMER_RESOLVING_ROOT_FH (0x8)
+#define TIMER_JUST_OUT_OF_BOOK (0x10)
+#define TIMER_CURRENT_OBVIOUS (0x20)
+#define TIMER_CURRENT_WONT_UNBLOCK (0x40)
+#define TIMER_ROOT_POSITION_CRITICAL (0x80)
+#define TIMER_MOVE_IMMEDIATELY (0x100)
+#define TIMER_MANY_ROOT_FLS (0x200)
+#define TIMER_STOPPING (0x400)
+#define TIMER_SPLIT_FAILED (0x800)
+
+typedef struct _MOVE_TIMER
+{
+ double dStartTime;
+ double dEndTime;
+ double dSoftTimeLimit;
+ double dHardTimeLimit;
+ ULONG uNodeCheckMask;
+ volatile BITV bvFlags;
+}
+MOVE_TIMER;
+
+// ----------------------------------------------------------------------
+//
+// Special move tag literals
+//
+#define ILLEGALMOVE ((ULONG)0x1DDD8888)
+
+//
+// useful macros
+//
+#ifdef DEBUG
+void
+_assert(CHAR *szFile, ULONG uLine);
+
+#define ASSERT(x) if (x) \
+ { ; } \
+ else \
+ { _assert(__FILE__, __LINE__); }
+#define VERIFY(x) ASSERT(x)
+#else
+#define ASSERT(x) ;
+#define VERIFY(x) x;
+#endif // DEBUG
+
+#ifdef PERF_COUNTERS
+#define INC(x) ((x) += 1)
+#else
+#define INC(x)
+#endif
+
+#define BREAKPOINT SystemDebugBreakpoint()
+
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+#ifdef _X86_
+//
+// Note: MAXU, MINU and ABS_DIFF require arguments with the high order
+// bit CLEAR to work right.
+//
+// These are branchless constructs. MAXU and MINU are equivalent to
+// MIN and MAX (with the above restriction on inputs)
+//
+// MIN0 and MAX0 are equivalent to MAX(0, x) and MIN(0, x). These
+// macros have no restiction on argument type.
+//
+// ABS_DIFF is equivalent to abs(x - y). Again, x and y must have
+// their high-order bits CLEAR for this to work.
+//
+// Note: gcc generates code with cmovs so no need for MAXU/MINU on
+// that compiler.
+//
+#define MINU(x, y) \
+ (((((int)((x)-(y)))>>31) & ((x)-(y)))+(y))
+#define MAXU(x, y) \
+ (((((int)((x)-(y)))>>31) & ((y)-(x)))+(x))
+#define MIN0(x) \
+ ((x) & (((int)(x)) >> 31))
+#define MAX0(x) \
+ ((x) & ~(((int)(x)) >> 31))
+
+
+#define ABS_DIFF(a, b) \
+ (((b)-(a)) - ((((b) - (a)) & (((int)((b) - (a))) >> 31) ) << 1))
+
+#endif // _X86_
+
+#ifndef MINU
+#define MINU(x, y) (MIN((x), (y)))
+#endif
+
+#ifndef MAXU
+#define MAXU(x, y) (MAX((x), (y)))
+#endif
+
+#ifndef MIN0
+#define MIN0(x) (MIN((x), 0))
+#endif
+
+#ifndef MAX0
+#define MAX0(x) (MAX((x), 0))
+#endif
+
+#ifndef ABS_DIFF
+#define ABS_DIFF(a, b) (abs((a) - (b)))
+#endif
+
+#define FILE_DISTANCE(a, b) (ABS_DIFF(FILE((a)), FILE((b))))
+#define RANK_DISTANCE(a, b) (ABS_DIFF(((a) & 0xF0), ((b) & 0xF0)) >> 4)
+#define REAL_DISTANCE(a, b) (MAXU(FILE_DISTANCE((a), (b)), \
+ RANK_DISTANCE((a), (b))))
+#ifdef DEBUG
+#define DISTANCE(a, b) DistanceBetweenSquares((a), (b))
+#else
+#define DISTANCE(a, b) g_pDistance[(a) - (b)]
+#endif // DEBUG
+
+#define IS_EMPTY( square ) (!(square))
+#define IS_OCCUPIED( square ) ((square))
+
+#define IS_DEAD( listindex ) ((listindex) > 119)
+#define IS_ALIVE( listindex ) ((listindex) <= 119)
+#define ILLEGAL_COOR (0x88)
+#define EDGE_DISTANCE(c) (MIN(MIN(abs(RANK(c) - 7), RANK(c)), \
+ MIN(abs(FILE(c) - 7), FILE(c))))
+#define NOT_ON_EDGE(c) ((((c) & 0xF0) != 0x00) && \
+ (((c) & 0xF0) != 0x70) && \
+ (((c) & 0x0F) != 0x00) && \
+ (((c) & 0x0F) != 0x07))
+#define ON_EDGE(c) (RANK8(c) || \
+ RANK1(c) || \
+ FILEA(c) || \
+ FILEH(c))
+#define CORNER_DISTANCE(c) (MAX(MIN((ULONG)abs(RANK(c) - 7), RANK(c)),\
+ MIN((ULONG)abs(FILE(c) - 7), FILE(c))))
+#define IN_CORNER(c) (((c) == A8) || \
+ ((c) == A1) || \
+ ((c) == H8) || \
+ ((c) == H1))
+#define WHITE_CORNER_DISTANCE(c) (MIN(DISTANCE((c), A8), \
+ DISTANCE((c), H1)))
+#define BLACK_CORNER_DISTANCE(c) (MIN(DISTANCE((c), H8), \
+ DISTANCE((c), A1)))
+#define SYM_SQ(c) ((7 - (((c) & 0xF0) >> 4)) << 4) \
+ | (7 - ((c) & 0x0F))
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a[0])))
+#define MAKE_PSQT(a, b, c, d) (((a) << 24) | ((b) << 16) | \
+ ((c) << 8) | (d))
+#define TO64(x) ((x) & 0x7) + ((0x7 - ((x)>>4)) << 3)
+#define COOR_TO_BIT_NUMBER(c) (((((c) & 0x70) >> 1) | ((c) & 0x7)))
+#define SLOWCOOR_TO_BB(c) (1ULL << COOR_TO_BIT_NUMBER(c))
+#define COOR_TO_BB(c) (BBSQUARE[COOR_TO_BIT_NUMBER(c)])
+#define SLOW_BIT_NUMBER_TO_COOR(b) ((((b) / 8) << 4) + ((b) & 7))
+#define BIT_NUMBER_TO_COOR(b) ((((b) & 0xF8) << 1) | ((b) & 7))
+
+#define BBRANK88 \
+ SLOWCOOR_TO_BB(A8) | SLOWCOOR_TO_BB(B8) | SLOWCOOR_TO_BB(C8) | \
+ SLOWCOOR_TO_BB(D8) | SLOWCOOR_TO_BB(E8) | SLOWCOOR_TO_BB(F8) | \
+ SLOWCOOR_TO_BB(G8) | SLOWCOOR_TO_BB(H8)
+
+#define BBRANK77 \
+ SLOWCOOR_TO_BB(A7) | SLOWCOOR_TO_BB(B7) | SLOWCOOR_TO_BB(C7) | \
+ SLOWCOOR_TO_BB(D7) | SLOWCOOR_TO_BB(E7) | SLOWCOOR_TO_BB(F7) | \
+ SLOWCOOR_TO_BB(G7) | SLOWCOOR_TO_BB(H7)
+
+#define BBRANK66 \
+ SLOWCOOR_TO_BB(A6) | SLOWCOOR_TO_BB(B6) | SLOWCOOR_TO_BB(C6) | \
+ SLOWCOOR_TO_BB(D6) | SLOWCOOR_TO_BB(E6) | SLOWCOOR_TO_BB(F6) | \
+ SLOWCOOR_TO_BB(G6) | SLOWCOOR_TO_BB(H6)
+
+#define BBRANK55 \
+ SLOWCOOR_TO_BB(A5) | SLOWCOOR_TO_BB(B5) | SLOWCOOR_TO_BB(C5) | \
+ SLOWCOOR_TO_BB(D5) | SLOWCOOR_TO_BB(E5) | SLOWCOOR_TO_BB(F5) | \
+ SLOWCOOR_TO_BB(G5) | SLOWCOOR_TO_BB(H5)
+
+#define BBRANK44 \
+ SLOWCOOR_TO_BB(A4) | SLOWCOOR_TO_BB(B4) | SLOWCOOR_TO_BB(C4) | \
+ SLOWCOOR_TO_BB(D4) | SLOWCOOR_TO_BB(E4) | SLOWCOOR_TO_BB(F4) | \
+ SLOWCOOR_TO_BB(G4) | SLOWCOOR_TO_BB(H4)
+
+#define BBRANK33 \
+ SLOWCOOR_TO_BB(A3) | SLOWCOOR_TO_BB(B3) | SLOWCOOR_TO_BB(C3) | \
+ SLOWCOOR_TO_BB(D3) | SLOWCOOR_TO_BB(E3) | SLOWCOOR_TO_BB(F3) | \
+ SLOWCOOR_TO_BB(G3) | SLOWCOOR_TO_BB(H3)
+
+#define BBRANK22 \
+ SLOWCOOR_TO_BB(A2) | SLOWCOOR_TO_BB(B2) | SLOWCOOR_TO_BB(C2) | \
+ SLOWCOOR_TO_BB(D2) | SLOWCOOR_TO_BB(E2) | SLOWCOOR_TO_BB(F2) | \
+ SLOWCOOR_TO_BB(G2) | SLOWCOOR_TO_BB(H2)
+
+#define BBRANK11 \
+ SLOWCOOR_TO_BB(A1) | SLOWCOOR_TO_BB(B1) | SLOWCOOR_TO_BB(C1) | \
+ SLOWCOOR_TO_BB(D1) | SLOWCOOR_TO_BB(E1) | SLOWCOOR_TO_BB(F1) | \
+ SLOWCOOR_TO_BB(G1) | SLOWCOOR_TO_BB(H1)
+
+#define BBFILEA \
+ SLOWCOOR_TO_BB(A1) | SLOWCOOR_TO_BB(A2) | SLOWCOOR_TO_BB(A3) | \
+ SLOWCOOR_TO_BB(A4) | SLOWCOOR_TO_BB(A5) | SLOWCOOR_TO_BB(A6) | \
+ SLOWCOOR_TO_BB(A7) | SLOWCOOR_TO_BB(A8)
+
+#define BBFILEB \
+ SLOWCOOR_TO_BB(B1) | SLOWCOOR_TO_BB(B2) | SLOWCOOR_TO_BB(B3) | \
+ SLOWCOOR_TO_BB(B4) | SLOWCOOR_TO_BB(B5) | SLOWCOOR_TO_BB(B6) | \
+ SLOWCOOR_TO_BB(B7) | SLOWCOOR_TO_BB(B8)
+
+#define BBFILEC \
+ SLOWCOOR_TO_BB(C1) | SLOWCOOR_TO_BB(C2) | SLOWCOOR_TO_BB(C3) | \
+ SLOWCOOR_TO_BB(C4) | SLOWCOOR_TO_BB(C5) | SLOWCOOR_TO_BB(C6) | \
+ SLOWCOOR_TO_BB(C7) | SLOWCOOR_TO_BB(C8)
+
+#define BBFILED \
+ SLOWCOOR_TO_BB(D1) | SLOWCOOR_TO_BB(D2) | SLOWCOOR_TO_BB(D3) | \
+ SLOWCOOR_TO_BB(D4) | SLOWCOOR_TO_BB(D5) | SLOWCOOR_TO_BB(D6) | \
+ SLOWCOOR_TO_BB(D7) | SLOWCOOR_TO_BB(D8)
+
+#define BBFILEE \
+ SLOWCOOR_TO_BB(E1) | SLOWCOOR_TO_BB(E2) | SLOWCOOR_TO_BB(E3) | \
+ SLOWCOOR_TO_BB(E4) | SLOWCOOR_TO_BB(E5) | SLOWCOOR_TO_BB(E6) | \
+ SLOWCOOR_TO_BB(E7) | SLOWCOOR_TO_BB(E8)
+
+#define BBFILEF \
+ SLOWCOOR_TO_BB(F1) | SLOWCOOR_TO_BB(F2) | SLOWCOOR_TO_BB(F3) | \
+ SLOWCOOR_TO_BB(F4) | SLOWCOOR_TO_BB(F5) | SLOWCOOR_TO_BB(F6) | \
+ SLOWCOOR_TO_BB(F7) | SLOWCOOR_TO_BB(F8)
+
+#define BBFILEG \
+ SLOWCOOR_TO_BB(G1) | SLOWCOOR_TO_BB(G2) | SLOWCOOR_TO_BB(G3) | \
+ SLOWCOOR_TO_BB(G4) | SLOWCOOR_TO_BB(G5) | SLOWCOOR_TO_BB(G6) | \
+ SLOWCOOR_TO_BB(G7) | SLOWCOOR_TO_BB(G8)
+
+#define BBFILEH \
+ SLOWCOOR_TO_BB(H1) | SLOWCOOR_TO_BB(H2) | SLOWCOOR_TO_BB(H3) | \
+ SLOWCOOR_TO_BB(H4) | SLOWCOOR_TO_BB(H5) | SLOWCOOR_TO_BB(H6) | \
+ SLOWCOOR_TO_BB(H7) | SLOWCOOR_TO_BB(H8)
+
+#define BBRANK72 \
+ BBRANK77 | BBRANK66 | BBRANK55 | BBRANK44 | BBRANK33 | BBRANK22
+
+#define BBRANK62 \
+ BBRANK66 | BBRANK55 | BBRANK44 | BBRANK33 | BBRANK22
+
+#define BBRANK52 \
+ BBRANK55 | BBRANK44 | BBRANK33 | BBRANK22
+
+#define BBRANK42 \
+ BBRANK44 | BBRANK33 | BBRANK22
+
+#define BBRANK32 \
+ BBRANK33 | BBRANK22
+
+#define BBRANK27 \
+ BBRANK22 | BBRANK33 | BBRANK44 | BBRANK55 | BBRANK66 | BBRANK77
+
+#define BBRANK37 \
+ BBRANK33 | BBRANK44 | BBRANK55 | BBRANK66 | BBRANK77
+
+#define BBRANK47 \
+ BBRANK44 | BBRANK55 | BBRANK66 | BBRANK77
+
+#define BBRANK57 \
+ BBRANK55 | BBRANK66 | BBRANK77
+
+#define BBRANK67 \
+ BBRANK66 | BBRANK77
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+//
+// util.c
+//
+COMMAND(LearnPsqtFromPgn);
+
+COMMAND(GeneratePositionAndBestMoveSuite);
+
+CHAR *
+WalkPV(SEARCHER_THREAD_CONTEXT *ctx);
+
+CHAR *
+ReadNextGameFromPgnFile(FILE *pf);
+
+COOR
+DistanceBetweenSquares(COOR a, COOR b);
+
+void CDECL
+Trace(CHAR *szMessage, ...);
+
+void CDECL
+Log(CHAR *szMessage, ...);
+
+void CDECL
+Bug(CHAR *szMessage, ...);
+
+char *
+FindChunk(char *sz, ULONG uTargetChunk);
+
+FLAG
+BufferIsZeroed(BYTE *p, ULONG u);
+
+char *
+ColorToString(ULONG u);
+
+char *
+CoorToString(COOR c);
+
+char *
+ScoreToString(SCORE iScore);
+
+char *
+TimeToString(double d);
+
+ULONG
+AcquireSpinLock(volatile ULONG *pSpinlock);
+
+FLAG
+TryAcquireSpinLock(volatile ULONG *pSpinlock);
+
+void
+ReleaseSpinLock(volatile ULONG *pSpinLock);
+
+BYTE
+Checksum(BYTE *p, ULONG uSize);
+
+FLAG
+BackupFile(CHAR *szFile);
+
+void
+UtilPrintPV(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta,
+ SCORE iScore,
+ MOVE mv);
+
+#define CANNOT_INITIALIZE_SPLIT (1)
+#define INCONSISTENT_POSITION (2)
+#define UNEXPECTED_SYSTEM_CALL_FAILURE (3)
+#define SHOULD_NOT_GET_HERE (4)
+#define GOT_ILLEGAL_MOVE_WHILE_PONDERING (5)
+#define CANNOT_OFFICIALLY_MAKE_MOVE (6)
+#define DETECTED_INCORRECT_INITIALIZATION (7)
+#define INCONSISTENT_STATE (8)
+#define FATAL_ACCESS_DENIED (9)
+#define TESTCASE_FAILURE (10)
+#define INITIALIZATION_FAILURE (11)
+
+void
+UtilPanic(ULONG uPanicCode,
+ POSITION *pos,
+ void *a1,
+ void *a2,
+ void *a3,
+ char *file, ULONG line);
+
+
+//
+// main.c
+//
+#define LOGFILE_NAME "typhoon.log"
+extern FILE *g_pfLogfile;
+
+void
+Banner(void);
+
+FLAG
+PreGameReset(FLAG fResetBoard);
+
+//
+// system dependent exports (see win32.c or fbsd.c)
+//
+typedef ULONG (THREAD_ENTRYPOINT)(ULONG);
+
+#ifdef DEBUG
+ULONG
+GetHeapMemoryUsage(void);
+#endif
+
+void
+SystemDebugBreakpoint(void);
+
+CHAR *
+SystemStrDup(CHAR *p);
+
+double
+SystemTimeStamp(void);
+
+FLAG
+SystemDoesFileExist(CHAR *szFilename);
+
+void
+SystemDeferExecution(ULONG uMs);
+
+void
+SystemFreeMemory(void *pMem);
+
+void *
+SystemAllocateMemory(ULONG dwSizeBytes);
+
+FLAG
+SystemMakeMemoryReadOnly(void *pMemory, ULONG dwSizeBytes);
+
+FLAG
+SystemMakeMemoryNoAccess(void *pMemory, ULONG dwSizeBytes);
+
+FLAG
+SystemMakeMemoryReadWrite(void *pMemory, ULONG dwSizeBytes);
+
+FLAG
+SystemDependentInitialization(void);
+
+UINT64 FASTCALL
+SystemReadTimeStampCounter(void);
+
+//
+// This routine _must_ implement a full memory fence -- it is used in
+// util.c to implement spinlocks.
+//
+FLAG
+SystemCreateThread(THREAD_ENTRYPOINT *pEntry, ULONG uParam, ULONG *puHandle);
+
+FLAG
+SystemWaitForThreadToExit(ULONG uThreadHandle);
+
+FLAG
+SystemGetThreadExitCode(ULONG uThreadHandle, ULONG *puCode);
+
+FLAG
+SystemDeleteThread(ULONG uThreadHandle);
+
+CHAR *
+SystemGetDateString(void);
+
+CHAR *
+SystemGetTimeString(void);
+
+FLAG
+SystemCopyFile(CHAR *szSource, CHAR *szDest);
+
+FLAG
+SystemDeleteFile(CHAR *szFile);
+
+ULONG
+SystemCreateLock(void);
+
+FLAG
+SystemDeleteLock(ULONG u);
+
+FLAG
+SystemBlockingWaitForLock(ULONG u);
+
+FLAG
+SystemReleaseLock(ULONG u);
+
+ULONG
+SystemCreateSemaphore(ULONG u);
+
+FLAG
+SystemDeleteSemaphore(ULONG u);
+
+void
+SystemReleaseSemaphoreResource(ULONG u);
+
+void
+SystemObtainSemaphoreResource(ULONG u);
+
+
+//
+// fen.c
+//
+#define STARTING_POSITION_IN_FEN \
+ "rnbqkbnr/pppppppp/--------/8/8/--------/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
+
+FLAG
+LooksLikeFen(char *szFen);
+
+char *
+PositionToFen(POSITION *p);
+
+FLAG
+FenToPosition(POSITION *p, char *szFen);
+
+//
+// testfen.c
+//
+#ifdef TEST
+void
+TestFenCode(void);
+#endif
+
+//
+// piece.c
+//
+// INVERTED VALUE == (VALUE_QUEEN / VALUE_PIECE) * VALUE_PAWN;
+#define VALUE_PAWN 100
+#define INVERT_PAWN 900
+#define VALUE_KNIGHT 300
+#define INVERT_KNIGHT 300
+#define VALUE_BISHOP 300
+#define INVERT_BISHOP 300
+#define VALUE_ROOK 500
+#define INVERT_ROOK 180
+#define VALUE_QUEEN 975
+#define INVERT_QUEEN 100
+#define VALUE_KING (INFINITY)
+#define INVERT_KING 1
+
+#define VALUE_FULL_ARMY (8 * VALUE_PAWN) + (2 * VALUE_KNIGHT) + \
+ (2 * VALUE_BISHOP) + (2 * VALUE_ROOK) + \
+ VALUE_QUEEN + VALUE_KING
+#define VALUE_MAX_ARMY (9 * VALUE_QUEEN) + (2 * VALUE_KNIGHT) + \
+ (2 * VALUE_BISHOP) + (2 * VALUE_ROOK) + \
+ VALUE_KING
+
+typedef struct _PIECE_DATA
+{
+ ULONG uValue;
+ ULONG uValueOver100;
+ ULONG uInvertedValue;
+ CHAR *szName;
+} PIECE_DATA;
+
+extern PIECE_DATA g_PieceData[8];
+
+#define PIECE_VALUE_OVER_100(p) (g_PieceData[PIECE_TYPE(p)].uValueOver100)
+extern ULONG
+PieceValueOver100(PIECE p);
+
+#define PIECE_VALUE(p) (g_PieceData[PIECE_TYPE(p)].uValue)
+extern ULONG
+PieceValue(PIECE p);
+
+#define INVERTED_PIECE_VALUE(p) (g_PieceData[PIECE_TYPE(p)].uInvertedValue)
+extern ULONG
+PieceInvertedValue(PIECE p);
+
+CHAR *
+PieceAbbrev(PIECE p);
+
+//
+// board.c
+//
+FLAG
+VerifyPositionConsistency(POSITION *pos, FLAG fContinueOnError);
+
+FLAG
+PositionsAreEquivalent(POSITION *p1, POSITION *p2);
+
+CHAR *
+DrawTextBoardFromPosition(POSITION *pos);
+
+void
+DumpPosition(POSITION *pos);
+
+CHAR *
+CastleInfoString(BITV bv);
+
+void
+SetRootToInitialPosition(void);
+
+//
+// move.c
+//
+void
+SlidePiece(POSITION *pos, COOR cFrom, COOR cTo);
+
+PIECE
+LiftPiece(POSITION *pos, COOR cSquare);
+
+void
+PlacePiece(POSITION *pos, COOR cSquare, PIECE pPiece);
+
+FLAG
+MakeMove(SEARCHER_THREAD_CONTEXT *ctx,
+ MOVE mv);
+
+void
+UnmakeMove(SEARCHER_THREAD_CONTEXT *ctx,
+ MOVE mv);
+
+FLAG
+MakeUserMove(SEARCHER_THREAD_CONTEXT *ctx, MOVE mvUser);
+
+void
+DumpMove(ULONG u);
+
+//
+// movesup.c
+//
+#define MOVE_TO_INDEX(mv) (((mv).uMove & 0xFFFF) + \
+ (0x10000 * GET_COLOR(mv.pMoved)))
+
+COOR
+FasterExposesCheck(POSITION *pos,
+ COOR cRemove,
+ COOR cLocation);
+
+COOR
+ExposesCheck(POSITION *pos,
+ COOR cRemove,
+ COOR cLocation);
+
+COOR
+ExposesCheckEp(POSITION *pos,
+ COOR cTest,
+ COOR cIgnore,
+ COOR cBlock,
+ COOR cKing);
+
+FLAG
+IsAttacked(COOR cTest, POSITION *pos, ULONG uSide);
+
+FLAG
+InCheck(POSITION *pos, ULONG uSide);
+
+FLAG
+SanityCheckMove(POSITION *pos, MOVE mv);
+
+FLAG
+LooksLikeFile(CHAR c);
+
+FLAG
+LooksLikeRank(CHAR c);
+
+FLAG
+LooksLikeCoor(CHAR *szData);
+
+CHAR *
+StripMove(CHAR *szMove);
+
+ULONG
+LooksLikeMove(CHAR *szData);
+
+void FASTCALL
+SelectBestWithHistory(SEARCHER_THREAD_CONTEXT *ctx, ULONG u);
+
+void FASTCALL
+SelectBestNoHistory(SEARCHER_THREAD_CONTEXT *ctx, ULONG u);
+
+void FASTCALL
+SelectMoveAtRoot(SEARCHER_THREAD_CONTEXT *ctx, ULONG u);
+
+#define NOT_MOVE 0
+#define MOVE_ICS 1
+#define MOVE_SAN 2
+
+COMMAND(PerftCommand);
+
+
+//
+// testmove.c
+//
+#ifdef TEST
+void
+TestLiftPlaceSlidePiece(void);
+
+void
+TestExposesCheck(void);
+
+void
+TestIsAttacked(void);
+
+void
+TestMakeUnmakeMove(void);
+#endif
+
+//
+// generate.c
+//
+#define SORT_THESE_FIRST (0x40000000)
+#define FIRST_KILLER (0x20000000)
+#define SECOND_KILLER (0x10000000)
+#define THIRD_KILLER (0x08000000)
+#define FOURTH_KILLER (0x04000000)
+#define GOOD_MOVE (0x02000000)
+#define STRIP_OFF_FLAGS (0x00FFFFFF)
+
+extern const int g_iQKDeltas[9];
+extern const int g_iNDeltas[9];
+extern const int g_iBDeltas[5];
+extern const int g_iRDeltas[5];
+
+void
+GenerateMoves(SEARCHER_THREAD_CONTEXT *ctx,
+ MOVE mvOrderFirst,
+ ULONG uType);
+
+FLAG
+WouldGiveCheck(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN MOVE mv);
+
+//
+// testgenerate.c
+//
+#ifdef TEST
+
+void
+PlyTest(SEARCHER_THREAD_CONTEXT *ctx,
+ ULONG uDepth,
+ FLAG fRootPositionInCheck);
+
+void
+TestMoveGenerator(void);
+
+void
+TestLegalMoveGenerator(void);
+
+#endif
+
+//
+// sig.c
+//
+extern UINT64 g_u64SigSeeds[128][7][2];
+extern UINT64 g_u64PawnSigSeeds[128][2];
+extern UINT64 g_u64CastleSigSeeds[16];
+extern UINT64 g_u64EpSigSeeds[9];
+
+void
+InitializeSigSystem(void);
+
+UINT64
+ComputePawnSig(POSITION *pos);
+
+UINT64
+ComputeSig(POSITION *pos);
+
+//
+// mersenne.c
+//
+void
+seedMT(unsigned int seed);
+
+unsigned int
+reloadMT(void);
+
+unsigned int
+randomMT(void);
+
+//
+// data.c
+//
+typedef struct _VECTOR_DELTA
+{
+ UCHAR iVector[2];
+ signed char iDelta;
+ signed char iNegDelta;
+}
+VECTOR_DELTA;
+
+extern ULONG g_uDistance[256];
+extern ULONG *g_pDistance;
+extern VECTOR_DELTA g_VectorDelta[256];
+extern VECTOR_DELTA *g_pVectorDelta;
+extern CHAR g_SwapTable[14][32][32];
+extern SCORE _PSQT[14][128];
+extern ULONG g_uSearchSortLimits[];
+extern MOVE NULLMOVE;
+extern MOVE HASHMOVE;
+extern MOVE RECOGNMOVE;
+extern MOVE DRAWMOVE;
+extern MOVE MATEMOVE;
+extern FLAG g_fIsWhiteSquare[128];
+extern BITBOARD BBFILE[8];
+extern BITBOARD BBRANK[9];
+extern BITBOARD BBWHITESQ;
+extern BITBOARD BBBLACKSQ;
+extern BITBOARD BBLEFTSIDE;
+extern BITBOARD BBRIGHTSIDE;
+extern BITBOARD BBSQUARE[64];
+extern BITBOARD BBROOK_PAWNS;
+extern BITBOARD BBPRECEEDING_RANKS[8][2];
+extern BITBOARD BBADJACENT_FILES[8];
+extern BITBOARD BBADJACENT_RANKS[9];
+
+void
+InitializeWhiteSquaresTable(void);
+
+void
+InitializeVectorDeltaTable(void);
+
+void
+InitializeSwapTable(void);
+
+void
+InitializeDistanceTable(void);
+
+void
+InitializeSearchDepthArray(void);
+
+ULONG
+GetSearchSortLimit(ULONG);
+
+#ifdef DEBUG
+#define SEARCH_SORT_LIMIT(x) (GetSearchSortLimit((x)))
+#else
+#define SEARCH_SORT_LIMIT(x) (g_uSearchSortLimits[(x)])
+#endif
+
+#ifdef DEBUG
+ULONG CheckVectorWithIndex(int i, ULONG uColor);
+#define CHECK_VECTOR_WITH_INDEX(i, color) \
+ CheckVectorWithIndex(i, color)
+
+int DirectionBetweenSquaresWithIndex(int i);
+#define CHECK_DELTA_WITH_INDEX(i) \
+ DirectionBetweenSquaresWithIndex(i)
+
+int DirectionBetweenSquaresFromTo(COOR, COOR);
+#define DIRECTION_BETWEEN_SQUARES(from, to) \
+ DirectionBetweenSquaresFromTo(from, to)
+
+int NegativeDirectionBetweenSquaresWithIndex(int i);
+#define NEG_DELTA_WITH_INDEX(i) \
+ NegativeDirectionBetweenSquaresWithIndex(i)
+
+FLAG IsSquareWhite(COOR c);
+#define IS_SQUARE_WHITE(c) \
+ IsSquareWhite(c)
+
+#else
+#define CHECK_VECTOR_WITH_INDEX(i, color) \
+ (g_pVectorDelta[(i)].iVector[(color)])
+
+#define CHECK_DELTA_WITH_INDEX(i) \
+ (g_pVectorDelta[(i)].iDelta)
+
+#define DIRECTION_BETWEEN_SQUARES(cFrom, cTo) \
+ CHECK_DELTA_WITH_INDEX((int)(cFrom) - (int)(cTo))
+
+#define NEG_DELTA_WITH_INDEX(i) \
+ (g_pVectorDelta[(i)].iNegDelta)
+
+#define IS_SQUARE_WHITE(c) \
+ (g_fIsWhiteSquare[(c)])
+#endif
+
+//
+// san.c
+//
+MOVE
+ParseMoveSan(CHAR *szInput,
+ POSITION *pos);
+
+CHAR *
+MoveToSan(MOVE mv, POSITION *pos);
+
+//
+// testsan.c
+//
+void
+TestSan(void);
+
+//
+// list.c
+//
+void
+InitializeListHead(IN DLIST_ENTRY *pListHead);
+
+FLAG
+IsListEmpty(IN DLIST_ENTRY *pListHead);
+
+FLAG
+RemoveEntryList(IN DLIST_ENTRY *pEntry);
+
+DLIST_ENTRY *
+RemoveHeadList(IN DLIST_ENTRY *pListHead);
+
+DLIST_ENTRY *
+RemoveTailList(IN DLIST_ENTRY *pListHead);
+
+void
+InsertTailList(IN DLIST_ENTRY *pListHead,
+ IN DLIST_ENTRY *pEntry);
+
+void
+InsertHeadList(IN DLIST_ENTRY *pListHead,
+ IN DLIST_ENTRY *pEntry);
+
+//
+// command.c
+//
+void
+ParseUserInput(FLAG fSearching);
+
+FLAG
+InitializeCommandSystem(void);
+
+void
+CleanupCommandSystem(void);
+
+//
+// input.c
+//
+void
+InitInputSystemInBatchMode(void);
+
+ULONG
+InitInputSystemWithDedicatedThread(void);
+
+void
+PushNewInput(CHAR *buf);
+
+CHAR *
+PeekNextInput(void);
+
+CHAR *
+ReadNextInput(void);
+
+CHAR *
+BlockingReadInput(void);
+
+ULONG
+NumberOfPendingInputEvents(void);
+
+volatile extern FLAG g_fExitProgram;
+
+//
+// ics.c
+//
+MOVE
+ParseMoveIcs(CHAR *szInput, POSITION *pos);
+
+CHAR *
+MoveToIcs(MOVE mv);
+
+//
+// testics.c
+//
+void
+TestIcs(void);
+
+//
+// gamelist.c
+//
+typedef enum _ERESULT
+{
+ RESULT_BLACK_WON = -1,
+ RESULT_DRAW = 0,
+ RESULT_WHITE_WON = 1,
+ RESULT_IN_PROGRESS,
+ RESULT_ABANDONED,
+ RESULT_UNKNOWN
+} ERESULT;
+
+typedef struct _GAME_RESULT
+{
+ ERESULT eResult;
+ CHAR szDescription[256];
+} GAME_RESULT;
+
+typedef struct _GAME_PLAYER
+{
+ CHAR *szName;
+ CHAR *szDescription;
+ FLAG fIsComputer;
+ ULONG uRating;
+}
+GAME_PLAYER;
+
+typedef struct _GAME_HEADER
+{
+ CHAR *szGameDescription;
+ CHAR *szLocation;
+ GAME_PLAYER sPlayer[2];
+ FLAG fGameIsRated;
+ UINT64 u64OpeningSig;
+ ERESULT eResult;
+ CHAR *szResultComment;
+ CHAR *szInitialFen;
+}
+GAME_HEADER;
+
+typedef struct _GAME_MOVE
+{
+ DLIST_ENTRY links;
+ ULONG uNumber;
+ MOVE mv;
+ CHAR *szComment;
+ CHAR *szDecoration;
+ CHAR *szMoveInSan;
+ CHAR *szMoveInIcs;
+ CHAR *szUndoPositionFen;
+ SCORE iMoveScore;
+ UINT64 u64PositionSigAfterMove;
+ UINT64 u64PositionSigBeforeMove;
+ volatile FLAG fInUse;
+}
+GAME_MOVE;
+
+typedef struct _GAME_DATA
+{
+ GAME_HEADER sHeader;
+ DLIST_ENTRY sMoveList;
+}
+GAME_DATA;
+
+extern GAME_DATA g_GameData;
+
+POSITION *
+GetRootPosition(void);
+
+FLAG
+SetRootPosition(CHAR *szFen);
+
+void
+ResetGameList(void);
+
+ULONG
+GetMoveNumber(ULONG uColor);
+
+void
+SetGameResultAndDescription(ERESULT r, CHAR *sz);
+
+INT
+GetGameResult(void);
+
+void
+SetMyName(void);
+
+void
+SetOpponentsName(CHAR *sz);
+
+void
+SetMyRating(ULONG u);
+
+void
+SetOpponentsRating(ULONG u);
+
+void
+DumpGameList(void);
+
+void
+TellGamelistThatIPlayColor(ULONG u);
+
+void
+DumpPgn(void);
+
+FLAG
+LoadPgn(CHAR *szPgn);
+
+ULONG
+CountOccurrancesOfSigInOfficialGameList(UINT64 u64Sig);
+
+FLAG
+DoesSigAppearInOfficialGameList(UINT64 u64Sig);
+
+FLAG
+OfficiallyTakebackMove(void);
+
+FLAG
+OfficiallyMakeMove(MOVE mv, SCORE iMoveScore, FLAG fFast);
+
+GAME_MOVE *
+GetNthOfficialMoveRecord(ULONG n);
+
+void
+MakeStatusLine(void);
+
+FLAG
+IsLegalDrawByRepetition(void);
+
+//
+// script.c
+//
+COMMAND(ScriptCommand);
+
+COMMAND(SolutionCommand);
+
+COMMAND(AvoidCommand);
+
+COMMAND(IdCommand);
+
+void
+PostMoveTestSuiteReport(SEARCHER_THREAD_CONTEXT *);
+
+FLAG
+CheckTestSuiteMove(MOVE mv, SCORE iScore, ULONG uDepth);
+
+FLAG
+WeAreRunningASuite(void);
+
+
+//
+// vars.c
+//
+COMMAND(SetCommand);
+
+//
+// root.c
+//
+extern ULONG g_uSoftExtendLimit;
+extern ULONG g_uHardExtendLimit;
+extern volatile MOVE_TIMER g_MoveTimer;
+extern ULONG g_uExtensionReduction[MAX_PLY_PER_SEARCH];
+
+#ifdef PERF_COUNTERS
+#define KEEP_TRACK_OF_FIRST_MOVE_FHs(x) \
+ ctx->sCounters.tree.u64BetaCutoffs++; \
+ if (x) \
+ { \
+ ctx->sCounters.tree.u64BetaCutoffsOnFirstMove++;\
+ }
+#else
+#define KEEP_TRACK_OF_FIRST_MOVE_FHs(x)
+#endif
+
+#define GAME_NOT_OVER 0
+#define GAME_WHITE_WON 1
+#define GAME_BLACK_WON 2
+#define GAME_DRAW_STALEMATE 3
+#define GAME_DRAW_REPETITION 4
+#define GAME_ONE_LEGAL_MOVE 5
+#define GAME_DRAW_FIFTY_MOVES_WO_PROGRESS 6
+
+GAME_RESULT
+Think(POSITION *pos);
+
+GAME_RESULT
+Ponder(POSITION *pos);
+
+GAME_RESULT
+Iterate(SEARCHER_THREAD_CONTEXT *ctx);
+
+void
+SetMoveTimerForSearch(FLAG fSwitchOver, ULONG uColor);
+
+void
+SetMoveTimerToThinkForever(void);
+
+void
+ClearRootNodecountHash(void);
+
+//
+// draw.c
+//
+FLAG
+IsDraw(SEARCHER_THREAD_CONTEXT *ctx);
+
+
+//
+// search.c
+//
+#define QPLIES_OF_NON_CAPTURE_CHECKS (1)
+#define FUTILITY_BASE_MARGIN (50) // + ctx->uPositional (min 100)
+#define DO_IID
+#define IID_R_FACTOR (TWO_PLY + HALF_PLY)
+
+#ifndef MP
+#define WE_SHOULD_STOP_SEARCHING (g_MoveTimer.bvFlags & TIMER_STOPPING)
+#else
+#define WE_SHOULD_STOP_SEARCHING ((g_MoveTimer.bvFlags & TIMER_STOPPING) || \
+ (ThreadUnderTerminatingSplit(ctx)))
+#endif
+
+SCORE FASTCALL
+QSearch(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta);
+
+SCORE FASTCALL
+Search(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta,
+ ULONG uDepth);
+
+
+//
+// searchsup.c
+//
+SCORE
+ComputeMoveScore(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN MOVE mv,
+ IN ULONG uMoveNum);
+
+FLAG
+ThreadUnderTerminatingSplit(SEARCHER_THREAD_CONTEXT *);
+
+FLAG
+WeShouldDoHistoryPruning(IN SCORE iRoughEval,
+ IN SCORE iAlpha,
+ IN SCORE iBeta,
+ IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN ULONG uRemainingDepth,
+ IN ULONG uLegalMoves,
+ IN MOVE mv,
+ IN ULONG uMoveNum,
+ IN INT iExtend);
+
+FLAG
+WeShouldTryNullmovePruning(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN SCORE iAlpha,
+ IN SCORE iBeta,
+ IN SCORE iRoughEval,
+ IN ULONG uNullDepth);
+
+FLAG
+TryNullmovePruning(IN OUT SEARCHER_THREAD_CONTEXT *ctx,
+ IN OUT FLAG *pfThreat,
+ IN SCORE iAlpha,
+ IN SCORE iBeta,
+ IN ULONG uNullDepth,
+ IN OUT INT *piOrigExtend,
+ OUT SCORE *piNullScore);
+
+void
+UpdatePV(SEARCHER_THREAD_CONTEXT *ctx, MOVE mv);
+
+FLAG
+CheckInputAndTimers(IN SEARCHER_THREAD_CONTEXT *ctx);
+
+void
+ComputeReactionToCheckExtension(IN OUT SEARCHER_THREAD_CONTEXT *ctx,
+ IN ULONG uGenFlags,
+ IN ULONG uMoveNum,
+ IN SCORE iRoughEval,
+ IN SCORE iAlpha,
+ IN OUT INT *piExtend,
+ IN OUT INT *piOrigExtend);
+
+void
+ComputeMoveExtension(IN OUT SEARCHER_THREAD_CONTEXT *ctx,
+ IN SCORE iAlpha,
+ IN SCORE iBeta,
+ IN ULONG uMoveNum,
+ IN SCORE iRoughEval,
+ IN ULONG uDepth,
+ IN OUT INT *piExtend);
+
+SCORE
+RescoreMovesViaSearch(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN ULONG uDepth,
+ IN SCORE iAlpha,
+ IN SCORE iBeta);
+
+FLAG
+MateDistancePruningCutoff(IN ULONG uPly,
+ IN FLAG fInCheck,
+ IN OUT SCORE *piBestScore,
+ IN OUT SCORE *piAlpha,
+ IN OUT SCORE *piBeta);
+
+FLAG
+CommonSearchInit(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN OUT SCORE *piAlpha,
+ IN OUT SCORE *piBeta,
+ IN OUT SCORE *piScore);
+
+ULONG
+SelectNullmoveRFactor(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN INT uDepth);
+
+#define VERIFY_BEFORE (1)
+#define VERIFY_AFTER (2)
+
+FLAG
+SanityCheckMoves(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN ULONG uCurrent,
+ IN ULONG uType);
+
+
+//
+// testsearch.c
+//
+FLAG
+TestSearch(void);
+
+//
+// see.c
+//
+#define SEE_HEAPS
+
+SCORE
+SEE(POSITION *pos,
+ MOVE mv);
+
+typedef struct _SEE_THREESOME
+{
+ PIECE pPiece;
+ COOR cLoc;
+ ULONG uVal;
+} SEE_THREESOME;
+
+typedef struct _SEE_LIST
+{
+ ULONG uCount;
+ SEE_THREESOME data[16];
+}
+SEE_LIST;
+
+SCORE
+ControlsSquareMinusPiece(ULONG uSide,
+ POSITION *pos,
+ COOR c,
+ COOR cIgnore);
+
+//
+// testsee.c
+//
+SCORE
+DebugSEE(POSITION *pos,
+ MOVE mv);
+
+void
+TestGetAttacks(void);
+
+//
+// hash.c
+//
+#define NUM_HASH_ENTRIES_PER_LINE 4
+#define HASH_FLAG_EXACT 0x1
+#define HASH_FLAG_LOWER 0x2
+#define HASH_FLAG_UPPER 0x4
+#define HASH_FLAG_VALID_BOUNDS 0x7
+#define HASH_FLAG_THREAT 0x8
+#define HASH_FLAG_DIRTY 0xF0
+
+typedef struct _HASH_ENTRY
+{
+ MOVE mv; // 0 1 2 3
+ UCHAR uDepth; // 4
+ UCHAR bvFlags; // 5 ==> d d d d | thr up low exact
+ signed short iValue; // 6 7
+ UINT64 u64Sig; // 8 9 A B C D E F == 16 bytes
+} HASH_ENTRY;
+
+FLAG
+InitializeHashSystem(void);
+
+void
+CleanupHashSystem(void);
+
+void
+ClearHashTable(void);
+
+void
+DirtyHashTable(void);
+
+void
+StoreLowerBound(MOVE mvBestMove,
+ POSITION *pos,
+ SCORE iValue,
+ ULONG uDepth,
+ FLAG fThreat);
+void
+StoreExactScore(MOVE mvBestMove,
+ POSITION *pos,
+ SCORE iValue,
+ ULONG uDepth,
+ FLAG fThreat,
+ ULONG uPly);
+
+void
+StoreUpperBound(//MOVE mvBestMove,
+ POSITION *pos,
+ SCORE iValue,
+ ULONG uDepth,
+ FLAG fThreat);
+
+HASH_ENTRY *
+HashLookup(SEARCHER_THREAD_CONTEXT *ctx,
+ ULONG uDepth,
+ ULONG uNextDepth,
+ SCORE iAlpha,
+ SCORE iBeta,
+ FLAG *pfThreat,
+ FLAG *pfAvoidNull,
+ MOVE *pHashMove,
+ SCORE *piScore);
+
+COOR
+CheckHashForDangerSquare(POSITION *pos);
+
+MOVE
+GetPonderMove(POSITION *pos);
+
+extern ULONG g_uHashTableSizeEntries;
+extern ULONG g_uHashTableSizeBytes;
+extern HASH_ENTRY *g_pHashTable;
+
+//
+// testhash.c
+//
+void
+AnalyzeFullHashTable(void);
+
+//
+// positionhash.c
+//
+// IDEA: store "mate threat" flag in here?
+// IDEA: store "king safety" numbers in here?
+//
+typedef struct _POSITION_HASH_ENTRY {
+ UINT64 u64Sig;
+ UCHAR cEnprise[2];
+ UCHAR uEnpriseCount[2];
+ UCHAR cTrapped[2];
+} POSITION_HASH_ENTRY;
+
+void
+InitializePositionHashSystem(void);
+
+void
+CleanupPositionHashSystem(void);
+
+void
+StoreEnprisePiece(POSITION *pos, COOR cSquare);
+
+void
+StoreTrappedPiece(POSITION *pos, COOR cSquare);
+
+COOR
+GetEnprisePiece(POSITION *pos, ULONG uSide);
+
+ULONG
+GetEnpriseCount(POSITION *pos, ULONG uSide);
+
+COOR
+GetTrappedPiece(POSITION *pos, ULONG uSide);
+
+FLAG
+SideCanStandPat(POSITION *pos, ULONG uSide);
+
+ULONG
+ValueOfMaterialInTroubleDespiteMove(POSITION *pos, ULONG uSide);
+
+ULONG
+ValueOfMaterialInTroubleAfterNull(POSITION *pos, ULONG uSide);
+
+//
+// pawnhash.c
+//
+#define COOR_TO_BIT(x) ((x) & 0x7) + ((0x7 - ((x) >> 4)) << 3)
+
+void
+ClearPawnHashStats(void);
+
+void
+ReportPawnHashStats(void);
+
+PAWN_HASH_ENTRY *
+PawnHashLookup(SEARCHER_THREAD_CONTEXT *ctx);
+
+//
+// eval.c
+//
+#define LAZY_EVAL
+#define LAZE_EVAL_BASE_SCORE 10
+extern const int g_iAhead[2];
+extern const int g_iBehind[2];
+
+ULONG
+DNABufferSizeBytes();
+
+char *
+ExportEvalDNA();
+
+FLAG
+WriteEvalDNA(char *szFilename);
+
+FLAG
+ImportEvalDNA(char *p);
+
+FLAG
+ReadEvalDNA(char *szFilename);
+
+
+
+SCORE
+Eval(SEARCHER_THREAD_CONTEXT *, SCORE, SCORE);
+
+FLAG
+EvalPasserRaces(POSITION *,
+ PAWN_HASH_ENTRY *);
+
+ULONG
+CountKingSafetyDefects(POSITION *pos,
+ ULONG uSide);
+
+//
+// testeval.c
+//
+#ifdef EVAL_DUMP
+void
+TestEval(void);
+
+void
+EvalTraceReport(void);
+
+void
+EvalTrace(ULONG uColor, PIECE p, COOR c, SCORE iVal, CHAR *szMessage);
+
+SCORE
+EvalSigmaForPiece(POSITION *pos, COOR c);
+
+void
+EvalTraceClear(void);
+
+void
+TestEvalWithSymmetry(void);
+
+#define EVAL_TERM(COL, PIE, COO, VAL, ADJ, MESS) \
+ (VAL) += (ADJ); \
+ EvalTrace((COL), (PIE), (COO), (ADJ), (MESS));
+#else
+#define EVAL_TERM(COL, PIE, COO, VAL, ADJ, MESS) \
+ (VAL) += (ADJ);
+#endif
+
+//
+// bitboard.c
+//
+void
+InitializeBitboards(void);
+
+ULONG CDECL
+SlowCountBits(BITBOARD bb);
+
+ULONG CDECL
+DeBruijnFirstBit(BITBOARD bb);
+
+ULONG CDECL
+SlowFirstBit(BITBOARD bb);
+
+ULONG CDECL
+SlowLastBit(BITBOARD bb);
+
+#ifdef CROUTINES
+#define CountBits SlowCountBits
+#define FirstBit SlowFirstBit
+#define LastBit SlowLastBit
+#endif
+
+COOR
+CoorFromBitBoardRank8ToRank1(BITBOARD *pbb);
+
+COOR
+CoorFromBitBoardRank1ToRank8(BITBOARD *pbb);
+
+//
+// x86.asm
+//
+ULONG CDECL
+CountBits(BITBOARD bb);
+
+ULONG CDECL
+FirstBit(BITBOARD bb);
+
+ULONG CDECL
+LastBit(BITBOARD bb);
+
+ULONG CDECL
+LockCompareExchange(volatile void *pDest,
+ ULONG uExch,
+ ULONG uComp);
+
+ULONG CDECL
+LockIncrement(volatile void *pDest);
+
+ULONG CDECL
+LockDecrement(volatile void *pDest);
+
+FLAG CDECL
+CanUseParallelOpcodes();
+
+ULONG CDECL
+ParallelCompareUlong(ULONG uComparand, void *pComparators);
+
+ULONG CDECL
+ParallelCompareVector(void *pComparand, void *pComparators);
+
+void CDECL
+GetAttacks(SEE_LIST *pList,
+ POSITION *pos,
+ COOR cSquare,
+ ULONG uSide);
+
+void CDECL
+SlowGetAttacks(SEE_LIST *pList,
+ POSITION *pos,
+ COOR cSquare,
+ ULONG uSide);
+#ifdef CROUTINES
+#define GetAttacks SlowGetAttacks
+#endif
+
+#ifdef _X86_
+//
+// Note: this is most of the stuff that x86.asm assumes about the
+// internal data structures. If any of this fails then either the
+// assembly language code needs to be updated or you need to use the C
+// version of the routine in see.c instead.
+//
+#define ASSERT_ASM_ASSUMPTIONS \
+ ASSERT(VALUE_PAWN == 100); \
+ ASSERT(OFFSET_OF(uCount, SEE_LIST) == 0); \
+ ASSERT(OFFSET_OF(data, SEE_LIST) == 4); \
+ ASSERT(sizeof(SEE_THREESOME) == 12); \
+ ASSERT(OFFSET_OF(pPiece, SEE_THREESOME) == 0); \
+ ASSERT(OFFSET_OF(cLoc, SEE_THREESOME) == 4); \
+ ASSERT(OFFSET_OF(uVal, SEE_THREESOME) == 8); \
+ ASSERT(OFFSET_OF(cNonPawns, POSITION) == 0x478); \
+ ASSERT(OFFSET_OF(uNonPawnCount, POSITION) == 0x500); \
+ ASSERT(OFFSET_OF(rgSquare, POSITION) == 0); \
+ ASSERT(sizeof(SQUARE) == 8); \
+ ASSERT(sizeof(VECTOR_DELTA) == 4); \
+ ASSERT(sizeof(g_VectorDelta) == 256 * 4); \
+ ASSERT(OFFSET_OF(iVector, VECTOR_DELTA) == 0); \
+ ASSERT(OFFSET_OF(iDelta, VECTOR_DELTA) == 2); \
+ ASSERT(OFFSET_OF(iNegDelta, VECTOR_DELTA) == 3); \
+ ASSERT(sizeof(g_PieceData) == 8 * 4 * 4); \
+ ASSERT(OFFSET_OF(uValue, PIECE_DATA) == 0);
+#else
+#define ASSERT_ASM_ASSUMPTIONS
+#endif
+
+//
+// testbitboard.c
+//
+void
+TestBitboards(void);
+
+//
+// dynamic.c
+//
+extern ULONG g_HistoryCounters[14][128];
+
+ULONG
+GetMoveFailHighPercentage(MOVE mv);
+
+void
+UpdateDynamicMoveOrdering(SEARCHER_THREAD_CONTEXT *ctx,
+ ULONG uRemainingDepth,
+ MOVE mvBest,
+ SCORE iScore,
+ ULONG uCurrent);
+
+void
+NewKillerMove(SEARCHER_THREAD_CONTEXT *ctx, MOVE mv, SCORE iScore);
+
+FLAG
+InitializeDynamicMoveOrdering(void);
+
+void
+CleanupDynamicMoveOrdering(void);
+
+void
+ClearDynamicMoveOrdering(void);
+
+void
+MaintainDynamicMoveOrdering(void);
+
+void
+IncrementMoveHistoryCounter(MOVE mv, ULONG u);
+
+void
+DecrementMoveHistoryCounter(MOVE mv, ULONG u);
+
+//
+// split.c
+//
+extern volatile ULONG g_uNumHelpersAvailable;
+extern ULONG g_uNumHelperThreads;
+
+FLAG
+InitializeParallelSearch(void);
+
+FLAG
+CleanupParallelSearch(void);
+
+void
+ClearHelperThreadIdleness(void);
+
+void
+DumpHelperIdlenessReport(void);
+
+SCORE
+StartParallelSearch(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN OUT SCORE *piAlpha,
+ IN SCORE iBeta,
+ IN OUT SCORE *piBestScore,
+ IN OUT MOVE *pmvBest,
+ IN ULONG uMoveNum,
+ IN INT iPositionExtend,
+ IN ULONG uDepth);
+
+void
+InitializeSearcherContext(POSITION *pos, SEARCHER_THREAD_CONTEXT *ctx);
+
+void
+ReInitializeSearcherContext(POSITION *pos, SEARCHER_THREAD_CONTEXT *ctx);
+
+void
+InitializeLightweightSearcherContext(POSITION *pos,
+ LIGHTWEIGHT_SEARCHER_CONTEXT *ctx);
+
+//
+// book.c
+//
+
+#define BOOK_PROBE_MISS_LIMIT (7)
+#define FLAG_DISABLED (1)
+#define FLAG_ALWAYSPLAY (2)
+#define FLAG_DELETED (4)
+
+#define BOOKMOVE_SELECT_MOVE (1)
+#define BOOKMOVE_DUMP (2)
+
+#pragma pack(4)
+typedef struct _BOOK_ENTRY
+{
+ UINT64 u64Sig; // 8 bytes
+ UINT64 u64NextSig; // 8 bytes
+ MOVE mvNext; // 4 bytes
+ ULONG uWins; // 4 bytes
+ ULONG uDraws; // 4 bytes
+ ULONG uLosses; // 4 bytes
+ BITV bvFlags; // 4 bytes
+}
+BOOK_ENTRY;
+#pragma pack()
+
+typedef struct _OPENING_NAME_MAPPING
+{
+ UINT64 u64Sig;
+ CHAR *szString;
+}
+OPENING_NAME_MAPPING;
+
+#define BOOK_EDITING_RECORD "bkedit.edt"
+#define OPENING_LEARNING_FILENAME "bklearn.bin"
+
+typedef struct _OPENING_LEARNING_ENTRY
+{
+ UINT64 u64Sig;
+ ULONG uWhiteWins;
+ ULONG uDraws;
+ ULONG uBlackWins;
+}
+OPENING_LEARNING_ENTRY;
+
+FLAG
+InitializeOpeningBook(void);
+
+void
+ResetOpeningBook(void);
+
+void
+CleanupOpeningBook(void);
+
+MOVE
+BookMove(POSITION *pos,
+ BITV bvFlags);
+
+COMMAND(BookCommand);
+
+extern ULONG g_uBookProbeFailures;
+extern FLAG g_fTournamentMode;
+extern CHAR *g_szBookName;
+
+//
+// bench.c
+//
+COMMAND(BenchCommand);
+
+//
+// testdraw.c
+//
+void
+TestDraw(void);
+
+//
+// probe.c
+//
+FLAG
+ProbeEGTB(SEARCHER_THREAD_CONTEXT *ctx, SCORE *score);
+
+void
+InitializeEGTB(void);
+
+void
+CleanupEGTB(void);
+
+//
+// dumptree.c
+//
+#ifdef DUMP_TREE
+
+void
+InitializeTreeDump(void);
+
+void
+CleanupTreeDump(void);
+
+void
+DTEnterNode(SEARCHER_THREAD_CONTEXT *ctx,
+ ULONG uDepth,
+ FLAG fIsQNode,
+ SCORE iAlpha,
+ SCORE iBeta);
+
+void
+DTLeaveNode(SEARCHER_THREAD_CONTEXT *ctx,
+ FLAG fQNode,
+ SCORE iBestScore,
+ MOVE mvBestMove);
+
+void CDECL
+DTTrace(ULONG uPly, CHAR *szMessage, ...);
+
+#define DTTRACE(...) DTTrace(ctx->uPly, __VA_ARGS__)
+
+#else
+
+#define DTTRACE(...)
+
+#define DTEnterNode(...)
+
+#define DTLeaveNode(...)
+
+#define InitializeTreeDump(...)
+
+#define CleanupTreeDump(...)
+
+#endif
+
+//
+// testsup.c
+//
+FLAG
+IsBoardLegal(POSITION *pos);
+
+void
+GenerateRandomLegalPosition(POSITION *pos);
+
+void
+GenerateRandomLegalSymetricPosition(POSITION *pos);
+
+//
+// recogn.c
+//
+#define UNRECOGNIZED (0)
+#define RECOGN_EXACT (1)
+#define RECOGN_UPPER (2)
+#define RECOGN_LOWER (3)
+#define RECOGN_EGTB (4)
+
+void
+InitializeInteriorNodeRecognizers(void);
+
+ULONG
+RecognLookup(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE *piScore,
+ FLAG fProbeEGTB);
+
+#ifdef EVAL_HASH
+void
+ClearEvalHashStats(void);
+
+void
+ReportEvalHashStats(void);
+
+SCORE
+ProbeEvalHash(SEARCHER_THREAD_CONTEXT *ctx);
+
+SCORE
+GetRoughEvalScore(IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN SCORE iAlpha,
+ IN SCORE iBeta,
+ IN FLAG fUseHash);
+
+void
+StoreEvalHash(SEARCHER_THREAD_CONTEXT *ctx, SCORE iScore);
+#endif // EVAL_HASH
+
+#endif // CHESS
diff --git a/src/save/main.c b/src/save/main.c
new file mode 100755
index 0000000..a1a0f1f
--- /dev/null
+++ b/src/save/main.c
@@ -0,0 +1,745 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ main.c
+
+Abstract:
+
+ Program entry point and setup code.
+
+Author:
+
+ Scott Gasch ([email protected]) 8 Apr 2004
+
+Revision History:
+
+ $Id: main.c 351 2008-06-28 04:21:53Z scott $
+
+**/
+
+#include "chess.h"
+
+FILE *g_pfLogfile = NULL;
+GAME_OPTIONS g_Options;
+CHAR g_szInitialCommand[SMALL_STRING_LEN_CHAR];
+ULONG g_uInputThreadHandle = (ULONG)-1;
+
+void
+Banner(void)
+/**
+
+Routine description:
+
+ Describe the compile/build options and program version.
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ char *p;
+
+ Trace("Typhoon %s (built on %s %s):\n", VERSION, __DATE__, __TIME__);
+ Trace(" Copyright (C) 2000-2007, Scott Gasch ([email protected])\n");
+ Trace(" " REVISION);
+ Trace(" " COMPILER_STRING);
+ Trace(" Make profile used: %s\n", PROFILE);
+#ifdef MP
+ Trace(" Multiprocessor enabled; %u searcher thread%s\n",
+ g_Options.uNumProcessors, (g_Options.uNumProcessors > 1) ? "s" : "");
+#else
+ Trace(" Single processor version\n");
+#endif
+#ifdef DEBUG
+ Trace(" DEBUG build\n");
+#endif
+#ifdef TEST
+ Trace(" Testcode compiled in\n");
+#endif
+#ifdef EVAL_DUMP
+ Trace(" Evaluation terms\n");
+#endif
+#ifdef EVAL_TIME
+ Trace(" Evaluation timing\n");
+#endif
+#ifdef PERF_COUNTERS
+ Trace(" Performance counters\n");
+#ifdef TEST_NULL
+ Trace(" Testing nullmove prediction algorithms\n");
+#endif
+#endif
+#ifdef DUMP_TREE
+ Trace(" Search tree dumpfile generation enabled\n");
+#endif
+ Trace(" Hash sizes: %u Mb (main), %u Mb / thread (pawn), %u Mb / thread (eval)\n",
+ (g_uHashTableSizeEntries * sizeof(HASH_ENTRY)) / MB,
+ PAWN_HASH_TABLE_SIZE * sizeof(PAWN_HASH_ENTRY) / MB,
+ EVAL_HASH_TABLE_SIZE * sizeof(EVAL_HASH_ENTRY) / MB);
+ Trace(" QCheckPlies: %u\n", QPLIES_OF_NON_CAPTURE_CHECKS);
+ Trace(" FutilityBase: %u\n", FUTILITY_BASE_MARGIN);
+ p = ExportEvalDNA();
+ Trace(" Logging Eval DNA.\n");
+ Log(p);
+ free(p);
+#ifdef DO_IID
+ Trace(" IID R-factor: %u ply\n", IID_R_FACTOR / ONE_PLY);
+#endif
+}
+
+
+void
+EndLogging(void)
+/**
+
+Routine description:
+
+ Close the main logfile.
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ if (NULL != g_pfLogfile)
+ {
+ fflush(g_pfLogfile);
+ fflush(stdout);
+ fclose(g_pfLogfile);
+ g_pfLogfile = NULL;
+ }
+}
+
+
+FLAG
+BeginLogging(void)
+/**
+
+Routine description:
+
+ Open the main logfile.
+
+Parameters:
+
+ void
+
+Return value:
+
+ FLAG
+
+**/
+{
+ if (NULL != g_pfLogfile)
+ {
+ EndLogging();
+ }
+ ASSERT(g_pfLogfile == NULL);
+ ASSERT(strlen(g_Options.szLogfile));
+
+ //
+ // If the logfile we want to write already exists, back it up.
+ //
+ if (TRUE == SystemDoesFileExist(g_Options.szLogfile))
+ {
+ VERIFY(BackupFile(g_Options.szLogfile));
+ }
+ ASSERT(FALSE == SystemDoesFileExist(g_Options.szLogfile));
+
+ g_pfLogfile = fopen(g_Options.szLogfile, "wb+");
+ if (NULL == g_pfLogfile)
+ {
+ UtilPanic(INITIALIZATION_FAILURE,
+ (void *)"Can't open logfile",
+ (void *)&(g_Options.szLogfile),
+ (void *)"write",
+ NULL,
+ __FILE__, __LINE__);
+ }
+ return(TRUE);
+}
+
+
+FLAG
+PreGameReset(FLAG fResetBoard)
+/**
+
+Routine description:
+
+ Reset internal state between games.
+
+Parameters:
+
+ void
+
+Return value:
+
+ FLAG
+
+**/
+{
+ if (TRUE == fResetBoard)
+ {
+ SetRootToInitialPosition();
+ }
+ SetMyName();
+ ClearDynamicMoveOrdering();
+ ClearHashTable();
+ ResetOpeningBook();
+ return(TRUE);
+}
+
+
+static ULONG
+_ParseHashOption(char *p,
+ ULONG uEntrySize)
+{
+ ULONG u, v;
+ CHAR c;
+
+ if ((!STRCMPI(p, "none")) || (!STRCMPI(p, "no"))) return(0);
+ if (2 == sscanf(p, "%u%1c", &u, &c))
+ {
+ v = u;
+ switch(c)
+ {
+ case 'K':
+ case 'k':
+ u *= 1024;
+ break;
+ case 'M':
+ case 'm':
+ u *= 1024 * 1024;
+ break;
+ case 'G':
+ case 'g':
+ u *= 1024 * 1024 * 1024;
+ break;
+ default:
+ Trace("Error (unrecognized size): \"%s\"\n", p);
+ break;
+ }
+ if (u < v)
+ {
+ Trace("Error (size too large): \"%s\"\n", p);
+ u = v;
+ }
+ u /= uEntrySize;
+ }
+ else
+ {
+ u = (ULONG)atoi(p);
+ }
+
+ while(!IS_A_POWER_OF_2(u))
+ {
+ u &= (u - 1);
+ }
+ return(u);
+}
+
+
+
+void
+InitializeOptions(int argc, char *argv[])
+/**
+
+Routine description:
+
+ Set global options to their initial state. This code also is
+ responsible for parsing the commandline in order to override the
+ default state of global options.
+
+Parameters:
+
+ int argc,
+ char *argv[]
+
+Return value:
+
+ void
+
+**/
+{
+ int i;
+
+ //
+ // Defaults
+ //
+ memset(&g_Options, 0, sizeof(g_Options));
+ g_szInitialCommand[0] = '\0';
+ g_Options.uMyClock = g_Options.uOpponentsClock = 600;
+ g_Options.fGameIsRated = FALSE;
+ g_Options.fOpponentIsComputer = FALSE;
+ g_Options.uSecPerMove = 0;
+ g_Options.uMaxDepth = MAX_PLY_PER_SEARCH - 1;
+ g_Options.fShouldPonder = TRUE;
+ g_Options.fPondering = g_Options.fThinking = FALSE;
+ g_Options.mvPonder.uMove = 0;
+ g_Options.fShouldPost = TRUE;
+ g_Options.fForceDrawWorthZero = FALSE;
+ g_Options.uMyIncrement = 0;
+ g_Options.uMovesPerTimePeriod = 0;
+ g_Options.szAnalyzeProgressReport[0] = '\0';
+ g_Options.fShouldAnnounceOpening = TRUE;
+ g_Options.eClock = CLOCK_NONE;
+ g_Options.eGameType = GAME_UNKNOWN;
+ g_Options.ePlayMode = FORCE_MODE;
+ g_Options.fNoInputThread = FALSE;
+ g_Options.fVerbosePosting = TRUE;
+ strcpy(g_Options.szEGTBPath, "/egtb/three;/etc/four;/egtb/five");
+ strcpy(g_Options.szLogfile, "typhoon.log");
+ strcpy(g_Options.szBookName, "book.bin");
+ g_Options.uNumHashTableEntries = 0x10000;
+ g_Options.uNumProcessors = 1;
+ g_Options.fStatusLine = TRUE;
+ g_Options.fShouldResign = FALSE;
+ g_Options.u64MaxNodeCount = 0ULL;
+
+ i = 1;
+ while(i < argc)
+ {
+#ifdef MP
+ if ((!STRCMPI(argv[i], "--cpus")) && (argc > i))
+ {
+ g_Options.uNumProcessors = (ULONG)atoi(argv[i+1]);
+ if ((g_Options.uNumProcessors == 0) ||
+ (g_Options.uNumProcessors > 64))
+ {
+ g_Options.uNumProcessors = 2;
+ }
+ i++;
+ }
+ else
+#endif
+ if ((!STRCMPI(argv[i], "--command")) && (argc > i))
+ {
+ strncpy(g_szInitialCommand,
+ argv[i+1],
+ SMALL_STRING_LEN_CHAR - 2);
+ strcat(g_szInitialCommand, "\r\n");
+ i++;
+ }
+ else if ((!STRCMPI(argv[i], "--hash")) && (argc > i))
+ {
+ g_Options.uNumHashTableEntries =
+ _ParseHashOption(argv[i+1],
+ sizeof(HASH_ENTRY));
+ i++;
+ }
+ else if ((!STRCMPI(argv[i], "--egtbpath")) && (argc > i))
+ {
+ g_Options.szEGTBPath[0] = '\0';
+ strncpy(g_Options.szEGTBPath, argv[i+1], SMALL_STRING_LEN_CHAR);
+ i++;
+ }
+ else if (!STRCMPI(argv[i], "--batch"))
+ {
+ g_Options.fNoInputThread = TRUE;
+ }
+ else if ((!STRCMPI(argv[i], "--dnafile")) && (argc > i))
+ {
+ if (!ReadEvalDNA(argv[i+1]))
+ {
+ UtilPanic(INITIALIZATION_FAILURE,
+ (void *)"Bad DNA file",
+ (void *)&(argv[i+1]),
+ (void *)"read",
+ NULL,
+ __FILE__, __LINE__);
+ }
+ i++;
+ }
+ else if ((!STRCMPI(argv[i], "--logfile")) && (argc > i))
+ {
+ strncpy(g_Options.szLogfile, argv[i+1],
+ SMALL_STRING_LEN_CHAR);
+ i++;
+ }
+ else if (!STRCMPI(argv[i], "--help")) {
+ Trace("Usage: %s [--batch] [--command arg] [--logfile arg] [--egtbpath arg]\n"
+ " [--dnafile arg] [--cpus arg] [--hash arg]\n\n"
+ " --batch : operate the engine without an input thread\n"
+ " --command : specify initial command(s) (requires arg)\n"
+ " --cpus : indicate the number of cpus to use (requires arg, MP build)\n"
+ " --hash : indicate desired hash size (requires arg)\n"
+ " --egtbpath : supplies the egtb path to engine (requires arg)\n"
+ " --logfile : indicate desired output logfile name (requires arg)\n"
+ " --dnafile : indicate desired eval profile input (requres arg)\n\n"
+ "Example: %s --hash 256m --cpus 2\n"
+ " %s --logfile test.out --batch --command \"test\" --dnafile test.in\n", argv[0], argv[0], argv[0]);
+ exit(-1);
+ }
+ else
+ {
+ Trace("Error (unknown argument): \"%s\"; try --help\n", argv[i]);
+ }
+
+ //
+ // TODO: parse other commandline options and override above
+ //
+
+ i++;
+ }
+}
+
+
+void
+CleanupOptions(void)
+/**
+
+Routine description:
+
+ Cleanup options...
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ NOTHING;
+}
+
+
+FLAG
+MainProgramInitialization(int argc, char *argv[])
+/**
+
+Routine description:
+
+ Perform main program initialization. This includes stuff like:
+ precomputing some data structures, resetting the global options,
+ parsing the commandline to override said options, and calling out
+ to other modules to tell them to initialize themselves.
+
+Parameters:
+
+ int argc,
+ char *argv[]
+
+Return value:
+
+ FLAG
+
+**/
+{
+ srand((unsigned int)time(0));
+ InitializeOptions(argc, argv);
+ InitializeTreeDump();
+ InitializeEGTB();
+ InitializeSigSystem();
+ InitializeInteriorNodeRecognizers();
+ InitializeSearchDepthArray();
+ InitializeWhiteSquaresTable();
+ InitializeVectorDeltaTable();
+ InitializeSwapTable();
+ InitializeDistanceTable();
+ InitializeOpeningBook();
+ InitializeDynamicMoveOrdering();
+ InitializeHashSystem();
+ InitializePositionHashSystem();
+#ifdef MP
+ InitializeParallelSearch();
+#endif
+ VERIFY(PreGameReset(TRUE));
+ return(BeginLogging());
+}
+
+
+FLAG
+MainProgramCleanup(void)
+/**
+
+Routine description:
+
+ Perform main program cleanup. Tear down the stuff we set up in
+ MainProgramInitialization.
+
+Parameters:
+
+ void
+
+Return value:
+
+ FLAG
+
+**/
+{
+ CleanupOpeningBook();
+ CleanupEGTB();
+ CleanupDynamicMoveOrdering();
+#ifdef MP
+ CleanupParallelSearch();
+#endif
+ CleanupPositionHashSystem();
+ CleanupHashSystem();
+ CleanupTreeDump();
+ CleanupOptions();
+ EndLogging();
+ return(TRUE);
+}
+
+
+#ifdef TEST
+FLAG
+RunStartupProgramTest(void)
+/**
+
+Routine description:
+
+ If we built this version with -DTEST then this code is the start
+ of the self-test that runs at program startup time.
+
+Parameters:
+
+ void
+
+Return value:
+
+ FLAG
+
+**/
+{
+ ULONG u, x, y;
+
+#ifdef _X86_
+ Trace("Testing CPP macros...\n");
+ for (u = 0; u < 1000000; u++)
+ {
+ x = rand() * rand();
+ y = rand() * rand();
+ x = x & ~(0x80000000);
+ y = y & ~(0x80000000);
+
+ if (MAX(x, y) != MAXU(x, y))
+ {
+ UtilPanic(TESTCASE_FAILURE,
+ NULL, "max maxu", NULL, NULL, __FILE__, __LINE__);
+ }
+
+ if (MAXU(x, y) != MAXU(y, x))
+ {
+ UtilPanic(TESTCASE_FAILURE,
+ NULL, "maxu assoc", NULL, NULL, __FILE__, __LINE__);
+ }
+
+ if (MIN(x, y) != MINU(x, y))
+ {
+ UtilPanic(TESTCASE_FAILURE,
+ NULL, "min minu", NULL, NULL, __FILE__, __LINE__);
+ }
+
+ if (MINU(x, y) != MINU(y, x))
+ {
+ UtilPanic(TESTCASE_FAILURE,
+ NULL, "minu assoc", NULL, NULL, __FILE__, __LINE__);
+ }
+
+ if (abs(x - y) != ABS_DIFF(x, y))
+ {
+ UtilPanic(TESTCASE_FAILURE,
+ NULL, "abs_diff", NULL, NULL, __FILE__, __LINE__);
+ }
+
+ if (ABS_DIFF(x, y) != ABS_DIFF(y, x))
+ {
+ UtilPanic(TESTCASE_FAILURE,
+ NULL, "abs_diff assoc", NULL, NULL, __FILE__, __LINE__);
+ }
+ }
+#endif
+
+ TestDraw();
+#ifdef EVAL_DUMP
+ TestEval();
+#endif
+ TestBitboards();
+ TestSan();
+ TestIcs();
+ TestGetAttacks();
+ TestMoveGenerator();
+ TestLegalMoveGenerator();
+ TestFenCode();
+ TestLiftPlaceSlidePiece();
+ TestExposesCheck();
+ TestIsAttacked();
+ TestMakeUnmakeMove();
+ TestSearch();
+
+ return(TRUE);
+}
+#endif // TEST
+
+
+
+void DeclareTerminalStates(GAME_RESULT result) {
+ switch(result.eResult) {
+ case RESULT_IN_PROGRESS:
+ return;
+ case RESULT_BLACK_WON:
+ Trace("0-1 {%s}\n", result.szDescription);
+ SetGameResultAndDescription(result.eResult, result.szDescription);
+ DumpPgn();
+ g_Options.ePlayMode = FORCE_MODE;
+ break;
+ case RESULT_WHITE_WON:
+ Trace("1-0 {%s}\n", result.szDescription);
+ SetGameResultAndDescription(result.eResult, result.szDescription);
+ DumpPgn();
+ g_Options.ePlayMode = FORCE_MODE;
+ break;
+ case RESULT_DRAW:
+ Trace("1/2-1/2 {%s}\n", result.szDescription);
+ Trace("tellics draw\n");
+ SetGameResultAndDescription(result.eResult, result.szDescription);
+ DumpPgn();
+ g_Options.ePlayMode = FORCE_MODE;
+ break;
+ case RESULT_ABANDONED:
+ case RESULT_UNKNOWN:
+ ASSERT(FALSE);
+ SetGameResultAndDescription(result.eResult, result.szDescription);
+ DumpPgn();
+ g_Options.ePlayMode = FORCE_MODE;
+ break;
+ }
+}
+
+
+// Main work loop
+void MainProgramLoop() {
+ POSITION pos;
+ GAME_RESULT result;
+ FLAG fThink;
+ FLAG fPonder;
+
+ while (!g_fExitProgram) {
+
+ // Prepare to search or ponder
+ memcpy(&pos, GetRootPosition(), sizeof(POSITION));
+ fThink = fPonder = FALSE;
+ result.eResult = RESULT_IN_PROGRESS;
+ result.szDescription[0] = '\0';
+
+ // What should we do?
+ switch(g_Options.ePlayMode) {
+ case I_PLAY_WHITE:
+ Trace("I play white.\n");
+ fThink = (pos.uToMove == WHITE);
+ fPonder = (pos.uToMove == BLACK);
+ break;
+ case I_PLAY_BLACK:
+ Trace("I play black.\n");
+ fThink = (pos.uToMove == BLACK);
+ fPonder = (pos.uToMove == WHITE);
+ break;
+ case FORCE_MODE:
+ default:
+ Trace("Force mode\n");
+ fThink = fPonder = FALSE;
+ break;
+ }
+
+ if (fThink) {
+ Trace("Think...\n");
+ result = Think(&pos);
+ if ((NumberOfPendingInputEvents() != 0) &&
+ (FALSE == g_fExitProgram))
+ {
+ MakeStatusLine();
+ ParseUserInput(FALSE);
+ }
+ DeclareTerminalStates(result);
+ } else if (fPonder) {
+ Trace("Ponder...\n");
+ if (g_Options.fShouldPonder) {
+ result = Ponder(&pos);
+ }
+ if (FALSE == g_fExitProgram)
+ {
+ MakeStatusLine();
+ ParseUserInput(FALSE);
+ }
+ DeclareTerminalStates(result);
+ } else {
+ Trace("Force mode, consume input and continue\n");
+ MakeStatusLine();
+ ParseUserInput(FALSE);
+ }
+ }
+}
+
+
+int CDECL
+main(int argc, char *argv[])
+/**
+
+Routine description:
+
+ Chess engine entry point and main loop.
+
+Parameters:
+
+ int argc,
+ char *argv[]
+
+Return value:
+
+ int CDECL
+
+**/
+{
+ // Initial setup work...
+ Trace("Setting up, please wait...\n");
+ if (FALSE == SystemDependentInitialization())
+ {
+ Trace("main: Operating system dependent init code failed, "
+ "aborting.\n");
+ exit(-1);
+ }
+ if (FALSE == MainProgramInitialization(argc, argv))
+ {
+ Trace("main: Main program init code failed, aborting.\n");
+ exit(-1);
+ }
+ Banner();
+#ifdef TEST
+ (void)RunStartupProgramTest();
+#endif
+ if (TRUE == g_Options.fNoInputThread)
+ {
+ InitInputSystemInBatchMode();
+ }
+ else
+ {
+ g_uInputThreadHandle = InitInputSystemWithDedicatedThread();
+ }
+
+ // Enter the main work loop code...
+ MainProgramLoop();
+
+ // If we get here g_fExitProgram is set -- clean up.
+ Trace("MAIN THREAD: thread terminating.\n");
+ if (FALSE == MainProgramCleanup())
+ {
+ Trace("main: Main program cleanup code failed, aborting.\n");
+ exit(-1);
+ }
+ exit(0);
+}
diff --git a/src/save/root.c b/src/save/root.c
new file mode 100755
index 0000000..ddd6015
--- /dev/null
+++ b/src/save/root.c
@@ -0,0 +1,1462 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ root.c
+
+Abstract:
+
+ Routines dealing with the root of the search tree. Specifically
+ move ordering at the root node, searching, search support, pondering,
+ pondering support, and the main iterative deepening loop.
+
+Author:
+
+ Scott Gasch ([email protected]) 21 May 2004
+
+Revision History:
+
+ $Id: root.c 351 2008-06-28 04:21:53Z scott $
+
+**/
+
+#include "chess.h"
+
+volatile MOVE_TIMER g_MoveTimer;
+ULONG g_uIterateDepth;
+ULONG g_uSoftExtendLimit;
+ULONG g_uHardExtendLimit;
+ULONG g_uExtensionReduction[MAX_PLY_PER_SEARCH];
+FLAG g_fCanSplit[MAX_PLY_PER_SEARCH];
+extern FILE *g_pfLogfile;
+SCORE g_iRootScore[2] = {0, 0};
+SCORE g_iScore;
+
+
+static void
+_SetMoveTimerForPonder(void)
+/**
+
+Routine description:
+
+ Set the move timer before a ponder operation. A time limit of -1
+ means search forever... so the only way out of the ponder is for
+ new user input to interrupt it.
+
+Parameters:
+
+ void
+
+Return value:
+
+ static void
+
+**/
+{
+ g_MoveTimer.dStartTime = SystemTimeStamp();
+ g_MoveTimer.dSoftTimeLimit = -1;
+ g_MoveTimer.dHardTimeLimit = -1;
+ g_MoveTimer.uNodeCheckMask = 0x200 - 1;
+ g_MoveTimer.bvFlags = 0;
+}
+
+
+void
+SetMoveTimerToThinkForever(void)
+/**
+
+Routine description:
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ g_MoveTimer.dStartTime = SystemTimeStamp();
+ g_MoveTimer.dSoftTimeLimit = -1;
+ g_MoveTimer.dHardTimeLimit = -1;
+ g_MoveTimer.uNodeCheckMask = 0x1000000 - 1;
+ g_MoveTimer.bvFlags = 0;
+}
+
+
+void
+SetMoveTimerForSearch(FLAG fSwitchOver, ULONG uColor)
+/**
+
+Routine description:
+
+ Set the move timer for a search operation.
+
+Parameters:
+
+ FLAG fSwitchOver : if TRUE then this search is a converted ponder
+ (i.e. they made the ponder move and now we are searching).
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG uMovesDone = GetMoveNumber(uColor);
+ double dClock = (double)g_Options.uMyClock;
+ double dSec = 0;
+ ULONG uMargin = 0;
+ ULONG uMovesToDo;
+
+ //
+ // If switching over from a ponder search leave the start time and
+ // move flags alone (i.e. N seconds in the past already).
+ //
+ if (FALSE == fSwitchOver)
+ {
+ g_MoveTimer.dStartTime = SystemTimeStamp();
+ g_MoveTimer.bvFlags = 0;
+ }
+
+ //
+ // Check the clock more often in search if there is little time
+ // left on the clock -- we can't afford an oversearch when the
+ // bullet game is down to the wire.
+ //
+#ifdef DEBUG
+ g_MoveTimer.uNodeCheckMask = 0x800 - 1;
+#else
+ if (WeAreRunningASuite())
+ {
+ g_MoveTimer.uNodeCheckMask = 0x20000 - 1;
+ }
+ else if (g_Options.u64MaxNodeCount)
+ {
+ g_MoveTimer.uNodeCheckMask = 0x1000 - 1;
+ }
+ else
+ {
+ if (dClock < 10.0)
+ {
+ g_MoveTimer.uNodeCheckMask = 0x400 - 1;
+ }
+ else
+ {
+ g_MoveTimer.uNodeCheckMask = 0x8000 - 1;
+ }
+ }
+#endif
+
+ switch (g_Options.eClock)
+ {
+ //
+ // Fixed time per move. Think for g_uMyIncrement seconds exactly and
+ // no hard time limit.
+ //
+ case CLOCK_FIXED:
+ dSec = (double)g_Options.uMyIncrement;
+ uMargin = 0;
+ break;
+
+ //
+ // N moves per time control or entire game in time control.
+ //
+ case CLOCK_NORMAL:
+ if (g_Options.uMovesPerTimePeriod != 0)
+ {
+ //
+ // N moves per time control.
+ //
+ ASSERT(g_Options.uMovesPerTimePeriod < 256);
+ uMovesToDo =
+ (g_Options.uMovesPerTimePeriod -
+ ((uMovesDone - 1) % g_Options.uMovesPerTimePeriod));
+#ifdef DEBUG
+ Trace("SetMoveTimer: %u moves left to do this in %s sec.\n",
+ uMovesToDo, TimeToString(dClock));
+#endif
+ ASSERT(uMovesToDo <= g_Options.uMovesPerTimePeriod);
+ dSec = (dClock / (double)uMovesToDo);
+ dSec *= 0.95;
+ uMargin = (ULONG)(dSec * 2.2);
+ if (uMovesToDo <= 5)
+ {
+ dSec *= 0.75;
+ uMargin /= 2;
+ }
+ break;
+ }
+ else
+ {
+ //
+ // Fixed time finish entire game.
+ //
+#ifdef DEBUG
+ Trace("SetMoveTimer: finish the game in %s sec.\n",
+ TimeToString(dClock));
+#endif
+ dSec = dClock / 60;
+ uMargin = (ULONG)(dSec * 2.2);
+ }
+ break;
+
+ //
+ // We get back a certain number of seconds with each move made.
+ //
+ case CLOCK_INCREMENT:
+ dSec = g_Options.uMyIncrement;
+ dSec += (dClock / 50);
+ uMargin = (int)(dSec * 2.2);
+
+#ifdef DEBUG
+ Trace("SetMoveTimer: finish the game in %s sec (+%u per move).\n",
+ TimeToString(dClock), g_Options.uMyIncrement);
+#endif
+
+ //
+ // If we are running out of time, think for less than the
+ // increment.
+ //
+ if (dClock < 20.0)
+ {
+ dSec -= g_Options.uMyIncrement;
+ uMargin = 0;
+ }
+ ASSERT(dSec > 0);
+ break;
+
+ case CLOCK_NONE:
+#ifdef DEBUG
+ Trace("SetMoveTimer: no time limit, think until interrupted.\n");
+#endif
+ g_MoveTimer.dHardTimeLimit = -1;
+ g_MoveTimer.dSoftTimeLimit = -1;
+ goto post;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ if ((dSec + uMargin) >= (dClock * 7 / 8)) uMargin = 0;
+ g_MoveTimer.dSoftTimeLimit = g_MoveTimer.dStartTime + dSec;
+ g_MoveTimer.dHardTimeLimit = g_MoveTimer.dStartTime + dSec + uMargin;
+
+ post:
+ if (TRUE == g_Options.fShouldPost)
+ {
+ if (g_MoveTimer.dSoftTimeLimit > 0)
+ {
+ Trace("SetMoveTimer: Soft time limit %s seconds.\n",
+ TimeToString(g_MoveTimer.dSoftTimeLimit -
+ g_MoveTimer.dStartTime));
+ ASSERT(g_MoveTimer.dHardTimeLimit > 0);
+ Trace("SetMoveTimer: Hard time limit %s seconds.\n",
+ TimeToString(g_MoveTimer.dHardTimeLimit -
+ g_MoveTimer.dStartTime));
+ if (TRUE == fSwitchOver)
+ {
+ Trace("SetMoveTimer: Already searched %s seconds.\n",
+ TimeToString(SystemTimeStamp() -
+ g_MoveTimer.dStartTime));
+ }
+ }
+#ifdef DEBUG
+ Trace("SetMoveTimer: Checking input and timer every %u nodes.\n",
+ g_MoveTimer.uNodeCheckMask);
+#endif
+ }
+}
+
+
+void
+ReInitializeSearcherContext(POSITION *pos,
+ SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Reinitializes a SEARCHER_THREAD_CONTEXT structure.
+
+Parameters:
+
+ POSITION *pos,
+ SEARCHER_THREAD_CONTEXT *ctx
+
+Return value:
+
+ void
+
+**/
+{
+ if (NULL != pos)
+ {
+ memmove(&(ctx->sPosition), pos, sizeof(POSITION));
+ }
+ ctx->uPly = 0;
+ ctx->uPositional = 133;
+ memset(&(ctx->sCounters), 0, sizeof(COUNTERS));
+}
+
+
+void
+InitializeSearcherContext(POSITION *pos,
+ SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Initialize a SEARCHER_THREAD_CONTEXT structure.
+
+Parameters:
+
+ POSITION *pos,
+ SEARCHER_THREAD_CONTEXT *ctx
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG u;
+
+ memset(ctx, 0, sizeof(SEARCHER_THREAD_CONTEXT));
+ ReInitializeSearcherContext(pos, ctx);
+ ctx->sMoveStack.uUnblockedKeyValue[0] = 1;
+ for (u = 1;
+ u < MAX_PLY_PER_SEARCH;
+ u++)
+ {
+ ctx->sMoveStack.uUnblockedKeyValue[u] =
+ ctx->sMoveStack.uUnblockedKeyValue[u-1] + 0x28F5C28;
+ }
+}
+
+
+void
+InitializeLightweightSearcherContext(POSITION *pos,
+ LIGHTWEIGHT_SEARCHER_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Initialize a LIGHTWEIGHT_SEARCHER_CONTEXT structure.
+
+Parameters:
+
+ POSITION *pos,
+ LIGHTWEIGHT_SEARCHER_CONTEXT *ctx
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG u;
+
+ memset(ctx, 0, sizeof(LIGHTWEIGHT_SEARCHER_CONTEXT));
+ if (NULL != pos)
+ {
+ memmove(&(ctx->sPosition), pos, sizeof(POSITION));
+ }
+ ctx->uPly = 0;
+ ctx->uPositional = 133;
+ ctx->sMoveStack.uUnblockedKeyValue[0] = 1;
+ for (u = 1;
+ u < MAX_PLY_PER_SEARCH;
+ u++)
+ {
+ ctx->sMoveStack.uUnblockedKeyValue[u] =
+ ctx->sMoveStack.uUnblockedKeyValue[u-1] + 0x28F5C28;
+ }
+}
+
+
+void
+PostMoveSearchReport(SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Dump a report to stdout after every move.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx,
+
+Return value:
+
+ void
+
+**/
+{
+ double d;
+ char buf[256];
+#ifdef PERF_COUNTERS
+ double n;
+#endif
+ d = (double)g_MoveTimer.dEndTime - (double)g_MoveTimer.dStartTime + 0.01;
+ ASSERT(d);
+ Trace("---------------------------------------------\n"
+ "Searched for %5.1f seconds, saw %"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT
+ " nodes (%"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT
+ " qnodes) (%6.0f nps).\n",
+ d, ctx->sCounters.tree.u64TotalNodeCount,
+ ctx->sCounters.tree.u64QNodeCount,
+ ((double)ctx->sCounters.tree.u64TotalNodeCount / d));
+ if (g_Options.fThinking)
+ {
+ snprintf(buf, ARRAY_LENGTH(buf), "d%u, %s, %3.1fs, %6.0fknps, PV=%s",
+ ctx->uRootDepth / ONE_PLY,
+ ScoreToString(ctx->iRootScore),
+ d,
+ ((double)ctx->sCounters.tree.u64TotalNodeCount / d / 1000),
+ ctx->szLastPV);
+ Trace("tellothers %s\n", buf);
+ }
+#ifdef MP
+#ifdef PERF_COUNTERS
+ if (ctx->sCounters.parallel.uNumSplits > 0)
+ {
+ n = (double)ctx->sCounters.parallel.uNumSplits;
+ Trace("Split %u times total ",
+ ctx->sCounters.parallel.uNumSplits);
+ Trace("(~%7.2fx/sec).\n", (n / d));
+ d = n + 1;
+ ASSERT(d);
+ n = (double)ctx->sCounters.parallel.uNumSplitsTerminated;
+ Trace(" ...%u (%5.2f percent) terminated early.\n",
+ ctx->sCounters.parallel.uNumSplitsTerminated, ((n/d) * 100.0));
+ DumpHelperIdlenessReport();
+ }
+#endif
+#endif
+
+#ifdef TEST
+ AnalyzeFullHashTable();
+#endif
+#ifdef PERF_COUNTERS
+ d = (double)(ctx->sCounters.hash.u64Probes) + 1;
+ ASSERT(d);
+ Trace("Hashing percentages: (%5.3f total, %5.3f useful)\n",
+ ((double)(ctx->sCounters.hash.u64OverallHits) / d) * 100.0,
+ ((double)(ctx->sCounters.hash.u64UsefulHits) / d) * 100.0);
+ d = (double)(ctx->sCounters.pawnhash.u64Probes) + 1;
+ ASSERT(d);
+ n = (double)(ctx->sCounters.pawnhash.u64Hits);
+ Trace("Pawn hash hitrate: %5.3f percent.\n", (n/d) * 100.0);
+ n = (double)(ctx->sCounters.tree.u64NullMoveSuccess);
+ d = (double)(ctx->sCounters.tree.u64NullMoves) + 1;
+ ASSERT(d);
+ Trace("Null move cutoff rate: %5.3f percent.\n",
+ ((n / d) * 100.0));
+#ifdef TEST_ENDGAME
+ n = (double)(ctx->sCounters.tree.u64EndgamePruningSuccess);
+ d = n + (double)(ctx->sCounters.tree.u64EndgamePruningFailures);
+ if (d != 0.0)
+ {
+ Trace("Endgame pruning heuristic success rate was %5.3f percent.\n"
+ "Endgame pruning heuristic was "
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT " / "
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT ".\n",
+ ((n / d) * 100.0),
+ ctx->sCounters.tree.u64EndgamePruningSuccess,
+ (ctx->sCounters.tree.u64EndgamePruningSuccess +
+ ctx->sCounters.tree.u64EndgamePruningFailures));
+ }
+ else
+ {
+ Trace("Never used endgame pruning heuristic.\n");
+ }
+#endif
+#ifdef TEST_NULL
+ n = (double)(ctx->sCounters.tree.u64AvoidNullSuccess);
+ d = n + (double)(ctx->sCounters.tree.u64AvoidNullFailures);
+ if (d != 0.0)
+ {
+ Trace("Avoid null move heuristic rate was %5.3f percent.\n"
+ "Avoid null move heuristic was "
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT " / "
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT ".\n",
+ ((n / d) * 100.0),
+ ctx->sCounters.tree.u64AvoidNullSuccess,
+ (ctx->sCounters.tree.u64AvoidNullSuccess +
+ ctx->sCounters.tree.u64AvoidNullFailures));
+ }
+ else
+ {
+ Trace("Never used the avoid null move heuristic.\n");
+ }
+ n = (double)(ctx->sCounters.tree.u64QuickNullSuccess);
+ n += (double)(ctx->sCounters.tree.u64QuickNullDeferredSuccess);
+ d = n + (double)(ctx->sCounters.tree.u64QuickNullFailures);
+ if (d != 0.0)
+ {
+ Trace("Quick null move heuristic rate was %5.3f percent.\n"
+ "Quick null move heuristic rate was "
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT " ("
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT ") / "
+ "%"COMPILER_LONGLONG_UNSIGNED_FORMAT ".\n",
+ ((n / d) * 100.0),
+ ctx->sCounters.tree.u64QuickNullSuccess,
+ ctx->sCounters.tree.u64QuickNullDeferredSuccess,
+ (ctx->sCounters.tree.u64QuickNullSuccess +
+ ctx->sCounters.tree.u64QuickNullDeferredSuccess +
+ ctx->sCounters.tree.u64QuickNullFailures));
+ }
+ else
+ {
+ Trace("Never used the quick null move heuristic.\n");
+ }
+#endif
+ n = (double)ctx->sCounters.tree.u64BetaCutoffsOnFirstMove;
+ d = (double)ctx->sCounters.tree.u64BetaCutoffs + 1;
+ Trace("First move beta cutoff rate was %5.3f percent.\n",
+ ((n / d) * 100.0));
+#ifdef LAZY_EVAL
+ d = (double)ctx->sCounters.tree.u64LazyEvals;
+ d += (double)ctx->sCounters.tree.u64FullEvals;
+ d += (double)ctx->sCounters.tree.u64EvalHashHits;
+ d += 1;
+ ASSERT(d);
+ Trace("Eval percentages: (%5.2f hash, %5.2f lazy, %5.2f full)\n",
+ ((double)ctx->sCounters.tree.u64EvalHashHits / d) * 100.0,
+ ((double)ctx->sCounters.tree.u64LazyEvals / d) * 100.0,
+ ((double)ctx->sCounters.tree.u64FullEvals / d) * 100.0);
+#endif
+ Trace("Extensions: (%u +, %u q+, %u 1mv, %u !kmvs, %u mult+, %u pawn\n"
+ " %u threat, %u zug, %u sing, %u endg, %u bm, %u recap)\n",
+ ctx->sCounters.extension.uCheck,
+ ctx->sCounters.extension.uQExtend,
+ ctx->sCounters.extension.uOneLegalMove,
+ ctx->sCounters.extension.uNoLegalKingMoves,
+ ctx->sCounters.extension.uMultiCheck,
+ ctx->sCounters.extension.uPawnPush,
+ ctx->sCounters.extension.uMateThreat,
+ ctx->sCounters.extension.uZugzwang,
+ ctx->sCounters.extension.uSingularReplyToCheck,
+ ctx->sCounters.extension.uEndgame,
+ ctx->sCounters.extension.uBotvinnikMarkoff,
+ ctx->sCounters.extension.uRecapture);
+#ifdef EVAL_TIME
+ n = (double)ctx->sCounters.tree.u64CyclesInEval;
+ Trace("Avg. cpu cycles in eval: %8.1f.\n", (n / d));
+#endif
+#endif
+ fflush(g_pfLogfile);
+}
+
+
+SCORE
+RootSearch(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta,
+ ULONG uDepth)
+/**
+
+Routine description:
+
+ Search at the root of the whole tree.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta,
+ ULONG uDepth,
+
+Return value:
+
+ SCORE
+
+**/
+{
+ PLY_INFO *pi = &ctx->sPlyInfo[ctx->uPly];
+ SCORE iBestScore = -INFINITY;
+ SCORE iInitialAlpha = iAlpha;
+ MOVE mv;
+ ULONG x, y;
+ SCORE iScore;
+ ULONG uNextDepth;
+ UINT64 u64StartingNodeCount;
+ ULONG uNumLegalMoves;
+
+#ifdef DEBUG
+ POSITION *pos = &ctx->sPosition;
+ ASSERT(IS_VALID_SCORE(iAlpha));
+ ASSERT(IS_VALID_SCORE(iBeta));
+ ASSERT(iAlpha < iBeta);
+ ASSERT((ctx->uPly == 0) || (ctx->uPly == 1)); // 1 is for under a ponder
+ memcpy(&pi->sPosition, pos, sizeof(POSITION));
+#endif
+
+ ctx->sCounters.tree.u64TotalNodeCount++;
+ pi->PV[ctx->uPly] = NULLMOVE;
+ pi->mvBest = NULLMOVE;
+ g_MoveTimer.bvFlags |= TIMER_SEARCHING_FIRST_MOVE;
+#ifdef DEBUG
+ Trace("---- depth=%u, a=%d, b=%d ----\n", uDepth / ONE_PLY, iAlpha, iBeta);
+#endif
+
+ uNumLegalMoves = 0;
+ for (x = ctx->sMoveStack.uBegin[ctx->uPly];
+ x < ctx->sMoveStack.uEnd[ctx->uPly];
+ x++)
+ {
+ SelectMoveAtRoot(ctx, x);
+ if (ctx->sMoveStack.mvf[x].bvFlags & MVF_MOVE_SEARCHED) break;
+ ctx->sMoveStack.mvf[x].bvFlags |= MVF_MOVE_SEARCHED;
+ mv = ctx->sMoveStack.mvf[x].mv;
+ mv.bvFlags |= WouldGiveCheck(ctx, mv);
+
+ if (MakeMove(ctx, mv))
+ {
+ uNumLegalMoves++;
+ u64StartingNodeCount = ctx->sCounters.tree.u64TotalNodeCount;
+
+ //
+ // TODO: Fancy recap shit here?
+ //
+
+ uNextDepth = uDepth - ONE_PLY;
+ if (IS_CHECKING_MOVE(mv))
+ {
+ uNextDepth += HALF_PLY;
+ ctx->sPlyInfo[ctx->uPly].iExtensionAmount = HALF_PLY;
+ }
+
+ ctx->sSearchFlags.fVerifyNullmove = TRUE;
+ ctx->sSearchFlags.uQsearchDepth = 0;
+ if (uNumLegalMoves == 1)
+ {
+ //
+ // Move 1, full a..b window
+ //
+ iScore = -Search(ctx, -iBeta, -iAlpha, uNextDepth);
+ }
+ else
+ {
+ //
+ // Moves 2..N, minimal window search
+ //
+ ASSERT(x > 0);
+ ASSERT(uNumLegalMoves > 1);
+ iScore = -Search(ctx, -iAlpha - 1, -iAlpha, uNextDepth);
+ if ((iAlpha < iScore) && (iScore < iBeta))
+ {
+ iScore = -Search(ctx, -iBeta, -iAlpha, uNextDepth);
+ }
+ }
+ ctx->sSearchFlags.fVerifyNullmove = FALSE;
+ UnmakeMove(ctx, mv);
+ if (WE_SHOULD_STOP_SEARCHING)
+ {
+ iBestScore = INVALID_SCORE;
+ goto end;
+ }
+#ifdef DEBUG
+ Trace("%2u. %-8s => node=%" COMPILER_LONGLONG_UNSIGNED_FORMAT
+ ", predict=%d, actual=%d, ",
+ x + 1,
+ MoveToSan(mv, &ctx->sPosition),
+ u64StartingNodeCount,
+ ctx->sMoveStack.mvf[x].iValue,
+ iScore);
+ ASSERT(PositionsAreEquivalent(&pi->sPosition, &ctx->sPosition));
+#endif
+ //
+ // Keep track of how many moves are under each one we
+ // search and use this as the basis for root move ordering
+ // next iteration.
+ //
+ u64StartingNodeCount = (ctx->sCounters.tree.u64TotalNodeCount -
+ u64StartingNodeCount);
+ u64StartingNodeCount >>= 9;
+ u64StartingNodeCount &= (MAX_INT / 4);
+ ctx->sMoveStack.mvf[x].iValue =
+ (SCORE)(u64StartingNodeCount + iScore);
+#ifdef DEBUG
+ Trace("next_predict: %d\n", ctx->sMoveStack.mvf[x].iValue);
+ ASSERT(iBestScore <= iAlpha);
+ ASSERT(iAlpha < iBeta);
+#endif
+ if (iScore > iBestScore)
+ {
+ iBestScore = iScore;
+ pi->mvBest = mv;
+ if (iScore > iAlpha)
+ {
+ //
+ // We have a best move so far. As of now it is
+ // the one we'll be playing. Also make sure to
+ // search it first at the next depth.
+ //
+#ifdef DEBUG
+ Trace("Best so far... root score=%d.\n", iScore);
+#endif
+ ctx->mvRootMove = mv;
+ ctx->iRootScore = iScore;
+ ctx->uRootDepth = uDepth;
+ ctx->sMoveStack.mvf[x].iValue = MAX_INT;
+
+ //
+ // If there was a previous PV move then knock its
+ // score down so that it will be considered second
+ // on the next depth.
+ //
+ for (y = ctx->sMoveStack.uBegin[ctx->uPly];
+ y < x;
+ y++)
+ {
+ if (ctx->sMoveStack.mvf[y].iValue == MAX_INT)
+ {
+ ctx->sMoveStack.mvf[y].iValue /= 2;
+ }
+ }
+
+ UpdatePV(ctx, mv);
+ if (iScore >= iBeta)
+ {
+ //
+ // Root fail high...
+ //
+ UpdateDynamicMoveOrdering(ctx,
+ uDepth,
+ mv,
+ iScore,
+ x + 1);
+ UtilPrintPV(ctx, iAlpha, iBeta, iScore, mv);
+ KEEP_TRACK_OF_FIRST_MOVE_FHs(iBestScore == -INFINITY);
+ ctx->sMoveStack.mvf[x].bvFlags &= ~MVF_MOVE_SEARCHED;
+ goto end;
+ }
+ else
+ {
+ //
+ // Root PV change...
+ //
+ UtilPrintPV(ctx, iAlpha, iBeta, iScore, mv);
+ iAlpha = iScore;
+ }
+ }
+ }
+ g_MoveTimer.bvFlags &= ~TIMER_SEARCHING_FIRST_MOVE;
+ }
+ }
+
+ if (iAlpha == iInitialAlpha)
+ {
+ //
+ // Root fail low...
+ //
+ ASSERT(iBestScore <= iAlpha);
+ ASSERT(PositionsAreEquivalent(pos, &pi->sPosition));
+ UtilPrintPV(ctx, iAlpha, iBeta, iBestScore, mv);
+ }
+
+ end:
+ return(iBestScore);
+}
+
+
+
+static GAME_RESULT
+_DetectPreMoveTerminalStates(SEARCHER_THREAD_CONTEXT *ctx,
+ FLAG fInCheck,
+ MOVE *pmv) {
+ ULONG u;
+ MOVE mv;
+ MOVE mvLegal;
+ ULONG uNumLegal = 0;
+ GAME_RESULT ret;
+
+ ret.eResult = RESULT_IN_PROGRESS;
+ ret.szDescription[0] = '\0';
+ pmv->uMove = 0;
+
+ for (u = ctx->sMoveStack.uBegin[ctx->uPly];
+ u < ctx->sMoveStack.uEnd[ctx->uPly];
+ u++) {
+ mv = ctx->sMoveStack.mvf[u].mv;
+ if (MakeMove(ctx, mv)) {
+ mvLegal = mv;
+ uNumLegal += 1;
+ UnmakeMove(ctx, mv);
+ if (uNumLegal > 1) {
+ return ret;
+ }
+ }
+ }
+ if (uNumLegal == 1) {
+ *pmv = mvLegal;
+ return ret;
+ }
+ ASSERT(uNumLegal == 0);
+ if (TRUE == fInCheck) {
+ if (ctx->sPosition.uToMove == WHITE) {
+ ret.eResult = RESULT_BLACK_WON;
+ strcpy(ret.szDescription, "black checkmated white");
+ return ret;
+ }
+ ret.eResult = RESULT_WHITE_WON;
+ strcpy(ret.szDescription, "white checkmated black");
+ return ret;
+ }
+ ret.eResult = RESULT_DRAW;
+ sprintf(ret.szDescription, "%s stalemated %s",
+ (ctx->sPosition.uToMove == WHITE) ? "black" : "white",
+ (ctx->sPosition.uToMove == WHITE) ? "while" : "black");
+ return ret;
+}
+
+
+
+static GAME_RESULT
+_DetectPostMoveTerminalStates(SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ This function is called by Iterate and MakeTheMove to declare
+ wins/losses/draws.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx
+
+Return value:
+
+ FLAG
+
+**/
+{
+ GAME_RESULT ret;
+ FLAG fInCheck = InCheck(&ctx->sPosition, ctx->sPosition.uToMove);
+
+ // Did we just make the 50th+ move without progress?
+ if (ctx->sPosition.uFifty >= 100) {
+ ret.eResult = RESULT_DRAW;
+ strcpy(ret.szDescription, "fifty moves without progress");
+ return ret;
+ }
+ GenerateMoves(ctx, NULLMOVE, (fInCheck ? GENERATE_ESCAPES :
+ GENERATE_ALL_MOVES));
+
+ // Did we just repeat a position for the 3rd time?
+ if (IsLegalDrawByRepetition()) {
+ ret.eResult = RESULT_DRAW;
+ strcpy(ret.szDescription, "third repetition of position");
+ return ret;
+ }
+
+ // Otherwise look for checkmates and stalemates.
+ MOVE mvUnused;
+ return _DetectPreMoveTerminalStates(ctx,
+ fInCheck,
+ &mvUnused);
+}
+
+
+static void
+_IterateSetSearchGlobals(ULONG uDepth)
+{
+ ULONG u, v;
+ ULONG uDontSplitLessThan;
+
+ //
+ // Set some globals that will be used throughout this search.
+ //
+ g_uIterateDepth = uDepth;
+ ASSERT(g_uIterateDepth > 0);
+ ASSERT(g_uIterateDepth < MAX_PLY_PER_SEARCH);
+
+ //
+ // For use in scaling back extensions that are very far from
+ // the root.
+ //
+ // Iterate g_Soft g_Hard
+ // | | | | | | | | |
+ // 0 1 2 2.5 3 3.5 4 (x Iterate)
+ // |-------------------|----|----|---------|----...
+ // |full full full full|-1/4|-1/2|-3/4 -3/4|none...
+ //
+ g_uSoftExtendLimit = g_uIterateDepth * 2;
+ g_uHardExtendLimit = g_uIterateDepth * 4;
+ for (u = 0; u < MAX_PLY_PER_SEARCH; u++)
+ {
+ if (u < g_uSoftExtendLimit)
+ {
+ g_uExtensionReduction[u] = 0;
+ }
+ else if (u < (g_uSoftExtendLimit + g_uIterateDepth / 2))
+ {
+ g_uExtensionReduction[u] = QUARTER_PLY;
+ }
+ else if (u < (g_uSoftExtendLimit + g_uIterateDepth))
+ {
+ g_uExtensionReduction[u] = HALF_PLY;
+ }
+ else if (u < g_uHardExtendLimit)
+ {
+ g_uExtensionReduction[u] = THREE_QUARTERS_PLY;
+ }
+ else
+ {
+ g_uExtensionReduction[u] = 5 * ONE_PLY;
+ }
+ }
+
+ //
+ // Determine how much depth we need below a point in the tree in
+ // order to split the search (which is based on iteration depth).
+ //
+ uDontSplitLessThan = (ULONG)((double)(uDepth) * 0.30);
+ for (v = 0; v < MAX_PLY_PER_SEARCH; v++)
+ {
+ g_fCanSplit[v] = ((v + 1) >= uDontSplitLessThan);
+ }
+ g_fCanSplit[0] = FALSE;
+}
+
+
+#define SKIP_GRADUAL_OPENING 600
+#define INITIAL_HALF_WINDOW 75
+#define FIRST_FAIL_STEP 150
+#define SECOND_FAIL_STEP 375
+
+void
+_IterateWidenWindow(ULONG uColor,
+ SCORE iScore,
+ SCORE *piBound,
+ ULONG *puState,
+ int iDir)
+{
+ SCORE iRoughScore = g_iRootScore[uColor];
+ static SCORE _Steps[] =
+ {
+ FIRST_FAIL_STEP,
+ SECOND_FAIL_STEP,
+ INFINITY
+ };
+
+// Trace("State = %u.\n", *puState);
+// Trace("Bound from %d to ", *piBound);
+ if ((abs(iRoughScore - iScore) > SKIP_GRADUAL_OPENING) ||
+ (*puState == 2))
+ {
+ *piBound = iDir * INFINITY;
+ *puState = 2;
+ }
+ else
+ {
+ ASSERT(*puState < 2);
+ *piBound = iScore;
+ *piBound += iDir * _Steps[*puState];
+ *puState += 1;
+ }
+// Trace("%d.\n", *piBound);
+// Trace("State = %u\n", *puState);
+}
+
+
+GAME_RESULT Iterate(SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Main iterative deepening loop for both thinking and pondering.
+ Call RootSearch with progressively deeper depths while there is
+ remaining time, we haven't found a forced mate, and there's no
+ user interruption.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx
+
+Return value:
+
+ FLAG : is the game over?
+
+**/
+{
+ ULONG uNumRootFailLows = 0;
+ ULONG uDepth;
+ ULONG uFailState = 0;
+ ULONG uColor;
+ ULONG u;
+ SCORE iAlpha = -INFINITY;
+ SCORE iBeta = +INFINITY;
+ SCORE iScore;
+ FLAG fInCheck = InCheck(&(ctx->sPosition), ctx->sPosition.uToMove);
+ MOVE mv;
+ GAME_RESULT ret;
+#ifdef DEBUG
+ POSITION board;
+ memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
+ VerifyPositionConsistency(&board, FALSE);
+#endif
+
+ uColor = ctx->sPosition.uToMove;
+ g_iRootScore[uColor] = GetRoughEvalScore(ctx, iAlpha, iBeta, TRUE);
+ g_iRootScore[FLIP(uColor)] = -g_iRootScore[uColor];
+
+ //
+ // Generate moves here so that RootSearch doesn't have to.
+ //
+ ASSERT((ctx->uPly == 0) || (ctx->uPly == 1)); // 1 is under a ponder
+ ctx->sPlyInfo[ctx->uPly].fInCheck = fInCheck;
+ GenerateMoves(ctx, NULLMOVE, (fInCheck ? GENERATE_ESCAPES :
+ GENERATE_ALL_MOVES));
+ ASSERT(ctx->sMoveStack.uBegin[0] == 0);
+
+ //
+ // See if we are sitting at a checkmate or stalemate position; no
+ // sense searching if so.
+ //
+ ret = _DetectPreMoveTerminalStates(ctx,
+ fInCheck,
+ &mv);
+ if (ret.eResult != RESULT_IN_PROGRESS) {
+ goto end;
+ }
+
+ // Game still in progress but only one legal move available?
+ if (mv.uMove != 0) {
+ ctx->mvRootMove = mv;
+ ctx->iRootScore = 0;
+ ctx->uRootDepth = 0;
+ ctx->sPlyInfo[0].PV[0] = mv;
+ ctx->sPlyInfo[0].PV[1] = NULLMOVE;
+ strcpy(ctx->szLastPV, "only");
+ if (!g_Options.fPondering) {
+ Trace("ONLY MOVE --> stop searching now\n");
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+ g_MoveTimer.bvFlags |= TIMER_CURRENT_OBVIOUS;
+ } else {
+ Trace("ONLY PONDER --> move immediately if prediction correct.\n");
+ g_MoveTimer.bvFlags |= TIMER_MOVE_IMMEDIATELY;
+ g_MoveTimer.bvFlags |= TIMER_CURRENT_OBVIOUS;
+ }
+ goto end;
+ }
+
+ for (uDepth = 1;
+ uDepth <= g_Options.uMaxDepth;
+ uDepth++)
+ {
+ //
+ // Re-rank the moves based on nodecounts and mark all moves as
+ // not yet searched at this depth.
+ //
+ for (u = ctx->sMoveStack.uBegin[ctx->uPly];
+ u < ctx->sMoveStack.uEnd[ctx->uPly];
+ u++)
+ {
+ ctx->sMoveStack.mvf[u].bvFlags &= ~MVF_MOVE_SEARCHED;
+ }
+
+ //
+ // Make sure a..b window makes sense and set some other per-depth
+ // globals used by the search.
+ //
+ _IterateSetSearchGlobals(uDepth);
+
+ //
+ // Try to get a PV for this depth before we're out of time...
+ //
+ do
+ {
+ if (iBeta > INFINITY) iBeta = +INFINITY;
+ if (iAlpha < -INFINITY) iAlpha = -INFINITY;
+ if (iAlpha >= iBeta) iAlpha = iBeta - 1;
+ iScore = RootSearch(ctx,
+ iAlpha,
+ iBeta,
+ uDepth * ONE_PLY + HALF_PLY);
+ if (g_MoveTimer.bvFlags & TIMER_STOPPING) break;
+ mv = ctx->mvRootMove;
+
+ //
+ // Got a PV, we're done with this depth.
+ //
+ if ((iAlpha < iScore) && (iScore < iBeta))
+ {
+ ASSERT(iScore == ctx->iRootScore);
+ ASSERT(mv.uMove);
+ ASSERT(SanityCheckMove(&ctx->sPosition, mv));
+ iAlpha = iScore - INITIAL_HALF_WINDOW;
+ iBeta = iScore + INITIAL_HALF_WINDOW;
+ g_iRootScore[uColor] = iScore;
+ g_iRootScore[FLIP(uColor)] = -iScore;
+ g_MoveTimer.bvFlags &= ~TIMER_RESOLVING_ROOT_FH;
+ g_MoveTimer.bvFlags &= ~TIMER_RESOLVING_ROOT_FL;
+ uFailState = 0;
+ (void)CheckTestSuiteMove(mv, iScore, uDepth);
+ break;
+ }
+
+ //
+ // Root fail low? We'll have to research with a wider
+ // window.
+ //
+ else if (iScore <= iAlpha)
+ {
+ ASSERT(ctx->mvRootMove.uMove);
+ g_MoveTimer.bvFlags |= TIMER_RESOLVING_ROOT_FL;
+ uNumRootFailLows++;
+ if (uNumRootFailLows > 3)
+ {
+ g_MoveTimer.bvFlags |= TIMER_MANY_ROOT_FLS;
+ }
+ _IterateWidenWindow(uColor, iScore, &iAlpha, &uFailState, -1);
+
+ //
+ // Consider all moves again with wider window...
+ //
+ for (u = ctx->sMoveStack.uBegin[ctx->uPly];
+ u < ctx->sMoveStack.uEnd[ctx->uPly];
+ u++)
+ {
+ ctx->sMoveStack.mvf[u].bvFlags &= ~MVF_MOVE_SEARCHED;
+ }
+ }
+
+ //
+ // Must be a root fail high.
+ //
+ else
+ {
+ ASSERT(iScore >= iBeta);
+ ASSERT(mv.uMove);
+ ASSERT(SanityCheckMove(&ctx->sPosition, mv));
+ g_MoveTimer.bvFlags |= TIMER_RESOLVING_ROOT_FH;
+ _IterateWidenWindow(uColor, iScore, &iBeta, &uFailState, +1);
+ }
+ }
+ while(1); // repeat until we run out of time or fall inside a..b
+
+ //
+ // We are here because either:
+ //
+ // 1. we completed a search depth,
+ // or 2. we ran out of time,
+ // or 3. there is one legal move and we want to make it immediately,
+ // or 4. there was user input and we unrolled the search.
+ //
+
+ //
+ // TODO: Scale back history between iterative depths?
+ //
+
+ //
+ // Mate-in-n when we have searched n? Stop searching.
+ //
+ if (IS_VALID_SCORE(iScore) &&
+ (ULONG)abs(iScore) >= (INFINITY - uDepth))
+ {
+ Trace("FORCED MATE --> stop searching now\n");
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+ }
+
+ //
+ // Have we reached user's maxdepth option? Stop searching.
+ //
+ if (uDepth >= g_Options.uMaxDepth)
+ {
+ Trace("DEPTH LIMIT --> stop searching now\n");
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+ }
+
+ //
+ // Did the move timer expire? Stop searching.
+ //
+ if (g_MoveTimer.bvFlags & TIMER_STOPPING) break;
+ }
+ g_Options.u64NodesSearched = ctx->sCounters.tree.u64TotalNodeCount;
+ g_MoveTimer.dEndTime = SystemTimeStamp();
+
+ //
+ // Here we are at the end of a search. If we were:
+ //
+ // ...Searching then: ...Pondering then:
+ //
+ // 1. we ran out of time 1. they made a different move than
+ // the predicted move and we aborted
+ // 2. we ran out of depth
+ // 2. we ran out of depth
+ // 3. we found a mate-in-n
+ // 3. we found a mate-in-n
+ // TODO: node count limit?
+ // (4. if they made the predicted move
+ // then we converted to a search)
+ //
+ ASSERT(ctx->mvRootMove.uMove);
+ ASSERT(SanityCheckMove(&board, ctx->mvRootMove));
+ if (g_MoveTimer.bvFlags & TIMER_RESOLVING_ROOT_FL)
+ {
+ ctx->sPlyInfo[ctx->uPly].PV[ctx->uPly] = ctx->mvRootMove;
+ ctx->sPlyInfo[ctx->uPly].PV[ctx->uPly+1] = NULLMOVE;
+ }
+ ret.eResult = RESULT_IN_PROGRESS;
+ ret.szDescription[0] = '\0';
+ end:
+ return ret;
+}
+
+void
+MakeTheMove(SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Make the move that search selected in the official game list.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx
+
+Return value:
+
+ FLAG
+
+**/
+{
+ MOVE mv = ctx->mvRootMove;
+ ASSERT(mv.uMove);
+
+ if (TRUE == g_Options.fThinking)
+ {
+ //
+ // TODO: keep track of how many moves in a row we are at or
+ // below a draw score and use this to respond to draw offers.
+ //
+
+ //
+ // Was this a search that converted from a ponder?
+ //
+ if (TRUE == g_Options.fSuccessfulPonder)
+ {
+ if (FALSE == OfficiallyMakeMove(g_Options.mvPonder, 0, FALSE))
+ {
+ UtilPanic(CANNOT_OFFICIALLY_MAKE_MOVE,
+ GetRootPosition(),
+ (void *)g_Options.mvPonder.uMove,
+ NULL,
+ NULL,
+ __FILE__,
+ __LINE__);
+ }
+ g_Options.fSuccessfulPonder = FALSE;
+ }
+
+ //
+ // Tell the server about our move and actually play it on the
+ // root board.
+ //
+ Trace("move %s\n", MoveToSan(mv, &ctx->sPosition));
+ if (FALSE == OfficiallyMakeMove(mv, g_iScore, FALSE))
+ {
+ UtilPanic(CANNOT_OFFICIALLY_MAKE_MOVE,
+ GetRootPosition(),
+ (void *)mv.uMove,
+ NULL,
+ NULL,
+ __FILE__,
+ __LINE__);
+ }
+ if (g_Options.fVerbosePosting)
+ {
+ PostMoveSearchReport(ctx);
+ PostMoveTestSuiteReport(ctx);
+ }
+ }
+ g_Options.fPondering = g_Options.fThinking = FALSE;
+}
+
+
+GAME_RESULT
+Ponder(POSITION *pos)
+/**
+
+Routine description:
+
+ Prepare to ponder.
+
+Parameters:
+
+ POSITION *pos
+
+Return value:
+
+ FLAG
+
+**/
+{
+ static SEARCHER_THREAD_CONTEXT ctx;
+ GAME_RESULT ret;
+
+ InitializeSearcherContext(pos, &ctx);
+ g_Options.fPondering = TRUE;
+ g_Options.fThinking = FALSE;
+ g_Options.fSuccessfulPonder = FALSE;
+ ret.eResult = RESULT_IN_PROGRESS;
+ ret.szDescription[0] = '\0';
+
+ //
+ // When do we not want to ponder
+ //
+ if ((g_Options.ePlayMode == FORCE_MODE) || (g_Options.uMyClock < 10))
+ {
+ g_Options.fPondering = FALSE;
+ return ret;
+ }
+
+ //
+ // What should we ponder?
+ //
+ g_Options.mvPonder = GetPonderMove(pos);
+ if (g_Options.mvPonder.uMove == 0)
+ {
+ g_Options.fPondering = FALSE;
+ return ret;
+ }
+ ASSERT(SanityCheckMove(pos, g_Options.mvPonder));
+
+ //
+ // Prepare to ponder by doing some maintenance on the dynamic move
+ // ordering scheme counters, changing the dirty tag in the hash
+ // code, and clearing the root nodes-per-move hash.
+ //
+ MaintainDynamicMoveOrdering();
+ DirtyHashTable();
+
+ //
+ // Make the move ponder move.
+ //
+ if (FALSE == MakeMove(&ctx, g_Options.mvPonder))
+ {
+ ASSERT(FALSE);
+ g_Options.fPondering = FALSE;
+ return ret;
+ }
+
+ //
+ // TODO: probe the book
+ //
+
+ _SetMoveTimerForPonder();
+
+ //
+ // TODO: Any preEval?
+ //
+
+ //
+ // TODO: Set draw value
+ //
+
+ MakeStatusLine();
+#if (PERF_COUNTERS && MP)
+ ClearHelperThreadIdleness();
+#endif
+ ASSERT(ctx.uPly == 1);
+ ret = Iterate(&ctx);
+ ASSERT(ctx.uPly == 1);
+ if (ret.eResult == RESULT_IN_PROGRESS) {
+ MakeTheMove(&ctx);
+ return _DetectPostMoveTerminalStates(&ctx);
+ } else {
+ return ret;
+ }
+}
+
+
+GAME_RESULT Think(POSITION *pos)
+/**
+
+Routine description:
+
+ Prepare to think.
+
+Parameters:
+
+ POSITION *pos
+
+Return value:
+
+ FLAG
+
+**/
+{
+ static SEARCHER_THREAD_CONTEXT ctx;
+ MOVE mvBook;
+ CHAR *p;
+
+ InitializeSearcherContext(pos, &ctx);
+ g_MoveTimer.bvFlags = 0;
+ g_Options.fPondering = FALSE;
+ g_Options.fThinking = TRUE;
+ g_Options.fSuccessfulPonder = FALSE;
+
+ //
+ // Prepare to think by doing some maintenance on the dynamic move
+ // ordering scheme counters, changing the dirty tag in the hash
+ // code, and clearing the root nodes-per-move hash.
+ //
+ if (NULL != (p = PositionToFen(&(ctx.sPosition))))
+ {
+ Trace("The root position is: %s\n", p);
+ SystemFreeMemory(p);
+ }
+ MaintainDynamicMoveOrdering();
+ DirtyHashTable();
+
+ //
+ // Check the opening book, maybe it has a move for us.
+ //
+ if ((g_uBookProbeFailures < 3) && (!WeAreRunningASuite()))
+ {
+ mvBook = BookMove(pos, BOOKMOVE_SELECT_MOVE);
+ if (mvBook.uMove == 0)
+ {
+ g_uBookProbeFailures++;
+ }
+ else
+ {
+ g_uBookProbeFailures = 0;
+ ASSERT(SanityCheckMove(pos, mvBook));
+ ctx.mvRootMove = mvBook;
+ MakeTheMove(&ctx);
+ return _DetectPostMoveTerminalStates(&ctx);
+ }
+ }
+
+ //
+ // TODO: Any preEval?
+ //
+
+ //
+ // Set time limit for move
+ //
+ SetMoveTimerForSearch(FALSE, pos->uToMove);
+
+ //
+ // TODO: Set draw value
+ //
+#if (PERF_COUNTERS && MP)
+ ClearHelperThreadIdleness();
+#endif
+ GAME_RESULT ret = Iterate(&ctx);
+ if (ret.eResult == RESULT_IN_PROGRESS) {
+ MakeTheMove(&ctx);
+ return _DetectPostMoveTerminalStates(&ctx);
+ } else {
+ return ret;
+ }
+}
diff --git a/src/save/util.c b/src/save/util.c
new file mode 100755
index 0000000..90431e2
--- /dev/null
+++ b/src/save/util.c
@@ -0,0 +1,1254 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ util.c
+
+Abstract:
+
+ General purpose utility code to support the engine.
+
+Author:
+
+ Scott Gasch ([email protected]) 8 Apr 2004
+
+Revision History:
+
+ $Id: util.c 345 2007-12-02 22:56:42Z scott $
+
+**/
+
+#include "chess.h"
+
+extern ULONG g_uIterateDepth;
+extern ULONG g_uFullWidthDepth;
+
+#define STATE_UNKNOWN (0)
+#define STATE_HEADER (1)
+#define STATE_MOVELIST (2)
+
+CHAR *
+ReadNextGameFromPgnFile(FILE *pf)
+/**
+
+Routine description:
+
+ Reads the next game in a PGN file and returns a pointer to it.
+
+Parameters:
+
+ FILE *pf : open file pointer
+
+Return value:
+
+ CHAR * : NULL on error, else caller must free via SystemFreeMemory.
+
+**/
+{
+ CHAR buf[MEDIUM_STRING_LEN_CHAR];
+ CHAR *p;
+ long lStartOfGame = -1;
+ long lEndOfGame = -1;
+ long lBefore;
+ ULONG uBytes;
+ ULONG uState = STATE_UNKNOWN;
+
+ while(1)
+ {
+ lBefore = ftell(pf);
+ if (fgets(buf, ARRAY_LENGTH(buf), pf) <= 0)
+ {
+ //Trace("fgets failed, errno=%u.\n", errno);
+ break;
+ }
+
+ //
+ // Skip leading whitespace on this line...
+ //
+ p = buf;
+ while(*p && isspace(*p)) p++;
+
+ if (*p == '\0')
+ {
+ //
+ // We just read a blank line
+ //
+ switch(uState)
+ {
+ case STATE_UNKNOWN:
+ break;
+
+ case STATE_HEADER:
+ uState = STATE_MOVELIST;
+ break;
+
+ case STATE_MOVELIST:
+ lEndOfGame = lBefore;
+ uBytes = lEndOfGame - lStartOfGame;
+ if (uBytes <= 0)
+ {
+ return(NULL);
+ }
+
+ p = SystemAllocateMemory(uBytes + 1);
+ ASSERT(p);
+ fseek(pf, lStartOfGame, SEEK_SET);
+ if (1 != fread(p, uBytes, 1, pf))
+ {
+ SystemFreeMemory(p);
+ return(NULL);
+ }
+ p[uBytes] = '\0';
+ return(p);
+ }
+ }
+ else
+ {
+ //
+ // We saw a non-blank line
+ //
+ switch(uState)
+ {
+ case STATE_HEADER:
+ case STATE_MOVELIST:
+ break;
+
+ case STATE_UNKNOWN:
+ if (*p == '[')
+ {
+ uState = STATE_HEADER;
+ lStartOfGame = lBefore;
+ }
+ break;
+ }
+ }
+ }
+ return(NULL);
+}
+
+
+COMMAND(LearnPsqtFromPgn)
+/**
+
+Routine description:
+
+Parameters:
+
+ CHAR *szFilename,
+
+Return value:
+
+ FLAG
+
+**/
+{
+ CHAR *szFilename;
+ ULONG uPSQT[12][128];
+ CHAR *pPGN;
+ FILE *pf = NULL;
+ DLIST_ENTRY *p;
+ GAME_MOVE *q;
+ ULONG x, y, z;
+ double d;
+ struct stat s;
+#ifdef DEBUG
+ ULONG uHeap;
+#endif
+
+ if (argc < 2)
+ {
+ Trace("Error (missing filename)\n");
+ return;
+ }
+ szFilename = argv[1];
+
+ if (FALSE == SystemDoesFileExist(szFilename))
+ {
+ Trace("LearnPsqtFromPgn: file \"%s\" doesn't exist.\n",
+ szFilename);
+ return;
+ }
+
+ if (0 != stat(szFilename, &s))
+ {
+ Trace("Stat failed.\n");
+ return;
+ }
+
+ pf = fopen(szFilename, "rb");
+ if (NULL == pf)
+ {
+ Trace("LearnPsqtFromPgn: error reading file \"%s\".\n",
+ szFilename);
+ return;
+ }
+
+ memset(uPSQT, 0, sizeof(uPSQT));
+#ifdef DEBUG
+ ResetGameList();
+ uHeap = GetHeapMemoryUsage();
+#endif
+ while((pPGN = ReadNextGameFromPgnFile(pf)) != NULL)
+ {
+ d = (double)ftell(pf);
+ d /= (double)s.st_size;
+ d *= 100.0;
+ printf("(%5.2f%% done)\r", d);
+
+ if (TRUE == LoadPgn(pPGN))
+ {
+ p = g_GameData.sMoveList.pFlink;
+ while(p != &(g_GameData.sMoveList))
+ {
+ q = CONTAINING_STRUCT(p, GAME_MOVE, links);
+ if ((q->uNumber > 10) &&
+ (q->uNumber < 50) &&
+ (!q->mv.pCaptured))
+ {
+ uPSQT[q->mv.pMoved - 2][q->mv.cTo] += 1;
+ }
+ p = p->pFlink;
+ }
+ }
+ SystemFreeMemory(pPGN);
+#ifdef DEBUG
+ ResetGameList();
+ ASSERT(uHeap == GetHeapMemoryUsage());
+#endif
+ }
+ fclose(pf);
+
+ z = 0;
+ for (x = 0; x < 12; x++)
+ {
+ for (y = 0; y < 128; y++)
+ {
+ if (uPSQT[x][y] > z)
+ {
+ z = uPSQT[x][y];
+ }
+ }
+ }
+
+ Trace("ULONG g_PSQT[12][128] = {\n");
+ for (x = 0; x < 12; x++)
+ {
+ Trace("// Piece 0x%x (%s)\n", x + 2, PieceAbbrev((PIECE)(x + 2)));
+ Trace("{\n");
+
+ for (y = 0; y < 128; y++)
+ {
+ if (y % 16 == 0) Trace("\n");
+ d = (double)uPSQT[x][y];
+ d /= (double)z;
+ d *= (double)1000.0;
+ Trace("%4u,", (ULONG)d);
+ }
+ Trace("},\n");
+ }
+ Trace("};\n");
+}
+
+
+COMMAND(GeneratePositionAndBestMoveSuite)
+/**
+
+Routine description:
+
+Parameters:
+
+ CHAR *szFilename,
+
+Return value:
+
+ FLAG
+
+**/
+{
+ CHAR *szFilename;
+ CHAR *pPGN;
+ FILE *pf = NULL;
+ DLIST_ENTRY *p;
+ GAME_MOVE *q;
+ SEARCHER_THREAD_CONTEXT *ctx = NULL;
+ FLAG fPost = g_Options.fShouldPost;
+ struct stat s;
+ double d;
+ POSITION board;
+
+ if (argc < 2)
+ {
+ Trace("Error (missing filename)\n");
+ goto end;
+ }
+ szFilename = argv[1];
+
+ if (FALSE == SystemDoesFileExist(szFilename))
+ {
+ Trace("LearnPsqtFromPgn: file \"%s\" doesn't exist.\n",
+ szFilename);
+ goto end;
+ }
+
+ if (0 != stat(szFilename, &s))
+ {
+ Trace("Stat failed.\n");
+ goto end;
+ }
+
+ pf = fopen(szFilename, "rb");
+ if (NULL == pf)
+ {
+ Trace("LearnPsqtFromPgn: error reading file \"%s\".\n",
+ szFilename);
+ goto end;
+ }
+
+ ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
+ if (NULL == ctx)
+ {
+ Trace("Out of memory.\n");
+ goto end;
+ }
+
+ g_Options.fShouldPost = FALSE;
+ while((pPGN = ReadNextGameFromPgnFile(pf)) != NULL)
+ {
+ d = (double)ftell(pf);
+ d /= (double)s.st_size;
+ d *= 100.0;
+ printf("(%5.2f%% done)\r", d);
+
+ if (TRUE == LoadPgn(pPGN))
+ {
+ p = g_GameData.sMoveList.pFlink;
+ while(p != &(g_GameData.sMoveList))
+ {
+ q = CONTAINING_STRUCT(p, GAME_MOVE, links);
+ if ((q->uNumber > 20) && (q->uNumber < 60))
+ {
+ if (FenToPosition(&board, q->szUndoPositionFen))
+ {
+ InitializeSearcherContext(&board, ctx);
+ g_MoveTimer.bvFlags = 0;
+ g_Options.fPondering = FALSE;
+ g_Options.fThinking = TRUE;
+ g_Options.fSuccessfulPonder = FALSE;
+
+ MaintainDynamicMoveOrdering();
+ DirtyHashTable();
+
+ g_MoveTimer.uNodeCheckMask = 0x1000 - 1;
+ g_MoveTimer.dStartTime = SystemTimeStamp();
+ g_MoveTimer.bvFlags = 0;
+ g_MoveTimer.dSoftTimeLimit =
+ g_MoveTimer.dStartTime + 3.0;
+ g_MoveTimer.dHardTimeLimit =
+ g_MoveTimer.dStartTime + 3.0;
+ g_Options.uMaxDepth = MAX_DEPTH_PER_SEARCH - 1;
+
+ //
+ // TODO: Set draw value
+ //
+#if (PERF_COUNTERS && MP)
+ ClearHelperThreadIdleness();
+#endif
+ GAME_RESULT result = Iterate(ctx);
+ if (result.eResult == RESULT_IN_PROGRESS) {
+ ASSERT(SanityCheckMove(&board,
+ ctx->sPlyInfo[0].PV[0]));
+ Trace("setboard %s\n", q->szUndoPositionFen);
+ Trace("gmmove %s\n", q->szMoveInSan);
+ Trace("solution %s\n",
+ MoveToSan(ctx->sPlyInfo[0].PV[0], &board));
+ }
+ }
+ }
+ p = p->pFlink;
+ }
+ }
+ SystemFreeMemory(pPGN);
+ }
+
+ end:
+ if (NULL != pf)
+ {
+ fclose(pf);
+ }
+
+ if (NULL != ctx)
+ {
+ SystemFreeMemory(ctx);
+ }
+
+ g_Options.fShouldPost = fPost;
+}
+
+
+char *
+FindChunk(char *sz, ULONG uTargetChunk)
+/**
+
+Routine description:
+
+ A support routine used by FenToPosition. Used to parse apart a
+ string and return the Nth chunk of text (delimited by whitespace)
+
+Parameters:
+
+ char *sz,
+ ULONG uTargetChunk
+
+Return value:
+
+ char *
+
+**/
+{
+ char *p = sz;
+ ULONG u = 0;
+
+ if (0 == uTargetChunk) return(p);
+
+ do
+ {
+ //
+ // Skip whitespace between chunks
+ //
+ while(isspace(*p) && *p) p++;
+ if (!*p) return(NULL);
+
+ u++;
+ if (u == uTargetChunk) return(p);
+
+ //
+ // Skip chunks
+ //
+ while(!isspace(*p) && &p) p++;
+ if (!*p) return(NULL);
+ }
+ while(1);
+
+#ifdef DEBUG
+ UtilPanic(SHOULD_NOT_GET_HERE,
+ NULL, NULL, NULL, NULL,
+ __FILE__, __LINE__);
+#endif
+ return(NULL);
+}
+
+
+
+CHAR *
+ScoreToString(SCORE iScore)
+/**
+
+Routine description:
+
+ Format a chess score as a string that looks like:
+
+ +0.100
+ -4.951
+ +MATE20
+ -MATE4
+ +0.000
+
+ etc...
+
+ Note: NOT thread safe.
+
+Parameters:
+
+ SCORE iScore
+
+Return value:
+
+ CHAR *
+
+**/
+{
+ static char szBuf[10];
+ ULONG uDist;
+
+ if (abs(iScore) < +NMATE)
+ {
+ snprintf(szBuf, ARRAY_LENGTH(szBuf),
+ "%c%u.%02u",
+ (iScore < 0) ? '-' : '+',
+ abs(iScore / 100),
+ abs(iScore % 100));
+ return(szBuf);
+ }
+
+ if (iScore > 0)
+ {
+ uDist = +INFINITY - iScore;
+ uDist /= 2;
+ if (uDist)
+ {
+ snprintf(szBuf, ARRAY_LENGTH(szBuf), "+MATE%u", uDist);
+ }
+ else
+ {
+ snprintf(szBuf, ARRAY_LENGTH(szBuf), "+MATE");
+ }
+ }
+ else
+ {
+ uDist = +INFINITY + iScore;
+ uDist /= 2;
+ if (uDist)
+ {
+ snprintf(szBuf, ARRAY_LENGTH(szBuf), "-MATE%u", uDist);
+ }
+ else
+ {
+ snprintf(szBuf, ARRAY_LENGTH(szBuf), "-MATE");
+ }
+ }
+ return(szBuf);
+}
+
+
+
+CHAR *
+CoorToString(COOR c)
+/**
+
+Routine description:
+
+ Take a chessboard coordinate and convert it into a string. Note:
+ NOT thread safe.
+
+Parameters:
+
+ COOR c
+
+Return value:
+
+ CHAR *
+
+**/
+{
+ static char buf[3];
+
+ if (IS_ON_BOARD(c))
+ {
+ buf[0] = 'a' + FILE(c);
+ buf[1] = '0' + RANK(c);
+ buf[2] = '\0';
+ }
+ else
+ {
+ buf[0] = '-';
+ buf[1] = '\0';
+ }
+ return(buf);
+}
+
+
+CHAR *
+ColorToString(ULONG u)
+/**
+
+Routine description:
+
+ Convert a color into a string ("WHITE" or "BLACK"). Callers
+ should not mess with the contents of the buffer returned!
+
+Parameters:
+
+ ULONG u
+
+Return value:
+
+ char
+
+**/
+{
+ static CHAR *szColor[2] =
+ {
+ "BLACK",
+ "WHITE"
+ };
+ ASSERT(IS_VALID_COLOR(u));
+ return(szColor[u]);
+}
+
+
+CHAR *
+TimeToString(double d)
+/**
+
+Routine description:
+
+ Convert a time value into a string. e.g.
+
+ 00:00:01.021 // seconds with ms
+ 00:15:21.998 // minutes+seconds
+ 01:59:23.232 // hours+minutes+sec
+ 27:08:11:103 // we don't do days
+
+ Note: NOT thread safe. The caller should not mess with the
+ buffer returned.
+
+Parameters:
+
+ double d
+
+Return value:
+
+ CHAR *
+
+**/
+{
+ ULONG uTotalSecs = (ULONG)d;
+ double dFract = d - (double)uTotalSecs;
+ ULONG uHours;
+ ULONG uMinutes;
+ ULONG uFract;
+ static char buf[13];
+
+ dFract *= 1000;
+ uFract = (int)dFract;
+ uHours = uTotalSecs / 60 / 60;
+ uTotalSecs -= uHours * 60 * 60;
+ uMinutes = uTotalSecs / 60;
+ uTotalSecs -= uMinutes * 60;
+ ASSERT(uTotalSecs < 60);
+
+ if (uHours != 0)
+ {
+ snprintf(buf, ARRAY_LENGTH(buf),
+ "%2u:%02u:%02u.%03u",
+ uHours, uMinutes, uTotalSecs, uFract);
+ }
+ else
+ {
+ snprintf(buf, ARRAY_LENGTH(buf),
+ "%02u:%02u.%03u",
+ uMinutes, uTotalSecs, uFract);
+ }
+ return(buf);
+}
+
+
+FLAG
+BufferIsZeroed(BYTE *p, ULONG u)
+/**
+
+Routine description:
+
+ Verify that a buffer is zeroed out.
+
+Parameters:
+
+ BYTE *p : buffer start
+ ULONG u : buffer length
+
+Return value:
+
+ FLAG
+
+**/
+{
+ while(u)
+ {
+ if (*p != (BYTE)0)
+ {
+ return(FALSE);
+ }
+ p++;
+ u--;
+ }
+ return(TRUE);
+}
+
+
+void CDECL
+Trace(CHAR *szMessage, ...)
+/**
+
+Routine description:
+
+ Trace a logging message on stdout and to the logfile
+
+Parameters:
+
+ CHAR *szMessage,
+ ...
+
+Return value:
+
+ void
+
+**/
+{
+ va_list ap; // Variable argument list
+ CHAR buf[MEDIUM_STRING_LEN_CHAR];
+
+ memset(buf, 0, sizeof(buf));
+
+ //
+ // Populate buffer
+ //
+ va_start(ap, szMessage);
+ COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
+ va_end(ap);
+
+ //
+ // Send to logfile
+ //
+ if (NULL != g_pfLogfile)
+ {
+ fprintf(g_pfLogfile, buf);
+ }
+
+ //
+ // Send to stdout
+ //
+ fprintf(stdout, buf);
+ fflush(stdout);
+}
+
+
+void CDECL
+Log(CHAR *szMessage, ...)
+/**
+
+Routine description:
+
+ Trace a logging message to the logfile only
+
+Parameters:
+
+ CHAR *szMessage,
+ ...
+
+Return value:
+
+ void
+
+**/
+{
+ va_list ap; // Variable argument list
+ CHAR buf[MEDIUM_STRING_LEN_CHAR];
+ memset(buf, 0, sizeof(buf));
+
+ //
+ // Populate buffer
+ //
+ va_start(ap, szMessage);
+ COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
+ va_end(ap);
+
+ //
+ // Send to logfile
+ //
+ if (NULL != g_pfLogfile)
+ {
+ fprintf(g_pfLogfile, buf);
+ }
+}
+
+
+void CDECL
+Bug(CHAR *szMessage, ...)
+/**
+
+Routine description:
+
+ Trace an error message to stderr and the logfile
+
+Parameters:
+
+ CHAR *szMessage,
+ ...
+
+Return value:
+
+ void
+
+**/
+{
+ va_list ap; // Variable argument list
+ CHAR buf[MEDIUM_STRING_LEN_CHAR];
+
+ memset(buf, 0, sizeof(buf));
+
+ //
+ // Populate buffer
+ //
+ va_start(ap, szMessage);
+ COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
+ va_end(ap);
+
+ //
+ // Send it to logfile
+ //
+ if (NULL != g_pfLogfile)
+ {
+ fprintf(g_pfLogfile, buf);
+ fflush(g_pfLogfile);
+ }
+
+ //
+ // Send it to stderr
+ //
+ fprintf(stderr, buf);
+ fflush(stderr);
+}
+
+
+#ifdef DEBUG
+void
+_assert(CHAR *szFile, ULONG uLine)
+/**
+
+Routine description:
+
+ An assertion handler
+
+Parameters:
+
+ CHAR *szFile,
+ UINT uLine
+
+Return value:
+
+ void
+
+**/
+{
+ Bug("Assertion failure in %s, line %u.\n", szFile, uLine);
+ BREAKPOINT;
+}
+#endif
+
+
+ULONG
+AcquireSpinLock(volatile ULONG *pSpinlock)
+/**
+
+Routine description:
+
+ Atomically acquire a lock or spin trying.
+
+Parameters:
+
+ ULONG *pSpinlock : a pointer to the lock
+
+Return value:
+
+ ULONG : the number of times we had to spin
+
+**/
+{
+ ULONG uLoops = 0;
+ while(0 != LockCompareExchange(pSpinlock, 1, 0))
+ {
+ uLoops++;
+ }
+ ASSERT(*pSpinlock == 1);
+ return(uLoops);
+}
+
+FLAG
+TryAcquireSpinLock(volatile ULONG *pSpinlock)
+{
+ return(0 != LockCompareExchange(pSpinlock, 1, 0));
+}
+
+void
+ReleaseSpinLock(volatile ULONG *pSpinlock)
+/**
+
+Routine description:
+
+ Release a lock so someone else can acquire it.
+
+Parameters:
+
+ ULONG *pSpinlock : a pointer to the lock
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG u;
+ ASSERT(*pSpinlock == 1);
+ u = LockCompareExchange(pSpinlock, 0, 1);
+ ASSERT(u == 1);
+}
+
+
+FLAG
+BackupFile(CHAR *szFile)
+/**
+
+Routine description:
+
+ Backup a file to file.000. If file.000 already exists, back it up
+ to file.001 etc...
+
+ Note: this function is recursive and can require quite a lot of
+ stack space. Also it is full of race conditions and should not be
+ used when some other code may be accessing the filesystem at the
+ same time.
+
+Parameters:
+
+ CHAR *szFile : the file to backup
+
+Return value:
+
+ FLAG
+
+**/
+{
+ ULONG u;
+ CHAR buf[SMALL_STRING_LEN_CHAR];
+ CHAR *p;
+
+ if (TRUE == SystemDoesFileExist(szFile))
+ {
+ if ((strlen(szFile) > 3) &&
+ (isdigit(szFile[0])) &&
+ (isdigit(szFile[1])) &&
+ (isdigit(szFile[2])))
+ {
+ u = (szFile[0] - '0') * 100;
+ u += (szFile[1] - '0') * 10;
+ u += szFile[2] - '0' + 1;
+ p = &(szFile[3]);
+ }
+ else
+ {
+ u = 0;
+ p = szFile;
+ }
+ snprintf(buf, ARRAY_LENGTH(buf), "%03u%s", u, p);
+ if (TRUE == SystemDoesFileExist(buf))
+ {
+ BackupFile(buf);
+ }
+ return(SystemCopyFile(szFile, buf) && SystemDeleteFile(szFile));
+ }
+ return(FALSE);
+}
+
+
+BYTE
+Checksum(BYTE *p, ULONG uSize)
+/**
+
+Routine description:
+
+ Compute the checksum of a buffer.
+
+Parameters:
+
+ BYTE *p,
+ ULONG uSize
+
+Return value:
+
+ BYTE
+
+**/
+{
+ BYTE b = 0;
+ while(uSize)
+ {
+ b ^= *p;
+ p++;
+ uSize--;
+ }
+ return(b);
+}
+
+void
+FinishPVTailFromHash(SEARCHER_THREAD_CONTEXT *ctx,
+ CHAR *buf,
+ ULONG uLenRemain)
+{
+ MOVE PV[MAX_PLY_PER_SEARCH];
+ MOVE mv;
+ ULONG uPly = ctx->uPly;
+ ULONG uLen;
+#ifdef DEBUG
+ POSITION board;
+ memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
+#endif
+
+ if (NULL == g_pHashTable) return;
+ do
+ {
+ mv = GetPonderMove(&ctx->sPosition);
+ if (mv.uMove == 0) break;
+ PV[ctx->uPly] = mv;
+
+ uLen = (ULONG)strlen(MoveToSan(mv, &ctx->sPosition)) + 1;
+ ASSERT(uLen <= 11);
+ if (uLenRemain <= uLen) break;
+ strcat(buf, MoveToSan(PV[ctx->uPly], &ctx->sPosition));
+ strcat(buf, " ");
+ uLenRemain -= uLen;
+
+ if (FALSE == MakeMove(ctx, mv)) break;
+ }
+ while(1);
+
+ //
+ // Unmake the moves
+ //
+ while(ctx->uPly > uPly)
+ {
+ UnmakeMove(ctx, PV[ctx->uPly - 1]);
+ }
+ ASSERT(ctx->uPly == uPly);
+ ASSERT(PositionsAreEquivalent(&board, &ctx->sPosition));
+}
+
+
+
+char *
+WalkPV(SEARCHER_THREAD_CONTEXT *ctx)
+/**
+
+Routine description:
+
+ Return a string buffer representing the principle variation.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx
+
+Return value:
+
+ CHAR *
+
+**/
+{
+ static CHAR buf[SMALL_STRING_LEN_CHAR];
+ ULONG u = ctx->uPly;
+ ULONG v = u;
+ MOVE mv;
+#ifdef DEBUG
+ POSITION board;
+ memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
+#endif
+
+ buf[0] = '\0';
+ while((mv.uMove = ctx->sPlyInfo[v].PV[u].uMove) != 0)
+ {
+ if (mv.uMove == HASHMOVE.uMove)
+ {
+ strncat(buf, "<TT> ", ARRAY_LENGTH(buf) - strlen(buf) - 1);
+ FinishPVTailFromHash(ctx, buf, ARRAY_LENGTH(buf) - strlen(buf));
+ ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
+ break;
+ }
+ else if (mv.uMove == RECOGNMOVE.uMove)
+ {
+ strncat(buf, "<REC>", ARRAY_LENGTH(buf) - strlen(buf) - 1);
+ ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
+ break;
+ }
+ else if (mv.uMove == DRAWMOVE.uMove)
+ {
+ strncat(buf, "<=>", ARRAY_LENGTH(buf) - strlen(buf) - 1);
+ ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
+ break;
+ }
+ else
+ {
+ strncat(buf, MoveToSan(mv, &ctx->sPosition),
+ ARRAY_LENGTH(buf) - strlen(buf));
+ strncat(buf, " ", ARRAY_LENGTH(buf) - strlen(buf) - 1);
+ }
+
+ if (FALSE == MakeMove(ctx, mv)) break;
+ u++;
+
+ if (strlen(buf) > (SMALL_STRING_LEN_CHAR - 10)) break;
+ }
+
+ //
+ // Unmake the moves
+ //
+ u--;
+ while(ctx->uPly > v)
+ {
+ UnmakeMove(ctx, ctx->sPlyInfo[v].PV[u]);
+ u--;
+ }
+ ASSERT(ctx->uPly == v);
+ ASSERT(PositionsAreEquivalent(&board, &ctx->sPosition));
+ return(buf);
+}
+
+
+void
+UtilPanic(ULONG uPanicCode,
+ POSITION *pos,
+ void *arg1, void *arg2, void *arg3,
+ char *szFile, ULONG uLine)
+{
+ Bug("Typhoon PANIC 0x%x (%p, %p, %p, %p)\n"
+ "Location: %s at line %u\n\n",
+ uPanicCode, pos, arg1, arg2, arg3, szFile, uLine);
+ Banner();
+ Bug("----------------------------------------------------------------\n");
+ switch(uPanicCode) {
+ case CANNOT_INITIALIZE_SPLIT:
+ case GOT_ILLEGAL_MOVE_WHILE_PONDERING:
+ case CANNOT_OFFICIALLY_MAKE_MOVE:
+ DumpPosition(pos);
+ DumpMove((ULONG)arg1);
+ break;
+ case INITIALIZATION_FAILURE:
+ Bug("%s\n", (char *)arg1);
+ break;
+ default:
+ break;
+ }
+ fflush(stdout);
+ fflush(g_pfLogfile);
+ BREAKPOINT;
+ exit(-1);
+}
+
+void
+UtilPrintPV(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta,
+ SCORE iScore,
+ MOVE mv)
+/**
+
+Routine description:
+
+ Print a PV out to stdout and the log.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE iAlpha,
+ SCORE iBeta,
+ SCORE iScore,
+ MOVE mv
+
+Return value:
+
+ void
+
+**/
+{
+ double dNow = SystemTimeStamp();
+
+ ASSERT(ctx->uThreadNumber == 0);
+ ASSERT(IS_VALID_SCORE(iAlpha));
+ ASSERT(IS_VALID_SCORE(iBeta));
+ ASSERT(iAlpha < iBeta);
+ ASSERT(IS_VALID_SCORE(iScore));
+
+ dNow -= g_MoveTimer.dStartTime;
+
+ //
+ // Set the last PV in the context if we have a root PV or a root
+ // fail high.
+ //
+ if ((iAlpha < iScore) && (iScore < iBeta))
+ {
+ strncpy(ctx->szLastPV, WalkPV(ctx), SMALL_STRING_LEN_CHAR);
+ }
+ else if (iScore > iBeta)
+ {
+ strncpy(ctx->szLastPV, MoveToSan(mv, &(ctx->sPosition)),
+ SMALL_STRING_LEN_CHAR);
+ }
+
+ if ((TRUE == g_Options.fThinking) && (TRUE == g_Options.fShouldPost))
+ {
+ //
+ // Maybe output the PV. Note: xboard gets confused by PV
+ // lines that don't match its requirements exactly; if we are
+ // running under xboard, match its expected format. Otherwise
+ // be more helpful / verbose.
+ //
+ if ((dNow > 0.35) || ((dNow > 0.15) && (g_Options.fVerbosePosting)))
+ {
+ if (TRUE == g_Options.fRunningUnderXboard)
+ {
+ if ((iAlpha < iScore) && (iScore < iBeta))
+ {
+ Trace("%2u %6d %5u %-12"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT" %s\n",
+ g_uIterateDepth,
+ iScore,
+ (ULONG)(dNow * 100),
+ ctx->sCounters.tree.u64TotalNodeCount,
+ ctx->szLastPV);
+ }
+ else if (iScore <= iAlpha)
+ {
+ Trace("%2u %6d %5u %-12"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT" FL --\n",
+ g_uIterateDepth,
+ iScore,
+ (ULONG)(dNow * 100),
+ ctx->sCounters.tree.u64TotalNodeCount);
+ }
+ else
+ {
+ ASSERT(iScore >= iBeta);
+ Trace("%2u %6d %5u %-12"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT" %s ++\n",
+ g_uIterateDepth,
+ iScore,
+ (ULONG)(dNow * 100),
+ ctx->sCounters.tree.u64TotalNodeCount,
+ ctx->szLastPV);
+ }
+ }
+ else // !running under xboard
+ {
+ if ((iAlpha < iScore) && (iScore < iBeta))
+ {
+ Trace("%2u %5s %-9s %-11"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT" %s\n",
+ g_uIterateDepth,
+ ScoreToString(iScore),
+ TimeToString(dNow),
+ ctx->sCounters.tree.u64TotalNodeCount,
+ ctx->szLastPV);
+ }
+ else if (iScore <= iAlpha)
+ {
+ Trace("%2u- %5s %-9s %-11"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT" FL --\n",
+ g_uIterateDepth,
+ ScoreToString(iScore),
+ TimeToString(dNow),
+ ctx->sCounters.tree.u64TotalNodeCount);
+ }
+ else
+ {
+ ASSERT(iScore >= iBeta);
+ Trace("%2u+ %5s %-9s %-11"
+ COMPILER_LONGLONG_UNSIGNED_FORMAT" %s ++\n",
+ g_uIterateDepth,
+ ScoreToString(iScore),
+ TimeToString(dNow),
+ ctx->sCounters.tree.u64TotalNodeCount,
+ ctx->szLastPV);
+ }
+ }
+ }
+ }
+}
diff --git a/src/save/vars.c b/src/save/vars.c
new file mode 100644
index 0000000..1db4c72
--- /dev/null
+++ b/src/save/vars.c
@@ -0,0 +1,483 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ vars.c
+
+Abstract:
+
+ This is code that implements variables in the engine. Some of
+ these variables are read only but others can be set by the engine
+ user to affect certain aspects of engine operation.
+
+Author:
+
+ Scott Gasch ([email protected]) 18 May 2004
+
+Revision History:
+
+ $Id: vars.c 345 2007-12-02 22:56:42Z scott $
+
+**/
+
+#include "chess.h"
+
+extern ULONG g_uNumInputEvents;
+
+typedef void(PUSERVARFUN)(void);
+
+//
+// Here's how we expose engine variables to the user.
+//
+typedef struct _USER_VARIABLE
+{
+ char *szName; // variable name
+ char *szType; // variable type:
+ // * - char *, strdup/free
+ // H - hash size
+ // B - boolean
+ // U - unsigned
+ // I - int
+ // M - move
+ // D - double
+ // S - string buffer
+ void *pValue; // pointer to value
+ PUSERVARFUN *pFunction; // funct to call when it changes
+} USER_VARIABLE;
+
+extern ULONG g_uBookProbeFailures;
+
+USER_VARIABLE g_UserVarList[] =
+{
+ { "AnnounceOpening",
+ "B",
+ (void *)&(g_Options.fShouldAnnounceOpening),
+ NULL },
+ { "BatchMode",
+ "b",
+ (void *)&(g_Options.fNoInputThread),
+ NULL },
+ { "BlackPlayer",
+ "*",
+ (void *)&(g_GameData.sHeader.sPlayer[BLACK].szName),
+ NULL },
+ { "BlackRating",
+ "U",
+ (void *)&(g_GameData.sHeader.sPlayer[BLACK].uRating),
+ NULL },
+ { "BlackDescription",
+ "*",
+ (void *)&(g_GameData.sHeader.sPlayer[BLACK].szDescription),
+ NULL },
+ { "BlackIsComputer",
+ "B",
+ (void *)&(g_GameData.sHeader.sPlayer[BLACK].fIsComputer),
+ NULL },
+ { "BookFileName",
+ "S",
+ (void *)&(g_Options.szBookName),
+ NULL },
+ { "BookProbeFailures",
+ "u",
+ (void *)&(g_uBookProbeFailures),
+ NULL },
+ { "ComputerTimeRemainingSec",
+ "U",
+ (void *)&(g_Options.uOpponentsClock),
+ NULL }, //&DoVerifyClocks },
+ { "EGTBPath",
+ "S",
+ (void *)&(g_Options.szEGTBPath),
+ InitializeEGTB },
+ { "FastScript",
+ "B",
+ (void *)&(g_Options.fFastScript),
+ NULL },
+ { "GameDescription",
+ "*",
+ (void *)&(g_GameData.sHeader.szGameDescription),
+ NULL },
+ { "GameLocation",
+ "*",
+ (void *)&(g_GameData.sHeader.szLocation),
+ NULL },
+ { "GameIsRated",
+ "B",
+ (void *)&(g_GameData.sHeader.fGameIsRated),
+ NULL },
+ { "GameResultComment",
+ "*",
+ (void *)&(g_GameData.sHeader.szResultComment),
+ NULL },
+ { "LastEval",
+ "I",
+ (void *)&(g_Options.iLastEvalScore),
+ NULL },
+ { "LogfileName",
+ "S",
+ (void *)&(g_Options.szLogfile),
+ NULL },
+ { "MoveToPonder",
+ "m",
+ (void *)&(g_Options.mvPonder),
+ NULL },
+ { "MovesPerTimePeriod",
+ "U",
+ (void *)&(g_Options.uMovesPerTimePeriod),
+ NULL },
+ { "OpponentTimeRemainingSec",
+ "U",
+ (void *)&(g_Options.uMyClock),
+ NULL }, //&DoVerifyClocks },
+ { "PendingInputEvents",
+ "u",
+ (void *)&(g_uNumInputEvents),
+ NULL },
+ { "PonderingNow",
+ "b",
+ (void *)&(g_Options.fPondering),
+ NULL },
+ { "PostLines",
+ "B",
+ (void *)&(g_Options.fShouldPost),
+ NULL },
+ { "Resign",
+ "B",
+ (void *)&(g_Options.fShouldResign),
+ NULL },
+ { "SearchDepthLimit",
+ "U",
+ (void *)&(g_Options.uMaxDepth),
+ NULL }, //&DoVerifySearchDepth },
+ { "SearchTimeLimit",
+ "U",
+ (void *)&(g_Options.uMyIncrement),
+ NULL }, //&DoVerifySearchTime },
+ { "SearchStartedTime",
+ "d",
+ (void *)&(g_MoveTimer.dStartTime),
+ NULL },
+ { "SearchSoftTimeLimit",
+ "d",
+ (void *)&(g_MoveTimer.dSoftTimeLimit),
+ NULL },
+ { "SearchHardTimeLimit",
+ "d",
+ (void *)&(g_MoveTimer.dHardTimeLimit),
+ NULL },
+ { "SearchNodesBetweenTimeCheck",
+ "u",
+ (void *)&(g_MoveTimer.uNodeCheckMask),
+ NULL },
+ { "StatusLine",
+ "B",
+ (void *)&(g_Options.fStatusLine),
+ NULL },
+ { "ThinkOnOpponentsTime",
+ "B",
+ (void *)&(g_Options.fShouldPonder),
+ NULL },
+ { "ThinkingNow",
+ "b",
+ (void *)&(g_Options.fThinking),
+ NULL },
+ { "TournamentMode",
+ "B",
+ (void *)&(g_fTournamentMode),
+ NULL },
+ { "VerbosePosting",
+ "B",
+ (void *)&(g_Options.fVerbosePosting),
+ NULL },
+ { "WhitePlayer",
+ "*",
+ (void *)&(g_GameData.sHeader.sPlayer[WHITE].szName),
+ NULL },
+ { "WhiteRating",
+ "U",
+ (void *)&(g_GameData.sHeader.sPlayer[WHITE].uRating),
+ NULL },
+ { "WhiteDescription",
+ "*",
+ (void *)&(g_GameData.sHeader.sPlayer[WHITE].szDescription),
+ NULL },
+ { "WhiteIsComputer",
+ "B",
+ (void *)&(g_GameData.sHeader.sPlayer[WHITE].fIsComputer),
+ NULL },
+ { "Xboard",
+ "B",
+ (void *)&(g_Options.fRunningUnderXboard),
+ NULL }
+};
+
+
+
+
+COMMAND(SetCommand)
+/**
+
+Routine description:
+
+ This function implements the 'set' engine command.
+
+ Usage:
+
+ set [variable name [value]]
+
+ With no arguments, set dumps a list of all variables and their
+ current values.
+
+ With one argument, set displays the specified variable's value.
+
+ With two arguments, set changes the value of the specified
+ variable to the given value.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x, y;
+ FLAG fFound;
+
+ if (argc == 1)
+ {
+ for (x = 0;
+ x < ARRAY_SIZE(g_UserVarList);
+ x++)
+ {
+ switch(toupper(g_UserVarList[x].szType[0]))
+ {
+ case 'H':
+ case 'U':
+ Trace("%-28s => %u\n",
+ g_UserVarList[x].szName,
+ *((unsigned int *)g_UserVarList[x].pValue));
+ break;
+ case 'I':
+ Trace("%-28s => %d\n",
+ g_UserVarList[x].szName,
+ *((int *)g_UserVarList[x].pValue));
+ break;
+ case 'S':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ (char *)g_UserVarList[x].pValue);
+ break;
+ case 'M':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ MoveToIcs(*((MOVE *)g_UserVarList[x].pValue)));
+ break;
+ case 'B':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ (*((FLAG *)g_UserVarList[x].pValue) == TRUE) ?
+ "TRUE" : "FALSE");
+ break;
+ case 'D':
+ Trace("%-28s => %f\n",
+ g_UserVarList[x].szName,
+ *((double *)g_UserVarList[x].pValue));
+ break;
+ case '*':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ *((char **)g_UserVarList[x].pValue));
+ break;
+ default:
+ Trace("%-28s => ???\n",
+ g_UserVarList[x].szName);
+ // ASSERT(FALSE);
+ break;
+ }
+ }
+ return;
+ }
+ else if (argc == 2)
+ {
+ fFound = FALSE;
+ for (x = 0;
+ x < ARRAY_SIZE(g_UserVarList);
+ x++)
+ {
+ if (!STRNCMPI(argv[1],
+ g_UserVarList[x].szName,
+ strlen(argv[1])))
+ {
+ fFound = TRUE;
+ switch(toupper(g_UserVarList[x].szType[0]))
+ {
+ case 'H':
+ case 'U':
+ Trace("%-28s => %u\n",
+ g_UserVarList[x].szName,
+ *((unsigned int *)g_UserVarList[x].pValue));
+ break;
+ case 'I':
+ Trace("%-28s => %d\n",
+ g_UserVarList[x].szName,
+ *((int *)g_UserVarList[x].pValue));
+ break;
+ case 'S':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ (char *)g_UserVarList[x].pValue);
+ break;
+ case 'M':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ MoveToIcs(*((MOVE *)g_UserVarList[x].pValue)));
+ break;
+ case 'B':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ (*((FLAG *)g_UserVarList[x].pValue) == TRUE) ?
+ "TRUE" : "FALSE");
+ break;
+ case 'D':
+ Trace("%-28s => %f\n",
+ g_UserVarList[x].szName,
+ *((double *)g_UserVarList[x].pValue));
+ break;
+ case '*':
+ Trace("%-28s => \"%s\"\n",
+ g_UserVarList[x].szName,
+ *((char **)g_UserVarList[x].pValue));
+ break;
+ default:
+ Trace("%-28s => ???\n",
+ g_UserVarList[x].szName);
+ // ASSERT(FALSE);
+ break;
+ }
+ }
+ }
+
+ if (FALSE == fFound)
+ {
+ Trace("Error (invalid variable): %s\n", argv[1]);
+ }
+ return;
+ }
+ else
+ {
+ ASSERT(argc > 2);
+
+ fFound = FALSE;
+
+ for (x = 0;
+ x < ARRAY_SIZE(g_UserVarList);
+ x++)
+ {
+ if (!STRNCMPI(argv[1],
+ g_UserVarList[x].szName,
+ strlen(argv[1])))
+ {
+ fFound = TRUE;
+
+ if (islower(g_UserVarList[x].szType[0]))
+ {
+ Trace("Error (variable is read only): %s\n",
+ argv[1]);
+ }
+
+ switch(g_UserVarList[x].szType[0])
+ {
+ case 'H':
+ y = atoi(argv[2]);
+ if ((y < 0) || (y & (y - 1)))
+ {
+ Trace("Error (invalid size): %d\n", y);
+ }
+ else
+ {
+ *((int *)g_UserVarList[x].pValue) = y;
+ }
+ break;
+
+ case '*':
+ if (NULL != *((char **)g_UserVarList[x].pValue))
+ {
+ SystemFreeMemory( *((char **)g_UserVarList[x].pValue ) );
+ }
+ *((char **)g_UserVarList[x].pValue) = STRDUP(argv[2]);
+ if (NULL == *((char **)g_UserVarList[x].pValue))
+ {
+ Trace("Error (out of memory)\n");
+ return;
+ }
+ break;
+
+ case 'S':
+ strncpy(((char *)g_UserVarList[x].pValue),
+ argv[2],
+ 127);
+ break;
+
+ case 'U':
+ y = atoi(argv[2]);
+ if (y < 0)
+ {
+ Trace("Error (invalid value): %d\n", y);
+ return;
+ }
+ *((unsigned *)g_UserVarList[x].pValue) = y;
+ break;
+
+ case 'I':
+ y = atoi(argv[2]);
+ *((int *)g_UserVarList[x].pValue) = y;
+ break;
+
+ case 'B':
+ if (toupper(*(argv[2])) == 'T')
+ {
+ *((FLAG *)g_UserVarList[x].pValue) = TRUE;
+ }
+ else if (toupper(*(argv[2])) == 'F')
+ {
+ *((FLAG *)g_UserVarList[x].pValue) = FALSE;
+ }
+ else
+ {
+ Trace("Error (invalid value, must be TRUE or "
+ "FALSE): %s\n", argv[2]);
+ }
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ if (NULL != g_UserVarList[x].pFunction)
+ {
+ (void)(g_UserVarList[x].pFunction)();
+ }
+ }
+ }
+
+ if (FALSE == fFound)
+ {
+ Trace("Error (invalid variable): %s\n", argv[1]);
+ }
+ }
+}
+
+//
+// TODO: unset?
+//