├── Demo ├── build.sh └── Demo.vcxproj ├── RebuildAndTest ├── build.sh └── RebuildAndTest.vcxproj ├── .gitignore ├── src ├── thc - the original umbrella.h ├── Portability.cpp ├── util.h ├── ChessEvaluation.h ├── PrivateChessDefs.cpp ├── ChessPositionRaw.h ├── Move.h ├── demo.cpp ├── ChessDefs.h ├── PrivateChessDefs.h ├── util.cpp ├── ChessRules.h ├── ChessPosition.h ├── test-framework.cpp ├── thc.h ├── thc-regen.h └── HashLookup.h ├── CMakeLists.txt ├── LICENSE ├── thc-chess-library.sln └── README.md /Demo/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | g++ ../src/demo.cpp ../src/thc.cpp 3 | 4 | -------------------------------------------------------------------------------- /RebuildAndTest/build.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | g++ ../src/test-framework.cpp ../src/thc.cpp ../src/util.cpp 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | -------------------------------------------------------------------------------- /src/thc - the original umbrella.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Umbrella header for all of general purpose Triple Happy Chess API 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2014, Bill Forster 6 | ****************************************************************************/ 7 | #ifndef THC_H 8 | #define THC_H 9 | 10 | #include "Portability.h" 11 | #include "Move.h" 12 | #include "ChessPosition.h" 13 | #include "ChessRules.h" 14 | #include "ChessEvaluation.h" 15 | 16 | #endif // THC_H 17 | 18 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | 3 | project(thc-chess) 4 | 5 | # specify the include directory for the outer project 6 | set(THC_CHESS_INCLUDE ${PROJECT_SOURCE_DIR}/src PARENT_SCOPE) 7 | # specify a release build 8 | add_definitions(-DKILL_DEBUG_COMPLETELY) 9 | # gather all sources 10 | file(GLOB THC_CHESS_SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/*.h) 11 | # don't compile twice the unified cpp objects, and remove testing from the final library 12 | list(REMOVE_ITEM THC_CHESS_SRCS ${PROJECT_SOURCE_DIR}/src/thc.cpp ${PROJECT_SOURCE_DIR}/src/thc-regen.cpp ${PROJECT_SOURCE_DIR}/src/test-framework.cpp) 13 | # define both a static and shared library 14 | add_library(thc_chess SHARED ${THC_CHESS_SRCS}) 15 | add_library(thc_chess_static STATIC ${THC_CHESS_SRCS}) 16 | -------------------------------------------------------------------------------- /src/Portability.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Portability.cpp Simple definitions to aid platform portability 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | #define _CRT_SECURE_NO_DEPRECATE 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // return 0 if case-insensitive match 14 | int strcmp_ignore( const char *s, const char *t ) 15 | { 16 | bool same=true; 17 | while( *s && *t && same ) 18 | { 19 | char c = *s++; 20 | char d = *t++; 21 | same = (c==d) || (isascii(c) && isascii(d) && toupper(c)==toupper(d)); 22 | } 23 | if( *s || *t ) 24 | same = false; 25 | return same?0:1; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Utility functions 4 | 5 | */ 6 | 7 | #ifndef UTIL_H_INCLUDED 8 | #define UTIL_H_INCLUDED 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace util 15 | { 16 | void putline(std::ostream &out,const std::string &line); 17 | std::string sprintf( const char *fmt, ... ); 18 | bool prefix( const std::string &s, const std::string prefix ); 19 | bool suffix( const std::string &s, const std::string suffix ); 20 | bool prefix_remove( std::string &s, const std::string prefix ); 21 | void ltrim( std::string &s ); 22 | void rtrim( std::string &s ); 23 | bool trim( std::string &s ); 24 | void tests(); 25 | void replace_all( std::string &s, const std::string from, const std::string to ); 26 | void replace_once( std::string &s, const std::string from, const std::string to ); 27 | void split( std::string &s, std::vector &fields ); 28 | std::string toupper( const std::string &s ); 29 | std::string tolower( const std::string &s ); 30 | } 31 | 32 | #endif // UTIL_H_INCLUDED 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 billforsternz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/ChessEvaluation.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * ChessEvaluation.h Chess classes - Simple chess AI, leaf scoring function for position 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | #ifndef CHESSEVALUATION_H 8 | #define CHESSEVALUATION_H 9 | #include "ChessRules.h" 10 | #include "Move.h" 11 | 12 | // TripleHappyChess 13 | namespace thc 14 | { 15 | 16 | class ChessEvaluation: public ChessRules 17 | { 18 | public: 19 | // Default constructor 20 | ChessEvaluation() : ChessRules() 21 | { 22 | } 23 | 24 | // Copy constructor 25 | ChessEvaluation( const ChessPosition& src ) : ChessRules( src ) 26 | { 27 | } 28 | 29 | // Assignment operator 30 | ChessEvaluation& operator=( const ChessPosition& src ) 31 | { 32 | *((ChessRules *)this) = src; 33 | return *this; 34 | } 35 | 36 | 37 | // Use leaf evaluator to generate a sorted move list 38 | void GenLegalMoveListSorted( MOVELIST *list ); 39 | void GenLegalMoveListSorted( std::vector &moves ); 40 | 41 | // Evaluate a position, leaf node (useful for playing programs) 42 | void EvaluateLeaf( int &material, int &positional ); 43 | 44 | // internal stuff 45 | protected: 46 | 47 | // Always some planning before calculating a move 48 | void Planning(); 49 | 50 | // Calculate material that side to play can win directly 51 | int Enprise(); 52 | int EnpriseWhite(); // fast white to move version 53 | int EnpriseBlack(); // fast black to move version 54 | 55 | // misc 56 | private: 57 | bool white_is_better; 58 | bool black_is_better; 59 | int planning_score_white_pieces; 60 | int planning_score_black_pieces; 61 | int planning_white_piece_pawn_percent; 62 | int planning_black_piece_pawn_percent; 63 | }; 64 | 65 | } //namespace thc 66 | 67 | #endif //CHESSEVALUATION_H 68 | -------------------------------------------------------------------------------- /thc-chess-library.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RebuildAndTest", "RebuildAndTest\RebuildAndTest.vcxproj", "{6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo.vcxproj", "{009345D5-4053-4476-B6BB-4AC86C491844}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Debug|x64.ActiveCfg = Debug|x64 19 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Debug|x64.Build.0 = Debug|x64 20 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Debug|x86.ActiveCfg = Debug|Win32 21 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Debug|x86.Build.0 = Debug|Win32 22 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Release|x64.ActiveCfg = Release|x64 23 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Release|x64.Build.0 = Release|x64 24 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Release|x86.ActiveCfg = Release|Win32 25 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D}.Release|x86.Build.0 = Release|Win32 26 | {009345D5-4053-4476-B6BB-4AC86C491844}.Debug|x64.ActiveCfg = Debug|x64 27 | {009345D5-4053-4476-B6BB-4AC86C491844}.Debug|x64.Build.0 = Debug|x64 28 | {009345D5-4053-4476-B6BB-4AC86C491844}.Debug|x86.ActiveCfg = Debug|Win32 29 | {009345D5-4053-4476-B6BB-4AC86C491844}.Debug|x86.Build.0 = Debug|Win32 30 | {009345D5-4053-4476-B6BB-4AC86C491844}.Release|x64.ActiveCfg = Release|x64 31 | {009345D5-4053-4476-B6BB-4AC86C491844}.Release|x64.Build.0 = Release|x64 32 | {009345D5-4053-4476-B6BB-4AC86C491844}.Release|x86.ActiveCfg = Release|Win32 33 | {009345D5-4053-4476-B6BB-4AC86C491844}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {047EA247-D686-48A4-B1FC-305C4EEE1A85} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /src/PrivateChessDefs.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * PrivateChessDefs.cpp Complement PrivateChessDefs.h by providing a shared instantation of 3 | * the automatically generated lookup tables. 4 | * Author: Bill Forster 5 | * License: MIT license. Full text of license is in associated file LICENSE 6 | * Copyright 2010-2020, Bill Forster 7 | ****************************************************************************/ 8 | #include "PrivateChessDefs.h" 9 | namespace thc 10 | { 11 | 12 | // All the lookup tables 13 | #define P 1 14 | #define B 2 15 | #define N 4 16 | #define R 8 17 | #define Q 16 18 | #define K 32 19 | 20 | // GeneratedLookupTables.h assumes a suitable type lte = lookup tables element 21 | // plus a bitmask convention for pieces using identifiers P,R,N,B,Q,K is 22 | // defined 23 | #include "GeneratedLookupTables.h" 24 | 25 | // A lookup table to convert our character piece convention to the lookup 26 | // convention. 27 | // Note for future reference. We could get a small performance boost, at the 28 | // cost of debuggability, by using this bitmask convention rather than our 29 | // ascii convention for pieces. The advantage would simply be that the 30 | // to_mask[] conversion would not then be required. In fact that used to be 31 | // how we did it, but we changed to the ascii convention which has many 32 | // advantages. Maybe a compromise where debug builds use the ascii convention 33 | // and release builds use a faster binary convention will be the ultimate 34 | // solution. We'll need a new api to convert to ascii convention for display 35 | // of board positions etc. if we do this. 36 | lte to_mask[] = 37 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x00-0x0f 38 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x10-0x1f 39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x20-0x2f 40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x30-0x3f 41 | 0,0,B,0,0,0,0,0,0,0,0,K,0,0,N,0, // 0x40-0x4f 'B'=0x42, 'K'=0x4b, 'N'=0x4e 42 | P,Q,R,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x50-0x5f 'P'=0x50, 'Q'=0x51, 'R'=0x52 43 | 0,0,B,0,0,0,0,0,0,0,0,K,0,0,N,0, // 0x60-0x6f 'b'=0x62, 'k'=0x6b, 'n'=0x6e 44 | P,Q,R,0,0,0,0,0,0,0,0,0,0,0,0,0}; // 0x70-0x7f 'p'=0x70, 'q'=0x71, 'r'=0x72 45 | #undef P 46 | #undef B 47 | #undef N 48 | #undef R 49 | #undef Q 50 | #undef K 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/ChessPositionRaw.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * ChessPositionRaw.h Chess classes - A raw chess position, could be used as a C style POD 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | #ifndef CHESSPOSITIONRAW_H 8 | #define CHESSPOSITIONRAW_H 9 | 10 | #include "ChessDefs.h" 11 | 12 | // TripleHappyChess 13 | namespace thc 14 | { 15 | 16 | // ChessPositionRaw - A complete representation of the position on the 17 | // board. Corresponds broadly to fields of Forsyth representation 18 | struct ChessPositionRaw 19 | { 20 | // Who to play 21 | bool white; 22 | 23 | // Pieces on board in readable form; Forsyth like but without compression, 24 | // eg "rnbqkbnr" 25 | // "pppppppp" 26 | // " " 27 | // " " 28 | // " " 29 | // " " 30 | // "PPPPPPPP" 31 | // "RNBQKBNR" 32 | // (represents starting position) 33 | char squares[64 +1]; // +1 allows a trailing '\0' 34 | // note indexed according to Square convention, a8=0 etc. 35 | 36 | // Half moves since pawn move or capture (for 50 move rule) 37 | // e.g. after 1.e4 it's 0 38 | int half_move_clock; 39 | 40 | // Full move count. Initially 1 and increments after black moves 41 | // e.g. after 1.e4 it's 1 42 | // e.g. after 1... d6 it's 2 43 | int full_move_count; 44 | 45 | // The following are deemed "details", and must be stored at the 46 | // end of the structure. Search for DETAIL for, ahem, details. 47 | // For performance reasons we want the details to be able to fit 48 | // into 32 bits. 49 | Square enpassant_target : 8; 50 | Square wking_square : 8; 51 | Square bking_square : 8; 52 | unsigned int wking : 1; // Castling still allowed flags 53 | unsigned int wqueen : 1; // unfortunately if the castling 54 | unsigned int bking : 1; // flags are declared as bool, 55 | unsigned int bqueen : 1; // with Visual C++ at least, 56 | // the details blow out and use 57 | // another 32 bits (??!!) 58 | // Note that for say white king side castling to be allowed in 59 | // the same sense as the Forsyth representation, not only 60 | // must wking be true, but the white king and king rook must 61 | // be present and in position, see the wking_allowed() etc. 62 | // methods in class ChessPosition, these are used for the ChessPosition 63 | // == operator. 64 | }; 65 | 66 | } //namespace thc 67 | 68 | #endif //CHESSPOSITIONRAW_H 69 | -------------------------------------------------------------------------------- /src/Move.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Move.h Chess classes - Move 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | #ifndef MOVE_H 8 | #define MOVE_H 9 | #include "ChessDefs.h" 10 | #include 11 | 12 | // TripleHappyChess 13 | namespace thc 14 | { 15 | class ChessRules; 16 | 17 | // Our representation of a chess move 18 | // 19 | // Note this is really an old school C struct, designed for speed 20 | // There is no constructor on purpose, we don't want unnecessary 21 | // construction of an array of Moves in a MOVELIST when we are running 22 | // the fast move generator. 23 | // The default assignment operator (bitwise copy) is ideal. 24 | // We define bitwise == and != operators 25 | // At one time we had 4 (count em, 4) move representations, but this 26 | // was always the primary and main representation. The others were 27 | // FMOVE (16 bit moves), NMOVE (natural string representation, eg 28 | // "Nf3") and TMOVE (terse string representation eg "g1f3"). When I 29 | // realised I could streamline an IMOVE (the old name for Move = 30 | // internal move) to only 32 bits, I realised I could live without 31 | // FMOVEs and that sparked a large simplification exercise. 32 | // 33 | class Move 34 | { 35 | public: 36 | // Move is a lightweight type, it is accommodated in only 32 bits 37 | Square src : 8; 38 | Square dst : 8; 39 | SPECIAL special : 8; 40 | int capture : 8; // ' ' (empty) if move not a capture 41 | // for some reason Visual C++ 2005 (at least) 42 | // blows sizeof(Move) out to 64 bits if 43 | // capture is defined as char instead of int 44 | 45 | bool operator ==(const Move &other) const 46 | { 47 | return( *((int32_t *)this) == *((int32_t *)(&other)) ); 48 | } 49 | 50 | bool operator !=(const Move &other) const 51 | { 52 | return( *((int32_t *)this) != *((int32_t *)(&other)) ); 53 | } 54 | 55 | // Use these sparingly when you need to specifically mark 56 | // a move as not yet set up (defined when we got rid of 57 | // 16 bit FMOVEs, we could always set and test 0 with those) 58 | void Invalid() { src=a8; dst=a8; } 59 | bool Valid() { return src!=a8 || dst!=a8; } 60 | 61 | // Read natural string move eg "Nf3" 62 | // return bool okay 63 | bool NaturalIn( ChessRules *cr, const char *natural_in ); 64 | 65 | // Read natural string move eg "Nf3" 66 | // return bool okay 67 | // Fast alternative for known good input 68 | bool NaturalInFast( ChessRules *cr, const char *natural_in ); 69 | 70 | // Read terse string move eg "g1f3" 71 | // return bool okay 72 | bool TerseIn( ChessRules *cr, const char *tmove ); 73 | 74 | // Convert to natural string 75 | // eg "Nf3" 76 | std::string NaturalOut( ChessRules *cr ); 77 | 78 | // Convert to terse string eg "e7e8q" 79 | std::string TerseOut(); 80 | }; 81 | 82 | // List of moves 83 | struct MOVELIST 84 | { 85 | int count; // number of moves 86 | Move moves[MAXMOVES]; 87 | }; 88 | 89 | } //namespace thc 90 | 91 | #endif //MOVE_H 92 | -------------------------------------------------------------------------------- /src/demo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Simple demo of THC Chess library 4 | 5 | This is a simple "hello world" exercise to get started with the THC chess library 6 | Just compile and link with thc.cpp. You only need thc.cpp and thc.h to use the 7 | THC library (see README.MD for more information) 8 | 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "thc.h" 15 | 16 | void display_position( thc::ChessRules &cr, const std::string &description ) 17 | { 18 | std::string fen = cr.ForsythPublish(); 19 | std::string s = cr.ToDebugStr(); 20 | printf( "%s\n", description.c_str() ); 21 | printf( "FEN (Forsyth Edwards Notation) = %s\n", fen.c_str() ); 22 | printf( "Position = %s\n", s.c_str() ); 23 | } 24 | 25 | int main() 26 | { 27 | // Example 1, Play a few good moves from the initial position 28 | thc::ChessRules cr; 29 | display_position( cr, "Initial position" ); 30 | thc::Move mv; 31 | mv.NaturalIn( &cr, "e4" ); 32 | cr.PlayMove(mv); 33 | mv.NaturalIn( &cr, "e5" ); 34 | cr.PlayMove(mv); 35 | mv.NaturalIn( &cr, "Nf3" ); 36 | cr.PlayMove(mv); 37 | mv.NaturalIn( &cr, "Nc6" ); 38 | cr.PlayMove(mv); 39 | mv.NaturalIn( &cr, "Bc4" ); 40 | cr.PlayMove(mv); 41 | mv.NaturalIn( &cr, "Bc5" ); 42 | cr.PlayMove(mv); 43 | display_position( cr, "Starting position of Italian opening, after 1.e4 e5 2.Nf3 Nc6 3.Bc4 Bc5" ); 44 | 45 | printf( "List of all legal moves in the current position\n" ); 46 | std::vector moves; 47 | std::vector check; 48 | std::vector mate; 49 | std::vector stalemate; 50 | cr.GenLegalMoveList( moves, check, mate, stalemate ); 51 | unsigned int len = moves.size(); 52 | for( unsigned int i=0; i 6 | ****************************************************************************/ 7 | #ifndef CHESSDEFS_H 8 | #define CHESSDEFS_H 9 | 10 | // Simple definition to aid platform portability (only remains of former Portability.h) 11 | int strcmp_ignore( const char *s, const char *t ); // return 0 if case-insensitive match 12 | 13 | // Fast test for is square white or black. Intend to move this to namespace thc when convenient... 14 | inline bool is_dark( int sq ) 15 | { 16 | bool dark = (!(sq&8) && (sq&1)) // eg (a8,b8,c8...h8) && (b8|d8|f8|h8) odd rank + odd file 17 | || ( (sq&8) && !(sq&1)); // eg (a7,b7,c7...h7) && (a7|c7|e7|g7) even rank + even file 18 | return dark; 19 | } 20 | 21 | // TripleHappyChess 22 | namespace thc 23 | { 24 | 25 | // Use the most natural square convention possible; Define Square to 26 | // correspond to a conventionally oriented chess diagram; Top left corner 27 | // (square a8) is 0, bottom right corner (square h1) is 63. 28 | // Note that instead of defining a special piece type, we use the built-in 29 | // char type, with 'N'=white knight, 'b'=black bishop etc. and ' '=an 30 | // empty square. 31 | enum Square 32 | { 33 | a8=0, 34 | b8, c8, d8, e8, f8, g8, h8, 35 | a7, b7, c7, d7, e7, f7, g7, h7, 36 | a6, b6, c6, d6, e6, f6, g6, h6, 37 | a5, b5, c5, d5, e5, f5, g5, h5, 38 | a4, b4, c4, d4, e4, f4, g4, h4, 39 | a3, b3, c3, d3, e3, f3, g3, h3, 40 | a2, b2, c2, d2, e2, f2, g2, h2, 41 | a1, b1, c1, d1, e1, f1, g1, h1, 42 | SQUARE_INVALID 43 | }; 44 | 45 | // thc::Square utilities 46 | inline char get_file( Square sq ) 47 | { return static_cast ( (static_cast(sq)&0x07) + 'a' ); } // eg c5->'c' 48 | inline char get_rank( Square sq ) 49 | { return static_cast ( '8' - ((static_cast(sq)>>3) & 0x07) ); } // eg c5->'5' 50 | inline Square make_square( char file, char rank ) 51 | { return static_cast ( ('8'-(rank))*8 + ((file)-'a') ); } // eg ('c','5') -> c5 52 | 53 | // Special (i.e. not ordinary) move types 54 | enum SPECIAL 55 | { 56 | NOT_SPECIAL = 0, 57 | SPECIAL_KING_MOVE, // special only because it changes wking_square, bking_square 58 | SPECIAL_WK_CASTLING, 59 | SPECIAL_BK_CASTLING, 60 | SPECIAL_WQ_CASTLING, 61 | SPECIAL_BQ_CASTLING, 62 | SPECIAL_PROMOTION_QUEEN, 63 | SPECIAL_PROMOTION_ROOK, 64 | SPECIAL_PROMOTION_BISHOP, 65 | SPECIAL_PROMOTION_KNIGHT, 66 | SPECIAL_WPAWN_2SQUARES, 67 | SPECIAL_BPAWN_2SQUARES, 68 | SPECIAL_WEN_PASSANT, 69 | SPECIAL_BEN_PASSANT, 70 | }; 71 | 72 | // Results of a test for legal position, note that they are powers 73 | // of 2, allowing a mask of reasons 74 | enum ILLEGAL_REASON 75 | { 76 | IR_NULL=0, IR_PAWN_POSITION=1, //pawns on 1st or 8th rank 77 | IR_NOT_ONE_KING_EACH=2, IR_CAN_TAKE_KING=4, 78 | IR_WHITE_TOO_MANY_PIECES=8, IR_WHITE_TOO_MANY_PAWNS=16, 79 | IR_BLACK_TOO_MANY_PIECES=32, IR_BLACK_TOO_MANY_PAWNS=64 80 | }; 81 | 82 | // Types of draw checked by IsDraw() 83 | enum DRAWTYPE 84 | { 85 | NOT_DRAW, 86 | DRAWTYPE_50MOVE, 87 | DRAWTYPE_INSUFFICIENT, // draw if superior side wants it 88 | // since inferior side has insufficient 89 | // mating material 90 | DRAWTYPE_INSUFFICIENT_AUTO, // don't wait to be asked, e.g. draw 91 | // immediately if bare kings 92 | DRAWTYPE_REPITITION, 93 | }; 94 | 95 | // Stalemate or checkmate game terminations 96 | enum TERMINAL 97 | { 98 | NOT_TERMINAL = 0, 99 | TERMINAL_WCHECKMATE = -1, // White is checkmated 100 | TERMINAL_WSTALEMATE = -2, // White is stalemated 101 | TERMINAL_BCHECKMATE = 1, // Black is checkmated 102 | TERMINAL_BSTALEMATE = 2 // Black is stalemated 103 | }; 104 | 105 | // Calculate an upper limit to the length of a list of moves 106 | #define MAXMOVES (27 + 2*13 + 2*14 + 2*8 + 8 + 8*4 + 3*27) 107 | //[Q 2*B 2*R 2*N K 8*P] + [3*Q] 108 | // ^ ^ 109 | //[calculated practical maximum ] + [margin] 110 | 111 | // We have developed an algorithm to compress any legal chess position, 112 | // including who to move, castling allowed flags and enpassant_target 113 | // into 24 bytes 114 | union CompressedPosition 115 | { 116 | unsigned char storage[24]; 117 | unsigned int ints[ 24 / sizeof(unsigned int) ]; 118 | }; 119 | 120 | // Types we'd really rather have in PrivateChessDefs.h, but not possible 121 | // at the moment, so we reluctantly expose them to users of the chess 122 | // classes. 123 | typedef unsigned char lte; // lte = lookup table element 124 | typedef int32_t DETAIL; 125 | 126 | } //namespace thc 127 | 128 | #endif // CHESSDEFS_H 129 | -------------------------------------------------------------------------------- /src/PrivateChessDefs.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * PrivateChessDefs.h Chess classes - Internal implementation details 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | #ifndef PRIVATE_CHESS_DEFS_H_INCLUDED 8 | #define PRIVATE_CHESS_DEFS_H_INCLUDED 9 | #include "ChessDefs.h" 10 | 11 | // TripleHappyChess 12 | namespace thc 13 | { 14 | 15 | // Check whether a piece is black, white or an empty square, should really make 16 | // these and most other macros into inline functions 17 | #define IsEmptySquare(p) ((p)==' ') 18 | #define IsBlack(p) ((p)>'a') // all lower case pieces 19 | #define IsWhite(p) ((p)<'a' && (p)!=' ') // all upper case pieces, and not empty 20 | 21 | // Allow easy iteration through squares 22 | inline Square& operator++ ( Square& sq ) 23 | { 24 | sq = (Square)(sq+1); 25 | return sq; 26 | } 27 | 28 | // Macro to convert chess notation to Square convention, 29 | // eg SQ('c','5') -> c5 30 | // (We didn't always have such a sensible Square convention. SQ() remains 31 | // useful for cases like SQ(file,rank), but you may actually see examples 32 | // like the hardwired SQ('c','5') which can safely be changed to simply 33 | // c5). 34 | #define SQ(f,r) ( (Square) ( ('8'-(r))*8 + ((f)-'a') ) ) 35 | 36 | // More Square macros 37 | #define FILE(sq) ( (char) ( ((sq)&0x07) + 'a' ) ) // eg c5->'c' 38 | #define RANK(sq) ( (char) ( '8' - (((sq)>>3) & 0x07) ) ) // eg c5->'5' 39 | #define IFILE(sq) ( (int)(sq) & 0x07 ) // eg c5->2 40 | #define IRANK(sq) ( 7 - ((((int)(sq)) >>3) & 0x07) ) // eg c5->4 41 | #define SOUTH(sq) ( (Square)((sq) + 8) ) // eg c5->c4 42 | #define NORTH(sq) ( (Square)((sq) - 8) ) // eg c5->c6 43 | #define SW(sq) ( (Square)((sq) + 7) ) // eg c5->b4 44 | #define SE(sq) ( (Square)((sq) + 9) ) // eg c5->d4 45 | #define NW(sq) ( (Square)((sq) - 9) ) // eg c5->b6 46 | #define NE(sq) ( (Square)((sq) - 7) ) // eg c5->d6 47 | 48 | // Utility macro 49 | #ifndef nbrof 50 | #define nbrof(array) (sizeof((array))/sizeof((array)[0])) 51 | #endif 52 | 53 | /* DETAIL is shorthand for the section of type ChessPosition that looks 54 | like this; 55 | 56 | Square enpassant_target : 8; 57 | Square wking_square : 8; 58 | Square bking_square : 8; 59 | int wking : 1; 60 | int wqueen : 1; 61 | int bking : 1; 62 | int bqueen : 1; 63 | 64 | We assume it is located in the last 4 bytes of ChessPosition, 65 | hence the definition of typedef DETAIL as unsigned long, and 66 | of DETAIL_ADDR below. We assume that ANDing the unsigned 67 | character at this address + 3, with ~WKING, where WKING 68 | is defined as unsigned char 0x01, will clear wking. See the 69 | definition of DETAIL_CASTLING and castling_prohibited_table[]. 70 | These assumptions are likely not portable and are tested in 71 | TestInternals(). If porting this code, step through that code 72 | first and make any adjustments necessary */ 73 | 74 | #define DETAIL_ADDR ( (DETAIL*) ((char *)this + sizeof(ChessPosition) - sizeof(DETAIL)) ) 75 | #define DETAIL_SAVE DETAIL tmp = *DETAIL_ADDR 76 | #define DETAIL_RESTORE *DETAIL_ADDR = tmp 77 | #define DETAIL_EQ_ALL ( (*DETAIL_ADDR&0x0fffffff) == (tmp&0x0fffffff) ) 78 | #define DETAIL_EQ_CASTLING ( (*DETAIL_ADDR&0x0f000000) == (tmp&0x0f000000) ) 79 | #define DETAIL_EQ_KING_POSITIONS ( (*DETAIL_ADDR&0x00ffff00) == (tmp&0x00ffff00) ) 80 | #define DETAIL_EQ_EN_PASSANT ( (*DETAIL_ADDR&0x000000ff) == (tmp&0x000000ff) ) 81 | #define DETAIL_PUSH detail_stack[detail_idx++] = *DETAIL_ADDR 82 | #define DETAIL_POP *DETAIL_ADDR = detail_stack[--detail_idx] 83 | #define DETAIL_CASTLING(sq) *( 3 + (unsigned char*)DETAIL_ADDR ) &= castling_prohibited_table[sq] 84 | 85 | // Bits corresponding to detail bits wking, wqueen, bking, bqueen for 86 | // DETAIL_CASTLING 87 | #define WKING 0x01 88 | #define WQUEEN 0x02 89 | #define BKING 0x04 90 | #define BQUEEN 0x08 91 | 92 | 93 | // Convert piece, e.g. 'N' to bitmask in lookup tables. See automatically 94 | // PrivateChessDefs.cpp and GeneratedLookupTables.h for format of 95 | // lookup tables 96 | extern lte to_mask[]; 97 | 98 | // Lookup squares a queen can move to 99 | extern const lte *queen_lookup[]; 100 | 101 | // Lookup squares a rook can move to 102 | extern const lte *rook_lookup[]; 103 | 104 | // Lookup squares a bishop can move to 105 | extern const lte *bishop_lookup[]; 106 | 107 | // Lookup squares a knight can move to 108 | extern const lte *knight_lookup[]; 109 | 110 | // Lookup squares a king can move to 111 | extern const lte *king_lookup[]; 112 | 113 | // Lookup squares a white pawn can move to 114 | extern const lte *pawn_white_lookup[]; 115 | 116 | // Lookup squares a black pawn can move to 117 | extern const lte *pawn_black_lookup[]; 118 | 119 | // Lookup good squares for enemy king when a king is on a square in an endgame 120 | extern const lte *good_king_position_lookup[]; 121 | 122 | // Lookup squares from which an enemy pawn attacks white 123 | extern const lte *pawn_attacks_white_lookup[]; 124 | 125 | // Lookup squares from which an enemy pawn attacks black 126 | extern const lte *pawn_attacks_black_lookup[]; 127 | 128 | // Lookup squares from which enemy pieces attack white 129 | extern const lte *attacks_white_lookup[]; 130 | 131 | // Lookup squares from which enemy pieces attack black 132 | extern const lte *attacks_black_lookup[]; 133 | 134 | } //namespace thc 135 | 136 | #endif // PRIVATE_CHESS_DEFS_H_INCLUDED 137 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Utility functions 4 | Bill Forster, October 2018 5 | 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include // For va_start, etc. 12 | #include 13 | #include "util.h" 14 | 15 | namespace util 16 | { 17 | 18 | void putline(std::ostream &out,const std::string &line) 19 | { 20 | out.write( line.c_str(), line.length() ); 21 | out.write( "\n", 1 ); 22 | } 23 | 24 | std::string sprintf( const char *fmt, ... ) 25 | { 26 | int size = strlen(fmt) * 3; // guess at size 27 | std::string str; 28 | va_list ap; 29 | for(;;) 30 | { 31 | str.resize(size); 32 | va_start(ap, fmt); 33 | int n = vsnprintf((char *)str.data(), size, fmt, ap); 34 | va_end(ap); 35 | if( n>-1 && n size ) // Needed size returned 41 | size = n + 1; // For null char 42 | else 43 | size *= 4; // Guess at a larger size 44 | } 45 | return str; 46 | } 47 | 48 | bool prefix( const std::string &s, const std::string prefix ) 49 | { 50 | size_t offset = s.find(prefix); 51 | return (offset == 0); 52 | } 53 | 54 | bool suffix( const std::string &s, const std::string suffix ) 55 | { 56 | return( s.length() >= suffix.length() && 57 | suffix == s.substr(s.length()-suffix.length(), suffix.length()) 58 | ); 59 | } 60 | 61 | bool prefix_remove( std::string &s, const std::string prefix ) 62 | { 63 | size_t offset = s.find(prefix); 64 | bool found = (offset == 0); 65 | if( found ) 66 | s = s.substr(prefix.length()); 67 | return found; 68 | } 69 | 70 | void ltrim( std::string &s ) 71 | { 72 | size_t first_char_offset = s.find_first_not_of(" \n\r\t"); 73 | if( first_char_offset == std::string::npos ) 74 | s.clear(); 75 | else 76 | s = s.substr(first_char_offset); 77 | } 78 | 79 | void rtrim( std::string &s ) 80 | { 81 | size_t final_char_offset = s.find_last_not_of(" \n\r\t"); 82 | if( final_char_offset == std::string::npos ) 83 | s.clear(); 84 | else 85 | s.erase(final_char_offset+1); 86 | } 87 | 88 | // Try for a little efficiency, return true if changes made 89 | bool trim( std::string &s ) 90 | { 91 | bool changed=false; 92 | size_t len = s.length(); 93 | if( len > 0 ) 94 | { 95 | size_t first_char_offset = s.find_first_not_of(" \n\r\t"); 96 | if( first_char_offset == std::string::npos ) 97 | { 98 | s.clear(); // string is all whitespace 99 | return true; 100 | } 101 | else if( first_char_offset > 0 ) 102 | { 103 | s = s.substr(first_char_offset); // effect left trim 104 | changed = true; 105 | } 106 | size_t final_char_offset = s.find_last_not_of(" \n\r\t"); 107 | if( final_char_offset != std::string::npos && final_char_offset < len-1 ) 108 | { 109 | s.erase(final_char_offset+1); // effect right trim 110 | changed = true; 111 | } 112 | } 113 | return changed; 114 | } 115 | 116 | static bool test_expect( std::string test_id, bool b, bool b_expected, const std::string s, const std::string s_expected ) 117 | { 118 | bool ok=true; 119 | if( b != b_expected ) 120 | { 121 | printf( "test %s: failed, 1st parameter wrong\n", test_id.c_str() ); 122 | ok = false; 123 | } 124 | if( s != s_expected ) 125 | { 126 | printf( "test %s: failed, 2nd parameter was %s\n", test_id.c_str(), s.c_str() ); 127 | ok = false; 128 | } 129 | return ok; 130 | } 131 | 132 | void tests() 133 | { 134 | std::string s; 135 | s = " "; 136 | bool changed = trim(s); 137 | test_expect( "1.0", changed, true, s, "" ); 138 | s = " hello"; 139 | changed = trim(s); 140 | test_expect( "1.1", changed, true, s, "hello" ); 141 | s = "hello "; 142 | changed = trim(s); 143 | test_expect( "1.2", changed, true, s, "hello" ); 144 | s = " hello "; 145 | changed = trim(s); 146 | test_expect( "1.3", changed, true, s, "hello" ); 147 | s = "hello"; 148 | changed = trim(s); 149 | test_expect( "1.4", changed, false, s, "hello" ); 150 | } 151 | 152 | void replace_all( std::string &s, const std::string from, const std::string to ) 153 | { 154 | size_t next = 0; 155 | for(;;) 156 | { 157 | size_t offset = s.find(from,next); 158 | if( offset == std::string::npos ) 159 | break; 160 | else 161 | s.replace(offset,from.length(),to); 162 | next = offset+to.length(); 163 | } 164 | } 165 | 166 | void replace_once( std::string &s, const std::string from, const std::string to ) 167 | { 168 | size_t offset = s.find(from); 169 | if( offset != std::string::npos ) 170 | s.replace(offset,from.length(),to); 171 | } 172 | 173 | void split( std::string &s, std::vector &fields ) 174 | { 175 | fields.clear(); 176 | size_t next = 0; 177 | bool more = true; 178 | while( more && s.length()>next) 179 | { 180 | size_t offset = s.find('\t',next); 181 | std::string frag; 182 | if( offset != std::string::npos ) 183 | frag = s.substr(next,offset-next); 184 | else 185 | { 186 | frag = s.substr(next); 187 | more = false; 188 | } 189 | fields.push_back(frag); 190 | if( more ) 191 | next = offset+1; 192 | } 193 | } 194 | 195 | std::string toupper( const std::string &s ) 196 | { 197 | std::string r = s; 198 | for( unsigned int i=0; i 6 | ****************************************************************************/ 7 | #ifndef CHESSRULES_H 8 | #define CHESSRULES_H 9 | #include "ChessPosition.h" 10 | #include "Move.h" 11 | #include 12 | 13 | // TripleHappyChess 14 | namespace thc 15 | { 16 | 17 | // Class encapsulates state of game and operations available 18 | class ChessRules: public ChessPosition 19 | { 20 | public: 21 | // Default constructor 22 | ChessRules() : ChessPosition() { Init(); } 23 | void Init() // TODO == ChessRules::Init() should call ChessPosition::Init() right ????!!!! 24 | // Thoughts: Maybe - but can't do this casually. For example we would need to 25 | // change the code that converts ChessPosition to ChessRules below, both the 26 | // copy constructor and assignment operator use ChessRules::Init() at a time 27 | // when it would be disastrous to set the initial position (because 28 | // we have carefully copied a position into the ChessRules object) 29 | { 30 | history_idx = 1; // prevent bogus repetition draws 31 | history[0].src = a8; // (look backwards through history stops when src==dst) 32 | history[0].dst = a8; 33 | detail_idx =0; 34 | } 35 | 36 | // Copy constructor 37 | ChessRules( const ChessPosition& src ) : ChessPosition( src ) 38 | { 39 | Init(); // even if src is e.g. ChessRules or ChessEngine don't 40 | // copy stuff for repetition, 50 move rule 41 | } 42 | 43 | // Assignment operator 44 | ChessRules& operator=( const ChessPosition& src ) 45 | { 46 | *((ChessPosition *)this) = src; 47 | Init(); // even if src is e.g. ChessRules or ChessEngine don't 48 | // copy stuff for repetition, 50 move rule 49 | return *this; 50 | } 51 | 52 | // Test internals, for porting to new environments etc 53 | bool TestInternals( int (*log)(const char *,...) = NULL ); 54 | 55 | // Initialise from Forsyth string 56 | bool Forsyth( const char *txt ) 57 | { 58 | bool okay = ChessPosition::Forsyth(txt); 59 | if( okay ) 60 | Init(); // clear stuff for repetition, 50 move rule 61 | return okay; 62 | } 63 | 64 | // Test for legal position, sets reason to a mask of possibly multiple reasons 65 | bool IsLegal( ILLEGAL_REASON& reason ); 66 | 67 | // Play a move 68 | void PlayMove( Move imove ); 69 | 70 | // Check draw rules (50 move rule etc.) 71 | bool IsDraw( bool white_asks, DRAWTYPE &result ); 72 | 73 | // Get number of times position has been repeated 74 | int GetRepetitionCount(); 75 | 76 | // Check insufficient material draw rule 77 | bool IsInsufficientDraw( bool white_asks, DRAWTYPE &result ); 78 | 79 | // Evaluate a position, returns bool okay (not okay means illegal position) 80 | bool Evaluate(); 81 | bool Evaluate( TERMINAL &score_terminal ); 82 | 83 | // Is a square is attacked by enemy ? 84 | bool AttackedSquare( Square square, bool enemy_is_white ); 85 | 86 | // Determine if an occupied square is attacked 87 | bool AttackedPiece( Square square ); 88 | 89 | // Transform a position with W to move into an equivalent with B to move and vice-versa 90 | void Transform(); 91 | 92 | // Transform a W move in a transformed position to a B one and vice-versa 93 | Move Transform( Move m ); 94 | 95 | // Create a list of all legal moves in this position 96 | void GenLegalMoveList( std::vector &moves ); 97 | 98 | // Create a list of all legal moves in this position, with extra info 99 | void GenLegalMoveList( std::vector &moves, 100 | std::vector &check, 101 | std::vector &mate, 102 | std::vector &stalemate ); 103 | 104 | // Create a list of all legal moves in this position 105 | void GenLegalMoveList( MOVELIST *list ); 106 | 107 | // Create a list of all legal moves in this position, with extra info 108 | void GenLegalMoveList( MOVELIST *list, bool check[MAXMOVES], 109 | bool mate[MAXMOVES], 110 | bool stalemate[MAXMOVES] ); 111 | 112 | // Make a move (with the potential to undo) 113 | void PushMove( Move& m ); 114 | 115 | // Undo a move 116 | void PopMove( Move& m ); 117 | 118 | // Test fundamental internal assumptions and operations 119 | void TestInternals(); 120 | 121 | // Private stuff 122 | protected: 123 | 124 | // Generate a list of all possible moves in a position (including 125 | // illegally "moving into check") 126 | void GenMoveList( MOVELIST *l ); 127 | 128 | // Generate moves for pieces that move along multi-move rays (B,R,Q) 129 | void LongMoves( MOVELIST *l, Square square, const lte *ptr ); 130 | 131 | // Generate moves for pieces that move along single-move rays (K,N,P) 132 | void ShortMoves( MOVELIST *l, Square square, const lte *ptr, SPECIAL special ); 133 | 134 | // Generate list of king moves 135 | void KingMoves( MOVELIST *l, Square square ); 136 | 137 | // Generate list of white pawn moves 138 | void WhitePawnMoves( MOVELIST *l, Square square ); 139 | 140 | // Generate list of black pawn moves 141 | void BlackPawnMoves( MOVELIST *l, Square square ); 142 | 143 | // Evaluate a position, returns bool okay (not okay means illegal position) 144 | bool Evaluate( MOVELIST *list, TERMINAL &score_terminal ); 145 | 146 | //### Data 147 | 148 | // Move history is a ring array 149 | Move history[256]; // must be 256 .. 150 | unsigned char history_idx; // .. so this loops around naturally 151 | 152 | // Detail stack is a ring array 153 | DETAIL detail_stack[256]; // must be 256 .. 154 | unsigned char detail_idx; // .. so this loops around naturally 155 | }; 156 | 157 | } //namespace thc 158 | 159 | #endif //CHESSRULES_H 160 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THC Chess Library 2 | 3 | THC stands for "Triplehappy Chess". Triplehappy is a former company name, and still exists 4 | as triplehappy.com, a website hosting my chess projects. THC the library is a C++ implementation 5 | of the rules of standard chess. It is intended to provide a convenient API for different types of C++ 6 | chess programs (engines, GUIs, utilities, you name it). THC used to take the form of a bunch of 7 | C++ files that needed to be gathered into a library, but C++ libraries are a bit awkward, so it 8 | now takes the form of just two C++ files, thc.cpp and thc.h with no further dependencies. 9 | 10 | Getting started 11 | =============== 12 | 13 | I have had quite a lot of correspondence from people who have had various problems getting 14 | started with THC, so I have simplified the process as much as possible - and it's now really 15 | simple! You don't have to worry about how THC is put together and tested. You just need 16 | to grab two files thc.cpp (a C++ file) and thc.h (a C++ include file) and add them into 17 | your project (irrespective of your OS, IDE compiler whatever - they're just simple, standard 18 | portable C++). 19 | 20 | To illustrate the process, I've introduced the new demonstration program called demo.cpp. This 21 | is a kind of 'Hello World' program for THC. Just build a program that compiles and links the 22 | two C++ files demo.cpp and thc.cpp together. I've included a Visual C++ 2017 solution and project 23 | but really any C++ development system should work fine. More recently I added the simplest possible 24 | bash build script to build the demo on Linux. (I also updated the Visual C++ project file to 2019, 25 | this mainly changed the platform toolset from v141 to v142). 26 | 27 | 28 | The demo.cpp program is simple and self-explanatory, and by looking at it and getting it 29 | going you will see the sort of things you can do with THC. It might be a good idea to keep 30 | demo.cpp as the main() file in your project (rename it to something else) and then to 31 | progressively replace it with the functionality you want to build. 32 | 33 | 34 | Rebuild and Test 35 | ================ 36 | 37 | I should mention that there's now a supplement to the Demo program I described in Getting started. 38 | It's called RebuildAndTest. You use it to, well, rebuild and test thc.c and thc.h. In this sense 39 | 'rebuild' means to pull the components of thc.c and thc.h together, and 'test' is just some 40 | rudimentary testing that I should extend, for example with perft (see github.com Issues for the 41 | repository - the good news is that tch-chess-library does pass this standard test!). 42 | 43 | You can still ignore Rebuild and Test if you just want to quickly get started, but this is a good 44 | place to go if you want to get into the weeds a little further. Just as for the Demo program, there 45 | are Visual C++ 2019 files for building RebuildAndTest and a rudimentary Linux build script as well. 46 | This time there are three C++ files to compile and link - test-framework.cpp, thc.cpp and util.cpp. 47 | 48 | Background 49 | ========== 50 | 51 | This is a general purpose chess library for C++. It provides clients with 52 | simple facilities for creating and manipulating chess positions and moves 53 | in accordance with the rules of standard chess. 54 | 55 | Features 56 | ======== 57 | 58 | * Import/export positions using FEN (Forsyth Edwards Notation) 59 | * Import/export moves using SAN (Standard algebraic notation) 60 | * Generate legal move list, understands all chess rules 61 | * Make moves in positions, push and pop moves in positions 62 | * Evaluate positions for mate and all draw rules 63 | * Compress positions 64 | * Generate fast position hash codes move by move. 65 | * Fast operation using lookup tables, efficient data structures 66 | 67 | THC and other projects/repositories 68 | =================================== 69 | 70 | In December 2020 I (finally) got all my GitHub chess projects properly aligned. 71 | 72 | - THC, a C++ implementation of the rules of chess (this project) 73 | - Tarrasch Chess GUI, My main project, a chess workbench 74 | - Sargon 1978, porting the original classic Z80 program to work as a UCI engine 75 | - Tarrasch Toy Engine, a simple original UCI engine 76 | 77 | The idea is that project thc will deliver a simple pair of C++ file thc.cpp and thc.h which 78 | implement the rules of chess for the other three projects. Finally, thc.cpp and thc.h 79 | are the same for all three projects! (at least on December 2nd 2020). 80 | 81 | Older Information 82 | ================= 83 | 84 | Everything that follows is a little tired and out of date, I will leave it in 85 | for now but I should rewrite, reorganise somewhat. 86 | 87 | This repository serves as 88 | the genesis of the files src/thc.cpp and src/thc.h in the peer repository 89 | tarrasch-chess-gui. Those files serve as a bedrock chess API for the program 90 | Tarrasch Chess GUI. Those two files are basically a concatenation of the files 91 | present in this library. The idea for that was inspired by SQLite, which is 92 | similarly distributed as single concatenated .c and .h files to avoid the 93 | pain point of integrating a library into a project. 94 | 95 | This repository has recently been brought up to date with its peer 96 | tarrasch-chess-gui repository. It is easier to understand 97 | the more granular presentation of the code in this repository. I used 98 | to say *One day it 99 | would be nice to add a python script or similar to this repository to 100 | automatically regenerate the concatenated two file version of the library.* 101 | I can now (August 7th 2019) say that this has been successfully implemented with a new program 102 | test-framework.cpp. This should make it practical to keep the repositories in 103 | sync from now on. 104 | 105 | Status 106 | ====== 107 | 108 | This code was written as part of the Tarrasch Chess GUI [see peer repository/(ies)]. At a certain 109 | point it seemed sensible to break the Chess API out into a library. After some experience 110 | with using a thc.lib / thc.a static library with Visual Studio/Windows and XCode/Mac I have 111 | reluctantly concluded that libraries can be very annoying and I now use a slightly different 112 | mechanism; I concatenate the modules together and provide a single thc.cpp and thc.h file 113 | to include in any project in the simplest possible way. This idea was inspired by SQLite3 114 | which does the same thing. The thc.cpp and thc.h files are in the source directory, and they 115 | are the only files you need EXCEPT, unfortunately DebugPrintf.h and Portability.h, which are 116 | Tarrasch Chess GUI files and are also needed just at the moment. The presence of DebugPrintf.h 117 | requires that the user contribute a DebugPrintfInner() or similar function. 118 | 119 | CMake Build 120 | =========== 121 | 122 | If you instead use CMake as a build system, you may prefer adding the library to your project 123 | as a CMake submodule. `CMakeLists.txt` provides the variable `THC_CHESS_INCLUDE` for the headers 124 | include directory and the libraries `thc_chess` (shared) and `thc_chess_static` (static). 125 | 126 | Usage example: 127 | ```cmake 128 | add_subdirectory("${PROJECT_SOURCE_DIR}/path/to/library" EXCLUDE_FROM_ALL) 129 | include_directories(${THC_CHESS_INCLUDE}) 130 | target_link_libraries(your_binary_name thc_chess_static) # or thc_chess for dynamic linking 131 | ``` 132 | 133 | To Do 134 | ===== 135 | 136 | I would like to do a bit of a renaming exercise - I am moving away from 137 | "using" and prefer explicit use of namespaces. All the thc library code 138 | is in namespace thc, so thc::position for example would be more logical 139 | than thc::ChessPosition (note thc = triple happy chess, where triple 140 | happy comes from triplehappy.com, a domain I use). 141 | 142 | An annoying thing is that all the code in this repository seems to have reverted to Windows 143 | CR/LF endings despite me carefully standardising on LF only. I need to sort this out. I blame 144 | (possibly unfairly) GitHub. 145 | 146 | Although you won't find much test code (yet), the code is battle proven from years of use and 147 | incremental improvement inside the Tarrasch Chess GUI project. 148 | 149 | Bill Forster 25Mar2014, updated 2Dec2020 150 | -------------------------------------------------------------------------------- /src/ChessPosition.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * ChessPosition.h Chess classes - Representation of the position on the board 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | #ifndef CHESSPOSITION_H 8 | #define CHESSPOSITION_H 9 | #include 10 | #include 11 | #include "ChessPositionRaw.h" 12 | 13 | // TripleHappyChess 14 | namespace thc 15 | { 16 | class Move; 17 | 18 | // ChessPosition - A complete representation of the position on the 19 | // board. 20 | class ChessPosition : public ChessPositionRaw 21 | { 22 | public: 23 | 24 | // Default constructor 25 | ChessPosition() { Init(); } 26 | virtual ~ChessPosition() {} // destructor not actually needed now as 27 | // we don't allocate resources in ctor. 28 | void Init() 29 | { 30 | white = true; 31 | memcpy( squares, 32 | "rnbqkbnr" 33 | "pppppppp" 34 | " " 35 | " " 36 | " " 37 | " " 38 | "PPPPPPPP" 39 | "RNBQKBNR", sizeof(squares) ); 40 | enpassant_target = SQUARE_INVALID; 41 | wking = true; 42 | wqueen = true; 43 | bking = true; 44 | bqueen = true; 45 | wking_square = e1; 46 | bking_square = e8; 47 | half_move_clock = 0; 48 | full_move_count = 1; 49 | } 50 | 51 | // Copy constructor and Assignment operator. Defining them this way 52 | // generates simple bitwise memory copy, which is exactly what we 53 | // want and is better practice than the old memcpy() versions (which 54 | // copy the vtable ptr as well - we don't want that). Thanks to GitHub 55 | // user metiscus for the pull request that fixed this. 56 | ChessPosition( const ChessPosition& src ) = default; 57 | ChessPosition& operator=( const ChessPosition& src ) = default; 58 | 59 | // Equality operator 60 | bool operator ==( const ChessPosition &other ) const 61 | { 62 | return( white == other.white && 63 | 0 == memcmp( &squares, &other.squares, 64 ) && 64 | groomed_enpassant_target() == other.groomed_enpassant_target() && 65 | wking_allowed() == other.wking_allowed() && 66 | wqueen_allowed() == other.wqueen_allowed() && 67 | bking_allowed() == other.bking_allowed() && 68 | bqueen_allowed() == other.bqueen_allowed() 69 | ); 70 | } 71 | 72 | // < Operator 73 | // Why do we want this elaborate operator? Well if we ever use the std 74 | // sort algorithm on ChessPosition objects we need a < operator with 75 | // the following properties (a and b are two ChessPositions); 76 | // 1) if a==b is true then aa6 && squares[idx-1]=='P' ) 128 | zap = false; // eg a5xb6 ep, through g5xh6 ep 129 | if( enpassant_target
a3 && squares[idx-1]=='p' ) 139 | zap = false; // eg a4xb3 ep, through g4xh3 ep 140 | if( enpassant_target

