Skip to content

Commit

Permalink
Caching pawn structure evaluation, ~10% speed up
Browse files Browse the repository at this point in the history
  • Loading branch information
quesswho committed Oct 23, 2024
1 parent 4a04ba3 commit 4e6dd02
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 37 deletions.
6 changes: 6 additions & 0 deletions milesChess.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
RelDebug|x64 = RelDebug|x64
RelDebug|x86 = RelDebug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
Expand All @@ -17,6 +19,10 @@ Global
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.Debug|x64.Build.0 = Debug|x64
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.Debug|x86.ActiveCfg = Debug|Win32
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.Debug|x86.Build.0 = Debug|Win32
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.RelDebug|x64.ActiveCfg = Release|x64
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.RelDebug|x64.Build.0 = Release|x64
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.RelDebug|x86.ActiveCfg = RelDebug|Win32
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.RelDebug|x86.Build.0 = RelDebug|Win32
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.Release|x64.ActiveCfg = Release|x64
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.Release|x64.Build.0 = Release|x64
{B830A8D2-D5AE-4B5F-9AA1-6BD2A4CBEE5E}.Release|x86.ActiveCfg = Release|Win32
Expand Down
58 changes: 58 additions & 0 deletions milesChess.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="RelDebug|Win32">
<Configuration>RelDebug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="RelDebug|x64">
<Configuration>RelDebug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
Expand Down Expand Up @@ -34,6 +42,11 @@
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
Expand All @@ -44,6 +57,11 @@
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
Expand All @@ -55,22 +73,35 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>C:\stuff\dev\milesChess\src;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|x64'">
<IncludePath>C:\stuff\dev\milesChess\src;$(IncludePath)</IncludePath>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
Expand Down Expand Up @@ -100,11 +131,38 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RelDebug|x64'">
<ClCompile>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<LanguageStandard>stdcpp20</LanguageStandard>
Expand Down
33 changes: 14 additions & 19 deletions src/Evaluate.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,6 @@

#define TEMPO 20

struct Score {
int mg;
int eg;

Score& operator+=(const Score& other) {
mg += other.mg;
eg += other.eg;
return *this;
}

Score& operator-=(const Score& other) {
mg -= other.mg;
eg -= other.eg;
return *this;
}
};

template<bool white>
static Score Pawn(const Board& board, int pos, int rpos) {
Expand All @@ -42,14 +26,17 @@ static Score Pawn(const Board& board, int pos, int rpos) {
middlegame -= 15;
}
if ((Lookup::isolated_mask[pos] & Pawn<white>(board)) == 0) {

middlegame -= 3;
endgame -= 15;
}
return Score({ middlegame, endgame });
}

