diff --git a/.github/workflows/cmake.yml b/.github/workflows/executable.yml
similarity index 65%
rename from .github/workflows/cmake.yml
rename to .github/workflows/executable.yml
index ce0e70a3..521a66d8 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/executable.yml
@@ -1,8 +1,14 @@
-name: CMake
+name: Executable
on:
push:
branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+ paths-ignore:
+ - .github/workflows/py_binding.yml
+ - src/Python/**
+ - pyproject.toml
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@@ -12,7 +18,7 @@ jobs:
build:
strategy:
matrix:
- arch: [ x86-64, x86-64-v2, x86-64-v3, x86-64-v4 ]
+ arch: [ x86-64, x86-64-v2, x86-64-v3, x86-64-v4, apple-m1, apple-m2, apple-m3, apple-m4 ]
os: [ ubuntu-latest , windows-latest, macos-latest ]
include:
- os: windows-latest
@@ -22,51 +28,65 @@ jobs:
arch: apple-m1
- os: windows-latest
arch: apple-m2
+ - os: windows-latest
+ arch: apple-m3
+ - os: windows-latest
+ arch: apple-m4
- os: ubuntu-latest
arch: apple-m1
- os: ubuntu-latest
arch: apple-m2
+ - os: ubuntu-latest
+ arch: apple-m3
+ - os: ubuntu-latest
+ arch: apple-m4
+ - os: macos-latest
+ arch: x86-64
+ - os: macos-latest
+ arch: x86-64-v2
+ - os: macos-latest
+ arch: x86-64-v3
+ - os: macos-latest
+ arch: x86-64-v4
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- if: matrix.os == 'ubuntu-latest'
name: Install Linux Dependencies
run: |
- sudo apt install libncurses5 ninja-build
+ sudo apt install ninja-build
sudo apt remove python3-lldb-14
- if: matrix.os == 'windows-latest'
name: Install Windows Dependencies
run: |
choco install ninja
- - if: matrix.os == 'macos-latest'
- name: Install MacOS Dependencies
- run: |
- brew install ninja
- if: matrix.os == 'ubuntu-latest'
- name: Install Clang 16 (Ubuntu)
+ name: Install Clang 20 (Ubuntu)
run: |
wget https://apt.llvm.org/llvm.sh
sudo chmod +x llvm.sh
- sudo ./llvm.sh 16
+ sudo ./llvm.sh 20
sudo rm -rf llvm.sh
- if: matrix.os == 'windows-latest'
- name: Install Clang 16 (Windows)
+ name: Install Clang 20 (Windows)
run: |
- choco install llvm --version 16.0.6 -y
+ choco install llvm --version 20.1.0 -y
- if: matrix.os == 'macos-latest'
- name: Install Clang 16 (MacOS)
+ name: Install Clang 20 (MacOS)
run: |
- brew install llvm@16
+ brew update-reset
+ brew update
+ brew install llvm@20
- if: matrix.os == 'ubuntu-latest'
name: Set CC and CXX for Linux
run: |
- echo "CC=clang-16" >> $GITHUB_ENV
- echo "CXX=clang++-16" >> $GITHUB_ENV
+ echo "CC=clang-20" >> $GITHUB_ENV
+ echo "CXX=clang++-20" >> $GITHUB_ENV
- if: matrix.os == 'windows-latest'
name: Set CC and CXX for Windows
shell: powershell
@@ -76,17 +96,17 @@ jobs:
- if: matrix.os == 'macos-latest'
name: Set CC and CXX for MacOS
run: |
- echo "CC=/usr/local/opt/llvm@16/bin/clang" >> $GITHUB_ENV
- echo "CXX=/usr/local/opt/llvm@16/bin/clang++" >> $GITHUB_ENV
- echo "PATH=/usr/local/opt/llvm@16/bin:$PATH" >> $GITHUB_ENV
+ echo "CC=/opt/homebrew/opt/llvm@20/bin/clang" >> $GITHUB_ENV
+ echo "CXX=/opt/homebrew/opt/llvm@20/bin/clang++" >> $GITHUB_ENV
+ echo "PATH=/opt/homebrew/opt/llvm@20/bin:$PATH" >> $GITHUB_ENV
- - if: matrix.arch == 'apple-m1' || matrix.arch == 'apple-m2'
- name: Configure CMake for Apple M1/M2 (ARM64)
- run: cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_CXX_FLAGS="--target=arm64 -mcpu=${{ matrix.arch }}" -G Ninja
+ - if: matrix.os == 'macos-latest'
+ name: Configure CMake for Apple (ARM64)
+ run: cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCI=ON -DCMAKE_CXX_FLAGS="-mcpu=${{ matrix.arch }}" -G Ninja
- - if: matrix.arch != 'apple-m1' && matrix.arch != 'apple-m2'
+ - if: matrix.os != 'macos-latest'
name: Configure CMake
- run: cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_CXX_FLAGS="-march=${{ matrix.arch }}" -G Ninja
+ run: cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCI=ON -DCMAKE_CXX_FLAGS="-march=${{ matrix.arch }}" -G Ninja
- name: Build
run: cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }}
@@ -109,7 +129,7 @@ jobs:
mv ${{ github.workspace }}/build/StockDory${{ matrix.extension }} ${{ github.workspace }}/StockDory-${{ env.VERSION }}-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.extension }}
- name: Upload Binary
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: StockDory-${{ env.VERSION }}-${{ matrix.os }}-${{ matrix.arch }}
path: ${{ github.workspace }}/StockDory-${{ env.VERSION }}-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.extension }}
diff --git a/.github/workflows/py_binding.yml b/.github/workflows/py_binding.yml
new file mode 100644
index 00000000..a9ffc590
--- /dev/null
+++ b/.github/workflows/py_binding.yml
@@ -0,0 +1,236 @@
+name: PyBinding
+
+on:
+ push:
+ branches: [ "master" ]
+ paths:
+ - pyproject.toml
+ - CMakeLists.txt
+ pull_request:
+ branches: [ "master" ]
+ paths:
+ - pyproject.toml
+ - CMakeLists.txt
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ arch: [ x86-64, x86-64-v2, x86-64-v3, x86-64-v4, apple-m1, apple-m2, apple-m3, apple-m4 ]
+ os: [ ubuntu-latest , windows-latest, macos-latest ]
+ python: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ]
+ exclude:
+ - os: windows-latest
+ arch: apple-m1
+ - os: windows-latest
+ arch: apple-m2
+ - os: windows-latest
+ arch: apple-m3
+ - os: windows-latest
+ arch: apple-m4
+ - os: ubuntu-latest
+ arch: apple-m1
+ - os: ubuntu-latest
+ arch: apple-m2
+ - os: ubuntu-latest
+ arch: apple-m3
+ - os: ubuntu-latest
+ arch: apple-m4
+ - os: macos-latest
+ arch: x86-64
+ - os: macos-latest
+ arch: x86-64-v2
+ - os: macos-latest
+ arch: x86-64-v3
+ - os: macos-latest
+ arch: x86-64-v4
+
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - if: matrix.os == 'ubuntu-latest'
+ name: Install Linux Dependencies
+ run: |
+ sudo apt install ninja-build
+ sudo apt remove python3-lldb-14
+ - if: matrix.os == 'windows-latest'
+ name: Install Windows Dependencies
+ run: |
+ choco install ninja
+
+ - if: matrix.os == 'ubuntu-latest'
+ name: Install Clang 20 (Ubuntu)
+ run: |
+ wget https://apt.llvm.org/llvm.sh
+ sudo chmod +x llvm.sh
+ sudo ./llvm.sh 20
+ sudo rm -rf llvm.sh
+ - if: matrix.os == 'windows-latest'
+ name: Install Clang 20 (Windows)
+ run: |
+ choco install llvm --version 20.1.0 -y
+ - if: matrix.os == 'macos-latest'
+ name: Install Clang 20 (MacOS)
+ run: |
+ brew update-reset
+ brew update
+ brew install llvm@20
+
+ - if: matrix.os == 'ubuntu-latest'
+ name: Set CC and CXX for Linux
+ run: |
+ echo "CC=clang-20" >> $GITHUB_ENV
+ echo "CXX=clang++-20" >> $GITHUB_ENV
+ - if: matrix.os == 'windows-latest'
+ name: Set CC and CXX for Windows
+ shell: powershell
+ run: |
+ echo "CC=clang" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ echo "CXX=clang++" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ - if: matrix.os == 'macos-latest'
+ name: Set CC and CXX for MacOS
+ run: |
+ echo "CC=/opt/homebrew/opt/llvm@20/bin/clang" >> $GITHUB_ENV
+ echo "CXX=/opt/homebrew/opt/llvm@20/bin/clang++" >> $GITHUB_ENV
+ echo "PATH=/opt/homebrew/opt/llvm@20/bin:$PATH" >> $GITHUB_ENV
+
+
+ - name: Setup Python ${{ matrix.python }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python }}
+
+ - name: Python Dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install scikit-build-core build twine pybind11 setuptools build tomlkit
+
+ - name: CMake Arguments (MacOS)
+ if: matrix.os == 'macos-latest'
+ run: |
+ echo "CMAKE_CXX_FLAGS=-mcpu=${{ matrix.arch }}" >> $GITHUB_ENV
+
+ - name: CMake Arguments (Linux)
+ if: matrix.os == 'ubuntu-latest'
+ run: |
+ echo "CMAKE_CXX_FLAGS=-march=${{ matrix.arch }}" >> $GITHUB_ENV
+
+ - name: CMake Arguments (Windows)
+ if: matrix.os == 'windows-latest'
+ shell: powershell
+ run: |
+ echo "CMAKE_CXX_FLAGS=-march=${{ matrix.arch }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+ - name: Set architecture environment variable (Windows)
+ if: matrix.os == 'windows-latest'
+ run: |
+ echo "ARCHITECTURE=${{ matrix.arch }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+ - name: Set architecture environment variable (Linux & MacOS)
+ if: matrix.os != 'windows-latest'
+ run: |
+ echo "ARCHITECTURE=${{ matrix.arch }}" >> $GITHUB_ENV
+
+ - name: Extract C++ Standard Library Version (Windows)
+ if: matrix.os == 'windows-latest'
+ shell: powershell
+ run: |
+ echo "Detecting STL version using $env:CXX"
+
+ $cxx_version = & $env:CXX -dM -E -x c++ NUL 2>$null | Select-String '_MSC_VER' | ForEach-Object {
+ if ($_ -match '_MSC_VER\s+(\d+)') {
+ "msvc$($matches[1])"
+ }
+ }
+
+ echo "CXX_VERSION=$cxx_version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+ - name: Extract C++ Standard Library Version (Linux & MacOS)
+ if: matrix.os != 'windows-latest'
+ shell: bash
+ run: |
+ echo "Detecting STL version on ${{ matrix.os }}"
+
+ if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
+ glibc_version=$(getconf GNU_LIBC_VERSION | awk '{print $2}')
+ STL_VERSION="libstdcxx${glibc_version}"
+ elif [[ "${{ matrix.os }}" == "macos-latest" ]]; then
+ clang_version=$(clang++ --version | grep -i 'clang version' | awk '{print $4}')
+ STL_VERSION="libcxx${clang_version}"
+ else
+ STL_VERSION="unknown"
+ fi
+
+ echo "Detected STL version: $STL_VERSION"
+ echo "CXX_VERSION=$STL_VERSION" >> $GITHUB_ENV
+
+ - name: Define version
+ shell: python
+ run: |
+ import os
+ import tomlkit
+
+ architecture = os.environ.get("ARCHITECTURE", "").replace("-", "_")
+ cxx_version = os.environ.get("CXX_VERSION", "")
+
+ with open("pyproject.toml", "r", encoding="utf-8") as f:
+ doc = tomlkit.parse(f.read())
+
+ doc["project"]["version"] = f"{doc['project']['version']}.arch.{architecture}.{cxx_version}"
+
+ with open("pyproject.toml", "w", encoding="utf-8") as f:
+ f.write(tomlkit.dumps(doc))
+
+ print(f"Set project version to {doc['project']['version']}")
+
+ - name: Build Wheel
+ run: |
+ python -m build
+
+ - name: Upload Wheel
+ uses: actions/upload-artifact@v4
+ with:
+ name: StockDory-python.${{ matrix.python }}-${{ matrix.os }}-${{ matrix.arch }}.whl
+ path: ./dist/*.whl
+
+ publish:
+ if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
+ needs: build
+ runs-on: ubuntu-latest
+
+ environment:
+ name: Python Packages Repository
+ url: https://pypi.fury.io/theblackplague/stockdory
+
+ steps:
+ - name: Download Wheels
+ uses: actions/download-artifact@v4
+ with:
+ path: dist
+ merge-multiple: true
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: 3.x
+
+ - name: Python Dependencies
+ run: |
+ python -m pip install --upgrade twine
+
+ - name: Show downloaded Wheels
+ run: ls -R dist
+
+ - name: Publish Wheels (Gemfury)
+ env:
+ FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
+ run: |
+ python -m twine upload \
+ --repository-url https://pypi.fury.io/theblackplague/ \
+ -u theblackplague \
+ -p "${FURY_TOKEN}" \
+ --non-interactive \
+ --skip-existing \
+ dist/*
diff --git a/.gitignore b/.gitignore
index fa52dbbf..128fd90f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,4 +76,11 @@ fabric.properties
.idea/httpRequests
# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
\ No newline at end of file
+.idea/caches/build_file_checksums.ser
+
+# Python Bindings Wheel
+dist/
+.venv/
+
+# Makefile
+Build/
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 00000000..086960cb
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+StockDory
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..9c799f54
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..79ee123c
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deployment.xml b/.idea/deployment.xml
new file mode 100644
index 00000000..c1975cda
--- /dev/null
+++ b/.idea/deployment.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
new file mode 100644
index 00000000..df886aaa
--- /dev/null
+++ b/.idea/editor.xml
@@ -0,0 +1,280 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/fileTemplates/internal/C Header File.h b/.idea/fileTemplates/internal/C Header File.h
new file mode 100644
index 00000000..d2964585
--- /dev/null
+++ b/.idea/fileTemplates/internal/C Header File.h
@@ -0,0 +1,5 @@
+#parse("C File Header.h")
+#[[#ifndef]]# STOCKDORY_${INCLUDE_GUARD}
+#[[#define]]# STOCKDORY_${INCLUDE_GUARD}
+
+#[[#endif]]# //STOCKDORY_${INCLUDE_GUARD}
diff --git a/.idea/fileTemplates/internal/C++ Class Header.h b/.idea/fileTemplates/internal/C++ Class Header.h
new file mode 100644
index 00000000..8c41c9e7
--- /dev/null
+++ b/.idea/fileTemplates/internal/C++ Class Header.h
@@ -0,0 +1,13 @@
+#parse("C File Header.h")
+#[[#ifndef]]# STOCKDORY_${INCLUDE_GUARD}
+#[[#define]]# STOCKDORY_${INCLUDE_GUARD}
+
+${NAMESPACES_OPEN}
+
+class ${NAME} {
+
+};
+
+${NAMESPACES_CLOSE}
+
+#[[#endif]]# //STOCKDORY_${INCLUDE_GUARD}
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 2a8f4e6e..d6fea122 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1,8 +1,13 @@
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 11daf914..b029fd4b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,12 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7f..f38acaaf 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,4 +3,7 @@
+
+
+
\ No newline at end of file
diff --git a/BinaryResource.cmake b/BinaryResource.cmake
index c9174ef9..cf4dbbb3 100644
--- a/BinaryResource.cmake
+++ b/BinaryResource.cmake
@@ -3,5 +3,5 @@ function(BinaryToHeader input_file output_file target_name)
string(LENGTH "${file_data}" file_size)
math(EXPR file_size "${file_size} / 2") # because each byte is represented by two hex characters
string(REGEX REPLACE "(..)" "0x\\1, " hex_data ${file_data})
- file(WRITE ${output_file} "constexpr unsigned char _${target_name}Data[] = { ${hex_data} };constexpr size_t _${target_name}Size = sizeof(_${target_name}Data);")
+ file(WRITE ${output_file} "constexpr unsigned char _${target_name}Data[] = { ${hex_data} };")
endfunction()
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8f7f272d..6ed0a395 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,22 +1,29 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.21)
project(StockDory)
set(VERSION "0.1" )
set(CODENAME "Starfish")
-if(CI)
- set(CI TRUE)
-else()
- set(CI FALSE)
-endif()
+option(BUILD_NATIVE "Enable native CPU architecture optimizations" ON)
+option(PYMODULE "Enable if building Python Bindings" OFF)
+option(CI "Enable if building via Continuous Integration such as Github Actions" OFF)
+option(PGO "Enable profile-guided optimization - uses existing profile or creates instrumentation executable" OFF)
+
+set(CMAKE_CXX_STANDARD 23)
-set(CMAKE_CXX_STANDARD 20)
if(CMAKE_CXX_FLAGS STREQUAL "")
- set(CMAKE_CXX_FLAGS "-march=native")
+ set(CMAKE_CXX_FLAGS "$ENV{CMAKE_CXX_FLAGS}")
+endif()
+
+if(BUILD_NATIVE AND NOT (PYMODULE OR CI))
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+else()
+ set(NANOTHREAD_NATIVE_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
-if(PGO MATCHES "True")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=full")
+
+if(PGO)
message(STATUS "PGO: Enabled")
if(EXISTS ${CMAKE_BINARY_DIR}/pgo.profdata)
message(STATUS "PGO: Using existing profile data at: ${CMAKE_BINARY_DIR}/pgo.profdata")
@@ -30,9 +37,7 @@ endif()
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Wextra -g -ftime-report")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
-set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
-
-set(CPM_DOWNLOAD_VERSION 0.38.0)
+set(CPM_DOWNLOAD_VERSION 0.40.8)
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
@@ -41,7 +46,7 @@ elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
message(STATUS "Setting CPM.cmake location to ${CPM_DOWNLOAD_LOCATION}")
else()
- set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
+ set(CPM_DOWNLOAD_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
message(STATUS "Setting CPM.cmake location to ${CPM_DOWNLOAD_LOCATION}")
endif()
@@ -51,9 +56,9 @@ foreach(DOWNLOAD_ATTEMPT RANGE 1 ${CPM_DOWNLOAD_RETRY_COUNT})
message(STATUS "CPM.cmake was not found at ${CPM_DOWNLOAD_LOCATION}")
message(STATUS "Attempt: ${DOWNLOAD_ATTEMPT}/${CPM_DOWNLOAD_RETRY_COUNT}: Downloading CPM.cmake...")
file(DOWNLOAD
- https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
- ${CPM_DOWNLOAD_LOCATION}
- STATUS DOWNLOAD_STAT
+ https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
+ ${CPM_DOWNLOAD_LOCATION}
+ STATUS DOWNLOAD_STAT
)
list(GET DOWNLOAD_STAT 0 DOWNLOAD_RES)
if(NOT DOWNLOAD_RES EQUAL 0)
@@ -76,7 +81,20 @@ endforeach()
include(${CPM_DOWNLOAD_LOCATION})
-CPMAddPackage("gh:TheBlackPlague/MantaRay#4038386a746ae65881e7d1f02673e1805f729cc9")
+CPMAddPackage(
+ NAME MantaRay
+ GITHUB_REPOSITORY TheBlackPlague/MantaRay
+ GIT_TAG 1c547d179c7cdf4f24e4f8a1fea228c6178d0ae2
+ OPTIONS
+ "BUILD_TEST OFF"
+ "BUILD_MB OFF"
+)
+
+CPMAddPackage(
+ NAME nanothread
+ GITHUB_REPOSITORY TheBlackPlague/nanothread
+ GIT_TAG master
+)
include(BinaryResource.cmake)
@@ -110,13 +128,56 @@ file(GLOB StockDoryFrontendType
"src/Terminal/UCI/*.h"
"src/Terminal/*.h")
-add_executable(StockDory src/Terminal/main.cpp
- ${StockDoryBackendType} ${StockDoryEngineType} ${StockDoryExternalType} ${StockDoryFrontendType})
+if(PYMODULE)
+ message(STATUS "Configured to build Python Module")
+
+ if(UNIX AND NOT APPLE)
+ message(STATUS "Enabling Position-Independent Code")
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+ set_target_properties(nanothread PROPERTIES POSITION_INDEPENDENT_CODE ON)
+ endif()
-target_include_directories(StockDory PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+ set(PYBIND11_FINDPYTHON ON)
+ CPMAddPackage("gh:pybind/pybind11#a2e59f0e7065404b44dfe92a28aca47ba1378dc4")
-target_link_libraries(StockDory MantaRay)
+ pybind11_add_module(StockDory src/Python/binding.cpp
+ ${StockDoryBackendType}
+ ${StockDoryEngineType}
+ ${StockDoryExternalType}
+ ${StockDoryFrontendType}
+ )
-if(NOT WIN32)
- target_link_libraries(StockDory pthread)
-endif()
\ No newline at end of file
+ target_include_directories(StockDory PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+ target_link_libraries(StockDory PRIVATE MantaRay nanothread)
+ if(NOT WIN32)
+ target_link_libraries(StockDory PRIVATE pthread)
+ endif()
+
+ install(TARGETS StockDory DESTINATION .)
+else()
+ message(STATUS "Configured to build executable")
+
+ add_executable(StockDory src/Terminal/main.cpp
+ ${StockDoryBackendType}
+ ${StockDoryEngineType}
+ ${StockDoryExternalType}
+ ${StockDoryFrontendType}
+ )
+
+ target_include_directories(StockDory PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+ target_link_libraries(StockDory MantaRay nanothread)
+ if(NOT WIN32)
+ target_link_libraries(StockDory pthread)
+ endif()
+
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
+endif()
+
+message(STATUS "NANOTHREAD COMPILATION: ${NANOTHREAD_NATIVE_FLAGS}")
+
+message(STATUS "CXX FLAGS: ${CMAKE_CXX_FLAGS}" )
+if(CMAKE_BUILD_TYPE MATCHES "Debug")
+ message(STATUS "CXX DEBUG FLAGS: ${CMAKE_CXX_FLAGS_DEBUG}" )
+elseif(CMAKE_BUILD_TYPE MATCHES "Release")
+ message(STATUS "CXX RELEASE FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
+endif()
diff --git a/Information.cmake b/Information.cmake
index 3693dbc7..0703683e 100644
--- a/Information.cmake
+++ b/Information.cmake
@@ -18,7 +18,7 @@ function(Information VERSION CODENAME DEV)
#include
const std::string NAME = \"StockDory\" \;
- const std::string AUTHOR = \"the StockDory Author\" \;
+ const std::string AUTHOR = \"the StockDory Authors\" \;
const std::string VERSION = \"${CODENAME}-${VERSION}\"\;
const std::string LICENSE = \"LGPL-3.0\" \;
diff --git a/Makefile b/Makefile
index 1cb9a153..44cbf342 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,33 @@
+# === Configuration ===
+
+# User-overridable variables
+CC ?= clang
+CXX ?= clang++
+EXE ?= StockDory
+
+# Detect OS and set environment-specific variables
ifeq ($(OS),Windows_NT)
- CP = powershell -Command "Copy-Item"
- RM = powershell -Command "Remove-Item -Recurse -Force"
- EXTENSION = .exe
+ CP = powershell -Command "Copy-Item -Force"
+ RM = powershell -Command "Remove-Item -Recurse -Force"
+ EXT = .exe
LLVM_PROFDATA = llvm-profdata
- SLASH = \\
+ SLASH = \\
else
- CP = cp
- RM = rm
- EXTENSION =
- LLVM_PROFDATA = llvm-profdata-16
- SLASH = /
+ UNIX_OS := $(shell uname -s)
+
+ CP = cp
+ RM = rm -rf
+ EXT =
+ LLVM_PROFDATA = llvm-profdata-20
+ SLASH = /
+
+ ifeq ($(UNIX_OS), Darwin)
+ LLVM_PROFDATA = llvm-profdata
+ endif
endif
+# === Targets ===
+
all: openbench
openbench:
@@ -19,11 +35,39 @@ ifdef EVALFILE
$(RM) src/Engine/Model/* && \
$(CP) $(EVALFILE) src/Engine/Model/
endif
- cmake -B RB -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -G Ninja -DPGO=True && \
- cmake --build RB --config Release && \
- RB$(SLASH)StockDory$(EXTENSION) bench && \
- $(LLVM_PROFDATA) merge -output=RB/pgo.profdata RB/pgo.profraw && \
- $(RM) RB/StockDory$(EXTENSION) && \
- cmake -B RB -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -G Ninja -DPGO=True && \
- cmake --build RB --config Release && \
- $(CP) RB/StockDory$(EXTENSION) StockDory$(EXTENSION)
+ @echo "[*] Performing initial build for profiling..."
+ cmake -B Build -G Ninja \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_C_COMPILER=$(CC) \
+ -DCMAKE_CXX_COMPILER=$(CXX) \
+ -DBUILD_NATIVE=ON \
+ -DPGO=ON
+ cmake --build Build --config Release
+
+ @echo "[*] Running benchmark to generate profiling data..."
+ Build$(SLASH)StockDory$(EXT) bench
+
+ @echo "[*] Merging profiling data..."
+ $(LLVM_PROFDATA) merge -output=Build/pgo.profdata Build/pgo.profraw
+ $(RM) Build$(SLASH)StockDory$(EXT)
+ $(RM) Build$(SLASH)pgo.profraw
+
+ @echo "[*] Performing optimized build with profiling data..."
+ cmake -B Build -G Ninja \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_C_COMPILER=$(CC) \
+ -DCMAKE_CXX_COMPILER=$(CXX) \
+ -DBUILD_NATIVE=ON \
+ -DPGO=ON
+ cmake --build Build --config Release
+
+ @echo "[*] Copying final binary to root directory..."
+ $(CP) Build$(SLASH)StockDory$(EXT) $(EXE)$(EXT)
+
+# === Utility Targets ===
+
+clean:
+ $(RM) Build
+ $(RM) $(EXE)$(EXT)
+
+.PHONY: all openbench clean
diff --git a/README.md b/README.md
index c09c3879..f7c0b403 100644
--- a/README.md
+++ b/README.md
@@ -37,8 +37,8 @@ instructions below.
StockDory is written in C++ and uses CMake as its build system.
**Requirements**:
-- 🏭 CMake >= 3.15
-- 🐉 Clang (LLVM) >= 16.0.0
+- 🏭 CMake >= 3.21
+- 🐉 Clang (LLVM) >= 20.0.0
- 🥷 Ninja >= 1.10.2
**Steps**:
@@ -86,7 +86,7 @@ If you would like to report a bug, please open an issue on this GitHub repositor
If you would like to contribute to the codebase, please fork this repository,
create a new branch (naming it appropriately for the changes you are making),
make your changes.
-Then, create an account on the [FindingChess Testing Framework](http://tests.findingchess.com/).
+Then, create an account on [Verdict](http://verdict.shaheryarsohail.com/).
Once your account is approved, appropriately set the source repository on your profile, and
create a test for your branch.
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..47bf070a
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,29 @@
+[build-system]
+requires = [
+ "scikit-build-core>=0.10.0",
+ "pybind11"
+]
+build-backend = "scikit_build_core.build"
+
+[project]
+name = "StockDory"
+version = "0.1+0"
+description = "Python Bindings for StockDory"
+readme = "README.md"
+license = { file = "LICENSE" }
+requires-python = ">=3.7"
+authors = [
+ { name = "StockDory Authors" }
+]
+keywords = [ "chess", "engine", "nnue" ]
+classifiers = [
+ "Programming Language :: Python :: 3",
+ "Operating System :: Microsoft :: Windows",
+]
+
+[tool.scikit-build]
+build.verbose = true
+cmake.args = ["-G", "Ninja"]
+cmake.define = { "CMAKE_BUILD_TYPE" = "Release", "PYMODULE" = "ON" }
+
+wheel.install-dir = ""
diff --git a/src/Backend/Board.h b/src/Backend/Board.h
index 9e2732f0..1f3c7949 100644
--- a/src/Backend/Board.h
+++ b/src/Backend/Board.h
@@ -7,725 +7,724 @@
#define STOCKDORY_BOARD_H
#include
-#include
#include
+#include
+#include
#include "Type/BitBoard.h"
-#include "Type/Piece.h"
+#include "Type/CheckBitBoard.h"
#include "Type/Color.h"
+#include "Type/Piece.h"
#include "Type/PieceColor.h"
#include "Type/PinBitBoard.h"
-#include "Type/CheckBitBoard.h"
#include "Type/PreviousState.h"
#include "Type/Zobrist.h"
#include "Template/MoveType.h"
#include "Move/AttackTable.h"
-#include "Move/UtilityTable.h"
#include "Move/BlackMagicFactory.h"
+#include "Move/RayTable.h"
#include "../External/strutil.h"
#include "../Engine/Evaluation.h"
-#include "Util.h"
-
namespace StockDory
{
class Board
{
- private:
- std::array, 3> BB {};
-
- std::array PieceAndColor {};
+ constexpr static uint8_t CastlingMask = 0xF;
+ constexpr static uint8_t WhiteKCastleMask = 0x8;
+ constexpr static uint8_t WhiteQCastleMask = 0x4;
+ constexpr static uint8_t BlackKCastleMask = 0x2;
+ constexpr static uint8_t BlackQCastleMask = 0x1;
- std::array ColorBB {};
+ constexpr static uint8_t ColorFlipMask = 0x10;
- // [COLOR TO MOVE] [WHITE KING CASTLE] [WHITE QUEEN CASTLE] [BLACK KING CASTLE] [BLACK QUEEN CASTLE]
- // [ 4 BITS ] [ 1 BIT ] [ 1 BIT ] [ 1 BIT ] [ 1 BIT ]
- uint8_t CastlingRightAndColorToMove = 0;
+ constexpr static std::array ColorCastleMask {
+ WhiteKCastleMask | WhiteQCastleMask,
+ BlackKCastleMask | BlackQCastleMask,
+ 0
+ };
- BitBoard EnPassantTarget = BBDefault;
+ std::array, 3> BB {};
- ZobristHash Hash = 0;
+ std::array PieceAndColor {};
- constexpr static uint8_t CastlingMask = 0x0F;
- constexpr static uint8_t WhiteKCastleMask = 0x08;
- constexpr static uint8_t WhiteQCastleMask = 0x04;
- constexpr static uint8_t BlackKCastleMask = 0x02;
- constexpr static uint8_t BlackQCastleMask = 0x01;
+ std::array ColorBB {};
- constexpr static uint8_t ColorFlipMask = 0x10;
+ // [COLOR TO MOVE] [WHITE KING CASTLE] [WHITE QUEEN CASTLE] [BLACK KING CASTLE] [BLACK QUEEN CASTLE]
+ // [ 4 BITS ] [ 1 BIT ] [ 1 BIT ] [ 1 BIT ] [ 1 BIT ]
+ uint8_t CastlingRightAndColorToMove = 0;
- constexpr static std::array ColorCastleMask {
- WhiteKCastleMask | WhiteQCastleMask,
- BlackKCastleMask | BlackQCastleMask
- };
+ BitBoard EnPassantTarget = BBDefault;
- constexpr static std::array, 2> CastleRookSquareStart {{
- {Square::H1, Square::A1},
- {Square::H8, Square::A8}
- }};
-
- constexpr static std::array, 2> CastleRookSquareEnd {{
- {Square::F1, Square::D1},
- {Square::F8, Square::D8}
- }};
+ ZobristHash Hash = 0;
public:
- Board() : Board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") {}
-
- explicit Board(const std::string& fen)
- {
- PieceColor none = PieceColor(NAP, NAC);
- std::fill(std::begin(PieceAndColor), std::end(PieceAndColor), none);
+ Board() : Board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") {}
- for (uint8_t i = 0; i < 3; i++)
- std::fill(std::begin(BB[i]), std::end(BB[i]), BBDefault);
+ Board(const std::string& fen)
+ {
+ constexpr auto none = PieceColor(NAP, NAC);
+ std::ranges::fill(PieceAndColor, none);
- std::vector splitFen = strutil::split(fen, " ");
+ for (uint8_t i = 0; i < 3; i++)
+ std::ranges::fill(BB[i], BBDefault);
- assert(splitFen.size() == 6);
+ const std::vector splitFen = strutil::split(fen, " ");
- std::vector splitPosition = strutil::split(splitFen[0], "/");
- std::reverse(splitPosition.begin(), splitPosition.end());
+ assert(splitFen.size() == 6);
- assert(splitPosition.size() == 8);
+ std::vector splitPosition = strutil::split(splitFen[0], "/");
+ std::ranges::reverse(splitPosition);
- for (uint8_t v = 0; v < 8; v++) {
- std::string& rankStr = splitPosition[v];
- uint8_t h = 0;
- for (char p : rankStr) {
- if (isdigit(p)) {
- h += static_cast(p - 48);
- continue;
- }
+ assert(splitPosition.size() == 8);
- Color color = Black;
-
- if (isupper(p)) color = White;
-
- Piece piece = NAP;
- switch (tolower(p)) {
- case 'p':
- piece = Pawn;
- break;
- case 'n':
- piece = Knight;
- break;
- case 'b':
- piece = Bishop;
- break;
- case 'r':
- piece = Rook;
- break;
- case 'q':
- piece = Queen;
- break;
- case 'k':
- piece = King;
- break;
- }
-
- uint8_t idx = v * 8 + h;
- auto sq = static_cast(idx);
- Set(BB[color][piece], sq);
- PieceAndColor[idx] = PieceColor(piece, color);
- if (piece == NAP) std::cout << "ERROR" << std::endl;
- Hash = HashPiece(Hash, piece, color, sq);
+ for (uint8_t v = 0; v < 8; v++) {
+ std::string& rankStr = splitPosition[v];
+ uint8_t h = 0;
+ for (const char p: rankStr) {
+ if (isdigit(p)) {
+ h += static_cast(p - 48);
+ continue;
+ }
- h++;
+ Color color = Black;
+
+ if (isupper(p)) color = White;
+
+ Piece piece = NAP;
+ switch (tolower(p)) {
+ case 'p':
+ piece = Pawn;
+ break;
+ case 'n':
+ piece = Knight;
+ break;
+ case 'b':
+ piece = Bishop;
+ break;
+ case 'r':
+ piece = Rook;
+ break;
+ case 'q':
+ piece = Queen;
+ break;
+ case 'k':
+ piece = King;
+ break;
+ default:;
}
- }
- if (splitFen[1][0] == 'w') {
- CastlingRightAndColorToMove = White << 4;
- Hash = HashColorFlip(Hash);
- } else {
- CastlingRightAndColorToMove = Black << 4;
- }
+ uint8_t idx = v * 8 + h;
+ const auto sq = static_cast(idx);
- std::string& castlingData = splitFen[2];
- CastlingRightAndColorToMove |= (castlingData.find('K') != std::string::npos ? 0x8 : 0x0);
- CastlingRightAndColorToMove |= (castlingData.find('Q') != std::string::npos ? 0x4 : 0x0);
- CastlingRightAndColorToMove |= (castlingData.find('k') != std::string::npos ? 0x2 : 0x0);
- CastlingRightAndColorToMove |= (castlingData.find('q') != std::string::npos ? 0x1 : 0x0);
+ Set(BB[color][piece], sq);
- Hash = HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
+ PieceAndColor[idx] = PieceColor(piece, color);
- EnPassantTarget = BBDefault;
- std::string& epData = splitFen[3];
- if (epData.length() == 2) {
- Square epSq = Util::StringToSquare(epData);
+ if (piece == NAP) std::cout << "ERROR" << std::endl;
- if (AttackTable::Pawn[Opposite(ColorToMove())][epSq] & BB[ColorToMove()][Pawn]) {
- EnPassantTarget = FromSquare(epSq);
- Hash = HashEnPassant(Hash, epSq);
- }
- }
+ Hash = Zobrist::HashPiece(Hash, piece, color, sq);
- ColorBB[Color::White] = BBDefault;
- ColorBB[Color::Black] = BBDefault;
- for (Piece p = Pawn; p != NAP; p = Next(p)) {
- ColorBB[White] |= BB[White][p];
- ColorBB[Black] |= BB[Black][p];
+ h++;
}
- ColorBB[NAC] = ~(ColorBB[White] | ColorBB[Black]);
}
- inline void LoadForEvaluation() const
- {
- Evaluation::ResetNetworkState();
-
- for (Square sq = A1; sq < NASQ; sq = Next(sq)) {
- PieceColor pc = PieceAndColor[sq];
- if (pc.Piece() == NAP || pc.Color() == NAC) continue;
-
- Evaluation::Activate(pc.Piece(), pc.Color(), sq);
- }
+ if (splitFen[1][0] == 'w') {
+ CastlingRightAndColorToMove = White << 4;
+ Hash = Zobrist::HashColorFlip(Hash);
+ } else {
+ CastlingRightAndColorToMove = Black << 4;
}
- [[nodiscard]]
- inline std::string Fen() const
- {
- std::array fenRank;
-
- for (uint8_t v = 0; v < 8; v++) {
- std::stringstream rankStr;
- uint8_t e = 0;
- for (uint8_t h = 0; h < 8; h++) {
- const PieceColor pc = PieceAndColor[v * 8 + h];
-
- if (pc.Piece() == NAP) {
- e++;
-
- if (h == 7) {
- rankStr << static_cast(e);
- e = 0;
- }
- continue;
- }
+ const std::string& castlingData = splitFen[2];
+ CastlingRightAndColorToMove |= castlingData.find('K') != std::string::npos ? WhiteKCastleMask : 0x0;
+ CastlingRightAndColorToMove |= castlingData.find('Q') != std::string::npos ? WhiteQCastleMask : 0x0;
+ CastlingRightAndColorToMove |= castlingData.find('k') != std::string::npos ? BlackKCastleMask : 0x0;
+ CastlingRightAndColorToMove |= castlingData.find('q') != std::string::npos ? BlackQCastleMask : 0x0;
- if (e != 0) {
- rankStr << static_cast(e);
- e = 0;
- }
+ Hash = Zobrist::HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
- char p;
-
- switch (pc.Piece()) {
- case Pawn:
- p = 'p';
- break;
- case Knight:
- p = 'n';
- break;
- case Bishop:
- p = 'b';
- break;
- case Rook:
- p = 'r';
- break;
- case Queen:
- p = 'q';
- break;
- case King:
- p = 'k';
- break;
- case NAP:
- break;
- }
-
- if (pc.Color() == White) p = static_cast(toupper(p));
-
- rankStr << p;
- }
-
- fenRank[v] = rankStr.str();
+ EnPassantTarget = BBDefault;
+ if (const std::string& epData = splitFen[3]; epData.length() == 2) {
+ if (const Square epSq = FromString(epData);
+ AttackTable::Pawn[Opposite(ColorToMove())][epSq] & BB[ColorToMove()][Pawn]) {
+ EnPassantTarget = FromSquare(epSq);
+ Hash = Zobrist::HashEnPassant(Hash, epSq);
}
-
- std::stringstream fen;
- for (uint8_t v = 0; v < 8; v++) {
- fen << fenRank[7 - v];
- if (v != 7) fen << '/';
- }
-
- fen << ' ';
- fen << (ColorToMove() == White ? 'w' : 'b');
- fen << ' ';
-
- if (CastlingRightAndColorToMove & CastlingMask) {
- if (CastlingRightAndColorToMove & WhiteKCastleMask) fen << 'K';
- if (CastlingRightAndColorToMove & WhiteQCastleMask) fen << 'Q';
- if (CastlingRightAndColorToMove & BlackKCastleMask) fen << 'k';
- if (CastlingRightAndColorToMove & BlackQCastleMask) fen << 'q';
- } else fen << '-';
-
- fen << ' ';
- if (EnPassantSquare() != NASQ) fen << Util::SquareToString(ToSquare(EnPassantTarget));
- else fen << '-';
-
- // Implement half and full move clocks.
- fen << ' ';
- fen << '0';
- fen << ' ';
- fen << '1';
-
- return fen.str();
}
- [[nodiscard]]
- constexpr inline ZobristHash Zobrist() const
- {
- return Hash;
+ ColorBB[White] = BBDefault;
+ ColorBB[Black] = BBDefault;
+ for (Piece p = Pawn; p != NAP; p = Next(p)) {
+ ColorBB[White] |= BB[White][p];
+ ColorBB[Black] |= BB[Black][p];
}
+ ColorBB[NAC] = ~(ColorBB[White] | ColorBB[Black]);
+ }
- constexpr inline PieceColor operator [](const Square sq) const
- {
- return PieceAndColor[sq];
- }
+ void LoadForEvaluation() const
+ {
+ Evaluation::ResetNetworkState();
- constexpr inline BitBoard operator [](const Color c) const
- {
- return ColorBB[c];
- }
-
- template
- [[nodiscard]]
- constexpr inline BitBoard PieceBoard(const Piece p) const
- {
- assert(p != NAP);
- assert(Color != NAC);
+ for (Square sq = A1; sq < NASQ; sq = Next(sq)) {
+ PieceColor pc = PieceAndColor[sq];
+ if (pc.Piece() == NAP || pc.Color() == NAC) continue;
- return BB[Color][p];
+ Evaluation::Activate(pc.Piece(), pc.Color(), sq);
}
+ }
- [[nodiscard]]
- constexpr inline BitBoard PieceBoard(const Piece p, const Color c) const
- {
- assert(p != NAP);
- assert(c != NAC);
+ std::string Fen() const
+ {
+ std::array fenRank;
- return BB[c][p];
- }
+ for (uint8_t v = 0; v < 8; v++) {
+ std::stringstream rankStr;
+ uint8_t e = 0;
+ for (uint8_t h = 0; h < 8; h++) {
+ const PieceColor pc = PieceAndColor[v * 8 + h];
- [[nodiscard]]
- constexpr inline Color ColorToMove() const
- {
- return static_cast(CastlingRightAndColorToMove >> 4);
- }
+ if (pc.Piece() == NAP) {
+ e++;
- template
- [[nodiscard]]
- constexpr inline bool CastlingRightK() const
- {
- if (Color == White) return CastlingRightAndColorToMove & WhiteKCastleMask;
- if (Color == Black) return CastlingRightAndColorToMove & BlackKCastleMask;
+ if (h == 7) {
+ rankStr << static_cast(e);
+ e = 0;
+ }
+ continue;
+ }
- throw std::invalid_argument("Invalid color");
- }
+ if (e != 0) {
+ rankStr << static_cast(e);
+ e = 0;
+ }
- template
- [[nodiscard]]
- constexpr inline bool CastlingRightQ() const
- {
- if (Color == White) return CastlingRightAndColorToMove & WhiteQCastleMask;
- if (Color == Black) return CastlingRightAndColorToMove & BlackQCastleMask;
+ char p = ' ';
+
+ switch (pc.Piece()) {
+ case Pawn:
+ p = 'p';
+ break;
+ case Knight:
+ p = 'n';
+ break;
+ case Bishop:
+ p = 'b';
+ break;
+ case Rook:
+ p = 'r';
+ break;
+ case Queen:
+ p = 'q';
+ break;
+ case King:
+ p = 'k';
+ break;
+ case NAP:
+ break;
+ }
- throw std::invalid_argument("Invalid color");
- }
+ if (pc.Color() == White) p = static_cast(toupper(p));
- [[nodiscard]]
- constexpr inline BitBoard EnPassant() const
- {
- return EnPassantTarget;
- }
+ rankStr << p;
+ }
- [[nodiscard]]
- constexpr inline Square EnPassantSquare() const
- {
- return ToSquare(EnPassantTarget);
+ fenRank[v] = rankStr.str();
}
- template
- [[nodiscard]]
- constexpr inline bool Checked() const
- {
- constexpr Color by = Opposite(We);
-
- const Square king = ToSquare(BB[We][King]);
+ std::stringstream fen;
+ for (uint8_t v = 0; v < 8; v++) {
+ fen << fenRank[7 - v];
+ if (v != 7) fen << '/';
+ }
- if (AttackTable::Pawn[We][king] & BB[by][Pawn]) return true;
+ fen << ' ';
+ fen << (ColorToMove() == White ? 'w' : 'b');
+ fen << ' ';
+
+ if (CastlingRightAndColorToMove & CastlingMask) {
+ if (CastlingRightAndColorToMove & WhiteKCastleMask) fen << 'K';
+ if (CastlingRightAndColorToMove & WhiteQCastleMask) fen << 'Q';
+ if (CastlingRightAndColorToMove & BlackKCastleMask) fen << 'k';
+ if (CastlingRightAndColorToMove & BlackQCastleMask) fen << 'q';
+ } else fen << '-';
+
+ fen << ' ';
+ if (EnPassantSquare() != NASQ) fen << ToString(ToSquare(EnPassantTarget));
+ else fen << '-';
+
+ // Implement half and full move clocks.
+ fen << ' ';
+ fen << '0';
+ fen << ' ';
+ fen << '1';
+
+ return fen.str();
+ }
+
+ ZobristHash Zobrist() const
+ {
+ return Hash;
+ }
+
+ PieceColor operator [](const Square sq) const
+ {
+ return PieceAndColor[sq];
+ }
+
+ BitBoard operator [](const Color c) const
+ {
+ return ColorBB[c];
+ }
+
+ template
+ BitBoard PieceBoard(const Piece p) const
+ {
+ assert(p != NAP);
+ assert(Color != NAC);
+
+ return BB[Color][p];
+ }
+
+ [[nodiscard]]
+ BitBoard PieceBoard(const Piece p, const Color c) const
+ {
+ assert(p != NAP);
+ assert(c != NAC);
+
+ return BB[c][p];
+ }
+
+ Color ColorToMove() const
+ {
+ return static_cast(CastlingRightAndColorToMove >> 4);
+ }
+
+ template
+ bool CastlingRightK() const
+ {
+ if (Color == White) return CastlingRightAndColorToMove & WhiteKCastleMask;
+ if (Color == Black) return CastlingRightAndColorToMove & BlackKCastleMask;
+
+ throw std::invalid_argument("Invalid color");
+ }
+
+ template
+ bool CastlingRightQ() const
+ {
+ if (Color == White) return CastlingRightAndColorToMove & WhiteQCastleMask;
+ if (Color == Black) return CastlingRightAndColorToMove & BlackQCastleMask;
+
+ throw std::invalid_argument("Invalid color");
+ }
+
+ BitBoard EnPassant() const
+ {
+ return EnPassantTarget;
+ }
+
+ Square EnPassantSquare() const
+ {
+ return ToSquare(EnPassantTarget);
+ }
+
+ template
+ bool Checked() const
+ {
+ constexpr Color by = Opposite(We);
+
+ const Square king = ToSquare(BB[We][King]);
+
+ if (AttackTable::Pawn[We][king] & BB[by][Pawn]) return true;
+
+ if (AttackTable::Knight[king] & BB[by][Knight]) return true;
+
+ const BitBoard occupied = ~ColorBB[NAC];
+ const BitBoard queen = BB[by][Queen];
+
+ if (AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, king, occupied)] &
+ (queen | BB[by][Bishop]))
+ return true;
+
+ if (AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook , king, occupied)] &
+ (queen | BB[by][ Rook ]))
+ return true;
+
+ return AttackTable::King[king] & BB[by][King];
+ }
+
+ template
+ CheckBitBoard Check() const
+ {
+ uint8_t count = 0;
+ auto check = CheckBitBoard();
+
+ const Square sq = ToSquare(BB[Opposite(By)][King]);
+
+ // Check if the square is under attack by opponent knights or pawns.
+ const BitBoard pawnCheck = AttackTable::Pawn[Opposite(By)][sq] & BB[By][Pawn];
+ const BitBoard knightCheck = AttackTable::Knight[sq] & BB[By][Knight];
+
+ // If the square is under attack by a pawn or knight, add it our checks.
+ check.Check |= pawnCheck;
+ check.Check |= knightCheck;
+
+ // Increment the count if there are checks.
+ count += static_cast(pawnCheck);
+ count += static_cast(knightCheck);
+
+ // Check if the square is under attack by opponent bishops, rooks, or queens.
+ // For queen, we can merge with checks for bishop and rook.
+ const BitBoard queen = BB[By][Queen];
- if (AttackTable::Knight[king] & BB[by][Knight]) return true;
+ // All the occupied squares:
+ const BitBoard occupied = ~ColorBB[NAC];
+
+ // Check if the square is under attack by opponent bishops or queens (diagonally).
+ const BitBoard diagonalCheck =
+ AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, sq, occupied)] &
+ (queen | BB[By][Bishop]);
- const BitBoard occupied = ~ColorBB[NAC];
- const BitBoard queen = BB[by][Queen];
+ // Check if the square is under attack by opponent rooks or queens (straight).
+ const BitBoard straightCheck =
+ AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook, sq, occupied)] &
+ (queen | BB[By][Rook]);
- if (AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, king, occupied)] &
- (queen | BB[by][Bishop])) return true;
+ // For sliding attacks, we must add the square of the attack's origin and all the squares to us from the
+ // attack:
+ if (diagonalCheck) {
+ const Square diagonalCheckSq = ToSquare(diagonalCheck);
+ check.Check |= RayTable::Between[sq][diagonalCheckSq] | FromSquare(diagonalCheckSq);
+ }
- if (AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook , king, occupied)] &
- (queen | BB[by][Rook ])) return true;
+ if (straightCheck) {
+ const Square straightCheckSq = ToSquare(straightCheck);
+ check.Check |= RayTable::Between[sq][straightCheckSq] | FromSquare(straightCheckSq);
- return AttackTable::King[king] & BB[by][King];
+ // In the case where there is more than one check, we must increment the count once more, as it's a
+ // double check.
+ if (Count(straightCheck) > 1) count++;
}
- template
- [[nodiscard]]
- constexpr inline CheckBitBoard Check() const
- {
- uint8_t count = 0;
- CheckBitBoard check = CheckBitBoard();
+ count += static_cast(diagonalCheck);
+ count += static_cast(straightCheck);
- const Square sq = ToSquare(BB[Opposite(By)][King]);
+ if (check.Check == BBDefault) check.Check = BBFilled;
- // Check if the square is under attack by opponent knights or pawns.
- const BitBoard pawnCheck = AttackTable::Pawn[Opposite(By)][sq] & BB[By][Pawn ];
- const BitBoard knightCheck = AttackTable::Knight [sq] & BB[By][Knight];
+ check.DoubleCheck = count > 1;
+ return check;
+ }
- // If the square is under attack by a pawn or knight, add it our checks.
- check.Check |= pawnCheck;
- check.Check |= knightCheck;
+ template
+ PinBitBoard Pin() const
+ {
+ auto pin = PinBitBoard();
- // Increment the count if there are checks.
- count += static_cast(pawnCheck);
- count += static_cast(knightCheck);
+ const Square sq = ToSquare(BB[We][King]);
- // Check if the square is under attack by opponent bishops, rooks, or queens.
- // For queen, we can merge with checks for bishop and rook.
- const BitBoard queen = BB[By][Queen];
+ // All the occupied squares:
+ // In this case, we want to let the pins pass through our pieces, since our pieces can move on the pins.
+ const BitBoard occupied = ColorBB[By];
- // All the occupied squares:
- BitBoard occupied = ~ColorBB[NAC];
+ // For queen, we can merge with checks for bishop and rook.
+ const BitBoard queen = BB[By][Queen];
- // Check if the square is under attack by opponent bishops or queens (diagonally).
- const BitBoard diagonalCheck =
- AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, sq, occupied)] &
- (queen | BB[By][Bishop]);
+ // Check if the square is under attack by opponent bishops or queens (diagonally).
+ const BitBoard diagonalCheck =
+ AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, sq, occupied)] &
+ (queen | BB[By][Bishop]);
- // Check if the square is under attack by opponent rooks or queens (straight).
- const BitBoard straightCheck =
- AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook , sq, occupied)] &
- (queen | BB[By][Rook ]);
+ // Check if the square is under attack by opponent rooks or queens (straight).
+ const BitBoard straightCheck =
+ AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook, sq, occupied)] &
+ (queen | BB[By][Rook]);
- // For sliding attacks, we must add the square of the attack's origin and all the squares to us from the
- // attack:
- if (diagonalCheck) {
- const Square diagonalCheckSq = ToSquare(diagonalCheck);
- check.Check |= UtilityTable::Between[sq][diagonalCheckSq] | FromSquare(diagonalCheckSq);
- }
+ // Iterate through the attacks and check if the attack is a diagonally pinning one.
+ BitBoardIterator iterator(diagonalCheck);
+ for (Square attSq = iterator.Value(); attSq != NASQ; attSq = iterator.Value())
+ if (const BitBoard possiblePin = RayTable::Between[sq][attSq] | FromSquare(attSq);
+ Count(possiblePin & ColorBB[We]) == 1) pin.Diagonal |= possiblePin;
- if (straightCheck) {
- const Square straightCheckSq = ToSquare(straightCheck);
- check.Check |= UtilityTable::Between[sq][straightCheckSq] | FromSquare(straightCheckSq);
+ // Iterate through the attacks and check if the attack is a straight pinning one.
+ iterator = BitBoardIterator(straightCheck);
+ for (Square attSq = iterator.Value(); attSq != NASQ; attSq = iterator.Value())
+ if (const BitBoard possiblePin = RayTable::Between[sq][attSq] | FromSquare(attSq);
+ Count(possiblePin & ColorBB[We]) == 1) pin.Straight |= possiblePin;
- // In the case where there is more than one check, we must increment the count once more, as it's a
- // double check.
- if (Count(straightCheck) > 1) count++;
- }
+ return pin;
+ }
- count += static_cast(diagonalCheck);
- count += static_cast(straightCheck);
+ BitBoard SquareAttackers(const Square sq, const BitBoard occ) const
+ {
+ BitBoard attackers = AttackTable::Pawn[White][sq] & BB[Black][ Pawn ] |
+ AttackTable::Pawn[Black][sq] & BB[White][ Pawn ] |
+ AttackTable::Knight [sq] & (BB[White][Knight] | BB[Black][Knight]) |
+ AttackTable::King [sq] & (BB[White][ King ] | BB[Black][ King ]) ;
- if (check.Check == BBDefault) check.Check = BBFilled;
+ attackers |= AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, sq, occ)] &
+ (BB[White][Bishop] | BB[Black][Bishop] | BB[White][Queen] | BB[Black][Queen]);
- check.DoubleCheck = count > 1;
- return check;
- }
+ attackers |= AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook, sq, occ)] &
+ (BB[White][ Rook ] | BB[Black][ Rook ] | BB[White][Queen] | BB[Black][Queen]);
- template
- [[nodiscard]]
- constexpr inline PinBitBoard Pin() const
- {
- PinBitBoard pin = PinBitBoard();
-
- const Square sq = ToSquare(BB[We][King]);
+ return attackers;
+ }
- // All the occupied squares:
- // In this case, we want to let the pins pass through our pieces, since our pieces can move on the pins.
- const BitBoard occupied = ColorBB[By];
+ PreviousStateNull Move()
+ {
+ const auto state = PreviousStateNull(EnPassantSquare());
- // For queen, we can merge with checks for bishop and rook.
- const BitBoard queen = BB[By][Queen];
+ Hash = Zobrist::HashEnPassant(Hash, EnPassantSquare());
+ EnPassantTarget = BBDefault;
- // Check if the square is under attack by opponent bishops or queens (diagonally).
- const BitBoard diagonalCheck =
- AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, sq, occupied)] &
- (queen | BB[By][Bishop]);
+ CastlingRightAndColorToMove ^= ColorFlipMask;
+ Hash = Zobrist::HashColorFlip(Hash);
- // Check if the square is under attack by opponent rooks or queens (straight).
- const BitBoard straightCheck =
- AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook , sq, occupied)] &
- (queen | BB[By][Rook ]);
-
- // Iterate through the attacks and check if the attack is a diagonally pinning one.
- BitBoardIterator iterator (diagonalCheck);
- for (Square attSq = iterator.Value(); attSq != NASQ; attSq = iterator.Value()) {
- const BitBoard possiblePin = UtilityTable::Between[sq][attSq] | FromSquare(attSq);
- if (Count(possiblePin & ColorBB[We]) == 1) pin.Diagonal |= possiblePin;
- }
+ return state;
+ }
- // Iterate through the attacks and check if the attack is a straight pinning one.
- iterator = BitBoardIterator(straightCheck);
- for (Square attSq = iterator.Value(); attSq != NASQ; attSq = iterator.Value()) {
- const BitBoard possiblePin = UtilityTable::Between[sq][attSq] | FromSquare(attSq);
- if (Count(possiblePin & ColorBB[We]) == 1) pin.Straight |= possiblePin;
- }
-
- return pin;
+ void UndoMove(const PreviousStateNull& state)
+ {
+ if (state.EnPassant != NASQ) {
+ EnPassantTarget = FromSquare(state.EnPassant);
+ Hash = Zobrist::HashEnPassant(Hash, state.EnPassant);
}
- [[nodiscard]]
- constexpr inline BitBoard SquareAttackers(const Square sq, const BitBoard occ) const
- {
- BitBoard attackers = (AttackTable::Pawn [White][sq] & BB[Black][Pawn ]) |
- (AttackTable::Pawn [Black][sq] & BB[White][Pawn ]) |
- (AttackTable::Knight [sq] & (BB[White][Knight] | BB[Black][Knight])) |
- (AttackTable::King [sq] & (BB[White][King ] | BB[Black][King ])) ;
-
- attackers |= AttackTable::Sliding[BlackMagicFactory::MagicIndex(Bishop, sq, occ)] &
- (BB[White][Bishop] | BB[Black][Bishop] | BB[White][Queen] | BB[Black][Queen]);
-
- attackers |= AttackTable::Sliding[BlackMagicFactory::MagicIndex(Rook , sq, occ)] &
- (BB[White][Rook ] | BB[Black][Rook ] | BB[White][Queen] | BB[Black][Queen]);
+ CastlingRightAndColorToMove ^= ColorFlipMask;
+ Hash = Zobrist::HashColorFlip(Hash);
+ }
- return attackers;
- }
+ template
+ PreviousState Move(const Square from, const Square to, const Piece promotion = NAP)
+ {
+ if (T & NNUE) Evaluation::PreMove();
- constexpr inline PreviousStateNull Move()
- {
- auto state = PreviousStateNull(EnPassantSquare());
+ auto state = PreviousState(PieceAndColor[from], PieceAndColor[to],
+ EnPassantSquare(), CastlingRightAndColorToMove,
+ Hash);
- Hash = HashEnPassant(Hash, EnPassantSquare());
- EnPassantTarget = BBDefault;
+ Hash = Zobrist::HashEnPassant(Hash, EnPassantSquare());
+ EnPassantTarget = BBDefault;
- CastlingRightAndColorToMove ^= ColorFlipMask;
- Hash = HashColorFlip(Hash);
+ CastlingRightAndColorToMove ^= ColorFlipMask;
+ Hash = Zobrist::HashColorFlip(Hash);
- return state;
- }
-
- constexpr inline void UndoMove(const PreviousStateNull& state)
- {
- if (state.EnPassant != NASQ) {
- EnPassantTarget = FromSquare(state.EnPassant);
- Hash = HashEnPassant(Hash, state.EnPassant);
- }
+ Hash = Zobrist::HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
- CastlingRightAndColorToMove ^= ColorFlipMask;
- Hash = HashColorFlip(Hash);
- }
+ const Piece pieceF = state.MovedPiece.Piece();
+ const Color colorF = state.MovedPiece.Color();
+ const Piece pieceT = state.CapturedPiece.Piece();
+ const Color colorT = state.CapturedPiece.Color();
- template
- constexpr inline PreviousState Move(const Square from, const Square to, const Piece promotion = NAP)
+ using RookCastlingHandler = std::array, 2>, 2>;
+ constexpr static RookCastlingHandler RookCastlingMask =
+ [] constexpr -> RookCastlingHandler
{
- if (T & NNUE) Evaluation::PreMove();
+ RookCastlingHandler result = {};
- auto state = PreviousState(PieceAndColor[from], PieceAndColor[to],
- EnPassantSquare(), CastlingRightAndColorToMove,
- Hash);
+ result[0] = {{}};
- Hash = HashEnPassant(Hash, EnPassantSquare());
- EnPassantTarget = BBDefault;
+ result[1][0] = {};
- CastlingRightAndColorToMove ^= ColorFlipMask;
- Hash = HashColorFlip(Hash);
-
- Hash = HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
+ for (Square sq = A1; sq <= NASQ; sq = Next(sq)) {
+ if (sq == A1) result[1][1][sq] = WhiteQCastleMask;
+ else if (sq == A8) result[1][1][sq] = BlackQCastleMask;
+ else if (sq == H1) result[1][1][sq] = WhiteKCastleMask;
+ else if (sq == H8) result[1][1][sq] = BlackKCastleMask;
+ }
- const Piece pieceF = state.MovedPiece .Piece();
- const Color colorF = state.MovedPiece .Color();
- const Piece pieceT = state.CapturedPiece.Piece();
- const Color colorT = state.CapturedPiece.Color();
+ return result;
+ }();
- if (pieceT == Rook && (CastlingRightAndColorToMove & ColorCastleMask[colorT])) {
- if (to == A1) CastlingRightAndColorToMove &= ~WhiteQCastleMask;
- else if (to == A8) CastlingRightAndColorToMove &= ~BlackQCastleMask;
- else if (to == H1) CastlingRightAndColorToMove &= ~WhiteKCastleMask;
- else if (to == H8) CastlingRightAndColorToMove &= ~BlackKCastleMask;
- }
+ CastlingRightAndColorToMove &= ~RookCastlingMask[pieceT == Rook][
+ static_cast(CastlingRightAndColorToMove & ColorCastleMask[colorT])
+ ][ to ];
+ CastlingRightAndColorToMove &= ~RookCastlingMask[pieceF == Rook][
+ static_cast(CastlingRightAndColorToMove & ColorCastleMask[colorF])
+ ][from];
- if (pieceF == Pawn) {
- if (to == state.EnPassant) {
- const Color opposite = Opposite(colorF);
+ if (pieceF == Pawn) {
+ if (to == state.EnPassant) {
+ const Color opposite = Opposite(colorF);
- const auto epPawnSq = static_cast(state.EnPassant ^ 8);
- EmptyNative ( Pawn, opposite, epPawnSq);
- Hash = HashPiece(Hash, Pawn, opposite, epPawnSq);
+ const auto epPawnSq = static_cast(state.EnPassant ^ 8);
+ EmptyNative(Pawn, opposite, epPawnSq);
+ Hash = Zobrist::HashPiece(Hash, Pawn, opposite, epPawnSq);
- if (T & NNUE) Evaluation::Deactivate(Pawn, opposite, epPawnSq);
+ if (T & NNUE) Evaluation::Deactivate(Pawn, opposite, epPawnSq);
- state.EnPassantCapture = true;
- } else if (static_cast(from ^ 16) == to) {
- const auto epSq = static_cast(to ^ 8);
- if (T & PERFT) {
+ state.EnPassantCapture = true;
+ } else if (static_cast(from ^ 16) == to) {
+ const auto epSq = static_cast(to ^ 8);
+ if (T & PERFT) {
+ EnPassantTarget = FromSquare(epSq);
+ Hash = Zobrist::HashEnPassant(Hash, epSq);
+ } else {
+ if (AttackTable::Pawn[colorF][epSq] & BB[Opposite(colorF)][Pawn]) {
EnPassantTarget = FromSquare(epSq);
- Hash = HashEnPassant(Hash, epSq);
- } else {
- if (AttackTable::Pawn[colorF][epSq] & BB[Opposite(colorF)][Pawn]) {
- EnPassantTarget = FromSquare(epSq);
- Hash = HashEnPassant(Hash, epSq);
- }
+ Hash = Zobrist::HashEnPassant(Hash, epSq);
}
- } else if (promotion != NAP) {
- state.PromotedPiece = promotion;
+ }
+ } else if (promotion != NAP) {
+ state.PromotedPiece = promotion;
- EmptyNative (Pawn , colorF, from);
- EmptyNative (pieceT , colorT, to );
- InsertNative(promotion, colorF, to );
+ EmptyNative(Pawn , colorF, from);
+ EmptyNative(pieceT , colorT, to);
+ InsertNative(promotion, colorF, to);
- if (T & NNUE) {
- Evaluation::Deactivate(Pawn , colorF, from);
- Evaluation::Activate (promotion, colorF, to );
+ if (T & NNUE) {
+ Evaluation::Deactivate(Pawn, colorF, from);
+ Evaluation::Activate(promotion, colorF, to);
- if (pieceT != NAP) Evaluation::Deactivate(pieceT, colorT, to);
- }
+ if (pieceT != NAP) Evaluation::Deactivate(pieceT, colorT, to);
+ }
- Hash = HashPiece(Hash, Pawn , colorF, from);
- Hash = HashPiece(Hash, pieceT , colorT, to );
- Hash = HashPiece(Hash, promotion, colorF, to );
+ Hash = Zobrist::HashPiece(Hash, Pawn, colorF, from);
+ Hash = Zobrist::HashPiece(Hash, pieceT, colorT, to);
+ Hash = Zobrist::HashPiece(Hash, promotion, colorF, to);
- Hash = HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
+ Hash = Zobrist::HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
- return state;
- }
- } else if ((CastlingRightAndColorToMove & ColorCastleMask[colorF])) {
- if (pieceF == Rook) {
- if (from == A1) CastlingRightAndColorToMove &= ~WhiteQCastleMask;
- else if (from == A8) CastlingRightAndColorToMove &= ~BlackQCastleMask;
- else if (from == H1) CastlingRightAndColorToMove &= ~WhiteKCastleMask;
- else if (from == H8) CastlingRightAndColorToMove &= ~BlackKCastleMask;
- } else if (pieceF == King) {
- CastlingRightAndColorToMove &= ~ColorCastleMask[colorF];
-
- if (to == C1 || to == C8 || to == G1 || to == G8) {
- state.CastlingFrom = CastleRookSquareStart[colorF][to < from];
- state.CastlingTo = CastleRookSquareEnd [colorF][to < from];
-
- EmptyNative (King, colorF, from );
- EmptyNative (Rook, colorF, state.CastlingFrom);
- InsertNative(King, colorF, to );
- InsertNative(Rook, colorF, state.CastlingTo );
-
- if (T & NNUE) {
- Evaluation::Transition(King, colorF, from, to);
- Evaluation::Transition(Rook, colorF,
- state.CastlingFrom, state.CastlingTo);
- }
-
- Hash = HashPiece(Hash, King, colorF, from );
- Hash = HashPiece(Hash, Rook, colorF, state.CastlingFrom);
- Hash = HashPiece(Hash, King, colorF, to );
- Hash = HashPiece(Hash, Rook, colorF, state.CastlingTo );
-
- Hash = HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
-
- return state;
- }
- }
+ return state;
}
+ } else if (pieceF == King && CastlingRightAndColorToMove & ColorCastleMask[colorF]) {
+ CastlingRightAndColorToMove &= ~ColorCastleMask[colorF];
+
+ if (to == C1 || to == C8 || to == G1 || to == G8) {
+ constexpr static std::array, 2> RookCastleSquareStart {{
+ {H1, A1},
+ {H8, A8}
+ }};
+
+ constexpr static std::array, 2> RookCastleSquareEnd {{
+ {F1, D1},
+ {F8, D8}
+ }};
+
+ state.CastlingFrom = RookCastleSquareStart[colorF][to < from];
+ state.CastlingTo = RookCastleSquareEnd [colorF][to < from];
+
+ EmptyNative(King, colorF, from);
+ EmptyNative(Rook, colorF, state.CastlingFrom);
+ InsertNative(King, colorF, to );
+ InsertNative(Rook, colorF, state.CastlingTo );
+
+ if (T & NNUE) {
+ Evaluation::Transition(King, colorF, from, to);
+ Evaluation::Transition(Rook, colorF, state.CastlingFrom, state.CastlingTo);
+ }
- MoveNative(pieceF, colorF, from, pieceT, colorT, to);
+ Hash = Zobrist::HashPiece(Hash, King, colorF, from);
+ Hash = Zobrist::HashPiece(Hash, Rook, colorF, state.CastlingFrom);
+ Hash = Zobrist::HashPiece(Hash, King, colorF, to );
+ Hash = Zobrist::HashPiece(Hash, Rook, colorF, state.CastlingTo );
- if (T & NNUE) {
- Evaluation::Transition(pieceF, colorF, from, to);
+ Hash = Zobrist::HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
- if (pieceT != NAP) Evaluation::Deactivate(pieceT, colorT, to);
+ return state;
}
+ }
- Hash = HashPiece(Hash, pieceF, colorF, from);
- Hash = HashPiece(Hash, pieceT, colorT, to );
- Hash = HashPiece(Hash, pieceF, colorF, to );
+ MoveNative(pieceF, colorF, from, pieceT, colorT, to);
- Hash = HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
+ if (T & NNUE) {
+ Evaluation::Transition(pieceF, colorF, from, to);
- return state;
+ if (pieceT != NAP) Evaluation::Deactivate(pieceT, colorT, to);
}
- template
- constexpr inline void UndoMove(const PreviousState& state, const Square from, const Square to)
- {
- if (T & NNUE) Evaluation::PreUndoMove();
+ Hash = Zobrist::HashPiece(Hash, pieceF, colorF, from);
+ Hash = Zobrist::HashPiece(Hash, pieceT, colorT, to);
+ Hash = Zobrist::HashPiece(Hash, pieceF, colorF, to);
- CastlingRightAndColorToMove = state.CastlingRightAndColorToMove;
- if (T & ZOBRIST) Hash = state.Hash;
+ Hash = Zobrist::HashCastling(Hash, CastlingRightAndColorToMove & CastlingMask);
- if (state.EnPassant != NASQ) EnPassantTarget = FromSquare(state.EnPassant);
- else EnPassantTarget = BBDefault;
+ return state;
+ }
- if (state.PromotedPiece != NAP) {
- EmptyNative (state.PromotedPiece, state.MovedPiece.Color(), to );
- InsertNative(Pawn , state.MovedPiece.Color(), from);
- } else {
- EmptyNative (state.MovedPiece.Piece(), state.MovedPiece.Color(), to );
- InsertNative(state.MovedPiece.Piece(), state.MovedPiece.Color(), from);
- }
+ template
+ void UndoMove(const PreviousState& state, const Square from, const Square to)
+ {
+ if (T & NNUE) Evaluation::PreUndoMove();
- if (state.CapturedPiece.Piece() != NAP) {
- InsertNative(state.CapturedPiece.Piece(), state.CapturedPiece.Color(), to);
- } else if (state.EnPassantCapture) {
- auto epPieceSq = static_cast(to ^ 8);
- InsertNative(Pawn, Opposite(state.MovedPiece.Color()), epPieceSq);
- } else if (state.CastlingFrom != NASQ) {
- EmptyNative (Rook, state.MovedPiece.Color(), state.CastlingTo );
- InsertNative(Rook, state.MovedPiece.Color(), state.CastlingFrom);
- }
+ CastlingRightAndColorToMove = state.CastlingRightAndColorToMove;
+ if (T & ZOBRIST) Hash = state.Hash;
+
+ if (state.EnPassant != NASQ) EnPassantTarget = FromSquare(state.EnPassant);
+ else EnPassantTarget = BBDefault;
+
+ if (state.PromotedPiece != NAP) {
+ EmptyNative(state.PromotedPiece, state.MovedPiece.Color(), to);
+ InsertNative(Pawn , state.MovedPiece.Color(), from);
+ } else {
+ EmptyNative(state.MovedPiece.Piece(), state.MovedPiece.Color(), to);
+ InsertNative(state.MovedPiece.Piece(), state.MovedPiece.Color(), from);
}
- template
- constexpr inline void MoveNative(const Piece pF, const Color cF, const Square sqF,
- const Piece pT, const Color cT, const Square sqT)
- {
- // Capture Section:
- Set(BB[cT][pT], sqT);
+ if (state.CapturedPiece.Piece() != NAP) {
+ InsertNative(state.CapturedPiece.Piece(), state.CapturedPiece.Color(), to);
+ } else if (state.EnPassantCapture) {
+ const auto epPieceSq = static_cast(to ^ 8);
+ InsertNative(Pawn, Opposite(state.MovedPiece.Color()), epPieceSq);
+ } else if (state.CastlingFrom != NASQ) {
+ EmptyNative(Rook, state.MovedPiece.Color(), state.CastlingTo );
+ InsertNative(Rook, state.MovedPiece.Color(), state.CastlingFrom);
+ }
+ }
- Set(ColorBB[cT], sqT);
+ void MoveNative(const Piece pF, const Color cF, const Square sqF,
+ const Piece pT, const Color cT, const Square sqT)
+ {
+ // Capture Section:
+ Set(BB[cT][pT] , sqT);
- // MoveNative Section:
- Set(BB[cF][pF], sqF);
- Set(BB[cF][pF], sqT);
+ Set(ColorBB[cT], sqT);
- Set(ColorBB[cF], sqF);
- Set(ColorBB[cF], sqT);
+ // MoveNative Section:
+ Set(BB[cF][pF], sqF);
+ Set(BB[cF][pF], sqT);
- UpdateNACBB();
+ Set(ColorBB[cF], sqF);
+ Set(ColorBB[cF], sqT);
- PieceAndColor[sqT] = PieceAndColor[sqF];
- PieceAndColor[sqF] = PieceColor(NAP, NAC);
- }
+ UpdateNACBB();
- template
- constexpr inline void EmptyNative(const Piece p, const Color c, const Square sq)
- {
- Set(BB[c][p], sq);
+ PieceAndColor[sqT] = PieceAndColor[sqF];
+ PieceAndColor[sqF] = PieceColor(NAP, NAC);
+ }
- Set(ColorBB[c], sq);
+ void EmptyNative(const Piece p, const Color c, const Square sq)
+ {
+ Set(BB[c][p] , sq);
- UpdateNACBB();
+ Set(ColorBB[c], sq);
- PieceAndColor[sq] = PieceColor(NAP, NAC);
- }
+ UpdateNACBB();
- template
- constexpr inline void InsertNative(const Piece p, const Color c, const Square sq)
- {
- Set(BB[c][p], sq);
+ PieceAndColor[sq] = PieceColor(NAP, NAC);
+ }
- Set(ColorBB[c], sq);
+ void InsertNative(const Piece p, const Color c, const Square sq)
+ {
+ Set(BB[c][p] , sq);
- UpdateNACBB();
+ Set(ColorBB[c], sq);
- PieceAndColor[sq] = PieceColor(p, c);
- }
+ UpdateNACBB();
- constexpr inline void UpdateNACBB()
- {
- ColorBB[Color::NAC] = ~(ColorBB[Color::White] | ColorBB[Color::Black]);
- }
+ PieceAndColor[sq] = PieceColor(p, c);
+ }
+
+ void UpdateNACBB()
+ {
+ ColorBB[NAC] = ~(ColorBB[White] | ColorBB[Black]);
+ }
};
diff --git a/src/Backend/Misc.h b/src/Backend/Misc.h
new file mode 100644
index 00000000..475eeead
--- /dev/null
+++ b/src/Backend/Misc.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2025 StockDory authors. See the list of authors for more details.
+// Licensed under LGPL-3.0.
+//
+
+#ifndef STOCKDORY_MISC_H
+#define STOCKDORY_MISC_H
+
+#include
+#include
+#include
+
+template>>
+std::string ToHex(const T v)
+{
+ std::stringstream ss;
+
+ ss << std::setfill('0') << std::setw(sizeof(T) * 2);
+ ss << std::uppercase << std::hex << v;
+
+ return ss.str();
+}
+
+#endif //STOCKDORY_MISC_H
diff --git a/src/Backend/Move/AttackTable.h b/src/Backend/Move/AttackTable.h
index 17d47099..454d740d 100644
--- a/src/Backend/Move/AttackTable.h
+++ b/src/Backend/Move/AttackTable.h
@@ -8,161 +8,94 @@
#include
-#include "BlackMagicFactory.h"
-
#include "../Type/BitBoard.h"
-#include "../Type/Piece.h"
-
-#include "../Util.h"
-namespace StockDory
+namespace StockDory::AttackTable
{
- class AttackTable
- {
-
- public:
-
- constexpr static std::array, 2> Pawn {{
- { // BEGIN WHITE
- 0x0000000000000200, 0x0000000000000500, 0x0000000000000a00, 0x0000000000001400,
- 0x0000000000002800, 0x0000000000005000, 0x000000000000a000, 0x0000000000004000,
- 0x0000000000020000, 0x0000000000050000, 0x00000000000a0000, 0x0000000000140000,
- 0x0000000000280000, 0x0000000000500000, 0x0000000000a00000, 0x0000000000400000,
- 0x0000000002000000, 0x0000000005000000, 0x000000000a000000, 0x0000000014000000,
- 0x0000000028000000, 0x0000000050000000, 0x00000000a0000000, 0x0000000040000000,
- 0x0000000200000000, 0x0000000500000000, 0x0000000a00000000, 0x0000001400000000,
- 0x0000002800000000, 0x0000005000000000, 0x000000a000000000, 0x0000004000000000,
- 0x0000020000000000, 0x0000050000000000, 0x00000a0000000000, 0x0000140000000000,
- 0x0000280000000000, 0x0000500000000000, 0x0000a00000000000, 0x0000400000000000,
- 0x0002000000000000, 0x0005000000000000, 0x000a000000000000, 0x0014000000000000,
- 0x0028000000000000, 0x0050000000000000, 0x00a0000000000000, 0x0040000000000000,
- 0x0200000000000000, 0x0500000000000000, 0x0a00000000000000, 0x1400000000000000,
- 0x2800000000000000, 0x5000000000000000, 0xa000000000000000, 0x4000000000000000,
- 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
- 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000
- }, // END WHITE
- { // BEGIN BLACK
- 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
- 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
- 0x0000000000000002, 0x0000000000000005, 0x000000000000000a, 0x0000000000000014,
- 0x0000000000000028, 0x0000000000000050, 0x00000000000000a0, 0x0000000000000040,
- 0x0000000000000200, 0x0000000000000500, 0x0000000000000a00, 0x0000000000001400,
- 0x0000000000002800, 0x0000000000005000, 0x000000000000a000, 0x0000000000004000,
- 0x0000000000020000, 0x0000000000050000, 0x00000000000a0000, 0x0000000000140000,
- 0x0000000000280000, 0x0000000000500000, 0x0000000000a00000, 0x0000000000400000,
- 0x0000000002000000, 0x0000000005000000, 0x000000000a000000, 0x0000000014000000,
- 0x0000000028000000, 0x0000000050000000, 0x00000000a0000000, 0x0000000040000000,
- 0x0000000200000000, 0x0000000500000000, 0x0000000a00000000, 0x0000001400000000,
- 0x0000002800000000, 0x0000005000000000, 0x000000a000000000, 0x0000004000000000,
- 0x0000020000000000, 0x0000050000000000, 0x00000a0000000000, 0x0000140000000000,
- 0x0000280000000000, 0x0000500000000000, 0x0000a00000000000, 0x0000400000000000,
- 0x0002000000000000, 0x0005000000000000, 0x000a000000000000, 0x0014000000000000,
- 0x0028000000000000, 0x0050000000000000, 0x00a0000000000000, 0x0040000000000000
- } // END BLACK
- }};
-
- constexpr static std::array Knight {
- 0x0000000000020400, 0x0000000000050800, 0x00000000000A1100, 0x0000000000142200,
- 0x0000000000284400, 0x0000000000508800, 0x0000000000A01000, 0x0000000000402000,
- 0x0000000002040004, 0x0000000005080008, 0x000000000A110011, 0x0000000014220022,
- 0x0000000028440044, 0x0000000050880088, 0x00000000A0100010, 0x0000000040200020,
- 0x0000000204000402, 0x0000000508000805, 0x0000000A1100110A, 0x0000001422002214,
- 0x0000002844004428, 0x0000005088008850, 0x000000A0100010A0, 0x0000004020002040,
- 0x0000020400040200, 0x0000050800080500, 0x00000A1100110A00, 0x0000142200221400,
- 0x0000284400442800, 0x0000508800885000, 0x0000A0100010A000, 0x0000402000204000,
- 0x0002040004020000, 0x0005080008050000, 0x000A1100110A0000, 0x0014220022140000,
- 0x0028440044280000, 0x0050880088500000, 0x00A0100010A00000, 0x0040200020400000,
- 0x0204000402000000, 0x0508000805000000, 0x0A1100110A000000, 0x1422002214000000,
- 0x2844004428000000, 0x5088008850000000, 0xA0100010A0000000, 0x4020002040000000,
- 0x0400040200000000, 0x0800080500000000, 0x1100110A00000000, 0x2200221400000000,
- 0x4400442800000000, 0x8800885000000000, 0x100010A000000000, 0x2000204000000000,
- 0x0004020000000000, 0x0008050000000000, 0x00110A0000000000, 0x0022140000000000,
- 0x0044280000000000, 0x0088500000000000, 0x0010A00000000000, 0x0020400000000000
- };
-
- constexpr static std::array King {
- 0x0000000000000302, 0x0000000000000705, 0x0000000000000E0A, 0x0000000000001C14,
- 0x0000000000003828, 0x0000000000007050, 0x000000000000E0A0, 0x000000000000C040,
- 0x0000000000030203, 0x0000000000070507, 0x00000000000E0A0E, 0x00000000001C141C,
- 0x0000000000382838, 0x0000000000705070, 0x0000000000E0A0E0, 0x0000000000C040C0,
- 0x0000000003020300, 0x0000000007050700, 0x000000000E0A0E00, 0x000000001C141C00,
- 0x0000000038283800, 0x0000000070507000, 0x00000000E0A0E000, 0x00000000C040C000,
- 0x0000000302030000, 0x0000000705070000, 0x0000000E0A0E0000, 0x0000001C141C0000,
- 0x0000003828380000, 0x0000007050700000, 0x000000E0A0E00000, 0x000000C040C00000,
- 0x0000030203000000, 0x0000070507000000, 0x00000E0A0E000000, 0x00001C141C000000,
- 0x0000382838000000, 0x0000705070000000, 0x0000E0A0E0000000, 0x0000C040C0000000,
- 0x0003020300000000, 0x0007050700000000, 0x000E0A0E00000000, 0x001C141C00000000,
- 0x0038283800000000, 0x0070507000000000, 0x00E0A0E000000000, 0x00C040C000000000,
- 0x0302030000000000, 0x0705070000000000, 0x0E0A0E0000000000, 0x1C141C0000000000,
- 0x3828380000000000, 0x7050700000000000, 0xE0A0E00000000000, 0xC040C00000000000,
- 0x0203000000000000, 0x0507000000000000, 0x0A0E000000000000, 0x141C000000000000,
- 0x2838000000000000, 0x5070000000000000, 0xA0E0000000000000, 0x40C0000000000000
- };
-
- static std::array Sliding;
-
- };
-
-} // StockDory
-
-std::array StockDory::AttackTable::Sliding = []() {
- std::array temp = std::array();
-
- const std::array, 4>, 2> deltaStride = {{
- {{{ 1, 1 },{ 1, -1 },{ -1, -1 },{ -1, 1 }}}, {{{ 1, 0 },{ 0, -1 },{ -1, 0 },{ 0, 1 }}}
+ constexpr std::array, 2> Pawn {{
+ {
+ // BEGIN WHITE
+ 0x0000000000000200, 0x0000000000000500, 0x0000000000000a00, 0x0000000000001400,
+ 0x0000000000002800, 0x0000000000005000, 0x000000000000a000, 0x0000000000004000,
+ 0x0000000000020000, 0x0000000000050000, 0x00000000000a0000, 0x0000000000140000,
+ 0x0000000000280000, 0x0000000000500000, 0x0000000000a00000, 0x0000000000400000,
+ 0x0000000002000000, 0x0000000005000000, 0x000000000a000000, 0x0000000014000000,
+ 0x0000000028000000, 0x0000000050000000, 0x00000000a0000000, 0x0000000040000000,
+ 0x0000000200000000, 0x0000000500000000, 0x0000000a00000000, 0x0000001400000000,
+ 0x0000002800000000, 0x0000005000000000, 0x000000a000000000, 0x0000004000000000,
+ 0x0000020000000000, 0x0000050000000000, 0x00000a0000000000, 0x0000140000000000,
+ 0x0000280000000000, 0x0000500000000000, 0x0000a00000000000, 0x0000400000000000,
+ 0x0002000000000000, 0x0005000000000000, 0x000a000000000000, 0x0014000000000000,
+ 0x0028000000000000, 0x0050000000000000, 0x00a0000000000000, 0x0040000000000000,
+ 0x0200000000000000, 0x0500000000000000, 0x0a00000000000000, 0x1400000000000000,
+ 0x2800000000000000, 0x5000000000000000, 0xa000000000000000, 0x4000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000
+ // END WHITE
+ },
+ {
+ // BEGIN BLACK
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x0000000000000002, 0x0000000000000005, 0x000000000000000a, 0x0000000000000014,
+ 0x0000000000000028, 0x0000000000000050, 0x00000000000000a0, 0x0000000000000040,
+ 0x0000000000000200, 0x0000000000000500, 0x0000000000000a00, 0x0000000000001400,
+ 0x0000000000002800, 0x0000000000005000, 0x000000000000a000, 0x0000000000004000,
+ 0x0000000000020000, 0x0000000000050000, 0x00000000000a0000, 0x0000000000140000,
+ 0x0000000000280000, 0x0000000000500000, 0x0000000000a00000, 0x0000000000400000,
+ 0x0000000002000000, 0x0000000005000000, 0x000000000a000000, 0x0000000014000000,
+ 0x0000000028000000, 0x0000000050000000, 0x00000000a0000000, 0x0000000040000000,
+ 0x0000000200000000, 0x0000000500000000, 0x0000000a00000000, 0x0000001400000000,
+ 0x0000002800000000, 0x0000005000000000, 0x000000a000000000, 0x0000004000000000,
+ 0x0000020000000000, 0x0000050000000000, 0x00000a0000000000, 0x0000140000000000,
+ 0x0000280000000000, 0x0000500000000000, 0x0000a00000000000, 0x0000400000000000,
+ 0x0002000000000000, 0x0005000000000000, 0x000a000000000000, 0x0014000000000000,
+ 0x0028000000000000, 0x0050000000000000, 0x00a0000000000000, 0x0040000000000000
+ // END BLACK
+ }
}};
- using MagicPair = std::pair;
-
- for (uint8_t i = 0; i < 2; i++) {
- const auto p = static_cast(i + 2);
- const std::array, 64>& magic = StockDory::BlackMagicFactory::Magic[i];
- const std::array, 4>& delta = deltaStride[i];
-
- for (uint8_t h = 0; h < 8; h++) for (uint8_t v = 0; v < 8; v++) {
- auto sq = static_cast(v * 8 + h);
-
- // Black Magic:
- BitBoard mask = ~(magic[sq].first.second);
- BitBoard occ = BBDefault;
-
- // Enumeration:
- while (true) {
- BitBoard moves = BBDefault;
-
- for (std::pair stride : delta) {
- auto hI = static_cast(h);
- auto vI = static_cast(v);
-
- while (!Get(occ, static_cast(vI * 8 + hI))) {
- auto dHI = static_cast(hI + stride.first );
- auto dVI = static_cast(vI + stride.second);
-
- if (dHI > 7 || dHI < 0) break;
- if (dVI > 7 || dVI < 0) break;
-
- hI = static_cast(hI + stride.first );
- vI = static_cast(vI + stride.second);
-
- moves |= FromSquare(static_cast(vI * 8 + hI));
- }
- }
-
- // List insertion:
- uint32_t idx = StockDory::BlackMagicFactory::MagicIndex(p, sq, occ);
- temp[idx] = moves;
+ constexpr std::array Knight {
+ 0x0000000000020400, 0x0000000000050800, 0x00000000000A1100, 0x0000000000142200,
+ 0x0000000000284400, 0x0000000000508800, 0x0000000000A01000, 0x0000000000402000,
+ 0x0000000002040004, 0x0000000005080008, 0x000000000A110011, 0x0000000014220022,
+ 0x0000000028440044, 0x0000000050880088, 0x00000000A0100010, 0x0000000040200020,
+ 0x0000000204000402, 0x0000000508000805, 0x0000000A1100110A, 0x0000001422002214,
+ 0x0000002844004428, 0x0000005088008850, 0x000000A0100010A0, 0x0000004020002040,
+ 0x0000020400040200, 0x0000050800080500, 0x00000A1100110A00, 0x0000142200221400,
+ 0x0000284400442800, 0x0000508800885000, 0x0000A0100010A000, 0x0000402000204000,
+ 0x0002040004020000, 0x0005080008050000, 0x000A1100110A0000, 0x0014220022140000,
+ 0x0028440044280000, 0x0050880088500000, 0x00A0100010A00000, 0x0040200020400000,
+ 0x0204000402000000, 0x0508000805000000, 0x0A1100110A000000, 0x1422002214000000,
+ 0x2844004428000000, 0x5088008850000000, 0xA0100010A0000000, 0x4020002040000000,
+ 0x0400040200000000, 0x0800080500000000, 0x1100110A00000000, 0x2200221400000000,
+ 0x4400442800000000, 0x8800885000000000, 0x100010A000000000, 0x2000204000000000,
+ 0x0004020000000000, 0x0008050000000000, 0x00110A0000000000, 0x0022140000000000,
+ 0x0044280000000000, 0x0088500000000000, 0x0010A00000000000, 0x0020400000000000
+ };
- // Occupation Recalculation:
- occ = (occ - mask) & mask;
+ constexpr std::array King {
+ 0x0000000000000302, 0x0000000000000705, 0x0000000000000E0A, 0x0000000000001C14,
+ 0x0000000000003828, 0x0000000000007050, 0x000000000000E0A0, 0x000000000000C040,
+ 0x0000000000030203, 0x0000000000070507, 0x00000000000E0A0E, 0x00000000001C141C,
+ 0x0000000000382838, 0x0000000000705070, 0x0000000000E0A0E0, 0x0000000000C040C0,
+ 0x0000000003020300, 0x0000000007050700, 0x000000000E0A0E00, 0x000000001C141C00,
+ 0x0000000038283800, 0x0000000070507000, 0x00000000E0A0E000, 0x00000000C040C000,
+ 0x0000000302030000, 0x0000000705070000, 0x0000000E0A0E0000, 0x0000001C141C0000,
+ 0x0000003828380000, 0x0000007050700000, 0x000000E0A0E00000, 0x000000C040C00000,
+ 0x0000030203000000, 0x0000070507000000, 0x00000E0A0E000000, 0x00001C141C000000,
+ 0x0000382838000000, 0x0000705070000000, 0x0000E0A0E0000000, 0x0000C040C0000000,
+ 0x0003020300000000, 0x0007050700000000, 0x000E0A0E00000000, 0x001C141C00000000,
+ 0x0038283800000000, 0x0070507000000000, 0x00E0A0E000000000, 0x00C040C000000000,
+ 0x0302030000000000, 0x0705070000000000, 0x0E0A0E0000000000, 0x1C141C0000000000,
+ 0x3828380000000000, 0x7050700000000000, 0xE0A0E00000000000, 0xC040C00000000000,
+ 0x0203000000000000, 0x0507000000000000, 0x0A0E000000000000, 0x141C000000000000,
+ 0x2838000000000000, 0x5070000000000000, 0xA0E0000000000000, 0x40C0000000000000
+ };
- // Skipping count:
- if (Count(occ) == 0) break;
- }
- }
- }
+ extern std::array Sliding;
- return temp;
-}();
+} // StockDory
#endif //STOCKDORY_ATTACKTABLE_H
diff --git a/src/Backend/Move/BlackMagicFactory.h b/src/Backend/Move/BlackMagicFactory.h
index e490db3b..36b2e01e 100644
--- a/src/Backend/Move/BlackMagicFactory.h
+++ b/src/Backend/Move/BlackMagicFactory.h
@@ -12,174 +12,273 @@
#include "../Type/BitBoard.h"
#include "../Type/Piece.h"
+#include "AttackTable.h"
+#include "RayTable.h"
+
namespace StockDory
{
class BlackMagicFactory
{
- public:
- constexpr static std::array Horizontal {
- 0x0101010101010101, 0x0202020202020202, 0x0404040404040404, 0x0808080808080808,
- 0x1010101010101010, 0x2020202020202020, 0x4040404040404040, 0x8080808080808080
- };
-
- constexpr static std::array Vertical {
- 0x00000000000000FF, 0x000000000000FF00, 0x0000000000FF0000, 0x00000000FF000000,
- 0x000000FF00000000, 0x0000FF0000000000, 0x00FF000000000000, 0xFF00000000000000
- };
-
- constexpr static BitBoard Edged = Horizontal[0] | Horizontal[7] | Vertical[0] | Vertical[7];
-
- private:
- constexpr static std::array PieceValue { 9, 12 };
-
- constexpr static std::array, 64> RookMagicConst {
- std::pair(0x80280013FF84FFFF, 10890), std::pair(0x5FFBFEFDFEF67FFF, 50579),
- std::pair(0xFFEFFAFFEFFDFFFF, 62020), std::pair(0x003000900300008A, 67322),
- std::pair(0x0050028010500023, 80251), std::pair(0x0020012120A00020, 58503),
- std::pair(0x0030006000C00030, 51175), std::pair(0x0058005806B00002, 83130),
- std::pair(0x7FBFF7FBFBEAFFFC, 50430), std::pair(0x0000140081050002, 21613),
- std::pair(0x0000180043800048, 72625), std::pair(0x7FFFE800021FFFB8, 80755),
- std::pair(0xFFFFCFFE7FCFFFAF, 69753), std::pair(0x00001800C0180060, 26973),
- std::pair(0x4F8018005FD00018, 84972), std::pair(0x0000180030620018, 31958),
- std::pair(0x00300018010C0003, 69272), std::pair(0x0003000C0085FFFF, 48372),
- std::pair(0xFFFDFFF7FBFEFFF7, 65477), std::pair(0x7FC1FFDFFC001FFF, 43972),
- std::pair(0xFFFEFFDFFDFFDFFF, 57154), std::pair(0x7C108007BEFFF81F, 53521),
- std::pair(0x20408007BFE00810, 30534), std::pair(0x0400800558604100, 16548),
- std::pair(0x0040200010080008, 46407), std::pair(0x0010020008040004, 11841),
- std::pair(0xFFFDFEFFF7FBFFF7, 21112), std::pair(0xFEBF7DFFF8FEFFF9, 44214),
- std::pair(0xC00000FFE001FFE0, 57925), std::pair(0x4AF01F00078007C3, 29574),
- std::pair(0xBFFBFAFFFB683F7F, 17309), std::pair(0x0807F67FFA102040, 40143),
- std::pair(0x200008E800300030, 64659), std::pair(0x0000008780180018, 70469),
- std::pair(0x0000010300180018, 62917), std::pair(0x4000008180180018, 60997),
- std::pair(0x008080310005FFFA, 18554), std::pair(0x4000188100060006, 14385),
- std::pair(0xFFFFFF7FFFBFBFFF, 0), std::pair(0x0000802000200040, 38091),
- std::pair(0x20000202EC002800, 25122), std::pair(0xFFFFF9FF7CFFF3FF, 60083),
- std::pair(0x000000404B801800, 72209), std::pair(0x2000002FE03FD000, 67875),
- std::pair(0xFFFFFF6FFE7FCFFD, 56290), std::pair(0xBFF7EFFFBFC00FFF, 43807),
- std::pair(0x000000100800A804, 73365), std::pair(0x6054000A58005805, 76398),
- std::pair(0x0829000101150028, 20024), std::pair(0x00000085008A0014, 9513),
- std::pair(0x8000002B00408028, 24324), std::pair(0x4000002040790028, 22996),
- std::pair(0x7800002010288028, 23213), std::pair(0x0000001800E08018, 56002),
- std::pair(0xA3A80003F3A40048, 22809), std::pair(0x2003D80000500028, 44545),
- std::pair(0xFFFFF37EEFEFDFBE, 36072), std::pair(0x40000280090013C1, 4750),
- std::pair(0xBF7FFEFFBFFAF71F, 6014), std::pair(0xFFFDFFFF777B7D6E, 36054),
- std::pair(0x48300007E8080C02, 78538), std::pair(0xAFE0000FFF780402, 28745),
- std::pair(0xEE73FFFBFFBB77FE, 8555), std::pair(0x0002000308482882, 1009)
- };
-
- constexpr static std::array, 64> BishopMagicConst {
- std::pair(0xA7020080601803D8, 60984), std::pair(0x13802040400801F1, 66046),
- std::pair(0x0A0080181001F60C, 32910), std::pair(0x1840802004238008, 16369),
- std::pair(0xC03FE00100000000, 42115), std::pair(0x24C00BFFFF400000, 835),
- std::pair(0x0808101F40007F04, 18910), std::pair(0x100808201EC00080, 25911),
- std::pair(0xFFA2FEFFBFEFB7FF, 63301), std::pair(0x083E3EE040080801, 16063),
- std::pair(0xC0800080181001F8, 17481), std::pair(0x0440007FE0031000, 59361),
- std::pair(0x2010007FFC000000, 18735), std::pair(0x1079FFE000FF8000, 61249),
- std::pair(0x3C0708101F400080, 68938), std::pair(0x080614080FA00040, 61791),
- std::pair(0x7FFE7FFF817FCFF9, 21893), std::pair(0x7FFEBFFFA01027FD, 62068),
- std::pair(0x53018080C00F4001, 19829), std::pair(0x407E0001000FFB8A, 26091),
- std::pair(0x201FE000FFF80010, 15815), std::pair(0xFFDFEFFFDE39FFEF, 16419),
- std::pair(0xCC8808000FBF8002, 59777), std::pair(0x7FF7FBFFF8203FFF, 16288),
- std::pair(0x8800013E8300C030, 33235), std::pair(0x0420009701806018, 15459),
- std::pair(0x7FFEFF7F7F01F7FD, 15863), std::pair(0x8700303010C0C006, 75555),
- std::pair(0xC800181810606000, 79445), std::pair(0x20002038001C8010, 15917),
- std::pair(0x087FF038000FC001, 8512), std::pair(0x00080C0C00083007, 73069),
- std::pair(0x00000080FC82C040, 16078), std::pair(0x000000407E416020, 19168),
- std::pair(0x00600203F8008020, 11056), std::pair(0xD003FEFE04404080, 62544),
- std::pair(0xA00020C018003088, 80477), std::pair(0x7FBFFE700BFFE800, 75049),
- std::pair(0x107FF00FE4000F90, 32947), std::pair(0x7F8FFFCFF1D007F8, 59172),
- std::pair(0x0000004100F88080, 55845), std::pair(0x00000020807C4040, 61806),
- std::pair(0x00000041018700C0, 73601), std::pair(0x0010000080FC4080, 15546),
- std::pair(0x1000003C80180030, 45243), std::pair(0xC10000DF80280050, 20333),
- std::pair(0xFFFFFFBFEFF80FDC, 33402), std::pair(0x000000101003F812, 25917),
- std::pair(0x0800001F40808200, 32875), std::pair(0x084000101F3FD208, 4639),
- std::pair(0x080000000F808081, 17077), std::pair(0x0004000008003F80, 62324),
- std::pair(0x08000001001FE040, 18159), std::pair(0x72DD000040900A00, 61436),
- std::pair(0xFFFFFEFFBFEFF81D, 57073), std::pair(0xCD8000200FEBF209, 61025),
- std::pair(0x100000101EC10082, 81259), std::pair(0x7FBAFFFFEFE0C02F, 64083),
- std::pair(0x7F83FFFFFFF07F7F, 56114), std::pair(0xFFF1FFFFFFF7FFC1, 57058),
- std::pair(0x0878040000FFE01F, 58912), std::pair(0x945E388000801012, 22194),
- std::pair(0x0840800080200FDA, 70880), std::pair(0x100000C05F582008, 11140)
- };
-
- using MagicPair = std::pair;
-
- constexpr static auto RookOccupiedMask =
- [](const Square sq) constexpr {
- // Horizontal files & vertical ranks.
- const BitBoard h = Horizontal[sq % 8] & ~(Vertical[0] | Vertical[7]);
- const BitBoard v = Vertical [sq / 8] & ~(Horizontal[0] | Horizontal[7]);
-
- // Occupied inside but not the square itself.
- return (h | v) & ~FromSquare(sq);
- };
-
- constexpr static auto BishopOccupiedMask =
- [](const Square sq) constexpr {
- const int h = sq % 8;
- const int v = sq / 8;
-
- // Simple ray cast.
- BitBoard ray = BBDefault;
- for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) {
- int dH = i - h;
- int dV = j - v;
-
- if (dH < 0) dH = -dH;
- if (dV < 0) dV = -dV;
-
- if (dH == dV && dV != 0) ray |= 1ULL << (j * 8 + i);
- }
+ constexpr static std::array PieceValue {9, 12};
+
+ constexpr static std::array, 64> RookMagicConst {
+ std::pair(0x80280013FF84FFFF, 10890), std::pair(0x5FFBFEFDFEF67FFF, 50579),
+ std::pair(0xFFEFFAFFEFFDFFFF, 62020), std::pair(0x003000900300008A, 67322),
+ std::pair(0x0050028010500023, 80251), std::pair(0x0020012120A00020, 58503),
+ std::pair(0x0030006000C00030, 51175), std::pair(0x0058005806B00002, 83130),
+ std::pair(0x7FBFF7FBFBEAFFFC, 50430), std::pair(0x0000140081050002, 21613),
+ std::pair(0x0000180043800048, 72625), std::pair(0x7FFFE800021FFFB8, 80755),
+ std::pair(0xFFFFCFFE7FCFFFAF, 69753), std::pair(0x00001800C0180060, 26973),
+ std::pair(0x4F8018005FD00018, 84972), std::pair(0x0000180030620018, 31958),
+ std::pair(0x00300018010C0003, 69272), std::pair(0x0003000C0085FFFF, 48372),
+ std::pair(0xFFFDFFF7FBFEFFF7, 65477), std::pair(0x7FC1FFDFFC001FFF, 43972),
+ std::pair(0xFFFEFFDFFDFFDFFF, 57154), std::pair(0x7C108007BEFFF81F, 53521),
+ std::pair(0x20408007BFE00810, 30534), std::pair(0x0400800558604100, 16548),
+ std::pair(0x0040200010080008, 46407), std::pair(0x0010020008040004, 11841),
+ std::pair(0xFFFDFEFFF7FBFFF7, 21112), std::pair(0xFEBF7DFFF8FEFFF9, 44214),
+ std::pair(0xC00000FFE001FFE0, 57925), std::pair(0x4AF01F00078007C3, 29574),
+ std::pair(0xBFFBFAFFFB683F7F, 17309), std::pair(0x0807F67FFA102040, 40143),
+ std::pair(0x200008E800300030, 64659), std::pair(0x0000008780180018, 70469),
+ std::pair(0x0000010300180018, 62917), std::pair(0x4000008180180018, 60997),
+ std::pair(0x008080310005FFFA, 18554), std::pair(0x4000188100060006, 14385),
+ std::pair(0xFFFFFF7FFFBFBFFF, 0 ), std::pair(0x0000802000200040, 38091),
+ std::pair(0x20000202EC002800, 25122), std::pair(0xFFFFF9FF7CFFF3FF, 60083),
+ std::pair(0x000000404B801800, 72209), std::pair(0x2000002FE03FD000, 67875),
+ std::pair(0xFFFFFF6FFE7FCFFD, 56290), std::pair(0xBFF7EFFFBFC00FFF, 43807),
+ std::pair(0x000000100800A804, 73365), std::pair(0x6054000A58005805, 76398),
+ std::pair(0x0829000101150028, 20024), std::pair(0x00000085008A0014, 9513),
+ std::pair(0x8000002B00408028, 24324), std::pair(0x4000002040790028, 22996),
+ std::pair(0x7800002010288028, 23213), std::pair(0x0000001800E08018, 56002),
+ std::pair(0xA3A80003F3A40048, 22809), std::pair(0x2003D80000500028, 44545),
+ std::pair(0xFFFFF37EEFEFDFBE, 36072), std::pair(0x40000280090013C1, 4750),
+ std::pair(0xBF7FFEFFBFFAF71F, 6014), std::pair(0xFFFDFFFF777B7D6E, 36054),
+ std::pair(0x48300007E8080C02, 78538), std::pair(0xAFE0000FFF780402, 28745),
+ std::pair(0xEE73FFFBFFBB77FE, 8555), std::pair(0x0002000308482882, 1009)
+ };
+
+ constexpr static std::array, 64> BishopMagicConst {
+ std::pair(0xA7020080601803D8, 60984), std::pair(0x13802040400801F1, 66046),
+ std::pair(0x0A0080181001F60C, 32910), std::pair(0x1840802004238008, 16369),
+ std::pair(0xC03FE00100000000, 42115), std::pair(0x24C00BFFFF400000, 835),
+ std::pair(0x0808101F40007F04, 18910), std::pair(0x100808201EC00080, 25911),
+ std::pair(0xFFA2FEFFBFEFB7FF, 63301), std::pair(0x083E3EE040080801, 16063),
+ std::pair(0xC0800080181001F8, 17481), std::pair(0x0440007FE0031000, 59361),
+ std::pair(0x2010007FFC000000, 18735), std::pair(0x1079FFE000FF8000, 61249),
+ std::pair(0x3C0708101F400080, 68938), std::pair(0x080614080FA00040, 61791),
+ std::pair(0x7FFE7FFF817FCFF9, 21893), std::pair(0x7FFEBFFFA01027FD, 62068),
+ std::pair(0x53018080C00F4001, 19829), std::pair(0x407E0001000FFB8A, 26091),
+ std::pair(0x201FE000FFF80010, 15815), std::pair(0xFFDFEFFFDE39FFEF, 16419),
+ std::pair(0xCC8808000FBF8002, 59777), std::pair(0x7FF7FBFFF8203FFF, 16288),
+ std::pair(0x8800013E8300C030, 33235), std::pair(0x0420009701806018, 15459),
+ std::pair(0x7FFEFF7F7F01F7FD, 15863), std::pair(0x8700303010C0C006, 75555),
+ std::pair(0xC800181810606000, 79445), std::pair(0x20002038001C8010, 15917),
+ std::pair(0x087FF038000FC001, 8512), std::pair(0x00080C0C00083007, 73069),
+ std::pair(0x00000080FC82C040, 16078), std::pair(0x000000407E416020, 19168),
+ std::pair(0x00600203F8008020, 11056), std::pair(0xD003FEFE04404080, 62544),
+ std::pair(0xA00020C018003088, 80477), std::pair(0x7FBFFE700BFFE800, 75049),
+ std::pair(0x107FF00FE4000F90, 32947), std::pair(0x7F8FFFCFF1D007F8, 59172),
+ std::pair(0x0000004100F88080, 55845), std::pair(0x00000020807C4040, 61806),
+ std::pair(0x00000041018700C0, 73601), std::pair(0x0010000080FC4080, 15546),
+ std::pair(0x1000003C80180030, 45243), std::pair(0xC10000DF80280050, 20333),
+ std::pair(0xFFFFFFBFEFF80FDC, 33402), std::pair(0x000000101003F812, 25917),
+ std::pair(0x0800001F40808200, 32875), std::pair(0x084000101F3FD208, 4639),
+ std::pair(0x080000000F808081, 17077), std::pair(0x0004000008003F80, 62324),
+ std::pair(0x08000001001FE040, 18159), std::pair(0x72DD000040900A00, 61436),
+ std::pair(0xFFFFFEFFBFEFF81D, 57073), std::pair(0xCD8000200FEBF209, 61025),
+ std::pair(0x100000101EC10082, 81259), std::pair(0x7FBAFFFFEFE0C02F, 64083),
+ std::pair(0x7F83FFFFFFF07F7F, 56114), std::pair(0xFFF1FFFFFFF7FFC1, 57058),
+ std::pair(0x0878040000FFE01F, 58912), std::pair(0x945E388000801012, 22194),
+ std::pair(0x0840800080200FDA, 70880), std::pair(0x100000C05F582008, 11140)
+ };
+
+ using MagicPair = std::pair;
+
+ constexpr static auto RookOccupiedMask = [](const Square sq) constexpr -> BitBoard
+ {
+ // Horizontal files & vertical ranks.
+ const BitBoard h = RayTable::Horizontal[sq % 8] & ~(RayTable::Vertical [0] | RayTable::Vertical [7]);
+ const BitBoard v = RayTable::Vertical [sq / 8] & ~(RayTable::Horizontal[0] | RayTable::Horizontal[7]);
+
+ // Occupied inside but not the square itself.
+ return (h | v) & ~FromSquare(sq);
+ };
+
+ constexpr static auto BishopOccupiedMask = [](const Square sq) constexpr -> BitBoard
+ {
+ const int h = sq % 8;
+ const int v = sq / 8;
+
+ // Simple ray cast.
+ BitBoard ray = BBDefault;
+ for (int i = 0; i < 8; i++)
+ for (int j = 0; j < 8; j++) {
+ int dH = i - h;
+ int dV = j - v;
+
+ if (dH < 0) dH = -dH;
+ if (dV < 0) dV = -dV;
+
+ if (dH == dV && dV != 0) ray |= 1ULL << (j * 8 + i);
+ }
- return ray & ~Edged;
- };
+ return ray & ~RayTable::Edged;
+ };
public:
- constexpr static std::array, 64>, 2> Magic = []() constexpr {
- std::array, 64>, 2> temp = {};
+ constexpr static std::array, 64>, 2> Magic =
+ [] constexpr -> std::array, 64>, 2>
+ {
+ std::array, 64>, 2> temp = {};
+
+ for (int h = 0; h < 8; h++)
+ for (int v = 0; v < 8; v++) {
+ const auto sq = static_cast(v * 8 + h);
+ const auto& [bmf, bms] = BishopMagicConst[sq];
+
+ // Black magic:
+ temp[0][sq] = {{bmf, ~BishopOccupiedMask(sq)}, bms};
+ }
- for (int h = 0; h < 8; h++) for (int v = 0; v < 8; v++) {
- const auto sq = static_cast(v * 8 + h);
- const std::pair& bishopConst = BishopMagicConst[sq];
+ for (int h = 0; h < 8; h++)
+ for (int v = 0; v < 8; v++) {
+ const auto sq = static_cast(v * 8 + h);
+ const auto& [rmf, rms] = RookMagicConst[sq];
- // Black magic:
- temp[0][sq] =
- {{bishopConst.first, ~BishopOccupiedMask(sq)}, bishopConst.second};
- }
+ // Black magic:
+ temp[1][sq] = {{rmf, ~RookOccupiedMask(sq)}, rms};
+ }
+
+ return temp;
+ }();
+
+ constexpr static uint32_t MagicIndex(const Piece p, const Square sq, const BitBoard occupied)
+ {
+ // Magic:
+ const auto& [magicPair, base] = Magic[p - 2][sq];
+ const auto& [magic , mask] = magicPair;
+
+ // Hash:
+ return base + static_cast(((occupied | mask) * magic) >> (64 - PieceValue[p - 2]));
+ }
+
+ };
+
+} // StockDory
+
+auto StockDory::AttackTable::Sliding = [] -> std::array
+{
+ auto temp = std::array();
+
+ for (uint8_t i = 0; i < 2; i++) {
+ constexpr std::array, 4>, 2> deltaStride = {{
+ {{
+ {1, 1}, {1, -1}, {-1, -1}, {-1, 1}
+ }}, {{
+ {1, 0}, {0, -1}, {-1, 0}, {0, 1}
+ }}
+ }};
+
+ const auto p = static_cast(i + 2);
+ const auto& magic = BlackMagicFactory::Magic[i];
+ const auto& delta = deltaStride[i];
+
+ for (uint8_t h = 0; h < 8; h++)
+ for (uint8_t v = 0; v < 8; v++) {
+ const auto sq = static_cast(v * 8 + h);
+
+ // Black Magic:
+ const BitBoard mask = ~(magic[sq].first.second);
+ BitBoard occ = BBDefault;
+
+ // Enumeration:
+ while (true) {
+ BitBoard moves = BBDefault;
- for (int h = 0; h < 8; h++) for (int v = 0; v < 8; v++) {
- const auto sq = static_cast(v * 8 + h);
- const std::pair& rookConst = RookMagicConst[sq];
+ for (auto [hD, vD] : delta) {
+ auto hI = static_cast(h);
+ auto vI = static_cast(v);
- // Black magic:
- temp[1][sq] =
- {{rookConst.first, ~RookOccupiedMask(sq)}, rookConst.second};
+ while (!Get(occ, static_cast(vI * 8 + hI))) {
+ const auto dHI = static_cast(hI + hD);
+ const auto dVI = static_cast(vI + vD);
+
+ if (dHI > 7 || dHI < 0) break;
+ if (dVI > 7 || dVI < 0) break;
+
+ hI = static_cast(hI + hD);
+ vI = static_cast(vI + vD);
+
+ moves |= FromSquare(static_cast(vI * 8 + hI));
+ }
+ }
+
+ // List insertion:
+ temp[BlackMagicFactory::MagicIndex(p, sq, occ)] = moves;
+
+ // Occupation Recalculation:
+ // ReSharper disable once CppRedundantParentheses
+ occ = (occ - mask) & mask;
+
+ // Skipping count:
+ if (Count(occ) == 0) break;
}
+ }
+ }
+
+ return temp;
+}();
+
+auto StockDory::RayTable::Between = [] -> std::array, 64>
+{
+ std::array, 64> temp = {};
- return temp;
- }();
+ for (Square f = A1; f != NASQ; f = Next(f)) {
+ const uint8_t fH = f % 8;
+ const uint8_t fV = f / 8;
- constexpr static inline uint32_t MagicIndex(const Piece p, const Square sq, const BitBoard occupied)
- {
- const std::array, 64>& pieceMagic = Magic[p - 2];
+ for (Square t = A1; t != NASQ; t = Next(t)) {
+ temp[f][t] = BBDefault;
- // Get magic:
- const std::pair& pieceMagicAtSq = pieceMagic[sq];
+ if (f == t) continue;
- // Relevant occupied squares:
- const BitBoard relevantOccupied = occupied | pieceMagicAtSq.first.second;
+ const uint8_t tH = t % 8;
+ const uint8_t tV = t / 8;
- // Hash:
- const BitBoard hash = relevantOccupied * pieceMagicAtSq.first.first;
+ BitBoard occ;
- // Offset applied:
- return pieceMagicAtSq.second + static_cast((hash >> (64 - PieceValue[p - 2])));
+ if (fH == tH || fV == tV) {
+ occ = FromSquare(f) | FromSquare(t);
+
+ const uint32_t mF = BlackMagicFactory::MagicIndex(Rook, f, occ);
+ const uint32_t mT = BlackMagicFactory::MagicIndex(Rook, t, occ);
+
+ // Rook squares:
+ temp[f][t] = AttackTable::Sliding[mF] & AttackTable::Sliding[mT];
+
+ continue;
}
- };
+ auto absH = static_cast(static_cast(fH) - static_cast(tH));
+ auto absV = static_cast(static_cast(fV) - static_cast(tV));
-} // StockDory
+ if (absH < 0) absH = static_cast(-absH);
+ if (absV < 0) absV = static_cast(-absV);
+
+ if (absH != absV) continue;
+
+ // Bishop squares:
+ occ = FromSquare(f) | FromSquare(t);
+
+ const uint32_t mF = BlackMagicFactory::MagicIndex(Bishop, f, occ);
+ const uint32_t mT = BlackMagicFactory::MagicIndex(Bishop, t, occ);
+
+ temp[f][t] = AttackTable::Sliding[mF] & AttackTable::Sliding[mT];
+ }
+ }
+
+ return temp;
+}();
#endif //STOCKDORY_BLACKMAGICFACTORY_H
diff --git a/src/Backend/Move/MoveList.h b/src/Backend/Move/MoveList.h
index 804f46f2..8444275a 100644
--- a/src/Backend/Move/MoveList.h
+++ b/src/Backend/Move/MoveList.h
@@ -9,12 +9,11 @@
#include
#include "../Type/BitBoard.h"
-#include "../Type/Piece.h"
+#include "../Type/CheckBitBoard.h"
#include "../Type/Color.h"
-#include "../Type/Square.h"
-#include "../Type/Move.h"
+#include "../Type/Piece.h"
#include "../Type/PinBitBoard.h"
-#include "../Type/CheckBitBoard.h"
+#include "../Type/Square.h"
#include "../Board.h"
@@ -28,261 +27,252 @@ namespace StockDory
class MoveList
{
- private:
- BitBoard InternalContainer;
+ constexpr static BitBoard WhiteQueenCastlePath = 0x0EULL;
+ constexpr static BitBoard WhiteKingCastlePath = 0x60ULL;
+ constexpr static BitBoard BlackQueenCastlePath = WhiteQueenCastlePath << 56;
+ constexpr static BitBoard BlackKingCastlePath = WhiteKingCastlePath << 56;
- constexpr static BitBoard WhiteQueenCastlePath = 0x0EULL ;
- constexpr static BitBoard WhiteKingCastlePath = 0x60ULL ;
- constexpr static BitBoard BlackQueenCastlePath = WhiteQueenCastlePath << 56;
- constexpr static BitBoard BlackKingCastlePath = WhiteKingCastlePath << 56;
+ constexpr static BitBoard QueenCastlePathMask = 0x0C0000000000000CULL;
- constexpr static BitBoard QueenCastlePathMask = 0x0C0000000000000CULL;
+ BitBoard InternalContainer;
public:
- constexpr static bool Promotion(const Square sq)
- {
- if (Piece != Piece::Pawn) return false;
-
- return (Color == White && sq > H6) || (Color == Black && sq < A3);
- }
-
- constexpr MoveList(const Board& board, const Square sq, const PinBitBoard& pin, const CheckBitBoard& check)
- {
- InternalContainer = BBDefault;
-
- if (Piece == Piece::Pawn ) Pawn (board, sq, pin, check);
- if (Piece == Piece::Knight) Knight(board, sq, pin, check);
- if (Piece == Piece::Bishop) Bishop(board, sq, pin, check);
- if (Piece == Piece::Rook ) Rook (board, sq, pin, check);
- if (Piece == Piece::Queen ) Queen (board, sq, pin, check);
- if (Piece == Piece::King ) King (board, sq );
- }
-
- [[nodiscard]]
- constexpr inline uint8_t Count() const
- {
- return ::Count(InternalContainer);
- }
-
- [[nodiscard]]
- constexpr inline BitBoardIterator Iterator() const
- {
- return BitBoardIterator(InternalContainer);
- }
-
- constexpr inline MoveList Mask(const BitBoard mask) const
- {
- MoveList result = *this;
- result.InternalContainer &= mask;
- return result;
- }
-
- private:
- constexpr inline void Pawn (const Board& board, const Square sq ,
- const PinBitBoard& pin , const CheckBitBoard& check)
- {
- if (Get(pin.Diagonal, sq)) {
- const BitBoard pawnAttack = AttackTable::Pawn[Color][sq];
- const BitBoard enPassant = board.EnPassant() & pawnAttack;
- const BitBoard normal = pawnAttack & board[Opposite(Color)];
-
- InternalContainer |= (enPassant & pin.Diagonal) | (normal & pin.Diagonal & check.Check);
-
- if (enPassant) {
- const Square epTarget = board.EnPassantSquare();
- const auto epPieceSq = static_cast(
- Color == White ?
- epTarget - 8 :
- epTarget + 8
- );
- if (!EnPassantLegal(board, sq, epPieceSq, epTarget))
- InternalContainer &= ~enPassant;
- }
-
- return;
- } else if (Get(pin.Straight, sq)) {
- const BitBoard sqBoard = FromSquare(sq);
-
- BitBoard pushes = (Color == White ? sqBoard << 8 : sqBoard >> 8 ) & board[NAC];
- if (pushes &&
- (sqBoard & (Color == White ?
- BlackMagicFactory::Vertical[1] :
- BlackMagicFactory::Vertical[6])))
- pushes |= (Color == White ? sqBoard << 16 : sqBoard >> 16) & board[NAC];
-
- InternalContainer |= pushes & pin.Straight & check.Check;
-
- return;
- }
+ constexpr static bool Promotion(const Square sq)
+ {
+ if (Piece != Piece::Pawn) return false;
+
+ return (Color == White && sq > H6) || (Color == Black && sq < A3);
+ }
+
+ MoveList(const Board& board, const Square sq, const PinBitBoard& pin, const CheckBitBoard& check)
+ {
+ InternalContainer = BBDefault;
+
+ if (Piece == ::Pawn ) Pawn (board, pin, check, sq);
+ if (Piece == ::Knight) Knight (board, pin, check, sq);
+ if (Piece == ::Bishop) Bishop (board, pin, check, sq);
+ if (Piece == ::Rook ) Rook (board, pin, check, sq);
+ if (Piece == ::Queen ) Queen (board, pin, check, sq);
+ if (Piece == ::King ) King (board, sq);
+ }
+
+ [[nodiscard]]
+ uint8_t Count() const
+ {
+ return ::Count(InternalContainer);
+ }
+
+ [[nodiscard]]
+ BitBoardIterator Iterator() const
+ {
+ return BitBoardIterator(InternalContainer);
+ }
+
+ MoveList Mask(const BitBoard mask) const
+ {
+ MoveList result = *this;
+ result.InternalContainer &= mask;
+ return result;
+ }
+ private:
+ [[clang::always_inline]]
+ void Pawn (const Board& board, const PinBitBoard& pin, const CheckBitBoard& check, const Square sq)
+ {
+ if (Get(pin.Diagonal, sq)) {
const BitBoard pawnAttack = AttackTable::Pawn[Color][sq];
+ const BitBoard enPassant = board.EnPassant() & pawnAttack;
const BitBoard normal = pawnAttack & board[Opposite(Color)];
- InternalContainer |= normal;
-
- const BitBoard sqBoard = FromSquare(sq);
-
- BitBoard pushes = (Color == White ? sqBoard << 8 : sqBoard >> 8 ) & board[NAC];
- if (pushes &&
- (sqBoard & (Color == White ?
- BlackMagicFactory::Vertical[1] :
- BlackMagicFactory::Vertical[6])))
- pushes |= (Color == White ? sqBoard << 16 : sqBoard >> 16) & board[NAC];
-
- InternalContainer |= pushes;
-
- InternalContainer &= check.Check;
-
- const BitBoard enPassant = board.EnPassant() & pawnAttack;
-
- InternalContainer |= enPassant;
+ InternalContainer |= enPassant & pin.Diagonal | normal & pin.Diagonal & check.Check;
if (enPassant) {
const Square epTarget = board.EnPassantSquare();
const auto epPieceSq = static_cast(
- Color == White ?
- epTarget - 8 :
- epTarget + 8
+ Color == White ? epTarget - 8 : epTarget + 8
);
if (!EnPassantLegal(board, sq, epPieceSq, epTarget))
InternalContainer &= ~enPassant;
}
- }
-
- constexpr inline void Knight(const Board& board, const Square sq ,
- const PinBitBoard& pin , const CheckBitBoard& check)
- {
- if (Get(pin.Straight | pin.Diagonal, sq)) return;
-
- InternalContainer |= AttackTable::Knight[sq] & ~board[Color] & check.Check;
- }
-
- constexpr inline void Bishop(const Board& board, const Square sq ,
- const PinBitBoard& pin , const CheckBitBoard& check)
- {
- if (Get(pin.Straight, sq)) return;
-
- const uint32_t idx = BlackMagicFactory::MagicIndex(Piece, sq, ~board[NAC]);
- InternalContainer |= AttackTable::Sliding[idx] & ~board[Color] & check.Check;
- if (Get(pin.Diagonal, sq)) InternalContainer &= pin.Diagonal;
+ return;
}
- constexpr inline void Rook (const Board& board, const Square sq ,
- const PinBitBoard& pin , const CheckBitBoard& check)
- {
- if (Get(pin.Diagonal, sq)) return;
-
- const uint32_t idx = BlackMagicFactory::MagicIndex(Piece, sq, ~board[NAC]);
- InternalContainer |= AttackTable::Sliding[idx] & ~board[Color] & check.Check;
-
- if (Get(pin.Straight, sq)) InternalContainer &= pin.Straight;
- }
-
- constexpr inline void Queen (const Board& board, const Square sq ,
- const PinBitBoard& pin , const CheckBitBoard& check)
- {
- const bool straight = Get(pin.Straight, sq);
- const bool diagonal = Get(pin.Diagonal, sq);
-
- if (straight && diagonal) return;
-
- if (straight) {
- const uint32_t idx =
- BlackMagicFactory::MagicIndex(Piece::Rook , sq, ~board[NAC]);
- InternalContainer |= AttackTable::Sliding[idx ] & ~board[Color] & check.Check & pin.Straight;
+ if (Get(pin.Straight, sq)) {
+ const BitBoard sqBoard = FromSquare(sq);
- } else if (diagonal) {
- const uint32_t idx =
- BlackMagicFactory::MagicIndex(Piece::Bishop, sq, ~board[NAC]);
- InternalContainer |= AttackTable::Sliding[idx ] & ~board[Color] & check.Check & pin.Diagonal;
+ BitBoard pushes = (Color == White ? sqBoard << 8 : sqBoard >> 8) & board[NAC];
+ if (pushes &&
+ sqBoard & (Color == White ? RayTable::Vertical[1] : RayTable::Vertical[6]))
+ pushes |= (Color == White ? sqBoard << 16 : sqBoard >> 16) & board[NAC];
- } else {
- const uint32_t idxR =
- BlackMagicFactory::MagicIndex(Piece::Rook , sq, ~board[NAC]);
- InternalContainer |= AttackTable::Sliding[idxR] & ~board[Color] & check.Check;
+ InternalContainer |= pushes & pin.Straight & check.Check;
- const uint32_t idxB =
- BlackMagicFactory::MagicIndex(Piece::Bishop, sq, ~board[NAC]);
- InternalContainer |= AttackTable::Sliding[idxB] & ~board[Color] & check.Check;
- }
+ return;
}
- constexpr inline void King (const Board& board, const Square sq )
- {
- BitBoard king = AttackTable::King[sq] & ~board[Color];
+ const BitBoard pawnAttack = AttackTable::Pawn[Color][sq];
+ const BitBoard normal = pawnAttack & board[Opposite(Color)];
- if (!king) return;
+ InternalContainer |= normal;
- auto iterator = BitBoardIterator(king);
- for (Square target = iterator.Value(); target != NASQ; target = iterator.Value()) {
- if (!KingMoveLegal(board, target)) Set(king, target);
- }
+ const BitBoard sqBoard = FromSquare(sq);
- InternalContainer |= king;
+ BitBoard pushes = (Color == White ? sqBoard << 8 : sqBoard >> 8) & board[NAC];
+ if (pushes &&
+ sqBoard & (Color == White ? RayTable::Vertical[1] : RayTable::Vertical[6]))
+ pushes |= (Color == White ? sqBoard << 16 : sqBoard >> 16) & board[NAC];
- if (!KingMoveLegal(board, sq)) return;
+ InternalContainer |= pushes;
- const bool kingSide = board.CastlingRightK();
- const bool queenSide = board.CastlingRightQ();
+ InternalContainer &= check.Check;
- if (queenSide &&
- Get(king, static_cast