2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {009345D5-4053-4476-B6BB-4AC86C491844} 24 | Win32Proj 25 | Demo 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | Disabled 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | pch.h 94 | 95 | 96 | Console 97 | true 98 | 99 | 100 | 101 | 102 | Use 103 | Level3 104 | Disabled 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | pch.h 109 | 110 | 111 | Console 112 | true 113 | 114 | 115 | 116 | 117 | NotUsing 118 | Level3 119 | MaxSpeed 120 | true 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | true 125 | pch.h 126 | 127 | 128 | Console 129 | true 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | Use 137 | Level3 138 | MaxSpeed 139 | true 140 | true 141 | true 142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | true 144 | pch.h 145 | 146 | 147 | Console 148 | true 149 | true 150 | true 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /RebuildAndTest/RebuildAndTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {6F9B7E96-AD17-46E1-B24D-A87E2D90C64D} 24 | Win32Proj 25 | RebuildAndTest 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | Disabled 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | pch.h 94 | 95 | 96 | Console 97 | true 98 | 99 | 100 | 101 | 102 | Use 103 | Level3 104 | Disabled 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | pch.h 109 | 110 | 111 | Console 112 | true 113 | 114 | 115 | 116 | 117 | NotUsing 118 | Level3 119 | MaxSpeed 120 | true 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | true 125 | pch.h 126 | 127 | 128 | Console 129 | true 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | Use 137 | Level3 138 | MaxSpeed 139 | true 140 | true 141 | true 142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | true 144 | pch.h 145 | 146 | 147 | Console 148 | true 149 | true 150 | true 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/test-framework.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Rebuild and Test THC Chess Library 4 | 5 | Does two jobs; 6 | 7 | 1) Concatenate the .cpp files into a single thc.cpp and the .h files into a single thc.h 8 | 2) Do some basic testing of the library 9 | 10 | Note that 1) generates thc-regen.cpp and thc-regen.h and 2) relies upon thc.h being 11 | included and thc.cpp being linked in. 12 | 13 | After some rework (refactoring, synchronising, harmonising) on 2 December 2020 the 14 | thc and thc-regen files do match (and a test is now included to check for this match) 15 | 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "util.h" 32 | #include "thc.h" 33 | 34 | // Prototypes 35 | bool regenerate_h_file(); 36 | bool regenerate_cpp_file(); 37 | bool files_match( const std::string &file1, const std::string &file2 ); 38 | 39 | int main() 40 | { 41 | // Step 1) 42 | bool ok=false; 43 | if( regenerate_h_file() ) 44 | if( regenerate_cpp_file() ) 45 | ok = true; 46 | 47 | // Step 2) 48 | if( ok ) 49 | { 50 | bool match = files_match( "../src/thc.cpp", "../src/thc-regen.cpp" ); 51 | printf( "File ../src/thc.cpp does %s regenerated file ../src/thc-regen.cpp as intended\n", match ? "match":"not match" ); 52 | match = files_match( "../src/thc.h", "../src/thc-regen.h" ); 53 | printf( "File ../src/thc.h does %s regenerated file ../src/thc-regen.h as intended\n", match ? "match":"not match" ); 54 | } 55 | 56 | // Step 3) 57 | if( ok ) 58 | { 59 | thc::ChessRules cr; 60 | bool ok = cr.TestInternals( printf ); 61 | printf( "Internal THC library tests %s\n", ok ? "pass":"fail" ); 62 | } 63 | return -1; 64 | } 65 | 66 | #define nbrof(array) (sizeof(array)/sizeof((array)[0])) 67 | 68 | bool regenerate_h_file() 69 | { 70 | const char *fixed_header[]= 71 | { 72 | "/****************************************************************************", 73 | " * Triple Happy Chess library = thc library", 74 | " * This is thc rendered as a single thc.h header + thc.cpp source file to", 75 | " * avoid the complications of libraries - Inspired by sqlite.c", 76 | " *", 77 | " * Author: Bill Forster", 78 | " * License: MIT license. Full text of license is in associated file LICENSE", 79 | " * Copyright 2010-2020, Bill Forster ", 80 | " ****************************************************************************/", 81 | "", 82 | "/*" , 83 | " thc.h The basic idea is to concatenate the following into one .h file;", 84 | "", 85 | " ChessDefs.h", 86 | " Move.h", 87 | " ChessPositionRaw.h", 88 | " ChessPosition.h", 89 | " ChessRules.h", 90 | " ChessEvaluation.h", 91 | "", 92 | " */", 93 | "", 94 | "#include ", 95 | "#include ", 96 | "#include ", 97 | "#include ", 98 | "#include " 99 | }; 100 | 101 | const char *hdr_files[]= 102 | { 103 | "../src/ChessDefs.h", 104 | "../src/Move.h", 105 | "../src/ChessPositionRaw.h", 106 | "../src/ChessPosition.h", 107 | "../src/ChessRules.h", 108 | "../src/ChessEvaluation.h" 109 | }; 110 | 111 | std::ofstream out("../src/thc-regen.h"); 112 | if( !out ) 113 | { 114 | printf( "Cannot open ../src/thc-regen.h\n" ); 115 | return false; 116 | } 117 | 118 | for( unsigned int i=0; i", 162 | " ****************************************************************************/", 163 | "", 164 | "/*", 165 | " thc.cpp The basic idea is to concatenate the following into one .cpp file;", 166 | "", 167 | " Portability.cpp", 168 | " PrivateChessDefs.h", 169 | " HashLookup.h", 170 | " ChessPosition.cpp", 171 | " ChessRules.cpp", 172 | " ChessEvaluation.cpp", 173 | " Move.cpp", 174 | " PrivateChessDefs.cpp", 175 | " nested inline expansion of -> GeneratedLookupTables.h", 176 | " */", 177 | "", 178 | "#define _CRT_SECURE_NO_WARNINGS", 179 | "#include ", 180 | "#include ", 181 | "#include ", 182 | "#include ", 183 | "#include ", 184 | "#include ", 185 | "#include \"thc.h\"", 186 | "using namespace std;", 187 | "using namespace thc;" 188 | }; 189 | 190 | const char *cpp_files[]= 191 | { 192 | "../src/Portability.cpp", 193 | "../src/PrivateChessDefs.h", 194 | "../src/HashLookup.h", 195 | "../src/ChessPosition.cpp", 196 | "../src/ChessRules.cpp", 197 | "../src/ChessEvaluation.cpp", 198 | "../src/Move.cpp", 199 | "../src/PrivateChessDefs.cpp" 200 | }; 201 | 202 | std::ofstream out("../src/thc-regen.cpp"); 203 | if( !out ) 204 | { 205 | printf( "Cannot open ../src/thc-regen.cpp\n" ); 206 | return false; 207 | } 208 | 209 | for( unsigned int i=0; i 9 | ****************************************************************************/ 10 | 11 | /* 12 | thc.h The basic idea is to concatenate the following into one .h file; 13 | 14 | ChessDefs.h 15 | Move.h 16 | ChessPositionRaw.h 17 | ChessPosition.h 18 | ChessRules.h 19 | ChessEvaluation.h 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | /**************************************************************************** 29 | * Chessdefs.h Chess classes - Common definitions 30 | * Author: Bill Forster 31 | * License: MIT license. Full text of license is in associated file LICENSE 32 | * Copyright 2010-2020, Bill Forster 33 | ****************************************************************************/ 34 | #ifndef CHESSDEFS_H 35 | #define CHESSDEFS_H 36 | 37 | // Simple definition to aid platform portability (only remains of former Portability.h) 38 | int strcmp_ignore( const char *s, const char *t ); // return 0 if case-insensitive match 39 | 40 | // Fast test for is square white or black. Intend to move this to namespace thc when convenient... 41 | inline bool is_dark( int sq ) 42 | { 43 | bool dark = (!(sq&8) && (sq&1)) // eg (a8,b8,c8...h8) && (b8|d8|f8|h8) odd rank + odd file 44 | || ( (sq&8) && !(sq&1)); // eg (a7,b7,c7...h7) && (a7|c7|e7|g7) even rank + even file 45 | return dark; 46 | } 47 | 48 | // TripleHappyChess 49 | namespace thc 50 | { 51 | 52 | // Use the most natural square convention possible; Define Square to 53 | // correspond to a conventionally oriented chess diagram; Top left corner 54 | // (square a8) is 0, bottom right corner (square h1) is 63. 55 | // Note that instead of defining a special piece type, we use the built-in 56 | // char type, with 'N'=white knight, 'b'=black bishop etc. and ' '=an 57 | // empty square. 58 | enum Square 59 | { 60 | a8=0, 61 | b8, c8, d8, e8, f8, g8, h8, 62 | a7, b7, c7, d7, e7, f7, g7, h7, 63 | a6, b6, c6, d6, e6, f6, g6, h6, 64 | a5, b5, c5, d5, e5, f5, g5, h5, 65 | a4, b4, c4, d4, e4, f4, g4, h4, 66 | a3, b3, c3, d3, e3, f3, g3, h3, 67 | a2, b2, c2, d2, e2, f2, g2, h2, 68 | a1, b1, c1, d1, e1, f1, g1, h1, 69 | SQUARE_INVALID 70 | }; 71 | 72 | // thc::Square utilities 73 | inline char get_file( Square sq ) 74 | { return static_cast ( (static_cast(sq)&0x07) + 'a' ); } // eg c5->'c' 75 | inline char get_rank( Square sq ) 76 | { return static_cast ( '8' - ((static_cast(sq)>>3) & 0x07) ); } // eg c5->'5' 77 | inline Square make_square( char file, char rank ) 78 | { return static_cast ( ('8'-(rank))*8 + ((file)-'a') ); } // eg ('c','5') -> c5 79 | 80 | // Special (i.e. not ordinary) move types 81 | enum SPECIAL 82 | { 83 | NOT_SPECIAL = 0, 84 | SPECIAL_KING_MOVE, // special only because it changes wking_square, bking_square 85 | SPECIAL_WK_CASTLING, 86 | SPECIAL_BK_CASTLING, 87 | SPECIAL_WQ_CASTLING, 88 | SPECIAL_BQ_CASTLING, 89 | SPECIAL_PROMOTION_QUEEN, 90 | SPECIAL_PROMOTION_ROOK, 91 | SPECIAL_PROMOTION_BISHOP, 92 | SPECIAL_PROMOTION_KNIGHT, 93 | SPECIAL_WPAWN_2SQUARES, 94 | SPECIAL_BPAWN_2SQUARES, 95 | SPECIAL_WEN_PASSANT, 96 | SPECIAL_BEN_PASSANT, 97 | }; 98 | 99 | // Results of a test for legal position, note that they are powers 100 | // of 2, allowing a mask of reasons 101 | enum ILLEGAL_REASON 102 | { 103 | IR_NULL=0, IR_PAWN_POSITION=1, //pawns on 1st or 8th rank 104 | IR_NOT_ONE_KING_EACH=2, IR_CAN_TAKE_KING=4, 105 | IR_WHITE_TOO_MANY_PIECES=8, IR_WHITE_TOO_MANY_PAWNS=16, 106 | IR_BLACK_TOO_MANY_PIECES=32, IR_BLACK_TOO_MANY_PAWNS=64 107 | }; 108 | 109 | // Types of draw checked by IsDraw() 110 | enum DRAWTYPE 111 | { 112 | NOT_DRAW, 113 | DRAWTYPE_50MOVE, 114 | DRAWTYPE_INSUFFICIENT, // draw if superior side wants it 115 | // since inferior side has insufficient 116 | // mating material 117 | DRAWTYPE_INSUFFICIENT_AUTO, // don't wait to be asked, e.g. draw 118 | // immediately if bare kings 119 | DRAWTYPE_REPITITION, 120 | }; 121 | 122 | // Stalemate or checkmate game terminations 123 | enum TERMINAL 124 | { 125 | NOT_TERMINAL = 0, 126 | TERMINAL_WCHECKMATE = -1, // White is checkmated 127 | TERMINAL_WSTALEMATE = -2, // White is stalemated 128 | TERMINAL_BCHECKMATE = 1, // Black is checkmated 129 | TERMINAL_BSTALEMATE = 2 // Black is stalemated 130 | }; 131 | 132 | // Calculate an upper limit to the length of a list of moves 133 | #define MAXMOVES (27 + 2*13 + 2*14 + 2*8 + 8 + 8*4 + 3*27) 134 | //[Q 2*B 2*R 2*N K 8*P] + [3*Q] 135 | // ^ ^ 136 | //[calculated practical maximum ] + [margin] 137 | 138 | // We have developed an algorithm to compress any legal chess position, 139 | // including who to move, castling allowed flags and enpassant_target 140 | // into 24 bytes 141 | union CompressedPosition 142 | { 143 | unsigned char storage[24]; 144 | unsigned int ints[ 24 / sizeof(unsigned int) ]; 145 | }; 146 | 147 | // Types we'd really rather have in PrivateChessDefs.h, but not possible 148 | // at the moment, so we reluctantly expose them to users of the chess 149 | // classes. 150 | typedef unsigned char lte; // lte = lookup table element 151 | typedef int32_t DETAIL; 152 | 153 | } //namespace thc 154 | 155 | #endif // CHESSDEFS_H 156 | /**************************************************************************** 157 | * Move.h Chess classes - Move 158 | * Author: Bill Forster 159 | * License: MIT license. Full text of license is in associated file LICENSE 160 | * Copyright 2010-2020, Bill Forster 161 | ****************************************************************************/ 162 | #ifndef MOVE_H 163 | #define MOVE_H 164 | 165 | // TripleHappyChess 166 | namespace thc 167 | { 168 | class ChessRules; 169 | 170 | // Our representation of a chess move 171 | // 172 | // Note this is really an old school C struct, designed for speed 173 | // There is no constructor on purpose, we don't want unnecessary 174 | // construction of an array of Moves in a MOVELIST when we are running 175 | // the fast move generator. 176 | // The default assignment operator (bitwise copy) is ideal. 177 | // We define bitwise == and != operators 178 | // At one time we had 4 (count em, 4) move representations, but this 179 | // was always the primary and main representation. The others were 180 | // FMOVE (16 bit moves), NMOVE (natural string representation, eg 181 | // "Nf3") and TMOVE (terse string representation eg "g1f3"). When I 182 | // realised I could streamline an IMOVE (the old name for Move = 183 | // internal move) to only 32 bits, I realised I could live without 184 | // FMOVEs and that sparked a large simplification exercise. 185 | // 186 | class Move 187 | { 188 | public: 189 | // Move is a lightweight type, it is accommodated in only 32 bits 190 | Square src : 8; 191 | Square dst : 8; 192 | SPECIAL special : 8; 193 | int capture : 8; // ' ' (empty) if move not a capture 194 | // for some reason Visual C++ 2005 (at least) 195 | // blows sizeof(Move) out to 64 bits if 196 | // capture is defined as char instead of int 197 | 198 | bool operator ==(const Move &other) const 199 | { 200 | return( *((int32_t *)this) == *((int32_t *)(&other)) ); 201 | } 202 | 203 | bool operator !=(const Move &other) const 204 | { 205 | return( *((int32_t *)this) != *((int32_t *)(&other)) ); 206 | } 207 | 208 | // Use these sparingly when you need to specifically mark 209 | // a move as not yet set up (defined when we got rid of 210 | // 16 bit FMOVEs, we could always set and test 0 with those) 211 | void Invalid() { src=a8; dst=a8; } 212 | bool Valid() { return src!=a8 || dst!=a8; } 213 | 214 | // Read natural string move eg "Nf3" 215 | // return bool okay 216 | bool NaturalIn( ChessRules *cr, const char *natural_in ); 217 | 218 | // Read natural string move eg "Nf3" 219 | // return bool okay 220 | // Fast alternative for known good input 221 | bool NaturalInFast( ChessRules *cr, const char *natural_in ); 222 | 223 | // Read terse string move eg "g1f3" 224 | // return bool okay 225 | bool TerseIn( ChessRules *cr, const char *tmove ); 226 | 227 | // Convert to natural string 228 | // eg "Nf3" 229 | std::string NaturalOut( ChessRules *cr ); 230 | 231 | // Convert to terse string eg "e7e8q" 232 | std::string TerseOut(); 233 | }; 234 | 235 | // List of moves 236 | struct MOVELIST 237 | { 238 | int count; // number of moves 239 | Move moves[MAXMOVES]; 240 | }; 241 | 242 | } //namespace thc 243 | 244 | #endif //MOVE_H 245 | /**************************************************************************** 246 | * ChessPositionRaw.h Chess classes - A raw chess position, could be used as a C style POD 247 | * Author: Bill Forster 248 | * License: MIT license. Full text of license is in associated file LICENSE 249 | * Copyright 2010-2020, Bill Forster 250 | ****************************************************************************/ 251 | #ifndef CHESSPOSITIONRAW_H 252 | #define CHESSPOSITIONRAW_H 253 | 254 | 255 | // TripleHappyChess 256 | namespace thc 257 | { 258 | 259 | // ChessPositionRaw - A complete representation of the position on the 260 | // board. Corresponds broadly to fields of Forsyth representation 261 | struct ChessPositionRaw 262 | { 263 | // Who to play 264 | bool white; 265 | 266 | // Pieces on board in readable form; Forsyth like but without compression, 267 | // eg "rnbqkbnr" 268 | // "pppppppp" 269 | // " " 270 | // " " 271 | // " " 272 | // " " 273 | // "PPPPPPPP" 274 | // "RNBQKBNR" 275 | // (represents starting position) 276 | char squares[64 +1]; // +1 allows a trailing '\0' 277 | // note indexed according to Square convention, a8=0 etc. 278 | 279 | // Half moves since pawn move or capture (for 50 move rule) 280 | // e.g. after 1.e4 it's 0 281 | int half_move_clock; 282 | 283 | // Full move count. Initially 1 and increments after black moves 284 | // e.g. after 1.e4 it's 1 285 | // e.g. after 1... d6 it's 2 286 | int full_move_count; 287 | 288 | // The following are deemed "details", and must be stored at the 289 | // end of the structure. Search for DETAIL for, ahem, details. 290 | // For performance reasons we want the details to be able to fit 291 | // into 32 bits. 292 | Square enpassant_target : 8; 293 | Square wking_square : 8; 294 | Square bking_square : 8; 295 | unsigned int wking : 1; // Castling still allowed flags 296 | unsigned int wqueen : 1; // unfortunately if the castling 297 | unsigned int bking : 1; // flags are declared as bool, 298 | unsigned int bqueen : 1; // with Visual C++ at least, 299 | // the details blow out and use 300 | // another 32 bits (??!!) 301 | // Note that for say white king side castling to be allowed in 302 | // the same sense as the Forsyth representation, not only 303 | // must wking be true, but the white king and king rook must 304 | // be present and in position, see the wking_allowed() etc. 305 | // methods in class ChessPosition, these are used for the ChessPosition 306 | // == operator. 307 | }; 308 | 309 | } //namespace thc 310 | 311 | #endif //CHESSPOSITIONRAW_H 312 | /**************************************************************************** 313 | * ChessPosition.h Chess classes - Representation of the position on the board 314 | * Author: Bill Forster 315 | * License: MIT license. Full text of license is in associated file LICENSE 316 | * Copyright 2010-2020, Bill Forster 317 | ****************************************************************************/ 318 | #ifndef CHESSPOSITION_H 319 | #define CHESSPOSITION_H 320 | 321 | // TripleHappyChess 322 | namespace thc 323 | { 324 | class Move; 325 | 326 | // ChessPosition - A complete representation of the position on the 327 | // board. 328 | class ChessPosition : public ChessPositionRaw 329 | { 330 | public: 331 | 332 | // Default constructor 333 | ChessPosition() { Init(); } 334 | virtual ~ChessPosition() {} // destructor not actually needed now as 335 | // we don't allocate resources in ctor. 336 | void Init() 337 | { 338 | white = true; 339 | memcpy( squares, 340 | "rnbqkbnr" 341 | "pppppppp" 342 | " " 343 | " " 344 | " " 345 | " " 346 | "PPPPPPPP" 347 | "RNBQKBNR", sizeof(squares) ); 348 | enpassant_target = SQUARE_INVALID; 349 | wking = true; 350 | wqueen = true; 351 | bking = true; 352 | bqueen = true; 353 | wking_square = e1; 354 | bking_square = e8; 355 | half_move_clock = 0; 356 | full_move_count = 1; 357 | } 358 | 359 | // Copy constructor and Assignment operator. Defining them this way 360 | // generates simple bitwise memory copy, which is exactly what we 361 | // want and is better practice than the old memcpy() versions (which 362 | // copy the vtable ptr as well - we don't want that). Thanks to GitHub 363 | // user metiscus for the pull request that fixed this. 364 | ChessPosition( const ChessPosition& src ) = default; 365 | ChessPosition& operator=( const ChessPosition& src ) = default; 366 | 367 | // Equality operator 368 | bool operator ==( const ChessPosition &other ) const 369 | { 370 | return( white == other.white && 371 | 0 == memcmp( &squares, &other.squares, 64 ) && 372 | groomed_enpassant_target() == other.groomed_enpassant_target() && 373 | wking_allowed() == other.wking_allowed() && 374 | wqueen_allowed() == other.wqueen_allowed() && 375 | bking_allowed() == other.bking_allowed() && 376 | bqueen_allowed() == other.bqueen_allowed() 377 | ); 378 | } 379 | 380 | // < Operator 381 | // Why do we want this elaborate operator? Well if we ever use the std 382 | // sort algorithm on ChessPosition objects we need a < operator with 383 | // the following properties (a and b are two ChessPositions); 384 | // 1) if a==b is true then aa6 && squares[idx-1]=='P' ) 436 | zap = false; // eg a5xb6 ep, through g5xh6 ep 437 | if( enpassant_target
a3 && squares[idx-1]=='p' ) 447 | zap = false; // eg a4xb3 ep, through g4xh3 ep 448 | if( enpassant_target