static Score Pawns(const Board& board) {
uint64 wp = board.m_WhitePawn, bp = board.m_BlackPawn;
Score score = { 0, 0 };


while (wp > 0) {
int rpos = PopPos(wp);
score += Pawn<true>(board, 63 - rpos, rpos);
Expand All @@ -63,7 +50,7 @@ static Score Pawns(const Board& board) {
}

// Relative static evaluation
static int64 Evaluate(const Board& board, bool white) {
static int64 Evaluate(const Board& board, PawnTable* table, uint64 pawnhash, bool white) {

int64 middlegame = 0, endgame = 0, result = 0;
Score score = { 0, 0 };
Expand Down Expand Up @@ -91,8 +78,16 @@ static int64 Evaluate(const Board& board, bool white) {
}
}


// Pawns
score += Pawns(board);

PTEntry* pawnStructure = table->Probe(pawnhash);
if (pawnStructure != nullptr) {
score += pawnStructure->m_Score;
} else {
Score pawn = Pawns(board);
table->Enter(pawnhash, PTEntry(pawnhash, pawn));
}

// Knights
int wkncnt = 0;
Expand Down
24 changes: 23 additions & 1 deletion src/Search.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ class Search {
int64 m_MaxTime;
private:
uint64 m_Hash[MAX_DEPTH];
uint64 m_PawnHash[MAX_DEPTH];
uint64 m_History[256];
std::vector<std::unique_ptr<std::thread>> m_Threads;
bool m_Running;
Timer m_Timer;
int m_Maxdepth; // Maximum depth currently set
uint64 m_NodeCnt;
TranspositionTable* m_Table;
PawnTable* m_PawnTable;
std::vector<RootMove> m_RootMoves;
int m_RootDelta;
public:
Expand All @@ -51,6 +53,7 @@ class Search {
: m_Maxdepth(0), m_Running(false), m_MaxTime(999999999999999), m_NodeCnt(0)
{
m_Table = new TranspositionTable(1024 * 1024 * 1024);
m_PawnTable = new PawnTable(1024 * 1024);
LoadPosition(Lookup::starting_pos);
}

Expand All @@ -72,6 +75,7 @@ class Search {
m_Info[0] = FenInfo(fen);
m_RootBoard = std::make_unique<Board>(Board(fen));
m_Hash[0] = Zobrist_Hash(*m_RootBoard, m_Info[0]);
m_PawnHash[0] = Zobrist_PawnHash(*m_RootBoard);
m_Table->Clear();
m_History[0] = m_Hash[0];
}
Expand Down Expand Up @@ -125,7 +129,7 @@ class Search {

int64 Quiesce(const Board& board, int64 alpha, int64 beta, int ply) {
m_NodeCnt++;
int64 bestScore = Evaluate(board, m_Info[ply].m_WhiteMove);
int64 bestScore = Evaluate(board, m_PawnTable, m_PawnHash[ply], m_Info[ply].m_WhiteMove);
if (bestScore >= beta) { // fail soft
return bestScore;
}
Expand Down Expand Up @@ -438,6 +442,7 @@ class Search {
int tpos = GET_SQUARE(move.m_To);

m_Hash[ply] = m_Hash[ply - 1] ^ Lookup::zobrist[64 * 12];
m_PawnHash[ply] = m_PawnHash[ply - 1];

if (m_Info[ply - 1].m_EnPassant) {
m_Hash[ply] ^= Lookup::zobrist[64 * 12 + 5 + (GET_SQUARE(m_Info[ply - 1].m_EnPassant) % 8)];
Expand All @@ -449,9 +454,11 @@ class Search {
switch (move.m_Capture) {
case MoveType::PAWN:
m_Hash[ply] ^= Lookup::zobrist[64 + tpos];
m_PawnHash[ply] ^= Lookup::zobrist[64 + tpos];
break;
case MoveType::EPASSANT:
m_Hash[ply] ^= Lookup::zobrist[56 + tpos];
m_PawnHash[ply] ^= Lookup::zobrist[56 + tpos];
break;
case MoveType::KNIGHT:
m_Hash[ply] ^= Lookup::zobrist[64 * 3 + tpos];
Expand All @@ -476,11 +483,13 @@ class Search {
switch (move.m_Type) {
case MoveType::PAWN:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[tpos] ^ Lookup::zobrist[fpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[tpos] ^ Lookup::zobrist[fpos];
m_Info[ply].m_HalfMoves = 0;
return Board(wp ^ swp, wkn, wb, wr, wq, wk, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::PAWN2:
m_Info[ply].m_EnPassant = move.m_To >> 8;
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[tpos] ^ Lookup::zobrist[fpos] ^ Lookup::zobrist[64 * 12 + 5 + (tpos % 8)];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[tpos] ^ Lookup::zobrist[fpos] ^ Lookup::zobrist[64 * 12 + 5 + (tpos % 8)];
m_Info[ply].m_HalfMoves = 0;
return Board(wp ^ swp, wkn, wb, wr, wq, wk, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::KNIGHT:
Expand Down Expand Up @@ -520,6 +529,7 @@ class Search {
return Board(wp, wkn, wb, wr, wq, wk ^ swp, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::EPASSANT:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[tpos] ^ Lookup::zobrist[fpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[tpos] ^ Lookup::zobrist[fpos];
return Board(wp ^ swp, wkn, wb, wr, wq, wk, bp & ~(move.m_To >> 8), bkn, bb, br, bq, bk);
case MoveType::KCASTLE:
m_Info[ply].m_WhiteCastleQueen = false;
Expand All @@ -545,15 +555,19 @@ class Search {
return Board(wp, wkn, wb, wr ^ 0b10010000ull, wq, wk ^ swp, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::P_KNIGHT:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[fpos] ^ Lookup::zobrist[64 * 2 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[fpos];
return Board(wp & (~move.m_From), wkn | move.m_To, wb, wr, wq, wk, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::P_BISHOP:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[fpos] ^ Lookup::zobrist[64 * 4 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[fpos];
return Board(wp & (~move.m_From), wkn, wb | move.m_To, wr, wq, wk, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::P_ROOK:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[fpos] ^ Lookup::zobrist[64 * 6 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[fpos];
return Board(wp & (~move.m_From), wkn, wb, wr | move.m_To, wq, wk, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::P_QUEEN:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[fpos] ^ Lookup::zobrist[64 * 8 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[fpos];
return Board(wp & (~move.m_From), wkn, wb, wr, wq | move.m_To, wk, bp & re, bkn & re, bb & re, br & re, bq & re, bk);
case MoveType::NONE:
assert("Invalid move!");
Expand All @@ -565,6 +579,7 @@ class Search {
case MoveType::PAWN:
case MoveType::PAWN2:
m_Hash[ply] ^= Lookup::zobrist[tpos];
m_PawnHash[ply] ^= Lookup::zobrist[tpos];
break;
case MoveType::EPASSANT:
m_Hash[ply] ^= Lookup::zobrist[8 + tpos];
Expand All @@ -590,11 +605,13 @@ class Search {
switch (move.m_Type) {
case MoveType::PAWN:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + tpos] ^ Lookup::zobrist[64 + fpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + tpos] ^ Lookup::zobrist[64 + fpos];
m_Info[ply].m_HalfMoves = 0;
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp ^ swp, bkn, bb, br, bq, bk);
case MoveType::PAWN2:
m_Info[ply].m_EnPassant = move.m_To << 8;
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + tpos] ^ Lookup::zobrist[64 + fpos] ^ Lookup::zobrist[64 * 12 + 5 + (tpos % 8)];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + tpos] ^ Lookup::zobrist[64 + fpos] ^ Lookup::zobrist[64 * 12 + 5 + (tpos % 8)];
m_Info[ply].m_HalfMoves = 0;
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp ^ swp, bkn, bb, br, bq, bk);
case MoveType::KNIGHT:
Expand Down Expand Up @@ -634,6 +651,7 @@ class Search {
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp, bkn, bb, br, bq, bk ^ swp);
case MoveType::EPASSANT:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + tpos] ^ Lookup::zobrist[64 + fpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + tpos] ^ Lookup::zobrist[64 + fpos];
return Board(wp & ~(move.m_To << 8), wkn, wb, wr, wq, wk, bp ^ swp, bkn, bb, br, bq, bk);
case MoveType::KCASTLE:
m_Info[ply].m_BlackCastleKing = false;
Expand All @@ -659,15 +677,19 @@ class Search {
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp, bkn, bb, br ^ (0b10010000ull << 56), bq, bk ^ swp);
case MoveType::P_KNIGHT:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + fpos] ^ Lookup::zobrist[3 * 64 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + fpos];
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp & (~move.m_From), bkn | move.m_To, bb, br, bq, bk);
case MoveType::P_BISHOP:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + fpos] ^ Lookup::zobrist[5 * 64 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + fpos];
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp & (~move.m_From), bkn, bb | move.m_To, br, bq, bk);
case MoveType::P_ROOK:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + fpos] ^ Lookup::zobrist[7 * 64 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + fpos];
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp & (~move.m_From), bkn, bb, br | move.m_To, bq, bk);
case MoveType::P_QUEEN:
m_Hash[ply] = m_Hash[ply] ^ Lookup::zobrist[64 + fpos] ^ Lookup::zobrist[9 * 64 + tpos];
m_PawnHash[ply] = m_PawnHash[ply] ^ Lookup::zobrist[64 + fpos];
return Board(wp & re, wkn & re, wb & re, wr & re, wq & re, wk, bp & (~move.m_From), bkn, bb, br, bq | move.m_To, bk);
case MoveType::NONE:
assert("Invalid move!");
Expand Down
Loading

0 comments on commit 4e6dd02

Please sign in to comment.