506 | ****************************************************************************/ 507 | #ifndef CHESSRULES_H 508 | #define CHESSRULES_H 509 | 510 | // TripleHappyChess 511 | namespace thc 512 | { 513 | 514 | // Class encapsulates state of game and operations available 515 | class ChessRules: public ChessPosition 516 | { 517 | public: 518 | // Default constructor 519 | ChessRules() : ChessPosition() { Init(); } 520 | void Init() // TODO == ChessRules::Init() should call ChessPosition::Init() right ????!!!! 521 | // Thoughts: Maybe - but can't do this casually. For example we would need to 522 | // change the code that converts ChessPosition to ChessRules below, both the 523 | // copy constructor and assignment operator use ChessRules::Init() at a time 524 | // when it would be disastrous to set the initial position (because 525 | // we have carefully copied a position into the ChessRules object) 526 | { 527 | history_idx = 1; // prevent bogus repetition draws 528 | history[0].src = a8; // (look backwards through history stops when src==dst) 529 | history[0].dst = a8; 530 | detail_idx =0; 531 | } 532 | 533 | // Copy constructor 534 | ChessRules( const ChessPosition& src ) : ChessPosition( src ) 535 | { 536 | Init(); // even if src is e.g. ChessRules or ChessEngine don't 537 | // copy stuff for repetition, 50 move rule 538 | } 539 | 540 | // Assignment operator 541 | ChessRules& operator=( const ChessPosition& src ) 542 | { 543 | *((ChessPosition *)this) = src; 544 | Init(); // even if src is e.g. ChessRules or ChessEngine don't 545 | // copy stuff for repetition, 50 move rule 546 | return *this; 547 | } 548 | 549 | // Test internals, for porting to new environments etc 550 | bool TestInternals( int (*log)(const char *,...) = NULL ); 551 | 552 | // Initialise from Forsyth string 553 | bool Forsyth( const char *txt ) 554 | { 555 | bool okay = ChessPosition::Forsyth(txt); 556 | if( okay ) 557 | Init(); // clear stuff for repetition, 50 move rule 558 | return okay; 559 | } 560 | 561 | // Test for legal position, sets reason to a mask of possibly multiple reasons 562 | bool IsLegal( ILLEGAL_REASON& reason ); 563 | 564 | // Play a move 565 | void PlayMove( Move imove ); 566 | 567 | // Check draw rules (50 move rule etc.) 568 | bool IsDraw( bool white_asks, DRAWTYPE &result ); 569 | 570 | // Get number of times position has been repeated 571 | int GetRepetitionCount(); 572 | 573 | // Check insufficient material draw rule 574 | bool IsInsufficientDraw( bool white_asks, DRAWTYPE &result ); 575 | 576 | // Evaluate a position, returns bool okay (not okay means illegal position) 577 | bool Evaluate(); 578 | bool Evaluate( TERMINAL &score_terminal ); 579 | 580 | // Is a square is attacked by enemy ? 581 | bool AttackedSquare( Square square, bool enemy_is_white ); 582 | 583 | // Determine if an occupied square is attacked 584 | bool AttackedPiece( Square square ); 585 | 586 | // Transform a position with W to move into an equivalent with B to move and vice-versa 587 | void Transform(); 588 | 589 | // Transform a W move in a transformed position to a B one and vice-versa 590 | Move Transform( Move m ); 591 | 592 | // Create a list of all legal moves in this position 593 | void GenLegalMoveList( std::vector &moves ); 594 | 595 | // Create a list of all legal moves in this position, with extra info 596 | void GenLegalMoveList( std::vector &moves, 597 | std::vector &check, 598 | std::vector &mate, 599 | std::vector &stalemate ); 600 | 601 | // Create a list of all legal moves in this position 602 | void GenLegalMoveList( MOVELIST *list ); 603 | 604 | // Create a list of all legal moves in this position, with extra info 605 | void GenLegalMoveList( MOVELIST *list, bool check[MAXMOVES], 606 | bool mate[MAXMOVES], 607 | bool stalemate[MAXMOVES] ); 608 | 609 | // Make a move (with the potential to undo) 610 | void PushMove( Move& m ); 611 | 612 | // Undo a move 613 | void PopMove( Move& m ); 614 | 615 | // Test fundamental internal assumptions and operations 616 | void TestInternals(); 617 | 618 | // Private stuff 619 | protected: 620 | 621 | // Generate a list of all possible moves in a position (including 622 | // illegally "moving into check") 623 | void GenMoveList( MOVELIST *l ); 624 | 625 | // Generate moves for pieces that move along multi-move rays (B,R,Q) 626 | void LongMoves( MOVELIST *l, Square square, const lte *ptr ); 627 | 628 | // Generate moves for pieces that move along single-move rays (K,N,P) 629 | void ShortMoves( MOVELIST *l, Square square, const lte *ptr, SPECIAL special ); 630 | 631 | // Generate list of king moves 632 | void KingMoves( MOVELIST *l, Square square ); 633 | 634 | // Generate list of white pawn moves 635 | void WhitePawnMoves( MOVELIST *l, Square square ); 636 | 637 | // Generate list of black pawn moves 638 | void BlackPawnMoves( MOVELIST *l, Square square ); 639 | 640 | // Evaluate a position, returns bool okay (not okay means illegal position) 641 | bool Evaluate( MOVELIST *list, TERMINAL &score_terminal ); 642 | 643 | //### Data 644 | 645 | // Move history is a ring array 646 | Move history[256]; // must be 256 .. 647 | unsigned char history_idx; // .. so this loops around naturally 648 | 649 | // Detail stack is a ring array 650 | DETAIL detail_stack[256]; // must be 256 .. 651 | unsigned char detail_idx; // .. so this loops around naturally 652 | }; 653 | 654 | } //namespace thc 655 | 656 | #endif //CHESSRULES_H 657 | /**************************************************************************** 658 | * ChessEvaluation.h Chess classes - Simple chess AI, leaf scoring function for position 659 | * Author: Bill Forster 660 | * License: MIT license. Full text of license is in associated file LICENSE 661 | * Copyright 2010-2020, Bill Forster 662 | ****************************************************************************/ 663 | #ifndef CHESSEVALUATION_H 664 | #define CHESSEVALUATION_H 665 | 666 | // TripleHappyChess 667 | namespace thc 668 | { 669 | 670 | class ChessEvaluation: public ChessRules 671 | { 672 | public: 673 | // Default constructor 674 | ChessEvaluation() : ChessRules() 675 | { 676 | } 677 | 678 | // Copy constructor 679 | ChessEvaluation( const ChessPosition& src ) : ChessRules( src ) 680 | { 681 | } 682 | 683 | // Assignment operator 684 | ChessEvaluation& operator=( const ChessPosition& src ) 685 | { 686 | *((ChessRules *)this) = src; 687 | return *this; 688 | } 689 | 690 | 691 | // Use leaf evaluator to generate a sorted move list 692 | void GenLegalMoveListSorted( MOVELIST *list ); 693 | void GenLegalMoveListSorted( std::vector &moves ); 694 | 695 | // Evaluate a position, leaf node (useful for playing programs) 696 | void EvaluateLeaf( int &material, int &positional ); 697 | 698 | // internal stuff 699 | protected: 700 | 701 | // Always some planning before calculating a move 702 | void Planning(); 703 | 704 | // Calculate material that side to play can win directly 705 | int Enprise(); 706 | int EnpriseWhite(); // fast white to move version 707 | int EnpriseBlack(); // fast black to move version 708 | 709 | // misc 710 | private: 711 | bool white_is_better; 712 | bool black_is_better; 713 | int planning_score_white_pieces; 714 | int planning_score_black_pieces; 715 | int planning_white_piece_pawn_percent; 716 | int planning_black_piece_pawn_percent; 717 | }; 718 | 719 | } //namespace thc 720 | 721 | #endif //CHESSEVALUATION_H 722 | -------------------------------------------------------------------------------- /src/thc-regen.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Triple Happy Chess library = thc library 3 | * This is thc rendered as a single thc.h header + thc.cpp source file to 4 | * avoid the complications of libraries - Inspired by sqlite.c 5 | * 6 | * Author: Bill Forster 7 | * License: MIT license. Full text of license is in associated file LICENSE 8 | * Copyright 2010-2020, Bill Forster 9 | ****************************************************************************/ 10 | 11 | /* 12 | thc.h The basic idea is to concatenate the following into one .h file; 13 | 14 | ChessDefs.h 15 | Move.h 16 | ChessPositionRaw.h 17 | ChessPosition.h 18 | ChessRules.h 19 | ChessEvaluation.h 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | /**************************************************************************** 29 | * Chessdefs.h Chess classes - Common definitions 30 | * Author: Bill Forster 31 | * License: MIT license. Full text of license is in associated file LICENSE 32 | * Copyright 2010-2020, Bill Forster 33 | ****************************************************************************/ 34 | #ifndef CHESSDEFS_H 35 | #define CHESSDEFS_H 36 | 37 | // Simple definition to aid platform portability (only remains of former Portability.h) 38 | int strcmp_ignore( const char *s, const char *t ); // return 0 if case-insensitive match 39 | 40 | // Fast test for is square white or black. Intend to move this to namespace thc when convenient... 41 | inline bool is_dark( int sq ) 42 | { 43 | bool dark = (!(sq&8) && (sq&1)) // eg (a8,b8,c8...h8) && (b8|d8|f8|h8) odd rank + odd file 44 | || ( (sq&8) && !(sq&1)); // eg (a7,b7,c7...h7) && (a7|c7|e7|g7) even rank + even file 45 | return dark; 46 | } 47 | 48 | // TripleHappyChess 49 | namespace thc 50 | { 51 | 52 | // Use the most natural square convention possible; Define Square to 53 | // correspond to a conventionally oriented chess diagram; Top left corner 54 | // (square a8) is 0, bottom right corner (square h1) is 63. 55 | // Note that instead of defining a special piece type, we use the built-in 56 | // char type, with 'N'=white knight, 'b'=black bishop etc. and ' '=an 57 | // empty square. 58 | enum Square 59 | { 60 | a8=0, 61 | b8, c8, d8, e8, f8, g8, h8, 62 | a7, b7, c7, d7, e7, f7, g7, h7, 63 | a6, b6, c6, d6, e6, f6, g6, h6, 64 | a5, b5, c5, d5, e5, f5, g5, h5, 65 | a4, b4, c4, d4, e4, f4, g4, h4, 66 | a3, b3, c3, d3, e3, f3, g3, h3, 67 | a2, b2, c2, d2, e2, f2, g2, h2, 68 | a1, b1, c1, d1, e1, f1, g1, h1, 69 | SQUARE_INVALID 70 | }; 71 | 72 | // thc::Square utilities 73 | inline char get_file( Square sq ) 74 | { return static_cast ( (static_cast(sq)&0x07) + 'a' ); } // eg c5->'c' 75 | inline char get_rank( Square sq ) 76 | { return static_cast ( '8' - ((static_cast(sq)>>3) & 0x07) ); } // eg c5->'5' 77 | inline Square make_square( char file, char rank ) 78 | { return static_cast ( ('8'-(rank))*8 + ((file)-'a') ); } // eg ('c','5') -> c5 79 | 80 | // Special (i.e. not ordinary) move types 81 | enum SPECIAL 82 | { 83 | NOT_SPECIAL = 0, 84 | SPECIAL_KING_MOVE, // special only because it changes wking_square, bking_square 85 | SPECIAL_WK_CASTLING, 86 | SPECIAL_BK_CASTLING, 87 | SPECIAL_WQ_CASTLING, 88 | SPECIAL_BQ_CASTLING, 89 | SPECIAL_PROMOTION_QUEEN, 90 | SPECIAL_PROMOTION_ROOK, 91 | SPECIAL_PROMOTION_BISHOP, 92 | SPECIAL_PROMOTION_KNIGHT, 93 | SPECIAL_WPAWN_2SQUARES, 94 | SPECIAL_BPAWN_2SQUARES, 95 | SPECIAL_WEN_PASSANT, 96 | SPECIAL_BEN_PASSANT, 97 | }; 98 | 99 | // Results of a test for legal position, note that they are powers 100 | // of 2, allowing a mask of reasons 101 | enum ILLEGAL_REASON 102 | { 103 | IR_NULL=0, IR_PAWN_POSITION=1, //pawns on 1st or 8th rank 104 | IR_NOT_ONE_KING_EACH=2, IR_CAN_TAKE_KING=4, 105 | IR_WHITE_TOO_MANY_PIECES=8, IR_WHITE_TOO_MANY_PAWNS=16, 106 | IR_BLACK_TOO_MANY_PIECES=32, IR_BLACK_TOO_MANY_PAWNS=64 107 | }; 108 | 109 | // Types of draw checked by IsDraw() 110 | enum DRAWTYPE 111 | { 112 | NOT_DRAW, 113 | DRAWTYPE_50MOVE, 114 | DRAWTYPE_INSUFFICIENT, // draw if superior side wants it 115 | // since inferior side has insufficient 116 | // mating material 117 | DRAWTYPE_INSUFFICIENT_AUTO, // don't wait to be asked, e.g. draw 118 | // immediately if bare kings 119 | DRAWTYPE_REPITITION, 120 | }; 121 | 122 | // Stalemate or checkmate game terminations 123 | enum TERMINAL 124 | { 125 | NOT_TERMINAL = 0, 126 | TERMINAL_WCHECKMATE = -1, // White is checkmated 127 | TERMINAL_WSTALEMATE = -2, // White is stalemated 128 | TERMINAL_BCHECKMATE = 1, // Black is checkmated 129 | TERMINAL_BSTALEMATE = 2 // Black is stalemated 130 | }; 131 | 132 | // Calculate an upper limit to the length of a list of moves 133 | #define MAXMOVES (27 + 2*13 + 2*14 + 2*8 + 8 + 8*4 + 3*27) 134 | //[Q 2*B 2*R 2*N K 8*P] + [3*Q] 135 | // ^ ^ 136 | //[calculated practical maximum ] + [margin] 137 | 138 | // We have developed an algorithm to compress any legal chess position, 139 | // including who to move, castling allowed flags and enpassant_target 140 | // into 24 bytes 141 | union CompressedPosition 142 | { 143 | unsigned char storage[24]; 144 | unsigned int ints[ 24 / sizeof(unsigned int) ]; 145 | }; 146 | 147 | // Types we'd really rather have in PrivateChessDefs.h, but not possible 148 | // at the moment, so we reluctantly expose them to users of the chess 149 | // classes. 150 | typedef unsigned char lte; // lte = lookup table element 151 | typedef int32_t DETAIL; 152 | 153 | } //namespace thc 154 | 155 | #endif // CHESSDEFS_H 156 | /**************************************************************************** 157 | * Move.h Chess classes - Move 158 | * Author: Bill Forster 159 | * License: MIT license. Full text of license is in associated file LICENSE 160 | * Copyright 2010-2020, Bill Forster 161 | ****************************************************************************/ 162 | #ifndef MOVE_H 163 | #define MOVE_H 164 | 165 | // TripleHappyChess 166 | namespace thc 167 | { 168 | class ChessRules; 169 | 170 | // Our representation of a chess move 171 | // 172 | // Note this is really an old school C struct, designed for speed 173 | // There is no constructor on purpose, we don't want unnecessary 174 | // construction of an array of Moves in a MOVELIST when we are running 175 | // the fast move generator. 176 | // The default assignment operator (bitwise copy) is ideal. 177 | // We define bitwise == and != operators 178 | // At one time we had 4 (count em, 4) move representations, but this 179 | // was always the primary and main representation. The others were 180 | // FMOVE (16 bit moves), NMOVE (natural string representation, eg 181 | // "Nf3") and TMOVE (terse string representation eg "g1f3"). When I 182 | // realised I could streamline an IMOVE (the old name for Move = 183 | // internal move) to only 32 bits, I realised I could live without 184 | // FMOVEs and that sparked a large simplification exercise. 185 | // 186 | class Move 187 | { 188 | public: 189 | // Move is a lightweight type, it is accommodated in only 32 bits 190 | Square src : 8; 191 | Square dst : 8; 192 | SPECIAL special : 8; 193 | int capture : 8; // ' ' (empty) if move not a capture 194 | // for some reason Visual C++ 2005 (at least) 195 | // blows sizeof(Move) out to 64 bits if 196 | // capture is defined as char instead of int 197 | 198 | bool operator ==(const Move &other) const 199 | { 200 | return( *((int32_t *)this) == *((int32_t *)(&other)) ); 201 | } 202 | 203 | bool operator !=(const Move &other) const 204 | { 205 | return( *((int32_t *)this) != *((int32_t *)(&other)) ); 206 | } 207 | 208 | // Use these sparingly when you need to specifically mark 209 | // a move as not yet set up (defined when we got rid of 210 | // 16 bit FMOVEs, we could always set and test 0 with those) 211 | void Invalid() { src=a8; dst=a8; } 212 | bool Valid() { return src!=a8 || dst!=a8; } 213 | 214 | // Read natural string move eg "Nf3" 215 | // return bool okay 216 | bool NaturalIn( ChessRules *cr, const char *natural_in ); 217 | 218 | // Read natural string move eg "Nf3" 219 | // return bool okay 220 | // Fast alternative for known good input 221 | bool NaturalInFast( ChessRules *cr, const char *natural_in ); 222 | 223 | // Read terse string move eg "g1f3" 224 | // return bool okay 225 | bool TerseIn( ChessRules *cr, const char *tmove ); 226 | 227 | // Convert to natural string 228 | // eg "Nf3" 229 | std::string NaturalOut( ChessRules *cr ); 230 | 231 | // Convert to terse string eg "e7e8q" 232 | std::string TerseOut(); 233 | }; 234 | 235 | // List of moves 236 | struct MOVELIST 237 | { 238 | int count; // number of moves 239 | Move moves[MAXMOVES]; 240 | }; 241 | 242 | } //namespace thc 243 | 244 | #endif //MOVE_H 245 | /**************************************************************************** 246 | * ChessPositionRaw.h Chess classes - A raw chess position, could be used as a C style POD 247 | * Author: Bill Forster 248 | * License: MIT license. Full text of license is in associated file LICENSE 249 | * Copyright 2010-2020, Bill Forster 250 | ****************************************************************************/ 251 | #ifndef CHESSPOSITIONRAW_H 252 | #define CHESSPOSITIONRAW_H 253 | 254 | 255 | // TripleHappyChess 256 | namespace thc 257 | { 258 | 259 | // ChessPositionRaw - A complete representation of the position on the 260 | // board. Corresponds broadly to fields of Forsyth representation 261 | struct ChessPositionRaw 262 | { 263 | // Who to play 264 | bool white; 265 | 266 | // Pieces on board in readable form; Forsyth like but without compression, 267 | // eg "rnbqkbnr" 268 | // "pppppppp" 269 | // " " 270 | // " " 271 | // " " 272 | // " " 273 | // "PPPPPPPP" 274 | // "RNBQKBNR" 275 | // (represents starting position) 276 | char squares[64 +1]; // +1 allows a trailing '\0' 277 | // note indexed according to Square convention, a8=0 etc. 278 | 279 | // Half moves since pawn move or capture (for 50 move rule) 280 | // e.g. after 1.e4 it's 0 281 | int half_move_clock; 282 | 283 | // Full move count. Initially 1 and increments after black moves 284 | // e.g. after 1.e4 it's 1 285 | // e.g. after 1... d6 it's 2 286 | int full_move_count; 287 | 288 | // The following are deemed "details", and must be stored at the 289 | // end of the structure. Search for DETAIL for, ahem, details. 290 | // For performance reasons we want the details to be able to fit 291 | // into 32 bits. 292 | Square enpassant_target : 8; 293 | Square wking_square : 8; 294 | Square bking_square : 8; 295 | unsigned int wking : 1; // Castling still allowed flags 296 | unsigned int wqueen : 1; // unfortunately if the castling 297 | unsigned int bking : 1; // flags are declared as bool, 298 | unsigned int bqueen : 1; // with Visual C++ at least, 299 | // the details blow out and use 300 | // another 32 bits (??!!) 301 | // Note that for say white king side castling to be allowed in 302 | // the same sense as the Forsyth representation, not only 303 | // must wking be true, but the white king and king rook must 304 | // be present and in position, see the wking_allowed() etc. 305 | // methods in class ChessPosition, these are used for the ChessPosition 306 | // == operator. 307 | }; 308 | 309 | } //namespace thc 310 | 311 | #endif //CHESSPOSITIONRAW_H 312 | /**************************************************************************** 313 | * ChessPosition.h Chess classes - Representation of the position on the board 314 | * Author: Bill Forster 315 | * License: MIT license. Full text of license is in associated file LICENSE 316 | * Copyright 2010-2020, Bill Forster 317 | ****************************************************************************/ 318 | #ifndef CHESSPOSITION_H 319 | #define CHESSPOSITION_H 320 | 321 | // TripleHappyChess 322 | namespace thc 323 | { 324 | class Move; 325 | 326 | // ChessPosition - A complete representation of the position on the 327 | // board. 328 | class ChessPosition : public ChessPositionRaw 329 | { 330 | public: 331 | 332 | // Default constructor 333 | ChessPosition() { Init(); } 334 | virtual ~ChessPosition() {} // destructor not actually needed now as 335 | // we don't allocate resources in ctor. 336 | void Init() 337 | { 338 | white = true; 339 | memcpy( squares, 340 | "rnbqkbnr" 341 | "pppppppp" 342 | " " 343 | " " 344 | " " 345 | " " 346 | "PPPPPPPP" 347 | "RNBQKBNR", sizeof(squares) ); 348 | enpassant_target = SQUARE_INVALID; 349 | wking = true; 350 | wqueen = true; 351 | bking = true; 352 | bqueen = true; 353 | wking_square = e1; 354 | bking_square = e8; 355 | half_move_clock = 0; 356 | full_move_count = 1; 357 | } 358 | 359 | // Copy constructor and Assignment operator. Defining them this way 360 | // generates simple bitwise memory copy, which is exactly what we 361 | // want and is better practice than the old memcpy() versions (which 362 | // copy the vtable ptr as well - we don't want that). Thanks to GitHub 363 | // user metiscus for the pull request that fixed this. 364 | ChessPosition( const ChessPosition& src ) = default; 365 | ChessPosition& operator=( const ChessPosition& src ) = default; 366 | 367 | // Equality operator 368 | bool operator ==( const ChessPosition &other ) const 369 | { 370 | return( white == other.white && 371 | 0 == memcmp( &squares, &other.squares, 64 ) && 372 | groomed_enpassant_target() == other.groomed_enpassant_target() && 373 | wking_allowed() == other.wking_allowed() && 374 | wqueen_allowed() == other.wqueen_allowed() && 375 | bking_allowed() == other.bking_allowed() && 376 | bqueen_allowed() == other.bqueen_allowed() 377 | ); 378 | } 379 | 380 | // < Operator 381 | // Why do we want this elaborate operator? Well if we ever use the std 382 | // sort algorithm on ChessPosition objects we need a < operator with 383 | // the following properties (a and b are two ChessPositions); 384 | // 1) if a==b is true then aa6 && squares[idx-1]=='P' ) 436 | zap = false; // eg a5xb6 ep, through g5xh6 ep 437 | if( enpassant_target
a3 && squares[idx-1]=='p' ) 447 | zap = false; // eg a4xb3 ep, through g4xh3 ep 448 | if( enpassant_target

506 | ****************************************************************************/ 507 | #ifndef CHESSRULES_H 508 | #define CHESSRULES_H 509 | 510 | // TripleHappyChess 511 | namespace thc 512 | { 513 | 514 | // Class encapsulates state of game and operations available 515 | class ChessRules: public ChessPosition 516 | { 517 | public: 518 | // Default constructor 519 | ChessRules() : ChessPosition() { Init(); } 520 | void Init() // TODO == ChessRules::Init() should call ChessPosition::Init() right ????!!!! 521 | // Thoughts: Maybe - but can't do this casually. For example we would need to 522 | // change the code that converts ChessPosition to ChessRules below, both the 523 | // copy constructor and assignment operator use ChessRules::Init() at a time 524 | // when it would be disastrous to set the initial position (because 525 | // we have carefully copied a position into the ChessRules object) 526 | { 527 | history_idx = 1; // prevent bogus repetition draws 528 | history[0].src = a8; // (look backwards through history stops when src==dst) 529 | history[0].dst = a8; 530 | detail_idx =0; 531 | } 532 | 533 | // Copy constructor 534 | ChessRules( const ChessPosition& src ) : ChessPosition( src ) 535 | { 536 | Init(); // even if src is e.g. ChessRules or ChessEngine don't 537 | // copy stuff for repetition, 50 move rule 538 | } 539 | 540 | // Assignment operator 541 | ChessRules& operator=( const ChessPosition& src ) 542 | { 543 | *((ChessPosition *)this) = src; 544 | Init(); // even if src is e.g. ChessRules or ChessEngine don't 545 | // copy stuff for repetition, 50 move rule 546 | return *this; 547 | } 548 | 549 | // Test internals, for porting to new environments etc 550 | bool TestInternals( int (*log)(const char *,...) = NULL ); 551 | 552 | // Initialise from Forsyth string 553 | bool Forsyth( const char *txt ) 554 | { 555 | bool okay = ChessPosition::Forsyth(txt); 556 | if( okay ) 557 | Init(); // clear stuff for repetition, 50 move rule 558 | return okay; 559 | } 560 | 561 | // Test for legal position, sets reason to a mask of possibly multiple reasons 562 | bool IsLegal( ILLEGAL_REASON& reason ); 563 | 564 | // Play a move 565 | void PlayMove( Move imove ); 566 | 567 | // Check draw rules (50 move rule etc.) 568 | bool IsDraw( bool white_asks, DRAWTYPE &result ); 569 | 570 | // Get number of times position has been repeated 571 | int GetRepetitionCount(); 572 | 573 | // Check insufficient material draw rule 574 | bool IsInsufficientDraw( bool white_asks, DRAWTYPE &result ); 575 | 576 | // Evaluate a position, returns bool okay (not okay means illegal position) 577 | bool Evaluate(); 578 | bool Evaluate( TERMINAL &score_terminal ); 579 | 580 | // Is a square is attacked by enemy ? 581 | bool AttackedSquare( Square square, bool enemy_is_white ); 582 | 583 | // Determine if an occupied square is attacked 584 | bool AttackedPiece( Square square ); 585 | 586 | // Transform a position with W to move into an equivalent with B to move and vice-versa 587 | void Transform(); 588 | 589 | // Transform a W move in a transformed position to a B one and vice-versa 590 | Move Transform( Move m ); 591 | 592 | // Create a list of all legal moves in this position 593 | void GenLegalMoveList( std::vector &moves ); 594 | 595 | // Create a list of all legal moves in this position, with extra info 596 | void GenLegalMoveList( std::vector &moves, 597 | std::vector &check, 598 | std::vector &mate, 599 | std::vector &stalemate ); 600 | 601 | // Create a list of all legal moves in this position 602 | void GenLegalMoveList( MOVELIST *list ); 603 | 604 | // Create a list of all legal moves in this position, with extra info 605 | void GenLegalMoveList( MOVELIST *list, bool check[MAXMOVES], 606 | bool mate[MAXMOVES], 607 | bool stalemate[MAXMOVES] ); 608 | 609 | // Make a move (with the potential to undo) 610 | void PushMove( Move& m ); 611 | 612 | // Undo a move 613 | void PopMove( Move& m ); 614 | 615 | // Test fundamental internal assumptions and operations 616 | void TestInternals(); 617 | 618 | // Private stuff 619 | protected: 620 | 621 | // Generate a list of all possible moves in a position (including 622 | // illegally "moving into check") 623 | void GenMoveList( MOVELIST *l ); 624 | 625 | // Generate moves for pieces that move along multi-move rays (B,R,Q) 626 | void LongMoves( MOVELIST *l, Square square, const lte *ptr ); 627 | 628 | // Generate moves for pieces that move along single-move rays (K,N,P) 629 | void ShortMoves( MOVELIST *l, Square square, const lte *ptr, SPECIAL special ); 630 | 631 | // Generate list of king moves 632 | void KingMoves( MOVELIST *l, Square square ); 633 | 634 | // Generate list of white pawn moves 635 | void WhitePawnMoves( MOVELIST *l, Square square ); 636 | 637 | // Generate list of black pawn moves 638 | void BlackPawnMoves( MOVELIST *l, Square square ); 639 | 640 | // Evaluate a position, returns bool okay (not okay means illegal position) 641 | bool Evaluate( MOVELIST *list, TERMINAL &score_terminal ); 642 | 643 | //### Data 644 | 645 | // Move history is a ring array 646 | Move history[256]; // must be 256 .. 647 | unsigned char history_idx; // .. so this loops around naturally 648 | 649 | // Detail stack is a ring array 650 | DETAIL detail_stack[256]; // must be 256 .. 651 | unsigned char detail_idx; // .. so this loops around naturally 652 | }; 653 | 654 | } //namespace thc 655 | 656 | #endif //CHESSRULES_H 657 | /**************************************************************************** 658 | * ChessEvaluation.h Chess classes - Simple chess AI, leaf scoring function for position 659 | * Author: Bill Forster 660 | * License: MIT license. Full text of license is in associated file LICENSE 661 | * Copyright 2010-2020, Bill Forster 662 | ****************************************************************************/ 663 | #ifndef CHESSEVALUATION_H 664 | #define CHESSEVALUATION_H 665 | 666 | // TripleHappyChess 667 | namespace thc 668 | { 669 | 670 | class ChessEvaluation: public ChessRules 671 | { 672 | public: 673 | // Default constructor 674 | ChessEvaluation() : ChessRules() 675 | { 676 | } 677 | 678 | // Copy constructor 679 | ChessEvaluation( const ChessPosition& src ) : ChessRules( src ) 680 | { 681 | } 682 | 683 | // Assignment operator 684 | ChessEvaluation& operator=( const ChessPosition& src ) 685 | { 686 | *((ChessRules *)this) = src; 687 | return *this; 688 | } 689 | 690 | 691 | // Use leaf evaluator to generate a sorted move list 692 | void GenLegalMoveListSorted( MOVELIST *list ); 693 | void GenLegalMoveListSorted( std::vector &moves ); 694 | 695 | // Evaluate a position, leaf node (useful for playing programs) 696 | void EvaluateLeaf( int &material, int &positional ); 697 | 698 | // internal stuff 699 | protected: 700 | 701 | // Always some planning before calculating a move 702 | void Planning(); 703 | 704 | // Calculate material that side to play can win directly 705 | int Enprise(); 706 | int EnpriseWhite(); // fast white to move version 707 | int EnpriseBlack(); // fast black to move version 708 | 709 | // misc 710 | private: 711 | bool white_is_better; 712 | bool black_is_better; 713 | int planning_score_white_pieces; 714 | int planning_score_black_pieces; 715 | int planning_white_piece_pawn_percent; 716 | int planning_black_piece_pawn_percent; 717 | }; 718 | 719 | } //namespace thc 720 | 721 | #endif //CHESSEVALUATION_H 722 | -------------------------------------------------------------------------------- /src/HashLookup.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * HashLookup.h Quickly generate position hash codes with these lookup tables 3 | * Author: Bill Forster 4 | * License: MIT license. Full text of license is in associated file LICENSE 5 | * Copyright 2010-2020, Bill Forster 6 | ****************************************************************************/ 7 | static uint32_t hash_lookup[64]['r'-'B'+1] = 8 | { // B K N P Q R 9 | { 0x8c7f0aac,0,0,0,0,0,0,0,0,0x97c4aa2f,0,0,0xb716a675,0,0xd821ccc0,0x9a4eb343,0xdba252fb, // 'B'->'R' 10 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x8b7d76c3, // 'S'->'a', where 'a' is a proxy for ' ' or '.' 11 | 0xd8e57d67,0,0,0,0,0,0,0,0,0x6c74a409,0,0,0x9fa1ded3,0,0xa5595115,0x6266d6f2,0x7005b724 // 'b'->'r' 12 | }, 13 | { 0x4c2b3a57,0,0,0,0,0,0,0,0,0xe44b3c46,0,0,0x0e84bdd8,0,0xf6b29a58,0x45cccd8c,0x6229393a, // 'B'->'R' 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7a4842c1, 15 | 0xcaae7de6,0,0,0,0,0,0,0,0,0xcfea4a27,0,0,0x8765a857,0,0x7adfc8ae,0x916b5e58,0x648d8b51 // 'b'->'r' 16 | }, 17 | { 0xecf3e6a5,0,0,0,0,0,0,0,0,0xd6094219,0,0,0x122f6b4d,0,0x565f9848,0x164e1b09,0xa5ee9794, // 'B'->'R' 18 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x052d0873, 19 | 0x5e4513d0,0,0,0,0,0,0,0,0,0xd52692f3,0,0,0xf5081ec5,0,0xc73547fe,0x23ee074f,0xdeb91daf // 'b'->'r' 20 | }, 21 | { 0xdebe09c0,0,0,0,0,0,0,0,0,0xfa86bb52,0,0,0x793e6063,0,0xcc95a7d8,0xcd087cb1,0x762382f3, // 'B'->'R' 22 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x853e031d, 23 | 0xc7d0c293,0,0,0,0,0,0,0,0,0xadcb0c93,0,0,0x1e473b8e,0,0xb87b61a7,0xa3d1dd20,0x94ff3fc1 // 'b'->'r' 24 | }, 25 | { 0x24b2cd09,0,0,0,0,0,0,0,0,0x89914ab9,0,0,0xf1d5d27f,0,0xc234a220,0x8597da1f,0x1b1cc2ca, // 'B'->'R' 26 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x6a2748f4, 27 | 0x793de097,0,0,0,0,0,0,0,0,0x43b9eaa3,0,0,0x2fb379fe,0,0xc6342dcb,0xbca6ab72,0x74c644b7 // 'b'->'r' 28 | }, 29 | { 0x376fd81c,0,0,0,0,0,0,0,0,0x9184e322,0,0,0x229da880,0,0x04cf6880,0x52fae7a4,0x9e1d5c35, // 'B'->'R' 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x26511785, 31 | 0x9cb24e26,0,0,0,0,0,0,0,0,0x38ea0de8,0,0,0x9def62f4,0,0x62f0f111,0xf199794f,0xe710b184 // 'b'->'r' 32 | }, 33 | { 0xae8bc669,0,0,0,0,0,0,0,0,0x732fec2a,0,0,0x5c08b5ba,0,0x9cf1ba1f,0x6fe15378,0xe7005101, // 'B'->'R' 34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb297f541, 35 | 0x196a6fe7,0,0,0,0,0,0,0,0,0x0f6aefa9,0,0,0xf8456839,0,0xaab13923,0xa7342f66,0xabaeec77 // 'b'->'r' 36 | }, 37 | { 0x2bc0bb0b,0,0,0,0,0,0,0,0,0x35dba1ae,0,0,0x5bafdc52,0,0x2101505b,0xc02cf780,0x50bfe98e, // 'B'->'R' 38 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x9b9aca63, 39 | 0x5d1c2635,0,0,0,0,0,0,0,0,0x53364b8c,0,0,0x91f86a79,0,0x09d63faa,0x70483054,0xa25fc8cb // 'b'->'r' 40 | }, 41 | { 0xfd061144,0,0,0,0,0,0,0,0,0xf57db306,0,0,0x1a1f9bc4,0,0xa71d442f,0x3578f27f,0xa29337f4, // 'B'->'R' 42 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x294b9483, 43 | 0xfecbf3cc,0,0,0,0,0,0,0,0,0xa7321b64,0,0,0x94f424b4,0,0x40d7b7e8,0x6a140f4e,0x7760248f // 'b'->'r' 44 | }, 45 | { 0x7985c694,0,0,0,0,0,0,0,0,0x3e92ace3,0,0,0x9f9e5bba,0,0x28b23b17,0x5687aacf,0x1c418b8d, // 'B'->'R' 46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xacbc9175, 47 | 0xa8053755,0,0,0,0,0,0,0,0,0x51342230,0,0,0x235ff531,0,0xc741a645,0x325338a9,0xf31716a3 // 'b'->'r' 48 | }, 49 | { 0x5e64c5c0,0,0,0,0,0,0,0,0,0xa99b5c5f,0,0,0xd22c9cc5,0,0x03796e5e,0x18dba100,0x9f72d771, // 'B'->'R' 50 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd6838eb2, 51 | 0xac74f524,0,0,0,0,0,0,0,0,0x1899e7a2,0,0,0xf8d16330,0,0xf9f93f5d,0xe0d14983,0x77f98662 // 'b'->'r' 52 | }, 53 | { 0x8276be2a,0,0,0,0,0,0,0,0,0xfa0d03cd,0,0,0x0e435170,0,0x9ad727e7,0x737f2b95,0xbd4060c9, // 'B'->'R' 54 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x051de97f, 55 | 0x0a083600,0,0,0,0,0,0,0,0,0x7113f78a,0,0,0x48660972,0,0xfac6322b,0x1ec533ba,0x5c048d7f // 'b'->'r' 56 | }, 57 | { 0x4bcfd817,0,0,0,0,0,0,0,0,0x7b1bd6bb,0,0,0x1e64f082,0,0xb04c1979,0x51675862,0xe166de3e, // 'B'->'R' 58 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x6a0d23a3, 59 | 0xeb117ade,0,0,0,0,0,0,0,0,0x106bf87b,0,0,0x3781a7c3,0,0xb145da52,0x90b037ae,0x910ccae3 // 'b'->'r' 60 | }, 61 | { 0xdd775c94,0,0,0,0,0,0,0,0,0x43f090d1,0,0,0x824bca32,0,0x85f3959b,0xeaae5b0e,0x180c7c29, // 'B'->'R' 62 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xebd0fc3a, 63 | 0x93713ac1,0,0,0,0,0,0,0,0,0x1546dc24,0,0,0xede65b0a,0,0x47189056,0x518dbc2b,0x02653368 // 'b'->'r' 64 | }, 65 | { 0xaadb680b,0,0,0,0,0,0,0,0,0xd7a3bb02,0,0,0x21bd8133,0,0xa5ad3450,0xb7613820,0xd76514b6, // 'B'->'R' 66 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4a168480, 67 | 0x43c55b26,0,0,0,0,0,0,0,0,0x2ee5a113,0,0,0x65d794ae,0,0x9625b62a,0x8d85b573,0x0525c4b8 // 'b'->'r' 68 | }, 69 | { 0x2a3989bc,0,0,0,0,0,0,0,0,0xd43569e8,0,0,0x5eabbe4d,0,0x0133b91e,0x257d3518,0xad85627d, // 'B'->'R' 70 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x91d28302, 71 | 0x451f3e03,0,0,0,0,0,0,0,0,0xb428205e,0,0,0xbc35ace2,0,0x49d9976b,0xf651fd0d,0x6eebf770 // 'b'->'r' 72 | }, 73 | { 0x3fae4928,0,0,0,0,0,0,0,0,0xc1903548,0,0,0x937f0c13,0,0x6566b25f,0x97900f48,0xe562c59a, // 'B'->'R' 74 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x927f19c2, 75 | 0xa39054f8,0,0,0,0,0,0,0,0,0x391be0b4,0,0,0xe43ce943,0,0xf3e75bec,0xae181f3d,0x7276cf0e // 'b'->'r' 76 | }, 77 | { 0x72fe9f60,0,0,0,0,0,0,0,0,0xd8ae3d04,0,0,0xfa839fc3,0,0xb31112ed,0x1dbf688b,0x4c24d3fc, // 'B'->'R' 78 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc45baa56, 79 | 0xd0550dcd,0,0,0,0,0,0,0,0,0x696d0b79,0,0,0x6581666d,0,0xace9934b,0xe18ffab8,0x3ff2a610 // 'b'->'r' 80 | }, 81 | { 0x94ce4c98,0,0,0,0,0,0,0,0,0x502f139d,0,0,0xe1b96895,0,0xf725846e,0xb149c019,0x96a5a5d0, // 'B'->'R' 82 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb9aa43bc, 83 | 0xa8e00779,0,0,0,0,0,0,0,0,0x8056cb76,0,0,0x88803475,0,0xf4c1e5bd,0x3b043653,0xa4dc8aa1 // 'b'->'r' 84 | }, 85 | { 0x65162768,0,0,0,0,0,0,0,0,0x6c81c3a0,0,0,0x9e6a3ce4,0,0x9b3c95fb,0x7990eafb,0x04e9d879, // 'B'->'R' 86 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x785a9546, 87 | 0x4d3401d5,0,0,0,0,0,0,0,0,0xb750a91f,0,0,0xa901220d,0,0x49b9c747,0x4a4286b8,0x622a9498 // 'b'->'r' 88 | }, 89 | { 0x9e36424f,0,0,0,0,0,0,0,0,0xbfc99829,0,0,0x6dc3c912,0,0xe0e23e28,0x22ae6db6,0x1a5540cf, // 'B'->'R' 90 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4c5c3b0b, 91 | 0x17a5d0a6,0,0,0,0,0,0,0,0,0x91e9386f,0,0,0x5aa2cd5d,0,0x97436ff9,0x8d43d481,0x9306fadf // 'b'->'r' 92 | }, 93 | { 0x089ba776,0,0,0,0,0,0,0,0,0xa7382b2c,0,0,0xf80de0d8,0,0xa6f03d7d,0x522ce018,0x6e717043, // 'B'->'R' 94 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x38a4abd2, 95 | 0xe58413ef,0,0,0,0,0,0,0,0,0x2429df03,0,0,0x5e1888ea,0,0x18e606cc,0x6f94d7e6,0xfbea3123 // 'b'->'r' 96 | }, 97 | { 0xe45516d6,0,0,0,0,0,0,0,0,0x42a5b3fe,0,0,0xce62babd,0,0x897a4ec5,0xb4320ad7,0x72ab4a2b, // 'B'->'R' 98 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x19a87820, 99 | 0x197d5c0b,0,0,0,0,0,0,0,0,0xeb633668,0,0,0x5a3118d4,0,0xb6d8848a,0x7820b6b6,0xffb46feb // 'b'->'r' 100 | }, 101 | { 0xd754f5a5,0,0,0,0,0,0,0,0,0x26423e7d,0,0,0xe796fe9c,0,0xde3d826f,0x099d7de8,0x29992302, // 'B'->'R' 102 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x8220f61b, 103 | 0x9d954fd3,0,0,0,0,0,0,0,0,0x2ab684d9,0,0,0x1fb2aa97,0,0xc76fe335,0xd9171133,0xdd6c44ae // 'b'->'r' 104 | }, 105 | { 0xceac7494,0,0,0,0,0,0,0,0,0x69514bb5,0,0,0x91b0961d,0,0x23d53e43,0x683d2a23,0x08814327, // 'B'->'R' 106 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x11b4ed89, 107 | 0xfb8a0849,0,0,0,0,0,0,0,0,0xb28ab129,0,0,0x5f8ffb97,0,0x741b5f83,0x6b8a0f2e,0xb8d8a2da // 'b'->'r' 108 | }, 109 | { 0x0cf357b2,0,0,0,0,0,0,0,0,0xddcb3b6c,0,0,0x5d912703,0,0xf9bbc71f,0x0441bb09,0xdb15ed8a, // 'B'->'R' 110 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3b11ee1b, 111 | 0x02ffb1ad,0,0,0,0,0,0,0,0,0xc3d140c7,0,0,0x5c2785a7,0,0xf1b2143d,0xbae0a955,0xbffff361 // 'b'->'r' 112 | }, 113 | { 0x2befec2c,0,0,0,0,0,0,0,0,0x56e32b22,0,0,0x8562a7a2,0,0x7d531458,0x0de91821,0x56c7ba85, // 'B'->'R' 114 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3332f8e8, 115 | 0x2df312ff,0,0,0,0,0,0,0,0,0x04bdd824,0,0,0x2bc5c700,0,0xcb2fc5cb,0x76a4b922,0x395320c5 // 'b'->'r' 116 | }, 117 | { 0xdfe4037e,0,0,0,0,0,0,0,0,0x5868f7b5,0,0,0xf1b1d4fe,0,0xed96bc50,0x9bb675be,0xb4548088, // 'B'->'R' 118 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x98be68bd, 119 | 0x08269881,0,0,0,0,0,0,0,0,0xc89ce8d1,0,0,0x2a296570,0,0x8001b923,0x9f193578,0x0ce50d5b // 'b'->'r' 120 | }, 121 | { 0x93c540a8,0,0,0,0,0,0,0,0,0xb2f81774,0,0,0x3ce68b24,0,0xfe0db0b0,0xef28a619,0x446b5143, // 'B'->'R' 122 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x9d2cdf67, 123 | 0xadd8e1fc,0,0,0,0,0,0,0,0,0x891f3b23,0,0,0xdd418c72,0,0x9704571e,0xc037541d,0xbae946f1 // 'b'->'r' 124 | }, 125 | { 0xf6e8cd21,0,0,0,0,0,0,0,0,0x4fdba092,0,0,0x8de2d511,0,0x65f1d0dd,0x365f3954,0x35b851fd, // 'B'->'R' 126 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x38f20a02, 127 | 0x2faa5845,0,0,0,0,0,0,0,0,0x37fff565,0,0,0xf1c2638c,0,0x91cf922c,0xbd533375,0x73bd6afd // 'b'->'r' 128 | }, 129 | { 0x7d8eb542,0,0,0,0,0,0,0,0,0xf8616e6f,0,0,0x3a37d85b,0,0xae382d55,0x411d81a7,0x15d5ee27, // 'B'->'R' 130 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x0edaffcb, 131 | 0x0e716e96,0,0,0,0,0,0,0,0,0x6f35ed9e,0,0,0x7ce2ee91,0,0x4fd1dac6,0xe18983c7,0xb2439112 // 'b'->'r' 132 | }, 133 | { 0xf9f5a35c,0,0,0,0,0,0,0,0,0x60b4582b,0,0,0x9e1ed453,0,0x2dfa81b1,0x8ae13329,0x0651585d, // 'B'->'R' 134 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xdac7f4ae, 135 | 0x11374595,0,0,0,0,0,0,0,0,0xbe6bf0c9,0,0,0xadecaf59,0,0x7a8549f2,0x742579e0,0xad5537db // 'b'->'r' 136 | }, 137 | { 0x895d4149,0,0,0,0,0,0,0,0,0x9b674e1c,0,0,0xe58c3feb,0,0xb6f660d1,0xfd86da69,0x7830f7ba, // 'B'->'R' 138 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x37868f80, 139 | 0x74bd5fd6,0,0,0,0,0,0,0,0,0xa9bf7e3f,0,0,0xe80b0410,0,0x4369186a,0x2320e0a4,0x0549625e // 'b'->'r' 140 | }, 141 | { 0x3aae1e18,0,0,0,0,0,0,0,0,0xc2251a74,0,0,0xe1af94bf,0,0x51eca4c3,0xe7886533,0x622ab088, // 'B'->'R' 142 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa55223b8, 143 | 0x969bf35b,0,0,0,0,0,0,0,0,0x531e6c5d,0,0,0xd4bf977b,0,0x850bcaee,0xa104f457,0x0003a0a0 // 'b'->'r' 144 | }, 145 | { 0xdf660893,0,0,0,0,0,0,0,0,0x4fd61248,0,0,0x4606d9c7,0,0x6cea6457,0xcc4ccc0d,0xe2a57d3a, // 'B'->'R' 146 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x2f85d651, 147 | 0xae0c9478,0,0,0,0,0,0,0,0,0xf3ea2774,0,0,0x74c4ebb7,0,0xafff3b40,0x7bc0aacb,0x372b82dc // 'b'->'r' 148 | }, 149 | { 0xc9ead3a4,0,0,0,0,0,0,0,0,0xf286e119,0,0,0x3abcb320,0,0xbb195daa,0xe15b2f0e,0x410251d6, // 'B'->'R' 150 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x504e251c, 151 | 0x369b9d14,0,0,0,0,0,0,0,0,0xf51b7fd2,0,0,0x84a8cd44,0,0x78c4b616,0x0691d4e3,0xb62a5b7a // 'b'->'r' 152 | }, 153 | { 0x351cc253,0,0,0,0,0,0,0,0,0x27588287,0,0,0x6cb82fc8,0,0xbafe423d,0x5fc99a8d,0xa5719605, // 'B'->'R' 154 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x76ace100, 155 | 0x37026c88,0,0,0,0,0,0,0,0,0x4712accf,0,0,0x2fbbb9cf,0,0x96377fb5,0xcebd948b,0xdd25a404 // 'b'->'r' 156 | }, 157 | { 0xbf4099a7,0,0,0,0,0,0,0,0,0x1e16915c,0,0,0xacc2cbad,0,0x8472f51a,0x46e2824a,0x21cf3734, // 'B'->'R' 158 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x2cc6d3ee, 159 | 0xb7841db1,0,0,0,0,0,0,0,0,0xb4586cdb,0,0,0x65642b33,0,0x769102e3,0x90bf7369,0xd7265312 // 'b'->'r' 160 | }, 161 | { 0x2eeb6d75,0,0,0,0,0,0,0,0,0x34721522,0,0,0x2514be33,0,0x2a3abe9e,0x7cf141b5,0x1ff50f3a, // 'B'->'R' 162 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x5b096fab, 163 | 0xb8da4737,0,0,0,0,0,0,0,0,0xf0c025fc,0,0,0x07cbc3fc,0,0xc3ec5b12,0xbf3b03ad,0xbfa86b57 // 'b'->'r' 164 | }, 165 | { 0x17b461c1,0,0,0,0,0,0,0,0,0xe75a2d46,0,0,0x37aad5ea,0,0x155b2c35,0xbfcf2330,0x8d5c7c5e, // 'B'->'R' 166 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xbb50483b, 167 | 0x95a03950,0,0,0,0,0,0,0,0,0x0bad669a,0,0,0xf641767c,0,0x358b50a3,0x4aca2e3a,0x497343b1 // 'b'->'r' 168 | }, 169 | { 0x3da6f46a,0,0,0,0,0,0,0,0,0xad6120c9,0,0,0x19acdd2c,0,0x1023470d,0x0434bb79,0x8e3f0746, // 'B'->'R' 170 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xedf5a226, 171 | 0x025d8ea7,0,0,0,0,0,0,0,0,0xab7fa688,0,0,0xd541fc0d,0,0xc8ffc7f8,0xfbfd0387,0x481f76d0 // 'b'->'r' 172 | }, 173 | { 0xb4183bf8,0,0,0,0,0,0,0,0,0x961efa16,0,0,0x2e7f61f8,0,0x105f5f4f,0x832c37d9,0x7c521708, // 'B'->'R' 174 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x94982ee3, 175 | 0xfa3d1f06,0,0,0,0,0,0,0,0,0xc99c5cd1,0,0,0xe062a5c7,0,0x9b41f9d4,0x569195d9,0x37e93fc2 // 'b'->'r' 176 | }, 177 | { 0xf629763c,0,0,0,0,0,0,0,0,0x7485f190,0,0,0x3b50cc38,0,0xe0fd9b72,0xf3068eed,0x7e054a97, // 'B'->'R' 178 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xf0fe2118, 179 | 0xb72f0404,0,0,0,0,0,0,0,0,0xcc988a64,0,0,0x7c74f3ec,0,0xa1650931,0xb5636957,0xdfd1561e // 'b'->'r' 180 | }, 181 | { 0x7f861e36,0,0,0,0,0,0,0,0,0x4b036099,0,0,0xd8346f14,0,0xd9545d61,0x31c06965,0x9e2d2ab9, // 'B'->'R' 182 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc5f8b197, 183 | 0x03637d9b,0,0,0,0,0,0,0,0,0xf969041d,0,0,0x58e44ba1,0,0xdcc05573,0x25ec8f35,0xc7ca0a77 // 'b'->'r' 184 | }, 185 | { 0xfb592bb3,0,0,0,0,0,0,0,0,0xfc2b1356,0,0,0x7a7679f6,0,0xc0e9f007,0x7f550a69,0x01094bf1, // 'B'->'R' 186 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa3b47889, 187 | 0x44fc9ab6,0,0,0,0,0,0,0,0,0x5e5b8f80,0,0,0x69160353,0,0x230be578,0x6da013a4,0xd2764ed1 // 'b'->'r' 188 | }, 189 | { 0x4c3f5c94,0,0,0,0,0,0,0,0,0x3099df75,0,0,0x66b09bf0,0,0x82e5cd03,0x1ee3607e,0x396cd72a, // 'B'->'R' 190 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xfb0f2241, 191 | 0x190c5614,0,0,0,0,0,0,0,0,0x67f78324,0,0,0xdcb89544,0,0x91b7cbd0,0xf9114070,0x57f687af // 'b'->'r' 192 | }, 193 | { 0xf5f9428a,0,0,0,0,0,0,0,0,0xc9f390ed,0,0,0xe8140568,0,0x694fb3de,0xc627f75b,0x5bf9362b, // 'B'->'R' 194 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x5549003f, 195 | 0x66458f9f,0,0,0,0,0,0,0,0,0x14c30f94,0,0,0x4d44c9c6,0,0x6840f509,0xc674cdbc,0x3b73b25b // 'b'->'r' 196 | }, 197 | { 0xed1c4a6f,0,0,0,0,0,0,0,0,0x21eab5a3,0,0,0x53478953,0,0x0dad674c,0xf3ef5512,0xb9c08d71, // 'B'->'R' 198 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x03921f4a, 199 | 0x02ece8e2,0,0,0,0,0,0,0,0,0x889134e1,0,0,0xc544c7ab,0,0x4df91683,0x259e4b8c,0xe2031ce4 // 'b'->'r' 200 | }, 201 | { 0x145b8f3a,0,0,0,0,0,0,0,0,0x4028cf81,0,0,0x16f03971,0,0xad6adc80,0xac0b5327,0xcf77f418, // 'B'->'R' 202 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3ed062ba, 203 | 0x6ea14124,0,0,0,0,0,0,0,0,0x6ba87963,0,0,0xc08be345,0,0x8eafb886,0xd460d003,0xdc4d14e2 // 'b'->'r' 204 | }, 205 | { 0x61085b79,0,0,0,0,0,0,0,0,0xba1f92a8,0,0,0x18b779bc,0,0x453435a1,0x41925d1c,0x21a8db44, // 'B'->'R' 206 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x9789101a, 207 | 0x0e2d02e0,0,0,0,0,0,0,0,0,0x79fa68f8,0,0,0x4d35916d,0,0x7ce947b3,0x431a2cc9,0x756135b5 // 'b'->'r' 208 | }, 209 | { 0x74c5a0c5,0,0,0,0,0,0,0,0,0x864bb3a1,0,0,0xaeeb8687,0,0x7127ea7d,0xb214825e,0xda464848, // 'B'->'R' 210 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4894b0f6, 211 | 0x6ef5db54,0,0,0,0,0,0,0,0,0x6142e487,0,0,0xd3adc6c3,0,0x2e5fe8d5,0x82643ddb,0xc9de1e6c // 'b'->'r' 212 | }, 213 | { 0x161ccd43,0,0,0,0,0,0,0,0,0x0e8d9866,0,0,0xa8f85f54,0,0xb26e6947,0x34e36253,0xc75894df, // 'B'->'R' 214 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd8e70900, 215 | 0xc7042e85,0,0,0,0,0,0,0,0,0xae6d8d5b,0,0,0x4269846b,0,0x2da97b9e,0x5fb237c9,0x11e247d3 // 'b'->'r' 216 | }, 217 | { 0x966cee07,0,0,0,0,0,0,0,0,0x027aec95,0,0,0x45d7a7e5,0,0xe45d5ddc,0x5ef03588,0x222ac6ab, // 'B'->'R' 218 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3272262e, 219 | 0xc7792000,0,0,0,0,0,0,0,0,0x75b91d68,0,0,0xecd782b3,0,0x0b6bb626,0xb715f459,0xccbf6c4a // 'b'->'r' 220 | }, 221 | { 0x7da649f3,0,0,0,0,0,0,0,0,0x13b36ae2,0,0,0x78310a7b,0,0x84d26157,0xe1f93c60,0x4e8b1b53, // 'B'->'R' 222 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7d08711a, 223 | 0x93d9dace,0,0,0,0,0,0,0,0,0x6a211820,0,0,0xf59d6c73,0,0x2c9299c6,0xa5441761,0x79ac91ac // 'b'->'r' 224 | }, 225 | { 0x090d833b,0,0,0,0,0,0,0,0,0xc89d2739,0,0,0x6e2edab2,0,0x8e7228ad,0x829076e9,0x28ed0c84, // 'B'->'R' 226 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x8942edb9, 227 | 0x24d2005d,0,0,0,0,0,0,0,0,0xae6fbd5b,0,0,0xa6433591,0,0x471089a3,0x8a0a8ec2,0x20fd0194 // 'b'->'r' 228 | }, 229 | { 0x536013ad,0,0,0,0,0,0,0,0,0x648664b9,0,0,0x25a2b3cf,0,0xf4d70177,0x28ed3ea4,0x2fe7cf69, // 'B'->'R' 230 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x21212abe, 231 | 0xe76b7e04,0,0,0,0,0,0,0,0,0x943441f1,0,0,0x8b36ddf2,0,0x179e5ccd,0x74f8259e,0xe919756d // 'b'->'r' 232 | }, 233 | { 0xe1cd7757,0,0,0,0,0,0,0,0,0x153da2e2,0,0,0x756711a3,0,0xcce59a49,0xb9630cda,0xe08ba7b7, // 'B'->'R' 234 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x6626861a, 235 | 0x17ecf576,0,0,0,0,0,0,0,0,0xe76f7416,0,0,0x6d2261cc,0,0xb0a57acf,0x7924fd62,0xb31a6e5a // 'b'->'r' 236 | }, 237 | { 0x9487cc33,0,0,0,0,0,0,0,0,0x53e57be6,0,0,0xb75bc72e,0,0xc1bc3ed0,0x06edfe3d,0xa2d4e5bc, // 'B'->'R' 238 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xbb3cdb2f, 239 | 0x3d71f7fa,0,0,0,0,0,0,0,0,0xc457b868,0,0,0x29191280,0,0x02800d8a,0xcbe04fcb,0x4eebd78d // 'b'->'r' 240 | }, 241 | { 0xf58bf147,0,0,0,0,0,0,0,0,0x3b9d125e,0,0,0x75489606,0,0x80e09ead,0x974abcf5,0xf427159e, // 'B'->'R' 242 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xdb93b60f, 243 | 0x8eccb8a9,0,0,0,0,0,0,0,0,0x750c98a6,0,0,0x18f3b535,0,0xf3ae0bab,0x9f265252,0x93646d87 // 'b'->'r' 244 | }, 245 | { 0xdcef0cdc,0,0,0,0,0,0,0,0,0xd21dcb41,0,0,0x285a96a9,0,0xe8a9fb42,0xfe0fdc72,0xd0c62b5c, // 'B'->'R' 246 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x15c2a14e, 247 | 0x28cf62e5,0,0,0,0,0,0,0,0,0x182e64db,0,0,0xa0ff7cf6,0,0xa2342064,0x65ffc99f,0xf30528dd // 'b'->'r' 248 | }, 249 | { 0x100df4b2,0,0,0,0,0,0,0,0,0xefce9dfc,0,0,0x6c8d60ae,0,0x7287625d,0x42391e72,0xba4a4ea1, // 'B'->'R' 250 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd95a930c, 251 | 0xbe034ee0,0,0,0,0,0,0,0,0,0x0886a6e9,0,0,0x4e96a350,0,0xf57fe442,0x1ea955c8,0x5af973f3 // 'b'->'r' 252 | }, 253 | { 0x71a2087d,0,0,0,0,0,0,0,0,0x5b51248a,0,0,0x644b5270,0,0x042e1ada,0x8827449b,0x2f6b62b8, // 'B'->'R' 254 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd8695c78, 255 | 0x66b8f141,0,0,0,0,0,0,0,0,0x894949c0,0,0,0xede60ac5,0,0xae262f58,0x19805d22,0x9bf30fcf // 'b'->'r' 256 | }, 257 | { 0xf1ff4803,0,0,0,0,0,0,0,0,0x1935dabc,0,0,0xde96ccee,0,0x178f1ea5,0x7443fcab,0x0e53c6d3, // 'B'->'R' 258 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x53a2ab58, 259 | 0x1626fe46,0,0,0,0,0,0,0,0,0x3b951e94,0,0,0x3cb76386,0,0x9d4d8f1c,0xd6ea5273,0x08779386 // 'b'->'r' 260 | }, 261 | { 0x85ba1342,0,0,0,0,0,0,0,0,0x03fec25c,0,0,0x8358dfdc,0,0x6dc58e66,0xa65b6365,0x116d4d7b, // 'B'->'R' 262 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x8b6a4ec5, 263 | 0x407f346d,0,0,0,0,0,0,0,0,0x084fa549,0,0,0x389e0064,0,0x9484d2b6,0x40d1234d,0xc5661795 // 'b'->'r' 264 | } 265 | }; 266 | 267 | static uint64_t hash64_lookup[64]['r'-'B'+1] = 268 | { 269 | { 0x218cd5fb8c7f0aac,0,0,0,0,0,0,0,0,0x6050629f97c4aa2f,0,0, // 'B'->'K'+2 270 | 0x0314ce51b716a675,0,0x7db3cc23d821ccc0,0x1d9060ed9a4eb343,0xfb4cbcf3dba252fb, // 'N'->'R' 271 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x9e54b8fa8b7d76c3, // 'S'->'a', where 'a' is a proxy for ' ' or '.' 272 | 0x3ea17988d8e57d67,0,0,0,0,0,0,0,0,0xf968dafe6c74a409,0,0, // 'b'->'k'+2 273 | 0x5fd3a5199fa1ded3,0,0xfd874015a5595115,0x0bb059ad6266d6f2,0x68b7c4e57005b724 // 'n'->'r' 274 | }, 275 | { 0x4f6097d64c2b3a57,0,0,0,0,0,0,0,0,0x29b76190e44b3c46,0,0, // 'B'->'K'+2 276 | 0xd4de74990e84bdd8,0,0xa385e3eef6b29a58,0xce990c7745cccd8c,0x7d84a6a56229393a, // 'N'->'R' 277 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa3d89f7f7a4842c1, 278 | 0xfd49f581caae7de6,0,0,0,0,0,0,0,0,0x5e3bf585cfea4a27,0,0, // 'b'->'k'+2 279 | 0x10b7c6c68765a857,0,0x5010998c7adfc8ae,0xc8820d5a916b5e58,0xcd45224a648d8b51 // 'n'->'r' 280 | }, 281 | { 0x49d47bfbecf3e6a5,0,0,0,0,0,0,0,0,0x1208d3b6d6094219,0,0, // 'B'->'K'+2 282 | 0x3dcd9c4e122f6b4d,0,0xaefea33e565f9848,0xa999e648164e1b09,0x617778c7a5ee9794, // 'N'->'R' 283 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3efdff2d052d0873, 284 | 0xa2494c855e4513d0,0,0,0,0,0,0,0,0,0xaa75be2fd52692f3,0,0, // 'b'->'k'+2 285 | 0xed47f2bbf5081ec5,0,0x846e54aac73547fe,0xda9bd1c323ee074f,0x6c91188adeb91daf // 'n'->'r' 286 | }, 287 | { 0x7f67d2f2debe09c0,0,0,0,0,0,0,0,0,0x8e000539fa86bb52,0,0, // 'B'->'K'+2 288 | 0x6d868ddb793e6063,0,0x497c3559cc95a7d8,0xd2934183cd087cb1,0xb4e2147d762382f3, // 'N'->'R' 289 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xbcfc6ace853e031d, 290 | 0x6a340f52c7d0c293,0,0,0,0,0,0,0,0,0x727804c5adcb0c93,0,0, // 'b'->'k'+2 291 | 0x5c4cb6ba1e473b8e,0,0xf80a0784b87b61a7,0xd422dc11a3d1dd20,0x5cf822c594ff3fc1 // 'n'->'r' 292 | }, 293 | { 0xeccaa1bf24b2cd09,0,0,0,0,0,0,0,0,0x65c4c15e89914ab9,0,0, // 'B'->'K'+2 294 | 0x0bc72298f1d5d27f,0,0xbd1a4e83c234a220,0x3b8d71458597da1f,0x72f721a81b1cc2ca, // 'N'->'R' 295 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x593890a46a2748f4, 296 | 0xeff1de3a793de097,0,0,0,0,0,0,0,0,0xd0a1a4b143b9eaa3,0,0, // 'b'->'k'+2 297 | 0x41da0db72fb379fe,0,0xfc492a98c6342dcb,0x61bb02a1bca6ab72,0xf80e879274c644b7 // 'n'->'r' 298 | }, 299 | { 0xb277df61376fd81c,0,0,0,0,0,0,0,0,0xe7aab1ce9184e322,0,0, // 'B'->'K'+2 300 | 0xe5a662f1229da880,0,0x4beb1c8704cf6880,0x1efdc7b552fae7a4,0xfdf472eb9e1d5c35, // 'N'->'R' 301 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x3dd5f02e26511785, 302 | 0x3fd9fdf09cb24e26,0,0,0,0,0,0,0,0,0x3a6f7bf438ea0de8,0,0, // 'b'->'k'+2 303 | 0x1b1caa7f9def62f4,0,0x7d507ba162f0f111,0xf371a151f199794f,0xe43ad49de710b184 // 'n'->'r' 304 | }, 305 | { 0x3bc16e0cae8bc669,0,0,0,0,0,0,0,0,0x5bacee76732fec2a,0,0, // 'B'->'K'+2 306 | 0xb094a72e5c08b5ba,0,0x629eeb769cf1ba1f,0x0ef071206fe15378,0xeaae9f22e7005101, // 'N'->'R' 307 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xbb0fc073b297f541, 308 | 0x1d231657196a6fe7,0,0,0,0,0,0,0,0,0xe1b86a7c0f6aefa9,0,0, // 'b'->'k'+2 309 | 0xa1917199f8456839,0,0x45be6caeaab13923,0x220029f2a7342f66,0x6109df6babaeec77 // 'n'->'r' 310 | }, 311 | { 0x5fce7e342bc0bb0b,0,0,0,0,0,0,0,0,0x5fd1dfe935dba1ae,0,0, // 'B'->'K'+2 312 | 0x530c326e5bafdc52,0,0xbfb096402101505b,0xae1c0d4cc02cf780,0x3ce0ef7650bfe98e, // 'N'->'R' 313 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xcba82a499b9aca63, 314 | 0x2bfe90925d1c2635,0,0,0,0,0,0,0,0,0x8101cb0453364b8c,0,0, // 'b'->'k'+2 315 | 0x7304c70791f86a79,0,0x4bd68a8309d63faa,0x4df1a43070483054,0xe2ce6c4ca25fc8cb // 'n'->'r' 316 | }, 317 | { 0xd6d51925fd061144,0,0,0,0,0,0,0,0,0x5a143074f57db306,0,0, // 'B'->'K'+2 318 | 0x3cdca5ed1a1f9bc4,0,0xbd072630a71d442f,0x809c986d3578f27f,0x8e2c27d2a29337f4, // 'N'->'R' 319 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xf14d28b3294b9483, 320 | 0x3396aa31fecbf3cc,0,0,0,0,0,0,0,0,0xa24dac47a7321b64,0,0, // 'b'->'k'+2 321 | 0x8c6bbf5a94f424b4,0,0xde06adb140d7b7e8,0x85074fee6a140f4e,0xf0b1951d7760248f // 'n'->'r' 322 | }, 323 | { 0x5949d2037985c694,0,0,0,0,0,0,0,0,0xc032204a3e92ace3,0,0, // 'B'->'K'+2 324 | 0x064d7e549f9e5bba,0,0xb31759ea28b23b17,0x2619ad415687aacf,0xf7cc97771c418b8d, // 'N'->'R' 325 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x21c10e14acbc9175, 326 | 0xfe910cd0a8053755,0,0,0,0,0,0,0,0,0xb53a142a51342230,0,0, // 'b'->'k'+2 327 | 0x73aa95f2235ff531,0,0xb585c01cc741a645,0x1224859a325338a9,0x9c9b8b57f31716a3 // 'n'->'r' 328 | }, 329 | { 0x4af48cb45e64c5c0,0,0,0,0,0,0,0,0,0xac021930a99b5c5f,0,0, // 'B'->'K'+2 330 | 0x2700b7c2d22c9cc5,0,0x7290666603796e5e,0x6ae0630918dba100,0xb2321d029f72d771, // 'N'->'R' 331 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x219c2d74d6838eb2, 332 | 0x60d9fb6cac74f524,0,0,0,0,0,0,0,0,0x9aa776e91899e7a2,0,0, // 'b'->'k'+2 333 | 0x199bb359f8d16330,0,0x61ffb57cf9f93f5d,0xf5d36375e0d14983,0xe538026477f98662 // 'n'->'r' 334 | }, 335 | { 0x128b105a8276be2a,0,0,0,0,0,0,0,0,0xf7c16444fa0d03cd,0,0, // 'B'->'K'+2 336 | 0x04f0e2690e435170,0,0x8c00a60a9ad727e7,0xfac5500c737f2b95,0x465ad668bd4060c9, // 'N'->'R' 337 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x2602a8e1051de97f, 338 | 0x979c69a50a083600,0,0,0,0,0,0,0,0,0x423a50a77113f78a,0,0, // 'b'->'k'+2 339 | 0xe59223a048660972,0,0x372ce57afac6322b,0x681fad211ec533ba,0x9475239a5c048d7f // 'n'->'r' 340 | }, 341 | { 0x8d5500634bcfd817,0,0,0,0,0,0,0,0,0xf9cadcd97b1bd6bb,0,0, // 'B'->'K'+2 342 | 0x458b09321e64f082,0,0x45e3e958b04c1979,0x7497fcd251675862,0xf856d714e166de3e, // 'N'->'R' 343 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x66d6b2de6a0d23a3, 344 | 0x0686fe9ceb117ade,0,0,0,0,0,0,0,0,0x3f980648106bf87b,0,0, // 'b'->'k'+2 345 | 0xe356d5123781a7c3,0,0x81807599b145da52,0xb567639890b037ae,0x4f751e27910ccae3 // 'n'->'r' 346 | }, 347 | { 0x471c2ceadd775c94,0,0,0,0,0,0,0,0,0x5f7f367b43f090d1,0,0, // 'B'->'K'+2 348 | 0xe515c11c824bca32,0,0x8664769885f3959b,0x06ca2e92eaae5b0e,0xc026fec3180c7c29, // 'N'->'R' 349 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa029b8acebd0fc3a, 350 | 0x5560bed393713ac1,0,0,0,0,0,0,0,0,0x545ce92d1546dc24,0,0, // 'b'->'k'+2 351 | 0xec95ab36ede65b0a,0,0xf795400047189056,0xdcc0e88a518dbc2b,0x2b27d2c302653368 // 'n'->'r' 352 | }, 353 | { 0x0c76f786aadb680b,0,0,0,0,0,0,0,0,0xe6c796dbd7a3bb02,0,0, // 'B'->'K'+2 354 | 0x40eeb76321bd8133,0,0x5476a9b9a5ad3450,0x7235efc6b7613820,0xe3a4cb93d76514b6, // 'N'->'R' 355 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x1ac8e4a24a168480, 356 | 0x8330083243c55b26,0,0,0,0,0,0,0,0,0x5935b8f22ee5a113,0,0, // 'b'->'k'+2 357 | 0x82b8936665d794ae,0,0xbd7708149625b62a,0x63071aab8d85b573,0xae3632760525c4b8 // 'n'->'r' 358 | }, 359 | { 0x87b3e8802a3989bc,0,0,0,0,0,0,0,0,0x9f5495e4d43569e8,0,0, // 'B'->'K'+2 360 | 0xf1d8596d5eabbe4d,0,0xb5e530690133b91e,0xe4929ec2257d3518,0x3475e0e1ad85627d, // 'N'->'R' 361 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xad575e8c91d28302, 362 | 0x5779870f451f3e03,0,0,0,0,0,0,0,0,0xa3974c76b428205e,0,0, // 'b'->'k'+2 363 | 0xad1e3a21bc35ace2,0,0x8c61689749d9976b,0xe115878cf651fd0d,0x45ce8f856eebf770 // 'n'->'r' 364 | }, 365 | { 0x8b2e7c263fae4928,0,0,0,0,0,0,0,0,0x25f4ef01c1903548,0,0, // 'B'->'K'+2 366 | 0x485f010a937f0c13,0,0xdb36ac066566b25f,0x07bd7f7d97900f48,0xa2931506e562c59a, // 'N'->'R' 367 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb5d8a266927f19c2, 368 | 0x4cb56fa6a39054f8,0,0,0,0,0,0,0,0,0x0204b14b391be0b4,0,0, // 'b'->'k'+2 369 | 0x75d0f572e43ce943,0,0x5f67e555f3e75bec,0x06476d7eae181f3d,0x87d149727276cf0e // 'n'->'r' 370 | }, 371 | { 0x8edd5ab272fe9f60,0,0,0,0,0,0,0,0,0xec0f7f33d8ae3d04,0,0, // 'B'->'K'+2 372 | 0x5c746d02fa839fc3,0,0x16e91d4cb31112ed,0x80b1929d1dbf688b,0x67ebd6094c24d3fc, // 'N'->'R' 373 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x27542273c45baa56, 374 | 0x063963c8d0550dcd,0,0,0,0,0,0,0,0,0x6cee1185696d0b79,0,0, // 'b'->'k'+2 375 | 0x57b55a746581666d,0,0xe7fae0b5ace9934b,0x9f4a88ebe18ffab8,0x022dd0c13ff2a610 // 'n'->'r' 376 | }, 377 | { 0x4770ff2b94ce4c98,0,0,0,0,0,0,0,0,0xf8077a4f502f139d,0,0, // 'B'->'K'+2 378 | 0x35b22c3ee1b96895,0,0xb0de694cf725846e,0x1d9eba2fb149c019,0x19735a4c96a5a5d0, // 'N'->'R' 379 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x93bf7695b9aa43bc, 380 | 0x4a2ec078a8e00779,0,0,0,0,0,0,0,0,0xb1fd37128056cb76,0,0, // 'b'->'k'+2 381 | 0x8a00b95988803475,0,0xac05620df4c1e5bd,0xb961c0de3b043653,0xf2e88e5ca4dc8aa1 // 'n'->'r' 382 | }, 383 | { 0x638cd0ec65162768,0,0,0,0,0,0,0,0,0x00b128696c81c3a0,0,0, // 'B'->'K'+2 384 | 0x3a222cd59e6a3ce4,0,0xa5aeae069b3c95fb,0x7471b2647990eafb,0x99b34e3004e9d879, // 'N'->'R' 385 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xf8da6628785a9546, 386 | 0x96b7a39a4d3401d5,0,0,0,0,0,0,0,0,0xd5751c9eb750a91f,0,0, // 'b'->'k'+2 387 | 0xf6781d85a901220d,0,0xea2fb88f49b9c747,0x0451b3bf4a4286b8,0xaad32de5622a9498 // 'n'->'r' 388 | }, 389 | { 0xb24cac259e36424f,0,0,0,0,0,0,0,0,0x70cf7e3bbfc99829,0,0, // 'B'->'K'+2 390 | 0xd04d3e716dc3c912,0,0xaf62305fe0e23e28,0x8282b96022ae6db6,0xa60a89f01a5540cf, // 'N'->'R' 391 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x557eb8d04c5c3b0b, 392 | 0x0773192017a5d0a6,0,0,0,0,0,0,0,0,0xca74803e91e9386f,0,0, // 'b'->'k'+2 393 | 0xeb66698a5aa2cd5d,0,0x18e4e98c97436ff9,0x8ade765d8d43d481,0x71293f409306fadf // 'n'->'r' 394 | }, 395 | { 0xfdbb759d089ba776,0,0,0,0,0,0,0,0,0x851b995aa7382b2c,0,0, // 'B'->'K'+2 396 | 0x621307e7f80de0d8,0,0xb1a72096a6f03d7d,0xce81e193522ce018,0x174449856e717043, // 'N'->'R' 397 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x76048b2438a4abd2, 398 | 0x3a4e7253e58413ef,0,0,0,0,0,0,0,0,0xd3aac07f2429df03,0,0, // 'b'->'k'+2 399 | 0x690985e45e1888ea,0,0x8a03a70518e606cc,0x9f903d5c6f94d7e6,0xe323c9ccfbea3123 // 'n'->'r' 400 | }, 401 | { 0xe30fdc9ae45516d6,0,0,0,0,0,0,0,0,0xe14eaef142a5b3fe,0,0, // 'B'->'K'+2 402 | 0x9e6b6453ce62babd,0,0x540baf8c897a4ec5,0x222a87e6b4320ad7,0x6788648772ab4a2b, // 'N'->'R' 403 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xfb074cb419a87820, 404 | 0x8b6e0250197d5c0b,0,0,0,0,0,0,0,0,0xdf2d599deb633668,0,0, // 'b'->'k'+2 405 | 0x9f2744005a3118d4,0,0x80b24ed7b6d8848a,0x611d7acf7820b6b6,0xec1eff4affb46feb // 'n'->'r' 406 | }, 407 | { 0x8ac8fefcd754f5a5,0,0,0,0,0,0,0,0,0x8a97ee8326423e7d,0,0, // 'B'->'K'+2 408 | 0x1ef4923de796fe9c,0,0xec5dc943de3d826f,0xae422c90099d7de8,0xd474277029992302, // 'N'->'R' 409 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4980a5c98220f61b, 410 | 0xf7e19e549d954fd3,0,0,0,0,0,0,0,0,0x0b0080742ab684d9,0,0, // 'b'->'k'+2 411 | 0xeb76e2e51fb2aa97,0,0x1db89effc76fe335,0x09398338d9171133,0x1b3ef53edd6c44ae // 'n'->'r' 412 | }, 413 | { 0x2cbddbb8ceac7494,0,0,0,0,0,0,0,0,0x51055a3069514bb5,0,0, // 'B'->'K'+2 414 | 0x639e549191b0961d,0,0x3f1ce77523d53e43,0xf3bf9fb9683d2a23,0x90128e0908814327, // 'N'->'R' 415 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x4cceb1ec11b4ed89, 416 | 0xe806d4befb8a0849,0,0,0,0,0,0,0,0,0x2914684fb28ab129,0,0, // 'b'->'k'+2 417 | 0x9481e2e65f8ffb97,0,0xe2e4dcce741b5f83,0x991261a16b8a0f2e,0x7246e784b8d8a2da // 'n'->'r' 418 | }, 419 | { 0x3cf06b900cf357b2,0,0,0,0,0,0,0,0,0xe86a88e4ddcb3b6c,0,0, // 'B'->'K'+2 420 | 0x94b507475d912703,0,0x2904dd3ef9bbc71f,0x2557bf170441bb09,0xa93eff5bdb15ed8a, // 'N'->'R' 421 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x55ebe96e3b11ee1b, 422 | 0x70b5200702ffb1ad,0,0,0,0,0,0,0,0,0xa02299fdc3d140c7,0,0, // 'b'->'k'+2 423 | 0x1394a3165c2785a7,0,0x5c7e8762f1b2143d,0xb24b689ebae0a955,0xe936e6f6bffff361 // 'n'->'r' 424 | }, 425 | { 0x3f5586502befec2c,0,0,0,0,0,0,0,0,0xe0e4e49b56e32b22,0,0, // 'B'->'K'+2 426 | 0x0a243e2f8562a7a2,0,0x6f24d1ef7d531458,0x0f5882720de91821,0x84823a0b56c7ba85, // 'N'->'R' 427 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x0fa2d7d73332f8e8, 428 | 0x7983d74e2df312ff,0,0,0,0,0,0,0,0,0xe8612fe704bdd824,0,0, // 'b'->'k'+2 429 | 0x2f32631e2bc5c700,0,0xbd69085acb2fc5cb,0x6f4c792276a4b922,0xe5e76a36395320c5 // 'n'->'r' 430 | }, 431 | { 0x30036751dfe4037e,0,0,0,0,0,0,0,0,0xac2e5aa35868f7b5,0,0, // 'B'->'K'+2 432 | 0xb717dc47f1b1d4fe,0,0x87689b6ded96bc50,0x85e3bf3b9bb675be,0x4df03270b4548088, // 'N'->'R' 433 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x521091a598be68bd, 434 | 0xff7a744408269881,0,0,0,0,0,0,0,0,0x00cb21b5c89ce8d1,0,0, // 'b'->'k'+2 435 | 0x5cb86c0d2a296570,0,0x98e8d8658001b923,0x787c73139f193578,0xa629ff6b0ce50d5b // 'n'->'r' 436 | }, 437 | { 0x60d4ad0893c540a8,0,0,0,0,0,0,0,0,0x01541b60b2f81774,0,0, // 'B'->'K'+2 438 | 0xfac246d13ce68b24,0,0xf86074c5fe0db0b0,0x2cb6697cef28a619,0xa9f32064446b5143, // 'N'->'R' 439 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x53f705819d2cdf67, 440 | 0x4b0b82fdadd8e1fc,0,0,0,0,0,0,0,0,0xae2b549d891f3b23,0,0, // 'b'->'k'+2 441 | 0x334b1385dd418c72,0,0x102e5fd09704571e,0xecfad0e6c037541d,0x9b74b1f8bae946f1 // 'n'->'r' 442 | }, 443 | { 0x4f2b17a8f6e8cd21,0,0,0,0,0,0,0,0,0x7a470a964fdba092,0,0, // 'B'->'K'+2 444 | 0x67394c1e8de2d511,0,0x48b438ff65f1d0dd,0xa2105a13365f3954,0x3d08a70435b851fd, // 'N'->'R' 445 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xe401d29438f20a02, 446 | 0x83b71b6a2faa5845,0,0,0,0,0,0,0,0,0x6ebf4a4a37fff565,0,0, // 'b'->'k'+2 447 | 0x5e30807bf1c2638c,0,0xed9fbdc391cf922c,0x74de7cd6bd533375,0x9792993c73bd6afd // 'n'->'r' 448 | }, 449 | { 0x5664eae57d8eb542,0,0,0,0,0,0,0,0,0x6e8974faf8616e6f,0,0, // 'B'->'K'+2 450 | 0xf872465d3a37d85b,0,0x97c072a9ae382d55,0x22291628411d81a7,0x5ac0e8bc15d5ee27, // 'N'->'R' 451 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x18c824d10edaffcb, 452 | 0xa83272b30e716e96,0,0,0,0,0,0,0,0,0x57e885286f35ed9e,0,0, // 'b'->'k'+2 453 | 0xa6fdb83b7ce2ee91,0,0x974d89ea4fd1dac6,0xd25c25dee18983c7,0xa8bfca1db2439112 // 'n'->'r' 454 | }, 455 | { 0x671bb8e1f9f5a35c,0,0,0,0,0,0,0,0,0x65b29e5e60b4582b,0,0, // 'B'->'K'+2 456 | 0x099ddcee9e1ed453,0,0xffd0aea52dfa81b1,0xfc10d17e8ae13329,0x5a15a8d80651585d, // 'N'->'R' 457 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x72b97d10dac7f4ae, 458 | 0xb8ae1b6311374595,0,0,0,0,0,0,0,0,0xf008dca7be6bf0c9,0,0, // 'b'->'k'+2 459 | 0xa3389e9dadecaf59,0,0xac0ae1fc7a8549f2,0xd0244c41742579e0,0x44463f17ad5537db // 'n'->'r' 460 | }, 461 | { 0xf9e9ecc8895d4149,0,0,0,0,0,0,0,0,0x906685809b674e1c,0,0, // 'B'->'K'+2 462 | 0xe3c98457e58c3feb,0,0xf4f98f25b6f660d1,0xc3ba556ffd86da69,0x1d0d69bf7830f7ba, // 'N'->'R' 463 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb2c0699a37868f80, 464 | 0x45b0d2d974bd5fd6,0,0,0,0,0,0,0,0,0x55e33559a9bf7e3f,0,0, // 'b'->'k'+2 465 | 0x1501bc86e80b0410,0,0x25ceb8d84369186a,0xc3e8c5f72320e0a4,0x1008e9cf0549625e // 'n'->'r' 466 | }, 467 | { 0x058d64653aae1e18,0,0,0,0,0,0,0,0,0x3ded4529c2251a74,0,0, // 'B'->'K'+2 468 | 0x2322e791e1af94bf,0,0x6ea9ffd051eca4c3,0x42b88f70e7886533,0x85a18c2b622ab088, // 'N'->'R' 469 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xdeff446ea55223b8, 470 | 0xc5e8cdc5969bf35b,0,0,0,0,0,0,0,0,0x2dedd176531e6c5d,0,0, // 'b'->'k'+2 471 | 0xf5700b93d4bf977b,0,0x6eeb5aef850bcaee,0x1e08b716a104f457,0x533aed6d0003a0a0 // 'n'->'r' 472 | }, 473 | { 0x1b649f8bdf660893,0,0,0,0,0,0,0,0,0x9559fa0b4fd61248,0,0, // 'B'->'K'+2 474 | 0x96f63ba14606d9c7,0,0xefbc5f876cea6457,0xbed26877cc4ccc0d,0xf0d7111ae2a57d3a, // 'N'->'R' 475 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd92062302f85d651, 476 | 0x0d712cc7ae0c9478,0,0,0,0,0,0,0,0,0xef92b0eff3ea2774,0,0, // 'b'->'k'+2 477 | 0x98a14ab674c4ebb7,0,0xfbc1d260afff3b40,0xe44d11647bc0aacb,0x66596752372b82dc // 'n'->'r' 478 | }, 479 | { 0xc7eb1a57c9ead3a4,0,0,0,0,0,0,0,0,0x615da595f286e119,0,0, // 'B'->'K'+2 480 | 0x362715fe3abcb320,0,0x25d6ca02bb195daa,0xc3d6ad08e15b2f0e,0xaf57dd0a410251d6, // 'N'->'R' 481 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x30666905504e251c, 482 | 0xa8218d26369b9d14,0,0,0,0,0,0,0,0,0xe6151ba6f51b7fd2,0,0, // 'b'->'k'+2 483 | 0xdcb0226484a8cd44,0,0x024951c178c4b616,0x18e5e6750691d4e3,0x1719823bb62a5b7a // 'n'->'r' 484 | }, 485 | { 0x7f6e4ea4351cc253,0,0,0,0,0,0,0,0,0x9e82c38527588287,0,0, // 'B'->'K'+2 486 | 0x94c1c9056cb82fc8,0,0x61e79826bafe423d,0x3dd6aea35fc99a8d,0x18b85858a5719605, // 'N'->'R' 487 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x2b453fb176ace100, 488 | 0xfc2496cf37026c88,0,0,0,0,0,0,0,0,0xdc0d7d544712accf,0,0, // 'b'->'k'+2 489 | 0xe58659722fbbb9cf,0,0x0efc250996377fb5,0x4567aff7cebd948b,0x787a9c84dd25a404 // 'n'->'r' 490 | }, 491 | { 0x7922fbb1bf4099a7,0,0,0,0,0,0,0,0,0x1da74c181e16915c,0,0, // 'B'->'K'+2 492 | 0x7ad1265eacc2cbad,0,0x7501cd828472f51a,0x8225df5346e2824a,0xfadecf8321cf3734, // 'N'->'R' 493 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xf79e4e4d2cc6d3ee, 494 | 0x6c78050bb7841db1,0,0,0,0,0,0,0,0,0x1996e18db4586cdb,0,0, // 'b'->'k'+2 495 | 0xdb6c89e465642b33,0,0x0a268851769102e3,0x1e08649a90bf7369,0x7bd42fc6d7265312 // 'n'->'r' 496 | }, 497 | { 0x4570c6af2eeb6d75,0,0,0,0,0,0,0,0,0x7550766234721522,0,0, // 'B'->'K'+2 498 | 0x675ef6152514be33,0,0x3c3a2f942a3abe9e,0x665a16aa7cf141b5,0x0f121f7a1ff50f3a, // 'N'->'R' 499 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xabdfc9b95b096fab, 500 | 0x1fb44491b8da4737,0,0,0,0,0,0,0,0,0x583f7265f0c025fc,0,0, // 'b'->'k'+2 501 | 0xdb544fd907cbc3fc,0,0xb6b96cf4c3ec5b12,0x665099d5bf3b03ad,0xa3a1c0b7bfa86b57 // 'n'->'r' 502 | }, 503 | { 0x61a33e6417b461c1,0,0,0,0,0,0,0,0,0x662f6cc4e75a2d46,0,0, // 'B'->'K'+2 504 | 0x05a0106f37aad5ea,0,0x6e87d4e2155b2c35,0x5fefcb0bbfcf2330,0x9d51afe28d5c7c5e, // 'N'->'R' 505 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa95f1861bb50483b, 506 | 0x11ee48ee95a03950,0,0,0,0,0,0,0,0,0xa01779930bad669a,0,0, // 'b'->'k'+2 507 | 0xd2893f70f641767c,0,0xe9fb540b358b50a3,0xa7469be14aca2e3a,0xabfab619497343b1 // 'n'->'r' 508 | }, 509 | { 0xb9f194613da6f46a,0,0,0,0,0,0,0,0,0x52f7155fad6120c9,0,0, // 'B'->'K'+2 510 | 0x8973c92d19acdd2c,0,0x50f3cb061023470d,0x1c483a590434bb79,0xd5542f588e3f0746, // 'N'->'R' 511 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x67b069ededf5a226, 512 | 0xc69b0a26025d8ea7,0,0,0,0,0,0,0,0,0x67c69033ab7fa688,0,0, // 'b'->'k'+2 513 | 0x47f9a410d541fc0d,0,0x522fdf97c8ffc7f8,0xb6c3eedafbfd0387,0x07aad303481f76d0 // 'n'->'r' 514 | }, 515 | { 0x8fc3875ab4183bf8,0,0,0,0,0,0,0,0,0xbcbcb1ae961efa16,0,0, // 'B'->'K'+2 516 | 0x66501e7a2e7f61f8,0,0x1c1ad59d105f5f4f,0x87e67302832c37d9,0x9b3702857c521708, // 'N'->'R' 517 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x15d1d57994982ee3, 518 | 0xb4060fc7fa3d1f06,0,0,0,0,0,0,0,0,0xaa69db0fc99c5cd1,0,0, // 'b'->'k'+2 519 | 0xa2815b4ee062a5c7,0,0x079625a39b41f9d4,0xf58a58b4569195d9,0xe3a8556737e93fc2 // 'n'->'r' 520 | }, 521 | { 0x1a71bf76f629763c,0,0,0,0,0,0,0,0,0xae9f59077485f190,0,0, // 'B'->'K'+2 522 | 0xddfeaab33b50cc38,0,0xe42d2d66e0fd9b72,0x077902f9f3068eed,0x004f23b37e054a97, // 'N'->'R' 523 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x88f04f9df0fe2118, 524 | 0xefed92b7b72f0404,0,0,0,0,0,0,0,0,0x677c8271cc988a64,0,0, // 'b'->'k'+2 525 | 0xf553a18b7c74f3ec,0,0x8630e9c3a1650931,0xcbdb96cdb5636957,0x5d772f7adfd1561e // 'n'->'r' 526 | }, 527 | { 0xfdf88d377f861e36,0,0,0,0,0,0,0,0,0x30c8fe584b036099,0,0, // 'B'->'K'+2 528 | 0x5af009fbd8346f14,0,0x04e53cfcd9545d61,0xd92cd1f831c06965,0x84a577449e2d2ab9, // 'N'->'R' 529 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc54aec75c5f8b197, 530 | 0xd7c0397303637d9b,0,0,0,0,0,0,0,0,0xb8747dd6f969041d,0,0, // 'b'->'k'+2 531 | 0x5f8b14b958e44ba1,0,0xa227795ddcc05573,0x390d9a6625ec8f35,0x4eb0338bc7ca0a77 // 'n'->'r' 532 | }, 533 | { 0x149dbecefb592bb3,0,0,0,0,0,0,0,0,0x898b1e52fc2b1356,0,0, // 'B'->'K'+2 534 | 0x15d6efd97a7679f6,0,0x464a8cecc0e9f007,0x38ad70037f550a69,0x023980a501094bf1, // 'N'->'R' 535 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x199a8587a3b47889, 536 | 0x0662c71d44fc9ab6,0,0,0,0,0,0,0,0,0x43d9a44e5e5b8f80,0,0, // 'b'->'k'+2 537 | 0x24efef0b69160353,0,0x10ef2bc9230be578,0x8385c20b6da013a4,0x10cb7b10d2764ed1 // 'n'->'r' 538 | }, 539 | { 0x39001c3c4c3f5c94,0,0,0,0,0,0,0,0,0xdb34ea7b3099df75,0,0, // 'B'->'K'+2 540 | 0x5e96e06766b09bf0,0,0x2980b6bf82e5cd03,0x0e1b82bb1ee3607e,0x8f475881396cd72a, // 'N'->'R' 541 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xe9443792fb0f2241, 542 | 0xc6012eb5190c5614,0,0,0,0,0,0,0,0,0xe28c351c67f78324,0,0, // 'b'->'k'+2 543 | 0x74d741c0dcb89544,0,0xe5b3f35591b7cbd0,0x27432ed8f9114070,0x550a764957f687af // 'n'->'r' 544 | }, 545 | { 0x3318bb88f5f9428a,0,0,0,0,0,0,0,0,0xb6825fd2c9f390ed,0,0, // 'B'->'K'+2 546 | 0x6ed80d8be8140568,0,0x6d4c29dc694fb3de,0x873a5975c627f75b,0x4d3bb7b35bf9362b, // 'N'->'R' 547 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x5974eb515549003f, 548 | 0x120671b766458f9f,0,0,0,0,0,0,0,0,0xc80f0c0f14c30f94,0,0, // 'b'->'k'+2 549 | 0x6bfe00834d44c9c6,0,0xc042f46a6840f509,0x6368e9d8c674cdbc,0xed5dc0d53b73b25b // 'n'->'r' 550 | }, 551 | { 0x290f8d1ced1c4a6f,0,0,0,0,0,0,0,0,0x07696f3a21eab5a3,0,0, // 'B'->'K'+2 552 | 0x59a72ed553478953,0,0xe54c064e0dad674c,0x187a8b6ff3ef5512,0x647f6341b9c08d71, // 'N'->'R' 553 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xdf00934c03921f4a, 554 | 0xe0dd050b02ece8e2,0,0,0,0,0,0,0,0,0xaae76519889134e1,0,0, // 'b'->'k'+2 555 | 0xb0d74567c544c7ab,0,0x3155f70b4df91683,0xfcc2e35a259e4b8c,0xeb0812ede2031ce4 // 'n'->'r' 556 | }, 557 | { 0xc26055a2145b8f3a,0,0,0,0,0,0,0,0,0x9465f7814028cf81,0,0, // 'B'->'K'+2 558 | 0x5d52cbfe16f03971,0,0x74b5c290ad6adc80,0x8045ad01ac0b5327,0xa4712a10cf77f418, // 'N'->'R' 559 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x605b0a213ed062ba, 560 | 0x4107cc216ea14124,0,0,0,0,0,0,0,0,0x5d6adcac6ba87963,0,0, // 'b'->'k'+2 561 | 0x8d1385e6c08be345,0,0x42caa3288eafb886,0x21c46948d460d003,0x7ef7e8cddc4d14e2 // 'n'->'r' 562 | }, 563 | { 0x3355046a61085b79,0,0,0,0,0,0,0,0,0xae868253ba1f92a8,0,0, // 'B'->'K'+2 564 | 0x839912f218b779bc,0,0x46ffc5a0453435a1,0x18f5539741925d1c,0x863dc14421a8db44, // 'N'->'R' 565 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xda13159f9789101a, 566 | 0x1e0ca2960e2d02e0,0,0,0,0,0,0,0,0,0x65425c4079fa68f8,0,0, // 'b'->'k'+2 567 | 0x28eb9ee54d35916d,0,0x3baafd1f7ce947b3,0x0bfb804f431a2cc9,0x95dee053756135b5 // 'n'->'r' 568 | }, 569 | { 0xf881db0f74c5a0c5,0,0,0,0,0,0,0,0,0xbf30ab33864bb3a1,0,0, // 'B'->'K'+2 570 | 0x00fcfdf9aeeb8687,0,0x9be6ad8c7127ea7d,0x2db76aadb214825e,0x943a140ada464848, // 'N'->'R' 571 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x9ce4d5f44894b0f6, 572 | 0x2b8ba6696ef5db54,0,0,0,0,0,0,0,0,0x14d4a3506142e487,0,0, // 'b'->'k'+2 573 | 0xafb56c46d3adc6c3,0,0xe1c3f8152e5fe8d5,0xfa0faede82643ddb,0xb83906c3c9de1e6c // 'n'->'r' 574 | }, 575 | { 0x9bccc550161ccd43,0,0,0,0,0,0,0,0,0xf76555400e8d9866,0,0, // 'B'->'K'+2 576 | 0x5410a481a8f85f54,0,0x81f46732b26e6947,0xcd7d3b6034e36253,0x4ce7416bc75894df, // 'N'->'R' 577 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd61bf3fbd8e70900, 578 | 0x8cac11d2c7042e85,0,0,0,0,0,0,0,0,0x6a4fc952ae6d8d5b,0,0, // 'b'->'k'+2 579 | 0xee4a22b94269846b,0,0x6a654d962da97b9e,0x85509f0f5fb237c9,0xefc6238f11e247d3 // 'n'->'r' 580 | }, 581 | { 0x4467ae1c966cee07,0,0,0,0,0,0,0,0,0xb8e10d47027aec95,0,0, // 'B'->'K'+2 582 | 0xe09d351b45d7a7e5,0,0x086c38d8e45d5ddc,0x5f3611395ef03588,0x6d0acb3a222ac6ab, // 'N'->'R' 583 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x005aa8d83272262e, 584 | 0x180977ccc7792000,0,0,0,0,0,0,0,0,0x3f68490d75b91d68,0,0, // 'b'->'k'+2 585 | 0xfa821792ecd782b3,0,0x5177c04e0b6bb626,0x93411fceb715f459,0xdbd8d714ccbf6c4a // 'n'->'r' 586 | }, 587 | { 0xa4c816477da649f3,0,0,0,0,0,0,0,0,0x756076b713b36ae2,0,0, // 'B'->'K'+2 588 | 0x5d4d6d2c78310a7b,0,0x71d078eb84d26157,0xaaef5cf5e1f93c60,0x560acc5b4e8b1b53, // 'N'->'R' 589 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x9264582c7d08711a, 590 | 0xe1741f0f93d9dace,0,0,0,0,0,0,0,0,0xc651a7fd6a211820,0,0, // 'b'->'k'+2 591 | 0xf1ed4657f59d6c73,0,0xe66d17cb2c9299c6,0xfdec864da5441761,0x6780a1fe79ac91ac // 'n'->'r' 592 | }, 593 | { 0x60721d9d090d833b,0,0,0,0,0,0,0,0,0xe535565fc89d2739,0,0, // 'B'->'K'+2 594 | 0xf755706e6e2edab2,0,0x10a93ed28e7228ad,0xcab89e84829076e9,0xaf7b721c28ed0c84, // 'N'->'R' 595 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xacf9f6c18942edb9, 596 | 0x3b27683124d2005d,0,0,0,0,0,0,0,0,0x3eb113b1ae6fbd5b,0,0, // 'b'->'k'+2 597 | 0x89f34957a6433591,0,0x3769be39471089a3,0xc5e59ed08a0a8ec2,0x2a821c2920fd0194 // 'n'->'r' 598 | }, 599 | { 0xbf2025da536013ad,0,0,0,0,0,0,0,0,0xec39c6f0648664b9,0,0, // 'B'->'K'+2 600 | 0xb8afa4c225a2b3cf,0,0x4b489baff4d70177,0x7b9ec91128ed3ea4,0x73fdfc142fe7cf69, // 'N'->'R' 601 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x31ab7aa621212abe, 602 | 0x7e740540e76b7e04,0,0,0,0,0,0,0,0,0x349ffe86943441f1,0,0, // 'b'->'k'+2 603 | 0xc73640ec8b36ddf2,0,0x89147296179e5ccd,0xd81fc84f74f8259e,0x7014984ae919756d // 'n'->'r' 604 | }, 605 | { 0x239a44a2e1cd7757,0,0,0,0,0,0,0,0,0xf998eea8153da2e2,0,0, // 'B'->'K'+2 606 | 0x6d499aa6756711a3,0,0x4d02cbf6cce59a49,0xd7c55695b9630cda,0x14375f22e08ba7b7, // 'N'->'R' 607 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xd16aa1756626861a, 608 | 0xba14aca017ecf576,0,0,0,0,0,0,0,0,0x1a37c9aae76f7416,0,0, // 'b'->'k'+2 609 | 0xf9b5657f6d2261cc,0,0x2808bd2cb0a57acf,0xc83702637924fd62,0x4ddff729b31a6e5a // 'n'->'r' 610 | }, 611 | { 0x3f3e5af99487cc33,0,0,0,0,0,0,0,0,0x134abb6753e57be6,0,0, // 'B'->'K'+2 612 | 0x095c0f9bb75bc72e,0,0x6cb6b6fbc1bc3ed0,0x682c093006edfe3d,0x1b8cd57fa2d4e5bc, // 'N'->'R' 613 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xe0b4468abb3cdb2f, 614 | 0x9176b5443d71f7fa,0,0,0,0,0,0,0,0,0x6e972511c457b868,0,0, // 'b'->'k'+2 615 | 0x3f1e5b0329191280,0,0x48b9de6502800d8a,0x98afd65ecbe04fcb,0xef6ff1d74eebd78d // 'n'->'r' 616 | }, 617 | { 0x1e16291df58bf147,0,0,0,0,0,0,0,0,0xc5b332663b9d125e,0,0, // 'B'->'K'+2 618 | 0xf9d3867b75489606,0,0x9c699c9e80e09ead,0xeebc54cb974abcf5,0x00af71c2f427159e, // 'N'->'R' 619 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x644ccddddb93b60f, 620 | 0xee771d3c8eccb8a9,0,0,0,0,0,0,0,0,0x3dff6a87750c98a6,0,0, // 'b'->'k'+2 621 | 0xac809ab318f3b535,0,0x401a18f4f3ae0bab,0x3976aa499f265252,0x7bbfadd793646d87 // 'n'->'r' 622 | }, 623 | { 0x065637c0dcef0cdc,0,0,0,0,0,0,0,0,0x0a3cf7f0d21dcb41,0,0, // 'B'->'K'+2 624 | 0x01e97191285a96a9,0,0xa3c3b6a8e8a9fb42,0xed6a40f3fe0fdc72,0x68868a15d0c62b5c, // 'N'->'R' 625 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb172765e15c2a14e, 626 | 0x609db79a28cf62e5,0,0,0,0,0,0,0,0,0xb4848c8f182e64db,0,0, // 'b'->'k'+2 627 | 0xcf328af0a0ff7cf6,0,0x9897b711a2342064,0xb583590a65ffc99f,0x89884691f30528dd // 'n'->'r' 628 | }, 629 | { 0xf44f3883100df4b2,0,0,0,0,0,0,0,0,0x74a0cbe7efce9dfc,0,0, // 'B'->'K'+2 630 | 0x5a187e496c8d60ae,0,0x99a6431d7287625d,0xe5c55cc342391e72,0xa771e9c7ba4a4ea1, // 'N'->'R' 631 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc51c91d0d95a930c, 632 | 0x5f7f88e2be034ee0,0,0,0,0,0,0,0,0,0x5b802e840886a6e9,0,0, // 'b'->'k'+2 633 | 0xab1161bd4e96a350,0,0x9f25775af57fe442,0x74f664641ea955c8,0x49dfb8865af973f3 // 'n'->'r' 634 | }, 635 | { 0x15c6f02071a2087d,0,0,0,0,0,0,0,0,0xdfd8ac515b51248a,0,0, // 'B'->'K'+2 636 | 0x3bb14677644b5270,0,0x1cc80976042e1ada,0x14d4c6f58827449b,0x366219252f6b62b8, // 'N'->'R' 637 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x526fba77d8695c78, 638 | 0x2edb451b66b8f141,0,0,0,0,0,0,0,0,0x9c7ff433894949c0,0,0, // 'b'->'k'+2 639 | 0x672cb64eede60ac5,0,0x5e1cbfbbae262f58,0xbec7965619805d22,0xb9ea065f9bf30fcf // 'n'->'r' 640 | }, 641 | { 0x86e36808f1ff4803,0,0,0,0,0,0,0,0,0xad954d381935dabc,0,0, // 'B'->'K'+2 642 | 0x7cd85b1dde96ccee,0,0x250a7a9c178f1ea5,0x0023c7df7443fcab,0x2b04d5a20e53c6d3, // 'N'->'R' 643 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x6ce720ba53a2ab58, 644 | 0x107ed77f1626fe46,0,0,0,0,0,0,0,0,0x10450f7e3b951e94,0,0, // 'b'->'k'+2 645 | 0x43ab4fd13cb76386,0,0x355015dc9d4d8f1c,0x592de86fd6ea5273,0xeeb15e9008779386 // 'n'->'r' 646 | }, 647 | { 0x16976fc885ba1342,0,0,0,0,0,0,0,0,0x3724563b03fec25c,0,0, // 'B'->'K'+2 648 | 0x9a2bb0f78358dfdc,0,0xdbbc03ec6dc58e66,0xb6e15407a65b6365,0xcd8a6b8c116d4d7b, // 'N'->'R' 649 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x283fb5208b6a4ec5, 650 | 0x28bdced4407f346d,0,0,0,0,0,0,0,0,0x579652eb084fa549,0,0, // 'b'->'k'+2 651 | 0x9b0ff04b389e0064,0,0xba2d0cdd9484d2b6,0x1d9c042840d1234d,0xa9cf3400c5661795 // 'n'->'r' 652 | } 653 | }; 654 | 655 | 656 | --------------------------------------------------------------------------------