Spaces:
Running
Running
Upload 109 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- Fairy-Stockfish-master/.gitattributes +1 -0
- Fairy-Stockfish-master/.github/FUNDING.yml +2 -0
- Fairy-Stockfish-master/.github/dependabot.yml +13 -0
- Fairy-Stockfish-master/.github/workflows/fairy.yml +93 -0
- Fairy-Stockfish-master/.github/workflows/ffishjs.yml +90 -0
- Fairy-Stockfish-master/.github/workflows/release.yml +116 -0
- Fairy-Stockfish-master/.github/workflows/stockfish.yml +213 -0
- Fairy-Stockfish-master/.github/workflows/wheels.yml +57 -0
- Fairy-Stockfish-master/.gitignore +43 -0
- Fairy-Stockfish-master/AGENTS.md +158 -0
- Fairy-Stockfish-master/AUTHORS +231 -0
- Fairy-Stockfish-master/Copying.txt +674 -0
- Fairy-Stockfish-master/MANIFEST.in +2 -0
- Fairy-Stockfish-master/README.md +126 -0
- Fairy-Stockfish-master/Top CPU Contributors.txt +205 -0
- Fairy-Stockfish-master/appveyor.yml +91 -0
- Fairy-Stockfish-master/pyffish.pyi +39 -0
- Fairy-Stockfish-master/setup.py +56 -0
- Fairy-Stockfish-master/src/Makefile +982 -0
- Fairy-Stockfish-master/src/Makefile_js +95 -0
- Fairy-Stockfish-master/src/apiutil.h +1165 -0
- Fairy-Stockfish-master/src/benchmark.cpp +195 -0
- Fairy-Stockfish-master/src/bitbase.cpp +177 -0
- Fairy-Stockfish-master/src/bitboard.cpp +501 -0
- Fairy-Stockfish-master/src/bitboard.h +787 -0
- Fairy-Stockfish-master/src/endgame.cpp +1321 -0
- Fairy-Stockfish-master/src/endgame.h +148 -0
- Fairy-Stockfish-master/src/evaluate.cpp +1736 -0
- Fairy-Stockfish-master/src/evaluate.h +66 -0
- Fairy-Stockfish-master/src/ffishjs.cpp +767 -0
- Fairy-Stockfish-master/src/incbin/UNLICENCE +26 -0
- Fairy-Stockfish-master/src/incbin/incbin.h +368 -0
- Fairy-Stockfish-master/src/magic.h +1741 -0
- Fairy-Stockfish-master/src/main.cpp +63 -0
- Fairy-Stockfish-master/src/material.cpp +321 -0
- Fairy-Stockfish-master/src/material.h +75 -0
- Fairy-Stockfish-master/src/misc.cpp +656 -0
- Fairy-Stockfish-master/src/misc.h +200 -0
- Fairy-Stockfish-master/src/movegen.cpp +528 -0
- Fairy-Stockfish-master/src/movegen.h +107 -0
- Fairy-Stockfish-master/src/movepick.cpp +279 -0
- Fairy-Stockfish-master/src/movepick.h +169 -0
- Fairy-Stockfish-master/src/nnue/evaluate_nnue.cpp +443 -0
- Fairy-Stockfish-master/src/nnue/evaluate_nnue.h +59 -0
- Fairy-Stockfish-master/src/nnue/features/half_ka_v2.cpp +90 -0
- Fairy-Stockfish-master/src/nnue/features/half_ka_v2.h +152 -0
- Fairy-Stockfish-master/src/nnue/features/half_ka_v2_variants.cpp +112 -0
- Fairy-Stockfish-master/src/nnue/features/half_ka_v2_variants.h +94 -0
- Fairy-Stockfish-master/src/nnue/layers/affine_transform.h +435 -0
- Fairy-Stockfish-master/src/nnue/layers/clipped_relu.h +191 -0
Fairy-Stockfish-master/.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
README.md merge=ours
|
Fairy-Stockfish-master/.github/FUNDING.yml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# These are supported funding model platforms
|
| 2 |
+
github: ianfab
|
Fairy-Stockfish-master/.github/dependabot.yml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Keep GitHub Actions up to date with GitHub's Dependabot...
|
| 2 |
+
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
|
| 3 |
+
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
|
| 4 |
+
version: 2
|
| 5 |
+
updates:
|
| 6 |
+
- package-ecosystem: github-actions
|
| 7 |
+
directory: /
|
| 8 |
+
groups:
|
| 9 |
+
github-actions:
|
| 10 |
+
patterns:
|
| 11 |
+
- "*" # Group all Actions updates into a single larger pull request
|
| 12 |
+
schedule:
|
| 13 |
+
interval: weekly
|
Fairy-Stockfish-master/.github/workflows/fairy.yml
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: fairy
|
| 2 |
+
on:
|
| 3 |
+
push:
|
| 4 |
+
branches:
|
| 5 |
+
- master
|
| 6 |
+
pull_request:
|
| 7 |
+
branches:
|
| 8 |
+
- master
|
| 9 |
+
jobs:
|
| 10 |
+
fairy:
|
| 11 |
+
name: ${{ matrix.config.name }}
|
| 12 |
+
runs-on: ${{ matrix.config.os }}
|
| 13 |
+
env:
|
| 14 |
+
COMPILER: ${{ matrix.config.compiler }}
|
| 15 |
+
COMP: ${{ matrix.config.comp }}
|
| 16 |
+
CXXFLAGS: "-Werror"
|
| 17 |
+
strategy:
|
| 18 |
+
matrix:
|
| 19 |
+
config:
|
| 20 |
+
- {
|
| 21 |
+
name: "Ubuntu 24.04 GCC",
|
| 22 |
+
os: ubuntu-24.04,
|
| 23 |
+
compiler: g++,
|
| 24 |
+
comp: gcc,
|
| 25 |
+
run_expensive_tests: true
|
| 26 |
+
}
|
| 27 |
+
- {
|
| 28 |
+
name: "Ubuntu 24.04 Clang",
|
| 29 |
+
os: ubuntu-24.04,
|
| 30 |
+
compiler: clang++,
|
| 31 |
+
comp: clang,
|
| 32 |
+
run_expensive_tests: false
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
defaults:
|
| 36 |
+
run:
|
| 37 |
+
working-directory: src
|
| 38 |
+
steps:
|
| 39 |
+
- uses: actions/checkout@v6
|
| 40 |
+
with:
|
| 41 |
+
fetch-depth: 0
|
| 42 |
+
|
| 43 |
+
- name: Download required packages
|
| 44 |
+
run: |
|
| 45 |
+
sudo apt update
|
| 46 |
+
sudo apt install expect valgrind g++-multilib
|
| 47 |
+
|
| 48 |
+
- name: Download the used network from the fishtest framework
|
| 49 |
+
run: |
|
| 50 |
+
make net
|
| 51 |
+
|
| 52 |
+
- name: Test NNUE
|
| 53 |
+
run: |
|
| 54 |
+
make clean
|
| 55 |
+
make -j2 ARCH=x86-64 nnue=yes debug=yes build
|
| 56 |
+
./stockfish bench
|
| 57 |
+
|
| 58 |
+
- name: Test NNUE largeboards
|
| 59 |
+
run: |
|
| 60 |
+
make clean
|
| 61 |
+
make -j2 ARCH=x86-64 largeboards=yes nnue=yes debug=yes build
|
| 62 |
+
./stockfish bench
|
| 63 |
+
|
| 64 |
+
- name: Build all variants
|
| 65 |
+
run: |
|
| 66 |
+
make clean
|
| 67 |
+
make -j2 ARCH=x86-64 largeboards=yes all=yes debug=yes build
|
| 68 |
+
|
| 69 |
+
- name: Test protocols
|
| 70 |
+
run: |
|
| 71 |
+
../tests/protocol.sh
|
| 72 |
+
|
| 73 |
+
- name: Test variants.ini
|
| 74 |
+
run: |
|
| 75 |
+
! ./stockfish check variants.ini 2>&1 >/dev/null | grep -v "Parsing variant"
|
| 76 |
+
|
| 77 |
+
- name: Test variant perft
|
| 78 |
+
run: |
|
| 79 |
+
../tests/perft.sh all
|
| 80 |
+
|
| 81 |
+
- name: Test variant bench
|
| 82 |
+
run: |
|
| 83 |
+
./stockfish bench xiangqi
|
| 84 |
+
./stockfish bench shogi
|
| 85 |
+
./stockfish bench capablanca
|
| 86 |
+
./stockfish bench sittuyin
|
| 87 |
+
|
| 88 |
+
- name: Test 32bit largeboards
|
| 89 |
+
run: |
|
| 90 |
+
if [[ "$COMP" == "gcc" ]]; then export EXTRACXXFLAGS=-Wno-class-memaccess; fi
|
| 91 |
+
make clean
|
| 92 |
+
make -j2 ARCH=x86-32 largeboards=yes build
|
| 93 |
+
../tests/perft.sh largeboard
|
Fairy-Stockfish-master/.github/workflows/ffishjs.yml
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: ffishjs
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [ master ]
|
| 6 |
+
pull_request:
|
| 7 |
+
branches: [ master ]
|
| 8 |
+
|
| 9 |
+
env:
|
| 10 |
+
EM_VERSION: 1.39.16
|
| 11 |
+
EM_CACHE_FOLDER: 'emsdk-cache'
|
| 12 |
+
|
| 13 |
+
jobs:
|
| 14 |
+
test:
|
| 15 |
+
runs-on: ubuntu-24.04
|
| 16 |
+
|
| 17 |
+
strategy:
|
| 18 |
+
matrix:
|
| 19 |
+
node-version: [12.x]
|
| 20 |
+
|
| 21 |
+
steps:
|
| 22 |
+
- uses: actions/checkout@v6
|
| 23 |
+
- name: Setup cache
|
| 24 |
+
id: cache-system-libraries
|
| 25 |
+
uses: actions/cache@v5
|
| 26 |
+
with:
|
| 27 |
+
path: ${{env.EM_CACHE_FOLDER}}
|
| 28 |
+
key: emsdk-${{env.EM_VERSION}}-${{ runner.os }}
|
| 29 |
+
- uses: mymindstorm/setup-emsdk@v16
|
| 30 |
+
with:
|
| 31 |
+
version: ${{env.EM_VERSION}}
|
| 32 |
+
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
| 33 |
+
- name: Use Node.js ${{ matrix.node-version }}
|
| 34 |
+
uses: actions/setup-node@v6
|
| 35 |
+
with:
|
| 36 |
+
node-version: ${{ matrix.node-version }}
|
| 37 |
+
- name: Build ffishjs
|
| 38 |
+
working-directory: src
|
| 39 |
+
run: make -f Makefile_js build debug=yes
|
| 40 |
+
- name: Install dependencies
|
| 41 |
+
working-directory: tests/js
|
| 42 |
+
run: npm install
|
| 43 |
+
- name: Run unit tests
|
| 44 |
+
working-directory: tests/js
|
| 45 |
+
run: npm test
|
| 46 |
+
|
| 47 |
+
build:
|
| 48 |
+
runs-on: ubuntu-24.04
|
| 49 |
+
needs: [test] #Building process must start after successful testing process
|
| 50 |
+
|
| 51 |
+
strategy:
|
| 52 |
+
matrix:
|
| 53 |
+
node-version: [12.x]
|
| 54 |
+
|
| 55 |
+
steps:
|
| 56 |
+
- uses: actions/checkout@v6
|
| 57 |
+
- name: Setup cache
|
| 58 |
+
id: cache-system-libraries
|
| 59 |
+
uses: actions/cache@v5
|
| 60 |
+
with:
|
| 61 |
+
path: ${{env.EM_CACHE_FOLDER}}
|
| 62 |
+
key: emsdk-${{env.EM_VERSION}}-${{ runner.os }}
|
| 63 |
+
- uses: mymindstorm/setup-emsdk@v16
|
| 64 |
+
with:
|
| 65 |
+
version: ${{env.EM_VERSION}}
|
| 66 |
+
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
| 67 |
+
- name: Use Node.js ${{ matrix.node-version }}
|
| 68 |
+
uses: actions/setup-node@v6
|
| 69 |
+
with:
|
| 70 |
+
node-version: ${{ matrix.node-version }}
|
| 71 |
+
- name: Build ffish.js ES6/ES2015 module
|
| 72 |
+
working-directory: src
|
| 73 |
+
run: rm -f ../tests/js/ffish.js & rm -f ../tests/js/ffish.wasm & make -f Makefile_js build es6=yes
|
| 74 |
+
- name: Upload ffish.js ES6/ES2015 module ZIP archive
|
| 75 |
+
uses: actions/upload-artifact@v7
|
| 76 |
+
with:
|
| 77 |
+
name: ffishjs-es6
|
| 78 |
+
path: tests/js/*
|
| 79 |
+
if-no-files-found: error
|
| 80 |
+
compression-level: 9
|
| 81 |
+
- name: Build ffish.js standard module
|
| 82 |
+
working-directory: src
|
| 83 |
+
run: rm -f ../tests/js/ffish.js & rm -f ../tests/js/ffish.wasm & make -f Makefile_js build
|
| 84 |
+
- name: Upload ffish.js standard module ZIP archive
|
| 85 |
+
uses: actions/upload-artifact@v7
|
| 86 |
+
with:
|
| 87 |
+
name: ffishjs-standard
|
| 88 |
+
path: tests/js/*
|
| 89 |
+
if-no-files-found: error
|
| 90 |
+
compression-level: 9
|
Fairy-Stockfish-master/.github/workflows/release.yml
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Release
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [ master ]
|
| 6 |
+
pull_request:
|
| 7 |
+
branches: [ master ]
|
| 8 |
+
|
| 9 |
+
jobs:
|
| 10 |
+
windows:
|
| 11 |
+
strategy:
|
| 12 |
+
matrix:
|
| 13 |
+
arch: ["x86-64-bmi2", "x86-64-modern", "x86-64"]
|
| 14 |
+
runs-on: windows-2022
|
| 15 |
+
|
| 16 |
+
steps:
|
| 17 |
+
- uses: al-cheb/configure-pagefile-action@v1.5
|
| 18 |
+
with:
|
| 19 |
+
minimum-size: 16GB
|
| 20 |
+
maximum-size: 16GB
|
| 21 |
+
disk-root: "C:"
|
| 22 |
+
|
| 23 |
+
- uses: actions/checkout@v6
|
| 24 |
+
|
| 25 |
+
- name: make
|
| 26 |
+
run: cd src && make clean && make -j build COMP=mingw ARCH=${{ matrix.arch }} EXE=fairy-stockfish_${{ matrix.arch }}.exe && strip fairy-stockfish_${{ matrix.arch }}.exe
|
| 27 |
+
|
| 28 |
+
- name: make largeboards
|
| 29 |
+
run: cd src && make clean && make -j build COMP=mingw ARCH=${{ matrix.arch }} EXE=fairy-stockfish-largeboards_${{ matrix.arch }}.exe largeboards=yes && strip fairy-stockfish-largeboards_${{ matrix.arch }}.exe
|
| 30 |
+
|
| 31 |
+
- name: make all
|
| 32 |
+
if: ${{ matrix.arch == 'x86-64' }}
|
| 33 |
+
run: cd src && make clean && make -j build COMP=mingw ARCH=${{ matrix.arch }} EXE=fairy-stockfish-all_${{ matrix.arch }}.exe largeboards=yes all=yes && strip fairy-stockfish-all_${{ matrix.arch }}.exe
|
| 34 |
+
|
| 35 |
+
- uses: actions/upload-artifact@v7
|
| 36 |
+
with:
|
| 37 |
+
name: fairy-stockfish-windows-${{ matrix.arch }}
|
| 38 |
+
path: src/fairy-stockfish*.exe
|
| 39 |
+
if-no-files-found: error
|
| 40 |
+
compression-level: 9
|
| 41 |
+
|
| 42 |
+
linux:
|
| 43 |
+
strategy:
|
| 44 |
+
matrix:
|
| 45 |
+
arch: ["x86-64-bmi2", "x86-64-modern", "x86-64"]
|
| 46 |
+
runs-on: ubuntu-24.04
|
| 47 |
+
|
| 48 |
+
steps:
|
| 49 |
+
- uses: actions/checkout@v6
|
| 50 |
+
|
| 51 |
+
- name: make
|
| 52 |
+
run: cd src && make clean && make -j build COMP=gcc ARCH=${{ matrix.arch }} EXE=fairy-stockfish_${{ matrix.arch }} && strip fairy-stockfish_${{ matrix.arch }}
|
| 53 |
+
|
| 54 |
+
- name: make largeboards
|
| 55 |
+
run: cd src && make clean && make -j build COMP=gcc ARCH=${{ matrix.arch }} EXE=fairy-stockfish-largeboards_${{ matrix.arch }} largeboards=yes && strip fairy-stockfish-largeboards_${{ matrix.arch }}
|
| 56 |
+
|
| 57 |
+
- name: make all
|
| 58 |
+
if: ${{ matrix.arch == 'x86-64' }}
|
| 59 |
+
run: cd src && make clean && make -j build COMP=gcc ARCH=${{ matrix.arch }} EXE=fairy-stockfish-all_${{ matrix.arch }} largeboards=yes all=yes && strip fairy-stockfish-all_${{ matrix.arch }}
|
| 60 |
+
|
| 61 |
+
- uses: actions/upload-artifact@v7
|
| 62 |
+
with:
|
| 63 |
+
name: fairy-stockfish-linux-${{ matrix.arch }}
|
| 64 |
+
path: src/fairy-stockfish*
|
| 65 |
+
if-no-files-found: error
|
| 66 |
+
compression-level: 9
|
| 67 |
+
|
| 68 |
+
macos:
|
| 69 |
+
strategy:
|
| 70 |
+
matrix:
|
| 71 |
+
arch: ["x86-64"]
|
| 72 |
+
runs-on: macos-15-intel
|
| 73 |
+
|
| 74 |
+
steps:
|
| 75 |
+
- uses: actions/checkout@v6
|
| 76 |
+
|
| 77 |
+
- name: make
|
| 78 |
+
run: cd src && make clean && make -j build COMP=clang ARCH=${{ matrix.arch }} EXE=fairy-stockfish_${{ matrix.arch }} && strip fairy-stockfish_${{ matrix.arch }}
|
| 79 |
+
|
| 80 |
+
- name: make largeboards
|
| 81 |
+
run: cd src && make clean && make -j build COMP=clang ARCH=${{ matrix.arch }} EXE=fairy-stockfish-largeboards_${{ matrix.arch }} largeboards=yes && strip fairy-stockfish-largeboards_${{ matrix.arch }}
|
| 82 |
+
|
| 83 |
+
- name: make all
|
| 84 |
+
run: cd src && make clean && make -j build COMP=clang ARCH=${{ matrix.arch }} EXE=fairy-stockfish-all_${{ matrix.arch }} largeboards=yes all=yes && strip fairy-stockfish-all_${{ matrix.arch }}
|
| 85 |
+
|
| 86 |
+
- uses: actions/upload-artifact@v7
|
| 87 |
+
with:
|
| 88 |
+
name: fairy-stockfish-macos-${{ matrix.arch }}
|
| 89 |
+
path: src/fairy-stockfish*
|
| 90 |
+
if-no-files-found: error
|
| 91 |
+
compression-level: 9
|
| 92 |
+
|
| 93 |
+
macos-m1:
|
| 94 |
+
strategy:
|
| 95 |
+
matrix:
|
| 96 |
+
arch: ["apple-silicon"]
|
| 97 |
+
runs-on: macos-14
|
| 98 |
+
|
| 99 |
+
steps:
|
| 100 |
+
- uses: actions/checkout@v6
|
| 101 |
+
|
| 102 |
+
- name: make
|
| 103 |
+
run: cd src && make clean && make -j build COMP=clang ARCH=${{ matrix.arch }} EXE=fairy-stockfish_${{ matrix.arch }} && strip fairy-stockfish_${{ matrix.arch }}
|
| 104 |
+
|
| 105 |
+
- name: make largeboards
|
| 106 |
+
run: cd src && make clean && make -j build COMP=clang ARCH=${{ matrix.arch }} EXE=fairy-stockfish-largeboards_${{ matrix.arch }} largeboards=yes && strip fairy-stockfish-largeboards_${{ matrix.arch }}
|
| 107 |
+
|
| 108 |
+
- name: make all
|
| 109 |
+
run: cd src && make clean && make -j build COMP=clang ARCH=${{ matrix.arch }} EXE=fairy-stockfish-all_${{ matrix.arch }} largeboards=yes all=yes && strip fairy-stockfish-all_${{ matrix.arch }}
|
| 110 |
+
|
| 111 |
+
- uses: actions/upload-artifact@v7
|
| 112 |
+
with:
|
| 113 |
+
name: fairy-stockfish-macos-m1-${{ matrix.arch }}
|
| 114 |
+
path: src/fairy-stockfish*
|
| 115 |
+
if-no-files-found: error
|
| 116 |
+
compression-level: 9
|
Fairy-Stockfish-master/.github/workflows/stockfish.yml
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Stockfish
|
| 2 |
+
on:
|
| 3 |
+
push:
|
| 4 |
+
branches:
|
| 5 |
+
- master
|
| 6 |
+
- tools
|
| 7 |
+
- github_ci
|
| 8 |
+
pull_request:
|
| 9 |
+
branches:
|
| 10 |
+
- master
|
| 11 |
+
- tools
|
| 12 |
+
jobs:
|
| 13 |
+
Stockfish:
|
| 14 |
+
name: ${{ matrix.config.name }}
|
| 15 |
+
runs-on: ${{ matrix.config.os }}
|
| 16 |
+
env:
|
| 17 |
+
COMPILER: ${{ matrix.config.compiler }}
|
| 18 |
+
COMP: ${{ matrix.config.comp }}
|
| 19 |
+
CXXFLAGS: "-Werror"
|
| 20 |
+
strategy:
|
| 21 |
+
matrix:
|
| 22 |
+
config:
|
| 23 |
+
- {
|
| 24 |
+
name: "Ubuntu 24.04 GCC",
|
| 25 |
+
os: ubuntu-24.04,
|
| 26 |
+
compiler: g++,
|
| 27 |
+
comp: gcc,
|
| 28 |
+
run_expensive_tests: true
|
| 29 |
+
}
|
| 30 |
+
- {
|
| 31 |
+
name: "Ubuntu 24.04 Clang",
|
| 32 |
+
os: ubuntu-24.04,
|
| 33 |
+
compiler: clang++,
|
| 34 |
+
comp: clang,
|
| 35 |
+
run_expensive_tests: false
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
defaults:
|
| 39 |
+
run:
|
| 40 |
+
working-directory: src
|
| 41 |
+
steps:
|
| 42 |
+
- uses: actions/checkout@v6
|
| 43 |
+
with:
|
| 44 |
+
fetch-depth: 0
|
| 45 |
+
|
| 46 |
+
- name: Download required packages
|
| 47 |
+
run: |
|
| 48 |
+
sudo apt update
|
| 49 |
+
sudo apt install expect valgrind g++-multilib llvm
|
| 50 |
+
|
| 51 |
+
- name: Download the used network from the fishtest framework
|
| 52 |
+
run: |
|
| 53 |
+
make net
|
| 54 |
+
|
| 55 |
+
- name: Extract the bench number from the commit history
|
| 56 |
+
run: |
|
| 57 |
+
git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig
|
| 58 |
+
[ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
|
| 59 |
+
|
| 60 |
+
- name: Check compiler
|
| 61 |
+
run: |
|
| 62 |
+
$COMPILER -v
|
| 63 |
+
|
| 64 |
+
- name: Test help target
|
| 65 |
+
run: |
|
| 66 |
+
make help
|
| 67 |
+
|
| 68 |
+
# x86-32 tests
|
| 69 |
+
|
| 70 |
+
- name: Test debug x86-32 build
|
| 71 |
+
run: |
|
| 72 |
+
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
|
| 73 |
+
make clean
|
| 74 |
+
make -j2 ARCH=x86-32 optimize=no debug=yes build
|
| 75 |
+
../tests/signature.sh $benchref
|
| 76 |
+
|
| 77 |
+
- name: Test debug x86-32 profile build (Optimization on, All features)
|
| 78 |
+
run: |
|
| 79 |
+
export CXXFLAGS=""
|
| 80 |
+
make clean
|
| 81 |
+
make -j2 ARCH=x86-32 optimize=yes all=yes largeboards=yes debug=yes profile-build
|
| 82 |
+
|
| 83 |
+
- name: Test x86-32 build
|
| 84 |
+
run: |
|
| 85 |
+
make clean
|
| 86 |
+
make -j2 ARCH=x86-32 build
|
| 87 |
+
../tests/signature.sh $benchref
|
| 88 |
+
|
| 89 |
+
- name: Test x86-32-sse41-popcnt build
|
| 90 |
+
run: |
|
| 91 |
+
make clean
|
| 92 |
+
make -j2 ARCH=x86-32-sse41-popcnt build
|
| 93 |
+
../tests/signature.sh $benchref
|
| 94 |
+
|
| 95 |
+
- name: Test x86-32-sse2 build
|
| 96 |
+
run: |
|
| 97 |
+
make clean
|
| 98 |
+
make -j2 ARCH=x86-32-sse2 build
|
| 99 |
+
../tests/signature.sh $benchref
|
| 100 |
+
|
| 101 |
+
- name: Test general-32 build
|
| 102 |
+
run: |
|
| 103 |
+
make clean
|
| 104 |
+
make -j2 ARCH=general-32 build
|
| 105 |
+
../tests/signature.sh $benchref
|
| 106 |
+
|
| 107 |
+
# x86-64 tests
|
| 108 |
+
|
| 109 |
+
- name: Test debug x86-64-modern build
|
| 110 |
+
run: |
|
| 111 |
+
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
|
| 112 |
+
make clean
|
| 113 |
+
make -j2 ARCH=x86-64-modern optimize=no debug=yes build
|
| 114 |
+
../tests/signature.sh $benchref
|
| 115 |
+
|
| 116 |
+
- name: Test debug x86-64-modern profile build (Optimization on, All features)
|
| 117 |
+
run: |
|
| 118 |
+
export CXXFLAGS=""
|
| 119 |
+
make clean
|
| 120 |
+
make -j2 ARCH=x86-64-modern optimize=yes all=yes largeboards=yes debug=yes profile-build
|
| 121 |
+
|
| 122 |
+
- name: Test x86-64-modern build
|
| 123 |
+
run: |
|
| 124 |
+
make clean
|
| 125 |
+
make -j2 ARCH=x86-64-modern build
|
| 126 |
+
../tests/signature.sh $benchref
|
| 127 |
+
|
| 128 |
+
- name: Test x86-64-ssse3 build
|
| 129 |
+
run: |
|
| 130 |
+
make clean
|
| 131 |
+
make -j2 ARCH=x86-64-ssse3 build
|
| 132 |
+
../tests/signature.sh $benchref
|
| 133 |
+
|
| 134 |
+
- name: Test x86-64-sse3-popcnt build
|
| 135 |
+
run: |
|
| 136 |
+
make clean
|
| 137 |
+
make -j2 ARCH=x86-64-sse3-popcnt build
|
| 138 |
+
../tests/signature.sh $benchref
|
| 139 |
+
|
| 140 |
+
- name: Test x86-64 build
|
| 141 |
+
run: |
|
| 142 |
+
make clean
|
| 143 |
+
make -j2 ARCH=x86-64 build
|
| 144 |
+
../tests/signature.sh $benchref
|
| 145 |
+
|
| 146 |
+
- name: Test general-64 build
|
| 147 |
+
run: |
|
| 148 |
+
make clean
|
| 149 |
+
make -j2 ARCH=general-64 build
|
| 150 |
+
../tests/signature.sh $benchref
|
| 151 |
+
|
| 152 |
+
# x86-64 with newer extensions tests
|
| 153 |
+
|
| 154 |
+
- name: Compile x86-64-avx2 build
|
| 155 |
+
run: |
|
| 156 |
+
make clean
|
| 157 |
+
make -j2 ARCH=x86-64-avx2 build
|
| 158 |
+
|
| 159 |
+
- name: Compile x86-64-bmi2 build
|
| 160 |
+
run: |
|
| 161 |
+
make clean
|
| 162 |
+
make -j2 ARCH=x86-64-bmi2 build
|
| 163 |
+
|
| 164 |
+
- name: Compile x86-64-avx512 build
|
| 165 |
+
run: |
|
| 166 |
+
make clean
|
| 167 |
+
make -j2 ARCH=x86-64-avx512 build
|
| 168 |
+
|
| 169 |
+
- name: Compile x86-64-vnni512 build
|
| 170 |
+
run: |
|
| 171 |
+
make clean
|
| 172 |
+
make -j2 ARCH=x86-64-vnni512 build
|
| 173 |
+
|
| 174 |
+
- name: Compile x86-64-vnni256 build
|
| 175 |
+
run: |
|
| 176 |
+
make clean
|
| 177 |
+
make -j2 ARCH=x86-64-vnni256 build
|
| 178 |
+
|
| 179 |
+
# Other tests
|
| 180 |
+
|
| 181 |
+
- name: Check perft and search reproducibility
|
| 182 |
+
run: |
|
| 183 |
+
make clean
|
| 184 |
+
make -j2 ARCH=x86-64-modern build
|
| 185 |
+
../tests/perft.sh
|
| 186 |
+
../tests/reprosearch.sh
|
| 187 |
+
|
| 188 |
+
# Sanitizers
|
| 189 |
+
|
| 190 |
+
- name: Run under valgrind
|
| 191 |
+
if: ${{ matrix.config.run_expensive_tests }}
|
| 192 |
+
run: |
|
| 193 |
+
export CXXFLAGS="-O1 -fno-inline"
|
| 194 |
+
make clean
|
| 195 |
+
make -j2 ARCH=x86-64-modern debug=yes optimize=no build > /dev/null
|
| 196 |
+
../tests/instrumented.sh --valgrind
|
| 197 |
+
../tests/instrumented.sh --valgrind-thread
|
| 198 |
+
|
| 199 |
+
- name: Run with UB sanitizer
|
| 200 |
+
if: ${{ matrix.config.run_expensive_tests }}
|
| 201 |
+
run: |
|
| 202 |
+
export CXXFLAGS="-O1 -fno-inline"
|
| 203 |
+
make clean
|
| 204 |
+
make -j2 ARCH=x86-64-modern sanitize=undefined optimize=no debug=yes build > /dev/null
|
| 205 |
+
../tests/instrumented.sh --sanitizer-undefined
|
| 206 |
+
|
| 207 |
+
- name: Run with thread sanitizer
|
| 208 |
+
if: ${{ matrix.config.run_expensive_tests }}
|
| 209 |
+
run: |
|
| 210 |
+
export CXXFLAGS="-O1 -fno-inline"
|
| 211 |
+
make clean
|
| 212 |
+
make -j2 ARCH=x86-64-modern sanitize=thread optimize=no debug=yes build > /dev/null
|
| 213 |
+
../tests/instrumented.sh --sanitizer-thread
|
Fairy-Stockfish-master/.github/workflows/wheels.yml
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Wheels
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- master
|
| 7 |
+
pull_request:
|
| 8 |
+
branches:
|
| 9 |
+
- master
|
| 10 |
+
|
| 11 |
+
jobs:
|
| 12 |
+
build_wheels:
|
| 13 |
+
name: Build wheels on ${{ matrix.os }}
|
| 14 |
+
runs-on: ${{ matrix.os }}
|
| 15 |
+
strategy:
|
| 16 |
+
matrix:
|
| 17 |
+
os: [ubuntu-24.04, windows-2022, macos-14]
|
| 18 |
+
|
| 19 |
+
steps:
|
| 20 |
+
- uses: actions/checkout@v6
|
| 21 |
+
|
| 22 |
+
# Used to host cibuildwheel
|
| 23 |
+
- uses: actions/setup-python@v6
|
| 24 |
+
|
| 25 |
+
- name: Install cibuildwheel
|
| 26 |
+
run: python -m pip install cibuildwheel==3.4.0
|
| 27 |
+
|
| 28 |
+
- name: Build wheels
|
| 29 |
+
run: python -m cibuildwheel --output-dir wheelhouse
|
| 30 |
+
# to supply options, put them in 'env', like:
|
| 31 |
+
env:
|
| 32 |
+
MACOSX_DEPLOYMENT_TARGET: "10.14"
|
| 33 |
+
CIBW_ARCHS_MACOS: "x86_64 arm64"
|
| 34 |
+
CIBW_SKIP: "pp* *-win32 *-manylinux_i686 *-musllinux_* cp36-* cp37-* cp38"
|
| 35 |
+
CIBW_TEST_COMMAND: python {project}/test.py
|
| 36 |
+
|
| 37 |
+
- uses: actions/upload-artifact@v7
|
| 38 |
+
with:
|
| 39 |
+
name: dist-wheel-${{ matrix.os }}
|
| 40 |
+
path: ./wheelhouse/*.whl
|
| 41 |
+
|
| 42 |
+
build_sdist:
|
| 43 |
+
name: Build source distribution
|
| 44 |
+
runs-on: ubuntu-24.04
|
| 45 |
+
steps:
|
| 46 |
+
- uses: actions/checkout@v6
|
| 47 |
+
- uses: actions/setup-python@v6
|
| 48 |
+
with:
|
| 49 |
+
python-version: '3.9'
|
| 50 |
+
|
| 51 |
+
- name: Build sdist
|
| 52 |
+
run: python setup.py sdist
|
| 53 |
+
|
| 54 |
+
- uses: actions/upload-artifact@v7
|
| 55 |
+
with:
|
| 56 |
+
name: dist-source
|
| 57 |
+
path: dist/*.tar.gz
|
Fairy-Stockfish-master/.gitignore
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ignore binaries in src/ that have no extension
|
| 2 |
+
/src/*
|
| 3 |
+
!/src/*.*
|
| 4 |
+
!/src/*/
|
| 5 |
+
|
| 6 |
+
# Files from build
|
| 7 |
+
**/*.o
|
| 8 |
+
**/*.s
|
| 9 |
+
src/.depend
|
| 10 |
+
|
| 11 |
+
# Built binary
|
| 12 |
+
src/stockfish*
|
| 13 |
+
src/-lstdc++.res
|
| 14 |
+
|
| 15 |
+
# Neural network for the NNUE evaluation
|
| 16 |
+
**/*.nnue
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
# Build/test artifacts
|
| 20 |
+
*.exe
|
| 21 |
+
tests/syzygy
|
| 22 |
+
|
| 23 |
+
# ffishjs
|
| 24 |
+
tests/js/node_modules
|
| 25 |
+
ffish.js
|
| 26 |
+
*.wasm
|
| 27 |
+
|
| 28 |
+
# pyffish
|
| 29 |
+
venv
|
| 30 |
+
*.so
|
| 31 |
+
pyffish.egg-info
|
| 32 |
+
__pycache__
|
| 33 |
+
*.pyc
|
| 34 |
+
|
| 35 |
+
# test artifacts
|
| 36 |
+
tests/*.exp
|
| 37 |
+
src/*.log
|
| 38 |
+
src/*.epd
|
| 39 |
+
src/*.txt
|
| 40 |
+
|
| 41 |
+
# IDEs
|
| 42 |
+
.vscode
|
| 43 |
+
.idea
|
Fairy-Stockfish-master/AGENTS.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fairy-Stockfish Development Guide
|
| 2 |
+
|
| 3 |
+
## Repository Overview
|
| 4 |
+
|
| 5 |
+
**Fairy-Stockfish** is a chess variant engine derived from Stockfish, designed to support numerous chess variants and protocols. Written primarily in C++17, it includes Python and JavaScript bindings for library use.
|
| 6 |
+
|
| 7 |
+
**Repository Statistics:**
|
| 8 |
+
- **Languages:** C++17 (primary), Python, JavaScript, Shell scripts
|
| 9 |
+
- **Architecture:** Multi-protocol chess engine (UCI, UCCI, USI, XBoard/CECP)
|
| 10 |
+
- **Target Platforms:** Windows, Linux, macOS, Android, WebAssembly
|
| 11 |
+
- **Supported Variants:** 90+ chess variants including regional, historical, and modern variants
|
| 12 |
+
|
| 13 |
+
## Build System & Requirements
|
| 14 |
+
|
| 15 |
+
### Prerequisites
|
| 16 |
+
- **Compiler:** GCC, Clang, or MSVC with C++17 support
|
| 17 |
+
- **Build Tool:** GNU Make (required for C++ engine)
|
| 18 |
+
- **Python:** 3.7+ (for Python bindings)
|
| 19 |
+
- **Node.js:** (for JavaScript bindings)
|
| 20 |
+
- **Additional Tools:** expect utility (for testing)
|
| 21 |
+
|
| 22 |
+
### Core Build Process
|
| 23 |
+
|
| 24 |
+
Note: Run engine and test commands from the `src/` directory unless specified otherwise.
|
| 25 |
+
|
| 26 |
+
#### Basic Build Commands
|
| 27 |
+
```bash
|
| 28 |
+
# Standard release build (recommended for most users)
|
| 29 |
+
make -j2 ARCH=x86-64 build
|
| 30 |
+
|
| 31 |
+
# Debug build (for development)
|
| 32 |
+
make -j2 ARCH=x86-64 debug=yes build
|
| 33 |
+
|
| 34 |
+
# All variants including ones with large boards (up to 12x10) and large branching factor (all)
|
| 35 |
+
make -j2 ARCH=x86-64 largeboards=yes all=yes build
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
### Python Bindings (pyffish)
|
| 39 |
+
```bash
|
| 40 |
+
# Build Python bindings (from repository root)
|
| 41 |
+
python3 setup.py install
|
| 42 |
+
|
| 43 |
+
# Alternative: Install from PyPI
|
| 44 |
+
pip install pyffish
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
### JavaScript Bindings (ffish.js)
|
| 48 |
+
Also see the `tests/js/README.md`.
|
| 49 |
+
```bash
|
| 50 |
+
cd src/
|
| 51 |
+
|
| 52 |
+
# Build JavaScript bindings (requires emscripten)
|
| 53 |
+
make -f Makefile_js build
|
| 54 |
+
|
| 55 |
+
# Alternative: Install from npm
|
| 56 |
+
npm install ffish
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
## Testing & Validation
|
| 60 |
+
|
| 61 |
+
All test commands below assume the current directory is `src/`.
|
| 62 |
+
|
| 63 |
+
### Core Engine Tests
|
| 64 |
+
```bash
|
| 65 |
+
# Basic functionality test
|
| 66 |
+
./stockfish bench
|
| 67 |
+
|
| 68 |
+
# Variant-specific benchmarks
|
| 69 |
+
./stockfish bench xiangqi
|
| 70 |
+
./stockfish bench shogi
|
| 71 |
+
./stockfish bench capablanca
|
| 72 |
+
|
| 73 |
+
# Validate variants configuration
|
| 74 |
+
./stockfish check variants.ini
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
### Comprehensive Test Suite
|
| 78 |
+
```bash
|
| 79 |
+
# Protocol compliance tests
|
| 80 |
+
../tests/protocol.sh
|
| 81 |
+
|
| 82 |
+
# Move generation validation
|
| 83 |
+
../tests/perft.sh all
|
| 84 |
+
../tests/perft.sh chess # Chess only
|
| 85 |
+
../tests/perft.sh largeboard # Large board variants only
|
| 86 |
+
|
| 87 |
+
# Regression testing
|
| 88 |
+
../tests/regression.sh
|
| 89 |
+
|
| 90 |
+
# Reproducible search test
|
| 91 |
+
../tests/reprosearch.sh
|
| 92 |
+
|
| 93 |
+
# Build signature verification
|
| 94 |
+
../tests/signature.sh
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
## Project Architecture
|
| 99 |
+
|
| 100 |
+
### Directory Structure
|
| 101 |
+
```
|
| 102 |
+
src/ # Core C++ engine source
|
| 103 |
+
tests/ # Test scripts and data
|
| 104 |
+
.github/workflows/ # CI/CD configurations
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
### Configuration Files
|
| 108 |
+
- **`src/variants.ini`**: Defines examples for configuration of chess variants
|
| 109 |
+
- **`setup.py`**: Python package build configuration
|
| 110 |
+
- **`tests/js/package.json`**: JavaScript bindings configuration
|
| 111 |
+
|
| 112 |
+
### Key Source Files in `src/`
|
| 113 |
+
- **`variant.h`**: Variant rule properties
|
| 114 |
+
- **`variant.cpp`**: Variant-specific game rules
|
| 115 |
+
- **`variant.ini`**: Variant rule configuration examples and documentation of variant properties
|
| 116 |
+
- **`position.h`**: Position representation
|
| 117 |
+
- **`position.cpp`**: Board logic
|
| 118 |
+
- **`movegen.cpp`**: Move generation logic
|
| 119 |
+
- **`parser.cpp`**: Variant rule configuration parsing
|
| 120 |
+
- **`piece.cpp`**: Piece type definitions and behavior
|
| 121 |
+
- **`pyffish.cpp`**: Python bindings
|
| 122 |
+
- **`ffishjs.cpp`**: JavaScript bindings
|
| 123 |
+
|
| 124 |
+
## Continuous Integration
|
| 125 |
+
|
| 126 |
+
### GitHub Actions Workflows
|
| 127 |
+
- **`fairy.yml`**: Core engine testing (perft, protocols, variants)
|
| 128 |
+
- **`stockfish.yml`**: Standard Stockfish compatibility tests
|
| 129 |
+
- **`release.yml`**: Binary releases for multiple platforms
|
| 130 |
+
- **`wheels.yml`**: Python package builds
|
| 131 |
+
- **`ffishjs.yml`**: JavaScript binding builds
|
| 132 |
+
|
| 133 |
+
## Common Development Patterns
|
| 134 |
+
|
| 135 |
+
### Making Engine Changes
|
| 136 |
+
1. **Always test basic functionality:** `./stockfish bench` after changes
|
| 137 |
+
2. **Validate variant compatibility:** `./stockfish check variants.ini`
|
| 138 |
+
3. **Run relevant tests:** `../tests/perft.sh all` for move generation changes
|
| 139 |
+
|
| 140 |
+
### Adding New Configurable Variants
|
| 141 |
+
1. **Edit `src/variants.ini`**: Add variant configuration
|
| 142 |
+
2. **Test parsing:** `./stockfish check variants.ini`
|
| 143 |
+
|
| 144 |
+
### Relevant websites for researching chess variant rules
|
| 145 |
+
- [Chess Variants on Wikipedia](https://en.wikipedia.org/wiki/List_of_chess_variants)
|
| 146 |
+
- [Chess Variants Wiki](https://www.chessvariants.com/)
|
| 147 |
+
- [Variant Chess on BoardGameGeek](https://boardgamegeek.com/boardgamefamily/4024/traditional-games-chess)
|
| 148 |
+
- [PyChess Variants](https://www.pychess.org/variants)
|
| 149 |
+
- [Ludii](https://ludii.games/library.php)
|
| 150 |
+
- [Lichess.org Variants](https://lichess.org/variant)
|
| 151 |
+
- [Greenchess](https://greenchess.net/variants.php)
|
| 152 |
+
- [Chess Variants on Chess.com](https://www.chess.com/variants)
|
| 153 |
+
|
| 154 |
+
### Development Best Practices
|
| 155 |
+
* Make sure to only stage and commit changes that were changed as part of the task, do not simply add all changes.
|
| 156 |
+
* Keep changes minimal and focused on the task at hand.
|
| 157 |
+
* After applying changes make sure that all places related to the task have been identified.
|
| 158 |
+
* Stay consistent with the existing code style and conventions.
|
Fairy-Stockfish-master/AUTHORS
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fairy-Stockfish authors
|
| 2 |
+
|
| 3 |
+
# Main author
|
| 4 |
+
Fabian Fichter (ianfab)
|
| 5 |
+
|
| 6 |
+
# Contributors in alphabetical order
|
| 7 |
+
alwey
|
| 8 |
+
Belzedar94
|
| 9 |
+
cloudfish
|
| 10 |
+
CouchTomato87
|
| 11 |
+
dpldgr
|
| 12 |
+
Fulmene
|
| 13 |
+
gbtami
|
| 14 |
+
gnunicode
|
| 15 |
+
johndoknjas
|
| 16 |
+
kz04px
|
| 17 |
+
majormink
|
| 18 |
+
mtaktikos
|
| 19 |
+
QueensGambit
|
| 20 |
+
RainRat
|
| 21 |
+
rkb97
|
| 22 |
+
romstad
|
| 23 |
+
Snowmoondaphne
|
| 24 |
+
SriMethan
|
| 25 |
+
thearst3rd
|
| 26 |
+
TheYoBots
|
| 27 |
+
tttak
|
| 28 |
+
yjf2002ghty
|
| 29 |
+
yoav-rozin
|
| 30 |
+
ydirson
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# List of authors for Stockfish, as of June 14, 2021
|
| 35 |
+
|
| 36 |
+
# Founders of the Stockfish project and fishtest infrastructure
|
| 37 |
+
Tord Romstad (romstad)
|
| 38 |
+
Marco Costalba (mcostalba)
|
| 39 |
+
Joona Kiiski (zamar)
|
| 40 |
+
Gary Linscott (glinscott)
|
| 41 |
+
|
| 42 |
+
# Authors and inventors of NNUE, training, NNUE port
|
| 43 |
+
Yu Nasu (ynasu87)
|
| 44 |
+
Motohiro Isozaki (yaneurao)
|
| 45 |
+
Hisayori Noda (nodchip)
|
| 46 |
+
|
| 47 |
+
# all other authors of the code in alphabetical order
|
| 48 |
+
Aditya (absimaldata)
|
| 49 |
+
Adrian Petrescu (apetresc)
|
| 50 |
+
Ajith Chandy Jose (ajithcj)
|
| 51 |
+
Alain Savard (Rocky640)
|
| 52 |
+
Alayan Feh (Alayan-stk-2)
|
| 53 |
+
Alexander Kure
|
| 54 |
+
Alexander Pagel (Lolligerhans)
|
| 55 |
+
Alfredo Menezes (lonfom169)
|
| 56 |
+
Ali AlZhrani (Cooffe)
|
| 57 |
+
Andrew Grant (AndyGrant)
|
| 58 |
+
Andrey Neporada (nepal)
|
| 59 |
+
Andy Duplain
|
| 60 |
+
Antoine Champion (antoinechampion)
|
| 61 |
+
Aram Tumanian (atumanian)
|
| 62 |
+
Arjun Temurnikar
|
| 63 |
+
Artem Solopiy (EntityFX)
|
| 64 |
+
Auguste Pop
|
| 65 |
+
Balint Pfliegel
|
| 66 |
+
Ben Koshy (BKSpurgeon)
|
| 67 |
+
Bill Henry (VoyagerOne)
|
| 68 |
+
Bojun Guo (noobpwnftw, Nooby)
|
| 69 |
+
braich
|
| 70 |
+
Brian Sheppard (SapphireBrand, briansheppard-toast)
|
| 71 |
+
Bruno de Melo Costa (BM123499)
|
| 72 |
+
Bryan Cross (crossbr)
|
| 73 |
+
candirufish
|
| 74 |
+
Chess13234
|
| 75 |
+
Chris Cain (ceebo)
|
| 76 |
+
Dale Weiler (graphitemaster)
|
| 77 |
+
Dan Schmidt (dfannius)
|
| 78 |
+
Daniel Axtens (daxtens)
|
| 79 |
+
Daniel Dugovic (ddugovic)
|
| 80 |
+
Dariusz Orzechowski (dorzechowski)
|
| 81 |
+
David Zar
|
| 82 |
+
Daylen Yang (daylen)
|
| 83 |
+
Deshawn Mohan-Smith (GoldenRare)
|
| 84 |
+
Dieter Dobbelaere (ddobbelaere)
|
| 85 |
+
DiscanX
|
| 86 |
+
Dominik Schlösser (domschl)
|
| 87 |
+
double-beep
|
| 88 |
+
Douglas Matos Gomes (dsmsgms)
|
| 89 |
+
Eduardo Cáceres (eduherminio)
|
| 90 |
+
Eelco de Groot (KingDefender)
|
| 91 |
+
Elvin Liu (solarlight2)
|
| 92 |
+
erbsenzaehler
|
| 93 |
+
Ernesto Gatti
|
| 94 |
+
Linmiao Xu (linrock)
|
| 95 |
+
Fabian Beuke (madnight)
|
| 96 |
+
Fabian Fichter (ianfab)
|
| 97 |
+
Fanael Linithien (Fanael)
|
| 98 |
+
fanon
|
| 99 |
+
Fauzi Akram Dabat (FauziAkram)
|
| 100 |
+
Felix Wittmann
|
| 101 |
+
gamander
|
| 102 |
+
Gary Heckman (gheckman)
|
| 103 |
+
George Sobala (gsobala)
|
| 104 |
+
gguliash
|
| 105 |
+
Gian-Carlo Pascutto (gcp)
|
| 106 |
+
Gontran Lemaire (gonlem)
|
| 107 |
+
Goodkov Vasiliy Aleksandrovich (goodkov)
|
| 108 |
+
Gregor Cramer
|
| 109 |
+
GuardianRM
|
| 110 |
+
Günther Demetz (pb00067, pb00068)
|
| 111 |
+
Guy Vreuls (gvreuls)
|
| 112 |
+
Henri Wiechers
|
| 113 |
+
Hiraoka Takuya (HiraokaTakuya)
|
| 114 |
+
homoSapiensSapiens
|
| 115 |
+
Hongzhi Cheng
|
| 116 |
+
Ivan Ivec (IIvec)
|
| 117 |
+
Jacques B. (Timshel)
|
| 118 |
+
Jan Ondruš (hxim)
|
| 119 |
+
Jared Kish (Kurtbusch)
|
| 120 |
+
Jarrod Torriero (DU-jdto)
|
| 121 |
+
Jean Gauthier (OuaisBla)
|
| 122 |
+
Jean-Francois Romang (jromang)
|
| 123 |
+
Jekaa
|
| 124 |
+
Jerry Donald Watson (jerrydonaldwatson)
|
| 125 |
+
jjoshua2
|
| 126 |
+
Jonathan Calovski (Mysseno)
|
| 127 |
+
Jonathan Buladas Dumale (SFisGOD)
|
| 128 |
+
Joost VandeVondele (vondele)
|
| 129 |
+
Jörg Oster (joergoster)
|
| 130 |
+
Joseph Ellis (jhellis3)
|
| 131 |
+
Joseph R. Prostko
|
| 132 |
+
Julian Willemer (NightlyKing)
|
| 133 |
+
jundery
|
| 134 |
+
Justin Blanchard (UncombedCoconut)
|
| 135 |
+
Kelly Wilson
|
| 136 |
+
Ken Takusagawa
|
| 137 |
+
kinderchocolate
|
| 138 |
+
Kiran Panditrao (Krgp)
|
| 139 |
+
Kojirion
|
| 140 |
+
Krystian Kuzniarek (kuzkry)
|
| 141 |
+
Leonardo Ljubičić (ICCF World Champion)
|
| 142 |
+
Leonid Pechenik (lp--)
|
| 143 |
+
Linus Arver (listx)
|
| 144 |
+
loco-loco
|
| 145 |
+
Lub van den Berg (ElbertoOne)
|
| 146 |
+
Luca Brivio (lucabrivio)
|
| 147 |
+
Lucas Braesch (lucasart)
|
| 148 |
+
Lyudmil Antonov (lantonov)
|
| 149 |
+
Maciej Żenczykowski (zenczykowski)
|
| 150 |
+
Malcolm Campbell (xoto10)
|
| 151 |
+
Mark Tenzer (31m059)
|
| 152 |
+
marotear
|
| 153 |
+
Matt Ginsberg (mattginsberg)
|
| 154 |
+
Matthew Lai (matthewlai)
|
| 155 |
+
Matthew Sullivan (Matt14916)
|
| 156 |
+
Maxim Molchanov (Maxim)
|
| 157 |
+
Michael An (man)
|
| 158 |
+
Michael Byrne (MichaelB7)
|
| 159 |
+
Michael Chaly (Vizvezdenec)
|
| 160 |
+
Michael Stembera (mstembera)
|
| 161 |
+
Michael Whiteley (protonspring)
|
| 162 |
+
Michel Van den Bergh (vdbergh)
|
| 163 |
+
Miguel Lahoz (miguel-l)
|
| 164 |
+
Mikael Bäckman (mbootsector)
|
| 165 |
+
Mira
|
| 166 |
+
Miroslav Fontán (Hexik)
|
| 167 |
+
Moez Jellouli (MJZ1977)
|
| 168 |
+
Mohammed Li (tthsqe12)
|
| 169 |
+
Nathan Rugg (nmrugg)
|
| 170 |
+
Nick Pelling (nickpelling)
|
| 171 |
+
Nicklas Persson (NicklasPersson)
|
| 172 |
+
Niklas Fiekas (niklasf)
|
| 173 |
+
Nikolay Kostov (NikolayIT)
|
| 174 |
+
Nguyen Pham (nguyenpham)
|
| 175 |
+
Norman Schmidt (FireFather)
|
| 176 |
+
notruck
|
| 177 |
+
Ondrej Mosnáček (WOnder93)
|
| 178 |
+
Oskar Werkelin Ahlin
|
| 179 |
+
Pablo Vazquez
|
| 180 |
+
Panthee
|
| 181 |
+
Pascal Romaret
|
| 182 |
+
Pasquale Pigazzini (ppigazzini)
|
| 183 |
+
Patrick Jansen (mibere)
|
| 184 |
+
pellanda
|
| 185 |
+
Peter Zsifkovits (CoffeeOne)
|
| 186 |
+
Praveen Kumar Tummala (praveentml)
|
| 187 |
+
Rahul Dsilva (silversolver1)
|
| 188 |
+
Ralph Stößer (Ralph Stoesser)
|
| 189 |
+
Raminder Singh
|
| 190 |
+
renouve
|
| 191 |
+
Reuven Peleg
|
| 192 |
+
Richard Lloyd
|
| 193 |
+
Rodrigo Exterckötter Tjäder
|
| 194 |
+
Ron Britvich (Britvich)
|
| 195 |
+
Ronald de Man (syzygy1, syzygy)
|
| 196 |
+
rqs
|
| 197 |
+
Ryan Schmitt
|
| 198 |
+
Ryan Takker
|
| 199 |
+
Sami Kiminki (skiminki)
|
| 200 |
+
Sebastian Buchwald (UniQP)
|
| 201 |
+
Sergei Antonov (saproj)
|
| 202 |
+
Sergei Ivanov (svivanov72)
|
| 203 |
+
Sergio Vieri (sergiovieri)
|
| 204 |
+
sf-x
|
| 205 |
+
Shane Booth (shane31)
|
| 206 |
+
Shawn Varghese (xXH4CKST3RXx)
|
| 207 |
+
Siad Daboul (Topologist)
|
| 208 |
+
Stefan Geschwentner (locutus2)
|
| 209 |
+
Stefano Cardanobile (Stefano80)
|
| 210 |
+
Steinar Gunderson (sesse)
|
| 211 |
+
Stéphane Nicolet (snicolet)
|
| 212 |
+
Prokop Randáček (ProkopRandacek)
|
| 213 |
+
Thanar2
|
| 214 |
+
thaspel
|
| 215 |
+
theo77186
|
| 216 |
+
Tom Truscott
|
| 217 |
+
Tom Vijlbrief (tomtor)
|
| 218 |
+
Tomasz Sobczyk (Sopel97)
|
| 219 |
+
Torsten Franz (torfranz, tfranzer)
|
| 220 |
+
Tracey Emery (basepr1me)
|
| 221 |
+
tttak
|
| 222 |
+
Unai Corzo (unaiic)
|
| 223 |
+
Uri Blass (uriblass)
|
| 224 |
+
Vince Negri (cuddlestmonkey)
|
| 225 |
+
zz4032
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
# Additionally, we acknowledge the authors and maintainers of fishtest,
|
| 229 |
+
# an amazing and essential framework for the development of Stockfish!
|
| 230 |
+
#
|
| 231 |
+
# https://github.com/glinscott/fishtest/blob/master/AUTHORS
|
Fairy-Stockfish-master/Copying.txt
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GNU GENERAL PUBLIC LICENSE
|
| 2 |
+
Version 3, 29 June 2007
|
| 3 |
+
|
| 4 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
| 5 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 6 |
+
of this license document, but changing it is not allowed.
|
| 7 |
+
|
| 8 |
+
Preamble
|
| 9 |
+
|
| 10 |
+
The GNU General Public License is a free, copyleft license for
|
| 11 |
+
software and other kinds of works.
|
| 12 |
+
|
| 13 |
+
The licenses for most software and other practical works are designed
|
| 14 |
+
to take away your freedom to share and change the works. By contrast,
|
| 15 |
+
the GNU General Public License is intended to guarantee your freedom to
|
| 16 |
+
share and change all versions of a program--to make sure it remains free
|
| 17 |
+
software for all its users. We, the Free Software Foundation, use the
|
| 18 |
+
GNU General Public License for most of our software; it applies also to
|
| 19 |
+
any other work released this way by its authors. You can apply it to
|
| 20 |
+
your programs, too.
|
| 21 |
+
|
| 22 |
+
When we speak of free software, we are referring to freedom, not
|
| 23 |
+
price. Our General Public Licenses are designed to make sure that you
|
| 24 |
+
have the freedom to distribute copies of free software (and charge for
|
| 25 |
+
them if you wish), that you receive source code or can get it if you
|
| 26 |
+
want it, that you can change the software or use pieces of it in new
|
| 27 |
+
free programs, and that you know you can do these things.
|
| 28 |
+
|
| 29 |
+
To protect your rights, we need to prevent others from denying you
|
| 30 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
| 31 |
+
certain responsibilities if you distribute copies of the software, or if
|
| 32 |
+
you modify it: responsibilities to respect the freedom of others.
|
| 33 |
+
|
| 34 |
+
For example, if you distribute copies of such a program, whether
|
| 35 |
+
gratis or for a fee, you must pass on to the recipients the same
|
| 36 |
+
freedoms that you received. You must make sure that they, too, receive
|
| 37 |
+
or can get the source code. And you must show them these terms so they
|
| 38 |
+
know their rights.
|
| 39 |
+
|
| 40 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
| 41 |
+
(1) assert copyright on the software, and (2) offer you this License
|
| 42 |
+
giving you legal permission to copy, distribute and/or modify it.
|
| 43 |
+
|
| 44 |
+
For the developers' and authors' protection, the GPL clearly explains
|
| 45 |
+
that there is no warranty for this free software. For both users' and
|
| 46 |
+
authors' sake, the GPL requires that modified versions be marked as
|
| 47 |
+
changed, so that their problems will not be attributed erroneously to
|
| 48 |
+
authors of previous versions.
|
| 49 |
+
|
| 50 |
+
Some devices are designed to deny users access to install or run
|
| 51 |
+
modified versions of the software inside them, although the manufacturer
|
| 52 |
+
can do so. This is fundamentally incompatible with the aim of
|
| 53 |
+
protecting users' freedom to change the software. The systematic
|
| 54 |
+
pattern of such abuse occurs in the area of products for individuals to
|
| 55 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
| 56 |
+
have designed this version of the GPL to prohibit the practice for those
|
| 57 |
+
products. If such problems arise substantially in other domains, we
|
| 58 |
+
stand ready to extend this provision to those domains in future versions
|
| 59 |
+
of the GPL, as needed to protect the freedom of users.
|
| 60 |
+
|
| 61 |
+
Finally, every program is threatened constantly by software patents.
|
| 62 |
+
States should not allow patents to restrict development and use of
|
| 63 |
+
software on general-purpose computers, but in those that do, we wish to
|
| 64 |
+
avoid the special danger that patents applied to a free program could
|
| 65 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
| 66 |
+
patents cannot be used to render the program non-free.
|
| 67 |
+
|
| 68 |
+
The precise terms and conditions for copying, distribution and
|
| 69 |
+
modification follow.
|
| 70 |
+
|
| 71 |
+
TERMS AND CONDITIONS
|
| 72 |
+
|
| 73 |
+
0. Definitions.
|
| 74 |
+
|
| 75 |
+
"This License" refers to version 3 of the GNU General Public License.
|
| 76 |
+
|
| 77 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
| 78 |
+
works, such as semiconductor masks.
|
| 79 |
+
|
| 80 |
+
"The Program" refers to any copyrightable work licensed under this
|
| 81 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
| 82 |
+
"recipients" may be individuals or organizations.
|
| 83 |
+
|
| 84 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
| 85 |
+
in a fashion requiring copyright permission, other than the making of an
|
| 86 |
+
exact copy. The resulting work is called a "modified version" of the
|
| 87 |
+
earlier work or a work "based on" the earlier work.
|
| 88 |
+
|
| 89 |
+
A "covered work" means either the unmodified Program or a work based
|
| 90 |
+
on the Program.
|
| 91 |
+
|
| 92 |
+
To "propagate" a work means to do anything with it that, without
|
| 93 |
+
permission, would make you directly or secondarily liable for
|
| 94 |
+
infringement under applicable copyright law, except executing it on a
|
| 95 |
+
computer or modifying a private copy. Propagation includes copying,
|
| 96 |
+
distribution (with or without modification), making available to the
|
| 97 |
+
public, and in some countries other activities as well.
|
| 98 |
+
|
| 99 |
+
To "convey" a work means any kind of propagation that enables other
|
| 100 |
+
parties to make or receive copies. Mere interaction with a user through
|
| 101 |
+
a computer network, with no transfer of a copy, is not conveying.
|
| 102 |
+
|
| 103 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
| 104 |
+
to the extent that it includes a convenient and prominently visible
|
| 105 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
| 106 |
+
tells the user that there is no warranty for the work (except to the
|
| 107 |
+
extent that warranties are provided), that licensees may convey the
|
| 108 |
+
work under this License, and how to view a copy of this License. If
|
| 109 |
+
the interface presents a list of user commands or options, such as a
|
| 110 |
+
menu, a prominent item in the list meets this criterion.
|
| 111 |
+
|
| 112 |
+
1. Source Code.
|
| 113 |
+
|
| 114 |
+
The "source code" for a work means the preferred form of the work
|
| 115 |
+
for making modifications to it. "Object code" means any non-source
|
| 116 |
+
form of a work.
|
| 117 |
+
|
| 118 |
+
A "Standard Interface" means an interface that either is an official
|
| 119 |
+
standard defined by a recognized standards body, or, in the case of
|
| 120 |
+
interfaces specified for a particular programming language, one that
|
| 121 |
+
is widely used among developers working in that language.
|
| 122 |
+
|
| 123 |
+
The "System Libraries" of an executable work include anything, other
|
| 124 |
+
than the work as a whole, that (a) is included in the normal form of
|
| 125 |
+
packaging a Major Component, but which is not part of that Major
|
| 126 |
+
Component, and (b) serves only to enable use of the work with that
|
| 127 |
+
Major Component, or to implement a Standard Interface for which an
|
| 128 |
+
implementation is available to the public in source code form. A
|
| 129 |
+
"Major Component", in this context, means a major essential component
|
| 130 |
+
(kernel, window system, and so on) of the specific operating system
|
| 131 |
+
(if any) on which the executable work runs, or a compiler used to
|
| 132 |
+
produce the work, or an object code interpreter used to run it.
|
| 133 |
+
|
| 134 |
+
The "Corresponding Source" for a work in object code form means all
|
| 135 |
+
the source code needed to generate, install, and (for an executable
|
| 136 |
+
work) run the object code and to modify the work, including scripts to
|
| 137 |
+
control those activities. However, it does not include the work's
|
| 138 |
+
System Libraries, or general-purpose tools or generally available free
|
| 139 |
+
programs which are used unmodified in performing those activities but
|
| 140 |
+
which are not part of the work. For example, Corresponding Source
|
| 141 |
+
includes interface definition files associated with source files for
|
| 142 |
+
the work, and the source code for shared libraries and dynamically
|
| 143 |
+
linked subprograms that the work is specifically designed to require,
|
| 144 |
+
such as by intimate data communication or control flow between those
|
| 145 |
+
subprograms and other parts of the work.
|
| 146 |
+
|
| 147 |
+
The Corresponding Source need not include anything that users
|
| 148 |
+
can regenerate automatically from other parts of the Corresponding
|
| 149 |
+
Source.
|
| 150 |
+
|
| 151 |
+
The Corresponding Source for a work in source code form is that
|
| 152 |
+
same work.
|
| 153 |
+
|
| 154 |
+
2. Basic Permissions.
|
| 155 |
+
|
| 156 |
+
All rights granted under this License are granted for the term of
|
| 157 |
+
copyright on the Program, and are irrevocable provided the stated
|
| 158 |
+
conditions are met. This License explicitly affirms your unlimited
|
| 159 |
+
permission to run the unmodified Program. The output from running a
|
| 160 |
+
covered work is covered by this License only if the output, given its
|
| 161 |
+
content, constitutes a covered work. This License acknowledges your
|
| 162 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
| 163 |
+
|
| 164 |
+
You may make, run and propagate covered works that you do not
|
| 165 |
+
convey, without conditions so long as your license otherwise remains
|
| 166 |
+
in force. You may convey covered works to others for the sole purpose
|
| 167 |
+
of having them make modifications exclusively for you, or provide you
|
| 168 |
+
with facilities for running those works, provided that you comply with
|
| 169 |
+
the terms of this License in conveying all material for which you do
|
| 170 |
+
not control copyright. Those thus making or running the covered works
|
| 171 |
+
for you must do so exclusively on your behalf, under your direction
|
| 172 |
+
and control, on terms that prohibit them from making any copies of
|
| 173 |
+
your copyrighted material outside their relationship with you.
|
| 174 |
+
|
| 175 |
+
Conveying under any other circumstances is permitted solely under
|
| 176 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
| 177 |
+
makes it unnecessary.
|
| 178 |
+
|
| 179 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 180 |
+
|
| 181 |
+
No covered work shall be deemed part of an effective technological
|
| 182 |
+
measure under any applicable law fulfilling obligations under article
|
| 183 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 184 |
+
similar laws prohibiting or restricting circumvention of such
|
| 185 |
+
measures.
|
| 186 |
+
|
| 187 |
+
When you convey a covered work, you waive any legal power to forbid
|
| 188 |
+
circumvention of technological measures to the extent such circumvention
|
| 189 |
+
is effected by exercising rights under this License with respect to
|
| 190 |
+
the covered work, and you disclaim any intention to limit operation or
|
| 191 |
+
modification of the work as a means of enforcing, against the work's
|
| 192 |
+
users, your or third parties' legal rights to forbid circumvention of
|
| 193 |
+
technological measures.
|
| 194 |
+
|
| 195 |
+
4. Conveying Verbatim Copies.
|
| 196 |
+
|
| 197 |
+
You may convey verbatim copies of the Program's source code as you
|
| 198 |
+
receive it, in any medium, provided that you conspicuously and
|
| 199 |
+
appropriately publish on each copy an appropriate copyright notice;
|
| 200 |
+
keep intact all notices stating that this License and any
|
| 201 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
| 202 |
+
keep intact all notices of the absence of any warranty; and give all
|
| 203 |
+
recipients a copy of this License along with the Program.
|
| 204 |
+
|
| 205 |
+
You may charge any price or no price for each copy that you convey,
|
| 206 |
+
and you may offer support or warranty protection for a fee.
|
| 207 |
+
|
| 208 |
+
5. Conveying Modified Source Versions.
|
| 209 |
+
|
| 210 |
+
You may convey a work based on the Program, or the modifications to
|
| 211 |
+
produce it from the Program, in the form of source code under the
|
| 212 |
+
terms of section 4, provided that you also meet all of these conditions:
|
| 213 |
+
|
| 214 |
+
a) The work must carry prominent notices stating that you modified
|
| 215 |
+
it, and giving a relevant date.
|
| 216 |
+
|
| 217 |
+
b) The work must carry prominent notices stating that it is
|
| 218 |
+
released under this License and any conditions added under section
|
| 219 |
+
7. This requirement modifies the requirement in section 4 to
|
| 220 |
+
"keep intact all notices".
|
| 221 |
+
|
| 222 |
+
c) You must license the entire work, as a whole, under this
|
| 223 |
+
License to anyone who comes into possession of a copy. This
|
| 224 |
+
License will therefore apply, along with any applicable section 7
|
| 225 |
+
additional terms, to the whole of the work, and all its parts,
|
| 226 |
+
regardless of how they are packaged. This License gives no
|
| 227 |
+
permission to license the work in any other way, but it does not
|
| 228 |
+
invalidate such permission if you have separately received it.
|
| 229 |
+
|
| 230 |
+
d) If the work has interactive user interfaces, each must display
|
| 231 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
| 232 |
+
interfaces that do not display Appropriate Legal Notices, your
|
| 233 |
+
work need not make them do so.
|
| 234 |
+
|
| 235 |
+
A compilation of a covered work with other separate and independent
|
| 236 |
+
works, which are not by their nature extensions of the covered work,
|
| 237 |
+
and which are not combined with it such as to form a larger program,
|
| 238 |
+
in or on a volume of a storage or distribution medium, is called an
|
| 239 |
+
"aggregate" if the compilation and its resulting copyright are not
|
| 240 |
+
used to limit the access or legal rights of the compilation's users
|
| 241 |
+
beyond what the individual works permit. Inclusion of a covered work
|
| 242 |
+
in an aggregate does not cause this License to apply to the other
|
| 243 |
+
parts of the aggregate.
|
| 244 |
+
|
| 245 |
+
6. Conveying Non-Source Forms.
|
| 246 |
+
|
| 247 |
+
You may convey a covered work in object code form under the terms
|
| 248 |
+
of sections 4 and 5, provided that you also convey the
|
| 249 |
+
machine-readable Corresponding Source under the terms of this License,
|
| 250 |
+
in one of these ways:
|
| 251 |
+
|
| 252 |
+
a) Convey the object code in, or embodied in, a physical product
|
| 253 |
+
(including a physical distribution medium), accompanied by the
|
| 254 |
+
Corresponding Source fixed on a durable physical medium
|
| 255 |
+
customarily used for software interchange.
|
| 256 |
+
|
| 257 |
+
b) Convey the object code in, or embodied in, a physical product
|
| 258 |
+
(including a physical distribution medium), accompanied by a
|
| 259 |
+
written offer, valid for at least three years and valid for as
|
| 260 |
+
long as you offer spare parts or customer support for that product
|
| 261 |
+
model, to give anyone who possesses the object code either (1) a
|
| 262 |
+
copy of the Corresponding Source for all the software in the
|
| 263 |
+
product that is covered by this License, on a durable physical
|
| 264 |
+
medium customarily used for software interchange, for a price no
|
| 265 |
+
more than your reasonable cost of physically performing this
|
| 266 |
+
conveying of source, or (2) access to copy the
|
| 267 |
+
Corresponding Source from a network server at no charge.
|
| 268 |
+
|
| 269 |
+
c) Convey individual copies of the object code with a copy of the
|
| 270 |
+
written offer to provide the Corresponding Source. This
|
| 271 |
+
alternative is allowed only occasionally and noncommercially, and
|
| 272 |
+
only if you received the object code with such an offer, in accord
|
| 273 |
+
with subsection 6b.
|
| 274 |
+
|
| 275 |
+
d) Convey the object code by offering access from a designated
|
| 276 |
+
place (gratis or for a charge), and offer equivalent access to the
|
| 277 |
+
Corresponding Source in the same way through the same place at no
|
| 278 |
+
further charge. You need not require recipients to copy the
|
| 279 |
+
Corresponding Source along with the object code. If the place to
|
| 280 |
+
copy the object code is a network server, the Corresponding Source
|
| 281 |
+
may be on a different server (operated by you or a third party)
|
| 282 |
+
that supports equivalent copying facilities, provided you maintain
|
| 283 |
+
clear directions next to the object code saying where to find the
|
| 284 |
+
Corresponding Source. Regardless of what server hosts the
|
| 285 |
+
Corresponding Source, you remain obligated to ensure that it is
|
| 286 |
+
available for as long as needed to satisfy these requirements.
|
| 287 |
+
|
| 288 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
| 289 |
+
you inform other peers where the object code and Corresponding
|
| 290 |
+
Source of the work are being offered to the general public at no
|
| 291 |
+
charge under subsection 6d.
|
| 292 |
+
|
| 293 |
+
A separable portion of the object code, whose source code is excluded
|
| 294 |
+
from the Corresponding Source as a System Library, need not be
|
| 295 |
+
included in conveying the object code work.
|
| 296 |
+
|
| 297 |
+
A "User Product" is either (1) a "consumer product", which means any
|
| 298 |
+
tangible personal property which is normally used for personal, family,
|
| 299 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
| 300 |
+
into a dwelling. In determining whether a product is a consumer product,
|
| 301 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
| 302 |
+
product received by a particular user, "normally used" refers to a
|
| 303 |
+
typical or common use of that class of product, regardless of the status
|
| 304 |
+
of the particular user or of the way in which the particular user
|
| 305 |
+
actually uses, or expects or is expected to use, the product. A product
|
| 306 |
+
is a consumer product regardless of whether the product has substantial
|
| 307 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
| 308 |
+
the only significant mode of use of the product.
|
| 309 |
+
|
| 310 |
+
"Installation Information" for a User Product means any methods,
|
| 311 |
+
procedures, authorization keys, or other information required to install
|
| 312 |
+
and execute modified versions of a covered work in that User Product from
|
| 313 |
+
a modified version of its Corresponding Source. The information must
|
| 314 |
+
suffice to ensure that the continued functioning of the modified object
|
| 315 |
+
code is in no case prevented or interfered with solely because
|
| 316 |
+
modification has been made.
|
| 317 |
+
|
| 318 |
+
If you convey an object code work under this section in, or with, or
|
| 319 |
+
specifically for use in, a User Product, and the conveying occurs as
|
| 320 |
+
part of a transaction in which the right of possession and use of the
|
| 321 |
+
User Product is transferred to the recipient in perpetuity or for a
|
| 322 |
+
fixed term (regardless of how the transaction is characterized), the
|
| 323 |
+
Corresponding Source conveyed under this section must be accompanied
|
| 324 |
+
by the Installation Information. But this requirement does not apply
|
| 325 |
+
if neither you nor any third party retains the ability to install
|
| 326 |
+
modified object code on the User Product (for example, the work has
|
| 327 |
+
been installed in ROM).
|
| 328 |
+
|
| 329 |
+
The requirement to provide Installation Information does not include a
|
| 330 |
+
requirement to continue to provide support service, warranty, or updates
|
| 331 |
+
for a work that has been modified or installed by the recipient, or for
|
| 332 |
+
the User Product in which it has been modified or installed. Access to a
|
| 333 |
+
network may be denied when the modification itself materially and
|
| 334 |
+
adversely affects the operation of the network or violates the rules and
|
| 335 |
+
protocols for communication across the network.
|
| 336 |
+
|
| 337 |
+
Corresponding Source conveyed, and Installation Information provided,
|
| 338 |
+
in accord with this section must be in a format that is publicly
|
| 339 |
+
documented (and with an implementation available to the public in
|
| 340 |
+
source code form), and must require no special password or key for
|
| 341 |
+
unpacking, reading or copying.
|
| 342 |
+
|
| 343 |
+
7. Additional Terms.
|
| 344 |
+
|
| 345 |
+
"Additional permissions" are terms that supplement the terms of this
|
| 346 |
+
License by making exceptions from one or more of its conditions.
|
| 347 |
+
Additional permissions that are applicable to the entire Program shall
|
| 348 |
+
be treated as though they were included in this License, to the extent
|
| 349 |
+
that they are valid under applicable law. If additional permissions
|
| 350 |
+
apply only to part of the Program, that part may be used separately
|
| 351 |
+
under those permissions, but the entire Program remains governed by
|
| 352 |
+
this License without regard to the additional permissions.
|
| 353 |
+
|
| 354 |
+
When you convey a copy of a covered work, you may at your option
|
| 355 |
+
remove any additional permissions from that copy, or from any part of
|
| 356 |
+
it. (Additional permissions may be written to require their own
|
| 357 |
+
removal in certain cases when you modify the work.) You may place
|
| 358 |
+
additional permissions on material, added by you to a covered work,
|
| 359 |
+
for which you have or can give appropriate copyright permission.
|
| 360 |
+
|
| 361 |
+
Notwithstanding any other provision of this License, for material you
|
| 362 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
| 363 |
+
that material) supplement the terms of this License with terms:
|
| 364 |
+
|
| 365 |
+
a) Disclaiming warranty or limiting liability differently from the
|
| 366 |
+
terms of sections 15 and 16 of this License; or
|
| 367 |
+
|
| 368 |
+
b) Requiring preservation of specified reasonable legal notices or
|
| 369 |
+
author attributions in that material or in the Appropriate Legal
|
| 370 |
+
Notices displayed by works containing it; or
|
| 371 |
+
|
| 372 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
| 373 |
+
requiring that modified versions of such material be marked in
|
| 374 |
+
reasonable ways as different from the original version; or
|
| 375 |
+
|
| 376 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
| 377 |
+
authors of the material; or
|
| 378 |
+
|
| 379 |
+
e) Declining to grant rights under trademark law for use of some
|
| 380 |
+
trade names, trademarks, or service marks; or
|
| 381 |
+
|
| 382 |
+
f) Requiring indemnification of licensors and authors of that
|
| 383 |
+
material by anyone who conveys the material (or modified versions of
|
| 384 |
+
it) with contractual assumptions of liability to the recipient, for
|
| 385 |
+
any liability that these contractual assumptions directly impose on
|
| 386 |
+
those licensors and authors.
|
| 387 |
+
|
| 388 |
+
All other non-permissive additional terms are considered "further
|
| 389 |
+
restrictions" within the meaning of section 10. If the Program as you
|
| 390 |
+
received it, or any part of it, contains a notice stating that it is
|
| 391 |
+
governed by this License along with a term that is a further
|
| 392 |
+
restriction, you may remove that term. If a license document contains
|
| 393 |
+
a further restriction but permits relicensing or conveying under this
|
| 394 |
+
License, you may add to a covered work material governed by the terms
|
| 395 |
+
of that license document, provided that the further restriction does
|
| 396 |
+
not survive such relicensing or conveying.
|
| 397 |
+
|
| 398 |
+
If you add terms to a covered work in accord with this section, you
|
| 399 |
+
must place, in the relevant source files, a statement of the
|
| 400 |
+
additional terms that apply to those files, or a notice indicating
|
| 401 |
+
where to find the applicable terms.
|
| 402 |
+
|
| 403 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
| 404 |
+
form of a separately written license, or stated as exceptions;
|
| 405 |
+
the above requirements apply either way.
|
| 406 |
+
|
| 407 |
+
8. Termination.
|
| 408 |
+
|
| 409 |
+
You may not propagate or modify a covered work except as expressly
|
| 410 |
+
provided under this License. Any attempt otherwise to propagate or
|
| 411 |
+
modify it is void, and will automatically terminate your rights under
|
| 412 |
+
this License (including any patent licenses granted under the third
|
| 413 |
+
paragraph of section 11).
|
| 414 |
+
|
| 415 |
+
However, if you cease all violation of this License, then your
|
| 416 |
+
license from a particular copyright holder is reinstated (a)
|
| 417 |
+
provisionally, unless and until the copyright holder explicitly and
|
| 418 |
+
finally terminates your license, and (b) permanently, if the copyright
|
| 419 |
+
holder fails to notify you of the violation by some reasonable means
|
| 420 |
+
prior to 60 days after the cessation.
|
| 421 |
+
|
| 422 |
+
Moreover, your license from a particular copyright holder is
|
| 423 |
+
reinstated permanently if the copyright holder notifies you of the
|
| 424 |
+
violation by some reasonable means, this is the first time you have
|
| 425 |
+
received notice of violation of this License (for any work) from that
|
| 426 |
+
copyright holder, and you cure the violation prior to 30 days after
|
| 427 |
+
your receipt of the notice.
|
| 428 |
+
|
| 429 |
+
Termination of your rights under this section does not terminate the
|
| 430 |
+
licenses of parties who have received copies or rights from you under
|
| 431 |
+
this License. If your rights have been terminated and not permanently
|
| 432 |
+
reinstated, you do not qualify to receive new licenses for the same
|
| 433 |
+
material under section 10.
|
| 434 |
+
|
| 435 |
+
9. Acceptance Not Required for Having Copies.
|
| 436 |
+
|
| 437 |
+
You are not required to accept this License in order to receive or
|
| 438 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
| 439 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
| 440 |
+
to receive a copy likewise does not require acceptance. However,
|
| 441 |
+
nothing other than this License grants you permission to propagate or
|
| 442 |
+
modify any covered work. These actions infringe copyright if you do
|
| 443 |
+
not accept this License. Therefore, by modifying or propagating a
|
| 444 |
+
covered work, you indicate your acceptance of this License to do so.
|
| 445 |
+
|
| 446 |
+
10. Automatic Licensing of Downstream Recipients.
|
| 447 |
+
|
| 448 |
+
Each time you convey a covered work, the recipient automatically
|
| 449 |
+
receives a license from the original licensors, to run, modify and
|
| 450 |
+
propagate that work, subject to this License. You are not responsible
|
| 451 |
+
for enforcing compliance by third parties with this License.
|
| 452 |
+
|
| 453 |
+
An "entity transaction" is a transaction transferring control of an
|
| 454 |
+
organization, or substantially all assets of one, or subdividing an
|
| 455 |
+
organization, or merging organizations. If propagation of a covered
|
| 456 |
+
work results from an entity transaction, each party to that
|
| 457 |
+
transaction who receives a copy of the work also receives whatever
|
| 458 |
+
licenses to the work the party's predecessor in interest had or could
|
| 459 |
+
give under the previous paragraph, plus a right to possession of the
|
| 460 |
+
Corresponding Source of the work from the predecessor in interest, if
|
| 461 |
+
the predecessor has it or can get it with reasonable efforts.
|
| 462 |
+
|
| 463 |
+
You may not impose any further restrictions on the exercise of the
|
| 464 |
+
rights granted or affirmed under this License. For example, you may
|
| 465 |
+
not impose a license fee, royalty, or other charge for exercise of
|
| 466 |
+
rights granted under this License, and you may not initiate litigation
|
| 467 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 468 |
+
any patent claim is infringed by making, using, selling, offering for
|
| 469 |
+
sale, or importing the Program or any portion of it.
|
| 470 |
+
|
| 471 |
+
11. Patents.
|
| 472 |
+
|
| 473 |
+
A "contributor" is a copyright holder who authorizes use under this
|
| 474 |
+
License of the Program or a work on which the Program is based. The
|
| 475 |
+
work thus licensed is called the contributor's "contributor version".
|
| 476 |
+
|
| 477 |
+
A contributor's "essential patent claims" are all patent claims
|
| 478 |
+
owned or controlled by the contributor, whether already acquired or
|
| 479 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
| 480 |
+
by this License, of making, using, or selling its contributor version,
|
| 481 |
+
but do not include claims that would be infringed only as a
|
| 482 |
+
consequence of further modification of the contributor version. For
|
| 483 |
+
purposes of this definition, "control" includes the right to grant
|
| 484 |
+
patent sublicenses in a manner consistent with the requirements of
|
| 485 |
+
this License.
|
| 486 |
+
|
| 487 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 488 |
+
patent license under the contributor's essential patent claims, to
|
| 489 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
| 490 |
+
propagate the contents of its contributor version.
|
| 491 |
+
|
| 492 |
+
In the following three paragraphs, a "patent license" is any express
|
| 493 |
+
agreement or commitment, however denominated, not to enforce a patent
|
| 494 |
+
(such as an express permission to practice a patent or covenant not to
|
| 495 |
+
sue for patent infringement). To "grant" such a patent license to a
|
| 496 |
+
party means to make such an agreement or commitment not to enforce a
|
| 497 |
+
patent against the party.
|
| 498 |
+
|
| 499 |
+
If you convey a covered work, knowingly relying on a patent license,
|
| 500 |
+
and the Corresponding Source of the work is not available for anyone
|
| 501 |
+
to copy, free of charge and under the terms of this License, through a
|
| 502 |
+
publicly available network server or other readily accessible means,
|
| 503 |
+
then you must either (1) cause the Corresponding Source to be so
|
| 504 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
| 505 |
+
patent license for this particular work, or (3) arrange, in a manner
|
| 506 |
+
consistent with the requirements of this License, to extend the patent
|
| 507 |
+
license to downstream recipients. "Knowingly relying" means you have
|
| 508 |
+
actual knowledge that, but for the patent license, your conveying the
|
| 509 |
+
covered work in a country, or your recipient's use of the covered work
|
| 510 |
+
in a country, would infringe one or more identifiable patents in that
|
| 511 |
+
country that you have reason to believe are valid.
|
| 512 |
+
|
| 513 |
+
If, pursuant to or in connection with a single transaction or
|
| 514 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
| 515 |
+
covered work, and grant a patent license to some of the parties
|
| 516 |
+
receiving the covered work authorizing them to use, propagate, modify
|
| 517 |
+
or convey a specific copy of the covered work, then the patent license
|
| 518 |
+
you grant is automatically extended to all recipients of the covered
|
| 519 |
+
work and works based on it.
|
| 520 |
+
|
| 521 |
+
A patent license is "discriminatory" if it does not include within
|
| 522 |
+
the scope of its coverage, prohibits the exercise of, or is
|
| 523 |
+
conditioned on the non-exercise of one or more of the rights that are
|
| 524 |
+
specifically granted under this License. You may not convey a covered
|
| 525 |
+
work if you are a party to an arrangement with a third party that is
|
| 526 |
+
in the business of distributing software, under which you make payment
|
| 527 |
+
to the third party based on the extent of your activity of conveying
|
| 528 |
+
the work, and under which the third party grants, to any of the
|
| 529 |
+
parties who would receive the covered work from you, a discriminatory
|
| 530 |
+
patent license (a) in connection with copies of the covered work
|
| 531 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
| 532 |
+
for and in connection with specific products or compilations that
|
| 533 |
+
contain the covered work, unless you entered into that arrangement,
|
| 534 |
+
or that patent license was granted, prior to 28 March 2007.
|
| 535 |
+
|
| 536 |
+
Nothing in this License shall be construed as excluding or limiting
|
| 537 |
+
any implied license or other defenses to infringement that may
|
| 538 |
+
otherwise be available to you under applicable patent law.
|
| 539 |
+
|
| 540 |
+
12. No Surrender of Others' Freedom.
|
| 541 |
+
|
| 542 |
+
If conditions are imposed on you (whether by court order, agreement or
|
| 543 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 544 |
+
excuse you from the conditions of this License. If you cannot convey a
|
| 545 |
+
covered work so as to satisfy simultaneously your obligations under this
|
| 546 |
+
License and any other pertinent obligations, then as a consequence you may
|
| 547 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
| 548 |
+
to collect a royalty for further conveying from those to whom you convey
|
| 549 |
+
the Program, the only way you could satisfy both those terms and this
|
| 550 |
+
License would be to refrain entirely from conveying the Program.
|
| 551 |
+
|
| 552 |
+
13. Use with the GNU Affero General Public License.
|
| 553 |
+
|
| 554 |
+
Notwithstanding any other provision of this License, you have
|
| 555 |
+
permission to link or combine any covered work with a work licensed
|
| 556 |
+
under version 3 of the GNU Affero General Public License into a single
|
| 557 |
+
combined work, and to convey the resulting work. The terms of this
|
| 558 |
+
License will continue to apply to the part which is the covered work,
|
| 559 |
+
but the special requirements of the GNU Affero General Public License,
|
| 560 |
+
section 13, concerning interaction through a network will apply to the
|
| 561 |
+
combination as such.
|
| 562 |
+
|
| 563 |
+
14. Revised Versions of this License.
|
| 564 |
+
|
| 565 |
+
The Free Software Foundation may publish revised and/or new versions of
|
| 566 |
+
the GNU General Public License from time to time. Such new versions will
|
| 567 |
+
be similar in spirit to the present version, but may differ in detail to
|
| 568 |
+
address new problems or concerns.
|
| 569 |
+
|
| 570 |
+
Each version is given a distinguishing version number. If the
|
| 571 |
+
Program specifies that a certain numbered version of the GNU General
|
| 572 |
+
Public License "or any later version" applies to it, you have the
|
| 573 |
+
option of following the terms and conditions either of that numbered
|
| 574 |
+
version or of any later version published by the Free Software
|
| 575 |
+
Foundation. If the Program does not specify a version number of the
|
| 576 |
+
GNU General Public License, you may choose any version ever published
|
| 577 |
+
by the Free Software Foundation.
|
| 578 |
+
|
| 579 |
+
If the Program specifies that a proxy can decide which future
|
| 580 |
+
versions of the GNU General Public License can be used, that proxy's
|
| 581 |
+
public statement of acceptance of a version permanently authorizes you
|
| 582 |
+
to choose that version for the Program.
|
| 583 |
+
|
| 584 |
+
Later license versions may give you additional or different
|
| 585 |
+
permissions. However, no additional obligations are imposed on any
|
| 586 |
+
author or copyright holder as a result of your choosing to follow a
|
| 587 |
+
later version.
|
| 588 |
+
|
| 589 |
+
15. Disclaimer of Warranty.
|
| 590 |
+
|
| 591 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 592 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 593 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 594 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 595 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 596 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 597 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 598 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 599 |
+
|
| 600 |
+
16. Limitation of Liability.
|
| 601 |
+
|
| 602 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 603 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 604 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 605 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 606 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 607 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 608 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 609 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 610 |
+
SUCH DAMAGES.
|
| 611 |
+
|
| 612 |
+
17. Interpretation of Sections 15 and 16.
|
| 613 |
+
|
| 614 |
+
If the disclaimer of warranty and limitation of liability provided
|
| 615 |
+
above cannot be given local legal effect according to their terms,
|
| 616 |
+
reviewing courts shall apply local law that most closely approximates
|
| 617 |
+
an absolute waiver of all civil liability in connection with the
|
| 618 |
+
Program, unless a warranty or assumption of liability accompanies a
|
| 619 |
+
copy of the Program in return for a fee.
|
| 620 |
+
|
| 621 |
+
END OF TERMS AND CONDITIONS
|
| 622 |
+
|
| 623 |
+
How to Apply These Terms to Your New Programs
|
| 624 |
+
|
| 625 |
+
If you develop a new program, and you want it to be of the greatest
|
| 626 |
+
possible use to the public, the best way to achieve this is to make it
|
| 627 |
+
free software which everyone can redistribute and change under these terms.
|
| 628 |
+
|
| 629 |
+
To do so, attach the following notices to the program. It is safest
|
| 630 |
+
to attach them to the start of each source file to most effectively
|
| 631 |
+
state the exclusion of warranty; and each file should have at least
|
| 632 |
+
the "copyright" line and a pointer to where the full notice is found.
|
| 633 |
+
|
| 634 |
+
<one line to give the program's name and a brief idea of what it does.>
|
| 635 |
+
Copyright (C) <year> <name of author>
|
| 636 |
+
|
| 637 |
+
This program is free software: you can redistribute it and/or modify
|
| 638 |
+
it under the terms of the GNU General Public License as published by
|
| 639 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 640 |
+
(at your option) any later version.
|
| 641 |
+
|
| 642 |
+
This program is distributed in the hope that it will be useful,
|
| 643 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 644 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 645 |
+
GNU General Public License for more details.
|
| 646 |
+
|
| 647 |
+
You should have received a copy of the GNU General Public License
|
| 648 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 649 |
+
|
| 650 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 651 |
+
|
| 652 |
+
If the program does terminal interaction, make it output a short
|
| 653 |
+
notice like this when it starts in an interactive mode:
|
| 654 |
+
|
| 655 |
+
<program> Copyright (C) <year> <name of author>
|
| 656 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 657 |
+
This is free software, and you are welcome to redistribute it
|
| 658 |
+
under certain conditions; type `show c' for details.
|
| 659 |
+
|
| 660 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 661 |
+
parts of the General Public License. Of course, your program's commands
|
| 662 |
+
might be different; for a GUI interface, you would use an "about box".
|
| 663 |
+
|
| 664 |
+
You should also get your employer (if you work as a programmer) or school,
|
| 665 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 666 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
| 667 |
+
<http://www.gnu.org/licenses/>.
|
| 668 |
+
|
| 669 |
+
The GNU General Public License does not permit incorporating your program
|
| 670 |
+
into proprietary programs. If your program is a subroutine library, you
|
| 671 |
+
may consider it more useful to permit linking proprietary applications with
|
| 672 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
| 673 |
+
Public License instead of this License. But first, please read
|
| 674 |
+
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
Fairy-Stockfish-master/MANIFEST.in
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
include AUTHORS Copying.txt Readme.md test.py
|
| 2 |
+
recursive-include src *.h *.cpp
|
Fairy-Stockfish-master/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fairy-Stockfish
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
[](https://github.com/fairy-stockfish/Fairy-Stockfish/actions?query=workflow%3ARelease)
|
| 6 |
+
[](https://github.com/fairy-stockfish/Fairy-Stockfish/actions?query=workflow%3Afairy)
|
| 7 |
+
[](https://ci.appveyor.com/project/ianfab/Fairy-Stockfish/branch/master)
|
| 8 |
+
[](https://badge.fury.io/py/pyffish)
|
| 9 |
+
[](https://www.npmjs.com/package/ffish)
|
| 10 |
+
|
| 11 |
+
Fairy-Stockfish is a chess variant engine derived from [Stockfish](https://github.com/official-stockfish/Stockfish/) designed for the support of fairy chess variants and easy extensibility with more games. It can play various regional, historical, and modern chess variants as well as [games with user-defined rules](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Variant-configuration). For [compatibility with graphical user interfaces](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Graphical-user-interfaces) it supports the UCI, UCCI, USI, UCI-cyclone, and CECP/XBoard protocols.
|
| 12 |
+
|
| 13 |
+
The goal of the project is to create an engine supporting a large variety of chess-like games, equipped with the powerful search of Stockfish. Despite its generality the [playing strength](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Playing-strength) is on a very high level in almost all supported variants. Due to its multi-protocol support Fairy-Stockfish works with almost any chess variant GUI.
|
| 14 |
+
|
| 15 |
+
## Installation
|
| 16 |
+
You can download the [Windows executable](https://github.com/fairy-stockfish/Fairy-Stockfish/releases/latest/download/fairy-stockfish-largeboard_x86-64.exe) or [Linux binary](https://github.com/fairy-stockfish/Fairy-Stockfish/releases/latest/download/fairy-stockfish-largeboard_x86-64) from the [latest release](https://github.com/fairy-stockfish/Fairy-Stockfish/releases/latest) or [compile the program from source](https://github.com/fairy-stockfish/Fairy-Stockfish#compiling-stockfish-yourself-from-the-sources). The program comes without a graphical user interface, so you perhaps want to use it together with a [compatible GUI](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Graphical-user-interfaces), or [play against it online](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Online) at [pychess](https://www.pychess.org/), [lishogi](https://lishogi.org/@/Fairy-Stockfish), or [lichess](https://lichess.org/@/Fairy-Stockfish). Read more about [how to use](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Usage) Fairy-Stockfish in the wiki.
|
| 17 |
+
|
| 18 |
+
If you want to preview the functionality of Fairy-Stockfish before downloading, you can try it out on the [Fairy-Stockfish playground](https://fairyground.vercel.app/) in the browser.
|
| 19 |
+
|
| 20 |
+
Optional NNUE evaluation parameter files to improve playing strength for many variants are in the [list of NNUE networks](https://fairy-stockfish.github.io/nnue/#current-best-nnue-networks).
|
| 21 |
+
For the regional variants Xiangqi, Janggi, and Makruk [dedicated releases with built-in NNUE networks](https://github.com/fairy-stockfish/Fairy-Stockfish-NNUE) are available. See the [wiki](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/NNUE) for more details on NNUE.
|
| 22 |
+
|
| 23 |
+
## Contributing
|
| 24 |
+
|
| 25 |
+
If you like this project, please support its development via [patreon](https://www.patreon.com/ianfab), [paypal](https://paypal.me/FairyStockfish), or [github](https://github.com/sponsors/ianfab), or by [contributing to the code](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Contributing) or documentation. An [introduction to the code base](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Understanding-the-code) can be found in the wiki.
|
| 26 |
+
|
| 27 |
+
## Supported games
|
| 28 |
+
|
| 29 |
+
The games currently supported besides chess are listed below. Fairy-Stockfish can also play user-defined variants loaded via a variant configuration file, see the file [`src/variants.ini`](https://github.com/ianfab/Fairy-Stockfish/blob/master/src/variants.ini) and the [wiki](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki/Variant-configuration).
|
| 30 |
+
|
| 31 |
+
### Regional and historical games
|
| 32 |
+
- [Xiangqi](https://en.wikipedia.org/wiki/Xiangqi), [Manchu](https://en.wikipedia.org/wiki/Manchu_chess), [Minixiangqi](https://www.pychess.org/variants/minixiangqi), [Supply chess](https://en.wikipedia.org/wiki/Xiangqi#Variations)
|
| 33 |
+
- [Shogi](https://en.wikipedia.org/wiki/Shogi), [Shogi variants](https://github.com/fairy-stockfish/Fairy-Stockfish#shogi-variants)
|
| 34 |
+
- [Janggi](https://en.wikipedia.org/wiki/Janggi)
|
| 35 |
+
- [Makruk](https://en.wikipedia.org/wiki/Makruk), [ASEAN](http://hgm.nubati.net/rules/ASEAN.html), Makpong, Ai-Wok
|
| 36 |
+
- [Ouk Chatrang](https://en.wikipedia.org/wiki/Makruk#Cambodian_chess), [Kar Ouk](https://en.wikipedia.org/wiki/Makruk#Cambodian_chess)
|
| 37 |
+
- [Sittuyin](https://en.wikipedia.org/wiki/Sittuyin)
|
| 38 |
+
- [Shatar](https://en.wikipedia.org/wiki/Shatar), [Jeson Mor](https://en.wikipedia.org/wiki/Jeson_Mor)
|
| 39 |
+
- [Shatranj](https://en.wikipedia.org/wiki/Shatranj), [Courier](https://en.wikipedia.org/wiki/Courier_chess)
|
| 40 |
+
- [Raazuvaa](https://www.reddit.com/r/chess/comments/sj7y3n/raazuvaa_the_chess_of_the_maldives)
|
| 41 |
+
|
| 42 |
+
### Chess variants
|
| 43 |
+
- [Capablanca](https://en.wikipedia.org/wiki/Capablanca_Chess), [Janus](https://en.wikipedia.org/wiki/Janus_Chess), [Modern](https://en.wikipedia.org/wiki/Modern_Chess_(chess_variant)), [Chancellor](https://en.wikipedia.org/wiki/Chancellor_Chess), [Embassy](https://en.wikipedia.org/wiki/Embassy_Chess), [Gothic](https://www.chessvariants.com/large.dir/gothicchess.html), [Capablanca random chess](https://en.wikipedia.org/wiki/Capablanca_Random_Chess)
|
| 44 |
+
- [Grand](https://en.wikipedia.org/wiki/Grand_Chess), [Shako](https://www.chessvariants.com/large.dir/shako.html), [Centaur](https://www.chessvariants.com/large.dir/contest/royalcourt.html), [Tencubed](https://www.chessvariants.com/contests/10/tencubedchess.html), [Opulent](https://www.chessvariants.com/rules/opulent-chess)
|
| 45 |
+
- [Chess960](https://en.wikipedia.org/wiki/Chess960), [Placement/Pre-Chess](https://www.chessvariants.com/link/placement-chess)
|
| 46 |
+
- [Crazyhouse](https://en.wikipedia.org/wiki/Crazyhouse), [Loop](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Chessgi](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Pocket Knight](http://www.chessvariants.com/other.dir/pocket.html), Capablanca-Crazyhouse
|
| 47 |
+
- [Bughouse](https://en.wikipedia.org/wiki/Bughouse_chess), [Koedem](http://schachclub-oetigheim.de/wp-content/uploads/2016/04/Koedem-rules.pdf)
|
| 48 |
+
- [Seirawan](https://en.wikipedia.org/wiki/Seirawan_chess), Seirawan-Crazyhouse, [Dragon Chess](https://www.edami.com/dragonchess/)
|
| 49 |
+
- [Amazon](https://www.chessvariants.com/diffmove.dir/amazone.html), [Chigorin](https://www.chessvariants.com/diffsetup.dir/chigorin.html), [Almost chess](https://en.wikipedia.org/wiki/Almost_Chess)
|
| 50 |
+
- [Hoppel-Poppel](http://www.chessvariants.com/diffmove.dir/hoppel-poppel.html), New Zealand
|
| 51 |
+
- [Antichess](https://lichess.org/variant/antichess), [Giveaway](http://www.chessvariants.com/diffobjective.dir/giveaway.old.html), [Suicide](https://www.freechess.org/Help/HelpFiles/suicide_chess.html), [Losers](https://www.chessclub.com/help/Wild17), [Codrus](http://www.binnewirtz.com/Schlagschach1.htm)
|
| 52 |
+
- [Extinction](https://en.wikipedia.org/wiki/Extinction_chess), [Kinglet](https://en.wikipedia.org/wiki/V._R._Parton#Kinglet_chess), Three Kings, [Coregal](https://www.chessvariants.com/winning.dir/coregal.html)
|
| 53 |
+
- [King of the Hill](https://en.wikipedia.org/wiki/King_of_the_Hill_(chess)), [Racing Kings](https://en.wikipedia.org/wiki/V._R._Parton#Racing_Kings)
|
| 54 |
+
- [Three-check](https://en.wikipedia.org/wiki/Three-check_chess), Five-check
|
| 55 |
+
- [Los Alamos](https://en.wikipedia.org/wiki/Los_Alamos_chess), [Gardner's Minichess](https://en.wikipedia.org/wiki/Minichess#5%C3%975_chess)
|
| 56 |
+
- [Atomic](https://en.wikipedia.org/wiki/Atomic_chess)
|
| 57 |
+
- [Horde](https://en.wikipedia.org/wiki/Dunsany%27s_Chess#Horde_Chess), [Maharajah and the Sepoys](https://en.wikipedia.org/wiki/Maharajah_and_the_Sepoys)
|
| 58 |
+
- [Knightmate](https://www.chessvariants.com/diffobjective.dir/knightmate.html), [Nightrider](https://en.wikipedia.org/wiki/Nightrider_(chess)), [Grasshopper](https://en.wikipedia.org/wiki/Grasshopper_chess)
|
| 59 |
+
- [Duck chess](https://duckchess.com/), [Omicron](http://www.eglebbk.dds.nl/program/chess-omicron.html), [Gustav III](https://www.chessvariants.com/play/gustav-iiis-chess)
|
| 60 |
+
- [Berolina Chess](https://en.wikipedia.org/wiki/Berolina_pawn#Berolina_chess), [Pawn-Sideways](https://arxiv.org/abs/2009.04374), [Pawn-Back](https://arxiv.org/abs/2009.04374), [Torpedo](https://arxiv.org/abs/2009.04374), [Legan Chess](https://en.wikipedia.org/wiki/Legan_chess)
|
| 61 |
+
- [Spartan Chess](https://www.chessvariants.com/rules/spartan-chess)
|
| 62 |
+
- [Wolf Chess](https://en.wikipedia.org/wiki/Wolf_chess)
|
| 63 |
+
- [Troitzky Chess](https://www.chessvariants.com/play/troitzky-chess)
|
| 64 |
+
|
| 65 |
+
### Shogi variants
|
| 66 |
+
- [Minishogi](https://en.wikipedia.org/wiki/Minishogi), [EuroShogi](https://en.wikipedia.org/wiki/EuroShogi), [Judkins shogi](https://en.wikipedia.org/wiki/Judkins_shogi)
|
| 67 |
+
- [Kyoto shogi](https://en.wikipedia.org/wiki/Kyoto_shogi), [Microshogi](https://en.wikipedia.org/wiki/Micro_shogi)
|
| 68 |
+
- [Dobutsu shogi](https://en.wikipedia.org/wiki/Dōbutsu_shōgi), [Goro goro shogi](https://en.wikipedia.org/wiki/D%C5%8Dbutsu_sh%C5%8Dgi#Variation)
|
| 69 |
+
- [Tori shogi](https://en.wikipedia.org/wiki/Tori_shogi)
|
| 70 |
+
- [Yari shogi](https://en.wikipedia.org/wiki/Yari_shogi)
|
| 71 |
+
- [Okisaki shogi](https://en.wikipedia.org/wiki/Okisaki_shogi)
|
| 72 |
+
- [Sho shogi](https://en.wikipedia.org/wiki/Sho_shogi)
|
| 73 |
+
|
| 74 |
+
### Related games
|
| 75 |
+
- [Amazons](https://en.wikipedia.org/wiki/Game_of_the_Amazons)
|
| 76 |
+
- [Ataxx](https://en.wikipedia.org/wiki/Ataxx)
|
| 77 |
+
- [Breakthrough](https://en.wikipedia.org/wiki/Breakthrough_(board_game))
|
| 78 |
+
- [Clobber](https://en.wikipedia.org/wiki/Clobber)
|
| 79 |
+
- [Cfour](https://en.wikipedia.org/wiki/Connect_Four), [Tic-tac-toe](https://en.wikipedia.org/wiki/Tic-tac-toe)
|
| 80 |
+
- [Five Field Kono](https://en.wikipedia.org/wiki/Five_Field_Kono)
|
| 81 |
+
- [Flipersi](https://en.wikipedia.org/wiki/Reversi), [Flipello](https://en.wikipedia.org/wiki/Reversi#Othello)
|
| 82 |
+
- [Fox and Hounds](https://boardgamegeek.com/boardgame/148180/fox-and-hounds)
|
| 83 |
+
- [Isolation](https://boardgamegeek.com/boardgame/1875/isolation)
|
| 84 |
+
- [Joust](https://www.chessvariants.com/programs.dir/joust.html)
|
| 85 |
+
- [Snailtrail](https://boardgamegeek.com/boardgame/37135/snailtrail)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
## Help
|
| 89 |
+
|
| 90 |
+
See the [Fairy-Stockfish Wiki](https://github.com/fairy-stockfish/Fairy-Stockfish/wiki) for more info, or if the required information is not available, open an [issue](https://github.com/fairy-stockfish/Fairy-Stockfish/issues) or join our [discord server](https://discord.gg/FYUGgmCFB4).
|
| 91 |
+
|
| 92 |
+
## Bindings
|
| 93 |
+
|
| 94 |
+
Besides the C++ engine, this project also includes bindings for other programming languages in order to be able to use it as a library for chess variants. They support move, SAN, and FEN generation, as well as checking of game end conditions for all variants supported by Fairy-Stockfish. Since the bindings are using the C++ code, they are very performant compared to libraries directly written in the respective target language.
|
| 95 |
+
|
| 96 |
+
### Python
|
| 97 |
+
|
| 98 |
+
The python binding [pyffish](https://pypi.org/project/pyffish/) contributed by [@gbtami](https://github.com/gbtami) is implemented in [pyffish.cpp](https://github.com/fairy-stockfish/Fairy-Stockfish/blob/master/src/pyffish.cpp). It is e.g. used in the backend for the [pychess server](https://github.com/gbtami/pychess-variants).
|
| 99 |
+
|
| 100 |
+
### Javascript
|
| 101 |
+
|
| 102 |
+
The javascript binding [ffish.js](https://www.npmjs.com/package/ffish) contributed by [@QueensGambit](https://github.com/QueensGambit) is implemented in [ffishjs.cpp](https://github.com/fairy-stockfish/Fairy-Stockfish/blob/master/src/ffishjs.cpp). The compilation/binding to javascript is done using emscripten, see the [readme](https://github.com/fairy-stockfish/Fairy-Stockfish/tree/master/tests/js).
|
| 103 |
+
|
| 104 |
+
## Ports
|
| 105 |
+
|
| 106 |
+
### WebAssembly
|
| 107 |
+
|
| 108 |
+
For in-browser use a [port of Fairy-Stockfish to WebAssembly](https://github.com/fairy-stockfish/fairy-stockfish.wasm) is available at [npm](https://www.npmjs.com/package/fairy-stockfish-nnue.wasm). It is e.g. used for local analysis on [pychess.org](https://www.pychess.org/analysis/chess). Also see the [Fairy-Stockfish WASM demo](https://github.com/ianfab/fairy-stockfish-nnue-wasm-demo) available at https://fairy-stockfish-nnue-wasm.vercel.app/.
|
| 109 |
+
|
| 110 |
+
## Terms of use
|
| 111 |
+
|
| 112 |
+
Fairy-Stockfish is free, and distributed under the **GNU General Public License version 3**
|
| 113 |
+
(GPL v3). Essentially, this means you are free to do almost exactly
|
| 114 |
+
what you want with the program, including distributing it among your
|
| 115 |
+
friends, making it available for download from your website, selling
|
| 116 |
+
it (either by itself or as part of some bigger software package), or
|
| 117 |
+
using it as the starting point for a software project of your own.
|
| 118 |
+
|
| 119 |
+
The only real limitation is that whenever you distribute Fairy-Stockfish in
|
| 120 |
+
some way, you MUST always include the full source code, or a pointer
|
| 121 |
+
to where the source code can be found, to generate the exact binary
|
| 122 |
+
you are distributing. If you make any changes to the source code,
|
| 123 |
+
these changes must also be made available under the GPL.
|
| 124 |
+
|
| 125 |
+
For full details, read the copy of the GPL v3 found in the file named
|
| 126 |
+
[*Copying.txt*](https://github.com/fairy-stockfish/Fairy-Stockfish/blob/master/Copying.txt).
|
Fairy-Stockfish-master/Top CPU Contributors.txt
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Contributors to Fishtest with >10,000 CPU hours, as of Jun 29, 2021.
|
| 2 |
+
Thank you!
|
| 3 |
+
|
| 4 |
+
Username CPU Hours Games played
|
| 5 |
+
-----------------------------------------------------
|
| 6 |
+
noobpwnftw 27649494 1834734733
|
| 7 |
+
mlang 1426107 89454622
|
| 8 |
+
dew 1380910 82831648
|
| 9 |
+
mibere 703840 46867607
|
| 10 |
+
grandphish2 692707 41737913
|
| 11 |
+
tvijlbrief 669642 42371594
|
| 12 |
+
JojoM 597778 35297180
|
| 13 |
+
TueRens 519226 31823562
|
| 14 |
+
cw 458421 30307421
|
| 15 |
+
fastgm 439667 25950040
|
| 16 |
+
gvreuls 436599 28177460
|
| 17 |
+
crunchy 427035 27344275
|
| 18 |
+
CSU_Dynasty 374765 25106278
|
| 19 |
+
Fisherman 326901 21822979
|
| 20 |
+
ctoks 325477 21767943
|
| 21 |
+
velislav 295343 18844324
|
| 22 |
+
linrock 292789 10624427
|
| 23 |
+
bcross 278584 19488961
|
| 24 |
+
okrout 262818 13803272
|
| 25 |
+
pemo 245982 11376085
|
| 26 |
+
glinscott 217799 13780820
|
| 27 |
+
leszek 212346 12959025
|
| 28 |
+
nordlandia 211692 13484886
|
| 29 |
+
bking_US 198894 11876016
|
| 30 |
+
drabel 196463 13450602
|
| 31 |
+
robal 195473 12375650
|
| 32 |
+
mgrabiak 187226 12016564
|
| 33 |
+
Dantist 183202 10990484
|
| 34 |
+
Thanar 179852 12365359
|
| 35 |
+
vdv 175274 9889046
|
| 36 |
+
spams 157128 10319326
|
| 37 |
+
marrco 150295 9402141
|
| 38 |
+
sqrt2 147963 9724586
|
| 39 |
+
mhoram 141278 8901241
|
| 40 |
+
CoffeeOne 137100 5024116
|
| 41 |
+
vdbergh 137041 8926915
|
| 42 |
+
malala 136182 8002293
|
| 43 |
+
xoto 133702 9156676
|
| 44 |
+
davar 122092 7960001
|
| 45 |
+
dsmith 122059 7570238
|
| 46 |
+
Data 113305 8220352
|
| 47 |
+
BrunoBanani 112960 7436849
|
| 48 |
+
MaZePallas 102823 6633619
|
| 49 |
+
sterni1971 100532 5880772
|
| 50 |
+
ElbertoOne 99028 7023771
|
| 51 |
+
brabos 92118 6186135
|
| 52 |
+
oz 92100 6486640
|
| 53 |
+
psk 89957 5984901
|
| 54 |
+
amicic 89156 5392305
|
| 55 |
+
sunu 88851 6028873
|
| 56 |
+
Vizvezdenec 83761 5344740
|
| 57 |
+
0x3C33 82614 5271253
|
| 58 |
+
BRAVONE 81239 5054681
|
| 59 |
+
racerschmacer 80899 5759262
|
| 60 |
+
cuistot 80300 4606144
|
| 61 |
+
nssy 76497 5259388
|
| 62 |
+
teddybaer 75125 5407666
|
| 63 |
+
Pking_cda 73776 5293873
|
| 64 |
+
jromang 72192 5057715
|
| 65 |
+
solarlight 70517 5028306
|
| 66 |
+
dv8silencer 70287 3883992
|
| 67 |
+
Bobo1239 68515 4652287
|
| 68 |
+
manap 66273 4121774
|
| 69 |
+
skiminki 65088 4023328
|
| 70 |
+
tinker 64333 4268790
|
| 71 |
+
sschnee 60767 3500800
|
| 72 |
+
qurashee 57344 3168264
|
| 73 |
+
robnjr 57262 4053117
|
| 74 |
+
Freja 56938 3733019
|
| 75 |
+
ttruscott 56010 3680085
|
| 76 |
+
rkl 55132 4164467
|
| 77 |
+
renouve 53811 3501516
|
| 78 |
+
finfish 51360 3370515
|
| 79 |
+
eva42 51272 3599691
|
| 80 |
+
rap 49985 3219146
|
| 81 |
+
pb00067 49727 3298270
|
| 82 |
+
ronaldjerum 47654 3240695
|
| 83 |
+
bigpen0r 47653 3335327
|
| 84 |
+
eastorwest 47585 3221629
|
| 85 |
+
biffhero 46564 3111352
|
| 86 |
+
VoyagerOne 45476 3452465
|
| 87 |
+
yurikvelo 44834 3034550
|
| 88 |
+
speedycpu 43842 3003273
|
| 89 |
+
jbwiebe 43305 2805433
|
| 90 |
+
Spprtr 42279 2680153
|
| 91 |
+
DesolatedDodo 42007 2447516
|
| 92 |
+
Antihistamine 41788 2761312
|
| 93 |
+
mhunt 41735 2691355
|
| 94 |
+
homyur 39893 2850481
|
| 95 |
+
gri 39871 2515779
|
| 96 |
+
Fifis 38776 2529121
|
| 97 |
+
oryx 38724 2966648
|
| 98 |
+
SC 37290 2731014
|
| 99 |
+
csnodgrass 36207 2688994
|
| 100 |
+
jmdana 36157 2210661
|
| 101 |
+
strelock 34716 2074055
|
| 102 |
+
rpngn 33951 2057395
|
| 103 |
+
Garf 33922 2751802
|
| 104 |
+
EthanOConnor 33370 2090311
|
| 105 |
+
slakovv 32915 2021889
|
| 106 |
+
manapbk 30987 1810399
|
| 107 |
+
Prcuvu 30377 2170122
|
| 108 |
+
anst 30301 2190091
|
| 109 |
+
jkiiski 30136 1904470
|
| 110 |
+
hyperbolic.tom 29840 2017394
|
| 111 |
+
Pyafue 29650 1902349
|
| 112 |
+
Wolfgang 29260 1658936
|
| 113 |
+
zeryl 28156 1579911
|
| 114 |
+
OuaisBla 27636 1578800
|
| 115 |
+
DMBK 27051 1999456
|
| 116 |
+
chriswk 26902 1868317
|
| 117 |
+
achambord 26582 1767323
|
| 118 |
+
Patrick_G 26276 1801617
|
| 119 |
+
yorkman 26193 1992080
|
| 120 |
+
SFTUser 25182 1675689
|
| 121 |
+
nabildanial 24942 1519409
|
| 122 |
+
Sharaf_DG 24765 1786697
|
| 123 |
+
ncfish1 24411 1520927
|
| 124 |
+
rodneyc 24227 1409514
|
| 125 |
+
agg177 23890 1395014
|
| 126 |
+
JanErik 23408 1703875
|
| 127 |
+
Isidor 23388 1680691
|
| 128 |
+
Norabor 23164 1591830
|
| 129 |
+
cisco2015 22897 1762669
|
| 130 |
+
Zirie 22542 1472937
|
| 131 |
+
team-oh 22272 1636708
|
| 132 |
+
MazeOfGalious 21978 1629593
|
| 133 |
+
sg4032 21947 1643265
|
| 134 |
+
ianh2105 21725 1632562
|
| 135 |
+
xor12 21628 1680365
|
| 136 |
+
dex 21612 1467203
|
| 137 |
+
nesoneg 21494 1463031
|
| 138 |
+
sphinx 21211 1384728
|
| 139 |
+
jjoshua2 21001 1423089
|
| 140 |
+
horst.prack 20878 1465656
|
| 141 |
+
Ente 20865 1477066
|
| 142 |
+
0xB00B1ES 20590 1208666
|
| 143 |
+
j3corre 20405 941444
|
| 144 |
+
Adrian.Schmidt123 20316 1281436
|
| 145 |
+
wei 19973 1745989
|
| 146 |
+
MaxKlaxxMiner 19850 1009176
|
| 147 |
+
rstoesser 19569 1293588
|
| 148 |
+
gopeto 19491 1174952
|
| 149 |
+
eudhan 19274 1283717
|
| 150 |
+
jundery 18445 1115855
|
| 151 |
+
megaman7de 18377 1067540
|
| 152 |
+
iisiraider 18247 1101015
|
| 153 |
+
ville 17883 1384026
|
| 154 |
+
chris 17698 1487385
|
| 155 |
+
purplefishies 17595 1092533
|
| 156 |
+
dju 17353 978595
|
| 157 |
+
DragonLord 17014 1162790
|
| 158 |
+
IgorLeMasson 16064 1147232
|
| 159 |
+
ako027ako 15671 1173203
|
| 160 |
+
chuckstablers 15289 891576
|
| 161 |
+
Nikolay.IT 15154 1068349
|
| 162 |
+
Andrew Grant 15114 895539
|
| 163 |
+
OssumOpossum 14857 1007129
|
| 164 |
+
Karby 14808 867120
|
| 165 |
+
enedene 14476 905279
|
| 166 |
+
bpfliegel 14298 884523
|
| 167 |
+
mpx86 14019 759568
|
| 168 |
+
jpulman 13982 870599
|
| 169 |
+
crocogoat 13803 1117422
|
| 170 |
+
joster 13794 950160
|
| 171 |
+
Nesa92 13786 1114691
|
| 172 |
+
Hjax 13535 915487
|
| 173 |
+
jsys14 13459 785000
|
| 174 |
+
Dark_wizzie 13422 1007152
|
| 175 |
+
mabichito 12903 749391
|
| 176 |
+
thijsk 12886 722107
|
| 177 |
+
AdrianSA 12860 804972
|
| 178 |
+
Flopzee 12698 894821
|
| 179 |
+
fatmurphy 12547 853210
|
| 180 |
+
Rudolphous 12520 832340
|
| 181 |
+
scuzzi 12511 845761
|
| 182 |
+
SapphireBrand 12416 969604
|
| 183 |
+
modolief 12386 896470
|
| 184 |
+
Machariel 12335 810784
|
| 185 |
+
pgontarz 12151 848794
|
| 186 |
+
stocky 11954 699440
|
| 187 |
+
mschmidt 11941 803401
|
| 188 |
+
Maxim 11543 836024
|
| 189 |
+
infinity 11470 727027
|
| 190 |
+
torbjo 11395 729145
|
| 191 |
+
Thomas A. Anderson 11372 732094
|
| 192 |
+
savage84 11358 670860
|
| 193 |
+
d64 11263 789184
|
| 194 |
+
MooTheCow 11237 720174
|
| 195 |
+
snicolet 11106 869170
|
| 196 |
+
ali-al-zhrani 11086 767926
|
| 197 |
+
AndreasKrug 10875 887457
|
| 198 |
+
pirt 10806 836519
|
| 199 |
+
basepi 10637 744851
|
| 200 |
+
michaelrpg 10508 739039
|
| 201 |
+
dzjp 10343 732529
|
| 202 |
+
aga 10302 622975
|
| 203 |
+
ols 10259 570669
|
| 204 |
+
lbraesch 10252 647825
|
| 205 |
+
FormazChar 10059 757283
|
Fairy-Stockfish-master/appveyor.yml
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: 1.0.{build}
|
| 2 |
+
clone_depth: 50
|
| 3 |
+
|
| 4 |
+
branches:
|
| 5 |
+
only:
|
| 6 |
+
- master
|
| 7 |
+
- merge
|
| 8 |
+
- appveyor
|
| 9 |
+
|
| 10 |
+
# Operating system (build VM template)
|
| 11 |
+
os: Visual Studio 2019
|
| 12 |
+
|
| 13 |
+
# Build platform, i.e. x86, x64, AnyCPU. This setting is optional.
|
| 14 |
+
platform:
|
| 15 |
+
- x86
|
| 16 |
+
- x64
|
| 17 |
+
|
| 18 |
+
# build Configuration, i.e. Debug, Release, etc.
|
| 19 |
+
configuration:
|
| 20 |
+
- Debug
|
| 21 |
+
- Release
|
| 22 |
+
|
| 23 |
+
matrix:
|
| 24 |
+
# The build fail immediately once one of the job fails
|
| 25 |
+
fast_finish: true
|
| 26 |
+
|
| 27 |
+
# Scripts that are called at very beginning, before repo cloning
|
| 28 |
+
init:
|
| 29 |
+
- cmake --version
|
| 30 |
+
- msbuild /version
|
| 31 |
+
|
| 32 |
+
before_build:
|
| 33 |
+
- ps: |
|
| 34 |
+
# Get sources
|
| 35 |
+
$src = get-childitem -Path *.cpp -Recurse -Exclude pyffish.cpp,ffishjs.cpp | select -ExpandProperty FullName
|
| 36 |
+
$src = $src -join ' '
|
| 37 |
+
$src = $src.Replace("\", "/")
|
| 38 |
+
|
| 39 |
+
# Build CMakeLists.txt
|
| 40 |
+
$t = 'cmake_minimum_required(VERSION 3.17)',
|
| 41 |
+
'project(Stockfish)',
|
| 42 |
+
'set(CMAKE_CXX_STANDARD 17)',
|
| 43 |
+
'set(CMAKE_CXX_STANDARD_REQUIRED ON)',
|
| 44 |
+
'set (CMAKE_CXX_EXTENSIONS OFF)',
|
| 45 |
+
'set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src)',
|
| 46 |
+
'set(source_files', $src, ')',
|
| 47 |
+
'add_compile_definitions(NNUE_EMBEDDING_OFF)',
|
| 48 |
+
'add_executable(stockfish ${source_files})'
|
| 49 |
+
|
| 50 |
+
# Write CMakeLists.txt without BOM
|
| 51 |
+
$MyPath = (Get-Item -Path "." -Verbose).FullName + '\CMakeLists.txt'
|
| 52 |
+
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
|
| 53 |
+
[System.IO.File]::WriteAllLines($MyPath, $t, $Utf8NoBomEncoding)
|
| 54 |
+
|
| 55 |
+
# Obtain bench reference from git log
|
| 56 |
+
$b = git log HEAD | sls "\b[Bb]ench[ :]+[0-9]{7}" | select -first 1
|
| 57 |
+
$bench = $b -match '\D+(\d+)' | % { $matches[1] }
|
| 58 |
+
Write-Host "Reference bench:" $bench
|
| 59 |
+
$g = "Visual Studio 16 2019"
|
| 60 |
+
If (${env:PLATFORM} -eq 'x64') { $a = "x64" }
|
| 61 |
+
If (${env:PLATFORM} -eq 'x86') { $a = "Win32" }
|
| 62 |
+
cmake -G "${g}" -A ${a} .
|
| 63 |
+
Write-Host "Generated files for: " $g $a
|
| 64 |
+
|
| 65 |
+
build_script:
|
| 66 |
+
- cmake --build . --config %CONFIGURATION% -- /verbosity:minimal
|
| 67 |
+
- ps: |
|
| 68 |
+
# Download default NNUE net from fishtest
|
| 69 |
+
$nnuenet = Get-Content -Path src\evaluate.h | Select-String -CaseSensitive -Pattern "EvalFileDefaultName" | Select-String -CaseSensitive -Pattern "nn-[a-z0-9]{12}.nnue"
|
| 70 |
+
$dummy = $nnuenet -match "(?<nnuenet>nn-[a-z0-9]{12}.nnue)"
|
| 71 |
+
$nnuenet = $Matches.nnuenet
|
| 72 |
+
Write-Host "Default net:" $nnuenet
|
| 73 |
+
$nnuedownloadurl = "https://github.com/official-stockfish/networks/raw/master/$nnuenet"
|
| 74 |
+
$nnuefilepath = "src\${env:CONFIGURATION}\$nnuenet"
|
| 75 |
+
if (Test-Path -Path $nnuefilepath) {
|
| 76 |
+
Write-Host "Already available."
|
| 77 |
+
} else {
|
| 78 |
+
Write-Host "Downloading $nnuedownloadurl to $nnuefilepath"
|
| 79 |
+
Invoke-WebRequest -Uri $nnuedownloadurl -OutFile $nnuefilepath
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
before_test:
|
| 83 |
+
- cd src/%CONFIGURATION%
|
| 84 |
+
- stockfish bench 2> out.txt >NUL
|
| 85 |
+
- ps: |
|
| 86 |
+
# Verify bench number
|
| 87 |
+
$s = (gc "./out.txt" | out-string)
|
| 88 |
+
$r = ($s -match 'Nodes searched \D+(\d+)' | % { $matches[1] })
|
| 89 |
+
Write-Host "Engine bench:" $r
|
| 90 |
+
Write-Host "Reference bench:" $bench
|
| 91 |
+
If ($r -ne $bench) { exit 1 }
|
Fairy-Stockfish-master/pyffish.pyi
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any
|
| 2 |
+
|
| 3 |
+
FEN_OK: int
|
| 4 |
+
NOTATION_DEFAULT: int
|
| 5 |
+
NOTATION_JANGGI: int
|
| 6 |
+
NOTATION_LAN: int
|
| 7 |
+
NOTATION_SAN: int
|
| 8 |
+
NOTATION_SHOGI_HODGES: int
|
| 9 |
+
NOTATION_SHOGI_HODGES_NUMBER: int
|
| 10 |
+
NOTATION_SHOGI_HOSKING: int
|
| 11 |
+
NOTATION_THAI_LAN: int
|
| 12 |
+
NOTATION_THAI_SAN: int
|
| 13 |
+
NOTATION_XIANGQI_WXF: int
|
| 14 |
+
VALUE_DRAW: int
|
| 15 |
+
VALUE_MATE: int
|
| 16 |
+
|
| 17 |
+
class error(Exception): ...
|
| 18 |
+
|
| 19 |
+
def version() -> tuple[int, int, int]: ...
|
| 20 |
+
def info() -> str: ...
|
| 21 |
+
def variants() -> list[str]: ...
|
| 22 |
+
def set_option(name: str, value: Any) -> None: ...
|
| 23 |
+
def load_variant_config(config: str) -> None: ...
|
| 24 |
+
def start_fen(variant: str) -> str: ...
|
| 25 |
+
def two_boards(variant: str) -> bool: ...
|
| 26 |
+
def captures_to_hand(variant: str) -> bool: ...
|
| 27 |
+
def get_san(variant: str, fen: str, move: str, chess960: bool = False, notation: int = NOTATION_DEFAULT) -> str: ...
|
| 28 |
+
def get_san_moves(variant: str, fen: str, movelist: list[str], chess960: bool = False, notation: int = NOTATION_DEFAULT) -> list[str]: ...
|
| 29 |
+
def legal_moves(variant: str, fen: str, movelist: list[str], chess960: bool = False) -> list[str]: ...
|
| 30 |
+
def get_fen(variant: str, fen: str, movelist: list[str], chess960: bool = False, sfen: bool = False, show_promoted: bool = False, count_started: int = 0) -> str: ...
|
| 31 |
+
def gives_check(variant: str, fen: str, movelist: list[str], chess960: bool = False) -> bool: ...
|
| 32 |
+
def is_capture(variant: str, fen: str, movelist: list[str], move: str, chess960: bool = False) -> bool: ...
|
| 33 |
+
def piece_to_partner(variant: str, fen: str, movelist: list[str], chess960: bool = False) -> str: ...
|
| 34 |
+
def game_result(variant: str, fen: str, movelist: list[str], chess960: bool = False) -> int: ...
|
| 35 |
+
def is_immediate_game_end(variant: str, fen: str, movelist: list[str], chess960: bool = False) -> tuple[bool, int]: ...
|
| 36 |
+
def is_optional_game_end(variant: str, fen: str, movelist: list[str], chess960: bool = False, count_started: int = 0) -> tuple[bool, int]: ...
|
| 37 |
+
def has_insufficient_material(variant: str, fen: str, movelist: list[str], chess960: bool = False) -> tuple[bool, bool]: ...
|
| 38 |
+
def validate_fen(fen: str, variant: str, chess960: bool = False) -> int: ...
|
| 39 |
+
def get_fog_fen(fen: str, variant: str, chess960: bool = False) -> str: ...
|
Fairy-Stockfish-master/setup.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
|
| 3 |
+
from setuptools import setup, Extension
|
| 4 |
+
from glob import glob
|
| 5 |
+
import platform
|
| 6 |
+
import io
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
if platform.python_compiler().startswith("MSC"):
|
| 11 |
+
args = ["/std:c++17"]
|
| 12 |
+
else:
|
| 13 |
+
args = ["-std=c++17", "-flto", "-Wno-date-time"]
|
| 14 |
+
|
| 15 |
+
args.extend(["-DLARGEBOARDS", "-DALLVARS", "-DPRECOMPUTED_MAGICS", "-DNNUE_EMBEDDING_OFF"])
|
| 16 |
+
|
| 17 |
+
if "64bit" in platform.architecture():
|
| 18 |
+
args.append("-DIS_64BIT")
|
| 19 |
+
|
| 20 |
+
CLASSIFIERS = [
|
| 21 |
+
"Development Status :: 3 - Alpha",
|
| 22 |
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
| 23 |
+
"Programming Language :: Python :: 3",
|
| 24 |
+
"Operating System :: OS Independent",
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
with io.open("README.md", "r", encoding="utf8") as fh:
|
| 28 |
+
long_description = fh.read().strip()
|
| 29 |
+
|
| 30 |
+
sources = glob("src/*.cpp") + glob("src/syzygy/*.cpp") + glob("src/nnue/*.cpp") + glob("src/nnue/features/*.cpp")
|
| 31 |
+
headers = glob("src/*.h") + glob("src/syzygy/*.h") + glob("src/nnue/*.h") + glob("src/nnue/features/*.h")
|
| 32 |
+
ffish_source_file = os.path.normcase("src/ffishjs.cpp")
|
| 33 |
+
try:
|
| 34 |
+
sources.remove(ffish_source_file)
|
| 35 |
+
except ValueError:
|
| 36 |
+
print(f"ffish_source_file {ffish_source_file} was not found in sources {sources}.")
|
| 37 |
+
|
| 38 |
+
pyffish_module = Extension(
|
| 39 |
+
"pyffish",
|
| 40 |
+
sources=sources,
|
| 41 |
+
depends=headers,
|
| 42 |
+
extra_compile_args=args)
|
| 43 |
+
|
| 44 |
+
setup(name="pyffish", version="0.0.89",
|
| 45 |
+
description="Fairy-Stockfish Python wrapper",
|
| 46 |
+
long_description=long_description,
|
| 47 |
+
long_description_content_type="text/markdown",
|
| 48 |
+
author="Bajusz Tamás",
|
| 49 |
+
author_email="gbtami@gmail.com",
|
| 50 |
+
license="GPL3",
|
| 51 |
+
classifiers=CLASSIFIERS,
|
| 52 |
+
url="https://github.com/gbtami/Fairy-Stockfish",
|
| 53 |
+
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*",
|
| 54 |
+
ext_modules=[pyffish_module],
|
| 55 |
+
data_files=[("", ["pyffish.pyi"])]
|
| 56 |
+
)
|
Fairy-Stockfish-master/src/Makefile
ADDED
|
@@ -0,0 +1,982 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 2 |
+
# Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 3 |
+
#
|
| 4 |
+
# Stockfish is free software: you can redistribute it and/or modify
|
| 5 |
+
# it under the terms of the GNU General Public License as published by
|
| 6 |
+
# the Free Software Foundation, either version 3 of the License, or
|
| 7 |
+
# (at your option) any later version.
|
| 8 |
+
#
|
| 9 |
+
# Stockfish is distributed in the hope that it will be useful,
|
| 10 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 12 |
+
# GNU General Public License for more details.
|
| 13 |
+
#
|
| 14 |
+
# You should have received a copy of the GNU General Public License
|
| 15 |
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
### ==========================================================================
|
| 19 |
+
### Section 1. General Configuration
|
| 20 |
+
### ==========================================================================
|
| 21 |
+
|
| 22 |
+
### Executable name
|
| 23 |
+
ifeq ($(COMP),mingw)
|
| 24 |
+
EXE = stockfish.exe
|
| 25 |
+
else
|
| 26 |
+
EXE = stockfish
|
| 27 |
+
endif
|
| 28 |
+
|
| 29 |
+
### Installation dir definitions
|
| 30 |
+
PREFIX = /usr/local
|
| 31 |
+
BINDIR = $(PREFIX)/bin
|
| 32 |
+
|
| 33 |
+
### Built-in benchmark for pgo-builds
|
| 34 |
+
ifeq ($(SDE_PATH),)
|
| 35 |
+
PGOBENCH = ./$(EXE) bench
|
| 36 |
+
else
|
| 37 |
+
PGOBENCH = $(SDE_PATH) -- ./$(EXE) bench
|
| 38 |
+
endif
|
| 39 |
+
|
| 40 |
+
### Source and object files
|
| 41 |
+
SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \
|
| 42 |
+
material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \
|
| 43 |
+
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
|
| 44 |
+
nnue/evaluate_nnue.cpp nnue/features/half_ka_v2.cpp \
|
| 45 |
+
partner.cpp parser.cpp piece.cpp variant.cpp xboard.cpp \
|
| 46 |
+
nnue/features/half_ka_v2_variants.cpp
|
| 47 |
+
|
| 48 |
+
OBJS = $(notdir $(SRCS:.cpp=.o))
|
| 49 |
+
|
| 50 |
+
VPATH = syzygy:nnue:nnue/features
|
| 51 |
+
|
| 52 |
+
### Establish the operating system name
|
| 53 |
+
KERNEL = $(shell uname -s)
|
| 54 |
+
ifeq ($(KERNEL),Linux)
|
| 55 |
+
OS = $(shell uname -o)
|
| 56 |
+
endif
|
| 57 |
+
|
| 58 |
+
### ==========================================================================
|
| 59 |
+
### Section 2. High-level Configuration
|
| 60 |
+
### ==========================================================================
|
| 61 |
+
#
|
| 62 |
+
# flag --- Comp switch --- Description
|
| 63 |
+
# ----------------------------------------------------------------------------
|
| 64 |
+
#
|
| 65 |
+
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
|
| 66 |
+
# sanitize = none/<sanitizer> ... (-fsanitize )
|
| 67 |
+
# --- ( undefined ) --- enable undefined behavior checks
|
| 68 |
+
# --- ( thread ) --- enable threading error checks
|
| 69 |
+
# --- ( address ) --- enable memory access checks
|
| 70 |
+
# --- ...etc... --- see compiler documentation for supported sanitizers
|
| 71 |
+
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
|
| 72 |
+
# arch = (name) --- (-arch) --- Target architecture
|
| 73 |
+
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
|
| 74 |
+
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction
|
| 75 |
+
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction
|
| 76 |
+
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
|
| 77 |
+
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
|
| 78 |
+
# mmx = yes/no --- -mmmx --- Use Intel MMX instructions
|
| 79 |
+
# sse2 = yes/no --- -msse2 --- Use Intel Streaming SIMD Extensions 2
|
| 80 |
+
# ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3
|
| 81 |
+
# sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1
|
| 82 |
+
# avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2
|
| 83 |
+
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
|
| 84 |
+
# vnni256 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 256
|
| 85 |
+
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
|
| 86 |
+
# neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture
|
| 87 |
+
#
|
| 88 |
+
# Note that Makefile is space sensitive, so when adding new architectures
|
| 89 |
+
# or modifying existing flags, you have to make sure there are no extra spaces
|
| 90 |
+
# at the end of the line for flag values.
|
| 91 |
+
#
|
| 92 |
+
# Example of use for these flags:
|
| 93 |
+
# make build ARCH=x86-64-avx512 debug=on sanitize="address undefined"
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
### 2.1. General and architecture defaults
|
| 97 |
+
largeboards = no
|
| 98 |
+
all = no
|
| 99 |
+
precomputedmagics = yes
|
| 100 |
+
nnue = no
|
| 101 |
+
load_net = $(if $(filter $(nnue),yes),net)
|
| 102 |
+
|
| 103 |
+
ifeq ($(ARCH),)
|
| 104 |
+
ARCH = x86-64-modern
|
| 105 |
+
help_skip_sanity = yes
|
| 106 |
+
endif
|
| 107 |
+
# explicitly check for the list of supported architectures (as listed with make help),
|
| 108 |
+
# the user can override with `make ARCH=x86-32-vnni256 SUPPORTED_ARCH=true`
|
| 109 |
+
ifeq ($(ARCH), $(filter $(ARCH), \
|
| 110 |
+
x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-bmi2 x86-64-avx2 \
|
| 111 |
+
x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
|
| 112 |
+
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \
|
| 113 |
+
armv7 armv7-neon armv8 apple-silicon general-64 general-32))
|
| 114 |
+
SUPPORTED_ARCH=true
|
| 115 |
+
else
|
| 116 |
+
SUPPORTED_ARCH=false
|
| 117 |
+
endif
|
| 118 |
+
|
| 119 |
+
optimize = yes
|
| 120 |
+
debug = no
|
| 121 |
+
sanitize = none
|
| 122 |
+
bits = 64
|
| 123 |
+
prefetch = no
|
| 124 |
+
popcnt = no
|
| 125 |
+
pext = no
|
| 126 |
+
sse = no
|
| 127 |
+
mmx = no
|
| 128 |
+
sse2 = no
|
| 129 |
+
ssse3 = no
|
| 130 |
+
sse41 = no
|
| 131 |
+
avx2 = no
|
| 132 |
+
avx512 = no
|
| 133 |
+
vnni256 = no
|
| 134 |
+
vnni512 = no
|
| 135 |
+
neon = no
|
| 136 |
+
STRIP = strip
|
| 137 |
+
|
| 138 |
+
### 2.2 Architecture specific
|
| 139 |
+
|
| 140 |
+
ifeq ($(findstring x86,$(ARCH)),x86)
|
| 141 |
+
|
| 142 |
+
# x86-32/64
|
| 143 |
+
|
| 144 |
+
ifeq ($(findstring x86-32,$(ARCH)),x86-32)
|
| 145 |
+
arch = i386
|
| 146 |
+
bits = 32
|
| 147 |
+
sse = yes
|
| 148 |
+
mmx = yes
|
| 149 |
+
else
|
| 150 |
+
arch = x86_64
|
| 151 |
+
sse = yes
|
| 152 |
+
sse2 = yes
|
| 153 |
+
endif
|
| 154 |
+
|
| 155 |
+
ifeq ($(findstring -sse,$(ARCH)),-sse)
|
| 156 |
+
sse = yes
|
| 157 |
+
endif
|
| 158 |
+
|
| 159 |
+
ifeq ($(findstring -popcnt,$(ARCH)),-popcnt)
|
| 160 |
+
popcnt = yes
|
| 161 |
+
endif
|
| 162 |
+
|
| 163 |
+
ifeq ($(findstring -mmx,$(ARCH)),-mmx)
|
| 164 |
+
mmx = yes
|
| 165 |
+
endif
|
| 166 |
+
|
| 167 |
+
ifeq ($(findstring -sse2,$(ARCH)),-sse2)
|
| 168 |
+
sse = yes
|
| 169 |
+
sse2 = yes
|
| 170 |
+
endif
|
| 171 |
+
|
| 172 |
+
ifeq ($(findstring -ssse3,$(ARCH)),-ssse3)
|
| 173 |
+
sse = yes
|
| 174 |
+
sse2 = yes
|
| 175 |
+
ssse3 = yes
|
| 176 |
+
endif
|
| 177 |
+
|
| 178 |
+
ifeq ($(findstring -sse41,$(ARCH)),-sse41)
|
| 179 |
+
sse = yes
|
| 180 |
+
sse2 = yes
|
| 181 |
+
ssse3 = yes
|
| 182 |
+
sse41 = yes
|
| 183 |
+
endif
|
| 184 |
+
|
| 185 |
+
ifeq ($(findstring -modern,$(ARCH)),-modern)
|
| 186 |
+
popcnt = yes
|
| 187 |
+
sse = yes
|
| 188 |
+
sse2 = yes
|
| 189 |
+
ssse3 = yes
|
| 190 |
+
sse41 = yes
|
| 191 |
+
endif
|
| 192 |
+
|
| 193 |
+
ifeq ($(findstring -avx2,$(ARCH)),-avx2)
|
| 194 |
+
popcnt = yes
|
| 195 |
+
sse = yes
|
| 196 |
+
sse2 = yes
|
| 197 |
+
ssse3 = yes
|
| 198 |
+
sse41 = yes
|
| 199 |
+
avx2 = yes
|
| 200 |
+
endif
|
| 201 |
+
|
| 202 |
+
ifeq ($(findstring -bmi2,$(ARCH)),-bmi2)
|
| 203 |
+
popcnt = yes
|
| 204 |
+
sse = yes
|
| 205 |
+
sse2 = yes
|
| 206 |
+
ssse3 = yes
|
| 207 |
+
sse41 = yes
|
| 208 |
+
avx2 = yes
|
| 209 |
+
pext = yes
|
| 210 |
+
endif
|
| 211 |
+
|
| 212 |
+
ifeq ($(findstring -avx512,$(ARCH)),-avx512)
|
| 213 |
+
popcnt = yes
|
| 214 |
+
sse = yes
|
| 215 |
+
sse2 = yes
|
| 216 |
+
ssse3 = yes
|
| 217 |
+
sse41 = yes
|
| 218 |
+
avx2 = yes
|
| 219 |
+
pext = yes
|
| 220 |
+
avx512 = yes
|
| 221 |
+
endif
|
| 222 |
+
|
| 223 |
+
ifeq ($(findstring -vnni256,$(ARCH)),-vnni256)
|
| 224 |
+
popcnt = yes
|
| 225 |
+
sse = yes
|
| 226 |
+
sse2 = yes
|
| 227 |
+
ssse3 = yes
|
| 228 |
+
sse41 = yes
|
| 229 |
+
avx2 = yes
|
| 230 |
+
pext = yes
|
| 231 |
+
vnni256 = yes
|
| 232 |
+
endif
|
| 233 |
+
|
| 234 |
+
ifeq ($(findstring -vnni512,$(ARCH)),-vnni512)
|
| 235 |
+
popcnt = yes
|
| 236 |
+
sse = yes
|
| 237 |
+
sse2 = yes
|
| 238 |
+
ssse3 = yes
|
| 239 |
+
sse41 = yes
|
| 240 |
+
avx2 = yes
|
| 241 |
+
pext = yes
|
| 242 |
+
avx512 = yes
|
| 243 |
+
vnni512 = yes
|
| 244 |
+
endif
|
| 245 |
+
|
| 246 |
+
ifeq ($(sse),yes)
|
| 247 |
+
prefetch = yes
|
| 248 |
+
endif
|
| 249 |
+
|
| 250 |
+
# 64-bit pext is not available on x86-32
|
| 251 |
+
ifeq ($(bits),32)
|
| 252 |
+
pext = no
|
| 253 |
+
endif
|
| 254 |
+
|
| 255 |
+
else
|
| 256 |
+
|
| 257 |
+
# all other architectures
|
| 258 |
+
|
| 259 |
+
ifeq ($(ARCH),general-32)
|
| 260 |
+
arch = any
|
| 261 |
+
bits = 32
|
| 262 |
+
endif
|
| 263 |
+
|
| 264 |
+
ifeq ($(ARCH),general-64)
|
| 265 |
+
arch = any
|
| 266 |
+
endif
|
| 267 |
+
|
| 268 |
+
ifeq ($(ARCH),armv7)
|
| 269 |
+
arch = armv7
|
| 270 |
+
prefetch = yes
|
| 271 |
+
bits = 32
|
| 272 |
+
endif
|
| 273 |
+
|
| 274 |
+
ifeq ($(ARCH),armv7-neon)
|
| 275 |
+
arch = armv7
|
| 276 |
+
prefetch = yes
|
| 277 |
+
popcnt = yes
|
| 278 |
+
neon = yes
|
| 279 |
+
bits = 32
|
| 280 |
+
endif
|
| 281 |
+
|
| 282 |
+
ifeq ($(ARCH),armv8)
|
| 283 |
+
arch = armv8
|
| 284 |
+
prefetch = yes
|
| 285 |
+
popcnt = yes
|
| 286 |
+
neon = yes
|
| 287 |
+
endif
|
| 288 |
+
|
| 289 |
+
ifeq ($(ARCH),apple-silicon)
|
| 290 |
+
arch = arm64
|
| 291 |
+
prefetch = yes
|
| 292 |
+
popcnt = yes
|
| 293 |
+
neon = yes
|
| 294 |
+
endif
|
| 295 |
+
|
| 296 |
+
ifeq ($(ARCH),ppc-32)
|
| 297 |
+
arch = ppc
|
| 298 |
+
bits = 32
|
| 299 |
+
endif
|
| 300 |
+
|
| 301 |
+
ifeq ($(ARCH),ppc-64)
|
| 302 |
+
arch = ppc64
|
| 303 |
+
popcnt = yes
|
| 304 |
+
prefetch = yes
|
| 305 |
+
endif
|
| 306 |
+
|
| 307 |
+
ifeq ($(findstring e2k,$(ARCH)),e2k)
|
| 308 |
+
arch = e2k
|
| 309 |
+
mmx = yes
|
| 310 |
+
bits = 64
|
| 311 |
+
sse = yes
|
| 312 |
+
sse2 = yes
|
| 313 |
+
ssse3 = yes
|
| 314 |
+
sse41 = yes
|
| 315 |
+
popcnt = yes
|
| 316 |
+
endif
|
| 317 |
+
|
| 318 |
+
endif
|
| 319 |
+
|
| 320 |
+
# Disable precomputed magics when 64-bit PEXT is available
|
| 321 |
+
ifeq ($(pext),yes)
|
| 322 |
+
precomputedmagics = no
|
| 323 |
+
endif
|
| 324 |
+
|
| 325 |
+
### ==========================================================================
|
| 326 |
+
### Section 3. Low-level Configuration
|
| 327 |
+
### ==========================================================================
|
| 328 |
+
|
| 329 |
+
### 3.1 Selecting compiler (default = gcc)
|
| 330 |
+
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS)
|
| 331 |
+
DEPENDFLAGS += -std=c++17
|
| 332 |
+
LDFLAGS += $(EXTRALDFLAGS)
|
| 333 |
+
|
| 334 |
+
# Ignore warning due to missing profile information from unused NNUE features
|
| 335 |
+
CXXFLAGS += -Wno-profile-instr-out-of-date
|
| 336 |
+
|
| 337 |
+
# Compile version with support for large board variants
|
| 338 |
+
# Use precomputed magics by default if pext is not available
|
| 339 |
+
ifneq ($(largeboards),no)
|
| 340 |
+
CXXFLAGS += -DLARGEBOARDS
|
| 341 |
+
ifeq ($(precomputedmagics),yes)
|
| 342 |
+
CXXFLAGS += -DPRECOMPUTED_MAGICS
|
| 343 |
+
endif
|
| 344 |
+
endif
|
| 345 |
+
|
| 346 |
+
# Embed and enable NNUE
|
| 347 |
+
ifeq ($(nnue),no)
|
| 348 |
+
CXXFLAGS += -DNNUE_EMBEDDING_OFF
|
| 349 |
+
endif
|
| 350 |
+
|
| 351 |
+
# Enable all variants, even heavyweight ones like duck and amazons
|
| 352 |
+
ifneq ($(all),no)
|
| 353 |
+
CXXFLAGS += -DALLVARS
|
| 354 |
+
endif
|
| 355 |
+
|
| 356 |
+
ifeq ($(COMP),)
|
| 357 |
+
COMP=gcc
|
| 358 |
+
endif
|
| 359 |
+
|
| 360 |
+
ifeq ($(COMP),gcc)
|
| 361 |
+
comp=gcc
|
| 362 |
+
CXX=g++
|
| 363 |
+
CXXFLAGS += -Wextra -Wshadow
|
| 364 |
+
ifeq ($(largeboards),no)
|
| 365 |
+
CXXFLAGS += -pedantic
|
| 366 |
+
endif
|
| 367 |
+
|
| 368 |
+
ifeq ($(arch),$(filter $(arch),armv7 armv8))
|
| 369 |
+
ifeq ($(OS),Android)
|
| 370 |
+
CXXFLAGS += -m$(bits)
|
| 371 |
+
LDFLAGS += -m$(bits)
|
| 372 |
+
endif
|
| 373 |
+
else
|
| 374 |
+
CXXFLAGS += -m$(bits)
|
| 375 |
+
LDFLAGS += -m$(bits)
|
| 376 |
+
endif
|
| 377 |
+
|
| 378 |
+
ifeq ($(arch),$(filter $(arch),armv7))
|
| 379 |
+
LDFLAGS += -latomic
|
| 380 |
+
endif
|
| 381 |
+
|
| 382 |
+
ifneq ($(KERNEL),Darwin)
|
| 383 |
+
LDFLAGS += -Wl,--no-as-needed
|
| 384 |
+
endif
|
| 385 |
+
endif
|
| 386 |
+
|
| 387 |
+
ifeq ($(COMP),mingw)
|
| 388 |
+
comp=mingw
|
| 389 |
+
|
| 390 |
+
ifeq ($(KERNEL),Linux)
|
| 391 |
+
ifeq ($(bits),64)
|
| 392 |
+
ifeq ($(shell which x86_64-w64-mingw32-c++-posix),)
|
| 393 |
+
CXX=x86_64-w64-mingw32-c++
|
| 394 |
+
else
|
| 395 |
+
CXX=x86_64-w64-mingw32-c++-posix
|
| 396 |
+
endif
|
| 397 |
+
else
|
| 398 |
+
ifeq ($(shell which i686-w64-mingw32-c++-posix),)
|
| 399 |
+
CXX=i686-w64-mingw32-c++
|
| 400 |
+
else
|
| 401 |
+
CXX=i686-w64-mingw32-c++-posix
|
| 402 |
+
endif
|
| 403 |
+
endif
|
| 404 |
+
else
|
| 405 |
+
CXX=g++
|
| 406 |
+
endif
|
| 407 |
+
|
| 408 |
+
CXXFLAGS += -Wextra -Wshadow
|
| 409 |
+
LDFLAGS += -static
|
| 410 |
+
endif
|
| 411 |
+
|
| 412 |
+
ifeq ($(COMP),icc)
|
| 413 |
+
comp=icc
|
| 414 |
+
CXX=icpc
|
| 415 |
+
CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi
|
| 416 |
+
endif
|
| 417 |
+
|
| 418 |
+
ifeq ($(COMP),clang)
|
| 419 |
+
comp=clang
|
| 420 |
+
CXX=clang++
|
| 421 |
+
CXXFLAGS += -pedantic -Wextra -Wshadow
|
| 422 |
+
|
| 423 |
+
ifneq ($(KERNEL),Darwin)
|
| 424 |
+
ifneq ($(KERNEL),OpenBSD)
|
| 425 |
+
ifneq ($(KERNEL),FreeBSD)
|
| 426 |
+
LDFLAGS += -latomic
|
| 427 |
+
endif
|
| 428 |
+
endif
|
| 429 |
+
endif
|
| 430 |
+
|
| 431 |
+
ifeq ($(arch),$(filter $(arch),armv7 armv8))
|
| 432 |
+
ifeq ($(OS),Android)
|
| 433 |
+
CXXFLAGS += -m$(bits)
|
| 434 |
+
LDFLAGS += -m$(bits)
|
| 435 |
+
endif
|
| 436 |
+
else
|
| 437 |
+
CXXFLAGS += -m$(bits)
|
| 438 |
+
LDFLAGS += -m$(bits)
|
| 439 |
+
endif
|
| 440 |
+
endif
|
| 441 |
+
|
| 442 |
+
ifeq ($(KERNEL),Darwin)
|
| 443 |
+
CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.14
|
| 444 |
+
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.14
|
| 445 |
+
XCRUN = xcrun
|
| 446 |
+
endif
|
| 447 |
+
|
| 448 |
+
# To cross-compile for Android, NDK version r21 or later is recommended.
|
| 449 |
+
# In earlier NDK versions, you'll need to pass -fno-addrsig if using GNU binutils.
|
| 450 |
+
# Currently we don't know how to make PGO builds with the NDK yet.
|
| 451 |
+
ifeq ($(COMP),ndk)
|
| 452 |
+
CXXFLAGS += -stdlib=libc++ -fPIE
|
| 453 |
+
comp=clang
|
| 454 |
+
ifeq ($(arch),armv7)
|
| 455 |
+
CXX=armv7a-linux-androideabi16-clang++
|
| 456 |
+
CXXFLAGS += -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=neon
|
| 457 |
+
STRIP=arm-linux-androideabi-strip
|
| 458 |
+
endif
|
| 459 |
+
ifeq ($(arch),armv8)
|
| 460 |
+
CXX=aarch64-linux-android21-clang++
|
| 461 |
+
STRIP=aarch64-linux-android-strip
|
| 462 |
+
endif
|
| 463 |
+
LDFLAGS += -static-libstdc++ -pie -lm -latomic
|
| 464 |
+
endif
|
| 465 |
+
|
| 466 |
+
ifeq ($(comp),icc)
|
| 467 |
+
profile_make = icc-profile-make
|
| 468 |
+
profile_use = icc-profile-use
|
| 469 |
+
else ifeq ($(comp),clang)
|
| 470 |
+
profile_make = clang-profile-make
|
| 471 |
+
profile_use = clang-profile-use
|
| 472 |
+
else
|
| 473 |
+
profile_make = gcc-profile-make
|
| 474 |
+
profile_use = gcc-profile-use
|
| 475 |
+
endif
|
| 476 |
+
|
| 477 |
+
### Travis CI script uses COMPILER to overwrite CXX
|
| 478 |
+
ifdef COMPILER
|
| 479 |
+
COMPCXX=$(COMPILER)
|
| 480 |
+
endif
|
| 481 |
+
|
| 482 |
+
### Allow overwriting CXX from command line
|
| 483 |
+
ifdef COMPCXX
|
| 484 |
+
CXX=$(COMPCXX)
|
| 485 |
+
endif
|
| 486 |
+
|
| 487 |
+
### Sometimes gcc is really clang
|
| 488 |
+
ifeq ($(COMP),gcc)
|
| 489 |
+
gccversion = $(shell $(CXX) --version)
|
| 490 |
+
gccisclang = $(findstring clang,$(gccversion))
|
| 491 |
+
ifneq ($(gccisclang),)
|
| 492 |
+
profile_make = clang-profile-make
|
| 493 |
+
profile_use = clang-profile-use
|
| 494 |
+
endif
|
| 495 |
+
endif
|
| 496 |
+
|
| 497 |
+
### On mingw use Windows threads, otherwise POSIX
|
| 498 |
+
ifneq ($(comp),mingw)
|
| 499 |
+
CXXFLAGS += -DUSE_PTHREADS
|
| 500 |
+
# On Android Bionic's C library comes with its own pthread implementation bundled in
|
| 501 |
+
ifneq ($(OS),Android)
|
| 502 |
+
# Haiku has pthreads in its libroot, so only link it in on other platforms
|
| 503 |
+
ifneq ($(KERNEL),Haiku)
|
| 504 |
+
ifneq ($(COMP),ndk)
|
| 505 |
+
LDFLAGS += -lpthread
|
| 506 |
+
endif
|
| 507 |
+
endif
|
| 508 |
+
endif
|
| 509 |
+
endif
|
| 510 |
+
|
| 511 |
+
### 3.2.1 Debugging
|
| 512 |
+
ifeq ($(debug),no)
|
| 513 |
+
CXXFLAGS += -DNDEBUG
|
| 514 |
+
else
|
| 515 |
+
CXXFLAGS += -g
|
| 516 |
+
endif
|
| 517 |
+
|
| 518 |
+
### 3.2.2 Debugging with undefined behavior sanitizers
|
| 519 |
+
ifneq ($(sanitize),none)
|
| 520 |
+
CXXFLAGS += -g3 $(addprefix -fsanitize=,$(sanitize))
|
| 521 |
+
LDFLAGS += $(addprefix -fsanitize=,$(sanitize))
|
| 522 |
+
endif
|
| 523 |
+
|
| 524 |
+
### 3.3 Optimization
|
| 525 |
+
ifeq ($(optimize),yes)
|
| 526 |
+
|
| 527 |
+
CXXFLAGS += -O3 -fno-strict-aliasing
|
| 528 |
+
|
| 529 |
+
ifeq ($(comp),gcc)
|
| 530 |
+
ifeq ($(OS), Android)
|
| 531 |
+
CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
|
| 532 |
+
endif
|
| 533 |
+
endif
|
| 534 |
+
|
| 535 |
+
ifeq ($(comp),$(filter $(comp),gcc clang icc))
|
| 536 |
+
ifeq ($(KERNEL),Darwin)
|
| 537 |
+
CXXFLAGS += -mdynamic-no-pic
|
| 538 |
+
endif
|
| 539 |
+
endif
|
| 540 |
+
|
| 541 |
+
ifeq ($(comp),clang)
|
| 542 |
+
clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
|
| 543 |
+
ifeq ($(shell expr $(clangmajorversion) \< 16),1)
|
| 544 |
+
CXXFLAGS += -fexperimental-new-pass-manager
|
| 545 |
+
endif
|
| 546 |
+
endif
|
| 547 |
+
endif
|
| 548 |
+
|
| 549 |
+
### 3.4 Bits
|
| 550 |
+
ifeq ($(bits),64)
|
| 551 |
+
CXXFLAGS += -DIS_64BIT
|
| 552 |
+
endif
|
| 553 |
+
|
| 554 |
+
### 3.5 prefetch
|
| 555 |
+
ifeq ($(prefetch),yes)
|
| 556 |
+
ifeq ($(sse),yes)
|
| 557 |
+
CXXFLAGS += -msse
|
| 558 |
+
endif
|
| 559 |
+
else
|
| 560 |
+
CXXFLAGS += -DNO_PREFETCH
|
| 561 |
+
endif
|
| 562 |
+
|
| 563 |
+
### 3.6 popcnt
|
| 564 |
+
ifeq ($(popcnt),yes)
|
| 565 |
+
ifeq ($(arch),$(filter $(arch),ppc64 armv7 armv8 arm64))
|
| 566 |
+
CXXFLAGS += -DUSE_POPCNT
|
| 567 |
+
else ifeq ($(comp),icc)
|
| 568 |
+
CXXFLAGS += -msse3 -DUSE_POPCNT
|
| 569 |
+
else
|
| 570 |
+
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
|
| 571 |
+
endif
|
| 572 |
+
endif
|
| 573 |
+
|
| 574 |
+
ifeq ($(avx2),yes)
|
| 575 |
+
CXXFLAGS += -DUSE_AVX2
|
| 576 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 577 |
+
CXXFLAGS += -mavx2 -mbmi
|
| 578 |
+
endif
|
| 579 |
+
endif
|
| 580 |
+
|
| 581 |
+
ifeq ($(avx512),yes)
|
| 582 |
+
CXXFLAGS += -DUSE_AVX512
|
| 583 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 584 |
+
CXXFLAGS += -mavx512f -mavx512bw
|
| 585 |
+
endif
|
| 586 |
+
endif
|
| 587 |
+
|
| 588 |
+
ifeq ($(vnni256),yes)
|
| 589 |
+
CXXFLAGS += -DUSE_VNNI
|
| 590 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 591 |
+
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256
|
| 592 |
+
endif
|
| 593 |
+
endif
|
| 594 |
+
|
| 595 |
+
ifeq ($(vnni512),yes)
|
| 596 |
+
CXXFLAGS += -DUSE_VNNI
|
| 597 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 598 |
+
CXXFLAGS += -mavx512vnni -mavx512dq -mavx512vl
|
| 599 |
+
endif
|
| 600 |
+
endif
|
| 601 |
+
|
| 602 |
+
ifeq ($(sse41),yes)
|
| 603 |
+
CXXFLAGS += -DUSE_SSE41
|
| 604 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 605 |
+
CXXFLAGS += -msse4.1
|
| 606 |
+
endif
|
| 607 |
+
endif
|
| 608 |
+
|
| 609 |
+
ifeq ($(ssse3),yes)
|
| 610 |
+
CXXFLAGS += -DUSE_SSSE3
|
| 611 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 612 |
+
CXXFLAGS += -mssse3
|
| 613 |
+
endif
|
| 614 |
+
endif
|
| 615 |
+
|
| 616 |
+
ifeq ($(sse2),yes)
|
| 617 |
+
CXXFLAGS += -DUSE_SSE2
|
| 618 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 619 |
+
CXXFLAGS += -msse2
|
| 620 |
+
endif
|
| 621 |
+
endif
|
| 622 |
+
|
| 623 |
+
ifeq ($(mmx),yes)
|
| 624 |
+
CXXFLAGS += -DUSE_MMX
|
| 625 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 626 |
+
CXXFLAGS += -mmmx
|
| 627 |
+
endif
|
| 628 |
+
endif
|
| 629 |
+
|
| 630 |
+
ifeq ($(neon),yes)
|
| 631 |
+
CXXFLAGS += -DUSE_NEON
|
| 632 |
+
ifeq ($(KERNEL),Linux)
|
| 633 |
+
ifneq ($(COMP),ndk)
|
| 634 |
+
ifneq ($(arch),armv8)
|
| 635 |
+
CXXFLAGS += -mfpu=neon
|
| 636 |
+
endif
|
| 637 |
+
endif
|
| 638 |
+
endif
|
| 639 |
+
endif
|
| 640 |
+
|
| 641 |
+
### 3.7 pext
|
| 642 |
+
ifeq ($(pext),yes)
|
| 643 |
+
CXXFLAGS += -DUSE_PEXT
|
| 644 |
+
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 645 |
+
CXXFLAGS += -mbmi2
|
| 646 |
+
endif
|
| 647 |
+
endif
|
| 648 |
+
|
| 649 |
+
### 3.8 Link Time Optimization
|
| 650 |
+
### This is a mix of compile and link time options because the lto link phase
|
| 651 |
+
### needs access to the optimization flags.
|
| 652 |
+
ifeq ($(optimize),yes)
|
| 653 |
+
ifeq ($(debug), no)
|
| 654 |
+
ifeq ($(comp),clang)
|
| 655 |
+
CXXFLAGS += -flto
|
| 656 |
+
ifneq ($(findstring MINGW,$(KERNEL)),)
|
| 657 |
+
CXXFLAGS += -fuse-ld=lld
|
| 658 |
+
else ifneq ($(findstring MSYS,$(KERNEL)),)
|
| 659 |
+
CXXFLAGS += -fuse-ld=lld
|
| 660 |
+
endif
|
| 661 |
+
LDFLAGS += $(CXXFLAGS)
|
| 662 |
+
|
| 663 |
+
# GCC and CLANG use different methods for parallelizing LTO and CLANG pretends to be
|
| 664 |
+
# GCC on some systems.
|
| 665 |
+
else ifeq ($(comp),gcc)
|
| 666 |
+
ifeq ($(gccisclang),)
|
| 667 |
+
CXXFLAGS += -flto
|
| 668 |
+
LDFLAGS += $(CXXFLAGS) -flto=jobserver
|
| 669 |
+
ifneq ($(findstring MINGW,$(KERNEL)),)
|
| 670 |
+
LDFLAGS += -save-temps
|
| 671 |
+
else ifneq ($(findstring MSYS,$(KERNEL)),)
|
| 672 |
+
LDFLAGS += -save-temps
|
| 673 |
+
endif
|
| 674 |
+
else
|
| 675 |
+
CXXFLAGS += -flto
|
| 676 |
+
LDFLAGS += $(CXXFLAGS)
|
| 677 |
+
endif
|
| 678 |
+
|
| 679 |
+
# To use LTO and static linking on windows, the tool chain requires a recent gcc:
|
| 680 |
+
# gcc version 10.1 in msys2 or TDM-GCC version 9.2 are known to work, older might not.
|
| 681 |
+
# So, only enable it for a cross from Linux by default.
|
| 682 |
+
else ifeq ($(comp),mingw)
|
| 683 |
+
ifeq ($(KERNEL),Linux)
|
| 684 |
+
ifneq ($(arch),i386)
|
| 685 |
+
CXXFLAGS += -flto
|
| 686 |
+
LDFLAGS += $(CXXFLAGS) -flto=jobserver
|
| 687 |
+
endif
|
| 688 |
+
endif
|
| 689 |
+
endif
|
| 690 |
+
endif
|
| 691 |
+
endif
|
| 692 |
+
|
| 693 |
+
### 3.9 Android 5 can only run position independent executables. Note that this
|
| 694 |
+
### breaks Android 4.0 and earlier.
|
| 695 |
+
ifeq ($(OS), Android)
|
| 696 |
+
CXXFLAGS += -fPIE
|
| 697 |
+
LDFLAGS += -fPIE -pie
|
| 698 |
+
endif
|
| 699 |
+
|
| 700 |
+
### ==========================================================================
|
| 701 |
+
### Section 4. Public Targets
|
| 702 |
+
### ==========================================================================
|
| 703 |
+
|
| 704 |
+
|
| 705 |
+
help:
|
| 706 |
+
@echo ""
|
| 707 |
+
@echo "To compile stockfish, type: "
|
| 708 |
+
@echo ""
|
| 709 |
+
@echo "make target ARCH=arch [COMP=compiler] [COMPCXX=cxx]"
|
| 710 |
+
@echo ""
|
| 711 |
+
@echo "Supported targets:"
|
| 712 |
+
@echo ""
|
| 713 |
+
@echo "help > Display architecture details"
|
| 714 |
+
@echo "build > Standard build"
|
| 715 |
+
@echo "net > Download the default nnue net"
|
| 716 |
+
@echo "profile-build > Faster build (with profile-guided optimization)"
|
| 717 |
+
@echo "strip > Strip executable"
|
| 718 |
+
@echo "install > Install executable"
|
| 719 |
+
@echo "clean > Clean up"
|
| 720 |
+
@echo ""
|
| 721 |
+
@echo "Supported archs:"
|
| 722 |
+
@echo ""
|
| 723 |
+
@echo "x86-64-vnni512 > x86 64-bit with vnni support 512bit wide"
|
| 724 |
+
@echo "x86-64-vnni256 > x86 64-bit with vnni support 256bit wide"
|
| 725 |
+
@echo "x86-64-avx512 > x86 64-bit with avx512 support"
|
| 726 |
+
@echo "x86-64-bmi2 > x86 64-bit with bmi2 support"
|
| 727 |
+
@echo "x86-64-avx2 > x86 64-bit with avx2 support"
|
| 728 |
+
@echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support"
|
| 729 |
+
@echo "x86-64-modern > common modern CPU, currently x86-64-sse41-popcnt"
|
| 730 |
+
@echo "x86-64-ssse3 > x86 64-bit with ssse3 support"
|
| 731 |
+
@echo "x86-64-sse3-popcnt > x86 64-bit with sse3 and popcnt support"
|
| 732 |
+
@echo "x86-64 > x86 64-bit generic (with sse2 support)"
|
| 733 |
+
@echo "x86-32-sse41-popcnt > x86 32-bit with sse41 and popcnt support"
|
| 734 |
+
@echo "x86-32-sse2 > x86 32-bit with sse2 support"
|
| 735 |
+
@echo "x86-32 > x86 32-bit generic (with mmx and sse support)"
|
| 736 |
+
@echo "ppc-64 > PPC 64-bit"
|
| 737 |
+
@echo "ppc-32 > PPC 32-bit"
|
| 738 |
+
@echo "armv7 > ARMv7 32-bit"
|
| 739 |
+
@echo "armv7-neon > ARMv7 32-bit with popcnt and neon"
|
| 740 |
+
@echo "armv8 > ARMv8 64-bit with popcnt and neon"
|
| 741 |
+
@echo "e2k > Elbrus 2000"
|
| 742 |
+
@echo "apple-silicon > Apple silicon ARM64"
|
| 743 |
+
@echo "general-64 > unspecified 64-bit"
|
| 744 |
+
@echo "general-32 > unspecified 32-bit"
|
| 745 |
+
@echo ""
|
| 746 |
+
@echo "Supported compilers:"
|
| 747 |
+
@echo ""
|
| 748 |
+
@echo "gcc > Gnu compiler (default)"
|
| 749 |
+
@echo "mingw > Gnu compiler with MinGW under Windows"
|
| 750 |
+
@echo "clang > LLVM Clang compiler"
|
| 751 |
+
@echo "icc > Intel compiler"
|
| 752 |
+
@echo "ndk > Google NDK to cross-compile for Android"
|
| 753 |
+
@echo ""
|
| 754 |
+
@echo "Simple examples. If you don't know what to do, you likely want to run: "
|
| 755 |
+
@echo ""
|
| 756 |
+
@echo "make -j build ARCH=x86-64 (A portable, slow compile for 64-bit systems)"
|
| 757 |
+
@echo "make -j build ARCH=x86-32 (A portable, slow compile for 32-bit systems)"
|
| 758 |
+
@echo ""
|
| 759 |
+
@echo "Advanced examples, for experienced users looking for performance: "
|
| 760 |
+
@echo ""
|
| 761 |
+
@echo "make help ARCH=x86-64-bmi2"
|
| 762 |
+
@echo "make -j profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-9.0"
|
| 763 |
+
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang"
|
| 764 |
+
@echo ""
|
| 765 |
+
@echo "-------------------------------"
|
| 766 |
+
ifeq ($(SUPPORTED_ARCH)$(help_skip_sanity), true)
|
| 767 |
+
@echo "The selected architecture $(ARCH) will enable the following configuration: "
|
| 768 |
+
@$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
|
| 769 |
+
else
|
| 770 |
+
@echo "Specify a supported architecture with the ARCH option for more details"
|
| 771 |
+
@echo ""
|
| 772 |
+
@echo "-------------------------------"
|
| 773 |
+
@echo "Embed and enable NNUE by default: "
|
| 774 |
+
@echo ""
|
| 775 |
+
@echo "make build ARCH=x86-64 nnue=yes"
|
| 776 |
+
@echo ""
|
| 777 |
+
@echo "-------------------------------"
|
| 778 |
+
@echo "Version for large boards: "
|
| 779 |
+
@echo ""
|
| 780 |
+
@echo "make build ARCH=x86-64 COMP=gcc largeboards=yes"
|
| 781 |
+
@echo ""
|
| 782 |
+
@echo "Include all variants (adds Game of the Amazons): "
|
| 783 |
+
@echo ""
|
| 784 |
+
@echo "make build ARCH=x86-64 largeboards=yes all=yes"
|
| 785 |
+
@echo ""
|
| 786 |
+
endif
|
| 787 |
+
|
| 788 |
+
|
| 789 |
+
.PHONY: help build profile-build strip install clean net objclean profileclean \
|
| 790 |
+
config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
|
| 791 |
+
clang-profile-use clang-profile-make
|
| 792 |
+
|
| 793 |
+
build: $(load_net) config-sanity
|
| 794 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
|
| 795 |
+
|
| 796 |
+
profile-build: $(load_net) config-sanity objclean profileclean
|
| 797 |
+
@echo ""
|
| 798 |
+
@echo "Step 1/4. Building instrumented executable ..."
|
| 799 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
|
| 800 |
+
@echo ""
|
| 801 |
+
@echo "Step 2/4. Running benchmark for pgo-build ..."
|
| 802 |
+
$(PGOBENCH) > /dev/null
|
| 803 |
+
@echo ""
|
| 804 |
+
@echo "Step 3/4. Building optimized executable ..."
|
| 805 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
|
| 806 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
|
| 807 |
+
@echo ""
|
| 808 |
+
@echo "Step 4/4. Deleting profile data ..."
|
| 809 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) profileclean
|
| 810 |
+
|
| 811 |
+
strip:
|
| 812 |
+
$(STRIP) $(EXE)
|
| 813 |
+
|
| 814 |
+
install:
|
| 815 |
+
-mkdir -p -m 755 $(BINDIR)
|
| 816 |
+
-cp $(EXE) $(BINDIR)
|
| 817 |
+
-strip $(BINDIR)/$(EXE)
|
| 818 |
+
|
| 819 |
+
# clean all
|
| 820 |
+
clean: objclean profileclean
|
| 821 |
+
@rm -f .depend *~ core
|
| 822 |
+
|
| 823 |
+
# evaluation network (nnue)
|
| 824 |
+
net:
|
| 825 |
+
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
|
| 826 |
+
@echo "Default net: $(nnuenet)"
|
| 827 |
+
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
|
| 828 |
+
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
|
| 829 |
+
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
|
| 830 |
+
@if [ "x$(curl_or_wget)" = "x" ]; then \
|
| 831 |
+
echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
|
| 832 |
+
fi
|
| 833 |
+
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
|
| 834 |
+
@if [ "x$(shasum_command)" = "x" ]; then \
|
| 835 |
+
echo "shasum / sha256sum not found, skipping net validation"; \
|
| 836 |
+
fi
|
| 837 |
+
@for nnuedownloadurl in "$(nnuedownloadurl1)" "$(nnuedownloadurl2)"; do \
|
| 838 |
+
if test -f "$(nnuenet)"; then \
|
| 839 |
+
echo "$(nnuenet) available."; \
|
| 840 |
+
else \
|
| 841 |
+
if [ "x$(curl_or_wget)" != "x" ]; then \
|
| 842 |
+
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
|
| 843 |
+
fi; \
|
| 844 |
+
fi; \
|
| 845 |
+
if [ "x$(shasum_command)" != "x" ]; then \
|
| 846 |
+
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
|
| 847 |
+
echo "Removing failed download"; rm -f $(nnuenet); \
|
| 848 |
+
else \
|
| 849 |
+
echo "Network validated"; break; \
|
| 850 |
+
fi; \
|
| 851 |
+
fi; \
|
| 852 |
+
done
|
| 853 |
+
@if ! test -f "$(nnuenet)"; then \
|
| 854 |
+
echo "Failed to download $(nnuenet)."; \
|
| 855 |
+
fi
|
| 856 |
+
|
| 857 |
+
# clean binaries and objects
|
| 858 |
+
objclean:
|
| 859 |
+
@rm -f $(EXE) *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o
|
| 860 |
+
|
| 861 |
+
# clean auxiliary profiling files
|
| 862 |
+
profileclean:
|
| 863 |
+
@rm -rf profdir
|
| 864 |
+
@rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s
|
| 865 |
+
@rm -f stockfish.profdata *.profraw
|
| 866 |
+
@rm -f stockfish.exe.lto_wrapper_args
|
| 867 |
+
@rm -f stockfish.exe.ltrans.out
|
| 868 |
+
@rm -f ./-lstdc++.res
|
| 869 |
+
|
| 870 |
+
default:
|
| 871 |
+
help
|
| 872 |
+
|
| 873 |
+
### ==========================================================================
|
| 874 |
+
### Section 5. Private Targets
|
| 875 |
+
### ==========================================================================
|
| 876 |
+
|
| 877 |
+
all: $(EXE) .depend
|
| 878 |
+
|
| 879 |
+
config-sanity: $(load_net)
|
| 880 |
+
@echo ""
|
| 881 |
+
@echo "Config:"
|
| 882 |
+
@echo "debug: '$(debug)'"
|
| 883 |
+
@echo "sanitize: '$(sanitize)'"
|
| 884 |
+
@echo "optimize: '$(optimize)'"
|
| 885 |
+
@echo "arch: '$(arch)'"
|
| 886 |
+
@echo "bits: '$(bits)'"
|
| 887 |
+
@echo "kernel: '$(KERNEL)'"
|
| 888 |
+
@echo "os: '$(OS)'"
|
| 889 |
+
@echo "prefetch: '$(prefetch)'"
|
| 890 |
+
@echo "popcnt: '$(popcnt)'"
|
| 891 |
+
@echo "pext: '$(pext)'"
|
| 892 |
+
@echo "sse: '$(sse)'"
|
| 893 |
+
@echo "mmx: '$(mmx)'"
|
| 894 |
+
@echo "sse2: '$(sse2)'"
|
| 895 |
+
@echo "ssse3: '$(ssse3)'"
|
| 896 |
+
@echo "sse41: '$(sse41)'"
|
| 897 |
+
@echo "avx2: '$(avx2)'"
|
| 898 |
+
@echo "avx512: '$(avx512)'"
|
| 899 |
+
@echo "vnni256: '$(vnni256)'"
|
| 900 |
+
@echo "vnni512: '$(vnni512)'"
|
| 901 |
+
@echo "neon: '$(neon)'"
|
| 902 |
+
@echo ""
|
| 903 |
+
@echo "Fairy-Stockfish specific:"
|
| 904 |
+
@echo "largeboards: '$(largeboards)'"
|
| 905 |
+
@echo "all: '$(all)'"
|
| 906 |
+
@echo "precomputedmagics: '$(precomputedmagics)'"
|
| 907 |
+
@echo "nnue: '$(nnue)'"
|
| 908 |
+
@echo ""
|
| 909 |
+
@echo "Flags:"
|
| 910 |
+
@echo "CXX: $(CXX)"
|
| 911 |
+
@echo "CXXFLAGS: $(CXXFLAGS)"
|
| 912 |
+
@echo "LDFLAGS: $(LDFLAGS)"
|
| 913 |
+
@echo ""
|
| 914 |
+
@echo "Testing config sanity. If this fails, try 'make help' ..."
|
| 915 |
+
@echo ""
|
| 916 |
+
@test "$(debug)" = "yes" || test "$(debug)" = "no"
|
| 917 |
+
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
|
| 918 |
+
@test "$(SUPPORTED_ARCH)" = "true"
|
| 919 |
+
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
|
| 920 |
+
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
|
| 921 |
+
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64"
|
| 922 |
+
@test "$(bits)" = "32" || test "$(bits)" = "64"
|
| 923 |
+
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
|
| 924 |
+
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
|
| 925 |
+
@test "$(pext)" = "yes" || test "$(pext)" = "no"
|
| 926 |
+
@test "$(sse)" = "yes" || test "$(sse)" = "no"
|
| 927 |
+
@test "$(mmx)" = "yes" || test "$(mmx)" = "no"
|
| 928 |
+
@test "$(sse2)" = "yes" || test "$(sse2)" = "no"
|
| 929 |
+
@test "$(ssse3)" = "yes" || test "$(ssse3)" = "no"
|
| 930 |
+
@test "$(sse41)" = "yes" || test "$(sse41)" = "no"
|
| 931 |
+
@test "$(avx2)" = "yes" || test "$(avx2)" = "no"
|
| 932 |
+
@test "$(avx512)" = "yes" || test "$(avx512)" = "no"
|
| 933 |
+
@test "$(vnni256)" = "yes" || test "$(vnni256)" = "no"
|
| 934 |
+
@test "$(vnni512)" = "yes" || test "$(vnni512)" = "no"
|
| 935 |
+
@test "$(neon)" = "yes" || test "$(neon)" = "no"
|
| 936 |
+
@test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \
|
| 937 |
+
|| test "$(comp)" = "armv7a-linux-androideabi16-clang" || test "$(comp)" = "aarch64-linux-android21-clang"
|
| 938 |
+
|
| 939 |
+
$(EXE): $(OBJS)
|
| 940 |
+
+$(CXX) -o $@ $(OBJS) $(LDFLAGS)
|
| 941 |
+
|
| 942 |
+
clang-profile-make:
|
| 943 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 944 |
+
EXTRACXXFLAGS='-fprofile-instr-generate ' \
|
| 945 |
+
EXTRALDFLAGS=' -fprofile-instr-generate' \
|
| 946 |
+
all
|
| 947 |
+
|
| 948 |
+
clang-profile-use:
|
| 949 |
+
$(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw
|
| 950 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 951 |
+
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \
|
| 952 |
+
EXTRALDFLAGS='-fprofile-use ' \
|
| 953 |
+
all
|
| 954 |
+
|
| 955 |
+
gcc-profile-make:
|
| 956 |
+
@mkdir -p profdir
|
| 957 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 958 |
+
EXTRACXXFLAGS='-fprofile-generate=profdir' \
|
| 959 |
+
EXTRALDFLAGS='-lgcov' \
|
| 960 |
+
all
|
| 961 |
+
|
| 962 |
+
gcc-profile-use:
|
| 963 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 964 |
+
EXTRACXXFLAGS='-fprofile-use=profdir -fno-peel-loops -fno-tracer' \
|
| 965 |
+
EXTRALDFLAGS='-lgcov' \
|
| 966 |
+
all
|
| 967 |
+
|
| 968 |
+
icc-profile-make:
|
| 969 |
+
@mkdir -p profdir
|
| 970 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 971 |
+
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
|
| 972 |
+
all
|
| 973 |
+
|
| 974 |
+
icc-profile-use:
|
| 975 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 976 |
+
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
|
| 977 |
+
all
|
| 978 |
+
|
| 979 |
+
.depend:
|
| 980 |
+
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
|
| 981 |
+
|
| 982 |
+
-include .depend
|
Fairy-Stockfish-master/src/Makefile_js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ffish.js, a JavaScript chess variant library derived from Fairy-Stockfish
|
| 2 |
+
# Copyright (C) 2022 Fabian Fichter, Johannes Czech
|
| 3 |
+
#
|
| 4 |
+
# ffish.js is free software: you can redistribute it and/or modify
|
| 5 |
+
# it under the terms of the GNU General Public License as published by
|
| 6 |
+
# the Free Software Foundation, either version 3 of the License, or
|
| 7 |
+
# (at your option) any later version.
|
| 8 |
+
#
|
| 9 |
+
# ffish.js is distributed in the hope that it will be useful,
|
| 10 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 12 |
+
# GNU General Public License for more details.
|
| 13 |
+
#
|
| 14 |
+
# You should have received a copy of the GNU General Public License
|
| 15 |
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 16 |
+
|
| 17 |
+
EXE = ../tests/js/ffish.js
|
| 18 |
+
|
| 19 |
+
SRCS = ffishjs.cpp benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp \
|
| 20 |
+
material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \
|
| 21 |
+
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
|
| 22 |
+
nnue/evaluate_nnue.cpp nnue/features/half_ka_v2.cpp \
|
| 23 |
+
partner.cpp parser.cpp piece.cpp variant.cpp xboard.cpp \
|
| 24 |
+
nnue/features/half_ka_v2_variants.cpp
|
| 25 |
+
|
| 26 |
+
CXX=emcc
|
| 27 |
+
CXXFLAGS += --bind -DNNUE_EMBEDDING_OFF -DNO_THREADS -std=c++17 -Wall
|
| 28 |
+
|
| 29 |
+
largeboards = yes
|
| 30 |
+
all = yes
|
| 31 |
+
optimize = yes
|
| 32 |
+
debug = no
|
| 33 |
+
|
| 34 |
+
### Debugging
|
| 35 |
+
ifeq ($(debug),no)
|
| 36 |
+
CXXFLAGS += -DNDEBUG -s ASSERTIONS=0 -s SAFE_HEAP=0
|
| 37 |
+
else
|
| 38 |
+
CXXFLAGS += -g -s ASSERTIONS=1 -s SAFE_HEAP=1
|
| 39 |
+
endif
|
| 40 |
+
|
| 41 |
+
### Optimization
|
| 42 |
+
ifeq ($(optimize),yes)
|
| 43 |
+
CXXFLAGS += -O3
|
| 44 |
+
endif
|
| 45 |
+
|
| 46 |
+
# Compile version with support for large board variants
|
| 47 |
+
# Use precomputed magics by default
|
| 48 |
+
ifneq ($(largeboards),no)
|
| 49 |
+
CXXFLAGS += -DLARGEBOARDS -DPRECOMPUTED_MAGICS -s TOTAL_MEMORY=32MB -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=1GB
|
| 50 |
+
endif
|
| 51 |
+
|
| 52 |
+
# Enable all variants, even heavyweight ones like duck and amazons
|
| 53 |
+
ifneq ($(all),no)
|
| 54 |
+
CXXFLAGS += -DALLVARS
|
| 55 |
+
endif
|
| 56 |
+
|
| 57 |
+
### Compile as ES6/ES2015 module
|
| 58 |
+
ifeq ($(es6),yes)
|
| 59 |
+
CXXFLAGS += -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
|
| 60 |
+
endif
|
| 61 |
+
|
| 62 |
+
.PHONY: help objclean clean build deps test serve
|
| 63 |
+
|
| 64 |
+
help:
|
| 65 |
+
@echo ""
|
| 66 |
+
@echo "To compile ffishjs, type: "
|
| 67 |
+
@echo ""
|
| 68 |
+
@echo "make -f Makefile_js build"
|
| 69 |
+
@echo ""
|
| 70 |
+
@echo "Supported targets:"
|
| 71 |
+
@echo ""
|
| 72 |
+
@echo "help > Display this help"
|
| 73 |
+
@echo "build > Standard build"
|
| 74 |
+
@echo "clean > Clean up"
|
| 75 |
+
@echo "deps > Install runtime dependencies using npm"
|
| 76 |
+
@echo "test > Run tests"
|
| 77 |
+
@echo "serve > Run example server"
|
| 78 |
+
@echo ""
|
| 79 |
+
|
| 80 |
+
objclean:
|
| 81 |
+
@rm -f $(EXE)
|
| 82 |
+
|
| 83 |
+
clean: objclean
|
| 84 |
+
|
| 85 |
+
build:
|
| 86 |
+
$(CXX) $(CXXFLAGS) $(SRCS) -o $(EXE)
|
| 87 |
+
|
| 88 |
+
deps:
|
| 89 |
+
cd ../tests/js && npm install
|
| 90 |
+
|
| 91 |
+
test: deps
|
| 92 |
+
cd ../tests/js && npm test
|
| 93 |
+
|
| 94 |
+
serve: deps
|
| 95 |
+
cd ../tests/js && node index.js
|
Fairy-Stockfish-master/src/apiutil.h
ADDED
|
@@ -0,0 +1,1165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
|
| 3 |
+
Copyright (C) 2018-2022 Fabian Fichter
|
| 4 |
+
|
| 5 |
+
Fairy-Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Fairy-Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef APIUTIL_H_INCLUDED
|
| 20 |
+
#define APIUTIL_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <array>
|
| 23 |
+
#include <vector>
|
| 24 |
+
#include <string>
|
| 25 |
+
#include <sstream>
|
| 26 |
+
#include <cctype>
|
| 27 |
+
#include <iostream>
|
| 28 |
+
#include <math.h>
|
| 29 |
+
|
| 30 |
+
#include "types.h"
|
| 31 |
+
#include "position.h"
|
| 32 |
+
#include "variant.h"
|
| 33 |
+
|
| 34 |
+
namespace Stockfish {
|
| 35 |
+
|
| 36 |
+
enum Notation {
|
| 37 |
+
NOTATION_DEFAULT,
|
| 38 |
+
// https://en.wikipedia.org/wiki/Algebraic_notation_(chess)
|
| 39 |
+
NOTATION_SAN,
|
| 40 |
+
NOTATION_LAN,
|
| 41 |
+
// https://en.wikipedia.org/wiki/Shogi_notation#Western_notation
|
| 42 |
+
NOTATION_SHOGI_HOSKING, // Examples: P76, S’34
|
| 43 |
+
NOTATION_SHOGI_HODGES, // Examples: P-7f, S*3d
|
| 44 |
+
NOTATION_SHOGI_HODGES_NUMBER, // Examples: P-76, S*34
|
| 45 |
+
// http://www.janggi.pl/janggi-notation/
|
| 46 |
+
NOTATION_JANGGI,
|
| 47 |
+
// https://en.wikipedia.org/wiki/Xiangqi#Notation
|
| 48 |
+
NOTATION_XIANGQI_WXF,
|
| 49 |
+
// https://web.archive.org/web/20180817205956/http://bgsthai.com/2018/05/07/lawofthaichessc/
|
| 50 |
+
NOTATION_THAI_SAN,
|
| 51 |
+
NOTATION_THAI_LAN,
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
inline Notation default_notation(const Variant* v) {
|
| 55 |
+
if (v->variantTemplate == "shogi")
|
| 56 |
+
return NOTATION_SHOGI_HODGES_NUMBER;
|
| 57 |
+
return NOTATION_SAN;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
enum Termination {
|
| 61 |
+
ONGOING,
|
| 62 |
+
CHECKMATE,
|
| 63 |
+
STALEMATE,
|
| 64 |
+
INSUFFICIENT_MATERIAL,
|
| 65 |
+
N_MOVE_RULE,
|
| 66 |
+
N_FOLD_REPETITION,
|
| 67 |
+
VARIANT_END,
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
const std::array<std::string, 12> THAI_FILES = {"ก", "ข", "ค", "ง", "จ", "ฉ", "ช", "ญ", "ต", "ถ", "ธ", "น"};
|
| 71 |
+
const std::array<std::string, 12> THAI_RANKS = {"๑", "๒", "๓", "๔", "๕", "๖", "๗", "๘", "๙", "๑๐", "๑๑", "๑๒"};
|
| 72 |
+
|
| 73 |
+
namespace SAN {
|
| 74 |
+
|
| 75 |
+
enum Disambiguation {
|
| 76 |
+
NO_DISAMBIGUATION,
|
| 77 |
+
FILE_DISAMBIGUATION,
|
| 78 |
+
RANK_DISAMBIGUATION,
|
| 79 |
+
SQUARE_DISAMBIGUATION,
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
inline bool is_shogi(Notation n) {
|
| 83 |
+
return n == NOTATION_SHOGI_HOSKING || n == NOTATION_SHOGI_HODGES || n == NOTATION_SHOGI_HODGES_NUMBER;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
inline bool is_thai(Notation n) {
|
| 87 |
+
return n == NOTATION_THAI_SAN || n == NOTATION_THAI_LAN;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
// is there more than one file with a pair of pieces?
|
| 91 |
+
inline bool multi_tandem(Bitboard b) {
|
| 92 |
+
int tandems = 0;
|
| 93 |
+
for (File f = FILE_A; f <= FILE_MAX; ++f)
|
| 94 |
+
if (more_than_one(b & file_bb(f)))
|
| 95 |
+
tandems++;
|
| 96 |
+
return tandems >= 2;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
inline std::string piece_to_thai_char(Piece pc, bool promoted) {
|
| 100 |
+
switch(type_of(pc)) {
|
| 101 |
+
case KING:
|
| 102 |
+
return "ข";
|
| 103 |
+
case KHON:
|
| 104 |
+
return "ค";
|
| 105 |
+
case FERS:
|
| 106 |
+
return promoted ? "ง" : "ม็";
|
| 107 |
+
case KNIGHT:
|
| 108 |
+
return "ม";
|
| 109 |
+
case ROOK:
|
| 110 |
+
return "ร";
|
| 111 |
+
case PAWN:
|
| 112 |
+
return "บ";
|
| 113 |
+
case AIWOK:
|
| 114 |
+
return "ว";
|
| 115 |
+
default:
|
| 116 |
+
return "X";
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
inline std::string piece(const Position& pos, Move m, Notation n) {
|
| 121 |
+
Color us = pos.side_to_move();
|
| 122 |
+
Square from = from_sq(m);
|
| 123 |
+
Piece pc = pos.moved_piece(m);
|
| 124 |
+
PieceType pt = type_of(pc);
|
| 125 |
+
// Quiet pawn moves
|
| 126 |
+
if ((n == NOTATION_SAN || n == NOTATION_LAN || n == NOTATION_THAI_SAN) && type_of(pc) == PAWN && type_of(m) != DROP)
|
| 127 |
+
return "";
|
| 128 |
+
// Tandem pawns
|
| 129 |
+
else if (n == NOTATION_XIANGQI_WXF && popcount(pos.pieces(us, pt) & file_bb(from)) >= 3 - multi_tandem(pos.pieces(us, pt)))
|
| 130 |
+
return std::to_string(popcount(forward_file_bb(us, from) & pos.pieces(us, pt)) + 1);
|
| 131 |
+
// Moves of promoted pieces
|
| 132 |
+
else if (is_shogi(n) && type_of(m) != DROP && pos.unpromoted_piece_on(from))
|
| 133 |
+
return "+" + std::string(1, toupper(pos.piece_to_char()[pos.unpromoted_piece_on(from)]));
|
| 134 |
+
// Promoted drops
|
| 135 |
+
else if (is_shogi(n) && type_of(m) == DROP && dropped_piece_type(m) != in_hand_piece_type(m))
|
| 136 |
+
return "+" + std::string(1, toupper(pos.piece_to_char()[in_hand_piece_type(m)]));
|
| 137 |
+
else if (is_thai(n))
|
| 138 |
+
return piece_to_thai_char(pc, pos.is_promoted(from));
|
| 139 |
+
else if (pos.piece_to_char_synonyms()[pc] != ' ')
|
| 140 |
+
return std::string(1, toupper(pos.piece_to_char_synonyms()[pc]));
|
| 141 |
+
else
|
| 142 |
+
return std::string(1, toupper(pos.piece_to_char()[pc]));
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
inline std::string file(const Position& pos, Square s, Notation n) {
|
| 146 |
+
switch (n)
|
| 147 |
+
{
|
| 148 |
+
case NOTATION_SHOGI_HOSKING:
|
| 149 |
+
case NOTATION_SHOGI_HODGES:
|
| 150 |
+
case NOTATION_SHOGI_HODGES_NUMBER:
|
| 151 |
+
return std::to_string(pos.max_file() - file_of(s) + 1);
|
| 152 |
+
case NOTATION_JANGGI:
|
| 153 |
+
return std::to_string(file_of(s) + 1);
|
| 154 |
+
case NOTATION_XIANGQI_WXF:
|
| 155 |
+
return std::to_string((pos.side_to_move() == WHITE ? pos.max_file() - file_of(s) : file_of(s)) + 1);
|
| 156 |
+
case NOTATION_THAI_SAN:
|
| 157 |
+
case NOTATION_THAI_LAN:
|
| 158 |
+
return THAI_FILES[file_of(s)];
|
| 159 |
+
default:
|
| 160 |
+
return std::string(1, char('a' + file_of(s)));
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
inline std::string rank(const Position& pos, Square s, Notation n) {
|
| 165 |
+
switch (n)
|
| 166 |
+
{
|
| 167 |
+
case NOTATION_SHOGI_HOSKING:
|
| 168 |
+
case NOTATION_SHOGI_HODGES_NUMBER:
|
| 169 |
+
return std::to_string(pos.max_rank() - rank_of(s) + 1);
|
| 170 |
+
case NOTATION_SHOGI_HODGES:
|
| 171 |
+
return std::string(1, char('a' + pos.max_rank() - rank_of(s)));
|
| 172 |
+
case NOTATION_JANGGI:
|
| 173 |
+
return std::to_string((pos.max_rank() - rank_of(s) + 1) % 10);
|
| 174 |
+
case NOTATION_XIANGQI_WXF:
|
| 175 |
+
{
|
| 176 |
+
if (pos.empty(s))
|
| 177 |
+
// Handle piece drops
|
| 178 |
+
return std::to_string(relative_rank(pos.side_to_move(), s, pos.max_rank()) + 1);
|
| 179 |
+
else if (pos.pieces(pos.side_to_move(), type_of(pos.piece_on(s))) & forward_file_bb(pos.side_to_move(), s))
|
| 180 |
+
return "-";
|
| 181 |
+
else
|
| 182 |
+
return "+";
|
| 183 |
+
}
|
| 184 |
+
case NOTATION_THAI_SAN:
|
| 185 |
+
case NOTATION_THAI_LAN:
|
| 186 |
+
return THAI_RANKS[rank_of(s)];
|
| 187 |
+
default:
|
| 188 |
+
return std::to_string(rank_of(s) + 1);
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
inline std::string square(const Position& pos, Square s, Notation n) {
|
| 193 |
+
switch (n)
|
| 194 |
+
{
|
| 195 |
+
case NOTATION_JANGGI:
|
| 196 |
+
return rank(pos, s, n) + file(pos, s, n);
|
| 197 |
+
default:
|
| 198 |
+
return file(pos, s, n) + rank(pos, s, n);
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
inline Disambiguation disambiguation_level(const Position& pos, Move m, Notation n) {
|
| 203 |
+
// Drops never need disambiguation
|
| 204 |
+
if (type_of(m) == DROP)
|
| 205 |
+
return NO_DISAMBIGUATION;
|
| 206 |
+
|
| 207 |
+
// NOTATION_LAN and Janggi always use disambiguation
|
| 208 |
+
if (n == NOTATION_LAN || n == NOTATION_THAI_LAN || n == NOTATION_JANGGI)
|
| 209 |
+
return SQUARE_DISAMBIGUATION;
|
| 210 |
+
|
| 211 |
+
Color us = pos.side_to_move();
|
| 212 |
+
Square from = from_sq(m);
|
| 213 |
+
Square to = to_sq(m);
|
| 214 |
+
Piece pc = pos.moved_piece(m);
|
| 215 |
+
PieceType pt = type_of(pc);
|
| 216 |
+
|
| 217 |
+
// Xiangqi uses either file disambiguation or +/- if two pieces on file
|
| 218 |
+
if (n == NOTATION_XIANGQI_WXF)
|
| 219 |
+
{
|
| 220 |
+
// Disambiguate by rank (+/-) if target square of other piece is valid
|
| 221 |
+
if (popcount(pos.pieces(us, pt) & file_bb(from)) == 2 && !multi_tandem(pos.pieces(us, pt)))
|
| 222 |
+
{
|
| 223 |
+
Square otherFrom = lsb((pos.pieces(us, pt) & file_bb(from)) ^ from);
|
| 224 |
+
Square otherTo = otherFrom + Direction(to) - Direction(from);
|
| 225 |
+
if (is_ok(otherTo) && (pos.board_bb(us, pt) & otherTo))
|
| 226 |
+
return RANK_DISAMBIGUATION;
|
| 227 |
+
}
|
| 228 |
+
return FILE_DISAMBIGUATION;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
// Pawn captures always use disambiguation
|
| 232 |
+
if ((n == NOTATION_SAN || n == NOTATION_THAI_SAN) && pt == PAWN)
|
| 233 |
+
{
|
| 234 |
+
if (pos.capture(m))
|
| 235 |
+
return FILE_DISAMBIGUATION;
|
| 236 |
+
if (type_of(m) == PROMOTION && from != to && pos.sittuyin_promotion())
|
| 237 |
+
return SQUARE_DISAMBIGUATION;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
// A disambiguation occurs if we have more than one piece of type 'pt'
|
| 241 |
+
// that can reach 'to' with a legal move.
|
| 242 |
+
Bitboard b = pos.pieces(us, pt) ^ from;
|
| 243 |
+
Bitboard others = 0;
|
| 244 |
+
|
| 245 |
+
while (b)
|
| 246 |
+
{
|
| 247 |
+
Square s = pop_lsb(b);
|
| 248 |
+
// Construct a potential move with identical special move flags
|
| 249 |
+
// and only a different "from" square.
|
| 250 |
+
Move testMove = Move(m ^ make_move(from, to) ^ make_move(s, to));
|
| 251 |
+
if ( pos.pseudo_legal(testMove)
|
| 252 |
+
&& pos.legal(testMove)
|
| 253 |
+
&& !(is_shogi(n) && pos.unpromoted_piece_on(s) != pos.unpromoted_piece_on(from)))
|
| 254 |
+
others |= s;
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
if (!others)
|
| 258 |
+
return NO_DISAMBIGUATION;
|
| 259 |
+
else if (is_shogi(n))
|
| 260 |
+
return SQUARE_DISAMBIGUATION;
|
| 261 |
+
else if (!(others & file_bb(from)))
|
| 262 |
+
return FILE_DISAMBIGUATION;
|
| 263 |
+
else if (!(others & rank_bb(from)))
|
| 264 |
+
return RANK_DISAMBIGUATION;
|
| 265 |
+
else
|
| 266 |
+
return SQUARE_DISAMBIGUATION;
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
inline std::string disambiguation(const Position& pos, Square s, Notation n, Disambiguation d) {
|
| 270 |
+
switch (d)
|
| 271 |
+
{
|
| 272 |
+
case FILE_DISAMBIGUATION:
|
| 273 |
+
return file(pos, s, n);
|
| 274 |
+
case RANK_DISAMBIGUATION:
|
| 275 |
+
return rank(pos, s, n);
|
| 276 |
+
case SQUARE_DISAMBIGUATION:
|
| 277 |
+
return square(pos, s, n);
|
| 278 |
+
default:
|
| 279 |
+
assert(d == NO_DISAMBIGUATION);
|
| 280 |
+
return "";
|
| 281 |
+
}
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
inline const std::string move_to_san(Position& pos, Move m, Notation n) {
|
| 285 |
+
std::string san = "";
|
| 286 |
+
Color us = pos.side_to_move();
|
| 287 |
+
Square from = from_sq(m);
|
| 288 |
+
Square to = to_sq(m);
|
| 289 |
+
|
| 290 |
+
if (type_of(m) == CASTLING)
|
| 291 |
+
{
|
| 292 |
+
san = to > from ? "O-O" : "O-O-O";
|
| 293 |
+
|
| 294 |
+
if (is_gating(m))
|
| 295 |
+
{
|
| 296 |
+
san += std::string("/") + (char)toupper(pos.piece_to_char()[make_piece(us, gating_type(m))]);
|
| 297 |
+
san += square(pos, gating_square(m), n);
|
| 298 |
+
}
|
| 299 |
+
}
|
| 300 |
+
else
|
| 301 |
+
{
|
| 302 |
+
// Piece
|
| 303 |
+
san += piece(pos, m, n);
|
| 304 |
+
|
| 305 |
+
if (n == NOTATION_THAI_LAN)
|
| 306 |
+
san += " ";
|
| 307 |
+
|
| 308 |
+
// Origin square, disambiguation
|
| 309 |
+
Disambiguation d = disambiguation_level(pos, m, n);
|
| 310 |
+
san += disambiguation(pos, from, n, d);
|
| 311 |
+
|
| 312 |
+
// Separator/Operator
|
| 313 |
+
if (type_of(m) == DROP)
|
| 314 |
+
san += n == NOTATION_SHOGI_HOSKING ? '\'' : is_shogi(n) ? '*' : '@';
|
| 315 |
+
else if (n == NOTATION_XIANGQI_WXF)
|
| 316 |
+
{
|
| 317 |
+
if (rank_of(from) == rank_of(to))
|
| 318 |
+
san += '=';
|
| 319 |
+
else if (relative_rank(us, to, pos.max_rank()) > relative_rank(us, from, pos.max_rank()))
|
| 320 |
+
san += '+';
|
| 321 |
+
else
|
| 322 |
+
san += '-';
|
| 323 |
+
}
|
| 324 |
+
else if (pos.capture(m))
|
| 325 |
+
san += 'x';
|
| 326 |
+
else if (n == NOTATION_LAN || n == NOTATION_THAI_LAN || (is_shogi(n) && (n != NOTATION_SHOGI_HOSKING || d == SQUARE_DISAMBIGUATION)) || n == NOTATION_JANGGI || (n == NOTATION_THAI_SAN && type_of(pos.moved_piece(m)) != PAWN))
|
| 327 |
+
san += '-';
|
| 328 |
+
|
| 329 |
+
// Destination square
|
| 330 |
+
if (n == NOTATION_XIANGQI_WXF && type_of(m) != DROP)
|
| 331 |
+
san += file_of(to) == file_of(from) ? std::to_string(std::abs(rank_of(to) - rank_of(from))) : file(pos, to, n);
|
| 332 |
+
else
|
| 333 |
+
san += square(pos, to, n);
|
| 334 |
+
|
| 335 |
+
// Suffix
|
| 336 |
+
if (type_of(m) == PROMOTION)
|
| 337 |
+
san += std::string("=") + (char)toupper(pos.piece_to_char()[make_piece(us, promotion_type(m))]);
|
| 338 |
+
else if (type_of(m) == PIECE_PROMOTION)
|
| 339 |
+
san += is_shogi(n) ? std::string("+") : std::string("=") + (char)toupper(pos.piece_to_char()[make_piece(us, pos.promoted_piece_type(type_of(pos.moved_piece(m))))]);
|
| 340 |
+
else if (type_of(m) == PIECE_DEMOTION)
|
| 341 |
+
san += is_shogi(n) ? std::string("-") : std::string("=") + std::string(1, toupper(pos.piece_to_char()[pos.unpromoted_piece_on(from)]));
|
| 342 |
+
else if (type_of(m) == NORMAL && is_shogi(n) && pos.pseudo_legal(make<PIECE_PROMOTION>(from, to)))
|
| 343 |
+
san += std::string("=");
|
| 344 |
+
if (is_gating(m))
|
| 345 |
+
san += std::string("/") + (char)toupper(pos.piece_to_char()[make_piece(us, gating_type(m))]);
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
// Wall square
|
| 349 |
+
if (pos.walling())
|
| 350 |
+
san += "," + square(pos, gating_square(m), n);
|
| 351 |
+
|
| 352 |
+
// Check and checkmate
|
| 353 |
+
if (pos.gives_check(m) && !is_shogi(n) && n != NOTATION_XIANGQI_WXF)
|
| 354 |
+
{
|
| 355 |
+
StateInfo st;
|
| 356 |
+
pos.do_move(m, st);
|
| 357 |
+
san += MoveList<LEGAL>(pos).size() ? "+" : "#";
|
| 358 |
+
pos.undo_move(m);
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
return san;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
} // namespace SAN
|
| 365 |
+
|
| 366 |
+
inline bool has_insufficient_material(Color c, const Position& pos) {
|
| 367 |
+
|
| 368 |
+
// Other win rules
|
| 369 |
+
if ( pos.captures_to_hand()
|
| 370 |
+
|| pos.count_in_hand(c, ALL_PIECES)
|
| 371 |
+
|| (pos.extinction_value() != VALUE_NONE && !pos.extinction_pseudo_royal())
|
| 372 |
+
|| (pos.variant()->nFoldRule && pos.variant()->nFoldValue != VALUE_DRAW)
|
| 373 |
+
|| (pos.flag_region(c) && pos.count(c, pos.flag_piece(c))))
|
| 374 |
+
return false;
|
| 375 |
+
|
| 376 |
+
// Precalculate if any promotion pawn types have pieces
|
| 377 |
+
bool hasPromotingPawn = false;
|
| 378 |
+
for (PieceSet pawnTypes = pos.promotion_pawn_types(c); pawnTypes; )
|
| 379 |
+
{
|
| 380 |
+
PieceType pawnType = pop_lsb(pawnTypes);
|
| 381 |
+
if (pos.count(c, pawnType) > 0)
|
| 382 |
+
{
|
| 383 |
+
hasPromotingPawn = true;
|
| 384 |
+
break;
|
| 385 |
+
}
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
// Determine checkmating potential of present pieces
|
| 389 |
+
constexpr PieceSet MAJOR_PIECES = piece_set(ROOK) | QUEEN | ARCHBISHOP | CHANCELLOR
|
| 390 |
+
| SILVER | GOLD | COMMONER | CENTAUR | AMAZON | BERS;
|
| 391 |
+
constexpr PieceSet COLORBOUND_PIECES = piece_set(BISHOP) | FERS | FERS_ALFIL | ALFIL | ELEPHANT;
|
| 392 |
+
Bitboard restricted = pos.pieces(KING);
|
| 393 |
+
Bitboard colorbound = 0;
|
| 394 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 395 |
+
{
|
| 396 |
+
PieceType pt = pop_lsb(ps);
|
| 397 |
+
|
| 398 |
+
// Constrained pieces
|
| 399 |
+
if (pt == KING || !(pos.board_bb(c, pt) & pos.board_bb(~c, KING)) || (pos.extinction_pseudo_royal() && pos.blast_on_capture() && (pos.extinction_piece_types() & pt)))
|
| 400 |
+
restricted |= pos.pieces(c, pt);
|
| 401 |
+
|
| 402 |
+
// If piece is a major piece or a custom piece we consider it sufficient for mate.
|
| 403 |
+
// To avoid false positives, we assume any custom piece has mating potential.
|
| 404 |
+
else if ((MAJOR_PIECES & pt) || is_custom(pt))
|
| 405 |
+
{
|
| 406 |
+
// Check if piece is already on the board
|
| 407 |
+
if (pos.count(c, pt) > 0)
|
| 408 |
+
return false;
|
| 409 |
+
|
| 410 |
+
// Check if any pawn can promote to this piece type
|
| 411 |
+
if (hasPromotingPawn && (pos.promotion_piece_types(c) & pt))
|
| 412 |
+
return false;
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
// Collect color-bound pieces
|
| 416 |
+
else if (COLORBOUND_PIECES & pt)
|
| 417 |
+
colorbound |= pos.pieces(pt);
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
Bitboard unbound = pos.pieces() ^ restricted ^ colorbound;
|
| 421 |
+
|
| 422 |
+
// Color-bound pieces
|
| 423 |
+
if ((colorbound & pos.pieces(c)) && (((DarkSquares & colorbound) && (~DarkSquares & colorbound)) || unbound || pos.stalemate_value() != VALUE_DRAW || pos.check_counting() || pos.makpong()))
|
| 424 |
+
return false;
|
| 425 |
+
|
| 426 |
+
// Unbound pieces require one helper piece of either color
|
| 427 |
+
if ((pos.pieces(c) & unbound) && (popcount(pos.pieces() ^ restricted) >= 2 || pos.stalemate_value() != VALUE_DRAW || pos.check_counting() || pos.makpong()))
|
| 428 |
+
return false;
|
| 429 |
+
|
| 430 |
+
// Non-draw stalemate with lone custom king
|
| 431 |
+
if ( pos.stalemate_value() != VALUE_DRAW && pos.king_type() != KING
|
| 432 |
+
&& pos.pieces(c, KING) && (pos.board_bb(c, KING) & pos.board_bb(~c, KING)))
|
| 433 |
+
return false;
|
| 434 |
+
|
| 435 |
+
return true;
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
inline Bitboard checked(const Position& pos) {
|
| 439 |
+
return (pos.checkers() ? square_bb(pos.square<KING>(pos.side_to_move())) : Bitboard(0))
|
| 440 |
+
| (pos.extinction_pseudo_royal() ? pos.checked_pseudo_royals(pos.side_to_move()) : Bitboard(0));
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
namespace FEN {
|
| 444 |
+
|
| 445 |
+
enum FenValidation : int {
|
| 446 |
+
FEN_INVALID_COUNTING_RULE = -14,
|
| 447 |
+
FEN_INVALID_CHECK_COUNT = -13,
|
| 448 |
+
FEN_INVALID_PROMOTED_PIECE = -12,
|
| 449 |
+
FEN_INVALID_NB_PARTS = -11,
|
| 450 |
+
FEN_INVALID_CHAR = -10,
|
| 451 |
+
FEN_TOUCHING_KINGS = -9,
|
| 452 |
+
FEN_INVALID_BOARD_GEOMETRY = -8,
|
| 453 |
+
FEN_INVALID_POCKET_INFO = -7,
|
| 454 |
+
FEN_INVALID_SIDE_TO_MOVE = -6,
|
| 455 |
+
FEN_INVALID_CASTLING_INFO = -5,
|
| 456 |
+
FEN_INVALID_EN_PASSANT_SQ = -4,
|
| 457 |
+
FEN_INVALID_NUMBER_OF_KINGS = -3,
|
| 458 |
+
FEN_INVALID_HALF_MOVE_COUNTER = -2,
|
| 459 |
+
FEN_INVALID_MOVE_COUNTER = -1,
|
| 460 |
+
FEN_EMPTY = 0,
|
| 461 |
+
FEN_OK = 1
|
| 462 |
+
};
|
| 463 |
+
enum Validation : int {
|
| 464 |
+
NOK,
|
| 465 |
+
OK
|
| 466 |
+
};
|
| 467 |
+
|
| 468 |
+
struct CharSquare {
|
| 469 |
+
int rowIdx;
|
| 470 |
+
int fileIdx;
|
| 471 |
+
CharSquare() : rowIdx(-1), fileIdx(-1) {}
|
| 472 |
+
CharSquare(int row, int file) : rowIdx(row), fileIdx(file) {}
|
| 473 |
+
};
|
| 474 |
+
|
| 475 |
+
inline bool operator==(const CharSquare& s1, const CharSquare& s2) {
|
| 476 |
+
return s1.rowIdx == s2.rowIdx && s1.fileIdx == s2.fileIdx;
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
inline bool operator!=(const CharSquare& s1, const CharSquare& s2) {
|
| 480 |
+
return !(s1 == s2);
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
inline int non_root_euclidian_distance(const CharSquare& s1, const CharSquare& s2) {
|
| 484 |
+
return pow(s1.rowIdx - s2.rowIdx, 2) + pow(s1.fileIdx - s2.fileIdx, 2);
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
class CharBoard {
|
| 488 |
+
private:
|
| 489 |
+
int nbRanks;
|
| 490 |
+
int nbFiles;
|
| 491 |
+
std::vector<char> board; // fill an array where the pieces are for later geometry checks
|
| 492 |
+
public:
|
| 493 |
+
CharBoard(int ranks, int files) : nbRanks(ranks), nbFiles(files) {
|
| 494 |
+
assert(nbFiles > 0 && nbRanks > 0);
|
| 495 |
+
board = std::vector<char>(nbRanks * nbFiles, ' ');
|
| 496 |
+
}
|
| 497 |
+
void set_piece(int rankIdx, int fileIdx, char c) {
|
| 498 |
+
board[rankIdx * nbFiles + fileIdx] = c;
|
| 499 |
+
}
|
| 500 |
+
char get_piece(int rowIdx, int fileIdx) const {
|
| 501 |
+
return board[rowIdx * nbFiles + fileIdx];
|
| 502 |
+
}
|
| 503 |
+
int get_nb_ranks() const {
|
| 504 |
+
return nbRanks;
|
| 505 |
+
}
|
| 506 |
+
int get_nb_files() const {
|
| 507 |
+
return nbFiles;
|
| 508 |
+
}
|
| 509 |
+
/// Returns the square of a given character
|
| 510 |
+
CharSquare get_square_for_piece(char piece) const {
|
| 511 |
+
CharSquare s;
|
| 512 |
+
for (int r = 0; r < nbRanks; ++r)
|
| 513 |
+
{
|
| 514 |
+
for (int c = 0; c < nbFiles; ++c)
|
| 515 |
+
{
|
| 516 |
+
if (get_piece(r, c) == piece)
|
| 517 |
+
{
|
| 518 |
+
s.rowIdx = r;
|
| 519 |
+
s.fileIdx = c;
|
| 520 |
+
return s;
|
| 521 |
+
}
|
| 522 |
+
}
|
| 523 |
+
}
|
| 524 |
+
return s;
|
| 525 |
+
}
|
| 526 |
+
/// Returns all square positions for a given piece
|
| 527 |
+
std::vector<CharSquare> get_squares_for_pieces(Color color, PieceSet ps, const std::string& pieceChars) const {
|
| 528 |
+
std::vector<CharSquare> squares;
|
| 529 |
+
size_t pcIdx;
|
| 530 |
+
for (int r = 0; r < nbRanks; ++r)
|
| 531 |
+
for (int c = 0; c < nbFiles; ++c)
|
| 532 |
+
if ((pcIdx = pieceChars.find(get_piece(r, c))) != std::string::npos && (ps & type_of(Piece(pcIdx))) && color_of(Piece(pcIdx)) == color)
|
| 533 |
+
squares.emplace_back(CharSquare(r, c));
|
| 534 |
+
return squares;
|
| 535 |
+
}
|
| 536 |
+
friend std::ostream& operator<<(std::ostream& os, const CharBoard& board);
|
| 537 |
+
};
|
| 538 |
+
|
| 539 |
+
inline std::ostream& operator<<(std::ostream& os, const CharBoard& board) {
|
| 540 |
+
for (int r = 0; r < board.nbRanks; ++r)
|
| 541 |
+
{
|
| 542 |
+
for (int c = 0; c < board.nbFiles; ++c)
|
| 543 |
+
os << "[" << board.get_piece(r, c) << "] ";
|
| 544 |
+
os << std::endl;
|
| 545 |
+
}
|
| 546 |
+
return os;
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
inline bool contains(const std::string& str, char c) {
|
| 550 |
+
return str.find(c) != std::string::npos;
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
inline bool in_any(const std::vector<std::string>& vec, char c) {
|
| 554 |
+
for (std::string str : vec)
|
| 555 |
+
if (contains(str, c))
|
| 556 |
+
return true;
|
| 557 |
+
return false;
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
inline Validation check_for_valid_characters(const std::string& firstFenPart, const std::string& validSpecialCharactersFirstField, const Variant* v) {
|
| 561 |
+
for (char c : firstFenPart)
|
| 562 |
+
{
|
| 563 |
+
if (!isdigit(c) && !in_any({v->pieceToChar, v->pieceToCharSynonyms, validSpecialCharactersFirstField}, c))
|
| 564 |
+
{
|
| 565 |
+
std::cerr << "Invalid piece character: '" << c << "'." << std::endl;
|
| 566 |
+
return NOK;
|
| 567 |
+
}
|
| 568 |
+
}
|
| 569 |
+
return OK;
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
inline Validation check_promoted_pieces(const std::string& firstFenPart, const Variant* v) {
|
| 573 |
+
// Only check promoted pieces if the variant supports shogi-style promotions
|
| 574 |
+
if (!v || !v->shogiStylePromotions)
|
| 575 |
+
return OK;
|
| 576 |
+
|
| 577 |
+
for (size_t i = 0; i < firstFenPart.length() - 1; ++i) {
|
| 578 |
+
// Look for promoted pieces ('+' followed by piece character)
|
| 579 |
+
if (firstFenPart[i] == '+') {
|
| 580 |
+
char pieceChar = firstFenPart[i + 1];
|
| 581 |
+
|
| 582 |
+
// Skip if next character is not a piece character or is a special character
|
| 583 |
+
if (isdigit(pieceChar) || pieceChar == '/' || pieceChar == ' ' || pieceChar == '[')
|
| 584 |
+
continue;
|
| 585 |
+
|
| 586 |
+
// Find the piece type corresponding to this character
|
| 587 |
+
size_t idx = v->pieceToChar.find(pieceChar);
|
| 588 |
+
if (idx == std::string::npos) {
|
| 589 |
+
// Try synonyms
|
| 590 |
+
idx = v->pieceToCharSynonyms.find(pieceChar);
|
| 591 |
+
if (idx == std::string::npos)
|
| 592 |
+
continue; // Character validation will catch this
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
// Ensure idx is within valid range for piece types
|
| 596 |
+
if (idx >= PIECE_TYPE_NB)
|
| 597 |
+
continue;
|
| 598 |
+
|
| 599 |
+
// Get the piece type directly from the index
|
| 600 |
+
PieceType pt = PieceType(idx);
|
| 601 |
+
|
| 602 |
+
// Check if this piece type has a promoted form
|
| 603 |
+
if (pt != NO_PIECE_TYPE && pt < PIECE_TYPE_NB && v->promotedPieceType[pt] == NO_PIECE_TYPE) {
|
| 604 |
+
std::cerr << "Invalid promoted piece: '+' followed by '" << pieceChar
|
| 605 |
+
<< "'. This piece cannot be promoted in variant." << std::endl;
|
| 606 |
+
return NOK;
|
| 607 |
+
}
|
| 608 |
+
}
|
| 609 |
+
}
|
| 610 |
+
return OK;
|
| 611 |
+
}
|
| 612 |
+
|
| 613 |
+
inline std::vector<std::string> get_fen_parts(const std::string& fullFen, char delim) {
|
| 614 |
+
std::vector<std::string> fenParts;
|
| 615 |
+
std::string curPart;
|
| 616 |
+
std::stringstream ss(fullFen);
|
| 617 |
+
while (std::getline(ss, curPart, delim))
|
| 618 |
+
fenParts.emplace_back(curPart);
|
| 619 |
+
return fenParts;
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
/// fills the character board according to a given FEN string
|
| 623 |
+
inline Validation fill_char_board(CharBoard& board, const std::string& fenBoard, const std::string& validSpecialCharactersFirstField, const Variant* v) {
|
| 624 |
+
int rankIdx = 0;
|
| 625 |
+
int fileIdx = 0;
|
| 626 |
+
|
| 627 |
+
char prevChar = '?';
|
| 628 |
+
for (char c : fenBoard)
|
| 629 |
+
{
|
| 630 |
+
if (c == ' ' || c == '[')
|
| 631 |
+
break;
|
| 632 |
+
if (c == '*')
|
| 633 |
+
++fileIdx;
|
| 634 |
+
else if (isdigit(c))
|
| 635 |
+
{
|
| 636 |
+
fileIdx += c - '0';
|
| 637 |
+
// if we have multiple digits attached we can add multiples of 9 to compute the resulting number (e.g. -> 21 = 2 + 2 * 9 + 1)
|
| 638 |
+
if (isdigit(prevChar))
|
| 639 |
+
fileIdx += 9 * (prevChar - '0');
|
| 640 |
+
}
|
| 641 |
+
else if (c == '/')
|
| 642 |
+
{
|
| 643 |
+
++rankIdx;
|
| 644 |
+
if (fileIdx != board.get_nb_files())
|
| 645 |
+
{
|
| 646 |
+
std::cerr << "curRankWidth != nbFiles: " << fileIdx << " != " << board.get_nb_files() << std::endl;
|
| 647 |
+
return NOK;
|
| 648 |
+
}
|
| 649 |
+
if (rankIdx == board.get_nb_ranks())
|
| 650 |
+
break;
|
| 651 |
+
fileIdx = 0;
|
| 652 |
+
}
|
| 653 |
+
else if (!contains(validSpecialCharactersFirstField, c))
|
| 654 |
+
{ // normal piece
|
| 655 |
+
if (fileIdx == board.get_nb_files())
|
| 656 |
+
{
|
| 657 |
+
std::cerr << "File index: " << fileIdx << " for piece '" << c << "' exceeds maximum of allowed number of files: " << board.get_nb_files() << "." << std::endl;
|
| 658 |
+
return NOK;
|
| 659 |
+
}
|
| 660 |
+
board.set_piece(v->maxRank-rankIdx, fileIdx, c); // we mirror the rank index because the black pieces are given first in the FEN
|
| 661 |
+
++fileIdx;
|
| 662 |
+
}
|
| 663 |
+
prevChar = c;
|
| 664 |
+
}
|
| 665 |
+
|
| 666 |
+
if (v->pieceDrops)
|
| 667 |
+
{ // pockets can either be defined by [] or /
|
| 668 |
+
if (rankIdx+1 != board.get_nb_ranks() && rankIdx != board.get_nb_ranks())
|
| 669 |
+
{
|
| 670 |
+
std::cerr << "Invalid number of ranks. Expected: " << board.get_nb_ranks() << " Actual: " << rankIdx+1 << std::endl;
|
| 671 |
+
return NOK;
|
| 672 |
+
}
|
| 673 |
+
}
|
| 674 |
+
else
|
| 675 |
+
{
|
| 676 |
+
if (rankIdx+1 != board.get_nb_ranks())
|
| 677 |
+
{
|
| 678 |
+
std::cerr << "Invalid number of ranks. Expected: " << board.get_nb_ranks() << " Actual: " << rankIdx+1 << std::endl;
|
| 679 |
+
return NOK;
|
| 680 |
+
}
|
| 681 |
+
}
|
| 682 |
+
return OK;
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
inline Validation check_touching_kings(const CharBoard& board, const std::array<CharSquare, 2>& kingPositions) {
|
| 686 |
+
if (non_root_euclidian_distance(kingPositions[WHITE], kingPositions[BLACK]) <= 2)
|
| 687 |
+
{
|
| 688 |
+
std::cerr << "King pieces are next to each other." << std::endl;
|
| 689 |
+
std::cerr << board << std::endl;
|
| 690 |
+
return NOK;
|
| 691 |
+
}
|
| 692 |
+
return OK;
|
| 693 |
+
}
|
| 694 |
+
|
| 695 |
+
inline Validation fill_castling_info_splitted(const std::string& castlingInfo, std::array<std::string, 2>& castlingInfoSplitted) {
|
| 696 |
+
for (char c : castlingInfo)
|
| 697 |
+
{
|
| 698 |
+
if (c != '-')
|
| 699 |
+
{
|
| 700 |
+
if (!isalpha(c))
|
| 701 |
+
{
|
| 702 |
+
std::cerr << "Invalid castling specification: '" << c << "'." << std::endl;
|
| 703 |
+
return NOK;
|
| 704 |
+
}
|
| 705 |
+
else if (isupper(c))
|
| 706 |
+
castlingInfoSplitted[WHITE] += tolower(c);
|
| 707 |
+
else
|
| 708 |
+
castlingInfoSplitted[BLACK] += c;
|
| 709 |
+
}
|
| 710 |
+
}
|
| 711 |
+
return OK;
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
inline std::string color_to_string(Color c) {
|
| 715 |
+
switch (c)
|
| 716 |
+
{
|
| 717 |
+
case WHITE:
|
| 718 |
+
return "WHITE";
|
| 719 |
+
case BLACK:
|
| 720 |
+
return "BLACK";
|
| 721 |
+
case COLOR_NB:
|
| 722 |
+
return "COLOR_NB";
|
| 723 |
+
default:
|
| 724 |
+
return "INVALID_COLOR";
|
| 725 |
+
}
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
inline std::string castling_rights_to_string(CastlingRights castlingRights) {
|
| 729 |
+
switch (castlingRights)
|
| 730 |
+
{
|
| 731 |
+
case KING_SIDE:
|
| 732 |
+
return "KING_SIDE";
|
| 733 |
+
case QUEEN_SIDE:
|
| 734 |
+
return "QUEENS_SIDE";
|
| 735 |
+
case WHITE_OO:
|
| 736 |
+
return "WHITE_OO";
|
| 737 |
+
case WHITE_OOO:
|
| 738 |
+
return "WHITE_OOO";
|
| 739 |
+
case BLACK_OO:
|
| 740 |
+
return "BLACK_OO";
|
| 741 |
+
case BLACK_OOO:
|
| 742 |
+
return "BLACK_OOO";
|
| 743 |
+
case WHITE_CASTLING:
|
| 744 |
+
return "WHITE_CASTLING";
|
| 745 |
+
case BLACK_CASTLING:
|
| 746 |
+
return "BLACK_CASTLING";
|
| 747 |
+
case ANY_CASTLING:
|
| 748 |
+
return "ANY_CASTLING";
|
| 749 |
+
case CASTLING_RIGHT_NB:
|
| 750 |
+
return "CASTLING_RIGHT_NB";
|
| 751 |
+
default:
|
| 752 |
+
return "INVALID_CASTLING_RIGHTS";
|
| 753 |
+
}
|
| 754 |
+
}
|
| 755 |
+
|
| 756 |
+
inline Validation check_castling_rank(const std::array<std::string, 2>& castlingInfoSplitted, const CharBoard& board,
|
| 757 |
+
const std::array<CharSquare, 2>& kingPositions, const Variant* v) {
|
| 758 |
+
|
| 759 |
+
for (Color c : {WHITE, BLACK})
|
| 760 |
+
{
|
| 761 |
+
const Rank castlingRank = relative_rank(c, v->castlingRank, v->maxRank);
|
| 762 |
+
for (char castlingFlag : castlingInfoSplitted[c])
|
| 763 |
+
{
|
| 764 |
+
if (tolower(castlingFlag) == 'k' || tolower(castlingFlag) == 'q')
|
| 765 |
+
{
|
| 766 |
+
if (kingPositions[c].rowIdx != castlingRank)
|
| 767 |
+
{
|
| 768 |
+
std::cerr << "The " << color_to_string(c) << " king must be on rank " << castlingRank << " if castling is enabled for " << color_to_string(c) << "." << std::endl;
|
| 769 |
+
return NOK;
|
| 770 |
+
}
|
| 771 |
+
bool kingside = tolower(castlingFlag) == 'k';
|
| 772 |
+
bool castlingRook = false;
|
| 773 |
+
size_t pcIdx;
|
| 774 |
+
for (int f = kingside ? board.get_nb_files() - 1 : 0; f != kingPositions[c].fileIdx; kingside ? f-- : f++)
|
| 775 |
+
if ( (pcIdx = v->pieceToChar.find(board.get_piece(castlingRank, f))) != std::string::npos
|
| 776 |
+
&& (v->castlingRookPieces[c] & type_of(Piece(pcIdx)))
|
| 777 |
+
&& color_of(Piece(pcIdx)) == c)
|
| 778 |
+
{
|
| 779 |
+
castlingRook = true;
|
| 780 |
+
break;
|
| 781 |
+
}
|
| 782 |
+
if (!castlingRook)
|
| 783 |
+
{
|
| 784 |
+
std::cerr << "No castling rook for flag " << castlingFlag << std::endl;
|
| 785 |
+
return NOK;
|
| 786 |
+
}
|
| 787 |
+
}
|
| 788 |
+
else if (board.get_piece(castlingRank, tolower(castlingFlag) - 'a') == ' ')
|
| 789 |
+
{
|
| 790 |
+
std::cerr << "No gating piece for flag " << castlingFlag << std::endl;
|
| 791 |
+
return NOK;
|
| 792 |
+
}
|
| 793 |
+
}
|
| 794 |
+
}
|
| 795 |
+
return OK;
|
| 796 |
+
}
|
| 797 |
+
|
| 798 |
+
inline Validation check_standard_castling(std::array<std::string, 2>& castlingInfoSplitted, const CharBoard& board,
|
| 799 |
+
const std::array<CharSquare, 2>& kingPositions, const std::array<CharSquare, 2>& kingPositionsStart,
|
| 800 |
+
const std::array<std::vector<CharSquare>, 2>& rookPositionsStart, const Variant* v) {
|
| 801 |
+
|
| 802 |
+
for (Color c : {WHITE, BLACK})
|
| 803 |
+
{
|
| 804 |
+
if (castlingInfoSplitted[c].size() == 0)
|
| 805 |
+
continue;
|
| 806 |
+
if (kingPositions[c] != kingPositionsStart[c])
|
| 807 |
+
{
|
| 808 |
+
std::cerr << "The " << color_to_string(c) << " KING has moved. Castling is no longer valid for " << color_to_string(c) << "." << std::endl;
|
| 809 |
+
return NOK;
|
| 810 |
+
}
|
| 811 |
+
|
| 812 |
+
for (CastlingRights castling: {KING_SIDE, QUEEN_SIDE})
|
| 813 |
+
{
|
| 814 |
+
CharSquare rookStartingSquare = castling == QUEEN_SIDE ? rookPositionsStart[c][0] : rookPositionsStart[c][1];
|
| 815 |
+
char targetChar = castling == QUEEN_SIDE ? 'q' : 'k';
|
| 816 |
+
size_t pcIdx;
|
| 817 |
+
if (castlingInfoSplitted[c].find(targetChar) != std::string::npos)
|
| 818 |
+
{
|
| 819 |
+
if ( (pcIdx = v->pieceToChar.find(board.get_piece(rookStartingSquare.rowIdx, rookStartingSquare.fileIdx))) == std::string::npos
|
| 820 |
+
|| !(v->castlingRookPieces[c] & type_of(Piece(pcIdx)))
|
| 821 |
+
|| color_of(Piece(pcIdx)) != c)
|
| 822 |
+
{
|
| 823 |
+
std::cerr << "The " << color_to_string(c) << " ROOK on the "<< castling_rights_to_string(castling) << " has moved. "
|
| 824 |
+
<< castling_rights_to_string(castling) << " castling is no longer valid for " << color_to_string(c) << "." << std::endl;
|
| 825 |
+
return NOK;
|
| 826 |
+
}
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
}
|
| 830 |
+
}
|
| 831 |
+
return OK;
|
| 832 |
+
}
|
| 833 |
+
|
| 834 |
+
inline Validation check_pocket_info(const std::string& fenBoard, int nbRanks, const Variant* v, std::string& pocket) {
|
| 835 |
+
|
| 836 |
+
char stopChar;
|
| 837 |
+
int offset = 0;
|
| 838 |
+
if (std::count(fenBoard.begin(), fenBoard.end(), '/') == nbRanks)
|
| 839 |
+
{
|
| 840 |
+
// look for last '/'
|
| 841 |
+
stopChar = '/';
|
| 842 |
+
}
|
| 843 |
+
else if (std::count(fenBoard.begin(), fenBoard.end(), '[') == 1)
|
| 844 |
+
{
|
| 845 |
+
// pocket is defined as [ and ]
|
| 846 |
+
stopChar = '[';
|
| 847 |
+
offset = 1;
|
| 848 |
+
if (*(fenBoard.end()-1) != ']')
|
| 849 |
+
{
|
| 850 |
+
std::cerr << "Pocket specification does not end with ']'." << std::endl;
|
| 851 |
+
return NOK;
|
| 852 |
+
}
|
| 853 |
+
}
|
| 854 |
+
else
|
| 855 |
+
// allow to skip pocket
|
| 856 |
+
return OK;
|
| 857 |
+
|
| 858 |
+
// look for last '/'
|
| 859 |
+
for (auto it = fenBoard.rbegin()+offset; it != fenBoard.rend(); ++it)
|
| 860 |
+
{
|
| 861 |
+
const char c = *it;
|
| 862 |
+
if (c == stopChar)
|
| 863 |
+
return OK;
|
| 864 |
+
if (c != '-')
|
| 865 |
+
{
|
| 866 |
+
if (!in_any({v->pieceToChar, v->pieceToCharSynonyms}, c))
|
| 867 |
+
{
|
| 868 |
+
std::cerr << "Invalid pocket piece: '" << c << "'." << std::endl;
|
| 869 |
+
return NOK;
|
| 870 |
+
}
|
| 871 |
+
else
|
| 872 |
+
pocket += c;
|
| 873 |
+
}
|
| 874 |
+
}
|
| 875 |
+
std::cerr << "Pocket piece closing character '" << stopChar << "' was not found." << std::endl;
|
| 876 |
+
return NOK;
|
| 877 |
+
}
|
| 878 |
+
|
| 879 |
+
inline int piece_count(const std::string& fenBoard, Color c, PieceType pt, const Variant* v) {
|
| 880 |
+
return std::count(fenBoard.begin(), fenBoard.end(), v->pieceToChar[make_piece(c, pt)]);
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
inline Validation check_number_of_kings(const std::string& fenBoard, const std::string& startFenBoard, const Variant* v) {
|
| 884 |
+
int nbWhiteKings = piece_count(fenBoard, WHITE, KING, v);
|
| 885 |
+
int nbBlackKings = piece_count(fenBoard, BLACK, KING, v);
|
| 886 |
+
int nbWhiteKingsStart = piece_count(startFenBoard, WHITE, KING, v);
|
| 887 |
+
int nbBlackKingsStart = piece_count(startFenBoard, BLACK, KING, v);
|
| 888 |
+
|
| 889 |
+
if (nbWhiteKings > 1)
|
| 890 |
+
{
|
| 891 |
+
std::cerr << "Invalid number of white kings. Maximum: 1. Given: " << nbWhiteKings << std::endl;
|
| 892 |
+
return NOK;
|
| 893 |
+
}
|
| 894 |
+
if (nbBlackKings > 1)
|
| 895 |
+
{
|
| 896 |
+
std::cerr << "Invalid number of black kings. Maximum: 1. Given: " << nbBlackKings << std::endl;
|
| 897 |
+
return NOK;
|
| 898 |
+
}
|
| 899 |
+
if (nbWhiteKings != nbWhiteKingsStart)
|
| 900 |
+
{
|
| 901 |
+
std::cerr << "Invalid number of white kings. Expected: " << nbWhiteKingsStart << ". Given: " << nbWhiteKings << std::endl;
|
| 902 |
+
return NOK;
|
| 903 |
+
}
|
| 904 |
+
if (nbBlackKings != nbBlackKingsStart)
|
| 905 |
+
{
|
| 906 |
+
std::cerr << "Invalid number of black kings. Expected: " << nbBlackKingsStart << ". Given: " << nbBlackKings << std::endl;
|
| 907 |
+
return NOK;
|
| 908 |
+
}
|
| 909 |
+
return OK;
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
|
| 913 |
+
inline Validation check_en_passant_square(const std::string& enPassantInfo) {
|
| 914 |
+
if (enPassantInfo.size() != 1 || enPassantInfo[0] != '-')
|
| 915 |
+
{
|
| 916 |
+
if (enPassantInfo.size() != 2)
|
| 917 |
+
{
|
| 918 |
+
std::cerr << "Invalid en-passant square '" << enPassantInfo << "'. Expects 2 characters. Actual: " << enPassantInfo.size() << " character(s)." << std::endl;
|
| 919 |
+
return NOK;
|
| 920 |
+
}
|
| 921 |
+
if (!isalpha(enPassantInfo[0]))
|
| 922 |
+
{
|
| 923 |
+
std::cerr << "Invalid en-passant square '" << enPassantInfo << "'. Expects 1st character to be a letter." << std::endl;
|
| 924 |
+
return NOK;
|
| 925 |
+
}
|
| 926 |
+
if (!isdigit(enPassantInfo[1]))
|
| 927 |
+
{
|
| 928 |
+
std::cerr << "Invalid en-passant square '" << enPassantInfo << "'. Expects 2nd character to be a digit." << std::endl;
|
| 929 |
+
return NOK;
|
| 930 |
+
}
|
| 931 |
+
}
|
| 932 |
+
return OK;
|
| 933 |
+
}
|
| 934 |
+
|
| 935 |
+
|
| 936 |
+
inline Validation check_check_count(const std::string& checkCountInfo) {
|
| 937 |
+
if (checkCountInfo.size() != 3)
|
| 938 |
+
{
|
| 939 |
+
std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 3 characters. Actual: " << checkCountInfo.size() << " character(s)." << std::endl;
|
| 940 |
+
return NOK;
|
| 941 |
+
}
|
| 942 |
+
if (!isdigit(checkCountInfo[0]))
|
| 943 |
+
{
|
| 944 |
+
std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 1st character to be a digit." << std::endl;
|
| 945 |
+
return NOK;
|
| 946 |
+
}
|
| 947 |
+
if (!isdigit(checkCountInfo[2])) {
|
| 948 |
+
std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 3rd character to be a digit." << std::endl;
|
| 949 |
+
return NOK;
|
| 950 |
+
}
|
| 951 |
+
return OK;
|
| 952 |
+
}
|
| 953 |
+
|
| 954 |
+
inline Validation check_lichess_check_count(const std::string& checkCountInfo) {
|
| 955 |
+
if (checkCountInfo.size() != 4)
|
| 956 |
+
{
|
| 957 |
+
std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 4 characters. Actual: " << checkCountInfo.size() << " character(s)." << std::endl;
|
| 958 |
+
return NOK;
|
| 959 |
+
}
|
| 960 |
+
if (!isdigit(checkCountInfo[1]) || checkCountInfo[1] - '0' > 3)
|
| 961 |
+
{
|
| 962 |
+
std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 2nd character to be a digit up to 3." << std::endl;
|
| 963 |
+
return NOK;
|
| 964 |
+
}
|
| 965 |
+
if (!isdigit(checkCountInfo[3]) || checkCountInfo[3] - '0' > 3) {
|
| 966 |
+
std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 4th character to be a digit up to 3." << std::endl;
|
| 967 |
+
return NOK;
|
| 968 |
+
}
|
| 969 |
+
return OK;
|
| 970 |
+
}
|
| 971 |
+
|
| 972 |
+
inline Validation check_digit_field(const std::string& field) {
|
| 973 |
+
if (field.size() == 1 && field[0] == '-')
|
| 974 |
+
return OK;
|
| 975 |
+
for (char c : field)
|
| 976 |
+
if (!isdigit(c))
|
| 977 |
+
return NOK;
|
| 978 |
+
return OK;
|
| 979 |
+
}
|
| 980 |
+
|
| 981 |
+
inline std::string get_valid_special_chars(const Variant* v) {
|
| 982 |
+
std::string validSpecialCharactersFirstField = "/*";
|
| 983 |
+
// Whether or not '-', '+', '~', '[', ']' are valid depends on the variant being played.
|
| 984 |
+
if (v->shogiStylePromotions)
|
| 985 |
+
validSpecialCharactersFirstField += '+';
|
| 986 |
+
if (v->promotionPieceTypes[WHITE] || v->promotionPieceTypes[BLACK])
|
| 987 |
+
validSpecialCharactersFirstField += '~';
|
| 988 |
+
if (!v->freeDrops && (v->pieceDrops || v->seirawanGating))
|
| 989 |
+
validSpecialCharactersFirstField += "[-]";
|
| 990 |
+
return validSpecialCharactersFirstField;
|
| 991 |
+
}
|
| 992 |
+
|
| 993 |
+
inline FenValidation validate_fen(const std::string& fen, const Variant* v, bool chess960 = false) {
|
| 994 |
+
|
| 995 |
+
const std::string validSpecialCharactersFirstField = get_valid_special_chars(v);
|
| 996 |
+
// 0) Layout
|
| 997 |
+
// check for empty fen
|
| 998 |
+
if (fen.empty())
|
| 999 |
+
{
|
| 1000 |
+
std::cerr << "Fen is empty." << std::endl;
|
| 1001 |
+
return FEN_EMPTY;
|
| 1002 |
+
}
|
| 1003 |
+
|
| 1004 |
+
std::vector<std::string> fenParts = get_fen_parts(fen, ' ');
|
| 1005 |
+
std::vector<std::string> startFenParts = get_fen_parts(v->startFen, ' ');
|
| 1006 |
+
|
| 1007 |
+
// check for number of parts
|
| 1008 |
+
const unsigned int maxNumberFenParts = 6 + v->checkCounting;
|
| 1009 |
+
if (fenParts.size() < 1 || fenParts.size() > maxNumberFenParts)
|
| 1010 |
+
{
|
| 1011 |
+
std::cerr << "Invalid number of fen parts. Expected: >= 1 and <= " << maxNumberFenParts
|
| 1012 |
+
<< " Actual: " << fenParts.size() << std::endl;
|
| 1013 |
+
return FEN_INVALID_NB_PARTS;
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
// 1) Part
|
| 1017 |
+
// check for valid characters
|
| 1018 |
+
if (check_for_valid_characters(fenParts[0], validSpecialCharactersFirstField, v) == NOK)
|
| 1019 |
+
return FEN_INVALID_CHAR;
|
| 1020 |
+
|
| 1021 |
+
// check for valid promoted pieces
|
| 1022 |
+
if (check_promoted_pieces(fenParts[0], v) == NOK)
|
| 1023 |
+
return FEN_INVALID_PROMOTED_PIECE;
|
| 1024 |
+
|
| 1025 |
+
// check for number of ranks
|
| 1026 |
+
const int nbRanks = v->maxRank + 1;
|
| 1027 |
+
// check for number of files
|
| 1028 |
+
const int nbFiles = v->maxFile + 1;
|
| 1029 |
+
CharBoard board(nbRanks, nbFiles); // create a 2D character board for later geometry checks
|
| 1030 |
+
|
| 1031 |
+
if (fill_char_board(board, fenParts[0], validSpecialCharactersFirstField, v) == NOK)
|
| 1032 |
+
return FEN_INVALID_BOARD_GEOMETRY;
|
| 1033 |
+
|
| 1034 |
+
// check for pocket
|
| 1035 |
+
std::string pocket = "";
|
| 1036 |
+
if (v->pieceDrops || v->seirawanGating)
|
| 1037 |
+
{
|
| 1038 |
+
if (check_pocket_info(fenParts[0], nbRanks, v, pocket) == NOK)
|
| 1039 |
+
return FEN_INVALID_POCKET_INFO;
|
| 1040 |
+
}
|
| 1041 |
+
|
| 1042 |
+
// check for number of kings
|
| 1043 |
+
if (v->pieceTypes & KING)
|
| 1044 |
+
{
|
| 1045 |
+
// we have a royal king in this variant,
|
| 1046 |
+
// ensure that each side has exactly as many kings as in the starting position
|
| 1047 |
+
// (variants like giveaway use the COMMONER piece type instead)
|
| 1048 |
+
if (check_number_of_kings(fenParts[0], startFenParts[0], v) == NOK)
|
| 1049 |
+
return FEN_INVALID_NUMBER_OF_KINGS;
|
| 1050 |
+
|
| 1051 |
+
// check for touching kings if there are exactly two royal kings on the board (excluding pocket)
|
| 1052 |
+
if ( v->kingType == KING
|
| 1053 |
+
&& piece_count(fenParts[0], WHITE, KING, v) - piece_count(pocket, WHITE, KING, v) == 1
|
| 1054 |
+
&& piece_count(fenParts[0], BLACK, KING, v) - piece_count(pocket, BLACK, KING, v) == 1)
|
| 1055 |
+
{
|
| 1056 |
+
std::array<CharSquare, 2> kingPositions;
|
| 1057 |
+
kingPositions[WHITE] = board.get_square_for_piece(v->pieceToChar[make_piece(WHITE, KING)]);
|
| 1058 |
+
kingPositions[BLACK] = board.get_square_for_piece(v->pieceToChar[make_piece(BLACK, KING)]);
|
| 1059 |
+
if (check_touching_kings(board, kingPositions) == NOK)
|
| 1060 |
+
return FEN_TOUCHING_KINGS;
|
| 1061 |
+
}
|
| 1062 |
+
}
|
| 1063 |
+
|
| 1064 |
+
// 2) Part
|
| 1065 |
+
// check side to move char
|
| 1066 |
+
if (fenParts.size() >= 2 && fenParts[1][0] != 'w' && fenParts[1][0] != 'b')
|
| 1067 |
+
{
|
| 1068 |
+
std::cerr << "Invalid side to move specification: '" << fenParts[1][0] << "'." << std::endl;
|
| 1069 |
+
return FEN_INVALID_SIDE_TO_MOVE;
|
| 1070 |
+
}
|
| 1071 |
+
|
| 1072 |
+
// Castling and en passant can be skipped
|
| 1073 |
+
bool skipCastlingAndEp = fenParts.size() >= 4 && fenParts.size() <= 5 && isdigit(fenParts[2][0]);
|
| 1074 |
+
|
| 1075 |
+
// 3) Part
|
| 1076 |
+
// check castling rights
|
| 1077 |
+
if (fenParts.size() >= 3 && !skipCastlingAndEp && v->castling)
|
| 1078 |
+
{
|
| 1079 |
+
std::array<std::string, 2> castlingInfoSplitted;
|
| 1080 |
+
if (fill_castling_info_splitted(fenParts[2], castlingInfoSplitted) == NOK)
|
| 1081 |
+
return FEN_INVALID_CASTLING_INFO;
|
| 1082 |
+
|
| 1083 |
+
if (castlingInfoSplitted[WHITE].size() != 0 || castlingInfoSplitted[BLACK].size() != 0)
|
| 1084 |
+
{
|
| 1085 |
+
std::array<CharSquare, 2> kingPositions;
|
| 1086 |
+
kingPositions[WHITE] = board.get_square_for_piece(toupper(v->pieceToChar[v->castlingKingPiece[WHITE]]));
|
| 1087 |
+
kingPositions[BLACK] = board.get_square_for_piece(tolower(v->pieceToChar[v->castlingKingPiece[BLACK]]));
|
| 1088 |
+
|
| 1089 |
+
CharBoard startBoard(board.get_nb_ranks(), board.get_nb_files());
|
| 1090 |
+
fill_char_board(startBoard, v->startFen, validSpecialCharactersFirstField, v);
|
| 1091 |
+
|
| 1092 |
+
// Check pieces present on castling rank against castling/gating rights
|
| 1093 |
+
if (check_castling_rank(castlingInfoSplitted, board, kingPositions, v) == NOK)
|
| 1094 |
+
return FEN_INVALID_CASTLING_INFO;
|
| 1095 |
+
|
| 1096 |
+
// only check exact squares if starting position of castling pieces is known
|
| 1097 |
+
if (!v->chess960 && !v->castlingDroppedPiece && !chess960)
|
| 1098 |
+
{
|
| 1099 |
+
std::array<CharSquare, 2> kingPositionsStart;
|
| 1100 |
+
kingPositionsStart[WHITE] = startBoard.get_square_for_piece(v->pieceToChar[make_piece(WHITE, v->castlingKingPiece[WHITE])]);
|
| 1101 |
+
kingPositionsStart[BLACK] = startBoard.get_square_for_piece(v->pieceToChar[make_piece(BLACK, v->castlingKingPiece[BLACK])]);
|
| 1102 |
+
std::array<std::vector<CharSquare>, 2> rookPositionsStart;
|
| 1103 |
+
rookPositionsStart[WHITE] = startBoard.get_squares_for_pieces(WHITE, v->castlingRookPieces[WHITE], v->pieceToChar);
|
| 1104 |
+
rookPositionsStart[BLACK] = startBoard.get_squares_for_pieces(BLACK, v->castlingRookPieces[BLACK], v->pieceToChar);
|
| 1105 |
+
|
| 1106 |
+
if (check_standard_castling(castlingInfoSplitted, board, kingPositions, kingPositionsStart, rookPositionsStart, v) == NOK)
|
| 1107 |
+
return FEN_INVALID_CASTLING_INFO;
|
| 1108 |
+
}
|
| 1109 |
+
}
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
// 4) Part
|
| 1113 |
+
// check en-passant square
|
| 1114 |
+
if (fenParts.size() >= 4 && !skipCastlingAndEp)
|
| 1115 |
+
{
|
| 1116 |
+
if (v->doubleStep && (v->pieceTypes & PAWN))
|
| 1117 |
+
{
|
| 1118 |
+
if (check_en_passant_square(fenParts[3]) == NOK)
|
| 1119 |
+
return FEN_INVALID_EN_PASSANT_SQ;
|
| 1120 |
+
}
|
| 1121 |
+
else if (v->countingRule && !check_digit_field(fenParts[3]))
|
| 1122 |
+
return FEN_INVALID_COUNTING_RULE;
|
| 1123 |
+
}
|
| 1124 |
+
|
| 1125 |
+
// 5) Part
|
| 1126 |
+
// check check count
|
| 1127 |
+
unsigned int optionalInbetweenFields = 2 * !skipCastlingAndEp;
|
| 1128 |
+
unsigned int optionalTrailingFields = 0;
|
| 1129 |
+
if (fenParts.size() >= 3 + optionalInbetweenFields && v->checkCounting && fenParts.size() % 2)
|
| 1130 |
+
{
|
| 1131 |
+
if (check_check_count(fenParts[2 + optionalInbetweenFields]) == NOK)
|
| 1132 |
+
{
|
| 1133 |
+
// allow valid lichess style check as alternative
|
| 1134 |
+
if (fenParts.size() < 5 + optionalInbetweenFields || check_lichess_check_count(fenParts[fenParts.size() - 1]) == NOK)
|
| 1135 |
+
return FEN_INVALID_CHECK_COUNT;
|
| 1136 |
+
else
|
| 1137 |
+
optionalTrailingFields++;
|
| 1138 |
+
}
|
| 1139 |
+
else
|
| 1140 |
+
optionalInbetweenFields++;
|
| 1141 |
+
}
|
| 1142 |
+
|
| 1143 |
+
// 6) Part
|
| 1144 |
+
// check half move counter
|
| 1145 |
+
if (fenParts.size() >= 3 + optionalInbetweenFields && !check_digit_field(fenParts[fenParts.size() - 2 - optionalTrailingFields]))
|
| 1146 |
+
{
|
| 1147 |
+
std::cerr << "Invalid half move counter: '" << fenParts[fenParts.size()-2] << "'." << std::endl;
|
| 1148 |
+
return FEN_INVALID_HALF_MOVE_COUNTER;
|
| 1149 |
+
}
|
| 1150 |
+
|
| 1151 |
+
// 7) Part
|
| 1152 |
+
// check move counter
|
| 1153 |
+
if (fenParts.size() >= 4 + optionalInbetweenFields && !check_digit_field(fenParts[fenParts.size() - 1 - optionalTrailingFields]))
|
| 1154 |
+
{
|
| 1155 |
+
std::cerr << "Invalid move counter: '" << fenParts[fenParts.size()-1] << "'." << std::endl;
|
| 1156 |
+
return FEN_INVALID_MOVE_COUNTER;
|
| 1157 |
+
}
|
| 1158 |
+
|
| 1159 |
+
return FEN_OK;
|
| 1160 |
+
}
|
| 1161 |
+
} // namespace FEN
|
| 1162 |
+
|
| 1163 |
+
} // namespace Stockfish
|
| 1164 |
+
|
| 1165 |
+
#endif // #ifndef APIUTIL_H_INCLUDED
|
Fairy-Stockfish-master/src/benchmark.cpp
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <fstream>
|
| 20 |
+
#include <iostream>
|
| 21 |
+
#include <istream>
|
| 22 |
+
#include <vector>
|
| 23 |
+
|
| 24 |
+
#include "position.h"
|
| 25 |
+
#include "uci.h"
|
| 26 |
+
|
| 27 |
+
using namespace std;
|
| 28 |
+
|
| 29 |
+
namespace {
|
| 30 |
+
|
| 31 |
+
const vector<string> Defaults = {
|
| 32 |
+
"setoption name UCI_Chess960 value false",
|
| 33 |
+
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
| 34 |
+
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
|
| 35 |
+
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11",
|
| 36 |
+
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
|
| 37 |
+
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14 moves d4e6",
|
| 38 |
+
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14 moves g2g4",
|
| 39 |
+
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15",
|
| 40 |
+
"r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13",
|
| 41 |
+
"r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16",
|
| 42 |
+
"4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17",
|
| 43 |
+
"2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11",
|
| 44 |
+
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
|
| 45 |
+
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
|
| 46 |
+
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
|
| 47 |
+
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
|
| 48 |
+
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26",
|
| 49 |
+
"6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1",
|
| 50 |
+
"3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1",
|
| 51 |
+
"2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1 moves g5g6 f3e3 g6g5 e3f3",
|
| 52 |
+
"8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1",
|
| 53 |
+
"7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1",
|
| 54 |
+
"8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1",
|
| 55 |
+
"8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1",
|
| 56 |
+
"8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1",
|
| 57 |
+
"8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1",
|
| 58 |
+
"5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1",
|
| 59 |
+
"6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1",
|
| 60 |
+
"1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1",
|
| 61 |
+
"6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1",
|
| 62 |
+
"8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1",
|
| 63 |
+
"5rk1/q6p/2p3bR/1pPp1rP1/1P1Pp3/P3B1Q1/1K3P2/R7 w - - 93 90",
|
| 64 |
+
"4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21",
|
| 65 |
+
"r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16",
|
| 66 |
+
"3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40",
|
| 67 |
+
"4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1",
|
| 68 |
+
|
| 69 |
+
// 5-man positions
|
| 70 |
+
"8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate
|
| 71 |
+
"8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", // Na2 - mate
|
| 72 |
+
"8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", // draw
|
| 73 |
+
|
| 74 |
+
// 6-man positions
|
| 75 |
+
"8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", // Re5 - mate
|
| 76 |
+
"8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", // Ka2 - mate
|
| 77 |
+
"8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw
|
| 78 |
+
|
| 79 |
+
// 7-man positions
|
| 80 |
+
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw
|
| 81 |
+
|
| 82 |
+
// Mate and stalemate positions
|
| 83 |
+
"6k1/3b3r/1p1p4/p1n2p2/1PPNpP1q/P3Q1p1/1R1RB1P1/5K2 b - - 0 1",
|
| 84 |
+
"r2r1n2/pp2bk2/2p1p2p/3q4/3PN1QP/2P3R1/P4PP1/5RK1 w - - 0 1",
|
| 85 |
+
"8/8/8/8/8/6k1/6p1/6K1 w - -",
|
| 86 |
+
"7k/7P/6K1/8/3B4/8/8/8 b - -",
|
| 87 |
+
|
| 88 |
+
// Chess 960
|
| 89 |
+
"setoption name UCI_Chess960 value true",
|
| 90 |
+
"bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w HFhf - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6",
|
| 91 |
+
"setoption name UCI_Chess960 value false"
|
| 92 |
+
};
|
| 93 |
+
|
| 94 |
+
} // namespace
|
| 95 |
+
|
| 96 |
+
namespace Stockfish {
|
| 97 |
+
|
| 98 |
+
/// setup_bench() builds a list of UCI commands to be run by bench. There
|
| 99 |
+
/// are five parameters: TT size in MB, number of search threads that
|
| 100 |
+
/// should be used, the limit value spent for each position, a file name
|
| 101 |
+
/// where to look for positions in FEN format, the type of the limit:
|
| 102 |
+
/// depth, perft, nodes and movetime (in millisecs), and evaluation type
|
| 103 |
+
/// mixed (default), classical, NNUE.
|
| 104 |
+
///
|
| 105 |
+
/// bench -> search default positions up to depth 13
|
| 106 |
+
/// bench 64 1 15 -> search default positions up to depth 15 (TT = 64MB)
|
| 107 |
+
/// bench 64 4 5000 current movetime -> search current position with 4 threads for 5 sec
|
| 108 |
+
/// bench 64 1 100000 default nodes -> search default positions for 100K nodes each
|
| 109 |
+
/// bench 16 1 5 default perft -> run a perft 5 on default positions
|
| 110 |
+
|
| 111 |
+
vector<string> setup_bench(const Position& current, istream& is) {
|
| 112 |
+
|
| 113 |
+
vector<string> fens, list;
|
| 114 |
+
string go, token, varname;
|
| 115 |
+
|
| 116 |
+
streampos args = is.tellg();
|
| 117 |
+
// Check whether the next token is a variant name
|
| 118 |
+
if ((is >> token) && variants.find(token) != variants.end())
|
| 119 |
+
{
|
| 120 |
+
args = is.tellg();
|
| 121 |
+
varname = token;
|
| 122 |
+
}
|
| 123 |
+
else
|
| 124 |
+
{
|
| 125 |
+
is.seekg(args);
|
| 126 |
+
varname = string(Options["UCI_Variant"]);
|
| 127 |
+
}
|
| 128 |
+
const Variant* variant = variants.find(varname)->second;
|
| 129 |
+
|
| 130 |
+
// Assign default values to missing arguments
|
| 131 |
+
string ttSize = (is >> token) ? token : "16";
|
| 132 |
+
string threads = (is >> token) ? token : "1";
|
| 133 |
+
string limit = (is >> token) ? token : "13";
|
| 134 |
+
string fenFile = (is >> token) ? token : "default";
|
| 135 |
+
string limitType = (is >> token) ? token : "depth";
|
| 136 |
+
string evalType = (is >> token) ? token : "mixed";
|
| 137 |
+
|
| 138 |
+
go = limitType == "eval" ? "eval" : "go " + limitType + " " + limit;
|
| 139 |
+
|
| 140 |
+
if (fenFile == "default")
|
| 141 |
+
{
|
| 142 |
+
if (varname != "chess")
|
| 143 |
+
fens.push_back(variant->startFen);
|
| 144 |
+
else
|
| 145 |
+
fens = Defaults;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
else if (fenFile == "current")
|
| 149 |
+
fens.push_back(current.fen());
|
| 150 |
+
|
| 151 |
+
else
|
| 152 |
+
{
|
| 153 |
+
string fen;
|
| 154 |
+
ifstream file(fenFile);
|
| 155 |
+
|
| 156 |
+
if (!file.is_open())
|
| 157 |
+
{
|
| 158 |
+
cerr << "Unable to open file " << fenFile << endl;
|
| 159 |
+
exit(EXIT_FAILURE);
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
while (getline(file, fen))
|
| 163 |
+
if (!fen.empty())
|
| 164 |
+
fens.push_back(fen);
|
| 165 |
+
|
| 166 |
+
file.close();
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
list.emplace_back("setoption name Threads value " + threads);
|
| 170 |
+
list.emplace_back("setoption name Hash value " + ttSize);
|
| 171 |
+
list.emplace_back("setoption name UCI_Variant value " + varname);
|
| 172 |
+
list.emplace_back("ucinewgame");
|
| 173 |
+
|
| 174 |
+
size_t posCounter = 0;
|
| 175 |
+
|
| 176 |
+
for (const string& fen : fens)
|
| 177 |
+
if (fen.find("setoption") != string::npos)
|
| 178 |
+
list.emplace_back(fen);
|
| 179 |
+
else
|
| 180 |
+
{
|
| 181 |
+
if (evalType == "classical" || (evalType == "mixed" && posCounter % 2 == 0))
|
| 182 |
+
list.emplace_back("setoption name Use NNUE value false");
|
| 183 |
+
else if (evalType == "NNUE" || (evalType == "mixed" && posCounter % 2 != 0))
|
| 184 |
+
list.emplace_back("setoption name Use NNUE value true");
|
| 185 |
+
list.emplace_back("position fen " + fen);
|
| 186 |
+
list.emplace_back(go);
|
| 187 |
+
++posCounter;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
list.emplace_back("setoption name Use NNUE value true");
|
| 191 |
+
|
| 192 |
+
return list;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/bitbase.cpp
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <cassert>
|
| 20 |
+
#include <vector>
|
| 21 |
+
#include <bitset>
|
| 22 |
+
|
| 23 |
+
#include "bitboard.h"
|
| 24 |
+
#include "types.h"
|
| 25 |
+
|
| 26 |
+
namespace Stockfish {
|
| 27 |
+
|
| 28 |
+
namespace {
|
| 29 |
+
|
| 30 |
+
// There are 24 possible pawn squares: files A to D and ranks from 2 to 7.
|
| 31 |
+
// Positions with the pawn on files E to H will be mirrored before probing.
|
| 32 |
+
constexpr unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608
|
| 33 |
+
|
| 34 |
+
std::bitset<MAX_INDEX> KPKBitbase;
|
| 35 |
+
|
| 36 |
+
// A KPK bitbase index is an integer in [0, IndexMax] range
|
| 37 |
+
//
|
| 38 |
+
// Information is mapped in a way that minimizes the number of iterations:
|
| 39 |
+
//
|
| 40 |
+
// bit 0- 5: white king square (from SQ_A1 to SQ_H8)
|
| 41 |
+
// bit 6-11: black king square (from SQ_A1 to SQ_H8)
|
| 42 |
+
// bit 12: side to move (WHITE or BLACK)
|
| 43 |
+
// bit 13-14: white pawn file (from FILE_A to FILE_D)
|
| 44 |
+
// bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
|
| 45 |
+
unsigned index(Color stm, Square bksq, Square wksq, Square psq) {
|
| 46 |
+
return int(wksq) | (bksq << 6) | (stm << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
enum Result {
|
| 50 |
+
INVALID = 0,
|
| 51 |
+
UNKNOWN = 1,
|
| 52 |
+
DRAW = 2,
|
| 53 |
+
WIN = 4
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
|
| 57 |
+
|
| 58 |
+
struct KPKPosition {
|
| 59 |
+
KPKPosition() = default;
|
| 60 |
+
explicit KPKPosition(unsigned idx);
|
| 61 |
+
operator Result() const { return result; }
|
| 62 |
+
Result classify(const std::vector<KPKPosition>& db);
|
| 63 |
+
|
| 64 |
+
Color stm;
|
| 65 |
+
Square ksq[COLOR_NB], psq;
|
| 66 |
+
Result result;
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
} // namespace
|
| 70 |
+
|
| 71 |
+
bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) {
|
| 72 |
+
|
| 73 |
+
assert(file_of(wpsq) <= FILE_D);
|
| 74 |
+
|
| 75 |
+
return KPKBitbase[index(stm, bksq, wksq, wpsq)];
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
void Bitbases::init() {
|
| 80 |
+
|
| 81 |
+
#ifdef LARGEBOARDS
|
| 82 |
+
// Bitbases are not working for large-board version
|
| 83 |
+
return;
|
| 84 |
+
#endif
|
| 85 |
+
|
| 86 |
+
std::vector<KPKPosition> db(MAX_INDEX);
|
| 87 |
+
unsigned idx, repeat = 1;
|
| 88 |
+
|
| 89 |
+
// Initialize db with known win / draw positions
|
| 90 |
+
for (idx = 0; idx < MAX_INDEX; ++idx)
|
| 91 |
+
db[idx] = KPKPosition(idx);
|
| 92 |
+
|
| 93 |
+
// Iterate through the positions until none of the unknown positions can be
|
| 94 |
+
// changed to either wins or draws (15 cycles needed).
|
| 95 |
+
while (repeat)
|
| 96 |
+
for (repeat = idx = 0; idx < MAX_INDEX; ++idx)
|
| 97 |
+
repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN);
|
| 98 |
+
|
| 99 |
+
// Fill the bitbase with the decisive results
|
| 100 |
+
for (idx = 0; idx < MAX_INDEX; ++idx)
|
| 101 |
+
if (db[idx] == WIN)
|
| 102 |
+
KPKBitbase.set(idx);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
namespace {
|
| 106 |
+
|
| 107 |
+
KPKPosition::KPKPosition(unsigned idx) {
|
| 108 |
+
|
| 109 |
+
ksq[WHITE] = Square((idx >> 0) & 0x3F);
|
| 110 |
+
ksq[BLACK] = Square((idx >> 6) & 0x3F);
|
| 111 |
+
stm = Color ((idx >> 12) & 0x01);
|
| 112 |
+
psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));
|
| 113 |
+
|
| 114 |
+
// Invalid if two pieces are on the same square or if a king can be captured
|
| 115 |
+
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|
| 116 |
+
|| ksq[WHITE] == psq
|
| 117 |
+
|| ksq[BLACK] == psq
|
| 118 |
+
|| (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK])))
|
| 119 |
+
result = INVALID;
|
| 120 |
+
|
| 121 |
+
// Win if the pawn can be promoted without getting captured
|
| 122 |
+
else if ( stm == WHITE
|
| 123 |
+
&& rank_of(psq) == RANK_7
|
| 124 |
+
&& ksq[WHITE] != psq + NORTH
|
| 125 |
+
&& ( distance(ksq[BLACK], psq + NORTH) > 1
|
| 126 |
+
|| (distance(ksq[WHITE], psq + NORTH) == 1)))
|
| 127 |
+
result = WIN;
|
| 128 |
+
|
| 129 |
+
// Draw if it is stalemate or the black king can capture the pawn
|
| 130 |
+
else if ( stm == BLACK
|
| 131 |
+
&& ( !(attacks_bb<KING>(ksq[BLACK]) & ~(attacks_bb<KING>(ksq[WHITE]) | pawn_attacks_bb(WHITE, psq)))
|
| 132 |
+
|| (attacks_bb<KING>(ksq[BLACK]) & ~attacks_bb<KING>(ksq[WHITE]) & psq)))
|
| 133 |
+
result = DRAW;
|
| 134 |
+
|
| 135 |
+
// Position will be classified later
|
| 136 |
+
else
|
| 137 |
+
result = UNKNOWN;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
|
| 141 |
+
|
| 142 |
+
// White to move: If one move leads to a position classified as WIN, the result
|
| 143 |
+
// of the current position is WIN. If all moves lead to positions classified
|
| 144 |
+
// as DRAW, the current position is classified as DRAW, otherwise the current
|
| 145 |
+
// position is classified as UNKNOWN.
|
| 146 |
+
//
|
| 147 |
+
// Black to move: If one move leads to a position classified as DRAW, the result
|
| 148 |
+
// of the current position is DRAW. If all moves lead to positions classified
|
| 149 |
+
// as WIN, the position is classified as WIN, otherwise the current position is
|
| 150 |
+
// classified as UNKNOWN.
|
| 151 |
+
const Result Good = (stm == WHITE ? WIN : DRAW);
|
| 152 |
+
const Result Bad = (stm == WHITE ? DRAW : WIN);
|
| 153 |
+
|
| 154 |
+
Result r = INVALID;
|
| 155 |
+
Bitboard b = attacks_bb<KING>(ksq[stm]);
|
| 156 |
+
|
| 157 |
+
while (b)
|
| 158 |
+
r |= stm == WHITE ? db[index(BLACK, ksq[BLACK], pop_lsb(b), psq)]
|
| 159 |
+
: db[index(WHITE, pop_lsb(b), ksq[WHITE], psq)];
|
| 160 |
+
|
| 161 |
+
if (stm == WHITE)
|
| 162 |
+
{
|
| 163 |
+
if (rank_of(psq) < RANK_7) // Single push
|
| 164 |
+
r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH)];
|
| 165 |
+
|
| 166 |
+
if ( rank_of(psq) == RANK_2 // Double push
|
| 167 |
+
&& psq + NORTH != ksq[WHITE]
|
| 168 |
+
&& psq + NORTH != ksq[BLACK])
|
| 169 |
+
r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH + NORTH)];
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad;
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
} // namespace
|
| 176 |
+
|
| 177 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/bitboard.cpp
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <algorithm>
|
| 20 |
+
#include <bitset>
|
| 21 |
+
|
| 22 |
+
#include "bitboard.h"
|
| 23 |
+
#include "magic.h"
|
| 24 |
+
#include "misc.h"
|
| 25 |
+
#include "piece.h"
|
| 26 |
+
|
| 27 |
+
namespace Stockfish {
|
| 28 |
+
|
| 29 |
+
uint8_t PopCnt16[1 << 16];
|
| 30 |
+
uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
| 31 |
+
|
| 32 |
+
Bitboard SquareBB[SQUARE_NB];
|
| 33 |
+
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
| 34 |
+
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
| 35 |
+
Bitboard PseudoAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 36 |
+
Bitboard PseudoMoves[2][COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 37 |
+
Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 38 |
+
Bitboard LeaperMoves[2][COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 39 |
+
Bitboard BoardSizeBB[FILE_NB][RANK_NB];
|
| 40 |
+
RiderType AttackRiderTypes[PIECE_TYPE_NB];
|
| 41 |
+
RiderType MoveRiderTypes[2][PIECE_TYPE_NB];
|
| 42 |
+
|
| 43 |
+
Magic RookMagicsH[SQUARE_NB];
|
| 44 |
+
Magic RookMagicsV[SQUARE_NB];
|
| 45 |
+
Magic BishopMagics[SQUARE_NB];
|
| 46 |
+
Magic CannonMagicsH[SQUARE_NB];
|
| 47 |
+
Magic CannonMagicsV[SQUARE_NB];
|
| 48 |
+
Magic LameDabbabaMagics[SQUARE_NB];
|
| 49 |
+
Magic HorseMagics[SQUARE_NB];
|
| 50 |
+
Magic ElephantMagics[SQUARE_NB];
|
| 51 |
+
Magic JanggiElephantMagics[SQUARE_NB];
|
| 52 |
+
Magic CannonDiagMagics[SQUARE_NB];
|
| 53 |
+
Magic NightriderMagics[SQUARE_NB];
|
| 54 |
+
Magic GrasshopperMagicsH[SQUARE_NB];
|
| 55 |
+
Magic GrasshopperMagicsV[SQUARE_NB];
|
| 56 |
+
Magic GrasshopperMagicsD[SQUARE_NB];
|
| 57 |
+
|
| 58 |
+
Magic* magics[] = {BishopMagics, RookMagicsH, RookMagicsV, CannonMagicsH, CannonMagicsV,
|
| 59 |
+
LameDabbabaMagics, HorseMagics, ElephantMagics, JanggiElephantMagics, CannonDiagMagics, NightriderMagics,
|
| 60 |
+
GrasshopperMagicsH, GrasshopperMagicsV, GrasshopperMagicsD};
|
| 61 |
+
|
| 62 |
+
namespace {
|
| 63 |
+
|
| 64 |
+
// Some magics need to be split in order to reduce memory consumption.
|
| 65 |
+
// Otherwise on a 12x10 board they can be >100 MB.
|
| 66 |
+
#ifdef LARGEBOARDS
|
| 67 |
+
Bitboard RookTableH[0x11800]; // To store horizontal rook attacks
|
| 68 |
+
Bitboard RookTableV[0x4800]; // To store vertical rook attacks
|
| 69 |
+
Bitboard BishopTable[0x33C00]; // To store bishop attacks
|
| 70 |
+
Bitboard CannonTableH[0x11800]; // To store horizontal cannon attacks
|
| 71 |
+
Bitboard CannonTableV[0x4800]; // To store vertical cannon attacks
|
| 72 |
+
Bitboard LameDabbabaTable[0x500]; // To store lame dabbaba attacks
|
| 73 |
+
Bitboard HorseTable[0x500]; // To store horse attacks
|
| 74 |
+
Bitboard ElephantTable[0x400]; // To store elephant attacks
|
| 75 |
+
Bitboard JanggiElephantTable[0x1C000]; // To store janggi elephant attacks
|
| 76 |
+
Bitboard CannonDiagTable[0x33C00]; // To store diagonal cannon attacks
|
| 77 |
+
Bitboard NightriderTable[0x70200]; // To store nightrider attacks
|
| 78 |
+
Bitboard GrasshopperTableH[0x11800]; // To store horizontal grasshopper attacks
|
| 79 |
+
Bitboard GrasshopperTableV[0x4800]; // To store vertical grasshopper attacks
|
| 80 |
+
Bitboard GrasshopperTableD[0x33C00]; // To store diagonal grasshopper attacks
|
| 81 |
+
#else
|
| 82 |
+
Bitboard RookTableH[0xA00]; // To store horizontal rook attacks
|
| 83 |
+
Bitboard RookTableV[0xA00]; // To store vertical rook attacks
|
| 84 |
+
Bitboard BishopTable[0x1480]; // To store bishop attacks
|
| 85 |
+
Bitboard CannonTableH[0xA00]; // To store horizontal cannon attacks
|
| 86 |
+
Bitboard CannonTableV[0xA00]; // To store vertical cannon attacks
|
| 87 |
+
Bitboard LameDabbabaTable[0x240]; // To store lame dabbaba attacks
|
| 88 |
+
Bitboard HorseTable[0x240]; // To store horse attacks
|
| 89 |
+
Bitboard ElephantTable[0x1A0]; // To store elephant attacks
|
| 90 |
+
Bitboard JanggiElephantTable[0x5C00]; // To store janggi elephant attacks
|
| 91 |
+
Bitboard CannonDiagTable[0x1480]; // To store diagonal cannon attacks
|
| 92 |
+
Bitboard NightriderTable[0x1840]; // To store nightrider attacks
|
| 93 |
+
Bitboard GrasshopperTableH[0xA00]; // To store horizontal grasshopper attacks
|
| 94 |
+
Bitboard GrasshopperTableV[0xA00]; // To store vertical grasshopper attacks
|
| 95 |
+
Bitboard GrasshopperTableD[0x1480]; // To store diagonal grasshopper attacks
|
| 96 |
+
#endif
|
| 97 |
+
|
| 98 |
+
// Rider directions
|
| 99 |
+
const std::map<Direction, int> RookDirectionsV { {NORTH, 0}, {SOUTH, 0}};
|
| 100 |
+
const std::map<Direction, int> RookDirectionsH { {EAST, 0}, {WEST, 0} };
|
| 101 |
+
const std::map<Direction, int> BishopDirections { {NORTH_EAST, 0}, {SOUTH_EAST, 0}, {SOUTH_WEST, 0}, {NORTH_WEST, 0} };
|
| 102 |
+
const std::map<Direction, int> LameDabbabaDirections { {2 * NORTH, 0}, {2 * EAST, 0}, {2 * SOUTH, 0}, {2 * WEST, 0} };
|
| 103 |
+
const std::map<Direction, int> HorseDirections { {2 * SOUTH + WEST, 0}, {2 * SOUTH + EAST, 0}, {SOUTH + 2 * WEST, 0}, {SOUTH + 2 * EAST, 0},
|
| 104 |
+
{NORTH + 2 * WEST, 0}, {NORTH + 2 * EAST, 0}, {2 * NORTH + WEST, 0}, {2 * NORTH + EAST, 0} };
|
| 105 |
+
const std::map<Direction, int> ElephantDirections { {2 * NORTH_EAST, 0}, {2 * SOUTH_EAST, 0}, {2 * SOUTH_WEST, 0}, {2 * NORTH_WEST, 0} };
|
| 106 |
+
const std::map<Direction, int> JanggiElephantDirections { {NORTH + 2 * NORTH_EAST, 0}, {EAST + 2 * NORTH_EAST, 0},
|
| 107 |
+
{EAST + 2 * SOUTH_EAST, 0}, {SOUTH + 2 * SOUTH_EAST, 0},
|
| 108 |
+
{SOUTH + 2 * SOUTH_WEST, 0}, {WEST + 2 * SOUTH_WEST, 0},
|
| 109 |
+
{WEST + 2 * NORTH_WEST, 0}, {NORTH + 2 * NORTH_WEST, 0} };
|
| 110 |
+
const std::map<Direction, int> GrasshopperDirectionsV { {NORTH, 1}, {SOUTH, 1}};
|
| 111 |
+
const std::map<Direction, int> GrasshopperDirectionsH { {EAST, 1}, {WEST, 1} };
|
| 112 |
+
const std::map<Direction, int> GrasshopperDirectionsD { {NORTH_EAST, 1}, {SOUTH_EAST, 1}, {SOUTH_WEST, 1}, {NORTH_WEST, 1} };
|
| 113 |
+
|
| 114 |
+
enum MovementType { RIDER, HOPPER, LAME_LEAPER, HOPPER_RANGE };
|
| 115 |
+
|
| 116 |
+
template <MovementType MT>
|
| 117 |
+
#ifdef PRECOMPUTED_MAGICS
|
| 118 |
+
void init_magics(Bitboard table[], Magic magics[], std::map<Direction, int> directions, const Bitboard magicsInit[]);
|
| 119 |
+
#else
|
| 120 |
+
void init_magics(Bitboard table[], Magic magics[], std::map<Direction, int> directions);
|
| 121 |
+
#endif
|
| 122 |
+
|
| 123 |
+
template <MovementType MT>
|
| 124 |
+
Bitboard sliding_attack(std::map<Direction, int> directions, Square sq, Bitboard occupied, Color c = WHITE) {
|
| 125 |
+
assert(MT != LAME_LEAPER);
|
| 126 |
+
|
| 127 |
+
Bitboard attack = 0;
|
| 128 |
+
|
| 129 |
+
for (auto const& [d, limit] : directions)
|
| 130 |
+
{
|
| 131 |
+
int count = 0;
|
| 132 |
+
bool hurdle = false;
|
| 133 |
+
for (Square s = sq + (c == WHITE ? d : -d);
|
| 134 |
+
is_ok(s) && distance(s, s - (c == WHITE ? d : -d)) <= 2;
|
| 135 |
+
s += (c == WHITE ? d : -d))
|
| 136 |
+
{
|
| 137 |
+
if (MT != HOPPER || hurdle)
|
| 138 |
+
{
|
| 139 |
+
attack |= s;
|
| 140 |
+
// For hoppers we consider limit == 1 as a grasshopper,
|
| 141 |
+
// but limit > 1 as a limited distance hopper
|
| 142 |
+
if (limit && !(MT == HOPPER_RANGE && limit == 1) && ++count >= limit)
|
| 143 |
+
break;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
if (occupied & s)
|
| 147 |
+
{
|
| 148 |
+
if (MT == HOPPER && !hurdle)
|
| 149 |
+
hurdle = true;
|
| 150 |
+
else
|
| 151 |
+
break;
|
| 152 |
+
}
|
| 153 |
+
}
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
return attack;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
Bitboard lame_leaper_path(Direction d, Square s) {
|
| 160 |
+
Direction dr = d > 0 ? NORTH : SOUTH;
|
| 161 |
+
Direction df = (std::abs(d % NORTH) < NORTH / 2 ? d % NORTH : -(d % NORTH)) < 0 ? WEST : EAST;
|
| 162 |
+
Square to = s + d;
|
| 163 |
+
Bitboard b = 0;
|
| 164 |
+
if (!is_ok(to) || distance(s, to) >= 4)
|
| 165 |
+
return b;
|
| 166 |
+
while (s != to)
|
| 167 |
+
{
|
| 168 |
+
int diff = std::abs(file_of(to) - file_of(s)) - std::abs(rank_of(to) - rank_of(s));
|
| 169 |
+
if (diff > 0)
|
| 170 |
+
s += df;
|
| 171 |
+
else if (diff < 0)
|
| 172 |
+
s += dr;
|
| 173 |
+
else
|
| 174 |
+
s += df + dr;
|
| 175 |
+
|
| 176 |
+
if (s != to)
|
| 177 |
+
b |= s;
|
| 178 |
+
}
|
| 179 |
+
return b;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
Bitboard lame_leaper_path(std::map<Direction, int> directions, Square s) {
|
| 183 |
+
Bitboard b = 0;
|
| 184 |
+
for (const auto& i : directions)
|
| 185 |
+
b |= lame_leaper_path(i.first, s);
|
| 186 |
+
return b;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
Bitboard lame_leaper_attack(std::map<Direction, int> directions, Square s, Bitboard occupied) {
|
| 190 |
+
Bitboard b = 0;
|
| 191 |
+
for (const auto& i : directions)
|
| 192 |
+
{
|
| 193 |
+
Square to = s + i.first;
|
| 194 |
+
if (is_ok(to) && distance(s, to) < 4 && !(lame_leaper_path(i.first, s) & occupied))
|
| 195 |
+
b |= to;
|
| 196 |
+
}
|
| 197 |
+
return b;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
/// safe_destination() returns the bitboard of target square for the given step
|
| 203 |
+
/// from the given square. If the step is off the board, returns empty bitboard.
|
| 204 |
+
|
| 205 |
+
inline Bitboard safe_destination(Square s, int step) {
|
| 206 |
+
Square to = Square(s + step);
|
| 207 |
+
return is_ok(to) && distance(s, to) <= 3 ? square_bb(to) : Bitboard(0);
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
|
| 212 |
+
/// to be printed to standard output. Useful for debugging.
|
| 213 |
+
|
| 214 |
+
std::string Bitboards::pretty(Bitboard b) {
|
| 215 |
+
|
| 216 |
+
std::string s = "+---+---+---+---+---+---+---+---+---+---+---+---+\n";
|
| 217 |
+
|
| 218 |
+
for (Rank r = RANK_MAX; r >= RANK_1; --r)
|
| 219 |
+
{
|
| 220 |
+
for (File f = FILE_A; f <= FILE_MAX; ++f)
|
| 221 |
+
s += b & make_square(f, r) ? "| X " : "| ";
|
| 222 |
+
|
| 223 |
+
s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+---+---+---+---+\n";
|
| 224 |
+
}
|
| 225 |
+
s += " a b c d e f g h i j k l\n";
|
| 226 |
+
|
| 227 |
+
return s;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
/// Bitboards::init_pieces() initializes piece move/attack bitboards and rider types
|
| 231 |
+
|
| 232 |
+
void Bitboards::init_pieces() {
|
| 233 |
+
|
| 234 |
+
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
| 235 |
+
{
|
| 236 |
+
const PieceInfo* pi = pieceMap.find(pt)->second;
|
| 237 |
+
|
| 238 |
+
// Detect rider types
|
| 239 |
+
for (auto modality : {MODALITY_QUIET, MODALITY_CAPTURE})
|
| 240 |
+
{
|
| 241 |
+
for (bool initial : {false, true})
|
| 242 |
+
{
|
| 243 |
+
// We do not support initial captures
|
| 244 |
+
if (modality == MODALITY_CAPTURE && initial)
|
| 245 |
+
continue;
|
| 246 |
+
auto& riderTypes = modality == MODALITY_CAPTURE ? AttackRiderTypes[pt] : MoveRiderTypes[initial][pt];
|
| 247 |
+
riderTypes = NO_RIDER;
|
| 248 |
+
for (auto const& [d, limit] : pi->steps[initial][modality])
|
| 249 |
+
{
|
| 250 |
+
if (limit && LameDabbabaDirections.find(d) != LameDabbabaDirections.end())
|
| 251 |
+
riderTypes |= RIDER_LAME_DABBABA;
|
| 252 |
+
if (limit && HorseDirections.find(d) != HorseDirections.end())
|
| 253 |
+
riderTypes |= RIDER_HORSE;
|
| 254 |
+
if (limit && ElephantDirections.find(d) != ElephantDirections.end())
|
| 255 |
+
riderTypes |= RIDER_ELEPHANT;
|
| 256 |
+
if (limit && JanggiElephantDirections.find(d) != JanggiElephantDirections.end())
|
| 257 |
+
riderTypes |= RIDER_JANGGI_ELEPHANT;
|
| 258 |
+
}
|
| 259 |
+
for (auto const& [d, limit] : pi->slider[initial][modality])
|
| 260 |
+
{
|
| 261 |
+
if (BishopDirections.find(d) != BishopDirections.end())
|
| 262 |
+
riderTypes |= RIDER_BISHOP;
|
| 263 |
+
if (RookDirectionsH.find(d) != RookDirectionsH.end())
|
| 264 |
+
riderTypes |= RIDER_ROOK_H;
|
| 265 |
+
if (RookDirectionsV.find(d) != RookDirectionsV.end())
|
| 266 |
+
riderTypes |= RIDER_ROOK_V;
|
| 267 |
+
if (HorseDirections.find(d) != HorseDirections.end())
|
| 268 |
+
riderTypes |= RIDER_NIGHTRIDER;
|
| 269 |
+
}
|
| 270 |
+
for (auto const& [d, limit] : pi->hopper[initial][modality])
|
| 271 |
+
{
|
| 272 |
+
if (RookDirectionsH.find(d) != RookDirectionsH.end())
|
| 273 |
+
riderTypes |= limit == 1 ? RIDER_GRASSHOPPER_H : RIDER_CANNON_H;
|
| 274 |
+
if (RookDirectionsV.find(d) != RookDirectionsV.end())
|
| 275 |
+
riderTypes |= limit == 1 ? RIDER_GRASSHOPPER_V : RIDER_CANNON_V;
|
| 276 |
+
if (BishopDirections.find(d) != BishopDirections.end())
|
| 277 |
+
riderTypes |= limit == 1 ? RIDER_GRASSHOPPER_D : RIDER_CANNON_DIAG;
|
| 278 |
+
}
|
| 279 |
+
}
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
// Initialize move/attack bitboards
|
| 283 |
+
for (Color c : { WHITE, BLACK })
|
| 284 |
+
{
|
| 285 |
+
for (Square s = SQ_A1; s <= SQ_MAX; ++s)
|
| 286 |
+
{
|
| 287 |
+
for (auto modality : {MODALITY_QUIET, MODALITY_CAPTURE})
|
| 288 |
+
{
|
| 289 |
+
for (bool initial : {false, true})
|
| 290 |
+
{
|
| 291 |
+
// We do not support initial captures
|
| 292 |
+
if (modality == MODALITY_CAPTURE && initial)
|
| 293 |
+
continue;
|
| 294 |
+
auto& pseudo = modality == MODALITY_CAPTURE ? PseudoAttacks[c][pt][s] : PseudoMoves[initial][c][pt][s];
|
| 295 |
+
auto& leaper = modality == MODALITY_CAPTURE ? LeaperAttacks[c][pt][s] : LeaperMoves[initial][c][pt][s];
|
| 296 |
+
pseudo = 0;
|
| 297 |
+
leaper = 0;
|
| 298 |
+
for (auto const& [d, limit] : pi->steps[initial][modality])
|
| 299 |
+
{
|
| 300 |
+
pseudo |= safe_destination(s, c == WHITE ? d : -d);
|
| 301 |
+
if (!limit)
|
| 302 |
+
leaper |= safe_destination(s, c == WHITE ? d : -d);
|
| 303 |
+
}
|
| 304 |
+
pseudo |= sliding_attack<RIDER>(pi->slider[initial][modality], s, 0, c);
|
| 305 |
+
pseudo |= sliding_attack<HOPPER_RANGE>(pi->hopper[initial][modality], s, 0, c);
|
| 306 |
+
}
|
| 307 |
+
}
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
/// Bitboards::init() initializes various bitboard tables. It is called at
|
| 315 |
+
/// startup and relies on global objects to be already zero-initialized.
|
| 316 |
+
|
| 317 |
+
void Bitboards::init() {
|
| 318 |
+
|
| 319 |
+
for (unsigned i = 0; i < (1 << 16); ++i)
|
| 320 |
+
PopCnt16[i] = uint8_t(std::bitset<16>(i).count());
|
| 321 |
+
|
| 322 |
+
for (Square s = SQ_A1; s <= SQ_MAX; ++s)
|
| 323 |
+
SquareBB[s] = make_bitboard(s);
|
| 324 |
+
|
| 325 |
+
for (File f = FILE_A; f <= FILE_MAX; ++f)
|
| 326 |
+
for (Rank r = RANK_1; r <= RANK_MAX; ++r)
|
| 327 |
+
BoardSizeBB[f][r] = forward_file_bb(BLACK, make_square(f, r)) | SquareBB[make_square(f, r)] | (f > FILE_A ? BoardSizeBB[f - 1][r] : Bitboard(0));
|
| 328 |
+
|
| 329 |
+
for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
|
| 330 |
+
for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
|
| 331 |
+
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
| 332 |
+
|
| 333 |
+
#ifdef PRECOMPUTED_MAGICS
|
| 334 |
+
init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH, RookMagicHInit);
|
| 335 |
+
init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV, RookMagicVInit);
|
| 336 |
+
init_magics<RIDER>(BishopTable, BishopMagics, BishopDirections, BishopMagicInit);
|
| 337 |
+
init_magics<HOPPER>(CannonTableH, CannonMagicsH, RookDirectionsH, CannonMagicHInit);
|
| 338 |
+
init_magics<HOPPER>(CannonTableV, CannonMagicsV, RookDirectionsV, CannonMagicVInit);
|
| 339 |
+
init_magics<LAME_LEAPER>(LameDabbabaTable, LameDabbabaMagics, LameDabbabaDirections, LameDabbabaMagicInit);
|
| 340 |
+
init_magics<LAME_LEAPER>(HorseTable, HorseMagics, HorseDirections, HorseMagicInit);
|
| 341 |
+
init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections, ElephantMagicInit);
|
| 342 |
+
init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections, JanggiElephantMagicInit);
|
| 343 |
+
init_magics<HOPPER>(CannonDiagTable, CannonDiagMagics, BishopDirections, CannonDiagMagicInit);
|
| 344 |
+
init_magics<RIDER>(NightriderTable, NightriderMagics, HorseDirections, NightriderMagicInit);
|
| 345 |
+
init_magics<HOPPER>(GrasshopperTableH, GrasshopperMagicsH, GrasshopperDirectionsH, GrasshopperMagicHInit);
|
| 346 |
+
init_magics<HOPPER>(GrasshopperTableV, GrasshopperMagicsV, GrasshopperDirectionsV, GrasshopperMagicVInit);
|
| 347 |
+
init_magics<HOPPER>(GrasshopperTableD, GrasshopperMagicsD, GrasshopperDirectionsD, GrasshopperMagicDInit);
|
| 348 |
+
#else
|
| 349 |
+
init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH);
|
| 350 |
+
init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV);
|
| 351 |
+
init_magics<RIDER>(BishopTable, BishopMagics, BishopDirections);
|
| 352 |
+
init_magics<HOPPER>(CannonTableH, CannonMagicsH, RookDirectionsH);
|
| 353 |
+
init_magics<HOPPER>(CannonTableV, CannonMagicsV, RookDirectionsV);
|
| 354 |
+
init_magics<LAME_LEAPER>(LameDabbabaTable, LameDabbabaMagics, LameDabbabaDirections);
|
| 355 |
+
init_magics<LAME_LEAPER>(HorseTable, HorseMagics, HorseDirections);
|
| 356 |
+
init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections);
|
| 357 |
+
init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections);
|
| 358 |
+
init_magics<HOPPER>(CannonDiagTable, CannonDiagMagics, BishopDirections);
|
| 359 |
+
init_magics<RIDER>(NightriderTable, NightriderMagics, HorseDirections);
|
| 360 |
+
init_magics<HOPPER>(GrasshopperTableH, GrasshopperMagicsH, GrasshopperDirectionsH);
|
| 361 |
+
init_magics<HOPPER>(GrasshopperTableV, GrasshopperMagicsV, GrasshopperDirectionsV);
|
| 362 |
+
init_magics<HOPPER>(GrasshopperTableD, GrasshopperMagicsD, GrasshopperDirectionsD);
|
| 363 |
+
#endif
|
| 364 |
+
|
| 365 |
+
init_pieces();
|
| 366 |
+
|
| 367 |
+
for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
|
| 368 |
+
{
|
| 369 |
+
for (PieceType pt : { BISHOP, ROOK })
|
| 370 |
+
for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
|
| 371 |
+
{
|
| 372 |
+
if (PseudoAttacks[WHITE][pt][s1] & s2)
|
| 373 |
+
{
|
| 374 |
+
LineBB[s1][s2] = (attacks_bb(WHITE, pt, s1, 0) & attacks_bb(WHITE, pt, s2, 0)) | s1 | s2;
|
| 375 |
+
BetweenBB[s1][s2] = (attacks_bb(WHITE, pt, s1, square_bb(s2)) & attacks_bb(WHITE, pt, s2, square_bb(s1)));
|
| 376 |
+
}
|
| 377 |
+
BetweenBB[s1][s2] |= s2;
|
| 378 |
+
}
|
| 379 |
+
}
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
namespace {
|
| 383 |
+
|
| 384 |
+
// init_magics() computes all rook and bishop attacks at startup. Magic
|
| 385 |
+
// bitboards are used to look up attacks of sliding pieces. As a reference see
|
| 386 |
+
// www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
|
| 387 |
+
// called "fancy" approach.
|
| 388 |
+
|
| 389 |
+
template <MovementType MT>
|
| 390 |
+
#ifdef PRECOMPUTED_MAGICS
|
| 391 |
+
void init_magics(Bitboard table[], Magic magics[], std::map<Direction, int> directions, const Bitboard magicsInit[]) {
|
| 392 |
+
#else
|
| 393 |
+
void init_magics(Bitboard table[], Magic magics[], std::map<Direction, int> directions) {
|
| 394 |
+
#endif
|
| 395 |
+
|
| 396 |
+
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
| 397 |
+
#ifndef PRECOMPUTED_MAGICS
|
| 398 |
+
#ifdef LARGEBOARDS
|
| 399 |
+
int seeds[][RANK_NB] = { { 734, 10316, 55013, 32803, 12281, 15100, 16645, 255, 346, 89123 },
|
| 400 |
+
{ 734, 10316, 55013, 32803, 12281, 15100, 16645, 255, 346, 89123 } };
|
| 401 |
+
#else
|
| 402 |
+
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
|
| 403 |
+
{ 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } };
|
| 404 |
+
#endif
|
| 405 |
+
#endif
|
| 406 |
+
|
| 407 |
+
Bitboard* occupancy = new Bitboard[1 << (FILE_NB + RANK_NB - 4)];
|
| 408 |
+
Bitboard* reference = new Bitboard[1 << (FILE_NB + RANK_NB - 4)];
|
| 409 |
+
Bitboard edges, b;
|
| 410 |
+
int* epoch = new int[1 << (FILE_NB + RANK_NB - 4)]();
|
| 411 |
+
int cnt = 0, size = 0;
|
| 412 |
+
|
| 413 |
+
for (Square s = SQ_A1; s <= SQ_MAX; ++s)
|
| 414 |
+
{
|
| 415 |
+
// Board edges are not considered in the relevant occupancies
|
| 416 |
+
edges = ((Rank1BB | rank_bb(RANK_MAX)) & ~rank_bb(s)) | ((FileABB | file_bb(FILE_MAX)) & ~file_bb(s));
|
| 417 |
+
|
| 418 |
+
// Given a square 's', the mask is the bitboard of sliding attacks from
|
| 419 |
+
// 's' computed on an empty board. The index must be big enough to contain
|
| 420 |
+
// all the attacks for each possible subset of the mask and so is 2 power
|
| 421 |
+
// the number of 1s of the mask. Hence we deduce the size of the shift to
|
| 422 |
+
// apply to the 64 or 32 bits word to get the index.
|
| 423 |
+
Magic& m = magics[s];
|
| 424 |
+
// The mask for hoppers is unlimited distance, even if the hopper is limited distance (e.g., grasshopper)
|
| 425 |
+
m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack<MT == HOPPER ? HOPPER_RANGE : MT>(directions, s, 0)) & ~edges;
|
| 426 |
+
#ifdef LARGEBOARDS
|
| 427 |
+
m.shift = 128 - popcount(m.mask);
|
| 428 |
+
#else
|
| 429 |
+
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
|
| 430 |
+
#endif
|
| 431 |
+
|
| 432 |
+
// Set the offset for the attacks table of the square. We have individual
|
| 433 |
+
// table sizes for each square with "Fancy Magic Bitboards".
|
| 434 |
+
m.attacks = s == SQ_A1 ? table : magics[s - 1].attacks + size;
|
| 435 |
+
|
| 436 |
+
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and
|
| 437 |
+
// store the corresponding sliding attack bitboard in reference[].
|
| 438 |
+
b = size = 0;
|
| 439 |
+
do {
|
| 440 |
+
occupancy[size] = b;
|
| 441 |
+
reference[size] = MT == LAME_LEAPER ? lame_leaper_attack(directions, s, b) : sliding_attack<MT>(directions, s, b);
|
| 442 |
+
|
| 443 |
+
if (HasPext)
|
| 444 |
+
m.attacks[pext(b, m.mask)] = reference[size];
|
| 445 |
+
|
| 446 |
+
size++;
|
| 447 |
+
b = (b - m.mask) & m.mask;
|
| 448 |
+
} while (b);
|
| 449 |
+
|
| 450 |
+
if (HasPext)
|
| 451 |
+
continue;
|
| 452 |
+
|
| 453 |
+
#ifndef PRECOMPUTED_MAGICS
|
| 454 |
+
PRNG rng(seeds[Is64Bit][rank_of(s)]);
|
| 455 |
+
#endif
|
| 456 |
+
|
| 457 |
+
// Find a magic for square 's' picking up an (almost) random number
|
| 458 |
+
// until we find the one that passes the verification test.
|
| 459 |
+
for (int i = 0; i < size; )
|
| 460 |
+
{
|
| 461 |
+
for (m.magic = 0; popcount((m.magic * m.mask) >> (SQUARE_NB - FILE_NB)) < FILE_NB - 2; )
|
| 462 |
+
{
|
| 463 |
+
#ifdef LARGEBOARDS
|
| 464 |
+
#ifdef PRECOMPUTED_MAGICS
|
| 465 |
+
m.magic = magicsInit[s];
|
| 466 |
+
#else
|
| 467 |
+
m.magic = (rng.sparse_rand<Bitboard>() << 64) ^ rng.sparse_rand<Bitboard>();
|
| 468 |
+
#endif
|
| 469 |
+
#else
|
| 470 |
+
m.magic = rng.sparse_rand<Bitboard>();
|
| 471 |
+
#endif
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
// A good magic must map every possible occupancy to an index that
|
| 475 |
+
// looks up the correct sliding attack in the attacks[s] database.
|
| 476 |
+
// Note that we build up the database for square 's' as a side
|
| 477 |
+
// effect of verifying the magic. Keep track of the attempt count
|
| 478 |
+
// and save it in epoch[], little speed-up trick to avoid resetting
|
| 479 |
+
// m.attacks[] after every failed attempt.
|
| 480 |
+
for (++cnt, i = 0; i < size; ++i)
|
| 481 |
+
{
|
| 482 |
+
unsigned idx = m.index(occupancy[i]);
|
| 483 |
+
|
| 484 |
+
if (epoch[idx] < cnt)
|
| 485 |
+
{
|
| 486 |
+
epoch[idx] = cnt;
|
| 487 |
+
m.attacks[idx] = reference[i];
|
| 488 |
+
}
|
| 489 |
+
else if (m.attacks[idx] != reference[i])
|
| 490 |
+
break;
|
| 491 |
+
}
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
delete[] occupancy;
|
| 496 |
+
delete[] reference;
|
| 497 |
+
delete[] epoch;
|
| 498 |
+
}
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/bitboard.h
ADDED
|
@@ -0,0 +1,787 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef BITBOARD_H_INCLUDED
|
| 20 |
+
#define BITBOARD_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <string>
|
| 23 |
+
|
| 24 |
+
#include "types.h"
|
| 25 |
+
|
| 26 |
+
namespace Stockfish {
|
| 27 |
+
|
| 28 |
+
namespace Bitbases {
|
| 29 |
+
|
| 30 |
+
void init();
|
| 31 |
+
bool probe(Square wksq, Square wpsq, Square bksq, Color us);
|
| 32 |
+
|
| 33 |
+
} // namespace Stockfish::Bitbases
|
| 34 |
+
|
| 35 |
+
namespace Bitboards {
|
| 36 |
+
|
| 37 |
+
void init_pieces();
|
| 38 |
+
void init();
|
| 39 |
+
std::string pretty(Bitboard b);
|
| 40 |
+
|
| 41 |
+
} // namespace Stockfish::Bitboards
|
| 42 |
+
|
| 43 |
+
#ifdef LARGEBOARDS
|
| 44 |
+
constexpr Bitboard AllSquares = ((~Bitboard(0)) >> 8);
|
| 45 |
+
#else
|
| 46 |
+
constexpr Bitboard AllSquares = ~Bitboard(0);
|
| 47 |
+
#endif
|
| 48 |
+
#ifdef LARGEBOARDS
|
| 49 |
+
constexpr Bitboard DarkSquares = (Bitboard(0xAAA555AAA555AAULL) << 64) ^ Bitboard(0xA555AAA555AAA555ULL);
|
| 50 |
+
#else
|
| 51 |
+
constexpr Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
|
| 52 |
+
#endif
|
| 53 |
+
|
| 54 |
+
#ifdef LARGEBOARDS
|
| 55 |
+
constexpr Bitboard FileABB = (Bitboard(0x00100100100100ULL) << 64) ^ Bitboard(0x1001001001001001ULL);
|
| 56 |
+
#else
|
| 57 |
+
constexpr Bitboard FileABB = 0x0101010101010101ULL;
|
| 58 |
+
#endif
|
| 59 |
+
constexpr Bitboard FileBBB = FileABB << 1;
|
| 60 |
+
constexpr Bitboard FileCBB = FileABB << 2;
|
| 61 |
+
constexpr Bitboard FileDBB = FileABB << 3;
|
| 62 |
+
constexpr Bitboard FileEBB = FileABB << 4;
|
| 63 |
+
constexpr Bitboard FileFBB = FileABB << 5;
|
| 64 |
+
constexpr Bitboard FileGBB = FileABB << 6;
|
| 65 |
+
constexpr Bitboard FileHBB = FileABB << 7;
|
| 66 |
+
#ifdef LARGEBOARDS
|
| 67 |
+
constexpr Bitboard FileIBB = FileABB << 8;
|
| 68 |
+
constexpr Bitboard FileJBB = FileABB << 9;
|
| 69 |
+
constexpr Bitboard FileKBB = FileABB << 10;
|
| 70 |
+
constexpr Bitboard FileLBB = FileABB << 11;
|
| 71 |
+
#endif
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
#ifdef LARGEBOARDS
|
| 75 |
+
constexpr Bitboard Rank1BB = 0xFFF;
|
| 76 |
+
#else
|
| 77 |
+
constexpr Bitboard Rank1BB = 0xFF;
|
| 78 |
+
#endif
|
| 79 |
+
constexpr Bitboard Rank2BB = Rank1BB << (FILE_NB * 1);
|
| 80 |
+
constexpr Bitboard Rank3BB = Rank1BB << (FILE_NB * 2);
|
| 81 |
+
constexpr Bitboard Rank4BB = Rank1BB << (FILE_NB * 3);
|
| 82 |
+
constexpr Bitboard Rank5BB = Rank1BB << (FILE_NB * 4);
|
| 83 |
+
constexpr Bitboard Rank6BB = Rank1BB << (FILE_NB * 5);
|
| 84 |
+
constexpr Bitboard Rank7BB = Rank1BB << (FILE_NB * 6);
|
| 85 |
+
constexpr Bitboard Rank8BB = Rank1BB << (FILE_NB * 7);
|
| 86 |
+
#ifdef LARGEBOARDS
|
| 87 |
+
constexpr Bitboard Rank9BB = Rank1BB << (FILE_NB * 8);
|
| 88 |
+
constexpr Bitboard Rank10BB = Rank1BB << (FILE_NB * 9);
|
| 89 |
+
#endif
|
| 90 |
+
|
| 91 |
+
constexpr Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
|
| 92 |
+
constexpr Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
|
| 93 |
+
constexpr Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
|
| 94 |
+
constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB);
|
| 95 |
+
|
| 96 |
+
constexpr Bitboard KingFlank[FILE_NB] = {
|
| 97 |
+
QueenSide ^ FileDBB, QueenSide, QueenSide,
|
| 98 |
+
CenterFiles, CenterFiles,
|
| 99 |
+
KingSide, KingSide, KingSide ^ FileEBB
|
| 100 |
+
};
|
| 101 |
+
|
| 102 |
+
extern uint8_t PopCnt16[1 << 16];
|
| 103 |
+
extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
| 104 |
+
|
| 105 |
+
extern Bitboard SquareBB[SQUARE_NB];
|
| 106 |
+
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
| 107 |
+
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
| 108 |
+
extern Bitboard PseudoAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 109 |
+
extern Bitboard PseudoMoves[2][COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 110 |
+
extern Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 111 |
+
extern Bitboard LeaperMoves[2][COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 112 |
+
extern Bitboard SquareBB[SQUARE_NB];
|
| 113 |
+
extern Bitboard BoardSizeBB[FILE_NB][RANK_NB];
|
| 114 |
+
extern RiderType AttackRiderTypes[PIECE_TYPE_NB];
|
| 115 |
+
extern RiderType MoveRiderTypes[2][PIECE_TYPE_NB];
|
| 116 |
+
|
| 117 |
+
#ifdef LARGEBOARDS
|
| 118 |
+
int popcount(Bitboard b); // required for 128 bit pext
|
| 119 |
+
#endif
|
| 120 |
+
|
| 121 |
+
/// Magic holds all magic bitboards relevant data for a single square
|
| 122 |
+
struct Magic {
|
| 123 |
+
Bitboard mask;
|
| 124 |
+
Bitboard magic;
|
| 125 |
+
Bitboard* attacks;
|
| 126 |
+
unsigned shift;
|
| 127 |
+
|
| 128 |
+
// Compute the attack's index using the 'magic bitboards' approach
|
| 129 |
+
unsigned index(Bitboard occupied) const {
|
| 130 |
+
|
| 131 |
+
if (HasPext)
|
| 132 |
+
return unsigned(pext(occupied, mask));
|
| 133 |
+
|
| 134 |
+
#ifdef LARGEBOARDS
|
| 135 |
+
return unsigned(((occupied & mask) * magic) >> shift);
|
| 136 |
+
#else
|
| 137 |
+
if (Is64Bit)
|
| 138 |
+
return unsigned(((occupied & mask) * magic) >> shift);
|
| 139 |
+
#endif
|
| 140 |
+
|
| 141 |
+
unsigned lo = unsigned(occupied) & unsigned(mask);
|
| 142 |
+
unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
|
| 143 |
+
return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
|
| 144 |
+
}
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
extern Magic RookMagicsH[SQUARE_NB];
|
| 148 |
+
extern Magic RookMagicsV[SQUARE_NB];
|
| 149 |
+
extern Magic BishopMagics[SQUARE_NB];
|
| 150 |
+
extern Magic CannonMagicsH[SQUARE_NB];
|
| 151 |
+
extern Magic CannonMagicsV[SQUARE_NB];
|
| 152 |
+
extern Magic LameDabbabaMagics[SQUARE_NB];
|
| 153 |
+
extern Magic HorseMagics[SQUARE_NB];
|
| 154 |
+
extern Magic ElephantMagics[SQUARE_NB];
|
| 155 |
+
extern Magic JanggiElephantMagics[SQUARE_NB];
|
| 156 |
+
extern Magic CannonDiagMagics[SQUARE_NB];
|
| 157 |
+
extern Magic NightriderMagics[SQUARE_NB];
|
| 158 |
+
extern Magic GrasshopperMagicsH[SQUARE_NB];
|
| 159 |
+
extern Magic GrasshopperMagicsV[SQUARE_NB];
|
| 160 |
+
extern Magic GrasshopperMagicsD[SQUARE_NB];
|
| 161 |
+
|
| 162 |
+
extern Magic* magics[];
|
| 163 |
+
|
| 164 |
+
constexpr Bitboard make_bitboard() { return 0; }
|
| 165 |
+
|
| 166 |
+
template<typename ...Squares>
|
| 167 |
+
constexpr Bitboard make_bitboard(Square s, Squares... squares) {
|
| 168 |
+
return (Bitboard(1) << s) | make_bitboard(squares...);
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
inline Bitboard square_bb(Square s) {
|
| 172 |
+
assert(is_ok(s));
|
| 173 |
+
return SquareBB[s];
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
/// Overloads of bitwise operators between a Bitboard and a Square for testing
|
| 178 |
+
/// whether a given bit is set in a bitboard, and for setting and clearing bits.
|
| 179 |
+
|
| 180 |
+
inline Bitboard operator&( Bitboard b, Square s) { return b & square_bb(s); }
|
| 181 |
+
inline Bitboard operator|( Bitboard b, Square s) { return b | square_bb(s); }
|
| 182 |
+
inline Bitboard operator^( Bitboard b, Square s) { return b ^ square_bb(s); }
|
| 183 |
+
inline Bitboard& operator|=(Bitboard& b, Square s) { return b |= square_bb(s); }
|
| 184 |
+
inline Bitboard& operator^=(Bitboard& b, Square s) { return b ^= square_bb(s); }
|
| 185 |
+
|
| 186 |
+
inline Bitboard operator-( Bitboard b, Square s) { return b & ~square_bb(s); }
|
| 187 |
+
inline Bitboard& operator-=(Bitboard& b, Square s) { return b &= ~square_bb(s); }
|
| 188 |
+
|
| 189 |
+
inline Bitboard operator&(Square s, Bitboard b) { return b & s; }
|
| 190 |
+
inline Bitboard operator|(Square s, Bitboard b) { return b | s; }
|
| 191 |
+
inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; }
|
| 192 |
+
|
| 193 |
+
inline Bitboard operator|(Square s1, Square s2) { return square_bb(s1) | s2; }
|
| 194 |
+
|
| 195 |
+
constexpr bool more_than_one(Bitboard b) {
|
| 196 |
+
return b & (b - 1);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
inline Bitboard undo_move_board(Bitboard b, Move m) {
|
| 201 |
+
return (from_sq(m) != SQ_NONE && (b & to_sq(m))) ? (b ^ to_sq(m)) | from_sq(m) : b;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
/// board_size_bb() returns a bitboard representing all the squares
|
| 205 |
+
/// on a board with given size.
|
| 206 |
+
|
| 207 |
+
inline Bitboard board_size_bb(File f, Rank r) {
|
| 208 |
+
return BoardSizeBB[f][r];
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
constexpr bool opposite_colors(Square s1, Square s2) {
|
| 212 |
+
return (s1 + rank_of(s1) + s2 + rank_of(s2)) & 1;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
/// rank_bb() and file_bb() return a bitboard representing all the squares on
|
| 217 |
+
/// the given file or rank.
|
| 218 |
+
|
| 219 |
+
constexpr Bitboard rank_bb(Rank r) {
|
| 220 |
+
return Rank1BB << (FILE_NB * r);
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
constexpr Bitboard rank_bb(Square s) {
|
| 224 |
+
return rank_bb(rank_of(s));
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
constexpr Bitboard file_bb(File f) {
|
| 228 |
+
return FileABB << f;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
constexpr Bitboard file_bb(Square s) {
|
| 232 |
+
return file_bb(file_of(s));
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
/// shift() moves a bitboard one or two steps as specified by the direction D
|
| 237 |
+
|
| 238 |
+
template<Direction D>
|
| 239 |
+
constexpr Bitboard shift(Bitboard b) {
|
| 240 |
+
return D == NORTH ? b << NORTH : D == SOUTH ? b >> NORTH
|
| 241 |
+
: D == NORTH+NORTH? b <<(2 * NORTH) : D == SOUTH+SOUTH? b >> (2 * NORTH)
|
| 242 |
+
: D == EAST ? (b & ~file_bb(FILE_MAX)) << EAST : D == WEST ? (b & ~FileABB) >> EAST
|
| 243 |
+
: D == NORTH_EAST ? (b & ~file_bb(FILE_MAX)) << NORTH_EAST : D == NORTH_WEST ? (b & ~FileABB) << NORTH_WEST
|
| 244 |
+
: D == SOUTH_EAST ? (b & ~file_bb(FILE_MAX)) >> NORTH_WEST : D == SOUTH_WEST ? (b & ~FileABB) >> NORTH_EAST
|
| 245 |
+
: Bitboard(0);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
/// shift() moves a bitboard one step along direction D (mainly for pawns)
|
| 250 |
+
|
| 251 |
+
constexpr Bitboard shift(Direction D, Bitboard b) {
|
| 252 |
+
return D == NORTH ? b << NORTH : D == SOUTH ? b >> NORTH
|
| 253 |
+
: D == NORTH+NORTH? b <<(2 * NORTH) : D == SOUTH+SOUTH? b >> (2 * NORTH)
|
| 254 |
+
: D == EAST ? (b & ~file_bb(FILE_MAX)) << EAST : D == WEST ? (b & ~FileABB) >> EAST
|
| 255 |
+
: D == NORTH_EAST ? (b & ~file_bb(FILE_MAX)) << NORTH_EAST : D == NORTH_WEST ? (b & ~FileABB) << NORTH_WEST
|
| 256 |
+
: D == SOUTH_EAST ? (b & ~file_bb(FILE_MAX)) >> NORTH_WEST : D == SOUTH_WEST ? (b & ~FileABB) >> NORTH_EAST
|
| 257 |
+
: Bitboard(0);
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
/// pawn_attacks_bb() returns the squares attacked by pawns of the given color
|
| 262 |
+
/// from the squares in the given bitboard.
|
| 263 |
+
|
| 264 |
+
template<Color C>
|
| 265 |
+
constexpr Bitboard pawn_attacks_bb(Bitboard b) {
|
| 266 |
+
return C == WHITE ? shift<NORTH_WEST>(b) | shift<NORTH_EAST>(b)
|
| 267 |
+
: shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b);
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
inline Bitboard pawn_attacks_bb(Color c, Square s) {
|
| 271 |
+
|
| 272 |
+
assert(is_ok(s));
|
| 273 |
+
return PseudoAttacks[c][PAWN][s];
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
/// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the
|
| 278 |
+
/// given color from the squares in the given bitboard.
|
| 279 |
+
|
| 280 |
+
template<Color C>
|
| 281 |
+
constexpr Bitboard pawn_double_attacks_bb(Bitboard b) {
|
| 282 |
+
return C == WHITE ? shift<NORTH_WEST>(b) & shift<NORTH_EAST>(b)
|
| 283 |
+
: shift<SOUTH_WEST>(b) & shift<SOUTH_EAST>(b);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
/// adjacent_files_bb() returns a bitboard representing all the squares on the
|
| 288 |
+
/// adjacent files of a given square.
|
| 289 |
+
|
| 290 |
+
constexpr Bitboard adjacent_files_bb(Square s) {
|
| 291 |
+
return shift<EAST>(file_bb(s)) | shift<WEST>(file_bb(s));
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
/// line_bb() returns a bitboard representing an entire line (from board edge
|
| 296 |
+
/// to board edge) that intersects the two given squares. If the given squares
|
| 297 |
+
/// are not on a same file/rank/diagonal, the function returns 0. For instance,
|
| 298 |
+
/// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal.
|
| 299 |
+
|
| 300 |
+
inline Bitboard line_bb(Square s1, Square s2) {
|
| 301 |
+
|
| 302 |
+
assert(is_ok(s1) && is_ok(s2));
|
| 303 |
+
|
| 304 |
+
return LineBB[s1][s2];
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
/// between_bb(s1, s2) returns a bitboard representing the squares in the semi-open
|
| 309 |
+
/// segment between the squares s1 and s2 (excluding s1 but including s2). If the
|
| 310 |
+
/// given squares are not on a same file/rank/diagonal, it returns s2. For instance,
|
| 311 |
+
/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5, E6 and F7, but
|
| 312 |
+
/// between_bb(SQ_E6, SQ_F8) will return a bitboard with the square F8. This trick
|
| 313 |
+
/// allows to generate non-king evasion moves faster: the defending piece must either
|
| 314 |
+
/// interpose itself to cover the check or capture the checking piece.
|
| 315 |
+
|
| 316 |
+
inline Bitboard between_bb(Square s1, Square s2) {
|
| 317 |
+
|
| 318 |
+
assert(is_ok(s1) && is_ok(s2));
|
| 319 |
+
|
| 320 |
+
return BetweenBB[s1][s2];
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
inline Bitboard between_bb(Square s1, Square s2, PieceType pt) {
|
| 324 |
+
if (pt == HORSE)
|
| 325 |
+
return PseudoAttacks[WHITE][WAZIR][s2] & PseudoAttacks[WHITE][FERS][s1];
|
| 326 |
+
else if (pt == JANGGI_ELEPHANT)
|
| 327 |
+
return (PseudoAttacks[WHITE][WAZIR][s2] & PseudoAttacks[WHITE][ALFIL][s1])
|
| 328 |
+
| (PseudoAttacks[WHITE][KNIGHT][s2] & PseudoAttacks[WHITE][FERS][s1]);
|
| 329 |
+
else
|
| 330 |
+
return between_bb(s1, s2);
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
/// forward_ranks_bb() returns a bitboard representing the squares on the ranks in
|
| 335 |
+
/// front of the given one, from the point of view of the given color. For instance,
|
| 336 |
+
/// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2.
|
| 337 |
+
|
| 338 |
+
constexpr Bitboard forward_ranks_bb(Color c, Square s) {
|
| 339 |
+
return c == WHITE ? (AllSquares ^ Rank1BB) << FILE_NB * relative_rank(WHITE, s, RANK_MAX)
|
| 340 |
+
: (AllSquares ^ rank_bb(RANK_MAX)) >> FILE_NB * relative_rank(BLACK, s, RANK_MAX);
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
constexpr Bitboard forward_ranks_bb(Color c, Rank r) {
|
| 344 |
+
return c == WHITE ? (AllSquares ^ Rank1BB) << FILE_NB * (r - RANK_1)
|
| 345 |
+
: (AllSquares ^ rank_bb(RANK_MAX)) >> FILE_NB * (RANK_MAX - r);
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
/// zone_bb() returns a bitboard representing the squares on all the ranks
|
| 350 |
+
/// in front of and on the given relative rank, from the point of view of the given color.
|
| 351 |
+
/// For instance, zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2.
|
| 352 |
+
|
| 353 |
+
inline Bitboard zone_bb(Color c, Rank r, Rank maxRank) {
|
| 354 |
+
return forward_ranks_bb(c, relative_rank(c, r, maxRank)) | rank_bb(relative_rank(c, r, maxRank));
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
/// forward_file_bb() returns a bitboard representing all the squares along the
|
| 359 |
+
/// line in front of the given one, from the point of view of the given color.
|
| 360 |
+
|
| 361 |
+
constexpr Bitboard forward_file_bb(Color c, Square s) {
|
| 362 |
+
return forward_ranks_bb(c, s) & file_bb(s);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
/// pawn_attack_span() returns a bitboard representing all the squares that can
|
| 367 |
+
/// be attacked by a pawn of the given color when it moves along its file, starting
|
| 368 |
+
/// from the given square.
|
| 369 |
+
|
| 370 |
+
constexpr Bitboard pawn_attack_span(Color c, Square s) {
|
| 371 |
+
return forward_ranks_bb(c, s) & adjacent_files_bb(s);
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
/// passed_pawn_span() returns a bitboard which can be used to test if a pawn of
|
| 376 |
+
/// the given color and on the given square is a passed pawn.
|
| 377 |
+
|
| 378 |
+
constexpr Bitboard passed_pawn_span(Color c, Square s) {
|
| 379 |
+
return pawn_attack_span(c, s) | forward_file_bb(c, s);
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
/// aligned() returns true if the squares s1, s2 and s3 are aligned either on a
|
| 384 |
+
/// straight or on a diagonal line.
|
| 385 |
+
|
| 386 |
+
inline bool aligned(Square s1, Square s2, Square s3) {
|
| 387 |
+
return line_bb(s1, s2) & s3;
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
/// distance() functions return the distance between x and y, defined as the
|
| 392 |
+
/// number of steps for a king in x to reach y.
|
| 393 |
+
|
| 394 |
+
template<typename T1 = Square> inline int distance(Square x, Square y);
|
| 395 |
+
template<> inline int distance<File>(Square x, Square y) { return std::abs(file_of(x) - file_of(y)); }
|
| 396 |
+
template<> inline int distance<Rank>(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); }
|
| 397 |
+
template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
|
| 398 |
+
|
| 399 |
+
inline int edge_distance(File f, File maxFile = FILE_H) { return std::min(f, File(maxFile - f)); }
|
| 400 |
+
inline int edge_distance(Rank r, Rank maxRank = RANK_8) { return std::min(r, Rank(maxRank - r)); }
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
template<RiderType R>
|
| 404 |
+
inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
|
| 405 |
+
|
| 406 |
+
static_assert(R != NO_RIDER && !(R & (R - 1))); // exactly one bit
|
| 407 |
+
const Magic& m = R == RIDER_ROOK_H ? RookMagicsH[s]
|
| 408 |
+
: R == RIDER_ROOK_V ? RookMagicsV[s]
|
| 409 |
+
: R == RIDER_CANNON_H ? CannonMagicsH[s]
|
| 410 |
+
: R == RIDER_CANNON_V ? CannonMagicsV[s]
|
| 411 |
+
: R == RIDER_LAME_DABBABA ? LameDabbabaMagics[s]
|
| 412 |
+
: R == RIDER_HORSE ? HorseMagics[s]
|
| 413 |
+
: R == RIDER_ELEPHANT ? ElephantMagics[s]
|
| 414 |
+
: R == RIDER_JANGGI_ELEPHANT ? JanggiElephantMagics[s]
|
| 415 |
+
: R == RIDER_CANNON_DIAG ? CannonDiagMagics[s]
|
| 416 |
+
: R == RIDER_NIGHTRIDER ? NightriderMagics[s]
|
| 417 |
+
: R == RIDER_GRASSHOPPER_H ? GrasshopperMagicsH[s]
|
| 418 |
+
: R == RIDER_GRASSHOPPER_V ? GrasshopperMagicsV[s]
|
| 419 |
+
: R == RIDER_GRASSHOPPER_D ? GrasshopperMagicsD[s]
|
| 420 |
+
: BishopMagics[s];
|
| 421 |
+
return m.attacks[m.index(occupied)];
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
inline Square lsb(Bitboard b);
|
| 425 |
+
|
| 426 |
+
inline Bitboard rider_attacks_bb(RiderType R, Square s, Bitboard occupied) {
|
| 427 |
+
|
| 428 |
+
assert(R != NO_RIDER && !(R & (R - 1))); // exactly one bit
|
| 429 |
+
const Magic& m = magics[lsb(R)][s]; // re-use Bitboard lsb for riders
|
| 430 |
+
return m.attacks[m.index(occupied)];
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
/// attacks_bb(Square) returns the pseudo attacks of the give piece type
|
| 435 |
+
/// assuming an empty board.
|
| 436 |
+
|
| 437 |
+
template<PieceType Pt>
|
| 438 |
+
inline Bitboard attacks_bb(Square s) {
|
| 439 |
+
|
| 440 |
+
assert((Pt != PAWN) && (is_ok(s)));
|
| 441 |
+
|
| 442 |
+
return PseudoAttacks[WHITE][Pt][s];
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
/// attacks_bb(Square, Bitboard) returns the attacks by the given piece
|
| 447 |
+
/// assuming the board is occupied according to the passed Bitboard.
|
| 448 |
+
/// Sliding piece attacks do not continue passed an occupied square.
|
| 449 |
+
|
| 450 |
+
template<PieceType Pt>
|
| 451 |
+
inline Bitboard attacks_bb(Square s, Bitboard occupied) {
|
| 452 |
+
|
| 453 |
+
assert((Pt != PAWN) && (is_ok(s)));
|
| 454 |
+
|
| 455 |
+
switch (Pt)
|
| 456 |
+
{
|
| 457 |
+
case BISHOP: return rider_attacks_bb<RIDER_BISHOP>(s, occupied);
|
| 458 |
+
case ROOK : return rider_attacks_bb<RIDER_ROOK_H>(s, occupied) | rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
|
| 459 |
+
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
|
| 460 |
+
default : return PseudoAttacks[WHITE][Pt][s];
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
/// pop_rider() finds and clears a rider in a (hybrid) rider type
|
| 465 |
+
|
| 466 |
+
inline RiderType pop_rider(RiderType* r) {
|
| 467 |
+
assert(*r);
|
| 468 |
+
const RiderType r2 = *r & ~(*r - 1);
|
| 469 |
+
*r &= *r - 1;
|
| 470 |
+
return r2;
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
inline Bitboard attacks_bb(Color c, PieceType pt, Square s, Bitboard occupied) {
|
| 474 |
+
Bitboard b = LeaperAttacks[c][pt][s];
|
| 475 |
+
RiderType r = AttackRiderTypes[pt];
|
| 476 |
+
while (r)
|
| 477 |
+
b |= rider_attacks_bb(pop_rider(&r), s, occupied);
|
| 478 |
+
return b & PseudoAttacks[c][pt][s];
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
template <bool Initial=false>
|
| 483 |
+
inline Bitboard moves_bb(Color c, PieceType pt, Square s, Bitboard occupied) {
|
| 484 |
+
Bitboard b = LeaperMoves[Initial][c][pt][s];
|
| 485 |
+
RiderType r = MoveRiderTypes[Initial][pt];
|
| 486 |
+
while (r)
|
| 487 |
+
b |= rider_attacks_bb(pop_rider(&r), s, occupied);
|
| 488 |
+
return b & PseudoMoves[Initial][c][pt][s];
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
|
| 492 |
+
/// popcount() counts the number of non-zero bits in a bitboard
|
| 493 |
+
|
| 494 |
+
inline int popcount(Bitboard b) {
|
| 495 |
+
|
| 496 |
+
#ifndef USE_POPCNT
|
| 497 |
+
|
| 498 |
+
#ifdef LARGEBOARDS
|
| 499 |
+
union { Bitboard bb; uint16_t u[8]; } v = { b };
|
| 500 |
+
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]]
|
| 501 |
+
+ PopCnt16[v.u[4]] + PopCnt16[v.u[5]] + PopCnt16[v.u[6]] + PopCnt16[v.u[7]];
|
| 502 |
+
#else
|
| 503 |
+
union { Bitboard bb; uint16_t u[4]; } v = { b };
|
| 504 |
+
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
|
| 505 |
+
#endif
|
| 506 |
+
|
| 507 |
+
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
| 508 |
+
|
| 509 |
+
#ifdef LARGEBOARDS
|
| 510 |
+
return (int)_mm_popcnt_u64(uint64_t(b >> 64)) + (int)_mm_popcnt_u64(uint64_t(b));
|
| 511 |
+
#else
|
| 512 |
+
return (int)_mm_popcnt_u64(b);
|
| 513 |
+
#endif
|
| 514 |
+
|
| 515 |
+
#else // Assumed gcc or compatible compiler
|
| 516 |
+
|
| 517 |
+
#ifdef LARGEBOARDS
|
| 518 |
+
return __builtin_popcountll(b >> 64) + __builtin_popcountll(b);
|
| 519 |
+
#else
|
| 520 |
+
return __builtin_popcountll(b);
|
| 521 |
+
#endif
|
| 522 |
+
|
| 523 |
+
#endif
|
| 524 |
+
}
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
/// lsb() and msb() return the least/most significant bit in a non-zero bitboard
|
| 528 |
+
|
| 529 |
+
#if defined(__GNUC__) // GCC, Clang, ICC
|
| 530 |
+
|
| 531 |
+
inline Square lsb(Bitboard b) {
|
| 532 |
+
assert(b);
|
| 533 |
+
#ifdef LARGEBOARDS
|
| 534 |
+
if (!(b << 64))
|
| 535 |
+
return Square(__builtin_ctzll(b >> 64) + 64);
|
| 536 |
+
#endif
|
| 537 |
+
return Square(__builtin_ctzll(b));
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
inline Square msb(Bitboard b) {
|
| 541 |
+
assert(b);
|
| 542 |
+
#ifdef LARGEBOARDS
|
| 543 |
+
if (b >> 64)
|
| 544 |
+
return Square(int(SQUARE_BIT_MASK) ^ __builtin_clzll(b >> 64));
|
| 545 |
+
return Square(int(SQUARE_BIT_MASK) ^ (__builtin_clzll(b) + 64));
|
| 546 |
+
#else
|
| 547 |
+
return Square(int(SQUARE_BIT_MASK) ^ __builtin_clzll(b));
|
| 548 |
+
#endif
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
#elif defined(_MSC_VER) // MSVC
|
| 552 |
+
|
| 553 |
+
#ifdef _WIN64 // MSVC, WIN64
|
| 554 |
+
|
| 555 |
+
inline Square lsb(Bitboard b) {
|
| 556 |
+
assert(b);
|
| 557 |
+
unsigned long idx;
|
| 558 |
+
#ifdef LARGEBOARDS
|
| 559 |
+
if (uint64_t(b))
|
| 560 |
+
{
|
| 561 |
+
_BitScanForward64(&idx, uint64_t(b));
|
| 562 |
+
return Square(idx);
|
| 563 |
+
}
|
| 564 |
+
else
|
| 565 |
+
{
|
| 566 |
+
_BitScanForward64(&idx, uint64_t(b >> 64));
|
| 567 |
+
return Square(idx + 64);
|
| 568 |
+
}
|
| 569 |
+
#else
|
| 570 |
+
_BitScanForward64(&idx, b);
|
| 571 |
+
return (Square) idx;
|
| 572 |
+
#endif
|
| 573 |
+
}
|
| 574 |
+
|
| 575 |
+
inline Square msb(Bitboard b) {
|
| 576 |
+
assert(b);
|
| 577 |
+
unsigned long idx;
|
| 578 |
+
#ifdef LARGEBOARDS
|
| 579 |
+
if (b >> 64)
|
| 580 |
+
{
|
| 581 |
+
_BitScanReverse64(&idx, uint64_t(b >> 64));
|
| 582 |
+
return Square(idx + 64);
|
| 583 |
+
}
|
| 584 |
+
else
|
| 585 |
+
{
|
| 586 |
+
_BitScanReverse64(&idx, uint64_t(b));
|
| 587 |
+
return Square(idx);
|
| 588 |
+
}
|
| 589 |
+
#else
|
| 590 |
+
_BitScanReverse64(&idx, b);
|
| 591 |
+
return (Square) idx;
|
| 592 |
+
#endif
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
#else // MSVC, WIN32
|
| 596 |
+
|
| 597 |
+
inline Square lsb(Bitboard b) {
|
| 598 |
+
assert(b);
|
| 599 |
+
unsigned long idx;
|
| 600 |
+
|
| 601 |
+
#ifdef LARGEBOARDS
|
| 602 |
+
if (b << 96) {
|
| 603 |
+
_BitScanForward(&idx, uint32_t(b));
|
| 604 |
+
return Square(idx);
|
| 605 |
+
} else if (b << 64) {
|
| 606 |
+
_BitScanForward(&idx, uint32_t(b >> 32));
|
| 607 |
+
return Square(idx + 32);
|
| 608 |
+
} else if (b << 32) {
|
| 609 |
+
_BitScanForward(&idx, uint32_t(b >> 64));
|
| 610 |
+
return Square(idx + 64);
|
| 611 |
+
} else {
|
| 612 |
+
_BitScanForward(&idx, uint32_t(b >> 96));
|
| 613 |
+
return Square(idx + 96);
|
| 614 |
+
}
|
| 615 |
+
#else
|
| 616 |
+
if (b & 0xffffffff) {
|
| 617 |
+
_BitScanForward(&idx, uint32_t(b));
|
| 618 |
+
return Square(idx);
|
| 619 |
+
} else {
|
| 620 |
+
_BitScanForward(&idx, uint32_t(b >> 32));
|
| 621 |
+
return Square(idx + 32);
|
| 622 |
+
}
|
| 623 |
+
#endif
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
+
inline Square msb(Bitboard b) {
|
| 627 |
+
assert(b);
|
| 628 |
+
unsigned long idx;
|
| 629 |
+
|
| 630 |
+
#ifdef LARGEBOARDS
|
| 631 |
+
if (b >> 96) {
|
| 632 |
+
_BitScanReverse(&idx, uint32_t(b >> 96));
|
| 633 |
+
return Square(idx + 96);
|
| 634 |
+
} else if (b >> 64) {
|
| 635 |
+
_BitScanReverse(&idx, uint32_t(b >> 64));
|
| 636 |
+
return Square(idx + 64);
|
| 637 |
+
} else
|
| 638 |
+
#endif
|
| 639 |
+
if (b >> 32) {
|
| 640 |
+
_BitScanReverse(&idx, uint32_t(b >> 32));
|
| 641 |
+
return Square(idx + 32);
|
| 642 |
+
} else {
|
| 643 |
+
_BitScanReverse(&idx, uint32_t(b));
|
| 644 |
+
return Square(idx);
|
| 645 |
+
}
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
#endif
|
| 649 |
+
|
| 650 |
+
#else // Compiler is neither GCC nor MSVC compatible
|
| 651 |
+
|
| 652 |
+
#error "Compiler not supported."
|
| 653 |
+
|
| 654 |
+
#endif
|
| 655 |
+
|
| 656 |
+
/// least_significant_square_bb() returns the bitboard of the least significant
|
| 657 |
+
/// square of a non-zero bitboard. It is equivalent to square_bb(lsb(bb)).
|
| 658 |
+
|
| 659 |
+
inline Bitboard least_significant_square_bb(Bitboard b) {
|
| 660 |
+
assert(b);
|
| 661 |
+
return b & -b;
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard
|
| 665 |
+
|
| 666 |
+
inline Square pop_lsb(Bitboard& b) {
|
| 667 |
+
assert(b);
|
| 668 |
+
const Square s = lsb(b);
|
| 669 |
+
b &= b - 1;
|
| 670 |
+
return s;
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
|
| 674 |
+
/// frontmost_sq() returns the most advanced square for the given color,
|
| 675 |
+
/// requires a non-zero bitboard.
|
| 676 |
+
inline Square frontmost_sq(Color c, Bitboard b) {
|
| 677 |
+
assert(b);
|
| 678 |
+
return c == WHITE ? msb(b) : lsb(b);
|
| 679 |
+
}
|
| 680 |
+
|
| 681 |
+
|
| 682 |
+
/// popcount() counts the number of non-zero bits in a piece set
|
| 683 |
+
|
| 684 |
+
inline int popcount(PieceSet ps) {
|
| 685 |
+
|
| 686 |
+
#ifndef USE_POPCNT
|
| 687 |
+
|
| 688 |
+
union { uint64_t bb; uint16_t u[4]; } v = { (uint64_t)ps };
|
| 689 |
+
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
|
| 690 |
+
|
| 691 |
+
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
| 692 |
+
|
| 693 |
+
return (int)_mm_popcnt_u64(ps);
|
| 694 |
+
|
| 695 |
+
#else // Assumed gcc or compatible compiler
|
| 696 |
+
|
| 697 |
+
return __builtin_popcountll(ps);
|
| 698 |
+
|
| 699 |
+
#endif
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
/// lsb() and msb() return the least/most significant bit in a non-zero piece set
|
| 703 |
+
|
| 704 |
+
#if defined(__GNUC__) // GCC, Clang, ICC
|
| 705 |
+
|
| 706 |
+
inline PieceType lsb(PieceSet ps) {
|
| 707 |
+
assert(ps);
|
| 708 |
+
return PieceType(__builtin_ctzll(ps));
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
inline PieceType msb(PieceSet ps) {
|
| 712 |
+
assert(ps);
|
| 713 |
+
return PieceType((PIECE_TYPE_NB - 1) ^ __builtin_clzll(ps));
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
#elif defined(_MSC_VER) // MSVC
|
| 717 |
+
|
| 718 |
+
#ifdef _WIN64 // MSVC, WIN64
|
| 719 |
+
|
| 720 |
+
inline PieceType lsb(PieceSet ps) {
|
| 721 |
+
assert(ps);
|
| 722 |
+
unsigned long idx;
|
| 723 |
+
_BitScanForward64(&idx, ps);
|
| 724 |
+
return (PieceType) idx;
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
inline PieceType msb(PieceSet ps) {
|
| 728 |
+
assert(ps);
|
| 729 |
+
unsigned long idx;
|
| 730 |
+
_BitScanReverse64(&idx, ps);
|
| 731 |
+
return (PieceType) idx;
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
#else // MSVC, WIN32
|
| 735 |
+
|
| 736 |
+
inline PieceType lsb(PieceSet ps) {
|
| 737 |
+
assert(ps);
|
| 738 |
+
unsigned long idx;
|
| 739 |
+
|
| 740 |
+
if (ps & 0xffffffff) {
|
| 741 |
+
_BitScanForward(&idx, uint32_t(ps));
|
| 742 |
+
return PieceType(idx);
|
| 743 |
+
} else {
|
| 744 |
+
_BitScanForward(&idx, uint32_t(ps >> 32));
|
| 745 |
+
return PieceType(idx + 32);
|
| 746 |
+
}
|
| 747 |
+
}
|
| 748 |
+
|
| 749 |
+
inline PieceType msb(PieceSet ps) {
|
| 750 |
+
assert(ps);
|
| 751 |
+
unsigned long idx;
|
| 752 |
+
if (ps >> 32) {
|
| 753 |
+
_BitScanReverse(&idx, uint32_t(ps >> 32));
|
| 754 |
+
return PieceType(idx + 32);
|
| 755 |
+
} else {
|
| 756 |
+
_BitScanReverse(&idx, uint32_t(ps));
|
| 757 |
+
return PieceType(idx);
|
| 758 |
+
}
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
#endif
|
| 762 |
+
|
| 763 |
+
#else // Compiler is neither GCC nor MSVC compatible
|
| 764 |
+
|
| 765 |
+
#error "Compiler not supported."
|
| 766 |
+
|
| 767 |
+
#endif
|
| 768 |
+
|
| 769 |
+
/// pop_lsb() and pop_msb() find and clear the least/most significant bit in a non-zero piece set
|
| 770 |
+
|
| 771 |
+
inline PieceType pop_lsb(PieceSet& ps) {
|
| 772 |
+
assert(ps);
|
| 773 |
+
const PieceType pt = lsb(ps);
|
| 774 |
+
ps &= PieceSet(ps - 1);
|
| 775 |
+
return pt;
|
| 776 |
+
}
|
| 777 |
+
|
| 778 |
+
inline PieceType pop_msb(PieceSet& ps) {
|
| 779 |
+
assert(ps);
|
| 780 |
+
const PieceType pt = msb(ps);
|
| 781 |
+
ps &= ~piece_set(pt);
|
| 782 |
+
return pt;
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
} // namespace Stockfish
|
| 786 |
+
|
| 787 |
+
#endif // #ifndef BITBOARD_H_INCLUDED
|
Fairy-Stockfish-master/src/endgame.cpp
ADDED
|
@@ -0,0 +1,1321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <cassert>
|
| 20 |
+
|
| 21 |
+
#include "bitboard.h"
|
| 22 |
+
#include "endgame.h"
|
| 23 |
+
#include "movegen.h"
|
| 24 |
+
|
| 25 |
+
namespace Stockfish {
|
| 26 |
+
|
| 27 |
+
namespace {
|
| 28 |
+
|
| 29 |
+
// Used to drive the king towards the edge of the board
|
| 30 |
+
// in KX vs K and KQ vs KR endgames.
|
| 31 |
+
// Values range from 27 (center squares) to 90 (in the corners)
|
| 32 |
+
inline int push_to_edge(Square s, const Position& pos) {
|
| 33 |
+
int rd = edge_distance(rank_of(s), pos.max_rank()), fd = edge_distance(file_of(s), pos.max_file());
|
| 34 |
+
return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// Used to drive the king towards A1H8 corners in KBN vs K endgames.
|
| 38 |
+
// Values range from 0 on A8H1 diagonal to 7 in A1H8 corners.
|
| 39 |
+
inline int push_to_corner(Square s, const Position& pos) {
|
| 40 |
+
return abs((pos.max_file() + pos.max_rank()) / 2 - rank_of(s) - file_of(s));
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// Used to drive the king towards the edge of the board in KSF vs K.
|
| 44 |
+
inline int push_to_opposing_edge(Square s, const Position& pos) {
|
| 45 |
+
int rd = rank_of(s), fd = edge_distance(file_of(s), pos.max_file());
|
| 46 |
+
return 20 - (7 * fd * fd / 2 - 7 * rd * rd / 4);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// Drive a piece close to or away from another piece
|
| 50 |
+
inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); }
|
| 51 |
+
inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); }
|
| 52 |
+
|
| 53 |
+
#ifndef NDEBUG
|
| 54 |
+
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
|
| 55 |
+
return pos.non_pawn_material(c) == npm && pos.count<PAWN>(c) == pawnsCnt;
|
| 56 |
+
}
|
| 57 |
+
#endif
|
| 58 |
+
|
| 59 |
+
// Map the square as if strongSide is white and strongSide's only pawn
|
| 60 |
+
// is on the left half of the board.
|
| 61 |
+
Square normalize(const Position& pos, Color strongSide, Square sq) {
|
| 62 |
+
|
| 63 |
+
assert(pos.count<PAWN>(strongSide) == 1);
|
| 64 |
+
|
| 65 |
+
if (file_of(pos.square<PAWN>(strongSide)) > pos.max_file() / 2)
|
| 66 |
+
sq = flip_file(sq, pos.max_file());
|
| 67 |
+
|
| 68 |
+
return strongSide == WHITE ? sq : flip_rank(sq, pos.max_rank());
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
} // namespace
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
namespace Endgames {
|
| 75 |
+
|
| 76 |
+
std::pair<Map<Value>, Map<ScaleFactor>> maps;
|
| 77 |
+
|
| 78 |
+
void init() {
|
| 79 |
+
|
| 80 |
+
add<KPK>("KPK");
|
| 81 |
+
add<KNNK>("KNNK");
|
| 82 |
+
add<KBNK>("KBNK");
|
| 83 |
+
add<KRKP>("KRKP");
|
| 84 |
+
add<KRKB>("KRKB");
|
| 85 |
+
add<KRKN>("KRKN");
|
| 86 |
+
add<KQKP>("KQKP");
|
| 87 |
+
add<KQKR>("KQKR");
|
| 88 |
+
add<KNNKP>("KNNKP");
|
| 89 |
+
|
| 90 |
+
// Fairy piece endgames
|
| 91 |
+
add<KNSK>("KNSK");
|
| 92 |
+
add<KNFK>("KNFK");
|
| 93 |
+
add<KNSFKR>("KNSFKR");
|
| 94 |
+
add<KSFK>("KSFK");
|
| 95 |
+
add<KSFKF>("KSFKF");
|
| 96 |
+
add<KRKS>("KRKS");
|
| 97 |
+
add<KCKR>("KCKR");
|
| 98 |
+
add<KAKR>("KAKR");
|
| 99 |
+
|
| 100 |
+
// Anti
|
| 101 |
+
add<RK, EG_EVAL_ANTI>("RvM");
|
| 102 |
+
add<KN, EG_EVAL_ANTI>("MvN");
|
| 103 |
+
add<NN, EG_EVAL_ANTI>("NvN");
|
| 104 |
+
|
| 105 |
+
// Atomic
|
| 106 |
+
add<KPK, EG_EVAL_ATOMIC>("MPvM");
|
| 107 |
+
add<KNK, EG_EVAL_ATOMIC>("MNvM");
|
| 108 |
+
add<KBK, EG_EVAL_ATOMIC>("MBvM");
|
| 109 |
+
add<KRK, EG_EVAL_ATOMIC>("MRvM");
|
| 110 |
+
add<KQK, EG_EVAL_ATOMIC>("MQvM");
|
| 111 |
+
add<KNNK, EG_EVAL_ATOMIC>("MNNvM");
|
| 112 |
+
|
| 113 |
+
// Duck
|
| 114 |
+
add<KBK, EG_EVAL_DUCK>("MBvM");
|
| 115 |
+
add<KNK, EG_EVAL_DUCK>("MNvM");
|
| 116 |
+
add<KPK, EG_EVAL_DUCK>("MPvM");
|
| 117 |
+
|
| 118 |
+
// Racing kings
|
| 119 |
+
add<KQK, EG_EVAL_RK>("KQK");
|
| 120 |
+
add<KRK, EG_EVAL_RK>("KRK");
|
| 121 |
+
add<KK, EG_EVAL_RK>("KK");
|
| 122 |
+
|
| 123 |
+
add<KRPKB>("KRPKB");
|
| 124 |
+
add<KBPKB>("KBPKB");
|
| 125 |
+
add<KBPKN>("KBPKN");
|
| 126 |
+
add<KBPPKB>("KBPPKB");
|
| 127 |
+
add<KRPPKRP>("KRPPKRP");
|
| 128 |
+
}
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
/// Mate with KX vs K. This function is used to evaluate positions with
|
| 133 |
+
/// king and plenty of material vs a lone king. It simply gives the
|
| 134 |
+
/// attacking side a bonus for driving the defending king towards the edge
|
| 135 |
+
/// of the board, and for keeping the distance between the two kings small.
|
| 136 |
+
template<>
|
| 137 |
+
Value Endgame<KXK>::operator()(const Position& pos) const {
|
| 138 |
+
|
| 139 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 140 |
+
assert(!pos.checkers()); // Eval is never called when in check
|
| 141 |
+
|
| 142 |
+
// Stalemate detection with lone king
|
| 143 |
+
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
|
| 144 |
+
return VALUE_DRAW;
|
| 145 |
+
|
| 146 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 147 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 148 |
+
|
| 149 |
+
Value result = pos.non_pawn_material(strongSide)
|
| 150 |
+
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
| 151 |
+
+ push_to_edge(weakKing, pos)
|
| 152 |
+
+ push_close(strongKing, weakKing);
|
| 153 |
+
|
| 154 |
+
if ( pos.count<QUEEN>(strongSide)
|
| 155 |
+
|| pos.count<ROOK>(strongSide)
|
| 156 |
+
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
|
| 157 |
+
|| ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares)
|
| 158 |
+
&& (pos.pieces(strongSide, BISHOP) & DarkSquares))
|
| 159 |
+
|| pos.count<SILVER>(strongSide) >= 2
|
| 160 |
+
||(pos.count<SILVER>(strongSide) && pos.count<KNIGHT>(strongSide))
|
| 161 |
+
||(pos.count<SILVER>(strongSide) && pos.count<FERS>(strongSide))
|
| 162 |
+
||(pos.count<KNIGHT>(strongSide) && pos.count<FERS>(strongSide) >= 2)
|
| 163 |
+
||(pos.count<FERS>(strongSide) >= 3
|
| 164 |
+
&& ( DarkSquares & pos.pieces(strongSide, FERS))
|
| 165 |
+
&& (~DarkSquares & pos.pieces(strongSide, FERS))))
|
| 166 |
+
result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
| 167 |
+
|
| 168 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
|
| 173 |
+
/// defending king towards a corner square that our bishop attacks.
|
| 174 |
+
template<>
|
| 175 |
+
Value Endgame<KBNK>::operator()(const Position& pos) const {
|
| 176 |
+
|
| 177 |
+
assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
|
| 178 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 179 |
+
|
| 180 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 181 |
+
Square strongBishop = pos.square<BISHOP>(strongSide);
|
| 182 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 183 |
+
|
| 184 |
+
// If our bishop does not attack A1/H8, we flip the enemy king square
|
| 185 |
+
// to drive to opposite corners (A8/H1).
|
| 186 |
+
|
| 187 |
+
Value result = (VALUE_KNOWN_WIN + 3520)
|
| 188 |
+
+ push_close(strongKing, weakKing)
|
| 189 |
+
+ 420 * push_to_corner(opposite_colors(strongBishop, SQ_A1) ? flip_file(weakKing, pos.max_file()) : weakKing, pos);
|
| 190 |
+
|
| 191 |
+
assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
|
| 192 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
/// KP vs K. This endgame is evaluated with the help of a bitbase
|
| 197 |
+
template<>
|
| 198 |
+
Value Endgame<KPK>::operator()(const Position& pos) const {
|
| 199 |
+
|
| 200 |
+
assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
|
| 201 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 202 |
+
|
| 203 |
+
// Assume strongSide is white and the pawn is on files A-D
|
| 204 |
+
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
| 205 |
+
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 206 |
+
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 207 |
+
|
| 208 |
+
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
|
| 209 |
+
|
| 210 |
+
// Non-standard promotion, evaluation unclear
|
| 211 |
+
if ( pos.promotion_zone(us) != rank_bb(relative_rank(us, RANK_8, pos.max_rank()))
|
| 212 |
+
|| RANK_MAX != RANK_8
|
| 213 |
+
|| !(pos.promotion_piece_types(us) & QUEEN))
|
| 214 |
+
{
|
| 215 |
+
Value result = PawnValueEg + Value(rank_of(strongPawn));
|
| 216 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
if (!Bitbases::probe(strongKing, strongPawn, weakKing, us))
|
| 220 |
+
return VALUE_DRAW;
|
| 221 |
+
|
| 222 |
+
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(strongPawn));
|
| 223 |
+
|
| 224 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
/// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
|
| 229 |
+
/// a bitbase. The function below returns drawish scores when the pawn is
|
| 230 |
+
/// far advanced with support of the king, while the attacking king is far
|
| 231 |
+
/// away.
|
| 232 |
+
template<>
|
| 233 |
+
Value Endgame<KRKP>::operator()(const Position& pos) const {
|
| 234 |
+
|
| 235 |
+
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 236 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 237 |
+
|
| 238 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 239 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 240 |
+
Square strongRook = pos.square<ROOK>(strongSide);
|
| 241 |
+
Square weakPawn = pos.square<PAWN>(weakSide);
|
| 242 |
+
Square queeningSquare = make_square(file_of(weakPawn), relative_rank(weakSide, RANK_8));
|
| 243 |
+
Value result;
|
| 244 |
+
|
| 245 |
+
// If the stronger side's king is in front of the pawn, it's a win
|
| 246 |
+
if (forward_file_bb(strongSide, strongKing) & weakPawn)
|
| 247 |
+
result = RookValueEg - distance(strongKing, weakPawn);
|
| 248 |
+
|
| 249 |
+
// If the weaker side's king is too far from the pawn and the rook,
|
| 250 |
+
// it's a win.
|
| 251 |
+
else if ( distance(weakKing, weakPawn) >= 3 + (pos.side_to_move() == weakSide)
|
| 252 |
+
&& distance(weakKing, strongRook) >= 3)
|
| 253 |
+
result = RookValueEg - distance(strongKing, weakPawn);
|
| 254 |
+
|
| 255 |
+
// If the pawn is far advanced and supported by the defending king,
|
| 256 |
+
// the position is drawish
|
| 257 |
+
else if ( relative_rank(strongSide, weakKing) <= RANK_3
|
| 258 |
+
&& distance(weakKing, weakPawn) == 1
|
| 259 |
+
&& relative_rank(strongSide, strongKing) >= RANK_4
|
| 260 |
+
&& distance(strongKing, weakPawn) > 2 + (pos.side_to_move() == strongSide))
|
| 261 |
+
result = Value(80) - 8 * distance(strongKing, weakPawn);
|
| 262 |
+
|
| 263 |
+
else
|
| 264 |
+
result = Value(200) - 8 * ( distance(strongKing, weakPawn + pawn_push(weakSide))
|
| 265 |
+
- distance(weakKing, weakPawn + pawn_push(weakSide))
|
| 266 |
+
- distance(weakPawn, queeningSquare));
|
| 267 |
+
|
| 268 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
/// KR vs KB. This is very simple, and always returns drawish scores. The
|
| 273 |
+
/// score is slightly bigger when the defending king is close to the edge.
|
| 274 |
+
template<>
|
| 275 |
+
Value Endgame<KRKB>::operator()(const Position& pos) const {
|
| 276 |
+
|
| 277 |
+
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 278 |
+
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 279 |
+
|
| 280 |
+
Value result = Value(push_to_edge(pos.square<KING>(weakSide), pos));
|
| 281 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
/// KR vs KN. The attacking side has slightly better winning chances than
|
| 286 |
+
/// in KR vs KB, particularly if the king and the knight are far apart.
|
| 287 |
+
template<>
|
| 288 |
+
Value Endgame<KRKN>::operator()(const Position& pos) const {
|
| 289 |
+
|
| 290 |
+
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 291 |
+
assert(verify_material(pos, weakSide, KnightValueMg, 0));
|
| 292 |
+
|
| 293 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 294 |
+
Square weakKnight = pos.square<KNIGHT>(weakSide);
|
| 295 |
+
Value result = Value(push_to_edge(weakKing, pos) + push_away(weakKing, weakKnight));
|
| 296 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
/// KQ vs KP. In general, this is a win for the stronger side, but there are a
|
| 301 |
+
/// few important exceptions. A pawn on 7th rank and on the A,C,F or H files
|
| 302 |
+
/// with a king positioned next to it can be a draw, so in that case, we only
|
| 303 |
+
/// use the distance between the kings.
|
| 304 |
+
template<>
|
| 305 |
+
Value Endgame<KQKP>::operator()(const Position& pos) const {
|
| 306 |
+
|
| 307 |
+
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
| 308 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 309 |
+
|
| 310 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 311 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 312 |
+
Square weakPawn = pos.square<PAWN>(weakSide);
|
| 313 |
+
|
| 314 |
+
Value result = Value(push_close(strongKing, weakKing));
|
| 315 |
+
|
| 316 |
+
if ( relative_rank(weakSide, weakPawn) != RANK_7
|
| 317 |
+
|| distance(weakKing, weakPawn) != 1
|
| 318 |
+
|| ((FileBBB | FileDBB | FileEBB | FileGBB) & weakPawn))
|
| 319 |
+
result += QueenValueEg - PawnValueEg;
|
| 320 |
+
|
| 321 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
/// KQ vs KR. This is almost identical to KX vs K: we give the attacking
|
| 326 |
+
/// king a bonus for having the kings close together, and for forcing the
|
| 327 |
+
/// defending king towards the edge. If we also take care to avoid null move for
|
| 328 |
+
/// the defending side in the search, this is usually sufficient to win KQ vs KR.
|
| 329 |
+
template<>
|
| 330 |
+
Value Endgame<KQKR>::operator()(const Position& pos) const {
|
| 331 |
+
|
| 332 |
+
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
| 333 |
+
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 334 |
+
|
| 335 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 336 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 337 |
+
|
| 338 |
+
Value result = QueenValueEg
|
| 339 |
+
- RookValueEg
|
| 340 |
+
+ push_to_edge(weakKing, pos)
|
| 341 |
+
+ push_close(strongKing, weakKing);
|
| 342 |
+
|
| 343 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
/// KC vs KR. Drawish, but good winning chances if king and rook are close.
|
| 348 |
+
template<>
|
| 349 |
+
Value Endgame<KCKR>::operator()(const Position& pos) const {
|
| 350 |
+
|
| 351 |
+
assert(verify_material(pos, strongSide, ChancellorValueMg, 0));
|
| 352 |
+
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 353 |
+
|
| 354 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 355 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 356 |
+
Square weakRook = pos.square<ROOK>(weakSide);
|
| 357 |
+
|
| 358 |
+
Value result = Value(push_to_edge(weakKing, pos))
|
| 359 |
+
+ push_close(strongKing, weakKing)
|
| 360 |
+
+ push_close(weakRook, weakKing);
|
| 361 |
+
|
| 362 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
/// KA vs KR. Very drawish.
|
| 367 |
+
template<>
|
| 368 |
+
Value Endgame<KAKR>::operator()(const Position& pos) const {
|
| 369 |
+
|
| 370 |
+
assert(verify_material(pos, strongSide, ArchbishopValueMg, 0));
|
| 371 |
+
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 372 |
+
|
| 373 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 374 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 375 |
+
|
| 376 |
+
Value result = Value(push_to_edge(weakKing, pos))
|
| 377 |
+
+ push_close(strongKing, weakKing);
|
| 378 |
+
|
| 379 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
/// KNN vs KP. Very drawish, but there are some mate opportunities if we can
|
| 384 |
+
/// press the weakSide King to a corner before the pawn advances too much.
|
| 385 |
+
template<>
|
| 386 |
+
Value Endgame<KNNKP>::operator()(const Position& pos) const {
|
| 387 |
+
|
| 388 |
+
assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0));
|
| 389 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 390 |
+
|
| 391 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 392 |
+
Square weakPawn = pos.square<PAWN>(weakSide);
|
| 393 |
+
|
| 394 |
+
Value result = PawnValueEg
|
| 395 |
+
+ 2 * push_to_edge(weakKing, pos)
|
| 396 |
+
- 10 * relative_rank(weakSide, weakPawn);
|
| 397 |
+
|
| 398 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
/// Some cases of trivial draws
|
| 403 |
+
template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
/// KFsPs vs K.
|
| 407 |
+
template<>
|
| 408 |
+
Value Endgame<KFsPsK>::operator()(const Position& pos) const {
|
| 409 |
+
|
| 410 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 411 |
+
|
| 412 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 413 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 414 |
+
|
| 415 |
+
Value result = pos.non_pawn_material(strongSide)
|
| 416 |
+
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
| 417 |
+
+ push_to_edge(loserKSq, pos)
|
| 418 |
+
+ push_close(winnerKSq, loserKSq);
|
| 419 |
+
|
| 420 |
+
if ( pos.count<FERS>(strongSide) >= 3
|
| 421 |
+
&& ( DarkSquares & pos.pieces(strongSide, FERS))
|
| 422 |
+
&& (~DarkSquares & pos.pieces(strongSide, FERS)))
|
| 423 |
+
result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
| 424 |
+
else if (pos.count<FERS>(strongSide) + pos.count<PAWN>(strongSide) < 3)
|
| 425 |
+
return VALUE_DRAW;
|
| 426 |
+
else
|
| 427 |
+
{
|
| 428 |
+
bool dark = DarkSquares & pos.pieces(strongSide, FERS);
|
| 429 |
+
bool light = ~DarkSquares & pos.pieces(strongSide, FERS);
|
| 430 |
+
|
| 431 |
+
// Determine the color of ferzes from promoting pawns
|
| 432 |
+
Bitboard b = pos.pieces(strongSide, PAWN);
|
| 433 |
+
while (b && (!dark || !light))
|
| 434 |
+
{
|
| 435 |
+
Square s = pos.promotion_square(strongSide, pop_lsb(b));
|
| 436 |
+
if (s != SQ_NONE)
|
| 437 |
+
{
|
| 438 |
+
if (DarkSquares & s)
|
| 439 |
+
dark = true;
|
| 440 |
+
else
|
| 441 |
+
light = true;
|
| 442 |
+
}
|
| 443 |
+
}
|
| 444 |
+
if (!dark || !light)
|
| 445 |
+
return VALUE_DRAW; // we can not checkmate with same colored ferzes
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
|
| 452 |
+
/// Mate with KNS vs K.
|
| 453 |
+
template<>
|
| 454 |
+
Value Endgame<KNSK>::operator()(const Position& pos) const {
|
| 455 |
+
|
| 456 |
+
assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg, 0));
|
| 457 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 458 |
+
|
| 459 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 460 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 461 |
+
|
| 462 |
+
Value result = VALUE_KNOWN_WIN
|
| 463 |
+
+ push_close(winnerKSq, loserKSq)
|
| 464 |
+
+ push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
|
| 465 |
+
|
| 466 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
|
| 470 |
+
/// KNF vs K. Can only be won if the weaker side's king
|
| 471 |
+
/// is close to a corner of the same color as the fers.
|
| 472 |
+
template<>
|
| 473 |
+
Value Endgame<KNFK>::operator()(const Position& pos) const {
|
| 474 |
+
|
| 475 |
+
assert(verify_material(pos, strongSide, KnightValueMg + FersValueMg, 0));
|
| 476 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 477 |
+
|
| 478 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 479 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 480 |
+
Square fersSq = pos.square<FERS>(strongSide);
|
| 481 |
+
|
| 482 |
+
// tries to drive toward corners A1 or H8. If we have a
|
| 483 |
+
// fers that cannot reach the above squares, we flip the kings in order
|
| 484 |
+
// to drive the enemy toward corners A8 or H1.
|
| 485 |
+
if (opposite_colors(fersSq, SQ_A1))
|
| 486 |
+
{
|
| 487 |
+
winnerKSq = relative_square(BLACK, winnerKSq, pos.max_rank());
|
| 488 |
+
loserKSq = relative_square(BLACK, loserKSq, pos.max_rank());
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
Value result = Value(push_close(winnerKSq, loserKSq))
|
| 492 |
+
+ 50 * push_to_corner(loserKSq, pos);
|
| 493 |
+
|
| 494 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
/// KNSFKR vs K.
|
| 499 |
+
template<>
|
| 500 |
+
Value Endgame<KNSFKR>::operator()(const Position& pos) const {
|
| 501 |
+
|
| 502 |
+
assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg + FersValueMg, 0));
|
| 503 |
+
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 504 |
+
|
| 505 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 506 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 507 |
+
|
| 508 |
+
Value result = KnightValueEg + SilverValueEg + FersValueEg - RookValueEg
|
| 509 |
+
+ push_close(winnerKSq, loserKSq)
|
| 510 |
+
+ push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
|
| 511 |
+
|
| 512 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 513 |
+
}
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
/// Mate with KSF vs K.
|
| 517 |
+
template<>
|
| 518 |
+
Value Endgame<KSFK>::operator()(const Position& pos) const {
|
| 519 |
+
|
| 520 |
+
assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0));
|
| 521 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 522 |
+
|
| 523 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 524 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 525 |
+
|
| 526 |
+
Value result = VALUE_KNOWN_WIN
|
| 527 |
+
+ push_close(winnerKSq, loserKSq)
|
| 528 |
+
+ push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
|
| 529 |
+
|
| 530 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
|
| 534 |
+
/// Mate with KSF vs KF.
|
| 535 |
+
template<>
|
| 536 |
+
Value Endgame<KSFKF>::operator()(const Position& pos) const {
|
| 537 |
+
|
| 538 |
+
assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0));
|
| 539 |
+
assert(verify_material(pos, weakSide, FersValueMg, 0));
|
| 540 |
+
|
| 541 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 542 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 543 |
+
Square fersSq = pos.square<FERS>(weakSide);
|
| 544 |
+
|
| 545 |
+
Value result = SilverValueEg
|
| 546 |
+
+ push_close(winnerKSq, loserKSq)
|
| 547 |
+
+ push_away(fersSq, loserKSq)
|
| 548 |
+
+ push_to_opposing_edge(relative_square(strongSide, loserKSq, pos.max_rank()), pos);
|
| 549 |
+
|
| 550 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
|
| 554 |
+
/// KR vs KS
|
| 555 |
+
template<>
|
| 556 |
+
Value Endgame<KRKS>::operator()(const Position& pos) const {
|
| 557 |
+
|
| 558 |
+
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 559 |
+
assert(verify_material(pos, weakSide, SilverValueMg, 0));
|
| 560 |
+
|
| 561 |
+
Square winnerKSq = pos.square<KING>(strongSide);
|
| 562 |
+
Square loserKSq = pos.square<KING>(weakSide);
|
| 563 |
+
|
| 564 |
+
Value result = RookValueEg
|
| 565 |
+
- SilverValueEg
|
| 566 |
+
+ push_to_edge(loserKSq, pos)
|
| 567 |
+
+ push_close(winnerKSq, loserKSq);
|
| 568 |
+
|
| 569 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
|
| 573 |
+
/// KB and one or more pawns vs K. It checks for draws with rook pawns and
|
| 574 |
+
/// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
|
| 575 |
+
/// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
|
| 576 |
+
/// will be used.
|
| 577 |
+
template<>
|
| 578 |
+
ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
| 579 |
+
|
| 580 |
+
assert(pos.non_pawn_material(strongSide) == BishopValueMg);
|
| 581 |
+
assert(pos.count<PAWN>(strongSide) >= 1);
|
| 582 |
+
|
| 583 |
+
// No assertions about the material of weakSide, because we want draws to
|
| 584 |
+
// be detected even when the weaker side has some pawns.
|
| 585 |
+
|
| 586 |
+
Bitboard strongPawns = pos.pieces(strongSide, PAWN);
|
| 587 |
+
Bitboard allPawns = pos.pieces(PAWN);
|
| 588 |
+
|
| 589 |
+
Square strongBishop = pos.square<BISHOP>(strongSide);
|
| 590 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 591 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 592 |
+
|
| 593 |
+
// All strongSide pawns are on a single rook file?
|
| 594 |
+
if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB))
|
| 595 |
+
{
|
| 596 |
+
Square queeningSquare = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8));
|
| 597 |
+
|
| 598 |
+
if ( opposite_colors(queeningSquare, strongBishop)
|
| 599 |
+
&& distance(queeningSquare, weakKing) <= 1)
|
| 600 |
+
return SCALE_FACTOR_DRAW;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
// If all the pawns are on the same B or G file, then it's potentially a draw
|
| 604 |
+
if ((!(allPawns & ~FileBBB) || !(allPawns & ~FileGBB))
|
| 605 |
+
&& pos.non_pawn_material(weakSide) == 0
|
| 606 |
+
&& pos.count<PAWN>(weakSide) >= 1)
|
| 607 |
+
{
|
| 608 |
+
// Get the least advanced weakSide pawn
|
| 609 |
+
Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
|
| 610 |
+
|
| 611 |
+
// There's potential for a draw if our pawn is blocked on the 7th rank,
|
| 612 |
+
// the bishop cannot attack it or they only have one pawn left.
|
| 613 |
+
if ( relative_rank(strongSide, weakPawn) == RANK_7
|
| 614 |
+
&& (strongPawns & (weakPawn + pawn_push(weakSide)))
|
| 615 |
+
&& (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns)))
|
| 616 |
+
{
|
| 617 |
+
int strongKingDist = distance(weakPawn, strongKing);
|
| 618 |
+
int weakKingDist = distance(weakPawn, weakKing);
|
| 619 |
+
|
| 620 |
+
// It's a draw if the weak king is on its back two ranks, within 2
|
| 621 |
+
// squares of the blocking pawn and the strong king is not
|
| 622 |
+
// closer. (I think this rule only fails in practically
|
| 623 |
+
// unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
|
| 624 |
+
// and positions where qsearch will immediately correct the
|
| 625 |
+
// problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w).
|
| 626 |
+
if ( relative_rank(strongSide, weakKing) >= RANK_7
|
| 627 |
+
&& weakKingDist <= 2
|
| 628 |
+
&& weakKingDist <= strongKingDist)
|
| 629 |
+
return SCALE_FACTOR_DRAW;
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
return SCALE_FACTOR_NONE;
|
| 634 |
+
}
|
| 635 |
+
|
| 636 |
+
|
| 637 |
+
/// KQ vs KR and one or more pawns. It tests for fortress draws with a rook on
|
| 638 |
+
/// the third rank defended by a pawn.
|
| 639 |
+
template<>
|
| 640 |
+
ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
|
| 641 |
+
|
| 642 |
+
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
| 643 |
+
assert(pos.count<ROOK>(weakSide) == 1);
|
| 644 |
+
assert(pos.count<PAWN>(weakSide) >= 1);
|
| 645 |
+
|
| 646 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 647 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 648 |
+
Square weakRook = pos.square<ROOK>(weakSide);
|
| 649 |
+
|
| 650 |
+
if ( relative_rank(weakSide, weakKing) <= RANK_2
|
| 651 |
+
&& relative_rank(weakSide, strongKing) >= RANK_4
|
| 652 |
+
&& relative_rank(weakSide, weakRook) == RANK_3
|
| 653 |
+
&& ( pos.pieces(weakSide, PAWN)
|
| 654 |
+
& attacks_bb<KING>(weakKing)
|
| 655 |
+
& pawn_attacks_bb(strongSide, weakRook)))
|
| 656 |
+
return SCALE_FACTOR_DRAW;
|
| 657 |
+
|
| 658 |
+
return SCALE_FACTOR_NONE;
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
|
| 662 |
+
/// KRP vs KR. This function knows a handful of the most important classes of
|
| 663 |
+
/// drawn positions, but is far from perfect. It would probably be a good idea
|
| 664 |
+
/// to add more knowledge in the future.
|
| 665 |
+
///
|
| 666 |
+
/// It would also be nice to rewrite the actual code for this function,
|
| 667 |
+
/// which is mostly copied from Glaurung 1.x, and isn't very pretty.
|
| 668 |
+
template<>
|
| 669 |
+
ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
|
| 670 |
+
|
| 671 |
+
assert(verify_material(pos, strongSide, RookValueMg, 1));
|
| 672 |
+
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 673 |
+
|
| 674 |
+
// Assume strongSide is white and the pawn is on files A-D
|
| 675 |
+
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
| 676 |
+
Square strongRook = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
|
| 677 |
+
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 678 |
+
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 679 |
+
Square weakRook = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
|
| 680 |
+
|
| 681 |
+
File pawnFile = file_of(strongPawn);
|
| 682 |
+
Rank pawnRank = rank_of(strongPawn);
|
| 683 |
+
Square queeningSquare = make_square(pawnFile, RANK_8);
|
| 684 |
+
int tempo = (pos.side_to_move() == strongSide);
|
| 685 |
+
|
| 686 |
+
// If the pawn is not too far advanced and the defending king defends the
|
| 687 |
+
// queening square, use the third-rank defence.
|
| 688 |
+
if ( pawnRank <= RANK_5
|
| 689 |
+
&& distance(weakKing, queeningSquare) <= 1
|
| 690 |
+
&& strongKing <= SQ_H5
|
| 691 |
+
&& (rank_of(weakRook) == RANK_6 || (pawnRank <= RANK_3 && rank_of(strongRook) != RANK_6)))
|
| 692 |
+
return SCALE_FACTOR_DRAW;
|
| 693 |
+
|
| 694 |
+
// The defending side saves a draw by checking from behind in case the pawn
|
| 695 |
+
// has advanced to the 6th rank with the king behind.
|
| 696 |
+
if ( pawnRank == RANK_6
|
| 697 |
+
&& distance(weakKing, queeningSquare) <= 1
|
| 698 |
+
&& rank_of(strongKing) + tempo <= RANK_6
|
| 699 |
+
&& (rank_of(weakRook) == RANK_1 || (!tempo && distance<File>(weakRook, strongPawn) >= 3)))
|
| 700 |
+
return SCALE_FACTOR_DRAW;
|
| 701 |
+
|
| 702 |
+
if ( pawnRank >= RANK_6
|
| 703 |
+
&& weakKing == queeningSquare
|
| 704 |
+
&& rank_of(weakRook) == RANK_1
|
| 705 |
+
&& (!tempo || distance(strongKing, strongPawn) >= 2))
|
| 706 |
+
return SCALE_FACTOR_DRAW;
|
| 707 |
+
|
| 708 |
+
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
|
| 709 |
+
// and the black rook is behind the pawn.
|
| 710 |
+
if ( strongPawn == SQ_A7
|
| 711 |
+
&& strongRook == SQ_A8
|
| 712 |
+
&& (weakKing == SQ_H7 || weakKing == SQ_G7)
|
| 713 |
+
&& file_of(weakRook) == FILE_A
|
| 714 |
+
&& (rank_of(weakRook) <= RANK_3 || file_of(strongKing) >= FILE_D || rank_of(strongKing) <= RANK_5))
|
| 715 |
+
return SCALE_FACTOR_DRAW;
|
| 716 |
+
|
| 717 |
+
// If the defending king blocks the pawn and the attacking king is too far
|
| 718 |
+
// away, it's a draw.
|
| 719 |
+
if ( pawnRank <= RANK_5
|
| 720 |
+
&& weakKing == strongPawn + NORTH
|
| 721 |
+
&& distance(strongKing, strongPawn) - tempo >= 2
|
| 722 |
+
&& distance(strongKing, weakRook) - tempo >= 2)
|
| 723 |
+
return SCALE_FACTOR_DRAW;
|
| 724 |
+
|
| 725 |
+
// Pawn on the 7th rank supported by the rook from behind usually wins if the
|
| 726 |
+
// attacking king is closer to the queening square than the defending king,
|
| 727 |
+
// and the defending king cannot gain tempi by threatening the attacking rook.
|
| 728 |
+
if ( pawnRank == RANK_7
|
| 729 |
+
&& pawnFile != FILE_A
|
| 730 |
+
&& file_of(strongRook) == pawnFile
|
| 731 |
+
&& strongRook != queeningSquare
|
| 732 |
+
&& (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo)
|
| 733 |
+
&& (distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo))
|
| 734 |
+
return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(strongKing, queeningSquare));
|
| 735 |
+
|
| 736 |
+
// Similar to the above, but with the pawn further back
|
| 737 |
+
if ( pawnFile != FILE_A
|
| 738 |
+
&& file_of(strongRook) == pawnFile
|
| 739 |
+
&& strongRook < strongPawn
|
| 740 |
+
&& (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo)
|
| 741 |
+
&& (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn + NORTH) - 2 + tempo)
|
| 742 |
+
&& ( distance(weakKing, strongRook) + tempo >= 3
|
| 743 |
+
|| ( distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo
|
| 744 |
+
&& (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn) + tempo))))
|
| 745 |
+
return ScaleFactor( SCALE_FACTOR_MAX
|
| 746 |
+
- 8 * distance(strongPawn, queeningSquare)
|
| 747 |
+
- 2 * distance(strongKing, queeningSquare));
|
| 748 |
+
|
| 749 |
+
// If the pawn is not far advanced and the defending king is somewhere in
|
| 750 |
+
// the pawn's path, it's probably a draw.
|
| 751 |
+
if (pawnRank <= RANK_4 && weakKing > strongPawn)
|
| 752 |
+
{
|
| 753 |
+
if (file_of(weakKing) == file_of(strongPawn))
|
| 754 |
+
return ScaleFactor(10);
|
| 755 |
+
if ( distance<File>(weakKing, strongPawn) == 1
|
| 756 |
+
&& distance(strongKing, weakKing) > 2)
|
| 757 |
+
return ScaleFactor(24 - 2 * distance(strongKing, weakKing));
|
| 758 |
+
}
|
| 759 |
+
return SCALE_FACTOR_NONE;
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
template<>
|
| 763 |
+
ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
|
| 764 |
+
|
| 765 |
+
assert(verify_material(pos, strongSide, RookValueMg, 1));
|
| 766 |
+
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 767 |
+
|
| 768 |
+
// Test for a rook pawn
|
| 769 |
+
if (pos.pieces(PAWN) & (FileABB | FileHBB))
|
| 770 |
+
{
|
| 771 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 772 |
+
Square weakBishop = pos.square<BISHOP>(weakSide);
|
| 773 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 774 |
+
Square strongPawn = pos.square<PAWN>(strongSide);
|
| 775 |
+
Rank pawnRank = relative_rank(strongSide, strongPawn);
|
| 776 |
+
Direction push = pawn_push(strongSide);
|
| 777 |
+
|
| 778 |
+
// If the pawn is on the 5th rank and the pawn (currently) is on
|
| 779 |
+
// the same color square as the bishop then there is a chance of
|
| 780 |
+
// a fortress. Depending on the king position give a moderate
|
| 781 |
+
// reduction or a stronger one if the defending king is near the
|
| 782 |
+
// corner but not trapped there.
|
| 783 |
+
if (pawnRank == RANK_5 && !opposite_colors(weakBishop, strongPawn))
|
| 784 |
+
{
|
| 785 |
+
int d = distance(strongPawn + 3 * push, weakKing);
|
| 786 |
+
|
| 787 |
+
if (d <= 2 && !(d == 0 && weakKing == strongKing + 2 * push))
|
| 788 |
+
return ScaleFactor(24);
|
| 789 |
+
else
|
| 790 |
+
return ScaleFactor(48);
|
| 791 |
+
}
|
| 792 |
+
|
| 793 |
+
// When the pawn has moved to the 6th rank we can be fairly sure
|
| 794 |
+
// it's drawn if the bishop attacks the square in front of the
|
| 795 |
+
// pawn from a reasonable distance and the defending king is near
|
| 796 |
+
// the corner
|
| 797 |
+
if ( pawnRank == RANK_6
|
| 798 |
+
&& distance(strongPawn + 2 * push, weakKing) <= 1
|
| 799 |
+
&& (attacks_bb<BISHOP>(weakBishop) & (strongPawn + push))
|
| 800 |
+
&& distance<File>(weakBishop, strongPawn) >= 2)
|
| 801 |
+
return ScaleFactor(8);
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
return SCALE_FACTOR_NONE;
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
/// KRPP vs KRP. There is just a single rule: if the stronger side has no passed
|
| 808 |
+
/// pawns and the defending king is actively placed, the position is drawish.
|
| 809 |
+
template<>
|
| 810 |
+
ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
|
| 811 |
+
|
| 812 |
+
assert(verify_material(pos, strongSide, RookValueMg, 2));
|
| 813 |
+
assert(verify_material(pos, weakSide, RookValueMg, 1));
|
| 814 |
+
|
| 815 |
+
Square strongPawn1 = lsb(pos.pieces(strongSide, PAWN));
|
| 816 |
+
Square strongPawn2 = msb(pos.pieces(strongSide, PAWN));
|
| 817 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 818 |
+
|
| 819 |
+
// Does the stronger side have a passed pawn?
|
| 820 |
+
if (pos.pawn_passed(strongSide, strongPawn1) || pos.pawn_passed(strongSide, strongPawn2))
|
| 821 |
+
return SCALE_FACTOR_NONE;
|
| 822 |
+
|
| 823 |
+
Rank pawnRank = std::max(relative_rank(strongSide, strongPawn1), relative_rank(strongSide, strongPawn2));
|
| 824 |
+
|
| 825 |
+
if ( distance<File>(weakKing, strongPawn1) <= 1
|
| 826 |
+
&& distance<File>(weakKing, strongPawn2) <= 1
|
| 827 |
+
&& relative_rank(strongSide, weakKing) > pawnRank)
|
| 828 |
+
{
|
| 829 |
+
assert(pawnRank > RANK_1 && pawnRank < RANK_7);
|
| 830 |
+
return ScaleFactor(7 * pawnRank);
|
| 831 |
+
}
|
| 832 |
+
return SCALE_FACTOR_NONE;
|
| 833 |
+
}
|
| 834 |
+
|
| 835 |
+
|
| 836 |
+
/// K and two or more pawns vs K. There is just a single rule here: if all pawns
|
| 837 |
+
/// are on the same rook file and are blocked by the defending king, it's a draw.
|
| 838 |
+
template<>
|
| 839 |
+
ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
|
| 840 |
+
|
| 841 |
+
assert(pos.non_pawn_material(strongSide) == VALUE_ZERO);
|
| 842 |
+
assert(pos.count<PAWN>(strongSide) >= 2);
|
| 843 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 844 |
+
|
| 845 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 846 |
+
Bitboard strongPawns = pos.pieces(strongSide, PAWN);
|
| 847 |
+
|
| 848 |
+
// If all pawns are ahead of the king on a single rook file, it's a draw.
|
| 849 |
+
if ( !(strongPawns & ~(FileABB | FileHBB))
|
| 850 |
+
&& !(strongPawns & ~passed_pawn_span(weakSide, weakKing)))
|
| 851 |
+
return SCALE_FACTOR_DRAW;
|
| 852 |
+
|
| 853 |
+
return SCALE_FACTOR_NONE;
|
| 854 |
+
}
|
| 855 |
+
|
| 856 |
+
|
| 857 |
+
/// KBP vs KB. There are two rules: if the defending king is somewhere along the
|
| 858 |
+
/// path of the pawn, and the square of the king is not of the same color as the
|
| 859 |
+
/// stronger side's bishop, it's a draw. If the two bishops have opposite color,
|
| 860 |
+
/// it's almost always a draw.
|
| 861 |
+
template<>
|
| 862 |
+
ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
|
| 863 |
+
|
| 864 |
+
assert(verify_material(pos, strongSide, BishopValueMg, 1));
|
| 865 |
+
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 866 |
+
|
| 867 |
+
Square strongPawn = pos.square<PAWN>(strongSide);
|
| 868 |
+
Square strongBishop = pos.square<BISHOP>(strongSide);
|
| 869 |
+
Square weakBishop = pos.square<BISHOP>(weakSide);
|
| 870 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 871 |
+
|
| 872 |
+
// Case 1: Defending king blocks the pawn, and cannot be driven away
|
| 873 |
+
if ( (forward_file_bb(strongSide, strongPawn) & weakKing)
|
| 874 |
+
&& ( opposite_colors(weakKing, strongBishop)
|
| 875 |
+
|| relative_rank(strongSide, weakKing) <= RANK_6))
|
| 876 |
+
return SCALE_FACTOR_DRAW;
|
| 877 |
+
|
| 878 |
+
// Case 2: Opposite colored bishops
|
| 879 |
+
if (opposite_colors(strongBishop, weakBishop))
|
| 880 |
+
return SCALE_FACTOR_DRAW;
|
| 881 |
+
|
| 882 |
+
return SCALE_FACTOR_NONE;
|
| 883 |
+
}
|
| 884 |
+
|
| 885 |
+
|
| 886 |
+
/// KBPP vs KB. It detects a few basic draws with opposite-colored bishops
|
| 887 |
+
template<>
|
| 888 |
+
ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
|
| 889 |
+
|
| 890 |
+
assert(verify_material(pos, strongSide, BishopValueMg, 2));
|
| 891 |
+
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 892 |
+
|
| 893 |
+
Square strongBishop = pos.square<BISHOP>(strongSide);
|
| 894 |
+
Square weakBishop = pos.square<BISHOP>(weakSide);
|
| 895 |
+
|
| 896 |
+
if (!opposite_colors(strongBishop, weakBishop))
|
| 897 |
+
return SCALE_FACTOR_NONE;
|
| 898 |
+
|
| 899 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 900 |
+
Square strongPawn1 = lsb(pos.pieces(strongSide, PAWN));
|
| 901 |
+
Square strongPawn2 = msb(pos.pieces(strongSide, PAWN));
|
| 902 |
+
Square blockSq1, blockSq2;
|
| 903 |
+
|
| 904 |
+
if (relative_rank(strongSide, strongPawn1) > relative_rank(strongSide, strongPawn2))
|
| 905 |
+
{
|
| 906 |
+
blockSq1 = strongPawn1 + pawn_push(strongSide);
|
| 907 |
+
blockSq2 = make_square(file_of(strongPawn2), rank_of(strongPawn1));
|
| 908 |
+
}
|
| 909 |
+
else
|
| 910 |
+
{
|
| 911 |
+
blockSq1 = strongPawn2 + pawn_push(strongSide);
|
| 912 |
+
blockSq2 = make_square(file_of(strongPawn1), rank_of(strongPawn2));
|
| 913 |
+
}
|
| 914 |
+
|
| 915 |
+
switch (distance<File>(strongPawn1, strongPawn2))
|
| 916 |
+
{
|
| 917 |
+
case 0:
|
| 918 |
+
// Both pawns are on the same file. It's an easy draw if the defender firmly
|
| 919 |
+
// controls some square in the frontmost pawn's path.
|
| 920 |
+
if ( file_of(weakKing) == file_of(blockSq1)
|
| 921 |
+
&& relative_rank(strongSide, weakKing) >= relative_rank(strongSide, blockSq1)
|
| 922 |
+
&& opposite_colors(weakKing, strongBishop))
|
| 923 |
+
return SCALE_FACTOR_DRAW;
|
| 924 |
+
else
|
| 925 |
+
return SCALE_FACTOR_NONE;
|
| 926 |
+
|
| 927 |
+
case 1:
|
| 928 |
+
// Pawns on adjacent files. It's a draw if the defender firmly controls the
|
| 929 |
+
// square in front of the frontmost pawn's path, and the square diagonally
|
| 930 |
+
// behind this square on the file of the other pawn.
|
| 931 |
+
if ( weakKing == blockSq1
|
| 932 |
+
&& opposite_colors(weakKing, strongBishop)
|
| 933 |
+
&& ( weakBishop == blockSq2
|
| 934 |
+
|| (attacks_bb<BISHOP>(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP))
|
| 935 |
+
|| distance<Rank>(strongPawn1, strongPawn2) >= 2))
|
| 936 |
+
return SCALE_FACTOR_DRAW;
|
| 937 |
+
|
| 938 |
+
else if ( weakKing == blockSq2
|
| 939 |
+
&& opposite_colors(weakKing, strongBishop)
|
| 940 |
+
&& ( weakBishop == blockSq1
|
| 941 |
+
|| (attacks_bb<BISHOP>(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP))))
|
| 942 |
+
return SCALE_FACTOR_DRAW;
|
| 943 |
+
else
|
| 944 |
+
return SCALE_FACTOR_NONE;
|
| 945 |
+
|
| 946 |
+
default:
|
| 947 |
+
// The pawns are not on the same file or adjacent files. No scaling.
|
| 948 |
+
return SCALE_FACTOR_NONE;
|
| 949 |
+
}
|
| 950 |
+
}
|
| 951 |
+
|
| 952 |
+
|
| 953 |
+
/// KBP vs KN. There is a single rule: if the defending king is somewhere along
|
| 954 |
+
/// the path of the pawn, and the square of the king is not of the same color as
|
| 955 |
+
/// the stronger side's bishop, it's a draw.
|
| 956 |
+
template<>
|
| 957 |
+
ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
|
| 958 |
+
|
| 959 |
+
assert(verify_material(pos, strongSide, BishopValueMg, 1));
|
| 960 |
+
assert(verify_material(pos, weakSide, KnightValueMg, 0));
|
| 961 |
+
|
| 962 |
+
Square strongPawn = pos.square<PAWN>(strongSide);
|
| 963 |
+
Square strongBishop = pos.square<BISHOP>(strongSide);
|
| 964 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 965 |
+
|
| 966 |
+
if ( file_of(weakKing) == file_of(strongPawn)
|
| 967 |
+
&& relative_rank(strongSide, strongPawn) < relative_rank(strongSide, weakKing)
|
| 968 |
+
&& ( opposite_colors(weakKing, strongBishop)
|
| 969 |
+
|| relative_rank(strongSide, weakKing) <= RANK_6))
|
| 970 |
+
return SCALE_FACTOR_DRAW;
|
| 971 |
+
|
| 972 |
+
return SCALE_FACTOR_NONE;
|
| 973 |
+
}
|
| 974 |
+
|
| 975 |
+
|
| 976 |
+
/// KP vs KP. This is done by removing the weakest side's pawn and probing the
|
| 977 |
+
/// KP vs K bitbase: if the weakest side has a draw without the pawn, it probably
|
| 978 |
+
/// has at least a draw with the pawn as well. The exception is when the stronger
|
| 979 |
+
/// side's pawn is far advanced and not on a rook file; in this case it is often
|
| 980 |
+
/// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
|
| 981 |
+
template<>
|
| 982 |
+
ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
|
| 983 |
+
|
| 984 |
+
assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
|
| 985 |
+
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 986 |
+
|
| 987 |
+
// Assume strongSide is white and the pawn is on files A-D
|
| 988 |
+
Square strongKing = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
| 989 |
+
Square weakKing = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 990 |
+
Square strongPawn = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 991 |
+
|
| 992 |
+
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
|
| 993 |
+
|
| 994 |
+
// If the pawn has advanced to the fifth rank or further, and is not a
|
| 995 |
+
// rook pawn, it's too dangerous to assume that it's at least a draw.
|
| 996 |
+
if (rank_of(strongPawn) >= RANK_5 && file_of(strongPawn) != FILE_A)
|
| 997 |
+
return SCALE_FACTOR_NONE;
|
| 998 |
+
|
| 999 |
+
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
|
| 1000 |
+
// it's probably at least a draw even with the pawn.
|
| 1001 |
+
if ( pos.promotion_zone(us) != rank_bb(relative_rank(us, RANK_8, pos.max_rank()))
|
| 1002 |
+
|| RANK_MAX != RANK_8
|
| 1003 |
+
|| !(pos.promotion_piece_types(us) & QUEEN))
|
| 1004 |
+
return SCALE_FACTOR_NONE;
|
| 1005 |
+
|
| 1006 |
+
return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
| 1007 |
+
}
|
| 1008 |
+
|
| 1009 |
+
|
| 1010 |
+
/// Endgame evals for special variants
|
| 1011 |
+
/// R vs K. The rook side always wins if there is no immediate forced capture.
|
| 1012 |
+
template<>
|
| 1013 |
+
Value Endgame<RK, EG_EVAL_ANTI>::operator()(const Position& pos) const {
|
| 1014 |
+
|
| 1015 |
+
assert(pos.endgame_eval() == EG_EVAL_ANTI);
|
| 1016 |
+
|
| 1017 |
+
Square RSq = pos.square<ROOK>(strongSide);
|
| 1018 |
+
Square KSq = pos.square<COMMONER>(weakSide);
|
| 1019 |
+
|
| 1020 |
+
Value result = Value(push_to_edge(KSq, pos)) + push_close(RSq, KSq);
|
| 1021 |
+
|
| 1022 |
+
int dist_min = std::min(distance<Rank>(RSq, KSq), distance<File>(RSq, KSq));
|
| 1023 |
+
int dist_max = std::max(distance<Rank>(RSq, KSq), distance<File>(RSq, KSq));
|
| 1024 |
+
|
| 1025 |
+
if (dist_min == 0)
|
| 1026 |
+
result += strongSide == pos.side_to_move() || dist_max > 1 ? -VALUE_KNOWN_WIN : VALUE_KNOWN_WIN;
|
| 1027 |
+
else if (dist_min == 1)
|
| 1028 |
+
result += weakSide == pos.side_to_move() && dist_max > 1 ? -VALUE_KNOWN_WIN : VALUE_KNOWN_WIN;
|
| 1029 |
+
else
|
| 1030 |
+
result += VALUE_KNOWN_WIN;
|
| 1031 |
+
|
| 1032 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1033 |
+
}
|
| 1034 |
+
|
| 1035 |
+
|
| 1036 |
+
/// K vs N. The king usually wins, but there are a few exceptions.
|
| 1037 |
+
template<>
|
| 1038 |
+
Value Endgame<KN, EG_EVAL_ANTI>::operator()(const Position& pos) const {
|
| 1039 |
+
|
| 1040 |
+
assert(pos.endgame_eval() == EG_EVAL_ANTI);
|
| 1041 |
+
|
| 1042 |
+
Square KSq = pos.square<COMMONER>(strongSide);
|
| 1043 |
+
Square NSq = pos.square<KNIGHT>(weakSide);
|
| 1044 |
+
Bitboard kingAttacks = attacks_bb<KING>(KSq) & pos.board_bb();
|
| 1045 |
+
Bitboard knightAttacks = attacks_bb<KNIGHT>(NSq) & pos.board_bb();
|
| 1046 |
+
bool strongSideToMove = pos.side_to_move() == strongSide;
|
| 1047 |
+
|
| 1048 |
+
// Loss in 1 play
|
| 1049 |
+
if (strongSideToMove ? kingAttacks & NSq : knightAttacks & KSq)
|
| 1050 |
+
return VALUE_TB_LOSS_IN_MAX_PLY + 1;
|
| 1051 |
+
// Win in 2 ply
|
| 1052 |
+
if (kingAttacks & knightAttacks)
|
| 1053 |
+
return VALUE_TB_WIN_IN_MAX_PLY - 2;
|
| 1054 |
+
// Loss in 3 ply
|
| 1055 |
+
if (strongSideToMove ? knightAttacks & KSq : kingAttacks & NSq)
|
| 1056 |
+
return VALUE_TB_LOSS_IN_MAX_PLY + 3;
|
| 1057 |
+
|
| 1058 |
+
Value result = Value(push_to_edge(NSq, pos)) - push_to_edge(KSq, pos);
|
| 1059 |
+
// The king usually wins, but scenarios with king on the edge are more complicated
|
| 1060 |
+
if (!(KSq & (FileABB | FileHBB | Rank1BB | Rank8BB)))
|
| 1061 |
+
result += VALUE_KNOWN_WIN;
|
| 1062 |
+
|
| 1063 |
+
return strongSideToMove ? result : -result;
|
| 1064 |
+
}
|
| 1065 |
+
|
| 1066 |
+
/// N vs N. The side to move always wins/loses if the knights are on
|
| 1067 |
+
/// same/opposite colored squares.
|
| 1068 |
+
template<>
|
| 1069 |
+
Value Endgame<NN, EG_EVAL_ANTI>::operator()(const Position& pos) const {
|
| 1070 |
+
|
| 1071 |
+
assert(pos.endgame_eval() == EG_EVAL_ANTI);
|
| 1072 |
+
|
| 1073 |
+
Square N1Sq = pos.square<KNIGHT>(pos.side_to_move());
|
| 1074 |
+
Square N2Sq = pos.square<KNIGHT>(~pos.side_to_move());
|
| 1075 |
+
|
| 1076 |
+
Value result = VALUE_KNOWN_WIN + push_close(N1Sq, N2Sq);
|
| 1077 |
+
|
| 1078 |
+
return !opposite_colors(N1Sq, N2Sq) ? result : -result;
|
| 1079 |
+
}
|
| 1080 |
+
|
| 1081 |
+
|
| 1082 |
+
template<>
|
| 1083 |
+
Value Endgame<KXK, EG_EVAL_ATOMIC>::operator()(const Position& pos) const {
|
| 1084 |
+
|
| 1085 |
+
assert(pos.endgame_eval() == EG_EVAL_ATOMIC);
|
| 1086 |
+
|
| 1087 |
+
// Stalemate/checkmate detection with lone king
|
| 1088 |
+
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
|
| 1089 |
+
return std::min(pos.stalemate_value(), VALUE_MATE_IN_MAX_PLY - 1);
|
| 1090 |
+
|
| 1091 |
+
Square winnerKSq = pos.square<COMMONER>(strongSide);
|
| 1092 |
+
Square loserKSq = pos.square<COMMONER>(weakSide);
|
| 1093 |
+
|
| 1094 |
+
Value result = pos.non_pawn_material(strongSide)
|
| 1095 |
+
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
| 1096 |
+
+ push_to_edge(loserKSq, pos)
|
| 1097 |
+
+ push_away(winnerKSq, loserKSq);
|
| 1098 |
+
|
| 1099 |
+
// We need at least a major and a minor, or three minors to force checkmate
|
| 1100 |
+
if ( ((pos.count<QUEEN>(strongSide) || pos.count<ROOK>(strongSide)) && pos.count<ALL_PIECES>(strongSide) >= 3)
|
| 1101 |
+
|| (pos.count<BISHOP>(strongSide) + pos.count<KNIGHT>(strongSide) >= 3
|
| 1102 |
+
&& (pos.count<KNIGHT>(strongSide) >= 2 || ((pos.pieces(strongSide, BISHOP) & DarkSquares)
|
| 1103 |
+
&& (pos.pieces(strongSide, BISHOP) & ~DarkSquares)))))
|
| 1104 |
+
result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
|
| 1105 |
+
|
| 1106 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1107 |
+
}
|
| 1108 |
+
|
| 1109 |
+
template<>
|
| 1110 |
+
Value Endgame<KPK, EG_EVAL_ATOMIC>::operator()(const Position& pos) const {
|
| 1111 |
+
|
| 1112 |
+
assert(pos.endgame_eval() == EG_EVAL_ATOMIC);
|
| 1113 |
+
|
| 1114 |
+
Square winnerKSq = pos.square<COMMONER>(strongSide);
|
| 1115 |
+
Square loserKSq = pos.square<COMMONER>(weakSide);
|
| 1116 |
+
|
| 1117 |
+
int dist = distance(winnerKSq, loserKSq);
|
| 1118 |
+
// Draw in case of adjacent kings
|
| 1119 |
+
if (dist <= (strongSide == pos.side_to_move() ? 1 : 2))
|
| 1120 |
+
return VALUE_DRAW;
|
| 1121 |
+
|
| 1122 |
+
Value result = PawnValueEg
|
| 1123 |
+
+ 20 * relative_rank(strongSide, pos.square<PAWN>(strongSide), pos.max_rank()) - 20
|
| 1124 |
+
+ push_away(winnerKSq, loserKSq);
|
| 1125 |
+
|
| 1126 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1127 |
+
}
|
| 1128 |
+
|
| 1129 |
+
template<> Value Endgame<KNK, EG_EVAL_ATOMIC>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 1130 |
+
|
| 1131 |
+
template<> Value Endgame<KBK, EG_EVAL_ATOMIC>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 1132 |
+
|
| 1133 |
+
template<> Value Endgame<KRK, EG_EVAL_ATOMIC>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 1134 |
+
|
| 1135 |
+
template<>
|
| 1136 |
+
Value Endgame<KQK, EG_EVAL_ATOMIC>::operator()(const Position& pos) const {
|
| 1137 |
+
|
| 1138 |
+
assert(pos.endgame_eval() == EG_EVAL_ATOMIC);
|
| 1139 |
+
|
| 1140 |
+
// Stalemate/checkmate detection with lone king
|
| 1141 |
+
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
|
| 1142 |
+
return std::min(pos.stalemate_value(), VALUE_MATE_IN_MAX_PLY - 1);
|
| 1143 |
+
|
| 1144 |
+
Square winnerKSq = pos.square<COMMONER>(strongSide);
|
| 1145 |
+
Square loserKSq = pos.square<COMMONER>(weakSide);
|
| 1146 |
+
|
| 1147 |
+
int dist = distance(winnerKSq, loserKSq);
|
| 1148 |
+
// Draw in case of adjacent kings
|
| 1149 |
+
if (dist == 1)
|
| 1150 |
+
return VALUE_DRAW;
|
| 1151 |
+
// If the weaker side is to move and there is a way to connect kings, it is a draw
|
| 1152 |
+
if ( pos.side_to_move() == weakSide
|
| 1153 |
+
&& (attacks_bb<KING>(winnerKSq) & attacks_bb<KING>(loserKSq) & ~pos.pieces()))
|
| 1154 |
+
return VALUE_DRAW;
|
| 1155 |
+
|
| 1156 |
+
Value result = Value(push_to_edge(loserKSq, pos))
|
| 1157 |
+
+ push_away(winnerKSq, loserKSq);
|
| 1158 |
+
|
| 1159 |
+
if (dist >= (strongSide == pos.side_to_move() ? 3 : 4))
|
| 1160 |
+
result += VALUE_KNOWN_WIN;
|
| 1161 |
+
|
| 1162 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1163 |
+
}
|
| 1164 |
+
|
| 1165 |
+
template<> Value Endgame<KNNK, EG_EVAL_ATOMIC>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 1166 |
+
|
| 1167 |
+
|
| 1168 |
+
/// Self-mate with KX vs KX.
|
| 1169 |
+
template<>
|
| 1170 |
+
Value Endgame<KXKX, EG_EVAL_MISERE>::operator()(const Position& pos) const {
|
| 1171 |
+
|
| 1172 |
+
assert(!pos.checkers()); // Eval is never called when in check
|
| 1173 |
+
|
| 1174 |
+
// Stalemate detection with lone king
|
| 1175 |
+
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
|
| 1176 |
+
return VALUE_DRAW;
|
| 1177 |
+
|
| 1178 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 1179 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 1180 |
+
|
| 1181 |
+
Value result = pos.non_pawn_material(strongSide) * int(VALUE_KNOWN_WIN) / int(VALUE_KNOWN_WIN + pos.non_pawn_material(strongSide))
|
| 1182 |
+
- pos.non_pawn_material(weakSide)
|
| 1183 |
+
+ pos.count<PAWN>(weakSide) * PawnValueEg
|
| 1184 |
+
+ push_to_opposing_edge(relative_square(weakSide, strongKing, pos.max_rank()), pos) * 2
|
| 1185 |
+
+ push_close(strongKing, weakKing) * 2;
|
| 1186 |
+
|
| 1187 |
+
for (Bitboard b = pos.pieces(PAWN); b;)
|
| 1188 |
+
{
|
| 1189 |
+
Square s = pop_lsb(b);
|
| 1190 |
+
result += (push_close(strongKing, s) + push_close(weakKing, s)) / 2;
|
| 1191 |
+
}
|
| 1192 |
+
|
| 1193 |
+
if (!pos.count<PAWN>(weakSide))
|
| 1194 |
+
result = VALUE_DRAW;
|
| 1195 |
+
else if (pos.count<PAWN>(weakSide) == 1)
|
| 1196 |
+
result = result / 2;
|
| 1197 |
+
|
| 1198 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1199 |
+
}
|
| 1200 |
+
|
| 1201 |
+
|
| 1202 |
+
/// Mate with KX vs K. This function is used to evaluate positions with
|
| 1203 |
+
/// king and plenty of material vs a lone king. It simply gives the
|
| 1204 |
+
/// attacking side a bonus for driving the defending king towards the edge
|
| 1205 |
+
/// of the board, and for keeping the distance between the two kings small.
|
| 1206 |
+
template<>
|
| 1207 |
+
Value Endgame<KXK, EG_EVAL_DUCK>::operator()(const Position& pos) const {
|
| 1208 |
+
|
| 1209 |
+
Square strongKing = pos.square<COMMONER>(strongSide);
|
| 1210 |
+
Square weakKing = pos.square<COMMONER>(weakSide);
|
| 1211 |
+
|
| 1212 |
+
Value result = pos.non_pawn_material(strongSide)
|
| 1213 |
+
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
| 1214 |
+
+ push_to_edge(weakKing, pos)
|
| 1215 |
+
+ push_close(strongKing, weakKing);
|
| 1216 |
+
|
| 1217 |
+
result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
| 1218 |
+
|
| 1219 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1220 |
+
}
|
| 1221 |
+
|
| 1222 |
+
|
| 1223 |
+
/// Drawish, but king should stay away from the edge
|
| 1224 |
+
template<>
|
| 1225 |
+
Value Endgame<KNK, EG_EVAL_DUCK>::operator()(const Position& pos) const {
|
| 1226 |
+
|
| 1227 |
+
Square strongKing = pos.square<COMMONER>(strongSide);
|
| 1228 |
+
Square weakKing = pos.square<COMMONER>(weakSide);
|
| 1229 |
+
|
| 1230 |
+
Value result = Value(push_to_edge(weakKing, pos))
|
| 1231 |
+
+ push_close(strongKing, weakKing);
|
| 1232 |
+
|
| 1233 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1234 |
+
}
|
| 1235 |
+
|
| 1236 |
+
|
| 1237 |
+
/// Drawish, but king should stay away from the edge
|
| 1238 |
+
template<>
|
| 1239 |
+
Value Endgame<KBK, EG_EVAL_DUCK>::operator()(const Position& pos) const {
|
| 1240 |
+
|
| 1241 |
+
Square strongKing = pos.square<COMMONER>(strongSide);
|
| 1242 |
+
Square weakKing = pos.square<COMMONER>(weakSide);
|
| 1243 |
+
|
| 1244 |
+
Value result = Value(push_to_edge(weakKing, pos))
|
| 1245 |
+
+ push_close(strongKing, weakKing);
|
| 1246 |
+
|
| 1247 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1248 |
+
}
|
| 1249 |
+
|
| 1250 |
+
|
| 1251 |
+
/// Winning as long as pawn is safe
|
| 1252 |
+
template<>
|
| 1253 |
+
Value Endgame<KPK, EG_EVAL_DUCK>::operator()(const Position& pos) const {
|
| 1254 |
+
|
| 1255 |
+
Square strongKing = pos.square<COMMONER>(strongSide);
|
| 1256 |
+
Square weakKing = pos.square<COMMONER>(weakSide);
|
| 1257 |
+
Square strongPawn = pos.square<PAWN>(strongSide);
|
| 1258 |
+
|
| 1259 |
+
Value result = PawnValueEg + 50 * relative_rank(strongSide, strongPawn, pos.max_rank())
|
| 1260 |
+
+ push_to_edge(weakKing, pos)
|
| 1261 |
+
+ push_close(strongKing, weakKing)
|
| 1262 |
+
+ push_close(strongKing, strongPawn) / 2
|
| 1263 |
+
+ push_away(weakKing, strongPawn) / 2;
|
| 1264 |
+
|
| 1265 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1266 |
+
}
|
| 1267 |
+
|
| 1268 |
+
/// Winning as long as last rank can be blocked
|
| 1269 |
+
template<>
|
| 1270 |
+
Value Endgame<KQK, EG_EVAL_RK>::operator()(const Position& pos) const {
|
| 1271 |
+
|
| 1272 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 1273 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 1274 |
+
Square strongQueen = pos.square<QUEEN>(strongSide);
|
| 1275 |
+
|
| 1276 |
+
Value result;
|
| 1277 |
+
|
| 1278 |
+
if ( rank_of(weakKing) < rank_of(strongQueen)
|
| 1279 |
+
|| rank_of(weakKing) + (weakSide == pos.side_to_move()) < RANK_7
|
| 1280 |
+
|| (Rank8BB & attacks_bb<QUEEN>(strongQueen, pos.pieces()) & ~(attacks_bb<QUEEN>(weakKing) | attacks_bb<SHOGI_KNIGHT>(weakKing))))
|
| 1281 |
+
result = VALUE_KNOWN_WIN + 100 * rank_of(strongKing);
|
| 1282 |
+
else
|
| 1283 |
+
result = -VALUE_KNOWN_WIN;
|
| 1284 |
+
|
| 1285 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1286 |
+
}
|
| 1287 |
+
|
| 1288 |
+
/// Winning as long as last rank can be blocked
|
| 1289 |
+
template<>
|
| 1290 |
+
Value Endgame<KRK, EG_EVAL_RK>::operator()(const Position& pos) const {
|
| 1291 |
+
|
| 1292 |
+
Square strongKing = pos.square<KING>(strongSide);
|
| 1293 |
+
Square weakKing = pos.square<KING>(weakSide);
|
| 1294 |
+
Square strongRook = pos.square<ROOK>(strongSide);
|
| 1295 |
+
|
| 1296 |
+
Value result;
|
| 1297 |
+
|
| 1298 |
+
if ( rank_of(weakKing) < rank_of(strongRook)
|
| 1299 |
+
|| rank_of(weakKing) + (weakSide == pos.side_to_move()) < RANK_7
|
| 1300 |
+
|| (Rank8BB & attacks_bb<ROOK>(strongRook, pos.pieces()) & ~(attacks_bb<QUEEN>(weakKing) | attacks_bb<SHOGI_KNIGHT>(weakKing))))
|
| 1301 |
+
result = VALUE_KNOWN_WIN + 100 * rank_of(strongKing);
|
| 1302 |
+
else
|
| 1303 |
+
result = -VALUE_KNOWN_WIN;
|
| 1304 |
+
|
| 1305 |
+
return strongSide == pos.side_to_move() ? result : -result;
|
| 1306 |
+
}
|
| 1307 |
+
|
| 1308 |
+
/// KvK. Pure race
|
| 1309 |
+
template<>
|
| 1310 |
+
Value Endgame<KK, EG_EVAL_RK>::operator()(const Position& pos) const {
|
| 1311 |
+
|
| 1312 |
+
Square whiteKing = pos.square<KING>(WHITE);
|
| 1313 |
+
Square blackKing = pos.square<KING>(BLACK);
|
| 1314 |
+
|
| 1315 |
+
Value result = (VALUE_KNOWN_WIN + 100 * std::max(rank_of(whiteKing), rank_of(blackKing)))
|
| 1316 |
+
* std::clamp(rank_of(whiteKing) - rank_of(blackKing) - (pos.side_to_move() == BLACK), -1, 1);
|
| 1317 |
+
|
| 1318 |
+
return pos.side_to_move() == WHITE ? result : -result;
|
| 1319 |
+
}
|
| 1320 |
+
|
| 1321 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/endgame.h
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef ENDGAME_H_INCLUDED
|
| 20 |
+
#define ENDGAME_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <memory>
|
| 23 |
+
#include <string>
|
| 24 |
+
#include <type_traits>
|
| 25 |
+
#include <unordered_map>
|
| 26 |
+
#include <utility>
|
| 27 |
+
|
| 28 |
+
#include "position.h"
|
| 29 |
+
#include "types.h"
|
| 30 |
+
|
| 31 |
+
namespace Stockfish {
|
| 32 |
+
|
| 33 |
+
/// EndgameCode lists all supported endgame functions by corresponding codes
|
| 34 |
+
|
| 35 |
+
enum EndgameCode {
|
| 36 |
+
|
| 37 |
+
EVALUATION_FUNCTIONS,
|
| 38 |
+
KNNK, // KNN vs K
|
| 39 |
+
KNNKP, // KNN vs KP
|
| 40 |
+
KXK, // Generic "mate lone king" eval
|
| 41 |
+
KBNK, // KBN vs K
|
| 42 |
+
KPK, // KP vs K
|
| 43 |
+
KRKP, // KR vs KP
|
| 44 |
+
KRKB, // KR vs KB
|
| 45 |
+
KRKN, // KR vs KN
|
| 46 |
+
KQKP, // KQ vs KP
|
| 47 |
+
KQKR, // KQ vs KR
|
| 48 |
+
|
| 49 |
+
// Fairy piece endgames
|
| 50 |
+
KFsPsK, // KFsPsK vs K
|
| 51 |
+
KNSK, // KNS vs K
|
| 52 |
+
KNFK, // KNF vs K
|
| 53 |
+
KNSFKR, // KNSFKR vs K
|
| 54 |
+
KSFK, // KSF vs K
|
| 55 |
+
KSFKF, // KSF vs KF
|
| 56 |
+
KRKS, // KR vs KS
|
| 57 |
+
KCKR, // KC vs KR
|
| 58 |
+
KAKR, // KA vs KR
|
| 59 |
+
|
| 60 |
+
// Special
|
| 61 |
+
KXKX,
|
| 62 |
+
RK,
|
| 63 |
+
KN,
|
| 64 |
+
NN,
|
| 65 |
+
KQK,
|
| 66 |
+
KRK,
|
| 67 |
+
KBK,
|
| 68 |
+
KNK,
|
| 69 |
+
KK,
|
| 70 |
+
|
| 71 |
+
SCALING_FUNCTIONS,
|
| 72 |
+
KBPsK, // KB and pawns vs K
|
| 73 |
+
KQKRPs, // KQ vs KR and pawns
|
| 74 |
+
KRPKR, // KRP vs KR
|
| 75 |
+
KRPKB, // KRP vs KB
|
| 76 |
+
KRPPKRP, // KRPP vs KRP
|
| 77 |
+
KPsK, // K and pawns vs K
|
| 78 |
+
KBPKB, // KBP vs KB
|
| 79 |
+
KBPPKB, // KBPP vs KB
|
| 80 |
+
KBPKN, // KBP vs KN
|
| 81 |
+
KPKP // KP vs KP
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
/// Endgame functions can be of two types depending on whether they return a
|
| 86 |
+
/// Value or a ScaleFactor.
|
| 87 |
+
|
| 88 |
+
template<EndgameCode E, EndgameEval V = EG_EVAL_CHESS> using
|
| 89 |
+
eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
/// Base and derived functors for endgame evaluation and scaling functions
|
| 93 |
+
|
| 94 |
+
template<typename T>
|
| 95 |
+
struct EndgameBase {
|
| 96 |
+
|
| 97 |
+
explicit EndgameBase(Color c) : strongSide(c), weakSide(~c) {}
|
| 98 |
+
virtual ~EndgameBase() = default;
|
| 99 |
+
virtual T operator()(const Position&) const = 0;
|
| 100 |
+
|
| 101 |
+
const Color strongSide, weakSide;
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
template<EndgameCode E, EndgameEval V = EG_EVAL_CHESS, typename T = eg_type<E, V>>
|
| 106 |
+
struct Endgame : public EndgameBase<T> {
|
| 107 |
+
|
| 108 |
+
explicit Endgame(Color c) : EndgameBase<T>(c) {}
|
| 109 |
+
T operator()(const Position&) const override;
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
/// The Endgames namespace handles the pointers to endgame evaluation and scaling
|
| 114 |
+
/// base objects in two std::map. We use polymorphism to invoke the actual
|
| 115 |
+
/// endgame function by calling its virtual operator().
|
| 116 |
+
|
| 117 |
+
namespace Endgames {
|
| 118 |
+
|
| 119 |
+
template<typename T> using Ptr = std::unique_ptr<EndgameBase<T>>;
|
| 120 |
+
template<typename T> using Map = std::unordered_map<Key, Ptr<T>>;
|
| 121 |
+
|
| 122 |
+
extern std::pair<Map<Value>, Map<ScaleFactor>> maps;
|
| 123 |
+
|
| 124 |
+
void init();
|
| 125 |
+
|
| 126 |
+
template<typename T>
|
| 127 |
+
Map<T>& map() {
|
| 128 |
+
return std::get<std::is_same<T, ScaleFactor>::value>(maps);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
template<EndgameCode E, EndgameEval V = EG_EVAL_CHESS, typename T = eg_type<E, V>>
|
| 132 |
+
void add(const std::string& code) {
|
| 133 |
+
|
| 134 |
+
StateInfo st;
|
| 135 |
+
map<T>()[Position().set(code, WHITE, &st).material_key(V)] = Ptr<T>(new Endgame<E, V>(WHITE));
|
| 136 |
+
map<T>()[Position().set(code, BLACK, &st).material_key(V)] = Ptr<T>(new Endgame<E, V>(BLACK));
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
template<typename T>
|
| 140 |
+
const EndgameBase<T>* probe(Key key) {
|
| 141 |
+
auto it = map<T>().find(key);
|
| 142 |
+
return it != map<T>().end() ? it->second.get() : nullptr;
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
} // namespace Stockfish
|
| 147 |
+
|
| 148 |
+
#endif // #ifndef ENDGAME_H_INCLUDED
|
Fairy-Stockfish-master/src/evaluate.cpp
ADDED
|
@@ -0,0 +1,1736 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <algorithm>
|
| 20 |
+
#include <cassert>
|
| 21 |
+
#include <cstdlib>
|
| 22 |
+
#include <cstring> // For std::memset
|
| 23 |
+
#include <fstream>
|
| 24 |
+
#include <iomanip>
|
| 25 |
+
#include <sstream>
|
| 26 |
+
#include <iostream>
|
| 27 |
+
#include <streambuf>
|
| 28 |
+
#include <vector>
|
| 29 |
+
|
| 30 |
+
#include "bitboard.h"
|
| 31 |
+
#include "evaluate.h"
|
| 32 |
+
#include "material.h"
|
| 33 |
+
#include "misc.h"
|
| 34 |
+
#include "pawns.h"
|
| 35 |
+
#include "thread.h"
|
| 36 |
+
#include "timeman.h"
|
| 37 |
+
#include "uci.h"
|
| 38 |
+
#include "incbin/incbin.h"
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
// Macro to embed the default efficiently updatable neural network (NNUE) file
|
| 42 |
+
// data in the engine binary (using incbin.h, by Dale Weiler).
|
| 43 |
+
// This macro invocation will declare the following three variables
|
| 44 |
+
// const unsigned char gEmbeddedNNUEData[]; // a pointer to the embedded data
|
| 45 |
+
// const unsigned char *const gEmbeddedNNUEEnd; // a marker to the end
|
| 46 |
+
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
|
| 47 |
+
// Note that this does not work in Microsoft Visual Studio.
|
| 48 |
+
#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
|
| 49 |
+
INCBIN(EmbeddedNNUE, EvalFileDefaultName);
|
| 50 |
+
#else
|
| 51 |
+
const unsigned char gEmbeddedNNUEData[1] = {0x0};
|
| 52 |
+
[[maybe_unused]]
|
| 53 |
+
const unsigned char *const gEmbeddedNNUEEnd = &gEmbeddedNNUEData[1];
|
| 54 |
+
const unsigned int gEmbeddedNNUESize = 1;
|
| 55 |
+
#endif
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
using namespace std;
|
| 59 |
+
|
| 60 |
+
namespace Stockfish {
|
| 61 |
+
|
| 62 |
+
const Variant* currentNnueVariant;
|
| 63 |
+
|
| 64 |
+
namespace Eval {
|
| 65 |
+
|
| 66 |
+
bool useNNUE;
|
| 67 |
+
string eval_file_loaded = "None";
|
| 68 |
+
|
| 69 |
+
/// NNUE::init() tries to load a NNUE network at startup time, or when the engine
|
| 70 |
+
/// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
|
| 71 |
+
/// The name of the NNUE network is always retrieved from the EvalFile option.
|
| 72 |
+
/// We search the given network in three locations: internally (the default
|
| 73 |
+
/// network may be embedded in the binary), in the active working directory and
|
| 74 |
+
/// in the engine directory. Distro packagers may define the DEFAULT_NNUE_DIRECTORY
|
| 75 |
+
/// variable to have the engine search in a special directory in their distro.
|
| 76 |
+
|
| 77 |
+
void NNUE::init() {
|
| 78 |
+
|
| 79 |
+
useNNUE = Options["Use NNUE"];
|
| 80 |
+
if (!useNNUE)
|
| 81 |
+
return;
|
| 82 |
+
|
| 83 |
+
string eval_file = string(Options["EvalFile"]);
|
| 84 |
+
|
| 85 |
+
// Restrict NNUE usage to corresponding variant
|
| 86 |
+
// Support multiple variant networks separated by semicolon(Windows)/colon(Unix)
|
| 87 |
+
stringstream ss(eval_file);
|
| 88 |
+
string variant = string(Options["UCI_Variant"]);
|
| 89 |
+
useNNUE = false;
|
| 90 |
+
while (getline(ss, eval_file, UCI::SepChar))
|
| 91 |
+
{
|
| 92 |
+
string basename = eval_file.substr(eval_file.find_last_of("\\/") + 1);
|
| 93 |
+
string nnueAlias = variants.find(variant)->second->nnueAlias;
|
| 94 |
+
if (basename.rfind(variant, 0) != string::npos || (!nnueAlias.empty() && basename.rfind(nnueAlias, 0) != string::npos))
|
| 95 |
+
{
|
| 96 |
+
useNNUE = true;
|
| 97 |
+
break;
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
if (!useNNUE)
|
| 101 |
+
return;
|
| 102 |
+
|
| 103 |
+
currentNnueVariant = variants.find(variant)->second;
|
| 104 |
+
|
| 105 |
+
#if defined(DEFAULT_NNUE_DIRECTORY)
|
| 106 |
+
#define stringify2(x) #x
|
| 107 |
+
#define stringify(x) stringify2(x)
|
| 108 |
+
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
|
| 109 |
+
#else
|
| 110 |
+
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory };
|
| 111 |
+
#endif
|
| 112 |
+
|
| 113 |
+
for (string directory : dirs)
|
| 114 |
+
if (eval_file_loaded != eval_file)
|
| 115 |
+
{
|
| 116 |
+
if (directory != "<internal>")
|
| 117 |
+
{
|
| 118 |
+
ifstream stream(directory + eval_file, ios::binary);
|
| 119 |
+
if (load_eval(eval_file, stream))
|
| 120 |
+
eval_file_loaded = eval_file;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
if (directory == "<internal>" && eval_file == EvalFileDefaultName)
|
| 124 |
+
{
|
| 125 |
+
// C++ way to prepare a buffer for a memory stream
|
| 126 |
+
class MemoryBuffer : public basic_streambuf<char> {
|
| 127 |
+
public: MemoryBuffer(char* p, size_t n) { setg(p, p, p + n); setp(p, p + n); }
|
| 128 |
+
};
|
| 129 |
+
|
| 130 |
+
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
|
| 131 |
+
size_t(gEmbeddedNNUESize));
|
| 132 |
+
|
| 133 |
+
istream stream(&buffer);
|
| 134 |
+
if (load_eval(eval_file, stream))
|
| 135 |
+
eval_file_loaded = eval_file;
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
/// NNUE::verify() verifies that the last net used was loaded successfully
|
| 141 |
+
void NNUE::verify() {
|
| 142 |
+
|
| 143 |
+
string eval_file = string(Options["EvalFile"]);
|
| 144 |
+
|
| 145 |
+
if (useNNUE && eval_file.find(eval_file_loaded) == string::npos)
|
| 146 |
+
{
|
| 147 |
+
UCI::OptionsMap defaults;
|
| 148 |
+
UCI::init(defaults);
|
| 149 |
+
|
| 150 |
+
string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
|
| 151 |
+
string msg2 = "The option is set to true, but the network file " + eval_file + " was not loaded successfully.";
|
| 152 |
+
string msg3 = "The UCI option EvalFile might need to specify the full path, including the directory name, to the network file.";
|
| 153 |
+
string msg4 = "The default net can be downloaded from: https://tests.stockfishchess.org/api/nn/" + string(defaults["EvalFile"]);
|
| 154 |
+
string msg5 = "The engine will be terminated now.";
|
| 155 |
+
|
| 156 |
+
sync_cout << "info string ERROR: " << msg1 << sync_endl;
|
| 157 |
+
sync_cout << "info string ERROR: " << msg2 << sync_endl;
|
| 158 |
+
sync_cout << "info string ERROR: " << msg3 << sync_endl;
|
| 159 |
+
sync_cout << "info string ERROR: " << msg4 << sync_endl;
|
| 160 |
+
sync_cout << "info string ERROR: " << msg5 << sync_endl;
|
| 161 |
+
|
| 162 |
+
exit(EXIT_FAILURE);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
if (CurrentProtocol != XBOARD)
|
| 166 |
+
{
|
| 167 |
+
if (useNNUE)
|
| 168 |
+
sync_cout << "info string NNUE evaluation using " << eval_file_loaded << " enabled" << sync_endl;
|
| 169 |
+
else
|
| 170 |
+
sync_cout << "info string classical evaluation enabled" << sync_endl;
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
namespace Trace {
|
| 176 |
+
|
| 177 |
+
enum Tracing { NO_TRACE, TRACE };
|
| 178 |
+
|
| 179 |
+
enum Term { // The first PIECE_TYPE_NB entries are reserved for PieceType
|
| 180 |
+
MATERIAL = PIECE_TYPE_NB, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, VARIANT, WINNABLE, TOTAL, TERM_NB
|
| 181 |
+
};
|
| 182 |
+
|
| 183 |
+
Score scores[TERM_NB][COLOR_NB];
|
| 184 |
+
|
| 185 |
+
double to_cp(Value v) { return double(v) / PawnValueEg; }
|
| 186 |
+
|
| 187 |
+
void add(int idx, Color c, Score s) {
|
| 188 |
+
scores[idx][c] = s;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
void add(int idx, Score w, Score b = SCORE_ZERO) {
|
| 192 |
+
scores[idx][WHITE] = w;
|
| 193 |
+
scores[idx][BLACK] = b;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
std::ostream& operator<<(std::ostream& os, Score s) {
|
| 197 |
+
os << std::setw(5) << to_cp(mg_value(s)) << " "
|
| 198 |
+
<< std::setw(5) << to_cp(eg_value(s));
|
| 199 |
+
return os;
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
std::ostream& operator<<(std::ostream& os, Term t) {
|
| 203 |
+
|
| 204 |
+
if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
|
| 205 |
+
os << " ---- ----" << " | " << " ---- ----";
|
| 206 |
+
else
|
| 207 |
+
os << scores[t][WHITE] << " | " << scores[t][BLACK];
|
| 208 |
+
|
| 209 |
+
os << " | " << scores[t][WHITE] - scores[t][BLACK] << " |\n";
|
| 210 |
+
return os;
|
| 211 |
+
}
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
using namespace Trace;
|
| 215 |
+
|
| 216 |
+
namespace {
|
| 217 |
+
|
| 218 |
+
// Threshold for lazy and space evaluation
|
| 219 |
+
constexpr Value LazyThreshold1 = Value(1565);
|
| 220 |
+
constexpr Value LazyThreshold2 = Value(1102);
|
| 221 |
+
constexpr Value SpaceThreshold = Value(11551);
|
| 222 |
+
|
| 223 |
+
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
| 224 |
+
constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10, 40 };
|
| 225 |
+
|
| 226 |
+
// SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
|
| 227 |
+
// higher if multiple safe checks are possible for that piece type.
|
| 228 |
+
constexpr int SafeCheck[][2] = {
|
| 229 |
+
{}, {600, 600}, {803, 1292}, {639, 974}, {1087, 1878}, {759, 1132}, {600, 900}
|
| 230 |
+
};
|
| 231 |
+
|
| 232 |
+
#define S(mg, eg) make_score(mg, eg)
|
| 233 |
+
|
| 234 |
+
// MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game,
|
| 235 |
+
// indexed by piece type and number of attacked squares in the mobility area.
|
| 236 |
+
constexpr Score MobilityBonus[][4 * RANK_NB] = {
|
| 237 |
+
{ S(-62,-79), S(-53,-57), S(-12,-31), S( -3,-17), S( 3, 7), S( 12, 13), // Knight
|
| 238 |
+
S( 21, 16), S( 28, 21), S( 37, 26) },
|
| 239 |
+
{ S(-47,-59), S(-20,-25), S( 14, -8), S( 29, 12), S( 39, 21), S( 53, 40), // Bishop
|
| 240 |
+
S( 53, 56), S( 60, 58), S( 62, 65), S( 69, 72), S( 78, 78), S( 83, 87),
|
| 241 |
+
S( 91, 88), S( 96, 98) },
|
| 242 |
+
{ S(-60,-82), S(-24,-15), S( 0, 17) ,S( 3, 43), S( 4, 72), S( 14,100), // Rook
|
| 243 |
+
S( 20,102), S( 30,122), S( 41,133), S(41 ,139), S( 41,153), S( 45,160),
|
| 244 |
+
S( 57,165), S( 58,170), S( 67,175) },
|
| 245 |
+
{ S(-29,-49), S(-16,-29), S( -8, -8), S( -8, 17), S( 18, 39), S( 25, 54), // Queen
|
| 246 |
+
S( 23, 59), S( 37, 73), S( 41, 76), S( 54, 95), S( 65, 95) ,S( 68,101),
|
| 247 |
+
S( 69,124), S( 70,128), S( 70,132), S( 70,133) ,S( 71,136), S( 72,140),
|
| 248 |
+
S( 74,147), S( 76,149), S( 90,153), S(104,169), S(105,171), S(106,171),
|
| 249 |
+
S(112,178), S(114,185), S(114,187), S(119,221) }
|
| 250 |
+
};
|
| 251 |
+
constexpr Score MaxMobility = S(150, 200);
|
| 252 |
+
constexpr Score DropMobility = S(10, 10);
|
| 253 |
+
|
| 254 |
+
// BishopPawns[distance from edge] contains a file-dependent penalty for pawns on
|
| 255 |
+
// squares of the same color as our bishop.
|
| 256 |
+
constexpr Score BishopPawns[int(FILE_NB) / 2] = {
|
| 257 |
+
S(3, 8), S(3, 9), S(2, 8), S(3, 8)
|
| 258 |
+
};
|
| 259 |
+
|
| 260 |
+
// KingProtector[knight/bishop] contains penalty for each distance unit to own king
|
| 261 |
+
constexpr Score KingProtector[] = { S(8, 9), S(6, 9) };
|
| 262 |
+
|
| 263 |
+
// Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
|
| 264 |
+
// pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
|
| 265 |
+
constexpr Score Outpost[] = { S(57, 38), S(31, 24) };
|
| 266 |
+
|
| 267 |
+
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
|
| 268 |
+
constexpr Score PassedRank[RANK_NB] = {
|
| 269 |
+
S(0, 0), S(7, 27), S(16, 32), S(17, 40), S(64, 71), S(170, 174), S(278, 262)
|
| 270 |
+
};
|
| 271 |
+
|
| 272 |
+
constexpr Score RookOnClosedFile = S(10, 5);
|
| 273 |
+
constexpr Score RookOnOpenFile[] = { S(19, 6), S(47, 26) };
|
| 274 |
+
|
| 275 |
+
// ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to
|
| 276 |
+
// which piece type attacks which one. Attacks on lesser pieces which are
|
| 277 |
+
// pawn-defended are not considered.
|
| 278 |
+
constexpr Score ThreatByMinor[PIECE_TYPE_NB] = {
|
| 279 |
+
S(0, 0), S(5, 32), S(55, 41), S(77, 56), S(89, 119), S(79, 162)
|
| 280 |
+
};
|
| 281 |
+
|
| 282 |
+
constexpr Score ThreatByRook[PIECE_TYPE_NB] = {
|
| 283 |
+
S(0, 0), S(3, 44), S(37, 68), S(42, 60), S(0, 39), S(58, 43)
|
| 284 |
+
};
|
| 285 |
+
|
| 286 |
+
constexpr Value CorneredBishop = Value(50);
|
| 287 |
+
|
| 288 |
+
// Assorted bonuses and penalties
|
| 289 |
+
constexpr Score UncontestedOutpost = S( 1, 10);
|
| 290 |
+
constexpr Score BishopOnKingRing = S( 24, 0);
|
| 291 |
+
constexpr Score BishopXRayPawns = S( 4, 5);
|
| 292 |
+
constexpr Score FlankAttacks = S( 8, 0);
|
| 293 |
+
constexpr Score Hanging = S( 69, 36);
|
| 294 |
+
constexpr Score KnightOnQueen = S( 16, 11);
|
| 295 |
+
constexpr Score LongDiagonalBishop = S( 45, 0);
|
| 296 |
+
constexpr Score MinorBehindPawn = S( 18, 3);
|
| 297 |
+
constexpr Score PassedFile = S( 11, 8);
|
| 298 |
+
constexpr Score PawnlessFlank = S( 17, 95);
|
| 299 |
+
constexpr Score ReachableOutpost = S( 31, 22);
|
| 300 |
+
constexpr Score RestrictedPiece = S( 7, 7);
|
| 301 |
+
constexpr Score RookOnKingRing = S( 16, 0);
|
| 302 |
+
constexpr Score SliderOnQueen = S( 60, 18);
|
| 303 |
+
constexpr Score ThreatByKing = S( 24, 89);
|
| 304 |
+
constexpr Score ThreatByPawnPush = S( 48, 39);
|
| 305 |
+
constexpr Score ThreatBySafePawn = S(173, 94);
|
| 306 |
+
constexpr Score TrappedRook = S( 55, 13);
|
| 307 |
+
constexpr Score WeakQueenProtection = S( 14, 0);
|
| 308 |
+
constexpr Score WeakQueen = S( 56, 15);
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
// Variant and fairy piece bonuses
|
| 312 |
+
constexpr Score KingProximity = S(2, 6);
|
| 313 |
+
constexpr Score EndgameKingProximity = S(0, 10);
|
| 314 |
+
constexpr Score ConnectedSoldier = S(20, 20);
|
| 315 |
+
|
| 316 |
+
constexpr int VirtualCheck = 600;
|
| 317 |
+
|
| 318 |
+
#undef S
|
| 319 |
+
|
| 320 |
+
// Evaluation class computes and stores attacks tables and other working data
|
| 321 |
+
template<Tracing T>
|
| 322 |
+
class Evaluation {
|
| 323 |
+
|
| 324 |
+
public:
|
| 325 |
+
Evaluation() = delete;
|
| 326 |
+
explicit Evaluation(const Position& p) : pos(p) {}
|
| 327 |
+
Evaluation& operator=(const Evaluation&) = delete;
|
| 328 |
+
Value value();
|
| 329 |
+
|
| 330 |
+
private:
|
| 331 |
+
template<Color Us> void initialize();
|
| 332 |
+
template<Color Us> Score pieces(PieceType Pt);
|
| 333 |
+
template<Color Us> Score hand(PieceType pt);
|
| 334 |
+
template<Color Us> Score king() const;
|
| 335 |
+
template<Color Us> Score threats() const;
|
| 336 |
+
template<Color Us> Score passed() const;
|
| 337 |
+
template<Color Us> Score space() const;
|
| 338 |
+
template<Color Us> Score variant() const;
|
| 339 |
+
Value winnable(Score score) const;
|
| 340 |
+
|
| 341 |
+
const Position& pos;
|
| 342 |
+
Material::Entry* me;
|
| 343 |
+
Pawns::Entry* pe;
|
| 344 |
+
Bitboard mobilityArea[COLOR_NB];
|
| 345 |
+
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
| 346 |
+
|
| 347 |
+
// attackedBy[color][piece type] is a bitboard representing all squares
|
| 348 |
+
// attacked by a given color and piece type. Special "piece types" which
|
| 349 |
+
// is also calculated is ALL_PIECES.
|
| 350 |
+
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
| 351 |
+
|
| 352 |
+
// attackedBy2[color] are the squares attacked by at least 2 units of a given
|
| 353 |
+
// color, including x-rays. But diagonal x-rays through pawns are not computed.
|
| 354 |
+
Bitboard attackedBy2[COLOR_NB];
|
| 355 |
+
|
| 356 |
+
// kingRing[color] are the squares adjacent to the king plus some other
|
| 357 |
+
// very near squares, depending on king position.
|
| 358 |
+
Bitboard kingRing[COLOR_NB];
|
| 359 |
+
|
| 360 |
+
// kingAttackersCount[color] is the number of pieces of the given color
|
| 361 |
+
// which attack a square in the kingRing of the enemy king.
|
| 362 |
+
int kingAttackersCount[COLOR_NB];
|
| 363 |
+
int kingAttackersCountInHand[COLOR_NB];
|
| 364 |
+
|
| 365 |
+
// kingAttackersWeight[color] is the sum of the "weights" of the pieces of
|
| 366 |
+
// the given color which attack a square in the kingRing of the enemy king.
|
| 367 |
+
// The weights of the individual piece types are given by the elements in
|
| 368 |
+
// the KingAttackWeights array.
|
| 369 |
+
int kingAttackersWeight[COLOR_NB];
|
| 370 |
+
int kingAttackersWeightInHand[COLOR_NB];
|
| 371 |
+
|
| 372 |
+
// kingAttacksCount[color] is the number of attacks by the given color to
|
| 373 |
+
// squares directly adjacent to the enemy king. Pieces which attack more
|
| 374 |
+
// than one square are counted multiple times. For instance, if there is
|
| 375 |
+
// a white knight on g5 and black's king is on g8, this white knight adds 2
|
| 376 |
+
// to kingAttacksCount[WHITE].
|
| 377 |
+
int kingAttacksCount[COLOR_NB];
|
| 378 |
+
};
|
| 379 |
+
|
| 380 |
+
|
| 381 |
+
// Evaluation::initialize() computes king and pawn attacks, and the king ring
|
| 382 |
+
// bitboard for a given color. This is done at the beginning of the evaluation.
|
| 383 |
+
|
| 384 |
+
template<Tracing T> template<Color Us>
|
| 385 |
+
void Evaluation<T>::initialize() {
|
| 386 |
+
|
| 387 |
+
constexpr Color Them = ~Us;
|
| 388 |
+
constexpr Direction Up = pawn_push(Us);
|
| 389 |
+
constexpr Direction Down = -Up;
|
| 390 |
+
Bitboard LowRanks = rank_bb(relative_rank(Us, RANK_2, pos.max_rank())) | rank_bb(relative_rank(Us, RANK_3, pos.max_rank()));
|
| 391 |
+
|
| 392 |
+
const Square ksq = pos.count<KING>(Us) ? pos.square<KING>(Us) : SQ_NONE;
|
| 393 |
+
|
| 394 |
+
Bitboard dblAttackByPawn = pawn_double_attacks_bb<Us>(pos.pieces(Us, PAWN));
|
| 395 |
+
|
| 396 |
+
// Find our pawns that are blocked or on the first two ranks
|
| 397 |
+
Bitboard b = pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | LowRanks);
|
| 398 |
+
|
| 399 |
+
// Squares occupied by those pawns, by our king or queen, by blockers to attacks on our king
|
| 400 |
+
// or controlled by enemy pawns are excluded from the mobility area.
|
| 401 |
+
if (pos.must_capture())
|
| 402 |
+
mobilityArea[Us] = AllSquares;
|
| 403 |
+
else
|
| 404 |
+
mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them)
|
| 405 |
+
| (pos.pieces(Us, SHOGI_PAWN) & shift<Down>(pos.pieces(Us)))
|
| 406 |
+
| shift<Down>(pos.pieces(Them, SHOGI_PAWN, SOLDIER))
|
| 407 |
+
| shift<EAST>(pos.promoted_soldiers(Them))
|
| 408 |
+
| shift<WEST>(pos.promoted_soldiers(Them)));
|
| 409 |
+
|
| 410 |
+
// Initialize attackedBy[] for king and pawns
|
| 411 |
+
attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from(Us, KING, ksq) : Bitboard(0);
|
| 412 |
+
attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
|
| 413 |
+
attackedBy[Us][SHOGI_PAWN] = shift<Up>(pos.pieces(Us, SHOGI_PAWN));
|
| 414 |
+
attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN] | attackedBy[Us][SHOGI_PAWN];
|
| 415 |
+
attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN])
|
| 416 |
+
| (attackedBy[Us][KING] & attackedBy[Us][SHOGI_PAWN])
|
| 417 |
+
| (attackedBy[Us][PAWN] & attackedBy[Us][SHOGI_PAWN])
|
| 418 |
+
| dblAttackByPawn;
|
| 419 |
+
|
| 420 |
+
// Init our king safety tables
|
| 421 |
+
if (!pos.count<KING>(Us))
|
| 422 |
+
kingRing[Us] = Bitboard(0);
|
| 423 |
+
else
|
| 424 |
+
{
|
| 425 |
+
Square s = make_square(std::clamp(file_of(ksq), FILE_B, File(pos.max_file() - 1)),
|
| 426 |
+
std::clamp(rank_of(ksq), RANK_2, Rank(pos.max_rank() - 1)));
|
| 427 |
+
kingRing[Us] = attacks_bb<KING>(s) | s;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
kingAttackersCount[Them] = popcount(kingRing[Us] & (pe->pawn_attacks(Them) | shift<Down>(pos.pieces(Them, SHOGI_PAWN))));
|
| 431 |
+
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
|
| 432 |
+
kingAttackersCountInHand[Them] = kingAttackersWeightInHand[Them] = 0;
|
| 433 |
+
|
| 434 |
+
// Remove from kingRing[] the squares defended by two pawns
|
| 435 |
+
kingRing[Us] &= ~dblAttackByPawn;
|
| 436 |
+
|
| 437 |
+
kingRing[Us] &= pos.board_bb();
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
|
| 441 |
+
// Evaluation::pieces() scores pieces of a given color and type
|
| 442 |
+
|
| 443 |
+
template<Tracing T> template<Color Us>
|
| 444 |
+
Score Evaluation<T>::pieces(PieceType Pt) {
|
| 445 |
+
|
| 446 |
+
constexpr Color Them = ~Us;
|
| 447 |
+
constexpr Direction Down = -pawn_push(Us);
|
| 448 |
+
constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
|
| 449 |
+
: Rank5BB | Rank4BB | Rank3BB);
|
| 450 |
+
Bitboard b1 = pos.pieces(Us, Pt);
|
| 451 |
+
Bitboard b, bb;
|
| 452 |
+
Score score = SCORE_ZERO;
|
| 453 |
+
|
| 454 |
+
attackedBy[Us][Pt] = 0;
|
| 455 |
+
|
| 456 |
+
while (b1)
|
| 457 |
+
{
|
| 458 |
+
Square s = pop_lsb(b1);
|
| 459 |
+
|
| 460 |
+
// Find attacked squares, including x-ray attacks for bishops and rooks
|
| 461 |
+
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
|
| 462 |
+
: Pt == ROOK && !pos.diagonal_lines() ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
|
| 463 |
+
: pos.attacks_from(Us, Pt, s);
|
| 464 |
+
|
| 465 |
+
// Restrict mobility to actual squares of board
|
| 466 |
+
b &= pos.board_bb(Us, Pt);
|
| 467 |
+
|
| 468 |
+
if (pos.blockers_for_king(Us) & s)
|
| 469 |
+
b &= line_bb(pos.square<KING>(Us), s);
|
| 470 |
+
|
| 471 |
+
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
|
| 472 |
+
attackedBy[Us][Pt] |= b;
|
| 473 |
+
attackedBy[Us][ALL_PIECES] |= b;
|
| 474 |
+
|
| 475 |
+
if (b & kingRing[Them])
|
| 476 |
+
{
|
| 477 |
+
kingAttackersCount[Us]++;
|
| 478 |
+
kingAttackersWeight[Us] += KingAttackWeights[std::min(Pt, FAIRY_PIECES)];
|
| 479 |
+
kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
else if (Pt == ROOK && (file_bb(s) & kingRing[Them]))
|
| 483 |
+
score += RookOnKingRing;
|
| 484 |
+
|
| 485 |
+
else if (Pt == BISHOP && (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & kingRing[Them]))
|
| 486 |
+
score += BishopOnKingRing;
|
| 487 |
+
|
| 488 |
+
if (Pt > QUEEN)
|
| 489 |
+
b = (b & pos.pieces()) | (pos.moves_from(Us, Pt, s) & ~pos.pieces() & pos.board_bb());
|
| 490 |
+
|
| 491 |
+
int mob = popcount(b & mobilityArea[Us]);
|
| 492 |
+
if (Pt <= QUEEN)
|
| 493 |
+
mobility[Us] += MobilityBonus[Pt - 2][mob];
|
| 494 |
+
else
|
| 495 |
+
mobility[Us] += MaxMobility * (mob - 2) / (8 + mob);
|
| 496 |
+
|
| 497 |
+
// Piece promotion bonus
|
| 498 |
+
if (pos.promoted_piece_type(Pt) != NO_PIECE_TYPE)
|
| 499 |
+
{
|
| 500 |
+
Bitboard zone = pos.promotion_zone(Us);
|
| 501 |
+
if (zone & (b | s))
|
| 502 |
+
score += make_score(PieceValue[MG][pos.promoted_piece_type(Pt)] - PieceValue[MG][Pt],
|
| 503 |
+
PieceValue[EG][pos.promoted_piece_type(Pt)] - PieceValue[EG][Pt]) / (zone & s && b ? 6 : 12);
|
| 504 |
+
}
|
| 505 |
+
else if (pos.piece_demotion() && pos.unpromoted_piece_on(s))
|
| 506 |
+
score -= make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)],
|
| 507 |
+
PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 4;
|
| 508 |
+
else if (pos.captures_to_hand() && pos.unpromoted_piece_on(s))
|
| 509 |
+
score += make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)],
|
| 510 |
+
PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 8;
|
| 511 |
+
|
| 512 |
+
// Penalty if the piece is far from the kings in drop variants
|
| 513 |
+
if ((pos.captures_to_hand() || pos.two_boards()) && pos.count<KING>(Them) && pos.count<KING>(Us))
|
| 514 |
+
{
|
| 515 |
+
if (!(b & (kingRing[Us] | kingRing[Them])))
|
| 516 |
+
score -= KingProximity * distance(s, pos.square<KING>(Us)) * distance(s, pos.square<KING>(Them));
|
| 517 |
+
}
|
| 518 |
+
|
| 519 |
+
else if (pos.count<KING>(Us) && (Pt == FERS || Pt == SILVER))
|
| 520 |
+
score -= EndgameKingProximity * (distance(s, pos.square<KING>(Us)) - 2);
|
| 521 |
+
|
| 522 |
+
if (Pt == SOLDIER && (pos.pieces(Us, SOLDIER) & rank_bb(s) & adjacent_files_bb(s)))
|
| 523 |
+
score += ConnectedSoldier;
|
| 524 |
+
|
| 525 |
+
if (Pt == BISHOP || Pt == KNIGHT)
|
| 526 |
+
{
|
| 527 |
+
// Bonus if the piece is on an outpost square or can reach one
|
| 528 |
+
// Bonus for knights (UncontestedOutpost) if few relevant targets
|
| 529 |
+
bb = OutpostRanks & (attackedBy[Us][PAWN] | shift<Down>(pos.pieces(PAWN)))
|
| 530 |
+
& ~pe->pawn_attacks_span(Them);
|
| 531 |
+
Bitboard targets = pos.pieces(Them) & ~pos.pieces(PAWN);
|
| 532 |
+
|
| 533 |
+
if ( Pt == KNIGHT
|
| 534 |
+
&& bb & s & ~CenterFiles // on a side outpost
|
| 535 |
+
&& !(b & targets) // no relevant attacks
|
| 536 |
+
&& (!more_than_one(targets & (s & QueenSide ? QueenSide : KingSide))))
|
| 537 |
+
score += UncontestedOutpost * popcount(pos.pieces(PAWN) & (s & QueenSide ? QueenSide : KingSide));
|
| 538 |
+
else if (bb & s)
|
| 539 |
+
score += Outpost[Pt == BISHOP];
|
| 540 |
+
else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us))
|
| 541 |
+
score += ReachableOutpost;
|
| 542 |
+
|
| 543 |
+
// Bonus for a knight or bishop shielded by pawn
|
| 544 |
+
if (shift<Down>(pos.pieces(PAWN)) & s)
|
| 545 |
+
score += MinorBehindPawn;
|
| 546 |
+
|
| 547 |
+
// Penalty if the piece is far from the king
|
| 548 |
+
if (pos.count<KING>(Us))
|
| 549 |
+
score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
|
| 550 |
+
|
| 551 |
+
if (Pt == BISHOP)
|
| 552 |
+
{
|
| 553 |
+
// Penalty according to the number of our pawns on the same color square as the
|
| 554 |
+
// bishop, bigger when the center files are blocked with pawns and smaller
|
| 555 |
+
// when the bishop is outside the pawn chain.
|
| 556 |
+
Bitboard blocked = pos.pieces(Us, PAWN) & shift<Down>(pos.pieces());
|
| 557 |
+
|
| 558 |
+
score -= BishopPawns[edge_distance(file_of(s), pos.max_file())] * pos.pawns_on_same_color_squares(Us, s)
|
| 559 |
+
* (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles));
|
| 560 |
+
|
| 561 |
+
// Penalty for all enemy pawns x-rayed
|
| 562 |
+
score -= BishopXRayPawns * popcount(attacks_bb<BISHOP>(s) & pos.pieces(Them, PAWN));
|
| 563 |
+
|
| 564 |
+
// Bonus for bishop on a long diagonal which can "see" both center squares
|
| 565 |
+
if (more_than_one(attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & Center))
|
| 566 |
+
score += LongDiagonalBishop;
|
| 567 |
+
|
| 568 |
+
// An important Chess960 pattern: a cornered bishop blocked by a friendly
|
| 569 |
+
// pawn diagonally in front of it is a very serious problem, especially
|
| 570 |
+
// when that pawn is also blocked.
|
| 571 |
+
if ( pos.is_chess960()
|
| 572 |
+
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
|
| 573 |
+
{
|
| 574 |
+
Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
|
| 575 |
+
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
|
| 576 |
+
score -= !pos.empty(s + d + pawn_push(Us)) ? 4 * make_score(CorneredBishop, CorneredBishop)
|
| 577 |
+
: 3 * make_score(CorneredBishop, CorneredBishop);
|
| 578 |
+
}
|
| 579 |
+
}
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
if (Pt == ROOK)
|
| 583 |
+
{
|
| 584 |
+
// Bonuses for rook on a (semi-)open or closed file
|
| 585 |
+
if (pos.is_on_semiopen_file(Us, s))
|
| 586 |
+
{
|
| 587 |
+
score += RookOnOpenFile[pos.is_on_semiopen_file(Them, s)];
|
| 588 |
+
}
|
| 589 |
+
else
|
| 590 |
+
{
|
| 591 |
+
// If our pawn on this file is blocked, increase penalty
|
| 592 |
+
if ( pos.pieces(Us, PAWN)
|
| 593 |
+
& shift<Down>(pos.pieces())
|
| 594 |
+
& file_bb(s))
|
| 595 |
+
{
|
| 596 |
+
score -= RookOnClosedFile;
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
// Penalty when trapped by the king, even more if the king cannot castle
|
| 600 |
+
if (mob <= 3 && pos.count<KING>(Us))
|
| 601 |
+
{
|
| 602 |
+
File kf = file_of(pos.square<KING>(Us));
|
| 603 |
+
if ((kf < FILE_E) == (file_of(s) < kf))
|
| 604 |
+
score -= TrappedRook * (1 + !pos.castling_rights(Us));
|
| 605 |
+
}
|
| 606 |
+
}
|
| 607 |
+
}
|
| 608 |
+
|
| 609 |
+
if (Pt == QUEEN)
|
| 610 |
+
{
|
| 611 |
+
// Penalty if any relative pin or discovered attack against the queen
|
| 612 |
+
Bitboard queenPinners;
|
| 613 |
+
if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners, Them))
|
| 614 |
+
score -= WeakQueen;
|
| 615 |
+
}
|
| 616 |
+
}
|
| 617 |
+
if constexpr (T)
|
| 618 |
+
Trace::add(Pt, Us, score);
|
| 619 |
+
|
| 620 |
+
return score;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
// Evaluation::hand() scores pieces of a given color and type in hand
|
| 624 |
+
template<Tracing T> template<Color Us>
|
| 625 |
+
Score Evaluation<T>::hand(PieceType pt) {
|
| 626 |
+
|
| 627 |
+
constexpr Color Them = ~Us;
|
| 628 |
+
|
| 629 |
+
Score score = SCORE_ZERO;
|
| 630 |
+
|
| 631 |
+
if (pos.count_in_hand(Us, pt) > 0 && pt != KING)
|
| 632 |
+
{
|
| 633 |
+
Bitboard b = pos.drop_region(Us, pt) & ~pos.pieces() & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]);
|
| 634 |
+
if ((b & kingRing[Them]) && pt != SHOGI_PAWN)
|
| 635 |
+
{
|
| 636 |
+
kingAttackersCountInHand[Us] += pos.count_in_hand(Us, pt);
|
| 637 |
+
kingAttackersWeightInHand[Us] += KingAttackWeights[std::min(pt, FAIRY_PIECES)] * pos.count_in_hand(Us, pt);
|
| 638 |
+
kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
|
| 639 |
+
}
|
| 640 |
+
Bitboard theirHalf = pos.board_bb() & ~forward_ranks_bb(Them, relative_rank(Them, Rank((pos.max_rank() - 1) / 2), pos.max_rank()));
|
| 641 |
+
mobility[Us] += DropMobility * popcount(b & theirHalf & ~attackedBy[Them][ALL_PIECES]);
|
| 642 |
+
|
| 643 |
+
// Bonus for Kyoto shogi style drops of promoted pieces
|
| 644 |
+
if (pos.promoted_piece_type(pt) != NO_PIECE_TYPE && pos.drop_promoted())
|
| 645 |
+
score += make_score(std::max(PieceValue[MG][pos.promoted_piece_type(pt)] - PieceValue[MG][pt], VALUE_ZERO),
|
| 646 |
+
std::max(PieceValue[EG][pos.promoted_piece_type(pt)] - PieceValue[EG][pt], VALUE_ZERO)) / 4 * pos.count_in_hand(Us, pt);
|
| 647 |
+
|
| 648 |
+
// Mobility bonus for reversi variants
|
| 649 |
+
if (pos.enclosing_drop())
|
| 650 |
+
mobility[Us] += make_score(500, 500) * popcount(b);
|
| 651 |
+
|
| 652 |
+
// Reduce score if there is a deficit of gates
|
| 653 |
+
if (pos.seirawan_gating() && !pos.piece_drops() && pos.count_in_hand(Us, ALL_PIECES) > popcount(pos.gates(Us)))
|
| 654 |
+
score -= make_score(200, 900) / pos.count_in_hand(Us, ALL_PIECES) * (pos.count_in_hand(Us, ALL_PIECES) - popcount(pos.gates(Us)));
|
| 655 |
+
|
| 656 |
+
// Redundant pieces that can not be doubled per file (e.g., shogi pawns)
|
| 657 |
+
if (pt == pos.drop_no_doubled())
|
| 658 |
+
score -= make_score(50, 20) * std::max(pos.count_with_hand(Us, pt) - pos.max_file() - 1, 0);
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
return score;
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
// Evaluation::king() assigns bonuses and penalties to a king of a given color
|
| 665 |
+
|
| 666 |
+
template<Tracing T> template<Color Us>
|
| 667 |
+
Score Evaluation<T>::king() const {
|
| 668 |
+
|
| 669 |
+
constexpr Color Them = ~Us;
|
| 670 |
+
Rank r = relative_rank(Us, std::min(Rank((pos.max_rank() - 1) / 2 + 1), pos.max_rank()), pos.max_rank());
|
| 671 |
+
Bitboard Camp = pos.board_bb() & ~forward_ranks_bb(Us, r);
|
| 672 |
+
|
| 673 |
+
if (!pos.count<KING>(Us) || !pos.checking_permitted() || pos.checkmate_value() != -VALUE_MATE)
|
| 674 |
+
return SCORE_ZERO;
|
| 675 |
+
|
| 676 |
+
Bitboard weak, b1, b2, b3, safe, unsafeChecks = 0;
|
| 677 |
+
Bitboard queenChecks, knightChecks, pawnChecks, otherChecks;
|
| 678 |
+
int kingDanger = 0;
|
| 679 |
+
const Square ksq = pos.square<KING>(Us);
|
| 680 |
+
|
| 681 |
+
// Init the score with king shelter and enemy pawns storm
|
| 682 |
+
Score score = pe->king_safety<Us>(pos);
|
| 683 |
+
|
| 684 |
+
// Attacked squares defended at most once by our queen or king
|
| 685 |
+
weak = attackedBy[Them][ALL_PIECES]
|
| 686 |
+
& ~attackedBy2[Us]
|
| 687 |
+
& (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]);
|
| 688 |
+
|
| 689 |
+
// Analyse the safe enemy's checks which are possible on next move
|
| 690 |
+
safe = ~pos.pieces(Them);
|
| 691 |
+
if (!pos.check_counting() || pos.checks_remaining(Them) > 1)
|
| 692 |
+
safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
|
| 693 |
+
|
| 694 |
+
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
| 695 |
+
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
| 696 |
+
|
| 697 |
+
std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
|
| 698 |
+
return attackedBy[c][pt] | (pos.piece_drops() && pos.count_in_hand(c, pt) > 0 ? pos.drop_region(c, pt) & ~pos.pieces() : Bitboard(0));
|
| 699 |
+
};
|
| 700 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 701 |
+
{
|
| 702 |
+
PieceType pt = pop_lsb(ps);
|
| 703 |
+
switch (pt)
|
| 704 |
+
{
|
| 705 |
+
case QUEEN:
|
| 706 |
+
// Enemy queen safe checks: we count them only if they are from squares from
|
| 707 |
+
// which we can't give a rook check, because rook checks are more valuable.
|
| 708 |
+
queenChecks = (b1 | b2)
|
| 709 |
+
& get_attacks(Them, QUEEN)
|
| 710 |
+
& pos.board_bb()
|
| 711 |
+
& safe
|
| 712 |
+
& ~attackedBy[Us][QUEEN]
|
| 713 |
+
& ~(b1 & attackedBy[Them][ROOK]);
|
| 714 |
+
|
| 715 |
+
if (queenChecks)
|
| 716 |
+
kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)];
|
| 717 |
+
break;
|
| 718 |
+
case ROOK:
|
| 719 |
+
case BISHOP:
|
| 720 |
+
case KNIGHT:
|
| 721 |
+
knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb();
|
| 722 |
+
if (knightChecks & safe)
|
| 723 |
+
kingDanger += SafeCheck[pt][more_than_one(knightChecks & safe)];
|
| 724 |
+
else
|
| 725 |
+
unsafeChecks |= knightChecks;
|
| 726 |
+
break;
|
| 727 |
+
case PAWN:
|
| 728 |
+
if (pos.piece_drops() && pos.count_in_hand(Them, pt) > 0)
|
| 729 |
+
{
|
| 730 |
+
pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb();
|
| 731 |
+
if (pawnChecks & safe)
|
| 732 |
+
kingDanger += SafeCheck[PAWN][more_than_one(pawnChecks & safe)];
|
| 733 |
+
else
|
| 734 |
+
unsafeChecks |= pawnChecks;
|
| 735 |
+
}
|
| 736 |
+
break;
|
| 737 |
+
case SHOGI_PAWN:
|
| 738 |
+
if (pos.promoted_piece_type(pt))
|
| 739 |
+
{
|
| 740 |
+
otherChecks = attacks_bb(Us, pos.promoted_piece_type(pt), ksq, pos.pieces()) & attackedBy[Them][pt]
|
| 741 |
+
& pos.promotion_zone(Them) & pos.board_bb();
|
| 742 |
+
if (otherChecks & safe)
|
| 743 |
+
kingDanger += SafeCheck[FAIRY_PIECES][more_than_one(otherChecks & safe)];
|
| 744 |
+
else
|
| 745 |
+
unsafeChecks |= otherChecks;
|
| 746 |
+
}
|
| 747 |
+
break;
|
| 748 |
+
case KING:
|
| 749 |
+
break;
|
| 750 |
+
default:
|
| 751 |
+
otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb();
|
| 752 |
+
if (otherChecks & safe)
|
| 753 |
+
kingDanger += SafeCheck[FAIRY_PIECES][more_than_one(otherChecks & safe)];
|
| 754 |
+
else
|
| 755 |
+
unsafeChecks |= otherChecks;
|
| 756 |
+
}
|
| 757 |
+
}
|
| 758 |
+
|
| 759 |
+
// Virtual piece drops
|
| 760 |
+
if (pos.two_boards() && pos.piece_drops())
|
| 761 |
+
{
|
| 762 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 763 |
+
{
|
| 764 |
+
PieceType pt = pop_lsb(ps);
|
| 765 |
+
if (pos.count_in_hand(Them, pt) <= 0 && (attacks_bb(Us, pt, ksq, pos.pieces()) & safe & pos.drop_region(Them, pt) & ~pos.pieces()))
|
| 766 |
+
{
|
| 767 |
+
kingDanger += VirtualCheck * 500 / (500 + PieceValue[MG][pt]);
|
| 768 |
+
// Presumably a mate threat
|
| 769 |
+
if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us))))
|
| 770 |
+
kingDanger += 2000;
|
| 771 |
+
}
|
| 772 |
+
}
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
if (pos.check_counting())
|
| 776 |
+
kingDanger += kingDanger * 7 / (3 + pos.checks_remaining(Them));
|
| 777 |
+
|
| 778 |
+
Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq;
|
| 779 |
+
Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s);
|
| 780 |
+
|
| 781 |
+
// Find the squares that opponent attacks in our king flank, the squares
|
| 782 |
+
// which they attack twice in that flank, and the squares that we defend.
|
| 783 |
+
b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp;
|
| 784 |
+
b2 = b1 & attackedBy2[Them];
|
| 785 |
+
b3 = attackedBy[Us][ALL_PIECES] & kingFlank & Camp;
|
| 786 |
+
|
| 787 |
+
int kingFlankAttack = popcount(b1) + popcount(b2);
|
| 788 |
+
int kingFlankDefense = popcount(b3);
|
| 789 |
+
|
| 790 |
+
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
|
| 791 |
+
+ kingAttackersCountInHand[Them] * kingAttackersWeight[Them]
|
| 792 |
+
+ kingAttackersCount[Them] * kingAttackersWeightInHand[Them]
|
| 793 |
+
+ 183 * popcount(kingRing[Us] & (weak | ~pos.board_bb(Us, KING))) * (1 + pos.captures_to_hand() + pos.check_counting())
|
| 794 |
+
+ 148 * popcount(unsafeChecks) * (1 + pos.check_counting())
|
| 795 |
+
+ 98 * popcount(pos.blockers_for_king(Us))
|
| 796 |
+
+ 69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2
|
| 797 |
+
+ 3 * kingFlankAttack * kingFlankAttack / 8
|
| 798 |
+
+ mg_value(mobility[Them] - mobility[Us]) * int(!pos.captures_to_hand())
|
| 799 |
+
- 873 * !(pos.major_pieces(Them) || pos.captures_to_hand())
|
| 800 |
+
* 2 / (2 + 2 * pos.check_counting() + 2 * pos.two_boards() + 2 * pos.makpong()
|
| 801 |
+
+ (pos.king_type() != KING) * (pos.diagonal_lines() ? 1 : 2))
|
| 802 |
+
- 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING])
|
| 803 |
+
- 6 * mg_value(score) / 8
|
| 804 |
+
- 4 * kingFlankDefense
|
| 805 |
+
+ 37;
|
| 806 |
+
|
| 807 |
+
// Transform the kingDanger units into a Score, and subtract it from the evaluation
|
| 808 |
+
if (kingDanger > 100)
|
| 809 |
+
score -= make_score(std::min(kingDanger, 3500) * kingDanger / 4096, kingDanger / 16);
|
| 810 |
+
|
| 811 |
+
// Penalty when our king is on a pawnless flank
|
| 812 |
+
if (!(pos.pieces(PAWN) & kingFlank))
|
| 813 |
+
score -= PawnlessFlank;
|
| 814 |
+
|
| 815 |
+
// Penalty if king flank is under attack, potentially moving toward the king
|
| 816 |
+
score -= FlankAttacks * kingFlankAttack * (1 + 5 * pos.captures_to_hand() + pos.check_counting());
|
| 817 |
+
|
| 818 |
+
if (pos.check_counting())
|
| 819 |
+
score += make_score(0, mg_value(score) * 2 / (2 + pos.checks_remaining(Them)));
|
| 820 |
+
|
| 821 |
+
if (pos.king_type() == WAZIR)
|
| 822 |
+
score += make_score(0, mg_value(score) / 2);
|
| 823 |
+
|
| 824 |
+
// For drop games, king danger is independent of game phase, but dependent on material density
|
| 825 |
+
if (pos.captures_to_hand() || pos.two_boards())
|
| 826 |
+
score = make_score(mg_value(score) * me->material_density() / 11000,
|
| 827 |
+
mg_value(score) * me->material_density() / 11000);
|
| 828 |
+
|
| 829 |
+
if constexpr (T)
|
| 830 |
+
Trace::add(KING, Us, score);
|
| 831 |
+
|
| 832 |
+
return score;
|
| 833 |
+
}
|
| 834 |
+
|
| 835 |
+
|
| 836 |
+
// Evaluation::threats() assigns bonuses according to the types of the
|
| 837 |
+
// attacking and the attacked pieces.
|
| 838 |
+
|
| 839 |
+
template<Tracing T> template<Color Us>
|
| 840 |
+
Score Evaluation<T>::threats() const {
|
| 841 |
+
|
| 842 |
+
constexpr Color Them = ~Us;
|
| 843 |
+
constexpr Direction Up = pawn_push(Us);
|
| 844 |
+
constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
| 845 |
+
|
| 846 |
+
Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe;
|
| 847 |
+
Score score = SCORE_ZERO;
|
| 848 |
+
|
| 849 |
+
// Bonuses for variants with mandatory captures
|
| 850 |
+
if (pos.must_capture())
|
| 851 |
+
{
|
| 852 |
+
// Penalties for possible captures
|
| 853 |
+
Bitboard captures = attackedBy[Us][ALL_PIECES] & pos.pieces(Them);
|
| 854 |
+
if (captures)
|
| 855 |
+
score -= make_score(2000, 2000) / (1 + popcount(captures & attackedBy[Them][ALL_PIECES] & ~attackedBy2[Us]));
|
| 856 |
+
|
| 857 |
+
// Bonus if we threaten to force captures
|
| 858 |
+
Bitboard moves = 0, piecebb = pos.pieces(Us);
|
| 859 |
+
while (piecebb)
|
| 860 |
+
{
|
| 861 |
+
Square s = pop_lsb(piecebb);
|
| 862 |
+
if (type_of(pos.piece_on(s)) != KING)
|
| 863 |
+
moves |= pos.moves_from(Us, type_of(pos.piece_on(s)), s);
|
| 864 |
+
}
|
| 865 |
+
score += make_score(200, 200) * popcount(attackedBy[Them][ALL_PIECES] & moves & ~pos.pieces());
|
| 866 |
+
score += make_score(200, 220) * popcount(attackedBy[Them][ALL_PIECES] & moves & ~pos.pieces() & ~attackedBy2[Us]);
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
// Extinction threats
|
| 870 |
+
if (pos.extinction_value() == -VALUE_MATE)
|
| 871 |
+
{
|
| 872 |
+
Bitboard bExt = attackedBy[Us][ALL_PIECES] & pos.pieces(Them);
|
| 873 |
+
for (PieceSet ps = pos.extinction_piece_types(); ps;)
|
| 874 |
+
{
|
| 875 |
+
PieceType pt = pop_lsb(ps);
|
| 876 |
+
if (pt == ALL_PIECES)
|
| 877 |
+
continue;
|
| 878 |
+
int denom = std::max(pos.count_with_hand(Them, pt) - pos.extinction_piece_count(), 1);
|
| 879 |
+
// Explosion threats
|
| 880 |
+
if (pos.blast_on_capture())
|
| 881 |
+
{
|
| 882 |
+
int evasions = popcount(((attackedBy[Them][pt] & ~pos.pieces(Them)) | pos.pieces(Them, pt)) & ~attackedBy[Us][ALL_PIECES]) * denom;
|
| 883 |
+
int attacks = popcount((attackedBy[Them][pt] | pos.pieces(Them, pt)) & attackedBy[Us][ALL_PIECES]);
|
| 884 |
+
int explosions = 0;
|
| 885 |
+
|
| 886 |
+
Bitboard bExtBlast = bExt & (attackedBy2[Us] | ~attackedBy[Us][pt]);
|
| 887 |
+
while (bExtBlast)
|
| 888 |
+
{
|
| 889 |
+
Square s = pop_lsb(bExtBlast);
|
| 890 |
+
if (((attacks_bb<KING>(s) | s) & pos.pieces(Them, pt)) && !(attacks_bb<KING>(s) & pos.pieces(Us, pt)))
|
| 891 |
+
explosions++;
|
| 892 |
+
}
|
| 893 |
+
int danger = 20 * attacks / (evasions + 1) + 40 * explosions;
|
| 894 |
+
score += make_score(danger * (100 + danger), 0);
|
| 895 |
+
}
|
| 896 |
+
else
|
| 897 |
+
// Direct extinction threats
|
| 898 |
+
score += make_score(1000, 1000) / (denom * denom) * popcount(bExt & pos.pieces(Them, pt));
|
| 899 |
+
}
|
| 900 |
+
}
|
| 901 |
+
|
| 902 |
+
// Non-pawn enemies
|
| 903 |
+
nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN, SHOGI_PAWN) & ~pos.pieces(SOLDIER);
|
| 904 |
+
|
| 905 |
+
// Squares strongly protected by the enemy, either because they defend the
|
| 906 |
+
// square with a pawn, or because they defend the square twice and we don't.
|
| 907 |
+
stronglyProtected = (attackedBy[Them][PAWN] | attackedBy[Them][SHOGI_PAWN] | attackedBy[Them][SOLDIER])
|
| 908 |
+
| (attackedBy2[Them] & ~attackedBy2[Us]);
|
| 909 |
+
|
| 910 |
+
// Non-pawn enemies, strongly protected
|
| 911 |
+
defended = nonPawnEnemies & stronglyProtected;
|
| 912 |
+
|
| 913 |
+
// Enemies not strongly protected and under our attack
|
| 914 |
+
weak = pos.pieces(Them) & ~stronglyProtected & attackedBy[Us][ALL_PIECES];
|
| 915 |
+
|
| 916 |
+
// Bonus according to the kind of attacking pieces
|
| 917 |
+
if (defended | weak)
|
| 918 |
+
{
|
| 919 |
+
b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]);
|
| 920 |
+
while (b)
|
| 921 |
+
score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(b)))];
|
| 922 |
+
|
| 923 |
+
b = weak & attackedBy[Us][ROOK];
|
| 924 |
+
while (b)
|
| 925 |
+
score += ThreatByRook[type_of(pos.piece_on(pop_lsb(b)))];
|
| 926 |
+
|
| 927 |
+
if (weak & attackedBy[Us][KING])
|
| 928 |
+
score += ThreatByKing;
|
| 929 |
+
|
| 930 |
+
b = ~attackedBy[Them][ALL_PIECES]
|
| 931 |
+
| (nonPawnEnemies & attackedBy2[Us]);
|
| 932 |
+
score += Hanging * popcount(weak & b);
|
| 933 |
+
|
| 934 |
+
// Additional bonus if weak piece is only protected by a queen
|
| 935 |
+
score += WeakQueenProtection * popcount(weak & attackedBy[Them][QUEEN]);
|
| 936 |
+
}
|
| 937 |
+
|
| 938 |
+
// Bonus for restricting their piece moves
|
| 939 |
+
b = attackedBy[Them][ALL_PIECES]
|
| 940 |
+
& ~stronglyProtected
|
| 941 |
+
& attackedBy[Us][ALL_PIECES];
|
| 942 |
+
score += RestrictedPiece * popcount(b);
|
| 943 |
+
|
| 944 |
+
// Protected or unattacked squares
|
| 945 |
+
safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES];
|
| 946 |
+
|
| 947 |
+
// Bonus for attacking enemy pieces with our relatively safe pawns
|
| 948 |
+
b = pos.pieces(Us, PAWN) & safe;
|
| 949 |
+
b = pawn_attacks_bb<Us>(b) & nonPawnEnemies;
|
| 950 |
+
score += ThreatBySafePawn * popcount(b);
|
| 951 |
+
|
| 952 |
+
// Find squares where our pawns can push on the next move
|
| 953 |
+
b = shift<Up>(pos.pieces(Us, PAWN)) & ~pos.pieces();
|
| 954 |
+
b |= shift<Up>(b & TRank3BB) & ~pos.pieces();
|
| 955 |
+
|
| 956 |
+
// Keep only the squares which are relatively safe
|
| 957 |
+
b &= ~attackedBy[Them][PAWN] & safe;
|
| 958 |
+
|
| 959 |
+
// Bonus for safe pawn threats on the next move
|
| 960 |
+
b = (pawn_attacks_bb<Us>(b) | shift<Up>(shift<Up>(pos.pieces(Us, SHOGI_PAWN, SOLDIER)))) & nonPawnEnemies;
|
| 961 |
+
score += ThreatByPawnPush * popcount(b);
|
| 962 |
+
|
| 963 |
+
// Bonus for threats on the next moves against enemy queen
|
| 964 |
+
if (pos.count<QUEEN>(Them) == 1)
|
| 965 |
+
{
|
| 966 |
+
bool queenImbalance = pos.count<QUEEN>() == 1;
|
| 967 |
+
|
| 968 |
+
Square s = pos.square<QUEEN>(Them);
|
| 969 |
+
safe = mobilityArea[Us]
|
| 970 |
+
& ~pos.pieces(Us, PAWN)
|
| 971 |
+
& ~stronglyProtected;
|
| 972 |
+
|
| 973 |
+
b = attackedBy[Us][KNIGHT] & attacks_bb<KNIGHT>(s);
|
| 974 |
+
|
| 975 |
+
score += KnightOnQueen * popcount(b & safe) * (1 + queenImbalance);
|
| 976 |
+
|
| 977 |
+
b = (attackedBy[Us][BISHOP] & attacks_bb<BISHOP>(s, pos.pieces()))
|
| 978 |
+
| (attackedBy[Us][ROOK ] & attacks_bb<ROOK >(s, pos.pieces()));
|
| 979 |
+
|
| 980 |
+
score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]) * (1 + queenImbalance);
|
| 981 |
+
}
|
| 982 |
+
|
| 983 |
+
if constexpr (T)
|
| 984 |
+
Trace::add(THREAT, Us, score);
|
| 985 |
+
|
| 986 |
+
return score;
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
// Evaluation::passed() evaluates the passed pawns and candidate passed
|
| 990 |
+
// pawns of the given color.
|
| 991 |
+
|
| 992 |
+
template<Tracing T> template<Color Us>
|
| 993 |
+
Score Evaluation<T>::passed() const {
|
| 994 |
+
|
| 995 |
+
constexpr Color Them = ~Us;
|
| 996 |
+
constexpr Direction Up = pawn_push(Us);
|
| 997 |
+
constexpr Direction Down = -Up;
|
| 998 |
+
|
| 999 |
+
auto king_proximity = [&](Color c, Square s) {
|
| 1000 |
+
return pos.extinction_value() == VALUE_MATE ? 0 : pos.count<KING>(c) ? std::min(distance(pos.square<KING>(c), s), 5) : 5;
|
| 1001 |
+
};
|
| 1002 |
+
|
| 1003 |
+
Bitboard b, bb, squaresToQueen, unsafeSquares, blockedPassers, helpers;
|
| 1004 |
+
Score score = SCORE_ZERO;
|
| 1005 |
+
|
| 1006 |
+
b = pe->passed_pawns(Us);
|
| 1007 |
+
|
| 1008 |
+
blockedPassers = b & shift<Down>(pos.pieces(Them, PAWN));
|
| 1009 |
+
if (blockedPassers)
|
| 1010 |
+
{
|
| 1011 |
+
helpers = shift<Up>(pos.pieces(Us, PAWN))
|
| 1012 |
+
& ~pos.pieces(Them)
|
| 1013 |
+
& (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]);
|
| 1014 |
+
|
| 1015 |
+
// Remove blocked candidate passers that don't have help to pass
|
| 1016 |
+
b &= ~blockedPassers
|
| 1017 |
+
| shift<WEST>(helpers)
|
| 1018 |
+
| shift<EAST>(helpers);
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
while (b)
|
| 1022 |
+
{
|
| 1023 |
+
Square s = pop_lsb(b);
|
| 1024 |
+
|
| 1025 |
+
assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up)));
|
| 1026 |
+
|
| 1027 |
+
int r = std::max(RANK_8 - std::max(relative_rank(Us, pos.promotion_square(Us, s), pos.max_rank()) - relative_rank(Us, s, pos.max_rank()), 0), 0);
|
| 1028 |
+
|
| 1029 |
+
Score bonus = PassedRank[r];
|
| 1030 |
+
|
| 1031 |
+
if (r > RANK_3)
|
| 1032 |
+
{
|
| 1033 |
+
int w = 5 * r - 13;
|
| 1034 |
+
Square blockSq = s + Up;
|
| 1035 |
+
|
| 1036 |
+
// Adjust bonus based on the king's proximity
|
| 1037 |
+
bonus += make_score(0, ( king_proximity(Them, blockSq) * 19 / 4
|
| 1038 |
+
- king_proximity(Us, blockSq) * 2) * w);
|
| 1039 |
+
|
| 1040 |
+
// If blockSq is not the queening square then consider also a second push
|
| 1041 |
+
if (r != RANK_7)
|
| 1042 |
+
bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w);
|
| 1043 |
+
|
| 1044 |
+
// If the pawn is free to advance, then increase the bonus
|
| 1045 |
+
if (pos.empty(blockSq))
|
| 1046 |
+
{
|
| 1047 |
+
squaresToQueen = forward_file_bb(Us, s);
|
| 1048 |
+
unsafeSquares = passed_pawn_span(Us, s);
|
| 1049 |
+
|
| 1050 |
+
bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN);
|
| 1051 |
+
|
| 1052 |
+
if (!(pos.pieces(Them) & bb))
|
| 1053 |
+
unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them);
|
| 1054 |
+
|
| 1055 |
+
// If there are no enemy pieces or attacks on passed pawn span, assign a big bonus.
|
| 1056 |
+
// Or if there is some, but they are all attacked by our pawns, assign a bit smaller bonus.
|
| 1057 |
+
// Otherwise assign a smaller bonus if the path to queen is not attacked
|
| 1058 |
+
// and even smaller bonus if it is attacked but block square is not.
|
| 1059 |
+
int k = !unsafeSquares ? 36 :
|
| 1060 |
+
!(unsafeSquares & ~attackedBy[Us][PAWN]) ? 30 :
|
| 1061 |
+
!(unsafeSquares & squaresToQueen) ? 17 :
|
| 1062 |
+
!(unsafeSquares & blockSq) ? 7 :
|
| 1063 |
+
0 ;
|
| 1064 |
+
|
| 1065 |
+
// Assign a larger bonus if the block square is defended
|
| 1066 |
+
if ((pos.pieces(Us) & bb) || (attackedBy[Us][ALL_PIECES] & blockSq))
|
| 1067 |
+
k += 5;
|
| 1068 |
+
|
| 1069 |
+
bonus += make_score(k * w, k * w);
|
| 1070 |
+
}
|
| 1071 |
+
} // r > RANK_3
|
| 1072 |
+
|
| 1073 |
+
score += bonus - PassedFile * edge_distance(file_of(s), pos.max_file());
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
// Passed custom pawns
|
| 1077 |
+
for (PieceSet ps = (pos.promotion_pawn_types(Us) & ~piece_set(PAWN)); ps;)
|
| 1078 |
+
{
|
| 1079 |
+
PieceType pt = pop_lsb(ps);
|
| 1080 |
+
Bitboard b2 = pos.pieces(Us, pt);
|
| 1081 |
+
while (b2)
|
| 1082 |
+
{
|
| 1083 |
+
Square s = pop_lsb(b2);
|
| 1084 |
+
if (pos.promotion_square(Us, s) == SQ_NONE || (pos.pieces(Them, pt) & forward_file_bb(Us, s)))
|
| 1085 |
+
continue;
|
| 1086 |
+
int r = std::max(RANK_8 - std::max(relative_rank(Us, pos.promotion_square(Us, s), pos.max_rank()) - relative_rank(Us, s, pos.max_rank()), 0), 0);
|
| 1087 |
+
score += PassedRank[r];
|
| 1088 |
+
}
|
| 1089 |
+
}
|
| 1090 |
+
|
| 1091 |
+
// Scale by maximum promotion piece value
|
| 1092 |
+
Value maxMg = VALUE_ZERO, maxEg = VALUE_ZERO;
|
| 1093 |
+
for (PieceSet ps = pos.promotion_piece_types(Us); ps;)
|
| 1094 |
+
{
|
| 1095 |
+
PieceType pt = pop_lsb(ps);
|
| 1096 |
+
maxMg = std::max(maxMg, PieceValue[MG][pt]);
|
| 1097 |
+
maxEg = std::max(maxEg, PieceValue[EG][pt]);
|
| 1098 |
+
}
|
| 1099 |
+
score = make_score(mg_value(score) * int(maxMg - PawnValueMg) / (QueenValueMg - PawnValueMg),
|
| 1100 |
+
eg_value(score) * int(maxEg - PawnValueEg) / (QueenValueEg - PawnValueEg));
|
| 1101 |
+
|
| 1102 |
+
// Score passed shogi pawns
|
| 1103 |
+
PieceType pt = pos.promoted_piece_type(SHOGI_PAWN);
|
| 1104 |
+
if (pt != NO_PIECE_TYPE)
|
| 1105 |
+
{
|
| 1106 |
+
b = pos.pieces(Us, SHOGI_PAWN);
|
| 1107 |
+
while (b)
|
| 1108 |
+
{
|
| 1109 |
+
Square s = pop_lsb(b);
|
| 1110 |
+
if ((pos.pieces(Them, SHOGI_PAWN) & forward_file_bb(Us, s)) || pos.promotion_square(Us, s) == SQ_NONE)
|
| 1111 |
+
continue;
|
| 1112 |
+
|
| 1113 |
+
Square blockSq = s + Up;
|
| 1114 |
+
int d = 2 * std::max(relative_rank(Us, pos.promotion_square(Us, s), pos.max_rank()) - relative_rank(Us, s, pos.max_rank()), 1);
|
| 1115 |
+
d += !!(attackedBy[Them][ALL_PIECES] & ~attackedBy2[Us] & blockSq);
|
| 1116 |
+
score += make_score(PieceValue[MG][pt], PieceValue[EG][pt]) / (d * d);
|
| 1117 |
+
}
|
| 1118 |
+
}
|
| 1119 |
+
|
| 1120 |
+
if constexpr (T)
|
| 1121 |
+
Trace::add(PASSED, Us, score);
|
| 1122 |
+
|
| 1123 |
+
return score;
|
| 1124 |
+
}
|
| 1125 |
+
|
| 1126 |
+
|
| 1127 |
+
// Evaluation::space() computes a space evaluation for a given side, aiming to improve game
|
| 1128 |
+
// play in the opening. It is based on the number of safe squares on the four central files
|
| 1129 |
+
// on ranks 2 to 4. Completely safe squares behind a friendly pawn are counted twice.
|
| 1130 |
+
// Finally, the space bonus is multiplied by a weight which decreases according to occupancy.
|
| 1131 |
+
|
| 1132 |
+
template<Tracing T> template<Color Us>
|
| 1133 |
+
Score Evaluation<T>::space() const {
|
| 1134 |
+
|
| 1135 |
+
bool pawnsOnly = !(pos.pieces(Us) ^ pos.pieces(Us, PAWN));
|
| 1136 |
+
|
| 1137 |
+
// Early exit if, for example, both queens or 6 minor pieces have been exchanged
|
| 1138 |
+
if (pos.non_pawn_material() < SpaceThreshold && !pawnsOnly && pos.double_step_region(Us))
|
| 1139 |
+
return SCORE_ZERO;
|
| 1140 |
+
|
| 1141 |
+
constexpr Color Them = ~Us;
|
| 1142 |
+
constexpr Direction Down = -pawn_push(Us);
|
| 1143 |
+
constexpr Bitboard SpaceMask =
|
| 1144 |
+
Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB)
|
| 1145 |
+
: CenterFiles & (Rank7BB | Rank6BB | Rank5BB);
|
| 1146 |
+
|
| 1147 |
+
// Find the available squares for our pieces inside the area defined by SpaceMask
|
| 1148 |
+
Bitboard safe = SpaceMask
|
| 1149 |
+
& ~pos.pieces(Us, PAWN)
|
| 1150 |
+
& ~attackedBy[Them][PAWN];
|
| 1151 |
+
|
| 1152 |
+
// Find all squares which are at most three squares behind some friendly pawn
|
| 1153 |
+
Bitboard behind = pos.pieces(Us, PAWN);
|
| 1154 |
+
behind |= shift<Down>(behind);
|
| 1155 |
+
behind |= shift<Down+Down>(behind);
|
| 1156 |
+
|
| 1157 |
+
if (pawnsOnly)
|
| 1158 |
+
{
|
| 1159 |
+
safe = pos.board_bb() & ((attackedBy2[Us] & ~attackedBy2[Them]) | (attackedBy[Us][PAWN] & ~pos.pieces(Us, PAWN)));
|
| 1160 |
+
behind = 0;
|
| 1161 |
+
}
|
| 1162 |
+
|
| 1163 |
+
// Compute space score based on the number of safe squares and number of our pieces
|
| 1164 |
+
// increased with number of total blocked pawns in position.
|
| 1165 |
+
int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]);
|
| 1166 |
+
int weight = pos.count<ALL_PIECES>(Us) - 3 + std::min(pe->blocked_count(), 9);
|
| 1167 |
+
Score score = make_score(bonus * weight * weight / 16, 0);
|
| 1168 |
+
|
| 1169 |
+
if (pos.flag_region(Us))
|
| 1170 |
+
score += make_score(200, 200) * popcount(behind & safe & pos.flag_region(Us));
|
| 1171 |
+
|
| 1172 |
+
if constexpr (T)
|
| 1173 |
+
Trace::add(SPACE, Us, score);
|
| 1174 |
+
|
| 1175 |
+
return score;
|
| 1176 |
+
}
|
| 1177 |
+
|
| 1178 |
+
|
| 1179 |
+
// Evaluation::variant() computes variant-specific evaluation bonuses for a given side.
|
| 1180 |
+
|
| 1181 |
+
template<Tracing T> template<Color Us>
|
| 1182 |
+
Score Evaluation<T>::variant() const {
|
| 1183 |
+
|
| 1184 |
+
constexpr Color Them = ~Us;
|
| 1185 |
+
constexpr Direction Down = pawn_push(Them);
|
| 1186 |
+
|
| 1187 |
+
Score score = SCORE_ZERO;
|
| 1188 |
+
|
| 1189 |
+
// Capture the flag
|
| 1190 |
+
if (pos.flag_region(Us))
|
| 1191 |
+
{
|
| 1192 |
+
Bitboard ctfPieces = pos.pieces(Us, pos.flag_piece(Us));
|
| 1193 |
+
Bitboard ctfTargets = pos.flag_region(Us) & pos.board_bb();
|
| 1194 |
+
Bitboard onHold = 0;
|
| 1195 |
+
Bitboard onHold2 = 0;
|
| 1196 |
+
Bitboard processed = 0;
|
| 1197 |
+
Bitboard blocked = pos.pieces(Us, PAWN) | attackedBy[Them][ALL_PIECES];
|
| 1198 |
+
Bitboard doubleBlocked = attackedBy2[Them]
|
| 1199 |
+
| (pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | attackedBy[Them][ALL_PIECES]))
|
| 1200 |
+
| (pos.pieces(Them) & pe->pawn_attacks(Them))
|
| 1201 |
+
| (pawn_attacks_bb<Them>(pos.pieces(Them, PAWN) & pe->pawn_attacks(Them)));
|
| 1202 |
+
Bitboard inaccessible = pos.pieces(Us, PAWN) & shift<Down>(pos.pieces(Them, PAWN));
|
| 1203 |
+
// Traverse all paths of the CTF pieces to the CTF targets.
|
| 1204 |
+
// Put squares that are attacked or occupied on hold for one iteration.
|
| 1205 |
+
// This reflects that likely a move will be needed to block or capture the attack.
|
| 1206 |
+
// If all piece types are eligible, use the king path as a proxy for distance.
|
| 1207 |
+
PieceType ptCtf = pos.flag_piece(Us) == ALL_PIECES ? KING : pos.flag_piece(Us);
|
| 1208 |
+
for (int dist = 0; (ctfPieces || onHold || onHold2) && (ctfTargets & ~processed); dist++)
|
| 1209 |
+
{
|
| 1210 |
+
int wins = popcount(ctfTargets & ctfPieces);
|
| 1211 |
+
if (wins)
|
| 1212 |
+
score += make_score(4000, 4000) * wins / (wins + dist * dist);
|
| 1213 |
+
Bitboard current = ctfPieces & ~ctfTargets;
|
| 1214 |
+
processed |= ctfPieces;
|
| 1215 |
+
ctfPieces = onHold & ~processed;
|
| 1216 |
+
onHold = onHold2 & ~processed;
|
| 1217 |
+
onHold2 = 0;
|
| 1218 |
+
while (current)
|
| 1219 |
+
{
|
| 1220 |
+
Square s = pop_lsb(current);
|
| 1221 |
+
Bitboard attacks = ( (PseudoAttacks[Us][ptCtf][s] & pos.pieces())
|
| 1222 |
+
| (PseudoMoves[0][Us][ptCtf][s] & ~pos.pieces())) & ~processed & pos.board_bb();
|
| 1223 |
+
ctfPieces |= attacks & ~blocked;
|
| 1224 |
+
onHold |= attacks & ~doubleBlocked;
|
| 1225 |
+
onHold2 |= attacks & ~inaccessible;
|
| 1226 |
+
}
|
| 1227 |
+
}
|
| 1228 |
+
}
|
| 1229 |
+
|
| 1230 |
+
// nCheck
|
| 1231 |
+
if (pos.check_counting())
|
| 1232 |
+
{
|
| 1233 |
+
int remainingChecks = pos.checks_remaining(Us);
|
| 1234 |
+
assert(remainingChecks > 0);
|
| 1235 |
+
score += make_score(3600, 1000) / (remainingChecks * remainingChecks);
|
| 1236 |
+
}
|
| 1237 |
+
|
| 1238 |
+
// Extinction
|
| 1239 |
+
if (pos.extinction_value() != VALUE_NONE)
|
| 1240 |
+
{
|
| 1241 |
+
for (PieceSet ps = pos.extinction_piece_types(); ps;)
|
| 1242 |
+
{
|
| 1243 |
+
PieceType pt = pop_lsb(ps);
|
| 1244 |
+
if (pt != ALL_PIECES)
|
| 1245 |
+
{
|
| 1246 |
+
// Single piece type extinction bonus
|
| 1247 |
+
int denom = std::max(pos.count(Us, pt) - pos.extinction_piece_count(), 1);
|
| 1248 |
+
if (pos.count(Them, pt) >= pos.extinction_opponent_piece_count() || pos.two_boards())
|
| 1249 |
+
score += make_score(1000000 / (500 + PieceValue[MG][pt]),
|
| 1250 |
+
1000000 / (500 + PieceValue[EG][pt])) / (denom * denom)
|
| 1251 |
+
* (pos.extinction_value() / VALUE_MATE);
|
| 1252 |
+
}
|
| 1253 |
+
else if (pos.extinction_value() == VALUE_MATE)
|
| 1254 |
+
{
|
| 1255 |
+
// Losing chess variant bonus
|
| 1256 |
+
score += make_score(pos.non_pawn_material(Us), pos.non_pawn_material(Us)) / std::max(pos.count<ALL_PIECES>(Us), 1);
|
| 1257 |
+
}
|
| 1258 |
+
else if (pos.count<PAWN>(Us) == pos.count<ALL_PIECES>(Us))
|
| 1259 |
+
{
|
| 1260 |
+
// Pawns easy to stop/capture
|
| 1261 |
+
int l = 0, m = 0, r = popcount(pos.pieces(Us, PAWN) & file_bb(FILE_A));
|
| 1262 |
+
for (File f = FILE_A; f <= pos.max_file(); ++f)
|
| 1263 |
+
{
|
| 1264 |
+
l = m; m = r; r = popcount(pos.pieces(Us, PAWN) & shift<EAST>(file_bb(f)));
|
| 1265 |
+
score -= make_score(80 - 10 * (edge_distance(f, pos.max_file()) % 2),
|
| 1266 |
+
80 - 15 * (edge_distance(f, pos.max_file()) % 2)) * m / (1 + l * r);
|
| 1267 |
+
}
|
| 1268 |
+
}
|
| 1269 |
+
else if (pos.count<PAWN>(Them) == pos.count<ALL_PIECES>(Them))
|
| 1270 |
+
{
|
| 1271 |
+
// Add a bonus according to how close we are to breaking through the pawn wall
|
| 1272 |
+
int dist = 8;
|
| 1273 |
+
Bitboard breakthroughs = attackedBy[Us][ALL_PIECES] & rank_bb(relative_rank(Us, pos.max_rank(), pos.max_rank()));
|
| 1274 |
+
if (breakthroughs)
|
| 1275 |
+
dist = attackedBy[Us][QUEEN] & breakthroughs ? 0 : 1;
|
| 1276 |
+
else for (File f = FILE_A; f <= pos.max_file(); ++f)
|
| 1277 |
+
dist = std::min(dist, popcount(pos.pieces(PAWN) & file_bb(f)));
|
| 1278 |
+
score += make_score(70, 70) * pos.count<PAWN>(Them) / (1 + dist * dist) / (pos.pieces(Us, QUEEN) ? 2 : 4);
|
| 1279 |
+
}
|
| 1280 |
+
}
|
| 1281 |
+
}
|
| 1282 |
+
|
| 1283 |
+
// Connect-n
|
| 1284 |
+
if (pos.connect_n() > 0)
|
| 1285 |
+
{
|
| 1286 |
+
//Calculate eligible pieces for connection once.
|
| 1287 |
+
//Still consider all opponent pieces as blocking.
|
| 1288 |
+
Bitboard connectPiecesUs = 0;
|
| 1289 |
+
for (PieceSet ps = pos.connect_piece_types(); ps;){
|
| 1290 |
+
PieceType pt = pop_lsb(ps);
|
| 1291 |
+
connectPiecesUs |= pos.pieces(pt);
|
| 1292 |
+
};
|
| 1293 |
+
connectPiecesUs &= pos.pieces(Us);
|
| 1294 |
+
|
| 1295 |
+
for (const Direction& d : pos.getConnectDirections())
|
| 1296 |
+
|
| 1297 |
+
{
|
| 1298 |
+
// Find sufficiently large gaps
|
| 1299 |
+
Bitboard b = pos.board_bb() & ~pos.pieces(Them);
|
| 1300 |
+
for (int i = 1; i < pos.connect_n(); i++)
|
| 1301 |
+
b &= shift(d, b);
|
| 1302 |
+
// Count number of pieces per gap
|
| 1303 |
+
while (b)
|
| 1304 |
+
{
|
| 1305 |
+
Square s = pop_lsb(b);
|
| 1306 |
+
int c = 0;
|
| 1307 |
+
for (int j = 0; j < pos.connect_n(); j++)
|
| 1308 |
+
if (connectPiecesUs & (s - j * d))
|
| 1309 |
+
c++;
|
| 1310 |
+
score += make_score(200, 200) * c / (pos.connect_n() - c) / (pos.connect_n() - c);
|
| 1311 |
+
}
|
| 1312 |
+
}
|
| 1313 |
+
}
|
| 1314 |
+
|
| 1315 |
+
// Potential piece flips (Reversi)
|
| 1316 |
+
if (pos.flip_enclosed_pieces())
|
| 1317 |
+
{
|
| 1318 |
+
// Stable pieces
|
| 1319 |
+
if (pos.flip_enclosed_pieces() == REVERSI)
|
| 1320 |
+
{
|
| 1321 |
+
Bitboard edges = (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) & pos.board_bb();
|
| 1322 |
+
Bitboard edgePieces = pos.pieces(Us) & edges;
|
| 1323 |
+
while (edgePieces)
|
| 1324 |
+
{
|
| 1325 |
+
Bitboard connectedEdge = attacks_bb(Us, ROOK, pop_lsb(edgePieces), ~(pos.pieces(Us) & edges)) & edges;
|
| 1326 |
+
if (!more_than_one(connectedEdge & ~pos.pieces(Us)))
|
| 1327 |
+
score += make_score(300, 300);
|
| 1328 |
+
else if (!(connectedEdge & ~pos.pieces()))
|
| 1329 |
+
score += make_score(200, 200);
|
| 1330 |
+
}
|
| 1331 |
+
}
|
| 1332 |
+
|
| 1333 |
+
// Unstable
|
| 1334 |
+
Bitboard unstable = 0;
|
| 1335 |
+
Bitboard drops = pos.drop_region(Them, IMMOBILE_PIECE);
|
| 1336 |
+
while (drops)
|
| 1337 |
+
{
|
| 1338 |
+
Square s = pop_lsb(drops);
|
| 1339 |
+
if (pos.flip_enclosed_pieces() == REVERSI)
|
| 1340 |
+
{
|
| 1341 |
+
Bitboard b = attacks_bb(Them, QUEEN, s, ~pos.pieces(Us)) & ~PseudoAttacks[Them][KING][s] & pos.pieces(Them);
|
| 1342 |
+
while(b)
|
| 1343 |
+
unstable |= between_bb(s, pop_lsb(b));
|
| 1344 |
+
}
|
| 1345 |
+
else
|
| 1346 |
+
unstable |= PseudoAttacks[Them][KING][s] & pos.pieces(Us);
|
| 1347 |
+
}
|
| 1348 |
+
score -= make_score(200, 200) * popcount(unstable);
|
| 1349 |
+
}
|
| 1350 |
+
|
| 1351 |
+
if (T)
|
| 1352 |
+
Trace::add(VARIANT, Us, score);
|
| 1353 |
+
|
| 1354 |
+
return score;
|
| 1355 |
+
}
|
| 1356 |
+
|
| 1357 |
+
|
| 1358 |
+
// Evaluation::winnable() adjusts the midgame and endgame score components, based on
|
| 1359 |
+
// the known attacking/defending status of the players. The final value is derived
|
| 1360 |
+
// by interpolation from the midgame and endgame values.
|
| 1361 |
+
|
| 1362 |
+
template<Tracing T>
|
| 1363 |
+
Value Evaluation<T>::winnable(Score score) const {
|
| 1364 |
+
|
| 1365 |
+
// No initiative bonus for variants that do not require sufficient mating material, e.g., extinction variants.
|
| 1366 |
+
// This protects them from misidentification as drawish.
|
| 1367 |
+
int complexity = 0;
|
| 1368 |
+
bool pawnsOnBothFlanks = true;
|
| 1369 |
+
if ( pos.extinction_value() == VALUE_NONE
|
| 1370 |
+
&& !pos.captures_to_hand()
|
| 1371 |
+
&& !pos.connect_n()
|
| 1372 |
+
&& !pos.material_counting()
|
| 1373 |
+
&& !(pos.flag_region(WHITE) || pos.flag_region(BLACK)))
|
| 1374 |
+
{
|
| 1375 |
+
int outflanking = !pos.count<KING>(WHITE) || !pos.count<KING>(BLACK) ? 0
|
| 1376 |
+
: distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
|
| 1377 |
+
+ int(rank_of(pos.square<KING>(WHITE)) - rank_of(pos.square<KING>(BLACK)));
|
| 1378 |
+
|
| 1379 |
+
pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide)
|
| 1380 |
+
&& (pos.pieces(PAWN) & KingSide);
|
| 1381 |
+
|
| 1382 |
+
bool almostUnwinnable = outflanking < 0
|
| 1383 |
+
&& pos.stalemate_value() == VALUE_DRAW
|
| 1384 |
+
&& !pawnsOnBothFlanks;
|
| 1385 |
+
|
| 1386 |
+
bool infiltration = (pos.count<KING>(WHITE) && rank_of(pos.square<KING>(WHITE)) > RANK_4)
|
| 1387 |
+
|| (pos.count<KING>(BLACK) && rank_of(pos.square<KING>(BLACK)) < RANK_5);
|
| 1388 |
+
|
| 1389 |
+
// Compute the initiative bonus for the attacking side
|
| 1390 |
+
complexity = 9 * pe->passed_count()
|
| 1391 |
+
+ 12 * pos.count(WHITE, pos.main_promotion_pawn_type(WHITE)) * bool(pos.main_promotion_pawn_type(WHITE))
|
| 1392 |
+
+ 12 * pos.count(BLACK, pos.main_promotion_pawn_type(BLACK)) * bool(pos.main_promotion_pawn_type(BLACK))
|
| 1393 |
+
+ 15 * pos.count<SOLDIER>()
|
| 1394 |
+
+ 9 * outflanking
|
| 1395 |
+
+ 21 * pawnsOnBothFlanks
|
| 1396 |
+
+ 24 * infiltration
|
| 1397 |
+
+ 51 * !pos.non_pawn_material()
|
| 1398 |
+
- 43 * almostUnwinnable
|
| 1399 |
+
-110 ;
|
| 1400 |
+
}
|
| 1401 |
+
|
| 1402 |
+
Value mg = mg_value(score);
|
| 1403 |
+
Value eg = eg_value(score);
|
| 1404 |
+
|
| 1405 |
+
// Now apply the bonus: note that we find the attacking side by extracting the
|
| 1406 |
+
// sign of the midgame or endgame values, and that we carefully cap the bonus
|
| 1407 |
+
// so that the midgame and endgame scores do not change sign after the bonus.
|
| 1408 |
+
int u = ((mg > 0) - (mg < 0)) * std::clamp(complexity + 50, -abs(mg), 0);
|
| 1409 |
+
int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg));
|
| 1410 |
+
|
| 1411 |
+
mg += u;
|
| 1412 |
+
eg += v;
|
| 1413 |
+
|
| 1414 |
+
// Compute the scale factor for the winning side
|
| 1415 |
+
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
|
| 1416 |
+
int sf = me->scale_factor(pos, strongSide);
|
| 1417 |
+
|
| 1418 |
+
// If scale factor is not already specific, scale up/down via general heuristics
|
| 1419 |
+
if (sf == SCALE_FACTOR_NORMAL && !pos.captures_to_hand() && !pos.material_counting())
|
| 1420 |
+
{
|
| 1421 |
+
if (pos.opposite_bishops())
|
| 1422 |
+
{
|
| 1423 |
+
// For pure opposite colored bishops endgames use scale factor
|
| 1424 |
+
// based on the number of passed pawns of the strong side.
|
| 1425 |
+
if ( pos.non_pawn_material(WHITE) == BishopValueMg
|
| 1426 |
+
&& pos.non_pawn_material(BLACK) == BishopValueMg)
|
| 1427 |
+
sf = 18 + 4 * popcount(pe->passed_pawns(strongSide));
|
| 1428 |
+
// For every other opposite colored bishops endgames use scale factor
|
| 1429 |
+
// based on the number of all pieces of the strong side.
|
| 1430 |
+
else
|
| 1431 |
+
sf = 22 + 3 * pos.count<ALL_PIECES>(strongSide);
|
| 1432 |
+
}
|
| 1433 |
+
// For rook endgames with strong side not having overwhelming pawn number advantage
|
| 1434 |
+
// and its pawns being on one flank and weak side protecting its pieces with a king
|
| 1435 |
+
// use lower scale factor.
|
| 1436 |
+
else if ( pos.non_pawn_material(WHITE) == RookValueMg
|
| 1437 |
+
&& pos.non_pawn_material(BLACK) == RookValueMg
|
| 1438 |
+
&& pos.count<PAWN>(strongSide) - pos.count<PAWN>(~strongSide) <= 1
|
| 1439 |
+
&& bool(KingSide & pos.pieces(strongSide, PAWN)) != bool(QueenSide & pos.pieces(strongSide, PAWN))
|
| 1440 |
+
&& pos.count<KING>(~strongSide)
|
| 1441 |
+
&& (attacks_bb<KING>(pos.square<KING>(~strongSide)) & pos.pieces(~strongSide, PAWN)))
|
| 1442 |
+
sf = 36;
|
| 1443 |
+
// For queen vs no queen endgames use scale factor
|
| 1444 |
+
// based on number of minors of side that doesn't have queen.
|
| 1445 |
+
else if (pos.count<QUEEN>() == 1)
|
| 1446 |
+
sf = 37 + 3 * (pos.count<QUEEN>(WHITE) == 1 ? pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK)
|
| 1447 |
+
: pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE));
|
| 1448 |
+
// In every other case use scale factor based on
|
| 1449 |
+
// the number of pawns of the strong side reduced if pawns are on a single flank.
|
| 1450 |
+
else
|
| 1451 |
+
sf = std::min(sf, 36 + 7 * (pos.count<PAWN>(strongSide) + pos.count<SOLDIER>(strongSide))) - 4 * !pawnsOnBothFlanks;
|
| 1452 |
+
|
| 1453 |
+
// Reduce scale factor in case of pawns being on a single flank
|
| 1454 |
+
sf -= 4 * !pawnsOnBothFlanks;
|
| 1455 |
+
}
|
| 1456 |
+
|
| 1457 |
+
// Interpolate between the middlegame and (scaled by 'sf') endgame score
|
| 1458 |
+
v = mg * int(me->game_phase())
|
| 1459 |
+
+ eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
|
| 1460 |
+
v /= PHASE_MIDGAME;
|
| 1461 |
+
|
| 1462 |
+
if constexpr (T)
|
| 1463 |
+
{
|
| 1464 |
+
Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
|
| 1465 |
+
Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
|
| 1466 |
+
}
|
| 1467 |
+
|
| 1468 |
+
return Value(v);
|
| 1469 |
+
}
|
| 1470 |
+
|
| 1471 |
+
|
| 1472 |
+
// Evaluation::value() is the main function of the class. It computes the various
|
| 1473 |
+
// parts of the evaluation and returns the value of the position from the point
|
| 1474 |
+
// of view of the side to move.
|
| 1475 |
+
|
| 1476 |
+
template<Tracing T>
|
| 1477 |
+
Value Evaluation<T>::value() {
|
| 1478 |
+
|
| 1479 |
+
assert(!pos.checkers());
|
| 1480 |
+
assert(!pos.is_immediate_game_end());
|
| 1481 |
+
|
| 1482 |
+
// Probe the material hash table
|
| 1483 |
+
me = Material::probe(pos);
|
| 1484 |
+
|
| 1485 |
+
// If we have a specialized evaluation function for the current material
|
| 1486 |
+
// configuration, call it and return.
|
| 1487 |
+
if (me->specialized_eval_exists())
|
| 1488 |
+
return me->evaluate(pos);
|
| 1489 |
+
|
| 1490 |
+
// Initialize score by reading the incrementally updated scores included in
|
| 1491 |
+
// the position object (material + piece square tables) and the material
|
| 1492 |
+
// imbalance. Score is computed internally from the white point of view.
|
| 1493 |
+
Score score = pos.psq_score();
|
| 1494 |
+
if (T)
|
| 1495 |
+
Trace::add(MATERIAL, score);
|
| 1496 |
+
score += me->imbalance() + pos.this_thread()->trend;
|
| 1497 |
+
|
| 1498 |
+
// Probe the pawn hash table
|
| 1499 |
+
pe = Pawns::probe(pos);
|
| 1500 |
+
score += pe->pawn_score(WHITE) - pe->pawn_score(BLACK);
|
| 1501 |
+
|
| 1502 |
+
// Early exit if score is high
|
| 1503 |
+
auto lazy_skip = [&](Value lazyThreshold) {
|
| 1504 |
+
return abs(mg_value(score) + eg_value(score)) / 2 > lazyThreshold + pos.non_pawn_material() / 64;
|
| 1505 |
+
};
|
| 1506 |
+
|
| 1507 |
+
if (lazy_skip(LazyThreshold1) && Options["UCI_Variant"] == "chess")
|
| 1508 |
+
goto make_v;
|
| 1509 |
+
|
| 1510 |
+
// Main evaluation begins here
|
| 1511 |
+
std::memset(attackedBy, 0, sizeof(attackedBy));
|
| 1512 |
+
initialize<WHITE>();
|
| 1513 |
+
initialize<BLACK>();
|
| 1514 |
+
|
| 1515 |
+
// Pieces evaluated first (also populates attackedBy, attackedBy2).
|
| 1516 |
+
// For unused piece types, we still need to set attack bitboard to zero.
|
| 1517 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 1518 |
+
{
|
| 1519 |
+
PieceType pt = pop_lsb(ps);
|
| 1520 |
+
if (pt != SHOGI_PAWN && pt != PAWN && pt != KING)
|
| 1521 |
+
score += pieces<WHITE>(pt) - pieces<BLACK>(pt);
|
| 1522 |
+
}
|
| 1523 |
+
|
| 1524 |
+
// Evaluate pieces in hand once attack tables are complete
|
| 1525 |
+
if (pos.piece_drops() || pos.seirawan_gating())
|
| 1526 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 1527 |
+
{
|
| 1528 |
+
PieceType pt = pop_lsb(ps);
|
| 1529 |
+
score += hand<WHITE>(pt) - hand<BLACK>(pt);
|
| 1530 |
+
}
|
| 1531 |
+
|
| 1532 |
+
score += (mobility[WHITE] - mobility[BLACK]) * (1 + pos.captures_to_hand() + pos.must_capture() + pos.check_counting());
|
| 1533 |
+
|
| 1534 |
+
// More complex interactions that require fully populated attack bitboards
|
| 1535 |
+
score += king< WHITE>() - king< BLACK>()
|
| 1536 |
+
+ passed< WHITE>() - passed< BLACK>()
|
| 1537 |
+
+ variant<WHITE>() - variant<BLACK>();
|
| 1538 |
+
|
| 1539 |
+
if (lazy_skip(LazyThreshold2) && Options["UCI_Variant"] == "chess")
|
| 1540 |
+
goto make_v;
|
| 1541 |
+
|
| 1542 |
+
score += threats<WHITE>() - threats<BLACK>()
|
| 1543 |
+
+ space< WHITE>() - space< BLACK>();
|
| 1544 |
+
|
| 1545 |
+
make_v:
|
| 1546 |
+
// Derive single value from mg and eg parts of score
|
| 1547 |
+
Value v = winnable(score);
|
| 1548 |
+
|
| 1549 |
+
// In case of tracing add all remaining individual evaluation terms
|
| 1550 |
+
if constexpr (T)
|
| 1551 |
+
{
|
| 1552 |
+
Trace::add(IMBALANCE, me->imbalance());
|
| 1553 |
+
Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK));
|
| 1554 |
+
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
|
| 1555 |
+
}
|
| 1556 |
+
|
| 1557 |
+
// Evaluation grain
|
| 1558 |
+
v = (v / 16) * 16;
|
| 1559 |
+
|
| 1560 |
+
// Side to move point of view
|
| 1561 |
+
v = (pos.side_to_move() == WHITE ? v : -v) + 80 * pos.captures_to_hand();
|
| 1562 |
+
|
| 1563 |
+
return v;
|
| 1564 |
+
}
|
| 1565 |
+
|
| 1566 |
+
|
| 1567 |
+
/// Fisher Random Chess: correction for cornered bishops, to fix chess960 play with NNUE
|
| 1568 |
+
|
| 1569 |
+
Value fix_FRC(const Position& pos) {
|
| 1570 |
+
|
| 1571 |
+
constexpr Bitboard Corners = Bitboard(1ULL) << SQ_A1 | Bitboard(1ULL) << SQ_H1 | Bitboard(1ULL) << SQ_A8 | Bitboard(1ULL) << SQ_H8;
|
| 1572 |
+
|
| 1573 |
+
if (!(pos.pieces(BISHOP) & Corners))
|
| 1574 |
+
return VALUE_ZERO;
|
| 1575 |
+
|
| 1576 |
+
int correction = 0;
|
| 1577 |
+
|
| 1578 |
+
if ( pos.piece_on(SQ_A1) == W_BISHOP
|
| 1579 |
+
&& pos.piece_on(SQ_B2) == W_PAWN)
|
| 1580 |
+
correction += !pos.empty(SQ_B3) ? -CorneredBishop * 4
|
| 1581 |
+
: -CorneredBishop * 3;
|
| 1582 |
+
|
| 1583 |
+
if ( pos.piece_on(SQ_H1) == W_BISHOP
|
| 1584 |
+
&& pos.piece_on(SQ_G2) == W_PAWN)
|
| 1585 |
+
correction += !pos.empty(SQ_G3) ? -CorneredBishop * 4
|
| 1586 |
+
: -CorneredBishop * 3;
|
| 1587 |
+
|
| 1588 |
+
if ( pos.piece_on(SQ_A8) == B_BISHOP
|
| 1589 |
+
&& pos.piece_on(SQ_B7) == B_PAWN)
|
| 1590 |
+
correction += !pos.empty(SQ_B6) ? CorneredBishop * 4
|
| 1591 |
+
: CorneredBishop * 3;
|
| 1592 |
+
|
| 1593 |
+
if ( pos.piece_on(SQ_H8) == B_BISHOP
|
| 1594 |
+
&& pos.piece_on(SQ_G7) == B_PAWN)
|
| 1595 |
+
correction += !pos.empty(SQ_G6) ? CorneredBishop * 4
|
| 1596 |
+
: CorneredBishop * 3;
|
| 1597 |
+
|
| 1598 |
+
return pos.side_to_move() == WHITE ? Value(correction)
|
| 1599 |
+
: -Value(correction);
|
| 1600 |
+
}
|
| 1601 |
+
|
| 1602 |
+
} // namespace Eval
|
| 1603 |
+
|
| 1604 |
+
|
| 1605 |
+
/// evaluate() is the evaluator for the outer world. It returns a static
|
| 1606 |
+
/// evaluation of the position from the point of view of the side to move.
|
| 1607 |
+
|
| 1608 |
+
Value Eval::evaluate(const Position& pos) {
|
| 1609 |
+
|
| 1610 |
+
Value v;
|
| 1611 |
+
|
| 1612 |
+
if (!Eval::useNNUE || !pos.nnue_applicable())
|
| 1613 |
+
v = Evaluation<NO_TRACE>(pos).value();
|
| 1614 |
+
else
|
| 1615 |
+
{
|
| 1616 |
+
// Scale and shift NNUE for compatibility with search and classical evaluation
|
| 1617 |
+
auto adjusted_NNUE = [&]()
|
| 1618 |
+
{
|
| 1619 |
+
int scale = 903
|
| 1620 |
+
+ 32 * pos.count<PAWN>()
|
| 1621 |
+
+ 32 * pos.non_pawn_material() / 1024;
|
| 1622 |
+
|
| 1623 |
+
Value nnue = NNUE::evaluate(pos, true) * scale / 1024;
|
| 1624 |
+
|
| 1625 |
+
if (pos.is_chess960())
|
| 1626 |
+
nnue += fix_FRC(pos);
|
| 1627 |
+
|
| 1628 |
+
if (pos.check_counting())
|
| 1629 |
+
{
|
| 1630 |
+
Color us = pos.side_to_move();
|
| 1631 |
+
nnue += 6 * scale / (5 * pos.checks_remaining( us))
|
| 1632 |
+
- 6 * scale / (5 * pos.checks_remaining(~us));
|
| 1633 |
+
}
|
| 1634 |
+
|
| 1635 |
+
return nnue;
|
| 1636 |
+
};
|
| 1637 |
+
|
| 1638 |
+
// If there is PSQ imbalance we use the classical eval, but we switch to
|
| 1639 |
+
// NNUE eval faster when shuffling or if the material on the board is high.
|
| 1640 |
+
int r50 = pos.rule50_count();
|
| 1641 |
+
Value psq = Value(abs(eg_value(pos.psq_score())));
|
| 1642 |
+
bool pure = !pos.check_counting();
|
| 1643 |
+
bool classical = psq * 5 > (750 + pos.non_pawn_material() / 64) * (5 + r50) && !pure;
|
| 1644 |
+
|
| 1645 |
+
v = classical ? Evaluation<NO_TRACE>(pos).value() // classical
|
| 1646 |
+
: adjusted_NNUE(); // NNUE
|
| 1647 |
+
}
|
| 1648 |
+
|
| 1649 |
+
// Damp down the evaluation linearly when shuffling
|
| 1650 |
+
if (pos.n_move_rule())
|
| 1651 |
+
{
|
| 1652 |
+
v = v * (2 * pos.n_move_rule() - pos.rule50_count()) / (2 * pos.n_move_rule());
|
| 1653 |
+
if (pos.material_counting())
|
| 1654 |
+
v += pos.material_counting_result() / (10 * std::max(2 * pos.n_move_rule() - pos.rule50_count(), 1));
|
| 1655 |
+
}
|
| 1656 |
+
|
| 1657 |
+
// Guarantee evaluation does not hit the virtual win/loss range
|
| 1658 |
+
if (pos.two_boards() && std::abs(v) >= VALUE_VIRTUAL_MATE_IN_MAX_PLY)
|
| 1659 |
+
v += v > VALUE_ZERO ? MAX_PLY + 1 : -MAX_PLY - 1;
|
| 1660 |
+
|
| 1661 |
+
// Guarantee evaluation does not hit the tablebase range
|
| 1662 |
+
v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
| 1663 |
+
|
| 1664 |
+
return v;
|
| 1665 |
+
}
|
| 1666 |
+
|
| 1667 |
+
/// trace() is like evaluate(), but instead of returning a value, it returns
|
| 1668 |
+
/// a string (suitable for outputting to stdout) that contains the detailed
|
| 1669 |
+
/// descriptions and values of each evaluation term. Useful for debugging.
|
| 1670 |
+
/// Trace scores are from white's point of view
|
| 1671 |
+
|
| 1672 |
+
std::string Eval::trace(Position& pos) {
|
| 1673 |
+
|
| 1674 |
+
if (pos.checkers())
|
| 1675 |
+
return "Final evaluation: none (in check)";
|
| 1676 |
+
|
| 1677 |
+
std::stringstream ss;
|
| 1678 |
+
ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2);
|
| 1679 |
+
|
| 1680 |
+
Value v;
|
| 1681 |
+
|
| 1682 |
+
std::memset(scores, 0, sizeof(scores));
|
| 1683 |
+
|
| 1684 |
+
pos.this_thread()->trend = SCORE_ZERO; // Reset any dynamic contempt
|
| 1685 |
+
|
| 1686 |
+
v = Evaluation<TRACE>(pos).value();
|
| 1687 |
+
|
| 1688 |
+
ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
|
| 1689 |
+
<< " Contributing terms for the classical eval:\n"
|
| 1690 |
+
<< "+------------+-------------+-------------+-------------+\n"
|
| 1691 |
+
<< "| Term | White | Black | Total |\n"
|
| 1692 |
+
<< "| | MG EG | MG EG | MG EG |\n"
|
| 1693 |
+
<< "+------------+-------------+-------------+-------------+\n"
|
| 1694 |
+
<< "| Material | " << Term(MATERIAL)
|
| 1695 |
+
<< "| Imbalance | " << Term(IMBALANCE)
|
| 1696 |
+
<< "| Pawns | " << Term(PAWN)
|
| 1697 |
+
<< "| Knights | " << Term(KNIGHT)
|
| 1698 |
+
<< "| Bishops | " << Term(BISHOP)
|
| 1699 |
+
<< "| Rooks | " << Term(ROOK)
|
| 1700 |
+
<< "| Queens | " << Term(QUEEN)
|
| 1701 |
+
<< "| Mobility | " << Term(MOBILITY)
|
| 1702 |
+
<< "|King safety | " << Term(KING)
|
| 1703 |
+
<< "| Threats | " << Term(THREAT)
|
| 1704 |
+
<< "| Passed | " << Term(PASSED)
|
| 1705 |
+
<< "| Space | " << Term(SPACE)
|
| 1706 |
+
<< "| Variant | " << Term(VARIANT)
|
| 1707 |
+
<< "| Winnable | " << Term(WINNABLE)
|
| 1708 |
+
<< "+------------+-------------+-------------+-------------+\n"
|
| 1709 |
+
<< "| Total | " << Term(TOTAL)
|
| 1710 |
+
<< "+------------+-------------+-------------+-------------+\n";
|
| 1711 |
+
|
| 1712 |
+
if (Eval::useNNUE && pos.nnue_applicable())
|
| 1713 |
+
ss << '\n' << NNUE::trace(pos) << '\n';
|
| 1714 |
+
|
| 1715 |
+
ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2) << std::setw(15);
|
| 1716 |
+
|
| 1717 |
+
v = pos.side_to_move() == WHITE ? v : -v;
|
| 1718 |
+
ss << "\nClassical evaluation " << to_cp(v) << " (white side)\n";
|
| 1719 |
+
if (Eval::useNNUE && pos.nnue_applicable())
|
| 1720 |
+
{
|
| 1721 |
+
v = NNUE::evaluate(pos, false);
|
| 1722 |
+
v = pos.side_to_move() == WHITE ? v : -v;
|
| 1723 |
+
ss << "NNUE evaluation " << to_cp(v) << " (white side)\n";
|
| 1724 |
+
}
|
| 1725 |
+
|
| 1726 |
+
v = evaluate(pos);
|
| 1727 |
+
v = pos.side_to_move() == WHITE ? v : -v;
|
| 1728 |
+
ss << "Final evaluation " << to_cp(v) << " (white side)";
|
| 1729 |
+
if (Eval::useNNUE && pos.nnue_applicable())
|
| 1730 |
+
ss << " [with scaled NNUE, hybrid, ...]";
|
| 1731 |
+
ss << "\n";
|
| 1732 |
+
|
| 1733 |
+
return ss.str();
|
| 1734 |
+
}
|
| 1735 |
+
|
| 1736 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/evaluate.h
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef EVALUATE_H_INCLUDED
|
| 20 |
+
#define EVALUATE_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <string>
|
| 23 |
+
#include <optional>
|
| 24 |
+
|
| 25 |
+
#include "types.h"
|
| 26 |
+
|
| 27 |
+
#include "variant.h"
|
| 28 |
+
|
| 29 |
+
namespace Stockfish {
|
| 30 |
+
|
| 31 |
+
class Position;
|
| 32 |
+
|
| 33 |
+
namespace Eval {
|
| 34 |
+
|
| 35 |
+
std::string trace(Position& pos);
|
| 36 |
+
Value evaluate(const Position& pos);
|
| 37 |
+
|
| 38 |
+
extern bool useNNUE;
|
| 39 |
+
extern std::string eval_file_loaded;
|
| 40 |
+
|
| 41 |
+
// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
|
| 42 |
+
// for the build process (profile-build and fishtest) to work. Do not change the
|
| 43 |
+
// name of the macro, as it is used in the Makefile.
|
| 44 |
+
#define EvalFileDefaultName "nn-3475407dc199.nnue"
|
| 45 |
+
|
| 46 |
+
namespace NNUE {
|
| 47 |
+
|
| 48 |
+
std::string trace(Position& pos);
|
| 49 |
+
Value evaluate(const Position& pos, bool adjusted = false);
|
| 50 |
+
|
| 51 |
+
void init();
|
| 52 |
+
void verify();
|
| 53 |
+
|
| 54 |
+
bool load_eval(std::string name, std::istream& stream);
|
| 55 |
+
bool save_eval(std::ostream& stream);
|
| 56 |
+
bool save_eval(const std::optional<std::string>& filename);
|
| 57 |
+
|
| 58 |
+
} // namespace NNUE
|
| 59 |
+
|
| 60 |
+
} // namespace Eval
|
| 61 |
+
|
| 62 |
+
extern const Variant* currentNnueVariant;
|
| 63 |
+
|
| 64 |
+
} // namespace Stockfish
|
| 65 |
+
|
| 66 |
+
#endif // #ifndef EVALUATE_H_INCLUDED
|
Fairy-Stockfish-master/src/ffishjs.cpp
ADDED
|
@@ -0,0 +1,767 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
ffish.js, a JavaScript chess variant library derived from Fairy-Stockfish
|
| 3 |
+
Copyright (C) 2022 Fabian Fichter, Johannes Czech
|
| 4 |
+
|
| 5 |
+
ffish.js is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
ffish.js is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <emscripten.h>
|
| 20 |
+
#include <emscripten/bind.h>
|
| 21 |
+
#include <vector>
|
| 22 |
+
#include <string>
|
| 23 |
+
#include <sstream>
|
| 24 |
+
#include<iostream>
|
| 25 |
+
|
| 26 |
+
#include "misc.h"
|
| 27 |
+
#include "types.h"
|
| 28 |
+
#include "bitboard.h"
|
| 29 |
+
#include "evaluate.h"
|
| 30 |
+
#include "position.h"
|
| 31 |
+
#include "search.h"
|
| 32 |
+
#include "syzygy/tbprobe.h"
|
| 33 |
+
#include "thread.h"
|
| 34 |
+
#include "tt.h"
|
| 35 |
+
#include "uci.h"
|
| 36 |
+
#include "piece.h"
|
| 37 |
+
#include "variant.h"
|
| 38 |
+
#include "movegen.h"
|
| 39 |
+
#include "apiutil.h"
|
| 40 |
+
|
| 41 |
+
using namespace emscripten;
|
| 42 |
+
|
| 43 |
+
using namespace Stockfish;
|
| 44 |
+
|
| 45 |
+
void initialize_stockfish() {
|
| 46 |
+
pieceMap.init();
|
| 47 |
+
variants.init();
|
| 48 |
+
UCI::init(Options);
|
| 49 |
+
Bitboards::init();
|
| 50 |
+
Position::init();
|
| 51 |
+
Bitbases::init();
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
#define DELIM " "
|
| 55 |
+
|
| 56 |
+
inline void save_pop_back(std::string& s) {
|
| 57 |
+
if (s.size() != 0) {
|
| 58 |
+
s.pop_back();
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
const Variant* get_variant(const std::string& uciVariant) {
|
| 63 |
+
if (uciVariant.size() == 0 || uciVariant == "Standard" || uciVariant == "standard")
|
| 64 |
+
return variants.find("chess")->second;
|
| 65 |
+
return variants.find(uciVariant)->second;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
template <bool isUCI>
|
| 69 |
+
inline bool is_move_none(Move move, const std::string& strMove, const Position& pos) {
|
| 70 |
+
if (move == MOVE_NONE) {
|
| 71 |
+
std::cerr << "The given ";
|
| 72 |
+
isUCI ? std::cerr << "uciMove" : std::cerr << "sanMove";
|
| 73 |
+
std::cerr << " '" << strMove << "' for position '" << pos.fen() << "' is invalid." << std::endl;
|
| 74 |
+
return true;
|
| 75 |
+
}
|
| 76 |
+
return false;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
class Board {
|
| 80 |
+
// note: we can't use references for strings here due to conversion to JavaScript
|
| 81 |
+
private:
|
| 82 |
+
const Variant* v;
|
| 83 |
+
StateListPtr states;
|
| 84 |
+
Position pos;
|
| 85 |
+
Thread* thread;
|
| 86 |
+
std::vector<Move> moveStack;
|
| 87 |
+
bool is960;
|
| 88 |
+
|
| 89 |
+
public:
|
| 90 |
+
static bool sfInitialized;
|
| 91 |
+
|
| 92 |
+
Board():
|
| 93 |
+
Board("chess", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" , false) {
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
Board(std::string uciVariant):
|
| 97 |
+
Board(uciVariant, "", false) {
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
Board(std::string uciVariant, std::string fen):
|
| 101 |
+
Board(uciVariant, fen, false) {
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
Board(std::string uciVariant, std::string fen, bool is960) {
|
| 105 |
+
init(uciVariant, fen, is960);
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
std::string legal_moves() {
|
| 109 |
+
std::string moves;
|
| 110 |
+
for (const ExtMove& move : MoveList<LEGAL>(this->pos)) {
|
| 111 |
+
moves += UCI::move(this->pos, move);
|
| 112 |
+
moves += DELIM;
|
| 113 |
+
}
|
| 114 |
+
save_pop_back(moves);
|
| 115 |
+
return moves;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
std::string legal_moves_san() {
|
| 119 |
+
std::string movesSan;
|
| 120 |
+
for (const ExtMove& move : MoveList<LEGAL>(this->pos)) {
|
| 121 |
+
movesSan += SAN::move_to_san(this->pos, move, NOTATION_SAN);
|
| 122 |
+
movesSan += DELIM;
|
| 123 |
+
}
|
| 124 |
+
save_pop_back(movesSan);
|
| 125 |
+
return movesSan;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
int number_legal_moves() const {
|
| 129 |
+
return MoveList<LEGAL>(pos).size();
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
bool push(std::string uciMove) {
|
| 133 |
+
const Move move = UCI::to_move(this->pos, uciMove);
|
| 134 |
+
if (is_move_none<true>(move, uciMove, pos))
|
| 135 |
+
return false;
|
| 136 |
+
do_move(move);
|
| 137 |
+
return true;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
bool push_san(std::string sanMove) {
|
| 141 |
+
return push_san(sanMove, NOTATION_SAN);
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
// TODO: This is a naive implementation which compares all legal SAN moves with the requested string.
|
| 145 |
+
// If the SAN move wasn't found the position remains unchanged. Alternatively, implement a direct conversion.
|
| 146 |
+
bool push_san(std::string sanMove, Notation notation) {
|
| 147 |
+
Move foundMove = MOVE_NONE;
|
| 148 |
+
for (const ExtMove& move : MoveList<LEGAL>(pos)) {
|
| 149 |
+
if (sanMove == SAN::move_to_san(this->pos, move, notation)) {
|
| 150 |
+
foundMove = move;
|
| 151 |
+
break;
|
| 152 |
+
}
|
| 153 |
+
}
|
| 154 |
+
if (is_move_none<false>(foundMove, sanMove, pos))
|
| 155 |
+
return false;
|
| 156 |
+
do_move(foundMove);
|
| 157 |
+
return true;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
void pop() {
|
| 161 |
+
pos.undo_move(this->moveStack.back());
|
| 162 |
+
moveStack.pop_back();
|
| 163 |
+
states->pop_back();
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
void reset() {
|
| 167 |
+
set_fen(v->startFen);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
bool is_960() const {
|
| 171 |
+
return is960;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
std::string fen() const {
|
| 175 |
+
return this->pos.fen();
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
std::string fen(bool showPromoted) const {
|
| 179 |
+
return this->pos.fen(false, showPromoted);
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
std::string fen(bool showPromoted, int countStarted) const {
|
| 183 |
+
return this->pos.fen(false, showPromoted, countStarted);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
void set_fen(std::string fen) {
|
| 187 |
+
resetStates();
|
| 188 |
+
moveStack.clear();
|
| 189 |
+
pos.set(v, fen, is960, &states->back(), thread);
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
// note: const identifier for pos not possible due to SAN::move_to_san()
|
| 193 |
+
std::string san_move(std::string uciMove) {
|
| 194 |
+
return san_move(uciMove, NOTATION_SAN);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
std::string san_move(std::string uciMove, Notation notation) {
|
| 198 |
+
const Move move = UCI::to_move(this->pos, uciMove);
|
| 199 |
+
if (is_move_none<true>(move, uciMove, pos))
|
| 200 |
+
return "";
|
| 201 |
+
return SAN::move_to_san(this->pos, UCI::to_move(this->pos, uciMove), notation);
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
std::string variation_san(std::string uciMoves) {
|
| 205 |
+
return variation_san(uciMoves, NOTATION_SAN, true);
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
std::string variation_san(std::string uciMoves, Notation notation) {
|
| 209 |
+
return variation_san(uciMoves, notation, true);
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
std::string variation_san(std::string uciMoves, Notation notation, bool moveNumbers) {
|
| 213 |
+
std::stringstream ss(uciMoves);
|
| 214 |
+
StateListPtr tempStates;
|
| 215 |
+
std::vector<Move> moves;
|
| 216 |
+
std::string variationSan = "";
|
| 217 |
+
std::string uciMove;
|
| 218 |
+
bool first = true;
|
| 219 |
+
|
| 220 |
+
while (std::getline(ss, uciMove, ' ')) {
|
| 221 |
+
const Move move = UCI::to_move(this->pos, uciMove);
|
| 222 |
+
if (is_move_none<true>(move, uciMove, pos))
|
| 223 |
+
return "";
|
| 224 |
+
moves.emplace_back(UCI::to_move(this->pos, uciMove));
|
| 225 |
+
if (first) {
|
| 226 |
+
first = false;
|
| 227 |
+
if (moveNumbers) {
|
| 228 |
+
variationSan = std::to_string(fullmove_number());
|
| 229 |
+
if (pos.side_to_move() == WHITE)
|
| 230 |
+
variationSan += ". ";
|
| 231 |
+
else
|
| 232 |
+
variationSan += "...";
|
| 233 |
+
}
|
| 234 |
+
variationSan += SAN::move_to_san(this->pos, moves.back(), Notation(notation));
|
| 235 |
+
}
|
| 236 |
+
else {
|
| 237 |
+
if (moveNumbers && pos.side_to_move() == WHITE) {
|
| 238 |
+
variationSan += DELIM;
|
| 239 |
+
variationSan += std::to_string(fullmove_number());
|
| 240 |
+
variationSan += ".";
|
| 241 |
+
}
|
| 242 |
+
variationSan += DELIM;
|
| 243 |
+
variationSan += SAN::move_to_san(this->pos, moves.back(), Notation(notation));
|
| 244 |
+
}
|
| 245 |
+
states->emplace_back();
|
| 246 |
+
pos.do_move(moves.back(), states->back());
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
// recover initial state
|
| 250 |
+
for(auto rIt = std::rbegin(moves); rIt != std::rend(moves); ++rIt) {
|
| 251 |
+
pos.undo_move(*rIt);
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
return variationSan;
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
// returns true for WHITE and false for BLACK
|
| 258 |
+
bool turn() const {
|
| 259 |
+
return !pos.side_to_move();
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
int fullmove_number() const {
|
| 263 |
+
return pos.game_ply() / 2 + 1;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
int halfmove_clock() const {
|
| 267 |
+
return pos.rule50_count();
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
int game_ply() const {
|
| 271 |
+
return pos.game_ply();
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
bool has_insufficient_material(bool turn) const {
|
| 275 |
+
return Stockfish::has_insufficient_material(turn ? WHITE : BLACK, pos);
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
bool is_insufficient_material() const {
|
| 279 |
+
return Stockfish::has_insufficient_material(WHITE, pos) && Stockfish::has_insufficient_material(BLACK, pos);
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
bool is_game_over() const {
|
| 283 |
+
return is_game_over(false);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
bool is_game_over(bool claim_draw) const {
|
| 287 |
+
if (is_insufficient_material())
|
| 288 |
+
return true;
|
| 289 |
+
if (claim_draw && pos.is_optional_game_end())
|
| 290 |
+
return true;
|
| 291 |
+
return MoveList<LEGAL>(pos).size() == 0;
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
std::string result() const {
|
| 295 |
+
return result(false);
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
std::string result(bool claim_draw) const {
|
| 299 |
+
Value result;
|
| 300 |
+
bool gameEnd = pos.is_immediate_game_end(result);
|
| 301 |
+
if (!gameEnd) {
|
| 302 |
+
if (is_insufficient_material()) {
|
| 303 |
+
gameEnd = true;
|
| 304 |
+
result = VALUE_DRAW;
|
| 305 |
+
}
|
| 306 |
+
}
|
| 307 |
+
if (!gameEnd && MoveList<LEGAL>(pos).size() == 0) {
|
| 308 |
+
gameEnd = true;
|
| 309 |
+
result = pos.checkers() ? pos.checkmate_value() : pos.stalemate_value();
|
| 310 |
+
}
|
| 311 |
+
if (!gameEnd && claim_draw)
|
| 312 |
+
gameEnd = pos.is_optional_game_end(result);
|
| 313 |
+
|
| 314 |
+
if (!gameEnd)
|
| 315 |
+
return "*";
|
| 316 |
+
if (result == 0)
|
| 317 |
+
return "1/2-1/2";
|
| 318 |
+
if (pos.side_to_move() == BLACK)
|
| 319 |
+
result = -result;
|
| 320 |
+
if (result > 0)
|
| 321 |
+
return "1-0";
|
| 322 |
+
else
|
| 323 |
+
return "0-1";
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
std::string checked_pieces() const {
|
| 327 |
+
Bitboard checked = Stockfish::checked(pos);
|
| 328 |
+
std::string squares;
|
| 329 |
+
while (checked) {
|
| 330 |
+
Square sr = pop_lsb(checked);
|
| 331 |
+
squares += UCI::square(pos, sr);
|
| 332 |
+
squares += DELIM;
|
| 333 |
+
}
|
| 334 |
+
save_pop_back(squares);
|
| 335 |
+
return squares;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
bool is_check() const {
|
| 339 |
+
return Stockfish::checked(pos);
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
bool is_bikjang() const {
|
| 343 |
+
return pos.bikjang();
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
bool is_capture(std::string uciMove) const {
|
| 347 |
+
return pos.capture(UCI::to_move(pos, uciMove));
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
std::string move_stack() const {
|
| 351 |
+
std::string moves;
|
| 352 |
+
for(auto it = std::begin(moveStack); it != std::end(moveStack); ++it) {
|
| 353 |
+
moves += UCI::move(pos, *it);
|
| 354 |
+
moves += DELIM;
|
| 355 |
+
}
|
| 356 |
+
save_pop_back(moves);
|
| 357 |
+
return moves;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
void push_moves(std::string uciMoves) {
|
| 361 |
+
std::stringstream ss(uciMoves);
|
| 362 |
+
std::string uciMove;
|
| 363 |
+
while (std::getline(ss, uciMove, ' ')) {
|
| 364 |
+
push(uciMove);
|
| 365 |
+
}
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
void push_san_moves(std::string sanMoves) {
|
| 369 |
+
return push_san_moves(sanMoves, NOTATION_SAN);
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
void push_san_moves(std::string sanMoves, Notation notation) {
|
| 373 |
+
std::stringstream ss(sanMoves);
|
| 374 |
+
std::string sanMove;
|
| 375 |
+
while (std::getline(ss, sanMove, ' '))
|
| 376 |
+
push_san(sanMove, notation);
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
std::string pocket(bool color) {
|
| 380 |
+
const Color c = Color(!color);
|
| 381 |
+
std::string pocket;
|
| 382 |
+
for (PieceType pt = KING; pt >= PAWN; --pt) {
|
| 383 |
+
for (int i = 0; i < pos.count_in_hand(c, pt); ++i) {
|
| 384 |
+
// only create BLACK pieces in order to convert to lower case
|
| 385 |
+
pocket += std::string(1, pos.piece_to_char()[make_piece(BLACK, pt)]);
|
| 386 |
+
}
|
| 387 |
+
}
|
| 388 |
+
return pocket;
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
std::string to_string() {
|
| 392 |
+
std::string stringBoard;
|
| 393 |
+
for (Rank r = pos.max_rank(); r >= RANK_1; --r) {
|
| 394 |
+
for (File f = FILE_A; f <= pos.max_file(); ++f) {
|
| 395 |
+
if (f != FILE_A)
|
| 396 |
+
stringBoard += " ";
|
| 397 |
+
const Piece p = pos.piece_on(make_square(f, r));
|
| 398 |
+
switch(p) {
|
| 399 |
+
case NO_PIECE:
|
| 400 |
+
stringBoard += '.';
|
| 401 |
+
break;
|
| 402 |
+
default:
|
| 403 |
+
stringBoard += pos.piece_to_char()[p];
|
| 404 |
+
}
|
| 405 |
+
}
|
| 406 |
+
if (r != RANK_1)
|
| 407 |
+
stringBoard += "\n";
|
| 408 |
+
}
|
| 409 |
+
return stringBoard;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
std::string to_verbose_string() {
|
| 413 |
+
std::stringstream ss;
|
| 414 |
+
operator<<(ss, pos);
|
| 415 |
+
return ss.str();
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
std::string variant() {
|
| 419 |
+
// Iterate through the variants map
|
| 420 |
+
for (auto it = variants.begin(); it != variants.end(); ++it)
|
| 421 |
+
if (it->second == v)
|
| 422 |
+
return it->first;
|
| 423 |
+
|
| 424 |
+
std::cerr << "Current variant is not registered." << std::endl;
|
| 425 |
+
return "unknown";
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
private:
|
| 429 |
+
void resetStates() {
|
| 430 |
+
this->states = StateListPtr(new std::deque<StateInfo>(1));
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
void do_move(Move move) {
|
| 434 |
+
states->emplace_back();
|
| 435 |
+
this->pos.do_move(move, states->back());
|
| 436 |
+
this->moveStack.emplace_back(move);
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
void init(std::string uciVariant, std::string fen, bool is960) {
|
| 440 |
+
if (!Board::sfInitialized) {
|
| 441 |
+
initialize_stockfish();
|
| 442 |
+
Board::sfInitialized = true;
|
| 443 |
+
}
|
| 444 |
+
v = get_variant(uciVariant);
|
| 445 |
+
UCI::init_variant(v);
|
| 446 |
+
this->resetStates();
|
| 447 |
+
if (fen == "")
|
| 448 |
+
fen = v->startFen;
|
| 449 |
+
this->pos.set(this->v, fen, is960, &this->states->back(), this->thread);
|
| 450 |
+
this->is960 = is960;
|
| 451 |
+
}
|
| 452 |
+
};
|
| 453 |
+
|
| 454 |
+
bool Board::sfInitialized = false;
|
| 455 |
+
|
| 456 |
+
namespace ffish {
|
| 457 |
+
// returns the version of the Fairy-Stockfish binary
|
| 458 |
+
std::string info() {
|
| 459 |
+
return engine_info();
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
template <typename T>
|
| 463 |
+
void set_option(std::string name, T value) {
|
| 464 |
+
Options[name] = value;
|
| 465 |
+
Board::sfInitialized = false;
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
std::string available_variants() {
|
| 469 |
+
std::string availableVariants;
|
| 470 |
+
for (std::string variant : variants.get_keys()) {
|
| 471 |
+
availableVariants += variant;
|
| 472 |
+
availableVariants += DELIM;
|
| 473 |
+
}
|
| 474 |
+
save_pop_back(availableVariants);
|
| 475 |
+
return availableVariants;
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
+
void load_variant_config(std::string variantInitContent) {
|
| 479 |
+
std::stringstream ss(variantInitContent);
|
| 480 |
+
if (!Board::sfInitialized)
|
| 481 |
+
initialize_stockfish();
|
| 482 |
+
variants.parse_istream<false>(ss);
|
| 483 |
+
Options["UCI_Variant"].set_combo(variants.get_keys());
|
| 484 |
+
Board::sfInitialized = true;
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
bool captures_to_hand(std::string uciVariant) {
|
| 488 |
+
const Variant* v = get_variant(uciVariant);
|
| 489 |
+
return v->capturesToHand;
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
std::string starting_fen(std::string uciVariant) {
|
| 493 |
+
const Variant* v = get_variant(uciVariant);
|
| 494 |
+
return v->startFen;
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
int validate_fen(std::string fen, std::string uciVariant, bool chess960) {
|
| 498 |
+
const Variant* v = get_variant(uciVariant);
|
| 499 |
+
return FEN::validate_fen(fen, v, chess960);
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
int validate_fen(std::string fen, std::string uciVariant) {
|
| 503 |
+
return validate_fen(fen, uciVariant, false);
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
int validate_fen(std::string fen) {
|
| 507 |
+
return validate_fen(fen, "chess");
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
class Game {
|
| 512 |
+
private:
|
| 513 |
+
std::unordered_map<std::string, std::string> header;
|
| 514 |
+
std::unique_ptr<Board> board;
|
| 515 |
+
std::string variant = "chess";
|
| 516 |
+
std::string fen = ""; // start pos
|
| 517 |
+
bool is960 = false;
|
| 518 |
+
bool parsedGame = false;
|
| 519 |
+
public:
|
| 520 |
+
std::string header_keys() {
|
| 521 |
+
std::string keys;
|
| 522 |
+
for (auto it = header.begin(); it != header.end(); ++it) {
|
| 523 |
+
keys += it->first;
|
| 524 |
+
keys += DELIM;
|
| 525 |
+
}
|
| 526 |
+
save_pop_back(keys);
|
| 527 |
+
return keys;
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
std::string headers(std::string item) {
|
| 531 |
+
auto it = header.find(item);
|
| 532 |
+
if (it == header.end())
|
| 533 |
+
return "";
|
| 534 |
+
return it->second;
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
std::string mainline_moves() {
|
| 538 |
+
if (!parsedGame)
|
| 539 |
+
return "";
|
| 540 |
+
return board->move_stack();
|
| 541 |
+
}
|
| 542 |
+
|
| 543 |
+
friend Game read_game_pgn(std::string);
|
| 544 |
+
};
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
bool skip_comment(const std::string& pgn, size_t& curIdx, size_t& lineEnd) {
|
| 548 |
+
curIdx = pgn.find('}', curIdx);
|
| 549 |
+
if (curIdx == std::string::npos) {
|
| 550 |
+
std::cerr << "Missing '}' for move comment while reading pgn." << std::endl;
|
| 551 |
+
return false;
|
| 552 |
+
}
|
| 553 |
+
if (curIdx > lineEnd)
|
| 554 |
+
lineEnd = pgn.find('\n', curIdx);
|
| 555 |
+
return true;
|
| 556 |
+
}
|
| 557 |
+
|
| 558 |
+
Game read_game_pgn(std::string pgn) {
|
| 559 |
+
Game game;
|
| 560 |
+
size_t lineStart = 0;
|
| 561 |
+
bool headersParsed = false;
|
| 562 |
+
|
| 563 |
+
while(true) {
|
| 564 |
+
size_t lineEnd = pgn.find('\n', lineStart);
|
| 565 |
+
|
| 566 |
+
if (lineEnd == std::string::npos)
|
| 567 |
+
lineEnd = pgn.size();
|
| 568 |
+
|
| 569 |
+
if (!headersParsed && pgn[lineStart] == '[') {
|
| 570 |
+
// parse header
|
| 571 |
+
// look for item
|
| 572 |
+
size_t headerKeyStart = lineStart+1;
|
| 573 |
+
size_t headerKeyEnd = pgn.find(' ', lineStart);
|
| 574 |
+
size_t headerItemStart = pgn.find('"', headerKeyEnd)+1;
|
| 575 |
+
size_t headerItemEnd = pgn.find('"', headerItemStart);
|
| 576 |
+
|
| 577 |
+
// put item into list
|
| 578 |
+
game.header[pgn.substr(headerKeyStart, headerKeyEnd-headerKeyStart)] = pgn.substr(headerItemStart, headerItemEnd-headerItemStart);
|
| 579 |
+
}
|
| 580 |
+
else {
|
| 581 |
+
if (!headersParsed) {
|
| 582 |
+
headersParsed = true;
|
| 583 |
+
auto it = game.header.find("Variant");
|
| 584 |
+
if (it != game.header.end()) {
|
| 585 |
+
game.is960 = it->second.find("960", it->second.size() - 3) != std::string::npos;
|
| 586 |
+
if (game.is960) {
|
| 587 |
+
game.variant = it->second.substr(0, it->second.size() - 3);
|
| 588 |
+
} else {
|
| 589 |
+
game.variant = it->second;
|
| 590 |
+
}
|
| 591 |
+
std::transform(game.variant.begin(), game.variant.end(), game.variant.begin(),
|
| 592 |
+
[](unsigned char c){ return std::tolower(c); });
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
it = game.header.find("FEN");
|
| 596 |
+
if (it != game.header.end())
|
| 597 |
+
game.fen = it->second;
|
| 598 |
+
|
| 599 |
+
game.board = std::make_unique<Board>(game.variant, game.fen, game.is960);
|
| 600 |
+
game.parsedGame = true;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
// game line
|
| 604 |
+
size_t curIdx = lineStart;
|
| 605 |
+
while (curIdx <= lineEnd) {
|
| 606 |
+
if (pgn[curIdx] == '*')
|
| 607 |
+
return game;
|
| 608 |
+
|
| 609 |
+
if (pgn[curIdx] == '{') {
|
| 610 |
+
if (!skip_comment(pgn, curIdx, lineEnd))
|
| 611 |
+
return game;
|
| 612 |
+
++curIdx;
|
| 613 |
+
}
|
| 614 |
+
|
| 615 |
+
// Movetext RAV (Recursive Annotation Variation)
|
| 616 |
+
size_t openedRAV = 0;
|
| 617 |
+
if (pgn[curIdx] == '(') {
|
| 618 |
+
openedRAV = 1;
|
| 619 |
+
++curIdx;
|
| 620 |
+
}
|
| 621 |
+
while (openedRAV != 0) {
|
| 622 |
+
switch (pgn[curIdx]) {
|
| 623 |
+
case '(':
|
| 624 |
+
++openedRAV;
|
| 625 |
+
break;
|
| 626 |
+
case ')':
|
| 627 |
+
--openedRAV;
|
| 628 |
+
break;
|
| 629 |
+
case '{':
|
| 630 |
+
if (!skip_comment(pgn, curIdx, lineEnd))
|
| 631 |
+
return game;
|
| 632 |
+
default: ; // pass
|
| 633 |
+
}
|
| 634 |
+
++curIdx;
|
| 635 |
+
if (curIdx > lineEnd)
|
| 636 |
+
lineEnd = pgn.find('\n', curIdx);
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
if (pgn[curIdx] == '$') {
|
| 640 |
+
// we are at a glyph
|
| 641 |
+
curIdx = pgn.find(' ', curIdx);
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
if (pgn[curIdx] >= '0' && pgn[curIdx] <= '9') {
|
| 645 |
+
// we are at a move number -> look for next point
|
| 646 |
+
curIdx = pgn.find('.', curIdx);
|
| 647 |
+
if (curIdx == std::string::npos)
|
| 648 |
+
break;
|
| 649 |
+
++curIdx;
|
| 650 |
+
// increment if we're at a space
|
| 651 |
+
while (curIdx < pgn.size() && pgn[curIdx] == ' ')
|
| 652 |
+
++curIdx;
|
| 653 |
+
// increment if we're at a point
|
| 654 |
+
while (curIdx < pgn.size() && pgn[curIdx] == '.')
|
| 655 |
+
++curIdx;
|
| 656 |
+
}
|
| 657 |
+
// extract sanMove
|
| 658 |
+
size_t sanMoveEnd = std::min(pgn.find(' ', curIdx), lineEnd);
|
| 659 |
+
if (sanMoveEnd > curIdx) {
|
| 660 |
+
std::string sanMove = pgn.substr(curIdx, sanMoveEnd-curIdx);
|
| 661 |
+
// clean possible ? and ! from string
|
| 662 |
+
size_t annotationChar1 = sanMove.find('?');
|
| 663 |
+
size_t annotationChar2 = sanMove.find('!');
|
| 664 |
+
if (annotationChar1 != std::string::npos || annotationChar2 != std::string::npos)
|
| 665 |
+
sanMove = sanMove.substr(0, std::min(annotationChar1, annotationChar2));
|
| 666 |
+
std::cout << sanMove << " ";
|
| 667 |
+
game.board->push_san(sanMove);
|
| 668 |
+
}
|
| 669 |
+
curIdx = sanMoveEnd+1;
|
| 670 |
+
}
|
| 671 |
+
}
|
| 672 |
+
lineStart = lineEnd+1;
|
| 673 |
+
|
| 674 |
+
if (lineStart >= pgn.size())
|
| 675 |
+
return game;
|
| 676 |
+
}
|
| 677 |
+
return game;
|
| 678 |
+
}
|
| 679 |
+
|
| 680 |
+
|
| 681 |
+
// binding code
|
| 682 |
+
EMSCRIPTEN_BINDINGS(ffish_js) {
|
| 683 |
+
class_<Board>("Board")
|
| 684 |
+
.constructor<>()
|
| 685 |
+
.constructor<std::string>()
|
| 686 |
+
.constructor<std::string, std::string>()
|
| 687 |
+
.constructor<std::string, std::string, bool>()
|
| 688 |
+
.function("legalMoves", &Board::legal_moves)
|
| 689 |
+
.function("legalMovesSan", &Board::legal_moves_san)
|
| 690 |
+
.function("numberLegalMoves", &Board::number_legal_moves)
|
| 691 |
+
.function("push", &Board::push)
|
| 692 |
+
.function("pushSan", select_overload<bool(std::string)>(&Board::push_san))
|
| 693 |
+
.function("pushSan", select_overload<bool(std::string, Notation)>(&Board::push_san))
|
| 694 |
+
.function("pop", &Board::pop)
|
| 695 |
+
.function("reset", &Board::reset)
|
| 696 |
+
.function("is960", &Board::is_960)
|
| 697 |
+
.function("fen", select_overload<std::string()const>(&Board::fen))
|
| 698 |
+
.function("fen", select_overload<std::string(bool)const>(&Board::fen))
|
| 699 |
+
.function("fen", select_overload<std::string(bool, int)const>(&Board::fen))
|
| 700 |
+
.function("setFen", &Board::set_fen)
|
| 701 |
+
.function("sanMove", select_overload<std::string(std::string)>(&Board::san_move))
|
| 702 |
+
.function("sanMove", select_overload<std::string(std::string, Notation)>(&Board::san_move))
|
| 703 |
+
.function("variationSan", select_overload<std::string(std::string)>(&Board::variation_san))
|
| 704 |
+
.function("variationSan", select_overload<std::string(std::string, Notation)>(&Board::variation_san))
|
| 705 |
+
.function("variationSan", select_overload<std::string(std::string, Notation, bool)>(&Board::variation_san))
|
| 706 |
+
.function("turn", &Board::turn)
|
| 707 |
+
.function("fullmoveNumber", &Board::fullmove_number)
|
| 708 |
+
.function("halfmoveClock", &Board::halfmove_clock)
|
| 709 |
+
.function("gamePly", &Board::game_ply)
|
| 710 |
+
.function("hasInsufficientMaterial", &Board::has_insufficient_material)
|
| 711 |
+
.function("isInsufficientMaterial", &Board::is_insufficient_material)
|
| 712 |
+
.function("isGameOver", select_overload<bool() const>(&Board::is_game_over))
|
| 713 |
+
.function("isGameOver", select_overload<bool(bool) const>(&Board::is_game_over))
|
| 714 |
+
.function("result", select_overload<std::string() const>(&Board::result))
|
| 715 |
+
.function("result", select_overload<std::string(bool) const>(&Board::result))
|
| 716 |
+
.function("checkedPieces", &Board::checked_pieces)
|
| 717 |
+
.function("isCheck", &Board::is_check)
|
| 718 |
+
.function("isBikjang", &Board::is_bikjang)
|
| 719 |
+
.function("isCapture", &Board::is_capture)
|
| 720 |
+
.function("moveStack", &Board::move_stack)
|
| 721 |
+
.function("pushMoves", &Board::push_moves)
|
| 722 |
+
.function("pushSanMoves", select_overload<void(std::string)>(&Board::push_san_moves))
|
| 723 |
+
.function("pushSanMoves", select_overload<void(std::string, Notation)>(&Board::push_san_moves))
|
| 724 |
+
.function("pocket", &Board::pocket)
|
| 725 |
+
.function("toString", &Board::to_string)
|
| 726 |
+
.function("toVerboseString", &Board::to_verbose_string)
|
| 727 |
+
.function("variant", &Board::variant);
|
| 728 |
+
class_<Game>("Game")
|
| 729 |
+
.function("headerKeys", &Game::header_keys)
|
| 730 |
+
.function("headers", &Game::headers)
|
| 731 |
+
.function("mainlineMoves", &Game::mainline_moves);
|
| 732 |
+
// usage: e.g. ffish.Notation.DEFAULT
|
| 733 |
+
enum_<Notation>("Notation")
|
| 734 |
+
.value("DEFAULT", NOTATION_DEFAULT)
|
| 735 |
+
.value("SAN", NOTATION_SAN)
|
| 736 |
+
.value("LAN", NOTATION_LAN)
|
| 737 |
+
.value("SHOGI_HOSKING", NOTATION_SHOGI_HOSKING)
|
| 738 |
+
.value("SHOGI_HODGES", NOTATION_SHOGI_HODGES)
|
| 739 |
+
.value("SHOGI_HODGES_NUMBER", NOTATION_SHOGI_HODGES_NUMBER)
|
| 740 |
+
.value("JANGGI", NOTATION_JANGGI)
|
| 741 |
+
.value("XIANGQI_WXF", NOTATION_XIANGQI_WXF)
|
| 742 |
+
.value("THAI_SAN", NOTATION_THAI_SAN)
|
| 743 |
+
.value("THAI_LAN", NOTATION_THAI_LAN);
|
| 744 |
+
// usage: e.g. ffish.Termination.CHECKMATE
|
| 745 |
+
enum_<Termination>("Termination")
|
| 746 |
+
.value("ONGOING", ONGOING)
|
| 747 |
+
.value("CHECKMATE", CHECKMATE)
|
| 748 |
+
.value("STALEMATE", STALEMATE)
|
| 749 |
+
.value("INSUFFICIENT_MATERIAL", INSUFFICIENT_MATERIAL)
|
| 750 |
+
.value("N_MOVE_RULE", N_MOVE_RULE)
|
| 751 |
+
.value("N_FOLD_REPETITION", N_FOLD_REPETITION)
|
| 752 |
+
.value("VARIANT_END", VARIANT_END);
|
| 753 |
+
function("info", &ffish::info);
|
| 754 |
+
function("setOption", &ffish::set_option<std::string>);
|
| 755 |
+
function("setOptionInt", &ffish::set_option<int>);
|
| 756 |
+
function("setOptionBool", &ffish::set_option<bool>);
|
| 757 |
+
function("readGamePGN", &read_game_pgn);
|
| 758 |
+
function("variants", &ffish::available_variants);
|
| 759 |
+
function("loadVariantConfig", &ffish::load_variant_config);
|
| 760 |
+
function("capturesToHand", &ffish::captures_to_hand);
|
| 761 |
+
function("startingFen", &ffish::starting_fen);
|
| 762 |
+
function("validateFen", select_overload<int(std::string)>(&ffish::validate_fen));
|
| 763 |
+
function("validateFen", select_overload<int(std::string, std::string)>(&ffish::validate_fen));
|
| 764 |
+
function("validateFen", select_overload<int(std::string, std::string, bool)>(&ffish::validate_fen));
|
| 765 |
+
// TODO: enable to string conversion method
|
| 766 |
+
// .class_function("getStringFromInstance", &Board::get_string_from_instance);
|
| 767 |
+
}
|
Fairy-Stockfish-master/src/incbin/UNLICENCE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The file "incbin.h" is free and unencumbered software released into
|
| 2 |
+
the public domain by Dale Weiler, see:
|
| 3 |
+
<https://github.com/graphitemaster/incbin>
|
| 4 |
+
|
| 5 |
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
| 6 |
+
distribute this software, either in source code form or as a compiled
|
| 7 |
+
binary, for any purpose, commercial or non-commercial, and by any
|
| 8 |
+
means.
|
| 9 |
+
|
| 10 |
+
In jurisdictions that recognize copyright laws, the author or authors
|
| 11 |
+
of this software dedicate any and all copyright interest in the
|
| 12 |
+
software to the public domain. We make this dedication for the benefit
|
| 13 |
+
of the public at large and to the detriment of our heirs and
|
| 14 |
+
successors. We intend this dedication to be an overt act of
|
| 15 |
+
relinquishment in perpetuity of all present and future rights to this
|
| 16 |
+
software under copyright law.
|
| 17 |
+
|
| 18 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 19 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 20 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
| 21 |
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 22 |
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 23 |
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 24 |
+
OTHER DEALINGS IN THE SOFTWARE.
|
| 25 |
+
|
| 26 |
+
For more information, please refer to <http://unlicense.org/>
|
Fairy-Stockfish-master/src/incbin/incbin.h
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* @file incbin.h
|
| 3 |
+
* @author Dale Weiler
|
| 4 |
+
* @brief Utility for including binary files
|
| 5 |
+
*
|
| 6 |
+
* Facilities for including binary files into the current translation unit and
|
| 7 |
+
* making use from them externally in other translation units.
|
| 8 |
+
*/
|
| 9 |
+
#ifndef INCBIN_HDR
|
| 10 |
+
#define INCBIN_HDR
|
| 11 |
+
#include <limits.h>
|
| 12 |
+
#if defined(__AVX512BW__) || \
|
| 13 |
+
defined(__AVX512CD__) || \
|
| 14 |
+
defined(__AVX512DQ__) || \
|
| 15 |
+
defined(__AVX512ER__) || \
|
| 16 |
+
defined(__AVX512PF__) || \
|
| 17 |
+
defined(__AVX512VL__) || \
|
| 18 |
+
defined(__AVX512F__)
|
| 19 |
+
# define INCBIN_ALIGNMENT_INDEX 6
|
| 20 |
+
#elif defined(__AVX__) || \
|
| 21 |
+
defined(__AVX2__)
|
| 22 |
+
# define INCBIN_ALIGNMENT_INDEX 5
|
| 23 |
+
#elif defined(__SSE__) || \
|
| 24 |
+
defined(__SSE2__) || \
|
| 25 |
+
defined(__SSE3__) || \
|
| 26 |
+
defined(__SSSE3__) || \
|
| 27 |
+
defined(__SSE4_1__) || \
|
| 28 |
+
defined(__SSE4_2__) || \
|
| 29 |
+
defined(__neon__)
|
| 30 |
+
# define INCBIN_ALIGNMENT_INDEX 4
|
| 31 |
+
#elif ULONG_MAX != 0xffffffffu
|
| 32 |
+
# define INCBIN_ALIGNMENT_INDEX 3
|
| 33 |
+
# else
|
| 34 |
+
# define INCBIN_ALIGNMENT_INDEX 2
|
| 35 |
+
#endif
|
| 36 |
+
|
| 37 |
+
/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */
|
| 38 |
+
#define INCBIN_ALIGN_SHIFT_0 1
|
| 39 |
+
#define INCBIN_ALIGN_SHIFT_1 2
|
| 40 |
+
#define INCBIN_ALIGN_SHIFT_2 4
|
| 41 |
+
#define INCBIN_ALIGN_SHIFT_3 8
|
| 42 |
+
#define INCBIN_ALIGN_SHIFT_4 16
|
| 43 |
+
#define INCBIN_ALIGN_SHIFT_5 32
|
| 44 |
+
#define INCBIN_ALIGN_SHIFT_6 64
|
| 45 |
+
|
| 46 |
+
/* Actual alignment value */
|
| 47 |
+
#define INCBIN_ALIGNMENT \
|
| 48 |
+
INCBIN_CONCATENATE( \
|
| 49 |
+
INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \
|
| 50 |
+
INCBIN_ALIGNMENT_INDEX)
|
| 51 |
+
|
| 52 |
+
/* Stringize */
|
| 53 |
+
#define INCBIN_STR(X) \
|
| 54 |
+
#X
|
| 55 |
+
#define INCBIN_STRINGIZE(X) \
|
| 56 |
+
INCBIN_STR(X)
|
| 57 |
+
/* Concatenate */
|
| 58 |
+
#define INCBIN_CAT(X, Y) \
|
| 59 |
+
X ## Y
|
| 60 |
+
#define INCBIN_CONCATENATE(X, Y) \
|
| 61 |
+
INCBIN_CAT(X, Y)
|
| 62 |
+
/* Deferred macro expansion */
|
| 63 |
+
#define INCBIN_EVAL(X) \
|
| 64 |
+
X
|
| 65 |
+
#define INCBIN_INVOKE(N, ...) \
|
| 66 |
+
INCBIN_EVAL(N(__VA_ARGS__))
|
| 67 |
+
|
| 68 |
+
/* Green Hills uses a different directive for including binary data */
|
| 69 |
+
#if defined(__ghs__)
|
| 70 |
+
# if (__ghs_asm == 2)
|
| 71 |
+
# define INCBIN_MACRO ".file"
|
| 72 |
+
/* Or consider the ".myrawdata" entry in the ld file */
|
| 73 |
+
# else
|
| 74 |
+
# define INCBIN_MACRO "\tINCBIN"
|
| 75 |
+
# endif
|
| 76 |
+
#else
|
| 77 |
+
# define INCBIN_MACRO ".incbin"
|
| 78 |
+
#endif
|
| 79 |
+
|
| 80 |
+
#ifndef _MSC_VER
|
| 81 |
+
# define INCBIN_ALIGN \
|
| 82 |
+
__attribute__((aligned(INCBIN_ALIGNMENT)))
|
| 83 |
+
#else
|
| 84 |
+
# define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT))
|
| 85 |
+
#endif
|
| 86 |
+
|
| 87 |
+
#if defined(__arm__) || /* GNU C and RealView */ \
|
| 88 |
+
defined(__arm) || /* Diab */ \
|
| 89 |
+
defined(_ARM) /* ImageCraft */
|
| 90 |
+
# define INCBIN_ARM
|
| 91 |
+
#endif
|
| 92 |
+
|
| 93 |
+
#ifdef __GNUC__
|
| 94 |
+
/* Utilize .balign where supported */
|
| 95 |
+
# define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
|
| 96 |
+
# define INCBIN_ALIGN_BYTE ".balign 1\n"
|
| 97 |
+
#elif defined(INCBIN_ARM)
|
| 98 |
+
/*
|
| 99 |
+
* On arm assemblers, the alignment value is calculated as (1 << n) where `n' is
|
| 100 |
+
* the shift count. This is the value passed to `.align'
|
| 101 |
+
*/
|
| 102 |
+
# define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n"
|
| 103 |
+
# define INCBIN_ALIGN_BYTE ".align 0\n"
|
| 104 |
+
#else
|
| 105 |
+
/* We assume other inline assembler's treat `.align' as `.balign' */
|
| 106 |
+
# define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
|
| 107 |
+
# define INCBIN_ALIGN_BYTE ".align 1\n"
|
| 108 |
+
#endif
|
| 109 |
+
|
| 110 |
+
/* INCBIN_CONST is used by incbin.c generated files */
|
| 111 |
+
#if defined(__cplusplus)
|
| 112 |
+
# define INCBIN_EXTERNAL extern "C"
|
| 113 |
+
# define INCBIN_CONST extern const
|
| 114 |
+
#else
|
| 115 |
+
# define INCBIN_EXTERNAL extern
|
| 116 |
+
# define INCBIN_CONST const
|
| 117 |
+
#endif
|
| 118 |
+
|
| 119 |
+
/**
|
| 120 |
+
* @brief Optionally override the linker section into which data is emitted.
|
| 121 |
+
*
|
| 122 |
+
* @warning If you use this facility, you'll have to deal with platform-specific linker output
|
| 123 |
+
* section naming on your own
|
| 124 |
+
*
|
| 125 |
+
* Overriding the default linker output section, e.g for esp8266/Arduino:
|
| 126 |
+
* @code
|
| 127 |
+
* #define INCBIN_OUTPUT_SECTION ".irom.text"
|
| 128 |
+
* #include "incbin.h"
|
| 129 |
+
* INCBIN(Foo, "foo.txt");
|
| 130 |
+
* // Data is emitted into program memory that never gets copied to RAM
|
| 131 |
+
* @endcode
|
| 132 |
+
*/
|
| 133 |
+
#if !defined(INCBIN_OUTPUT_SECTION)
|
| 134 |
+
# if defined(__APPLE__)
|
| 135 |
+
# define INCBIN_OUTPUT_SECTION ".const_data"
|
| 136 |
+
# else
|
| 137 |
+
# define INCBIN_OUTPUT_SECTION ".rodata"
|
| 138 |
+
# endif
|
| 139 |
+
#endif
|
| 140 |
+
|
| 141 |
+
#if defined(__APPLE__)
|
| 142 |
+
/* The directives are different for Apple branded compilers */
|
| 143 |
+
# define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n"
|
| 144 |
+
# define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
|
| 145 |
+
# define INCBIN_INT ".long "
|
| 146 |
+
# define INCBIN_MANGLE "_"
|
| 147 |
+
# define INCBIN_BYTE ".byte "
|
| 148 |
+
# define INCBIN_TYPE(...)
|
| 149 |
+
#else
|
| 150 |
+
# define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n"
|
| 151 |
+
# define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
|
| 152 |
+
# if defined(__ghs__)
|
| 153 |
+
# define INCBIN_INT ".word "
|
| 154 |
+
# else
|
| 155 |
+
# define INCBIN_INT ".int "
|
| 156 |
+
# endif
|
| 157 |
+
# if defined(__USER_LABEL_PREFIX__)
|
| 158 |
+
# define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__)
|
| 159 |
+
# else
|
| 160 |
+
# define INCBIN_MANGLE ""
|
| 161 |
+
# endif
|
| 162 |
+
# if defined(INCBIN_ARM)
|
| 163 |
+
/* On arm assemblers, `@' is used as a line comment token */
|
| 164 |
+
# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n"
|
| 165 |
+
# elif defined(__MINGW32__) || defined(__MINGW64__)
|
| 166 |
+
/* Mingw doesn't support this directive either */
|
| 167 |
+
# define INCBIN_TYPE(NAME)
|
| 168 |
+
# else
|
| 169 |
+
/* It's safe to use `@' on other architectures */
|
| 170 |
+
# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"
|
| 171 |
+
# endif
|
| 172 |
+
# define INCBIN_BYTE ".byte "
|
| 173 |
+
#endif
|
| 174 |
+
|
| 175 |
+
/* List of style types used for symbol names */
|
| 176 |
+
#define INCBIN_STYLE_CAMEL 0
|
| 177 |
+
#define INCBIN_STYLE_SNAKE 1
|
| 178 |
+
|
| 179 |
+
/**
|
| 180 |
+
* @brief Specify the prefix to use for symbol names.
|
| 181 |
+
*
|
| 182 |
+
* By default this is `g', producing symbols of the form:
|
| 183 |
+
* @code
|
| 184 |
+
* #include "incbin.h"
|
| 185 |
+
* INCBIN(Foo, "foo.txt");
|
| 186 |
+
*
|
| 187 |
+
* // Now you have the following symbols:
|
| 188 |
+
* // const unsigned char gFooData[];
|
| 189 |
+
* // const unsigned char *const gFooEnd;
|
| 190 |
+
* // const unsigned int gFooSize;
|
| 191 |
+
* @endcode
|
| 192 |
+
*
|
| 193 |
+
* If however you specify a prefix before including: e.g:
|
| 194 |
+
* @code
|
| 195 |
+
* #define INCBIN_PREFIX incbin
|
| 196 |
+
* #include "incbin.h"
|
| 197 |
+
* INCBIN(Foo, "foo.txt");
|
| 198 |
+
*
|
| 199 |
+
* // Now you have the following symbols instead:
|
| 200 |
+
* // const unsigned char incbinFooData[];
|
| 201 |
+
* // const unsigned char *const incbinFooEnd;
|
| 202 |
+
* // const unsigned int incbinFooSize;
|
| 203 |
+
* @endcode
|
| 204 |
+
*/
|
| 205 |
+
#if !defined(INCBIN_PREFIX)
|
| 206 |
+
# define INCBIN_PREFIX g
|
| 207 |
+
#endif
|
| 208 |
+
|
| 209 |
+
/**
|
| 210 |
+
* @brief Specify the style used for symbol names.
|
| 211 |
+
*
|
| 212 |
+
* Possible options are
|
| 213 |
+
* - INCBIN_STYLE_CAMEL "CamelCase"
|
| 214 |
+
* - INCBIN_STYLE_SNAKE "snake_case"
|
| 215 |
+
*
|
| 216 |
+
* Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:
|
| 217 |
+
* @code
|
| 218 |
+
* #include "incbin.h"
|
| 219 |
+
* INCBIN(Foo, "foo.txt");
|
| 220 |
+
*
|
| 221 |
+
* // Now you have the following symbols:
|
| 222 |
+
* // const unsigned char <prefix>FooData[];
|
| 223 |
+
* // const unsigned char *const <prefix>FooEnd;
|
| 224 |
+
* // const unsigned int <prefix>FooSize;
|
| 225 |
+
* @endcode
|
| 226 |
+
*
|
| 227 |
+
* If however you specify a style before including: e.g:
|
| 228 |
+
* @code
|
| 229 |
+
* #define INCBIN_STYLE INCBIN_STYLE_SNAKE
|
| 230 |
+
* #include "incbin.h"
|
| 231 |
+
* INCBIN(foo, "foo.txt");
|
| 232 |
+
*
|
| 233 |
+
* // Now you have the following symbols:
|
| 234 |
+
* // const unsigned char <prefix>foo_data[];
|
| 235 |
+
* // const unsigned char *const <prefix>foo_end;
|
| 236 |
+
* // const unsigned int <prefix>foo_size;
|
| 237 |
+
* @endcode
|
| 238 |
+
*/
|
| 239 |
+
#if !defined(INCBIN_STYLE)
|
| 240 |
+
# define INCBIN_STYLE INCBIN_STYLE_CAMEL
|
| 241 |
+
#endif
|
| 242 |
+
|
| 243 |
+
/* Style lookup tables */
|
| 244 |
+
#define INCBIN_STYLE_0_DATA Data
|
| 245 |
+
#define INCBIN_STYLE_0_END End
|
| 246 |
+
#define INCBIN_STYLE_0_SIZE Size
|
| 247 |
+
#define INCBIN_STYLE_1_DATA _data
|
| 248 |
+
#define INCBIN_STYLE_1_END _end
|
| 249 |
+
#define INCBIN_STYLE_1_SIZE _size
|
| 250 |
+
|
| 251 |
+
/* Style lookup: returning identifier */
|
| 252 |
+
#define INCBIN_STYLE_IDENT(TYPE) \
|
| 253 |
+
INCBIN_CONCATENATE( \
|
| 254 |
+
INCBIN_STYLE_, \
|
| 255 |
+
INCBIN_CONCATENATE( \
|
| 256 |
+
INCBIN_EVAL(INCBIN_STYLE), \
|
| 257 |
+
INCBIN_CONCATENATE(_, TYPE)))
|
| 258 |
+
|
| 259 |
+
/* Style lookup: returning string literal */
|
| 260 |
+
#define INCBIN_STYLE_STRING(TYPE) \
|
| 261 |
+
INCBIN_STRINGIZE( \
|
| 262 |
+
INCBIN_STYLE_IDENT(TYPE)) \
|
| 263 |
+
|
| 264 |
+
/* Generate the global labels by indirectly invoking the macro with our style
|
| 265 |
+
* type and concatenating the name against them. */
|
| 266 |
+
#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
|
| 267 |
+
INCBIN_INVOKE( \
|
| 268 |
+
INCBIN_GLOBAL, \
|
| 269 |
+
INCBIN_CONCATENATE( \
|
| 270 |
+
NAME, \
|
| 271 |
+
INCBIN_INVOKE( \
|
| 272 |
+
INCBIN_STYLE_IDENT, \
|
| 273 |
+
TYPE))) \
|
| 274 |
+
INCBIN_INVOKE( \
|
| 275 |
+
INCBIN_TYPE, \
|
| 276 |
+
INCBIN_CONCATENATE( \
|
| 277 |
+
NAME, \
|
| 278 |
+
INCBIN_INVOKE( \
|
| 279 |
+
INCBIN_STYLE_IDENT, \
|
| 280 |
+
TYPE)))
|
| 281 |
+
|
| 282 |
+
/**
|
| 283 |
+
* @brief Externally reference binary data included in another translation unit.
|
| 284 |
+
*
|
| 285 |
+
* Produces three external symbols that reference the binary data included in
|
| 286 |
+
* another translation unit.
|
| 287 |
+
*
|
| 288 |
+
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
|
| 289 |
+
* "Data", as well as "End" and "Size" after. An example is provided below.
|
| 290 |
+
*
|
| 291 |
+
* @param NAME The name given for the binary data
|
| 292 |
+
*
|
| 293 |
+
* @code
|
| 294 |
+
* INCBIN_EXTERN(Foo);
|
| 295 |
+
*
|
| 296 |
+
* // Now you have the following symbols:
|
| 297 |
+
* // extern const unsigned char <prefix>FooData[];
|
| 298 |
+
* // extern const unsigned char *const <prefix>FooEnd;
|
| 299 |
+
* // extern const unsigned int <prefix>FooSize;
|
| 300 |
+
* @endcode
|
| 301 |
+
*/
|
| 302 |
+
#define INCBIN_EXTERN(NAME) \
|
| 303 |
+
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \
|
| 304 |
+
INCBIN_CONCATENATE( \
|
| 305 |
+
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
|
| 306 |
+
INCBIN_STYLE_IDENT(DATA))[]; \
|
| 307 |
+
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \
|
| 308 |
+
INCBIN_CONCATENATE( \
|
| 309 |
+
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
|
| 310 |
+
INCBIN_STYLE_IDENT(END)); \
|
| 311 |
+
INCBIN_EXTERNAL const unsigned int \
|
| 312 |
+
INCBIN_CONCATENATE( \
|
| 313 |
+
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
|
| 314 |
+
INCBIN_STYLE_IDENT(SIZE))
|
| 315 |
+
|
| 316 |
+
/**
|
| 317 |
+
* @brief Include a binary file into the current translation unit.
|
| 318 |
+
*
|
| 319 |
+
* Includes a binary file into the current translation unit, producing three symbols
|
| 320 |
+
* for objects that encode the data and size respectively.
|
| 321 |
+
*
|
| 322 |
+
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
|
| 323 |
+
* "Data", as well as "End" and "Size" after. An example is provided below.
|
| 324 |
+
*
|
| 325 |
+
* @param NAME The name to associate with this binary data (as an identifier.)
|
| 326 |
+
* @param FILENAME The file to include (as a string literal.)
|
| 327 |
+
*
|
| 328 |
+
* @code
|
| 329 |
+
* INCBIN(Icon, "icon.png");
|
| 330 |
+
*
|
| 331 |
+
* // Now you have the following symbols:
|
| 332 |
+
* // const unsigned char <prefix>IconData[];
|
| 333 |
+
* // const unsigned char *const <prefix>IconEnd;
|
| 334 |
+
* // const unsigned int <prefix>IconSize;
|
| 335 |
+
* @endcode
|
| 336 |
+
*
|
| 337 |
+
* @warning This must be used in global scope
|
| 338 |
+
* @warning The identifiers may be different if INCBIN_STYLE is not default
|
| 339 |
+
*
|
| 340 |
+
* To externally reference the data included by this in another translation unit
|
| 341 |
+
* please @see INCBIN_EXTERN.
|
| 342 |
+
*/
|
| 343 |
+
#ifdef _MSC_VER
|
| 344 |
+
#define INCBIN(NAME, FILENAME) \
|
| 345 |
+
INCBIN_EXTERN(NAME)
|
| 346 |
+
#else
|
| 347 |
+
#define INCBIN(NAME, FILENAME) \
|
| 348 |
+
__asm__(INCBIN_SECTION \
|
| 349 |
+
INCBIN_GLOBAL_LABELS(NAME, DATA) \
|
| 350 |
+
INCBIN_ALIGN_HOST \
|
| 351 |
+
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
|
| 352 |
+
INCBIN_MACRO " \"" FILENAME "\"\n" \
|
| 353 |
+
INCBIN_GLOBAL_LABELS(NAME, END) \
|
| 354 |
+
INCBIN_ALIGN_BYTE \
|
| 355 |
+
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
|
| 356 |
+
INCBIN_BYTE "1\n" \
|
| 357 |
+
INCBIN_GLOBAL_LABELS(NAME, SIZE) \
|
| 358 |
+
INCBIN_ALIGN_HOST \
|
| 359 |
+
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \
|
| 360 |
+
INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \
|
| 361 |
+
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \
|
| 362 |
+
INCBIN_ALIGN_HOST \
|
| 363 |
+
".text\n" \
|
| 364 |
+
); \
|
| 365 |
+
INCBIN_EXTERN(NAME)
|
| 366 |
+
|
| 367 |
+
#endif
|
| 368 |
+
#endif
|
Fairy-Stockfish-master/src/magic.h
ADDED
|
@@ -0,0 +1,1741 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
|
| 3 |
+
Copyright (C) 2018-2022 Fabian Fichter
|
| 4 |
+
|
| 5 |
+
Fairy-Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Fairy-Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef MAGIC_H_INCLUDED
|
| 20 |
+
#define MAGIC_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
namespace Stockfish {
|
| 23 |
+
|
| 24 |
+
#ifdef PRECOMPUTED_MAGICS
|
| 25 |
+
#define B(a, b) (Bitboard(a) << 64) ^ Bitboard(b)
|
| 26 |
+
// Use precomputed magics if pext is not available,
|
| 27 |
+
// since the magics generation is very slow.
|
| 28 |
+
constexpr Bitboard RookMagicHInit[SQUARE_NB] = {
|
| 29 |
+
B(0x120000880110000, 0x1008000000020020),
|
| 30 |
+
B(0x24200C080840A052, 0x2004004000010008),
|
| 31 |
+
B(0xC030024000228800, 0x4000010400000020),
|
| 32 |
+
B(0x1A0020802008802, 0x206010208000),
|
| 33 |
+
B(0x12002000D001024, 0x80100800090138),
|
| 34 |
+
B(0x4220010000241010, 0x3098000602001500),
|
| 35 |
+
B(0x401010004801040, 0x8000280480100000),
|
| 36 |
+
B(0x820082024921836, 0x220028000),
|
| 37 |
+
B(0x100400502411400, 0x220402120240D14),
|
| 38 |
+
B(0x880202020010404, 0xA80202510000),
|
| 39 |
+
B(0x140002801000018, 0x1000346490040),
|
| 40 |
+
B(0x120000880110000, 0x1008000000020020),
|
| 41 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 42 |
+
B(0x8420060100020000, 0x800280400000120),
|
| 43 |
+
B(0x4010020018010, 0x40A00001100000),
|
| 44 |
+
B(0x40006A0004000200, 0x40000000110),
|
| 45 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 46 |
+
B(0x8908A20028110011, 0x800080000001A114),
|
| 47 |
+
B(0x200042000080F009, 0x20001000004000),
|
| 48 |
+
B(0x2820008820100, 0x10002400058000B9),
|
| 49 |
+
B(0x6083100420008050, 0x4040012600280080),
|
| 50 |
+
B(0x216020000000446, 0x4080204000000211),
|
| 51 |
+
B(0x340140003002089, 0x2402008000000911),
|
| 52 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 53 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 54 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 55 |
+
B(0x1010000060050000, 0x4000004050002602),
|
| 56 |
+
B(0x4022983A0060000, 0x80000040010400),
|
| 57 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 58 |
+
B(0x6020101802002840, 0x31000003000004),
|
| 59 |
+
B(0x9000420008840, 0x4881300000000210),
|
| 60 |
+
B(0xA200808865, 0x41C0048023000128),
|
| 61 |
+
B(0x31801100400000, 0x8802DC001221240),
|
| 62 |
+
B(0x884000080200920, 0x1004002410401001),
|
| 63 |
+
B(0x2400040000884, 0x421006208040C0),
|
| 64 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 65 |
+
B(0x24100400060009, 0x112008025042410),
|
| 66 |
+
B(0x1800040009040200, 0x180000A1004E408A),
|
| 67 |
+
B(0x24100400060009, 0x112008025042410),
|
| 68 |
+
B(0x4060402008080, 0xC240080000110000),
|
| 69 |
+
B(0x20080100920020, 0x2002248010242052),
|
| 70 |
+
B(0x10001010802050, 0x880000001C98420),
|
| 71 |
+
B(0x4000800100420022, 0x502022010A00D0),
|
| 72 |
+
B(0x4C18104500200885, 0x400880800),
|
| 73 |
+
B(0x8080810081020090, 0x8000000000000),
|
| 74 |
+
B(0x8000062812080201, 0x8004C8300800),
|
| 75 |
+
B(0xC010220920198, 0x85000A08000),
|
| 76 |
+
B(0x24100400060009, 0x112008025042410),
|
| 77 |
+
B(0x80102204040, 0x1000000900000000),
|
| 78 |
+
B(0x2080000004202804, 0x120880003461),
|
| 79 |
+
B(0x102004090A4030, 0x801020589240),
|
| 80 |
+
B(0x20001100814000A0, 0x420202000820004),
|
| 81 |
+
B(0x100800000A000120, 0x208000800010000),
|
| 82 |
+
B(0x1008205000040802, 0x80002000400040),
|
| 83 |
+
B(0x1480000098008401, 0xA0010000581010),
|
| 84 |
+
B(0x30C0008200100820, 0x102800080904834),
|
| 85 |
+
B(0x4810821884000500, 0x4400000200000212),
|
| 86 |
+
B(0x1811D00128A0180, 0x2500848803000000),
|
| 87 |
+
B(0x41618A0300040040, 0x21200200A421801),
|
| 88 |
+
B(0x80102204040, 0x1000000900000000),
|
| 89 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 90 |
+
B(0x8C890020410000A0, 0xA010000048000400),
|
| 91 |
+
B(0x40006002210044, 0x600008000408000),
|
| 92 |
+
B(0x1200447220090042, 0x80001000160012),
|
| 93 |
+
B(0x48410010AB000000, 0x9200600000000100),
|
| 94 |
+
B(0x2040000000240003, 0x8020080288000600),
|
| 95 |
+
B(0x9080000088848088, 0x4010210500000041),
|
| 96 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 97 |
+
B(0x480100400024, 0x1004800018200000),
|
| 98 |
+
B(0x808403080080200, 0x802601000000500),
|
| 99 |
+
B(0x8C890020410000A0, 0xA010000048000400),
|
| 100 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 101 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 102 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 103 |
+
B(0x400014006000000, 0x10006000810001F5),
|
| 104 |
+
B(0xC410062001414, 0x820080041B01044),
|
| 105 |
+
B(0x20000800310, 0x430040000201000),
|
| 106 |
+
B(0xA40010008000008, 0x4002200028000040),
|
| 107 |
+
B(0xC00102000008021C, 0x10C2000A010E024),
|
| 108 |
+
B(0x80004200104008, 0x50A00800C400020),
|
| 109 |
+
B(0x20200080012542, 0x910F0040000402C0),
|
| 110 |
+
B(0xB040100504000300, 0x24802002000040),
|
| 111 |
+
B(0x800001000014008, 0x400031004000),
|
| 112 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 113 |
+
B(0x84008002041081C0, 0x8080500200000000),
|
| 114 |
+
B(0x440090001012001, 0x4020004010),
|
| 115 |
+
B(0x100A0028088020, 0x80040E00010020),
|
| 116 |
+
B(0x2180808000810, 0xB018040A00040000),
|
| 117 |
+
B(0x40C80920304C4001, 0x42800B200800000),
|
| 118 |
+
B(0x85000425001000, 0x4810048020001100),
|
| 119 |
+
B(0x600C000801000004, 0x8015084010200020),
|
| 120 |
+
B(0x20020050000240C0, 0x100202008600800),
|
| 121 |
+
B(0x38000050001220, 0x9200010200145900),
|
| 122 |
+
B(0x1042108040005, 0x1402A0802201001),
|
| 123 |
+
B(0x824240000C20400, 0x1000000400080010),
|
| 124 |
+
B(0x84008002041081C0, 0x8080500200000000),
|
| 125 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 126 |
+
B(0x8000402308483, 0x20006020100100),
|
| 127 |
+
B(0x80880120000080, 0x8000240100084),
|
| 128 |
+
B(0x5840020004882001, 0x1004528000A00010),
|
| 129 |
+
B(0x8001018800300002, 0x84010040804),
|
| 130 |
+
B(0x180D10004000A008, 0xA001080008020004),
|
| 131 |
+
B(0x400080B, 0x10A0000004010000),
|
| 132 |
+
B(0x8080000200000, 0x2001000082004E0),
|
| 133 |
+
B(0x40040001000C2000, 0x2024800001004008),
|
| 134 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 135 |
+
B(0x8000402308483, 0x20006020100100),
|
| 136 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 137 |
+
B(0x2000200000, 0x1201011000802),
|
| 138 |
+
B(0x100100000000C4, 0x208004084048201),
|
| 139 |
+
B(0x400084000044, 0x100810140300),
|
| 140 |
+
B(0x29040C0C01010, 0x300204010820080),
|
| 141 |
+
B(0x1A808000020200, 0x1000000005210040),
|
| 142 |
+
B(0x20000400150000, 0x85008020),
|
| 143 |
+
B(0x40C040008184014, 0x8002AA00024010),
|
| 144 |
+
B(0x202000081B00804, 0x10001002008),
|
| 145 |
+
B(0x40011000210060, 0x6080C40000021004),
|
| 146 |
+
B(0x2000200000, 0x1201011000802),
|
| 147 |
+
B(0x4100480203840, 0x300080100804),
|
| 148 |
+
B(0x2000200000, 0x1201011000802),
|
| 149 |
+
};
|
| 150 |
+
constexpr Bitboard RookMagicVInit[SQUARE_NB] = {
|
| 151 |
+
B(0x202000812104400, 0x24800B01C0000303),
|
| 152 |
+
B(0x340020400010D, 0x88060150C00400),
|
| 153 |
+
B(0x400802040609, 0x49010200501A0002),
|
| 154 |
+
B(0x8002680301000208, 0x628006C0C020200),
|
| 155 |
+
B(0x20400209001C0804, 0xA044000800143110),
|
| 156 |
+
B(0xC400082060010202, 0x4000480401014000),
|
| 157 |
+
B(0x22500200144040, 0x8204820084704C00),
|
| 158 |
+
B(0x8C1204009030020, 0x328400805000000),
|
| 159 |
+
B(0x84800800D0001640, 0x200080040060108),
|
| 160 |
+
B(0x804810208020040, 0x140010108020000),
|
| 161 |
+
B(0x1102010B008004, 0x300208006220020),
|
| 162 |
+
B(0x140080404A0A2428, 0x6308010100080),
|
| 163 |
+
B(0x20444002120408, 0xA080010508010001),
|
| 164 |
+
B(0x82011044000D02, 0x4112028620110809),
|
| 165 |
+
B(0x81010831000C02, 0x408802085000000),
|
| 166 |
+
B(0x81010831000C02, 0x408802085000000),
|
| 167 |
+
B(0x920008920600040, 0x8053801004000028),
|
| 168 |
+
B(0x81140283208300, 0x10040C004200420),
|
| 169 |
+
B(0x103080022201, 0xC01000081312620),
|
| 170 |
+
B(0x2200221100008, 0x1000408104000A4),
|
| 171 |
+
B(0x4402088080042008, 0x210401501040340),
|
| 172 |
+
B(0x898400202170001, 0x80040404208000),
|
| 173 |
+
B(0x20080004051012, 0x5100048200081800),
|
| 174 |
+
B(0x2320020000401018, 0x108501021040210),
|
| 175 |
+
B(0x21080410A422021, 0x83040180008800),
|
| 176 |
+
B(0x44E8100000408224, 0x20010008040400),
|
| 177 |
+
B(0x1800240002810405, 0x23004820000020),
|
| 178 |
+
B(0x80A0100400110, 0x80104020100C4028),
|
| 179 |
+
B(0x1002050001222C0, 0x5100818004024020),
|
| 180 |
+
B(0x104000200040, 0xC010A09800102000),
|
| 181 |
+
B(0x1020003A058120, 0x450900809000302),
|
| 182 |
+
B(0x40040045008B1, 0x202800400383010),
|
| 183 |
+
B(0x4640200220034, 0x8800485420304000),
|
| 184 |
+
B(0x5001042100084288, 0x110820001240080A),
|
| 185 |
+
B(0x2002C04004010120, 0xA15008020880001),
|
| 186 |
+
B(0x2800004080C4190, 0x890808280020080),
|
| 187 |
+
B(0x40C0401000104000, 0x2020880008002580),
|
| 188 |
+
B(0x40020C002400802, 0x801104010000000),
|
| 189 |
+
B(0x44842000040080, 0x2050011084000400),
|
| 190 |
+
B(0x4110040800000401, 0x2023810029008000),
|
| 191 |
+
B(0x20884000840, 0x8017102004008000),
|
| 192 |
+
B(0x10411104000480, 0x1414042000201001),
|
| 193 |
+
B(0x220040000008, 0x800306021000000),
|
| 194 |
+
B(0x41400A0008080, 0x501000298ACAD10),
|
| 195 |
+
B(0x800240012831810, 0x80120004468050E),
|
| 196 |
+
B(0x800005020801008, 0x20102400240000),
|
| 197 |
+
B(0x20C00040C114C010, 0x88080820200C00),
|
| 198 |
+
B(0x1044010100820081, 0x20080841004000),
|
| 199 |
+
B(0x8041048400022, 0x8020836040005002),
|
| 200 |
+
B(0x2001004010205, 0x8001002884042009),
|
| 201 |
+
B(0x128088400087, 0x20008002201002),
|
| 202 |
+
B(0x8084108040402000, 0x80809000A080400),
|
| 203 |
+
B(0x408081840880, 0x201002088000040),
|
| 204 |
+
B(0xA40180010280, 0x241004006000010),
|
| 205 |
+
B(0x4204100080048140, 0x2002C4F104202020),
|
| 206 |
+
B(0x100140A10204, 0x980200800840060),
|
| 207 |
+
B(0x1005140010202048, 0x1442280800202815),
|
| 208 |
+
B(0x2000082025008600, 0x1108400040600003),
|
| 209 |
+
B(0x1005050648000, 0x200020240008002),
|
| 210 |
+
B(0x202010208044000, 0x8210404060008),
|
| 211 |
+
B(0x8011040402000210, 0xC840180408016004),
|
| 212 |
+
B(0x404098801028, 0x80020A0001000400),
|
| 213 |
+
B(0x404098801028, 0x80020A0001000400),
|
| 214 |
+
B(0x80101002180140, 0x40C2080820000C0),
|
| 215 |
+
B(0x208202081260800, 0x14090E4C04000050),
|
| 216 |
+
B(0x4221201084004C2, 0x110480A011060),
|
| 217 |
+
B(0x8000008421090204, 0x1C01010800024),
|
| 218 |
+
B(0x8000008421090204, 0x1C01010800024),
|
| 219 |
+
B(0x200180C840088A0, 0x401100400820000),
|
| 220 |
+
B(0x10084043A021070, 0x202041600080200),
|
| 221 |
+
B(0x210E6202001040C, 0x10100800080B0),
|
| 222 |
+
B(0x848008021204002, 0x801004308100BAD),
|
| 223 |
+
B(0xC082C0390A000601, 0x4040080189008),
|
| 224 |
+
B(0x431200240210402D, 0x58102820000),
|
| 225 |
+
B(0x202020100A0019B0, 0x4010C0D018000000),
|
| 226 |
+
B(0x800800908402203, 0x102948C84C184),
|
| 227 |
+
B(0x26801100080845, 0x4009702022A00820),
|
| 228 |
+
B(0x8880520010401040, 0x1060084832052000),
|
| 229 |
+
B(0x100100022042081, 0x10000600008C121),
|
| 230 |
+
B(0x46020384100040, 0x800200320882021),
|
| 231 |
+
B(0xC0002010148, 0x4200800800040003),
|
| 232 |
+
B(0x2002208020090040, 0x40820210021410),
|
| 233 |
+
B(0x9000A41160002004, 0x2A09000100080043),
|
| 234 |
+
B(0x800004010008001, 0x1108002020104600),
|
| 235 |
+
B(0x800540C000A4E041, 0x18021180000401),
|
| 236 |
+
B(0x808200900A900202, 0x8364202140012005),
|
| 237 |
+
B(0x1DBA52000081010, 0x4008000023000010),
|
| 238 |
+
B(0x4100110204401481, 0x800040091020001C),
|
| 239 |
+
B(0x4100110204401481, 0x800040091020001C),
|
| 240 |
+
B(0x4101100020400482, 0x2000402302100120),
|
| 241 |
+
B(0x100408000A020212, 0xA000400111000020),
|
| 242 |
+
B(0x2000010488080104, 0x3000404410208100),
|
| 243 |
+
B(0x2684220180008DD0, 0x422040200004000A),
|
| 244 |
+
B(0x2021200C0424, 0x1010100000080200),
|
| 245 |
+
B(0x8908020020801006, 0x3010800020C2000),
|
| 246 |
+
B(0x4000030008062044, 0x244010202688000),
|
| 247 |
+
B(0x242101200408009, 0x8150040000200015),
|
| 248 |
+
B(0x42004C02180204, 0x210208014241040),
|
| 249 |
+
B(0x4E1A01C208410804, 0x8890041000012004),
|
| 250 |
+
B(0x2080200401000080, 0x8001098429008004),
|
| 251 |
+
B(0xA01400121804104, 0x280200C400000500),
|
| 252 |
+
B(0xD0080408040420, 0x1006040100224000),
|
| 253 |
+
B(0x28400205000800C9, 0x6021101401040075),
|
| 254 |
+
B(0x4000900040020104, 0x88129801100D0C),
|
| 255 |
+
B(0x8000004002180410, 0x400380200400204),
|
| 256 |
+
B(0x4002A430043008, 0x400200340100020),
|
| 257 |
+
B(0x401960004140A42, 0x100880710000464),
|
| 258 |
+
B(0x58014090102, 0xB8D30004010080),
|
| 259 |
+
B(0xA004C08000244000, 0x11280100E0000040),
|
| 260 |
+
B(0x2102008089208804, 0x110001004080040),
|
| 261 |
+
B(0x700010084E003004, 0x8080864112000D40),
|
| 262 |
+
B(0x4080881000200C20, 0x30324040880E0600),
|
| 263 |
+
B(0x2024A40401810820, 0x3000888002000000),
|
| 264 |
+
B(0x8200100400014, 0x4400340800252844),
|
| 265 |
+
B(0x24A00804288281, 0x410103002201140),
|
| 266 |
+
B(0x4080005022A08, 0x1000402200100264),
|
| 267 |
+
B(0x200080032244040, 0x200502189010001),
|
| 268 |
+
B(0x28108110404001, 0x400600120008412),
|
| 269 |
+
B(0xA00002102810020, 0xB1080240015408),
|
| 270 |
+
B(0x810080200806, 0x410440804080046)
|
| 271 |
+
};
|
| 272 |
+
constexpr Bitboard BishopMagicInit[SQUARE_NB] = {
|
| 273 |
+
B(0x2001040305000010, 0x830200040400082),
|
| 274 |
+
B(0x1042400080E01200, 0x2004904010811400),
|
| 275 |
+
B(0x400010120200, 0x880080D080018000),
|
| 276 |
+
B(0x240190C00100040, 0x100A020140044404),
|
| 277 |
+
B(0x1018010404010004, 0x1001010018081E0),
|
| 278 |
+
B(0x41200A804C0904, 0x40000322000008),
|
| 279 |
+
B(0x4001180A004, 0x8000001106000000),
|
| 280 |
+
B(0x6006020020030600, 0x1840002100004841),
|
| 281 |
+
B(0x4200200100, 0x4001041808002000),
|
| 282 |
+
B(0x4100020050124600, 0x1001802902400CA0),
|
| 283 |
+
B(0x448C0081440161, 0x200206010008000),
|
| 284 |
+
B(0x400008008008408, 0x1000080210100080),
|
| 285 |
+
B(0x200280C01008200, 0x210200813000080),
|
| 286 |
+
B(0x1A000204400, 0x222200401023000),
|
| 287 |
+
B(0x10081040640A00, 0x8410021881400000),
|
| 288 |
+
B(0x1840400318080008, 0x800800840080000),
|
| 289 |
+
B(0x4204050C040, 0x6500600200140000),
|
| 290 |
+
B(0x1012100040204, 0x402404444400000),
|
| 291 |
+
B(0x6000012680008240, 0x410140000004220),
|
| 292 |
+
B(0x1000020810040008, 0x2D0011000060000),
|
| 293 |
+
B(0x1020020400, 0x400108059001001),
|
| 294 |
+
B(0x400020001100808, 0x480204800200000B),
|
| 295 |
+
B(0x10000010030084, 0x2042000848900022),
|
| 296 |
+
B(0x10000010030084, 0x2042000848900022),
|
| 297 |
+
B(0x100D801402400, 0x1512404009000400),
|
| 298 |
+
B(0x8000208005112400, 0xA02040401000000),
|
| 299 |
+
B(0x1000420002800200, 0x4CA000183020000),
|
| 300 |
+
B(0x800811480020, 0x408801010224001),
|
| 301 |
+
B(0xC805200810900100, 0x9000084204004020),
|
| 302 |
+
B(0x8200160204100004, 0x8040004004002022),
|
| 303 |
+
B(0x104514013080080, 0x146410040001000),
|
| 304 |
+
B(0x140844000080002, 0x1008102020040001),
|
| 305 |
+
B(0x4040400041A2002, 0x8040000A8802510),
|
| 306 |
+
B(0x801014041008002, 0x80068008025200),
|
| 307 |
+
B(0xA00540A414040, 0x4101040010A0000),
|
| 308 |
+
B(0x6484008010810002, 0x1100506884024000),
|
| 309 |
+
B(0x2800401008006000, 0x1005420884029020),
|
| 310 |
+
B(0x6822091010004421, 0x2000458080480),
|
| 311 |
+
B(0x40101000200101, 0x10020100001C4E0),
|
| 312 |
+
B(0x100400008C42, 0x4000100009008000),
|
| 313 |
+
B(0x851220018800400, 0x1681800040080080),
|
| 314 |
+
B(0x64200002010, 0x900020200040002),
|
| 315 |
+
B(0x20800080000022, 0x80040810002010),
|
| 316 |
+
B(0xA88408000802080, 0x20808001000000),
|
| 317 |
+
B(0x200000400C005040, 0x100140020290108),
|
| 318 |
+
B(0x224100000800408, 0x4204802004400020),
|
| 319 |
+
B(0x80080620010210, 0x91080088804040),
|
| 320 |
+
B(0x4008002100010, 0x80AC201001000001),
|
| 321 |
+
B(0x10008200902C046, 0x8080D03004000010),
|
| 322 |
+
B(0x3002100081000180, 0x2210002121528408),
|
| 323 |
+
B(0x8C101800804420, 0x1019880200043008),
|
| 324 |
+
B(0x200022000920D0, 0x8000800081300020),
|
| 325 |
+
B(0x1D40800880000, 0x400040001400050),
|
| 326 |
+
B(0x2020004100040, 0x200008040008008),
|
| 327 |
+
B(0x4840800040100001, 0x100100040203040),
|
| 328 |
+
B(0x40084001105, 0x8800080088000089),
|
| 329 |
+
B(0x4000128008020008, 0x4004200200440020),
|
| 330 |
+
B(0x210040008520000, 0x820219001080022),
|
| 331 |
+
B(0x1494040018002116, 0x400101047020008),
|
| 332 |
+
B(0x510008001910C224, 0x80200148118000),
|
| 333 |
+
B(0xC0301002301000, 0x4211A08004801),
|
| 334 |
+
B(0x50008E0C01001080, 0x100C004102845100),
|
| 335 |
+
B(0x400600020060400, 0x88024100250050),
|
| 336 |
+
B(0x8202920002002040, 0x810012000003),
|
| 337 |
+
B(0x800004208800200, 0x18AA00201000048),
|
| 338 |
+
B(0x402100800100002, 0x411000081000400),
|
| 339 |
+
B(0x101000022004044, 0x9000100040000),
|
| 340 |
+
B(0x41068001001, 0xC00400010001),
|
| 341 |
+
B(0x310210001040, 0x1A1200020010000),
|
| 342 |
+
B(0xA082409200004048, 0x490040800124101),
|
| 343 |
+
B(0x18844820E0040212, 0x1000404420D10000),
|
| 344 |
+
B(0x802908A40003348, 0x20200040104140),
|
| 345 |
+
B(0x1800404028205003, 0xC020010401089020),
|
| 346 |
+
B(0x802100044D01000, 0x8C41888000800040),
|
| 347 |
+
B(0x1D0161011410081, 0x10008000100200),
|
| 348 |
+
B(0x401000480040100, 0x286800404002212),
|
| 349 |
+
B(0x821030000100009, 0x2000090200A00000),
|
| 350 |
+
B(0x200020800200800, 0x2000480900841012),
|
| 351 |
+
B(0x80A000048030080, 0x200000120200008),
|
| 352 |
+
B(0x40B1400008020020, 0x148000200008004),
|
| 353 |
+
B(0xA021700002002010, 0x3040E400040100),
|
| 354 |
+
B(0x400242C200200640, 0x20440210200281),
|
| 355 |
+
B(0x80AC140040206240, 0x120000102801401),
|
| 356 |
+
B(0x2020340040832040, 0x10402100A44000),
|
| 357 |
+
B(0x420100400040220, 0x80014C8004000106),
|
| 358 |
+
B(0x504300822421120, 0x8004004008400100),
|
| 359 |
+
B(0x2001100008040, 0x2020104302000000),
|
| 360 |
+
B(0xA500802000A, 0x2008008000114100),
|
| 361 |
+
B(0x8A0020000200, 0x9C00101001002408),
|
| 362 |
+
B(0x104000001001008, 0x9001000204040060),
|
| 363 |
+
B(0x1000820080108200, 0xA401000008100001),
|
| 364 |
+
B(0x2008600009000480, 0x9008020001400000),
|
| 365 |
+
B(0x4000800200040200, 0xA00030400308082),
|
| 366 |
+
B(0x4004300202004709, 0x1000100180010020),
|
| 367 |
+
B(0xC014800100440010, 0x402020280002C010),
|
| 368 |
+
B(0x220208010884680, 0x1040280000042110),
|
| 369 |
+
B(0x40B0018019202801, 0x1008408000100040),
|
| 370 |
+
B(0x8269010206080044, 0x8001810000000040),
|
| 371 |
+
B(0x4000020880081040, 0x208A44000028000),
|
| 372 |
+
B(0x4004004E9004220A, 0x2104004001400024),
|
| 373 |
+
B(0x8035006008C0904, 0x402002001080120),
|
| 374 |
+
B(0x1800884002, 0x404400820000000),
|
| 375 |
+
B(0x8088000004008910, 0x8024100401000000),
|
| 376 |
+
B(0x142200086000100, 0x28021040020002E),
|
| 377 |
+
B(0x1000409141004018, 0x100410820080040A),
|
| 378 |
+
B(0x1800801800140, 0x810801060C0801),
|
| 379 |
+
B(0x1000C00100402220, 0x808023420000000),
|
| 380 |
+
B(0x8A0A202414305008, 0x100040200000021),
|
| 381 |
+
B(0xC0208024050, 0x8003088008020401),
|
| 382 |
+
B(0x8044004201440101, 0x400820080C024022),
|
| 383 |
+
B(0x406018884120099, 0xB00088018002000),
|
| 384 |
+
B(0x2000800010403010, 0xC5A002002010010),
|
| 385 |
+
B(0x800020040840, 0x201800202800200),
|
| 386 |
+
B(0x201280120020008D, 0x258809001000040),
|
| 387 |
+
B(0x9100002020181, 0x80400082204000),
|
| 388 |
+
B(0x104010080201001, 0x40080080181080),
|
| 389 |
+
B(0x8440248092000430, 0xA200804900100000),
|
| 390 |
+
B(0x2031010C01000C20, 0x200310A560082008),
|
| 391 |
+
B(0x400202081811400, 0x40081802050000C),
|
| 392 |
+
B(0x1011002100821300, 0x2400825040804100)
|
| 393 |
+
};
|
| 394 |
+
constexpr Bitboard CannonMagicHInit[SQUARE_NB] = {
|
| 395 |
+
B(0x120000880110000, 0x1008000000020020),
|
| 396 |
+
B(0x24200C080840A052, 0x2004004000010008),
|
| 397 |
+
B(0xC030024000228800, 0x4000010400000020),
|
| 398 |
+
B(0x1A0020802008802, 0x206010208000),
|
| 399 |
+
B(0x12002000D001024, 0x80100800090138),
|
| 400 |
+
B(0x4220010000241010, 0x3098000602001500),
|
| 401 |
+
B(0x401010004801040, 0x8000280480100000),
|
| 402 |
+
B(0x820082024921836, 0x220028000),
|
| 403 |
+
B(0x100400502411400, 0x220402120240D14),
|
| 404 |
+
B(0x880202020010404, 0xA80202510000),
|
| 405 |
+
B(0x140002801000018, 0x1000346490040),
|
| 406 |
+
B(0x120000880110000, 0x1008000000020020),
|
| 407 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 408 |
+
B(0x8420060100020000, 0x800280400000120),
|
| 409 |
+
B(0x4010020018010, 0x40A00001100000),
|
| 410 |
+
B(0x40006A0004000200, 0x40000000110),
|
| 411 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 412 |
+
B(0x8908A20028110011, 0x800080000001A114),
|
| 413 |
+
B(0x200042000080F009, 0x20001000004000),
|
| 414 |
+
B(0x2820008820100, 0x10002400058000B9),
|
| 415 |
+
B(0x6083100420008050, 0x4040012600280080),
|
| 416 |
+
B(0x216020000000446, 0x4080204000000211),
|
| 417 |
+
B(0x340140003002089, 0x2402008000000911),
|
| 418 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 419 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 420 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 421 |
+
B(0x1010000060050000, 0x4000004050002602),
|
| 422 |
+
B(0x4022983A0060000, 0x80000040010400),
|
| 423 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 424 |
+
B(0x6020101802002840, 0x31000003000004),
|
| 425 |
+
B(0x9000420008840, 0x4881300000000210),
|
| 426 |
+
B(0xA200808865, 0x41C0048023000128),
|
| 427 |
+
B(0x31801100400000, 0x8802DC001221240),
|
| 428 |
+
B(0x884000080200920, 0x1004002410401001),
|
| 429 |
+
B(0x2400040000884, 0x421006208040C0),
|
| 430 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 431 |
+
B(0x24100400060009, 0x112008025042410),
|
| 432 |
+
B(0x1800040009040200, 0x180000A1004E408A),
|
| 433 |
+
B(0x24100400060009, 0x112008025042410),
|
| 434 |
+
B(0x4060402008080, 0xC240080000110000),
|
| 435 |
+
B(0x20080100920020, 0x2002248010242052),
|
| 436 |
+
B(0x10001010802050, 0x880000001C98420),
|
| 437 |
+
B(0x4000800100420022, 0x502022010A00D0),
|
| 438 |
+
B(0x4C18104500200885, 0x400880800),
|
| 439 |
+
B(0x8080810081020090, 0x8000000000000),
|
| 440 |
+
B(0x8000062812080201, 0x8004C8300800),
|
| 441 |
+
B(0x1800040009040200, 0x180000A1004E408A),
|
| 442 |
+
B(0x24100400060009, 0x112008025042410),
|
| 443 |
+
B(0x80102204040, 0x1000000900000000),
|
| 444 |
+
B(0x2080000004202804, 0x120880003461),
|
| 445 |
+
B(0x102004090A4030, 0x801020589240),
|
| 446 |
+
B(0x20001100814000A0, 0x420202000820004),
|
| 447 |
+
B(0x100800000A000120, 0x208000800010000),
|
| 448 |
+
B(0x1008205000040802, 0x80002000400040),
|
| 449 |
+
B(0x1480000098008401, 0xA0010000581010),
|
| 450 |
+
B(0x30C0008200100820, 0x102800080904834),
|
| 451 |
+
B(0x4810821884000500, 0x4400000200000212),
|
| 452 |
+
B(0x1811D00128A0180, 0x2500848803000000),
|
| 453 |
+
B(0x41618A0300040040, 0x21200200A421801),
|
| 454 |
+
B(0x80102204040, 0x1000000900000000),
|
| 455 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 456 |
+
B(0x8C890020410000A0, 0xA010000048000400),
|
| 457 |
+
B(0x40006002210044, 0x600008000408000),
|
| 458 |
+
B(0x1200447220090042, 0x80001000160012),
|
| 459 |
+
B(0x48410010AB000000, 0x9200600000000100),
|
| 460 |
+
B(0x2040000000240003, 0x8020080288000600),
|
| 461 |
+
B(0x9080000088848088, 0x4010210500000041),
|
| 462 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 463 |
+
B(0x480100400024, 0x1004800018200000),
|
| 464 |
+
B(0x808403080080200, 0x802601000000500),
|
| 465 |
+
B(0x8C890020410000A0, 0xA010000048000400),
|
| 466 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 467 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 468 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 469 |
+
B(0x400014006000000, 0x10006000810001F5),
|
| 470 |
+
B(0xC410062001414, 0x820080041B01044),
|
| 471 |
+
B(0x20000800310, 0x430040000201000),
|
| 472 |
+
B(0xA40010008000008, 0x4002200028000040),
|
| 473 |
+
B(0xC00102000008021C, 0x10C2000A010E024),
|
| 474 |
+
B(0x80004200104008, 0x50A00800C400020),
|
| 475 |
+
B(0x20200080012542, 0x910F0040000402C0),
|
| 476 |
+
B(0xB040100504000300, 0x24802002000040),
|
| 477 |
+
B(0x800001000014008, 0x400031004000),
|
| 478 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 479 |
+
B(0x84008002041081C0, 0x8080500200000000),
|
| 480 |
+
B(0x440090001012001, 0x4020004010),
|
| 481 |
+
B(0x100A0028088020, 0x80040E00010020),
|
| 482 |
+
B(0x2180808000810, 0xB018040A00040000),
|
| 483 |
+
B(0x40C80920304C4001, 0x42800B200800000),
|
| 484 |
+
B(0x85000425001000, 0x4810048020001100),
|
| 485 |
+
B(0x600C000801000004, 0x8015084010200020),
|
| 486 |
+
B(0x20020050000240C0, 0x100202008600800),
|
| 487 |
+
B(0x38000050001220, 0x9200010200145900),
|
| 488 |
+
B(0x1042108040005, 0x1402A0802201001),
|
| 489 |
+
B(0x824240000C20400, 0x1000000400080010),
|
| 490 |
+
B(0x84008002041081C0, 0x8080500200000000),
|
| 491 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 492 |
+
B(0x8000402308483, 0x20006020100100),
|
| 493 |
+
B(0x80880120000080, 0x8000240100084),
|
| 494 |
+
B(0x5840020004882001, 0x1004528000A00010),
|
| 495 |
+
B(0x8001018800300002, 0x84010040804),
|
| 496 |
+
B(0x180D10004000A008, 0xA001080008020004),
|
| 497 |
+
B(0x400080B, 0x10A0000004010000),
|
| 498 |
+
B(0x8080000200000, 0x2001000082004E0),
|
| 499 |
+
B(0x40040001000C2000, 0x2024800001004008),
|
| 500 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 501 |
+
B(0x8000402308483, 0x20006020100100),
|
| 502 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 503 |
+
B(0x2000200000, 0x1201011000802),
|
| 504 |
+
B(0x100100000000C4, 0x208004084048201),
|
| 505 |
+
B(0x400084000044, 0x100810140300),
|
| 506 |
+
B(0x29040C0C01010, 0x300204010820080),
|
| 507 |
+
B(0x1A808000020200, 0x1000000005210040),
|
| 508 |
+
B(0x20000400150000, 0x85008020),
|
| 509 |
+
B(0x40C040008184014, 0x8002AA00024010),
|
| 510 |
+
B(0x202000081B00804, 0x10001002008),
|
| 511 |
+
B(0x40011000210060, 0x6080C40000021004),
|
| 512 |
+
B(0x2000200000, 0x1201011000802),
|
| 513 |
+
B(0x4100480203840, 0x300080100804),
|
| 514 |
+
B(0x2000200000, 0x1201011000802),
|
| 515 |
+
};
|
| 516 |
+
constexpr Bitboard CannonMagicVInit[SQUARE_NB] = {
|
| 517 |
+
B(0x202000812104400, 0x24800B01C0000303),
|
| 518 |
+
B(0x340020400010D, 0x88060150C00400),
|
| 519 |
+
B(0x400802040609, 0x49010200501A0002),
|
| 520 |
+
B(0x8002680301000208, 0x628006C0C020200),
|
| 521 |
+
B(0x20400209001C0804, 0xA044000800143110),
|
| 522 |
+
B(0xC400082060010202, 0x4000480401014000),
|
| 523 |
+
B(0x22500200144040, 0x8204820084704C00),
|
| 524 |
+
B(0x8C1204009030020, 0x328400805000000),
|
| 525 |
+
B(0x84800800D0001640, 0x200080040060108),
|
| 526 |
+
B(0x804810208020040, 0x140010108020000),
|
| 527 |
+
B(0x1102010B008004, 0x300208006220020),
|
| 528 |
+
B(0x140080404A0A2428, 0x6308010100080),
|
| 529 |
+
B(0x20444002120408, 0xA080010508010001),
|
| 530 |
+
B(0x82011044000D02, 0x4112028620110809),
|
| 531 |
+
B(0x81010831000C02, 0x408802085000000),
|
| 532 |
+
B(0x81010831000C02, 0x408802085000000),
|
| 533 |
+
B(0x920008920600040, 0x8053801004000028),
|
| 534 |
+
B(0x81140283208300, 0x10040C004200420),
|
| 535 |
+
B(0x103080022201, 0xC01000081312620),
|
| 536 |
+
B(0x2200221100008, 0x1000408104000A4),
|
| 537 |
+
B(0x4402088080042008, 0x210401501040340),
|
| 538 |
+
B(0x898400202170001, 0x80040404208000),
|
| 539 |
+
B(0x20080004051012, 0x5100048200081800),
|
| 540 |
+
B(0x2320020000401018, 0x108501021040210),
|
| 541 |
+
B(0x21080410A422021, 0x83040180008800),
|
| 542 |
+
B(0x44E8100000408224, 0x20010008040400),
|
| 543 |
+
B(0x1800240002810405, 0x23004820000020),
|
| 544 |
+
B(0x80A0100400110, 0x80104020100C4028),
|
| 545 |
+
B(0x1002050001222C0, 0x5100818004024020),
|
| 546 |
+
B(0x104000200040, 0xC010A09800102000),
|
| 547 |
+
B(0x1020003A058120, 0x450900809000302),
|
| 548 |
+
B(0x40040045008B1, 0x202800400383010),
|
| 549 |
+
B(0x4640200220034, 0x8800485420304000),
|
| 550 |
+
B(0x5001042100084288, 0x110820001240080A),
|
| 551 |
+
B(0x2002C04004010120, 0xA15008020880001),
|
| 552 |
+
B(0x2800004080C4190, 0x890808280020080),
|
| 553 |
+
B(0x40C0401000104000, 0x2020880008002580),
|
| 554 |
+
B(0x40020C002400802, 0x801104010000000),
|
| 555 |
+
B(0x44842000040080, 0x2050011084000400),
|
| 556 |
+
B(0x4110040800000401, 0x2023810029008000),
|
| 557 |
+
B(0x20884000840, 0x8017102004008000),
|
| 558 |
+
B(0x10411104000480, 0x1414042000201001),
|
| 559 |
+
B(0x220040000008, 0x800306021000000),
|
| 560 |
+
B(0x41400A0008080, 0x501000298ACAD10),
|
| 561 |
+
B(0x800240012831810, 0x80120004468050E),
|
| 562 |
+
B(0x800005020801008, 0x20102400240000),
|
| 563 |
+
B(0x20C00040C114C010, 0x88080820200C00),
|
| 564 |
+
B(0x1044010100820081, 0x20080841004000),
|
| 565 |
+
B(0x8041048400022, 0x8020836040005002),
|
| 566 |
+
B(0x2001004010205, 0x8001002884042009),
|
| 567 |
+
B(0x128088400087, 0x20008002201002),
|
| 568 |
+
B(0x8084108040402000, 0x80809000A080400),
|
| 569 |
+
B(0x408081840880, 0x201002088000040),
|
| 570 |
+
B(0xA40180010280, 0x241004006000010),
|
| 571 |
+
B(0x4204100080048140, 0x2002C4F104202020),
|
| 572 |
+
B(0x100140A10204, 0x980200800840060),
|
| 573 |
+
B(0x1005140010202048, 0x1442280800202815),
|
| 574 |
+
B(0x2000082025008600, 0x1108400040600003),
|
| 575 |
+
B(0x1005050648000, 0x200020240008002),
|
| 576 |
+
B(0x202010208044000, 0x8210404060008),
|
| 577 |
+
B(0x8011040402000210, 0xC840180408016004),
|
| 578 |
+
B(0x404098801028, 0x80020A0001000400),
|
| 579 |
+
B(0x404098801028, 0x80020A0001000400),
|
| 580 |
+
B(0x80101002180140, 0x40C2080820000C0),
|
| 581 |
+
B(0x208202081260800, 0x14090E4C04000050),
|
| 582 |
+
B(0x4221201084004C2, 0x110480A011060),
|
| 583 |
+
B(0x8000008421090204, 0x1C01010800024),
|
| 584 |
+
B(0x8000008421090204, 0x1C01010800024),
|
| 585 |
+
B(0x200180C840088A0, 0x401100400820000),
|
| 586 |
+
B(0x10084043A021070, 0x202041600080200),
|
| 587 |
+
B(0x210E6202001040C, 0x10100800080B0),
|
| 588 |
+
B(0x848008021204002, 0x801004308100BAD),
|
| 589 |
+
B(0xC082C0390A000601, 0x4040080189008),
|
| 590 |
+
B(0x431200240210402D, 0x58102820000),
|
| 591 |
+
B(0x202020100A0019B0, 0x4010C0D018000000),
|
| 592 |
+
B(0x800800908402203, 0x102948C84C184),
|
| 593 |
+
B(0x26801100080845, 0x4009702022A00820),
|
| 594 |
+
B(0x8880520010401040, 0x1060084832052000),
|
| 595 |
+
B(0x100100022042081, 0x10000600008C121),
|
| 596 |
+
B(0x46020384100040, 0x800200320882021),
|
| 597 |
+
B(0xC0002010148, 0x4200800800040003),
|
| 598 |
+
B(0x2002208020090040, 0x40820210021410),
|
| 599 |
+
B(0x9000A41160002004, 0x2A09000100080043),
|
| 600 |
+
B(0x800004010008001, 0x1108002020104600),
|
| 601 |
+
B(0x800540C000A4E041, 0x18021180000401),
|
| 602 |
+
B(0x808200900A900202, 0x8364202140012005),
|
| 603 |
+
B(0x1DBA52000081010, 0x4008000023000010),
|
| 604 |
+
B(0x4100110204401481, 0x800040091020001C),
|
| 605 |
+
B(0x4100110204401481, 0x800040091020001C),
|
| 606 |
+
B(0x4101100020400482, 0x2000402302100120),
|
| 607 |
+
B(0x100408000A020212, 0xA000400111000020),
|
| 608 |
+
B(0x2000010488080104, 0x3000404410208100),
|
| 609 |
+
B(0x2684220180008DD0, 0x422040200004000A),
|
| 610 |
+
B(0x2021200C0424, 0x1010100000080200),
|
| 611 |
+
B(0x8908020020801006, 0x3010800020C2000),
|
| 612 |
+
B(0x4000030008062044, 0x244010202688000),
|
| 613 |
+
B(0x242101200408009, 0x8150040000200015),
|
| 614 |
+
B(0x42004C02180204, 0x210208014241040),
|
| 615 |
+
B(0x4E1A01C208410804, 0x8890041000012004),
|
| 616 |
+
B(0x2080200401000080, 0x8001098429008004),
|
| 617 |
+
B(0xA01400121804104, 0x280200C400000500),
|
| 618 |
+
B(0xD0080408040420, 0x1006040100224000),
|
| 619 |
+
B(0x28400205000800C9, 0x6021101401040075),
|
| 620 |
+
B(0x4000900040020104, 0x88129801100D0C),
|
| 621 |
+
B(0x8000004002180410, 0x400380200400204),
|
| 622 |
+
B(0x4002A430043008, 0x400200340100020),
|
| 623 |
+
B(0x401960004140A42, 0x100880710000464),
|
| 624 |
+
B(0x58014090102, 0xB8D30004010080),
|
| 625 |
+
B(0xA004C08000244000, 0x11280100E0000040),
|
| 626 |
+
B(0x2102008089208804, 0x110001004080040),
|
| 627 |
+
B(0x700010084E003004, 0x8080864112000D40),
|
| 628 |
+
B(0x4080881000200C20, 0x30324040880E0600),
|
| 629 |
+
B(0x2024A40401810820, 0x3000888002000000),
|
| 630 |
+
B(0x8200100400014, 0x4400340800252844),
|
| 631 |
+
B(0x24A00804288281, 0x410103002201140),
|
| 632 |
+
B(0x4080005022A08, 0x1000402200100264),
|
| 633 |
+
B(0x200080032244040, 0x200502189010001),
|
| 634 |
+
B(0x28108110404001, 0x400600120008412),
|
| 635 |
+
B(0xA00002102810020, 0xB1080240015408),
|
| 636 |
+
B(0x810080200806, 0x410440804080046),
|
| 637 |
+
};
|
| 638 |
+
constexpr Bitboard LameDabbabaMagicInit[SQUARE_NB] = {
|
| 639 |
+
B(0x3C080482A592000C, 0x540104000020000),
|
| 640 |
+
B(0x2802C40008000420, 0x4A00000001818009),
|
| 641 |
+
B(0x1083040280804000, 0x120004C20100880),
|
| 642 |
+
B(0x6840940880000892, 0x2014A01080800C2),
|
| 643 |
+
B(0x8401489004000180, 0x2000800000400000),
|
| 644 |
+
B(0x820161C800000110, 0x8000100000204020),
|
| 645 |
+
B(0x610011A122000109, 0x1000004020008004),
|
| 646 |
+
B(0x83282004023000, 0xE000020004848446),
|
| 647 |
+
B(0x6840940880000892, 0x2014A01080800C2),
|
| 648 |
+
B(0x4020120800800002, 0x88008000010020),
|
| 649 |
+
B(0x30025B140A1000, 0x3141801401000040),
|
| 650 |
+
B(0x41104D1810100050, 0x8141002010910),
|
| 651 |
+
B(0x4200828A298400, 0x400340001040C000),
|
| 652 |
+
B(0x8016A4900110040, 0x844812001068020),
|
| 653 |
+
B(0x2250035820400A2, 0x8012010080900),
|
| 654 |
+
B(0x820080083A009000, 0x880404091080110),
|
| 655 |
+
B(0x80401500AF0020, 0x240000082201A04),
|
| 656 |
+
B(0x668020020C081005, 0x4008001004100021),
|
| 657 |
+
B(0x240100910000000, 0x82000A0030454000),
|
| 658 |
+
B(0xA24091400008, 0x200014880004A921),
|
| 659 |
+
B(0x840110042200410, 0x100080000A400000),
|
| 660 |
+
B(0x40024024102000, 0x1000000002180404),
|
| 661 |
+
B(0x92828423000530, 0x118800020110),
|
| 662 |
+
B(0x1122404A1C90A8, 0x822040280020D00),
|
| 663 |
+
B(0x41201A40900A000, 0x80C0480040605100),
|
| 664 |
+
B(0x2504A85005488280, 0x3028112120022800),
|
| 665 |
+
B(0x210180080626B048, 0x8000401000014000),
|
| 666 |
+
B(0x1000410401040200, 0x41014000050C0106),
|
| 667 |
+
B(0x1040650210802200, 0x80C0041000000),
|
| 668 |
+
B(0x4020C10110900002, 0x2140C2001050009),
|
| 669 |
+
B(0x191180092200022, 0x6010008400400800),
|
| 670 |
+
B(0x8010821088080202, 0xCA240011008208),
|
| 671 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 672 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 673 |
+
B(0x22080C8A0161401, 0x200C10004C002002),
|
| 674 |
+
B(0x8430818023034080, 0x210090800000801),
|
| 675 |
+
B(0x4845087008200, 0x40661480000),
|
| 676 |
+
B(0x1202804428812050, 0x100022038020000),
|
| 677 |
+
B(0x400016001201080, 0x24002200402060),
|
| 678 |
+
B(0x680E041300800800, 0xE00130080004000),
|
| 679 |
+
B(0x3409080200, 0x282840210000000),
|
| 680 |
+
B(0x803310108400, 0x85200000080100A0),
|
| 681 |
+
B(0xE180008A04162104, 0x9088240412404),
|
| 682 |
+
B(0x20080100920020, 0x2002248010242052),
|
| 683 |
+
B(0x8A000400C2410, 0x1000024086014300),
|
| 684 |
+
B(0x1821040024663, 0x100000100010009),
|
| 685 |
+
B(0x4000822310611, 0x120280406014008),
|
| 686 |
+
B(0x1004008010818D08, 0x800000141892000),
|
| 687 |
+
B(0x8010800004024042, 0x44B106008800896),
|
| 688 |
+
B(0xA0063423444, 0x41002C15811008),
|
| 689 |
+
B(0x2040012381001282, 0x4804080104A4000),
|
| 690 |
+
B(0x10840101820880, 0xA800008000020020),
|
| 691 |
+
B(0x10840101820880, 0xA800008000020020),
|
| 692 |
+
B(0x60201D8300408190, 0x2010020920200000),
|
| 693 |
+
B(0x4048100200090090, 0x2008090100000900),
|
| 694 |
+
B(0x24200000280210, 0xD440050008004000),
|
| 695 |
+
B(0x1280001000580020, 0x2200040089000A4),
|
| 696 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 697 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 698 |
+
B(0x4108000010209089, 0x913000000024840),
|
| 699 |
+
B(0x410C208008008E02, 0xE8000000000001),
|
| 700 |
+
B(0x802208004005, 0x94206000022080),
|
| 701 |
+
B(0xC00290018902002, 0x4204100000000000),
|
| 702 |
+
B(0x2102801400093816, 0x9810004001000202),
|
| 703 |
+
B(0x8008304000015800, 0x4A5C000000020000),
|
| 704 |
+
B(0x1020108380800514, 0x1144210000000080),
|
| 705 |
+
B(0xC0001000008090, 0x2812060000204000),
|
| 706 |
+
B(0x1001100200003100, 0x246240060A004004),
|
| 707 |
+
B(0xA00020A008002030, 0x2440C40000110B00),
|
| 708 |
+
B(0x80502104000C008, 0x8222200042100010),
|
| 709 |
+
B(0xC020200088014, 0x422094000000480),
|
| 710 |
+
B(0x1029002000001030, 0x8105841120000210),
|
| 711 |
+
B(0x49040D, 0x2310808A14042C0),
|
| 712 |
+
B(0x200040200080A02C, 0xB890290400080000),
|
| 713 |
+
B(0x2240180C0800002, 0x4151050280000100),
|
| 714 |
+
B(0x2240180C0800002, 0x4151050280000100),
|
| 715 |
+
B(0x8220224180420006, 0x4024501212011000),
|
| 716 |
+
B(0x1806810A0881000, 0x802002048400080),
|
| 717 |
+
B(0x400400A080842, 0x9305000401180000),
|
| 718 |
+
B(0x10008001444110, 0x4420401040041833),
|
| 719 |
+
B(0x2000002C02010E00, 0x400408D08009804),
|
| 720 |
+
B(0x69D008200020100, 0x100842240049021),
|
| 721 |
+
B(0x42C24450020000, 0xD38400880090884),
|
| 722 |
+
B(0x485800800100001, 0x2484086522018840),
|
| 723 |
+
B(0x900200020820042, 0x22302421400040C0),
|
| 724 |
+
B(0x50B0413001818000, 0x452014040800C40),
|
| 725 |
+
B(0x8004040021008, 0x20088A08000290),
|
| 726 |
+
B(0x600C000801000004, 0x8015084010200020),
|
| 727 |
+
B(0x208000C00, 0xE004804021100100),
|
| 728 |
+
B(0x20001000040204, 0x948110C0B2081),
|
| 729 |
+
B(0x268502400100021, 0x80A201840802080),
|
| 730 |
+
B(0x408C000008, 0x8822102408014),
|
| 731 |
+
B(0x1182080410100000, 0x608002046A0100),
|
| 732 |
+
B(0x100820A083C00002, 0x3100100410A00),
|
| 733 |
+
B(0x8401040000400124, 0x2000081288202200),
|
| 734 |
+
B(0xB014040003000800, 0x11960D1101210),
|
| 735 |
+
B(0x10040001900C000, 0x85603C1001280),
|
| 736 |
+
B(0x2000844000000100, 0x2000024C60800800),
|
| 737 |
+
B(0x120004234800900, 0x210010841040),
|
| 738 |
+
B(0x8010300040000002, 0x4200008222104100),
|
| 739 |
+
B(0x1000120402200100, 0x209080CC040108B4),
|
| 740 |
+
B(0x110049A00000800, 0x80000420022180A8),
|
| 741 |
+
B(0x80001C00080384, 0x1400101111081001),
|
| 742 |
+
B(0x8011200008100428, 0x2020000880800922),
|
| 743 |
+
B(0x10001000000204C8, 0x280C11104240),
|
| 744 |
+
B(0x50100C82C000500, 0x28000280618DD1),
|
| 745 |
+
B(0x8800498020000, 0x20500A0200320128),
|
| 746 |
+
B(0x20010104000860, 0x8021720186008),
|
| 747 |
+
B(0x4000000000100080, 0x35040084270C04),
|
| 748 |
+
B(0x4500080000800, 0x280100002482C842),
|
| 749 |
+
B(0x10400000000000, 0x20080051100130C2),
|
| 750 |
+
B(0x10400000000000, 0x20080051100130C2),
|
| 751 |
+
B(0x2000002110202014, 0x121004004004681),
|
| 752 |
+
B(0x400202001006D40, 0x82240082202424),
|
| 753 |
+
B(0x4500080000800, 0x280100002482C842),
|
| 754 |
+
B(0xC6000000D00804, 0x1050020C0081090C),
|
| 755 |
+
B(0x200080000000042, 0x10800661),
|
| 756 |
+
B(0x2000001011200200, 0x2A420000802A0222),
|
| 757 |
+
B(0x802020001202412, 0x2400404148426),
|
| 758 |
+
B(0x8000440801040002, 0x444002800010052A),
|
| 759 |
+
};
|
| 760 |
+
constexpr Bitboard HorseMagicInit[SQUARE_NB] = {
|
| 761 |
+
B(0x3C080482A592000C, 0x540104000020000),
|
| 762 |
+
B(0x2802C40008000420, 0x4A00000001818009),
|
| 763 |
+
B(0x1083040280804000, 0x120004C20100880),
|
| 764 |
+
B(0x6840940880000892, 0x2014A01080800C2),
|
| 765 |
+
B(0x8401489004000180, 0x2000800000400000),
|
| 766 |
+
B(0x820161C800000110, 0x8000100000204020),
|
| 767 |
+
B(0x610011A122000109, 0x1000004020008004),
|
| 768 |
+
B(0x83282004023000, 0xE000020004848446),
|
| 769 |
+
B(0x6840940880000892, 0x2014A01080800C2),
|
| 770 |
+
B(0x4020120800800002, 0x88008000010020),
|
| 771 |
+
B(0x30025B140A1000, 0x3141801401000040),
|
| 772 |
+
B(0x41104D1810100050, 0x8141002010910),
|
| 773 |
+
B(0x4200828A298400, 0x400340001040C000),
|
| 774 |
+
B(0x8016A4900110040, 0x844812001068020),
|
| 775 |
+
B(0x2250035820400A2, 0x8012010080900),
|
| 776 |
+
B(0x820080083A009000, 0x880404091080110),
|
| 777 |
+
B(0x80401500AF0020, 0x240000082201A04),
|
| 778 |
+
B(0x668020020C081005, 0x4008001004100021),
|
| 779 |
+
B(0x240100910000000, 0x82000A0030454000),
|
| 780 |
+
B(0xA24091400008, 0x200014880004A921),
|
| 781 |
+
B(0x840110042200410, 0x100080000A400000),
|
| 782 |
+
B(0x40024024102000, 0x1000000002180404),
|
| 783 |
+
B(0x92828423000530, 0x118800020110),
|
| 784 |
+
B(0x1122404A1C90A8, 0x822040280020D00),
|
| 785 |
+
B(0x41201A40900A000, 0x80C0480040605100),
|
| 786 |
+
B(0x2504A85005488280, 0x3028112120022800),
|
| 787 |
+
B(0x210180080626B048, 0x8000401000014000),
|
| 788 |
+
B(0x1000410401040200, 0x41014000050C0106),
|
| 789 |
+
B(0x1040650210802200, 0x80C0041000000),
|
| 790 |
+
B(0x4020C10110900002, 0x2140C2001050009),
|
| 791 |
+
B(0x191180092200022, 0x6010008400400800),
|
| 792 |
+
B(0x8010821088080202, 0xCA240011008208),
|
| 793 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 794 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 795 |
+
B(0x22080C8A0161401, 0x200C10004C002002),
|
| 796 |
+
B(0x8430818023034080, 0x210090800000801),
|
| 797 |
+
B(0x4845087008200, 0x40661480000),
|
| 798 |
+
B(0x1202804428812050, 0x100022038020000),
|
| 799 |
+
B(0x400016001201080, 0x24002200402060),
|
| 800 |
+
B(0x680E041300800800, 0xE00130080004000),
|
| 801 |
+
B(0x3409080200, 0x282840210000000),
|
| 802 |
+
B(0x803310108400, 0x85200000080100A0),
|
| 803 |
+
B(0xE180008A04162104, 0x9088240412404),
|
| 804 |
+
B(0x20080100920020, 0x2002248010242052),
|
| 805 |
+
B(0x8A000400C2410, 0x1000024086014300),
|
| 806 |
+
B(0x1821040024663, 0x100000100010009),
|
| 807 |
+
B(0x4000822310611, 0x120280406014008),
|
| 808 |
+
B(0x1004008010818D08, 0x800000141892000),
|
| 809 |
+
B(0x8010800004024042, 0x44B106008800896),
|
| 810 |
+
B(0xA0063423444, 0x41002C15811008),
|
| 811 |
+
B(0x2040012381001282, 0x4804080104A4000),
|
| 812 |
+
B(0x10840101820880, 0xA800008000020020),
|
| 813 |
+
B(0x10840101820880, 0xA800008000020020),
|
| 814 |
+
B(0x60201D8300408190, 0x2010020920200000),
|
| 815 |
+
B(0x4048100200090090, 0x2008090100000900),
|
| 816 |
+
B(0x24200000280210, 0xD440050008004000),
|
| 817 |
+
B(0x1280001000580020, 0x2200040089000A4),
|
| 818 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 819 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 820 |
+
B(0x4108000010209089, 0x913000000024840),
|
| 821 |
+
B(0x410C208008008E02, 0xE8000000000001),
|
| 822 |
+
B(0x802208004005, 0x94206000022080),
|
| 823 |
+
B(0xC00290018902002, 0x4204100000000000),
|
| 824 |
+
B(0x2102801400093816, 0x9810004001000202),
|
| 825 |
+
B(0x8008304000015800, 0x4A5C000000020000),
|
| 826 |
+
B(0x1020108380800514, 0x1144210000000080),
|
| 827 |
+
B(0xC0001000008090, 0x2812060000204000),
|
| 828 |
+
B(0x1001100200003100, 0x246240060A004004),
|
| 829 |
+
B(0xA00020A008002030, 0x2440C40000110B00),
|
| 830 |
+
B(0x80502104000C008, 0x8222200042100010),
|
| 831 |
+
B(0xC020200088014, 0x422094000000480),
|
| 832 |
+
B(0x1029002000001030, 0x8105841120000210),
|
| 833 |
+
B(0x49040D, 0x2310808A14042C0),
|
| 834 |
+
B(0x200040200080A02C, 0xB890290400080000),
|
| 835 |
+
B(0x2240180C0800002, 0x4151050280000100),
|
| 836 |
+
B(0x2240180C0800002, 0x4151050280000100),
|
| 837 |
+
B(0x8220224180420006, 0x4024501212011000),
|
| 838 |
+
B(0x1806810A0881000, 0x802002048400080),
|
| 839 |
+
B(0x400400A080842, 0x9305000401180000),
|
| 840 |
+
B(0x10008001444110, 0x4420401040041833),
|
| 841 |
+
B(0x2000002C02010E00, 0x400408D08009804),
|
| 842 |
+
B(0x69D008200020100, 0x100842240049021),
|
| 843 |
+
B(0x42C24450020000, 0xD38400880090884),
|
| 844 |
+
B(0x485800800100001, 0x2484086522018840),
|
| 845 |
+
B(0x900200020820042, 0x22302421400040C0),
|
| 846 |
+
B(0x50B0413001818000, 0x452014040800C40),
|
| 847 |
+
B(0x8004040021008, 0x20088A08000290),
|
| 848 |
+
B(0x600C000801000004, 0x8015084010200020),
|
| 849 |
+
B(0x208000C00, 0xE004804021100100),
|
| 850 |
+
B(0x20001000040204, 0x948110C0B2081),
|
| 851 |
+
B(0x268502400100021, 0x80A201840802080),
|
| 852 |
+
B(0x408C000008, 0x8822102408014),
|
| 853 |
+
B(0x1182080410100000, 0x608002046A0100),
|
| 854 |
+
B(0x100820A083C00002, 0x3100100410A00),
|
| 855 |
+
B(0x8401040000400124, 0x2000081288202200),
|
| 856 |
+
B(0xB014040003000800, 0x11960D1101210),
|
| 857 |
+
B(0x10040001900C000, 0x85603C1001280),
|
| 858 |
+
B(0x2000844000000100, 0x2000024C60800800),
|
| 859 |
+
B(0x120004234800900, 0x210010841040),
|
| 860 |
+
B(0x8010300040000002, 0x4200008222104100),
|
| 861 |
+
B(0x1000120402200100, 0x209080CC040108B4),
|
| 862 |
+
B(0x110049A00000800, 0x80000420022180A8),
|
| 863 |
+
B(0x80001C00080384, 0x1400101111081001),
|
| 864 |
+
B(0x8011200008100428, 0x2020000880800922),
|
| 865 |
+
B(0x10001000000204C8, 0x280C11104240),
|
| 866 |
+
B(0x50100C82C000500, 0x28000280618DD1),
|
| 867 |
+
B(0x8800498020000, 0x20500A0200320128),
|
| 868 |
+
B(0x20010104000860, 0x8021720186008),
|
| 869 |
+
B(0x4000000000100080, 0x35040084270C04),
|
| 870 |
+
B(0x4500080000800, 0x280100002482C842),
|
| 871 |
+
B(0x10400000000000, 0x20080051100130C2),
|
| 872 |
+
B(0x10400000000000, 0x20080051100130C2),
|
| 873 |
+
B(0x2000002110202014, 0x121004004004681),
|
| 874 |
+
B(0x400202001006D40, 0x82240082202424),
|
| 875 |
+
B(0x4500080000800, 0x280100002482C842),
|
| 876 |
+
B(0xC6000000D00804, 0x1050020C0081090C),
|
| 877 |
+
B(0x200080000000042, 0x10800661),
|
| 878 |
+
B(0x2000001011200200, 0x2A420000802A0222),
|
| 879 |
+
B(0x802020001202412, 0x2400404148426),
|
| 880 |
+
B(0x8000440801040002, 0x444002800010052A),
|
| 881 |
+
};
|
| 882 |
+
constexpr Bitboard ElephantMagicInit[SQUARE_NB] = {
|
| 883 |
+
B(0x64D2990200008, 0x4401880001C000),
|
| 884 |
+
B(0x29BAA00010020, 0x200000400800600),
|
| 885 |
+
B(0x3024240000000, 0x4100400010080),
|
| 886 |
+
B(0xA490A00480020, 0x20084001041010A4),
|
| 887 |
+
B(0x328C021008042, 0x100000000C10204),
|
| 888 |
+
B(0x1964090001018, 0x7002040148001205),
|
| 889 |
+
B(0x800302098404080, 0x4983020000000001),
|
| 890 |
+
B(0x8812244630A02080, 0x8200006204003C08),
|
| 891 |
+
B(0x41120231008000, 0x240441401020),
|
| 892 |
+
B(0x840091030C00040, 0x1400008200023400),
|
| 893 |
+
B(0x8001040E77030200, 0x100040090022000),
|
| 894 |
+
B(0x602022139D835040, 0x101002010025900),
|
| 895 |
+
B(0x405707C48400, 0x40010000008001),
|
| 896 |
+
B(0x982003456A82050, 0x60800820040030),
|
| 897 |
+
B(0x204184849200088, 0x101800004006),
|
| 898 |
+
B(0x300222470949200, 0x2A0800200200800),
|
| 899 |
+
B(0x400001211914000, 0x8200001407001),
|
| 900 |
+
B(0x2000008614831020, 0x4000020001404000),
|
| 901 |
+
B(0x84000024A2048048, 0x1200102000042),
|
| 902 |
+
B(0x424010A58422008, 0x88440242212A0110),
|
| 903 |
+
B(0x20020812C0C4408, 0x4121400000080010),
|
| 904 |
+
B(0x680200062042420, 0x2001100000800000),
|
| 905 |
+
B(0x200010060AEC855, 0x8083002040200000),
|
| 906 |
+
B(0x4000008BAA85810, 0x82000805C0200A90),
|
| 907 |
+
B(0x81450B200A025400, 0x4400101050000040),
|
| 908 |
+
B(0x820A2241409010, 0x888420030000),
|
| 909 |
+
B(0x909203000028, 0xC000004C00200041),
|
| 910 |
+
B(0x8021400A84880240, 0x100180002010020),
|
| 911 |
+
B(0x8001A20061410000, 0x14008499A000000),
|
| 912 |
+
B(0x8201444800A00080, 0x402010040588120),
|
| 913 |
+
B(0x100C06280020, 0x60010104840130),
|
| 914 |
+
B(0x520040800080044, 0x8220000080001402),
|
| 915 |
+
B(0x102021410040202, 0x2004400410006000),
|
| 916 |
+
B(0x5401832090020400, 0x300010020001),
|
| 917 |
+
B(0x180003105A84C108, 0x1012008800081000),
|
| 918 |
+
B(0x480C10210026904, 0xA006000004200418),
|
| 919 |
+
B(0x48050820210843A6, 0x108001004000C00),
|
| 920 |
+
B(0x1030101182206324, 0x4401008921502002),
|
| 921 |
+
B(0x40281060800800, 0x406000201260022),
|
| 922 |
+
B(0xC29002440040C820, 0x400001002008020),
|
| 923 |
+
B(0x40000400800241, 0xC220000000400280),
|
| 924 |
+
B(0x40880126014208, 0x2A8004C008940000),
|
| 925 |
+
B(0x121028100114080, 0x5010280481100082),
|
| 926 |
+
B(0x4000088280442, 0x908420140008041),
|
| 927 |
+
B(0x808C42400C0020, 0x3028100840801000),
|
| 928 |
+
B(0x4000000410078488, 0x501000000620000),
|
| 929 |
+
B(0x90080001421020A4, 0x4118400101060406),
|
| 930 |
+
B(0x280420004855, 0xD200100400820000),
|
| 931 |
+
B(0xA0063423444, 0x41002C15811008),
|
| 932 |
+
B(0x200061201808102, 0x4286969000200002),
|
| 933 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 934 |
+
B(0x4001A04880402000, 0x8100824080000001),
|
| 935 |
+
B(0x60201D8300408190, 0x2010020920200000),
|
| 936 |
+
B(0x20018C04908019, 0x2010884002002040),
|
| 937 |
+
B(0x800000000C40810, 0x680100081150000D),
|
| 938 |
+
B(0x2002002000040040, 0x8810049000010600),
|
| 939 |
+
B(0x41618A0300040040, 0x21200200A421801),
|
| 940 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 941 |
+
B(0x10208018C1020A20, 0x84C0432240610014),
|
| 942 |
+
B(0x5A04001400412854, 0x8A44006000010002),
|
| 943 |
+
B(0x13000C0810072432, 0x50049001021104),
|
| 944 |
+
B(0x400048801142130, 0x4C1204100226010C),
|
| 945 |
+
B(0x80001048, 0x408800104000080),
|
| 946 |
+
B(0x8104868204040412, 0x22244202000081),
|
| 947 |
+
B(0x8104868204040412, 0x22244202000081),
|
| 948 |
+
B(0x4140001000240440, 0x80209004410004E),
|
| 949 |
+
B(0x800800000100, 0xB111820100000002),
|
| 950 |
+
B(0x404240004220, 0x2110402802050080),
|
| 951 |
+
B(0x284010400004040, 0x100245002502020),
|
| 952 |
+
B(0x14880A100114010, 0x400208080010024),
|
| 953 |
+
B(0x4100004040440648, 0x10030D838041A80),
|
| 954 |
+
B(0x32004000210, 0x4010225C88014000),
|
| 955 |
+
B(0x2240180C0800002, 0x4151050280000100),
|
| 956 |
+
B(0x2010A12002000042, 0x189051442010000),
|
| 957 |
+
B(0x4060050080121883, 0x8250C10001000141),
|
| 958 |
+
B(0x10000000044100, 0x8401084010261009),
|
| 959 |
+
B(0xA00028040000, 0x2003224000002000),
|
| 960 |
+
B(0x2060009001000020, 0x1000432022020228),
|
| 961 |
+
B(0x404200000883080, 0x1080800848245000),
|
| 962 |
+
B(0x240000402080, 0xCA0820814210502),
|
| 963 |
+
B(0x200040200080A02C, 0xB890290400080000),
|
| 964 |
+
B(0x800000000300482, 0x9203008100100013),
|
| 965 |
+
B(0x8000210202042000, 0x22642104004C2400),
|
| 966 |
+
B(0x1040400805000401, 0x2A0300102C80010),
|
| 967 |
+
B(0x8010A01088020000, 0x122106105A06A030),
|
| 968 |
+
B(0x8000C00001010494, 0x130A1A20404120),
|
| 969 |
+
B(0x4B084010844290, 0x10A08008900840),
|
| 970 |
+
B(0x1180001802460000, 0xB08000034C82004),
|
| 971 |
+
B(0x4001880060028029, 0x204040002401000),
|
| 972 |
+
B(0x8021A0001308002A, 0x97001822040040),
|
| 973 |
+
B(0xC00000009A020AC1, 0x1000080900400),
|
| 974 |
+
B(0x60010110001990, 0x4000880900400000),
|
| 975 |
+
B(0x10290402401200, 0x230080402C08),
|
| 976 |
+
B(0x4220000219012000, 0x140204804100008),
|
| 977 |
+
B(0x1400200100002, 0x8E62200414128),
|
| 978 |
+
B(0x402808502004403, 0x20049100C0284520),
|
| 979 |
+
B(0xB30041004280280, 0x10020464DB200308),
|
| 980 |
+
B(0x440010800808, 0xA0102E295812100),
|
| 981 |
+
B(0x10008000B000, 0x2000058583220200),
|
| 982 |
+
B(0x2000844000000100, 0x2000024C60800800),
|
| 983 |
+
B(0x110000400100028, 0x24052304508004),
|
| 984 |
+
B(0x8458000000840004, 0x118006463400001),
|
| 985 |
+
B(0x804008000040050, 0x41044890228000),
|
| 986 |
+
B(0x20000050000400, 0x80A101824A00086),
|
| 987 |
+
B(0x600080404000020, 0x100007322480005),
|
| 988 |
+
B(0xD082200020020008, 0x642000630120001),
|
| 989 |
+
B(0x10000100040230, 0x8048114733320002),
|
| 990 |
+
B(0x20200442002A880A, 0x8200002CB4B8052),
|
| 991 |
+
B(0x290080000000, 0xA41297838F40D),
|
| 992 |
+
B(0x800205000080, 0xF221232039874400),
|
| 993 |
+
B(0x1444002004880C20, 0xC4100049144200),
|
| 994 |
+
B(0x4500080000800, 0x280100002482C842),
|
| 995 |
+
B(0x281240881008, 0x204084004C101900),
|
| 996 |
+
B(0x1444002004880C20, 0xC4100049144200),
|
| 997 |
+
B(0x4500080000800, 0x280100002482C842),
|
| 998 |
+
B(0xC0010928430540, 0x92041902180),
|
| 999 |
+
B(0x1051001208A, 0x4900064800C20640),
|
| 1000 |
+
B(0x882020418C00000, 0x30004040092A821),
|
| 1001 |
+
B(0x224404002004268C, 0x202500204C7D254),
|
| 1002 |
+
B(0x290080000000, 0xA41297838F40D),
|
| 1003 |
+
};
|
| 1004 |
+
constexpr Bitboard JanggiElephantMagicInit[SQUARE_NB] = {
|
| 1005 |
+
B(0xC502282200061400, 0x2D07081241D90200),
|
| 1006 |
+
B(0xC502282200061400, 0x2D07081241D90200),
|
| 1007 |
+
B(0x8084810022440C2, 0x81402202004),
|
| 1008 |
+
B(0x80204010A800500, 0x5000021001740218),
|
| 1009 |
+
B(0x8048100401208000, 0x2001000390000044),
|
| 1010 |
+
B(0x202080020000000, 0x4010800010090424),
|
| 1011 |
+
B(0x4081A0480073200, 0x100000A010406000),
|
| 1012 |
+
B(0x4081A0480073200, 0x100000A010406000),
|
| 1013 |
+
B(0x2040450004000C40, 0x8400000006302),
|
| 1014 |
+
B(0x84010410018201, 0xA00A00000100000),
|
| 1015 |
+
B(0x840091030C00040, 0x1400008200023400),
|
| 1016 |
+
B(0x801058C0A0022, 0xC1920480010034),
|
| 1017 |
+
B(0x80B4004800840800, 0x4080210A42040010),
|
| 1018 |
+
B(0x400402221000445, 0x80321200408040),
|
| 1019 |
+
B(0x4028142401012A00, 0x4005009000104448),
|
| 1020 |
+
B(0x1440102040800220, 0x82800010A082000),
|
| 1021 |
+
B(0x4100040300C00200, 0x800805100120000),
|
| 1022 |
+
B(0x8200080061100, 0x2000101400000),
|
| 1023 |
+
B(0x2000100410070001, 0x40818200B0900410),
|
| 1024 |
+
B(0x400088020080000, 0x4A000402000CA0),
|
| 1025 |
+
B(0x1402040410004000, 0x9840044504040),
|
| 1026 |
+
B(0x20800088A00A0400, 0x1000020100180),
|
| 1027 |
+
B(0x2001820520308201, 0x2008003404349000),
|
| 1028 |
+
B(0x4004808022100, 0x8001000008081080),
|
| 1029 |
+
B(0x102041041100425, 0x840400180B100104),
|
| 1030 |
+
B(0x8806446000800214, 0x404402100010000),
|
| 1031 |
+
B(0x8200141409C04101, 0x209030004A00D00),
|
| 1032 |
+
B(0x8806004800880080, 0x1560004201000A01),
|
| 1033 |
+
B(0x4200050600200090, 0x1CD0000000000421),
|
| 1034 |
+
B(0x4820100022408100, 0x101404080320),
|
| 1035 |
+
B(0x2A000A0A08080080, 0x1C02808000C2C0),
|
| 1036 |
+
B(0x8808425040040014, 0x2021000100020),
|
| 1037 |
+
B(0x5282104044A0020, 0x6B402104200008),
|
| 1038 |
+
B(0x4001091040068120, 0x202000004003031),
|
| 1039 |
+
B(0x4001091040068120, 0x202000004003031),
|
| 1040 |
+
B(0x98040200A0214344, 0xA00300840010),
|
| 1041 |
+
B(0x82508040A40808A, 0x40010000110042),
|
| 1042 |
+
B(0x4400100101023, 0x450C8480040022),
|
| 1043 |
+
B(0x210588880010800, 0x800A000108018102),
|
| 1044 |
+
B(0x9400010144400, 0xC00010100018000),
|
| 1045 |
+
B(0x20A0400100040004, 0x1242000101002040),
|
| 1046 |
+
B(0x8022900040001001, 0x100000014000260),
|
| 1047 |
+
B(0x51004124000A080, 0x40098400000002),
|
| 1048 |
+
B(0x2158040001080022, 0x80009238401222),
|
| 1049 |
+
B(0xA0103A0000802220, 0x20000200400010),
|
| 1050 |
+
B(0x1101001208240, 0x100000800001064),
|
| 1051 |
+
B(0x821020002090081, 0x5840D0010290280),
|
| 1052 |
+
B(0x821020002090081, 0x5840D0010290280),
|
| 1053 |
+
B(0x10400C1042000400, 0x4005000000440200),
|
| 1054 |
+
B(0x844022008804820, 0x1000800100118000),
|
| 1055 |
+
B(0x10802A9800800139, 0x4802840100842200),
|
| 1056 |
+
B(0x4000A008200081, 0x4001100200402000),
|
| 1057 |
+
B(0x200000008108400, 0x1000C00008080020),
|
| 1058 |
+
B(0x120C11500100081, 0x440300308041100),
|
| 1059 |
+
B(0x8080040080060100, 0xC00101B0040028),
|
| 1060 |
+
B(0x901420A00110000, 0x8200010044700280),
|
| 1061 |
+
B(0x140080080410000, 0x808040000C001001),
|
| 1062 |
+
B(0x80210C0200A0008, 0x88088004600201),
|
| 1063 |
+
B(0x8000004202020301, 0x2100142104002000),
|
| 1064 |
+
B(0x1101011210004880, 0x8500840400000000),
|
| 1065 |
+
B(0x40208802004800, 0x8080806009011240),
|
| 1066 |
+
B(0x800000140408880, 0xC001018004060040),
|
| 1067 |
+
B(0xC008080420500, 0x8024A10000000000),
|
| 1068 |
+
B(0x2800000000400010, 0x44001C00400408),
|
| 1069 |
+
B(0xA804008001200408, 0x202000020001000),
|
| 1070 |
+
B(0xC08288805004080, 0x200042000800004),
|
| 1071 |
+
B(0xA40A01000080012, 0x8800080042408),
|
| 1072 |
+
B(0x2200100000100810, 0x800200010000100),
|
| 1073 |
+
B(0x9881800004040001, 0x8058100100884004),
|
| 1074 |
+
B(0x820000044020014, 0x4AA00010245012),
|
| 1075 |
+
B(0x820000044020014, 0x4AA00010245012),
|
| 1076 |
+
B(0x4000080240000808, 0x10100022054000),
|
| 1077 |
+
B(0x5002000840101, 0x202020004000A00),
|
| 1078 |
+
B(0x1188008200008402, 0x8088100020A2204),
|
| 1079 |
+
B(0x304012004044080, 0x8028108818006010),
|
| 1080 |
+
B(0x102210000008400, 0x1008000200380002),
|
| 1081 |
+
B(0x51410E114200, 0x100C00084000000),
|
| 1082 |
+
B(0x5001242320218, 0x800025000040040),
|
| 1083 |
+
B(0x4008000200008190, 0x400020021000000),
|
| 1084 |
+
B(0x10910022F0040, 0x450084400040001),
|
| 1085 |
+
B(0x180010810000040, 0x4004100040040),
|
| 1086 |
+
B(0x1088801424062010, 0x400084010030401),
|
| 1087 |
+
B(0x3000120408000040, 0x10802001080A4051),
|
| 1088 |
+
B(0x200008420, 0x40C0100020008804),
|
| 1089 |
+
B(0x1048C000004000, 0x4220120804004000),
|
| 1090 |
+
B(0x404A180000000E, 0x4C30412008110102),
|
| 1091 |
+
B(0x400000404202005, 0x800808550EC40044),
|
| 1092 |
+
B(0x282000200212010, 0x8001C0C102000210),
|
| 1093 |
+
B(0x9012240000008100, 0x280CA04010040000),
|
| 1094 |
+
B(0x2000C04001020C00, 0x2002010101042000),
|
| 1095 |
+
B(0x1010000204408408, 0x8008004800E0C4A),
|
| 1096 |
+
B(0x800286801000025, 0x8402401040050088),
|
| 1097 |
+
B(0x40002000A0880000, 0x8400300108082086),
|
| 1098 |
+
B(0x2080004404011, 0x20C080400100001),
|
| 1099 |
+
B(0xB0010218100800, 0x8040200482C14103),
|
| 1100 |
+
B(0x8011035000000C20, 0x4200044043200040),
|
| 1101 |
+
B(0x804008000040050, 0x41044890228000),
|
| 1102 |
+
B(0x80000400A0020020, 0x5308022021000000),
|
| 1103 |
+
B(0x2118200000008004, 0x4141014004423D00),
|
| 1104 |
+
B(0x90C0000200008040, 0x41041062000082),
|
| 1105 |
+
B(0x1D000100941204, 0x12402001200420),
|
| 1106 |
+
B(0x8C0040400400065, 0x22300B408100000),
|
| 1107 |
+
B(0x8C0040400400065, 0x22300B408100000),
|
| 1108 |
+
B(0x802802044600000, 0x1210100401030082),
|
| 1109 |
+
B(0x9400488010000000, 0x8005404902040000),
|
| 1110 |
+
B(0x2214020200001, 0x40102100820200),
|
| 1111 |
+
B(0x2022000000800000, 0x6400440108480),
|
| 1112 |
+
B(0x110000400100028, 0x24052304508004),
|
| 1113 |
+
B(0x848820140010000, 0x201012500A000),
|
| 1114 |
+
B(0x848820140010000, 0x201012500A000),
|
| 1115 |
+
B(0x100100000000C4, 0x208004084048201),
|
| 1116 |
+
B(0x100500000000290, 0x10102818208000),
|
| 1117 |
+
B(0x2800414000C000, 0x20004005001301),
|
| 1118 |
+
B(0x698180005101241, 0x10002014800210),
|
| 1119 |
+
B(0x20000080000009, 0x440340C040),
|
| 1120 |
+
B(0x1C0220200290020, 0x42100004004011C0),
|
| 1121 |
+
B(0x200E620018320208, 0x440410402),
|
| 1122 |
+
B(0xD04101010004024, 0x20000121104010A4),
|
| 1123 |
+
B(0x220400000A80040, 0x806080020810010C),
|
| 1124 |
+
B(0xA000200000000080, 0x1040801A0081208),
|
| 1125 |
+
};
|
| 1126 |
+
constexpr Bitboard CannonDiagMagicInit[SQUARE_NB] = {
|
| 1127 |
+
B(0x811801000400, 0x312260280280202),
|
| 1128 |
+
B(0x44A000402022680, 0x1020224880420005),
|
| 1129 |
+
B(0x8000C80800200880, 0x2000810060080C0),
|
| 1130 |
+
B(0x2010300240428040, 0x40240002C004E30),
|
| 1131 |
+
B(0x1018010404010004, 0x1001010018081E0),
|
| 1132 |
+
B(0x2042040010080090, 0x100000008410300),
|
| 1133 |
+
B(0x400080020102000, 0x4500005300000000),
|
| 1134 |
+
B(0x2D00C80420010200, 0x804003280020008),
|
| 1135 |
+
B(0x8038820024420, 0x6010010080012040),
|
| 1136 |
+
B(0x1202028004200088, 0x50018100004000C6),
|
| 1137 |
+
B(0xA02010F0410081, 0x20013001000009A),
|
| 1138 |
+
B(0x4013002041030588, 0x4802004110000004),
|
| 1139 |
+
B(0x110020802000081, 0x202001800908002),
|
| 1140 |
+
B(0x22010404103, 0x2020882080491200),
|
| 1141 |
+
B(0x60000220400580, 0x85902800100100),
|
| 1142 |
+
B(0x100080800050100, 0x200010220021088),
|
| 1143 |
+
B(0x8088840404200080, 0x140011040104000),
|
| 1144 |
+
B(0x4008508080082015, 0x8010100200580048),
|
| 1145 |
+
B(0x4010400420201001, 0x260002080A80808),
|
| 1146 |
+
B(0xC2002004A0008008, 0x8020082000110840),
|
| 1147 |
+
B(0xA000A0820042400, 0x810408082100420),
|
| 1148 |
+
B(0x80231808100004, 0x204002000800400),
|
| 1149 |
+
B(0x8296144044004900, 0x4A1003008001840),
|
| 1150 |
+
B(0x80A0020A0011008, 0x800104846080810),
|
| 1151 |
+
B(0x803800801041000, 0x1030500102000404),
|
| 1152 |
+
B(0x240C00900800850, 0x1804000108810000),
|
| 1153 |
+
B(0x800400000088800, 0x800021801020000),
|
| 1154 |
+
B(0x84800409300082, 0x1002D40680044000),
|
| 1155 |
+
B(0xA110C0000200010, 0x401010001200260),
|
| 1156 |
+
B(0x8200160204100004, 0x8040004004002022),
|
| 1157 |
+
B(0x10001000000100C0, 0x84002811000200),
|
| 1158 |
+
B(0x2000080020014001, 0x42002020000102),
|
| 1159 |
+
B(0x109040044020018, 0x2020400202001000),
|
| 1160 |
+
B(0x620000CD0108, 0x40040201008000),
|
| 1161 |
+
B(0xA1402200A0020, 0x81400400300912),
|
| 1162 |
+
B(0x20020CF100018020, 0x801A14086404000),
|
| 1163 |
+
B(0x800801844001, 0x11621488425000),
|
| 1164 |
+
B(0x10201004A8080, 0x100A000801000010),
|
| 1165 |
+
B(0x2800411001000800, 0x80224084900020),
|
| 1166 |
+
B(0x40400024028100, 0x501000400230060),
|
| 1167 |
+
B(0x404808010080, 0x1201000400100004),
|
| 1168 |
+
B(0x80802005200, 0x2000200008A0000),
|
| 1169 |
+
B(0x20800080000022, 0x80040810002010),
|
| 1170 |
+
B(0x40016004808240, 0x400114000801100),
|
| 1171 |
+
B(0x8410004204240, 0x20011000604050),
|
| 1172 |
+
B(0x8000C1009008268, 0x201004000209000),
|
| 1173 |
+
B(0x10240C000920, 0xE000A5C14003002),
|
| 1174 |
+
B(0x10184024280008, 0x90240802000000),
|
| 1175 |
+
B(0x40889081081000, 0x8010050008800000),
|
| 1176 |
+
B(0x100008C089000019, 0x802032014020010),
|
| 1177 |
+
B(0x401C1804C00, 0x402501002002020),
|
| 1178 |
+
B(0x200022000920D0, 0x8000800081300020),
|
| 1179 |
+
B(0x801000400011, 0x400100044010226),
|
| 1180 |
+
B(0x4A04010100100000, 0x500400080400000),
|
| 1181 |
+
B(0xA000050200080000, 0x8500090001010000),
|
| 1182 |
+
B(0x40400040001812, 0x4403000400100A0),
|
| 1183 |
+
B(0x20C2250203020004, 0x210001C000080000),
|
| 1184 |
+
B(0x21000408C6020001, 0x4200830012D1001),
|
| 1185 |
+
B(0x840082016080A210, 0x2400080801081008),
|
| 1186 |
+
B(0x40001020000, 0x4041240200083120),
|
| 1187 |
+
B(0x2C04030010C0818, 0xA670002000818100),
|
| 1188 |
+
B(0x4704A07085000510, 0x914001000040),
|
| 1189 |
+
B(0x900210304100100, 0x1010004000281840),
|
| 1190 |
+
B(0x8202920002002040, 0x810012000003),
|
| 1191 |
+
B(0x4001400100050, 0x1144000408002000),
|
| 1192 |
+
B(0x5900200020008100, 0x40200020002004),
|
| 1193 |
+
B(0x301020002000480, 0x202000C0004),
|
| 1194 |
+
B(0x20D000201104040, 0x34840100020010),
|
| 1195 |
+
B(0x800004200080408, 0x40184200100240),
|
| 1196 |
+
B(0x8430080100404020, 0x90042100244500),
|
| 1197 |
+
B(0x3800100010220062, 0x50404030200218),
|
| 1198 |
+
B(0x42E20008002020, 0x2000008200200300),
|
| 1199 |
+
B(0xE488008280A004, 0x200001010CC80000),
|
| 1200 |
+
B(0x6018010041109810, 0x800002000242041A),
|
| 1201 |
+
B(0x40A8002438980, 0x8000810008208009),
|
| 1202 |
+
B(0x401000480040100, 0x286800404002212),
|
| 1203 |
+
B(0x821030000100009, 0x2000090200A00000),
|
| 1204 |
+
B(0x20000100C0008028, 0x5000000100400082),
|
| 1205 |
+
B(0x80A000048030080, 0x200000120200008),
|
| 1206 |
+
B(0x6300280800204003, 0x48000105C0040100),
|
| 1207 |
+
B(0x83008802420C0200, 0x2008020200080100),
|
| 1208 |
+
B(0x1050C3102200042, 0x20103900010008),
|
| 1209 |
+
B(0x8040902021408180, 0x12000021806200A4),
|
| 1210 |
+
B(0x3008204008C10004, 0x680110100010401),
|
| 1211 |
+
B(0x204321100421000, 0x400E204820494000),
|
| 1212 |
+
B(0x8000044022404048, 0x4024010090024021),
|
| 1213 |
+
B(0x140201424050, 0x280A000130008000),
|
| 1214 |
+
B(0x900340808004002, 0x21026008000380),
|
| 1215 |
+
B(0x82808000300444, 0x20002000A2001141),
|
| 1216 |
+
B(0x140180100406002, 0x4004480001000004),
|
| 1217 |
+
B(0x4808420800841900, 0x14008C0041000000),
|
| 1218 |
+
B(0x2008600009000480, 0x9008020001400000),
|
| 1219 |
+
B(0x2000100800100002, 0x2004100820210020),
|
| 1220 |
+
B(0x2062010401A8100, 0x12200108420090),
|
| 1221 |
+
B(0x1403188200032, 0x40048166105000),
|
| 1222 |
+
B(0x410020020140041, 0x4400348102940040),
|
| 1223 |
+
B(0x414040209208041, 0x4402400028B004),
|
| 1224 |
+
B(0x8008010100421202, 0x401418002008800),
|
| 1225 |
+
B(0x4000020010062200, 0xA02009148048000),
|
| 1226 |
+
B(0x4443080082008B, 0x104014022801010),
|
| 1227 |
+
B(0x42B440A0C000800, 0x9001009016111020),
|
| 1228 |
+
B(0x400000214002, 0x8008080209020009),
|
| 1229 |
+
B(0x480C414A001900, 0x3400100400210200),
|
| 1230 |
+
B(0x1006008800604, 0x20240004030A050),
|
| 1231 |
+
B(0x4C022401002A8300, 0x405008400000600),
|
| 1232 |
+
B(0x3104000800A1042, 0x2004800204406200),
|
| 1233 |
+
B(0xA09010280008200C, 0x4004000208C4168),
|
| 1234 |
+
B(0x2800401120C20120, 0x4A00450200022030),
|
| 1235 |
+
B(0x88001800304C0200, 0x204288102080000),
|
| 1236 |
+
B(0x8044004201440101, 0x400820080C024022),
|
| 1237 |
+
B(0xA000100C080, 0x4B40341004008081),
|
| 1238 |
+
B(0x94802001300810, 0x140206008000800),
|
| 1239 |
+
B(0x40002020202820, 0x280680404000040),
|
| 1240 |
+
B(0xA820800004200, 0x80E1401012000491),
|
| 1241 |
+
B(0x804000010020C000, 0x9403020200802000),
|
| 1242 |
+
B(0x8C0001284201400, 0xC000100C01620800),
|
| 1243 |
+
B(0x4010004002200414, 0x403080080200000),
|
| 1244 |
+
B(0x140400A100800101, 0x10054C031080400),
|
| 1245 |
+
B(0x20012C2400880082, 0x7000880020C03200),
|
| 1246 |
+
B(0x204040300004, 0x840800041101002),
|
| 1247 |
+
};
|
| 1248 |
+
constexpr Bitboard NightriderMagicInit[SQUARE_NB] = {
|
| 1249 |
+
B(0x8008100800020052, 0x8001440000000000),
|
| 1250 |
+
B(0x24028400210090, 0x4200000000021),
|
| 1251 |
+
B(0x22002020A0200800, 0x100820120000082),
|
| 1252 |
+
B(0x424009020002200, 0x84810D4100002A),
|
| 1253 |
+
B(0x404008020000600, 0x1000202000000081),
|
| 1254 |
+
B(0x21020001000680, 0x2140200000000000),
|
| 1255 |
+
B(0x2060021100000608, 0x8080020040000C8),
|
| 1256 |
+
B(0x910C20408001200, 0x80A4030800000500),
|
| 1257 |
+
B(0x2C40100010400009, 0x40400000200000C),
|
| 1258 |
+
B(0x4090210034400004, 0x2104008000000),
|
| 1259 |
+
B(0x1082008040840180, 0x140082080000000F),
|
| 1260 |
+
B(0x8041001002101002, 0x8C002000000),
|
| 1261 |
+
B(0x102205086800080, 0x84400030020D600),
|
| 1262 |
+
B(0x2120080A32044E0, 0x400A02000016000),
|
| 1263 |
+
B(0x6040003021040A0, 0x8000200206040040),
|
| 1264 |
+
B(0x8001000008104082, 0x4002104202000114),
|
| 1265 |
+
B(0x100400081080000, 0x201020020000020),
|
| 1266 |
+
B(0x203000090010040, 0x140040010000000C),
|
| 1267 |
+
B(0x9140000108100040, 0x4004004C08450010),
|
| 1268 |
+
B(0x4402A12120020000, 0x450C002C000040C),
|
| 1269 |
+
B(0x2028000200120800, 0x100100401001000),
|
| 1270 |
+
B(0x800890081000, 0x10700A080180048),
|
| 1271 |
+
B(0x41040C4008400, 0x8080001000080020),
|
| 1272 |
+
B(0x2404000001060401, 0x10800116C0009110),
|
| 1273 |
+
B(0x2001810020400110, 0xA0100800000480E2),
|
| 1274 |
+
B(0x4081400120200218, 0x8800410800000000),
|
| 1275 |
+
B(0x4C020020300E00, 0x810800000000808),
|
| 1276 |
+
B(0xC8002200100108, 0x4860040380000100),
|
| 1277 |
+
B(0x8000E0000804080, 0x4C800000000000),
|
| 1278 |
+
B(0x211880010934041, 0x31000040000188),
|
| 1279 |
+
B(0x4800801000003140, 0x80000000028),
|
| 1280 |
+
B(0x61240410840004, 0x230100050000002),
|
| 1281 |
+
B(0x61240410840004, 0x230100050000002),
|
| 1282 |
+
B(0x4020008000C04C42, 0x3000021000000804),
|
| 1283 |
+
B(0x829808040040840, 0x288010000002200),
|
| 1284 |
+
B(0xA0420002040084, 0x1008604002000048),
|
| 1285 |
+
B(0x10200004980, 0x2010410028000000),
|
| 1286 |
+
B(0x4900200420100010, 0x1000A00401001898),
|
| 1287 |
+
B(0x20000801600134, 0xC0002400000021C),
|
| 1288 |
+
B(0x200040021010001, 0x8800000400000088),
|
| 1289 |
+
B(0x88000824, 0x8800000040010000),
|
| 1290 |
+
B(0x40000000200000D0, 0x8200004000AA84),
|
| 1291 |
+
B(0x1002000000812002, 0x4000001C1008480),
|
| 1292 |
+
B(0xC00010420003, 0x400002C00000004),
|
| 1293 |
+
B(0x208400008008040, 0x111004280000C0),
|
| 1294 |
+
B(0x60004000E800241, 0x202001000010040),
|
| 1295 |
+
B(0x200004800061, 0x1109100480045800),
|
| 1296 |
+
B(0x52880000200001, 0x608204100012DA0),
|
| 1297 |
+
B(0x1000429008100800, 0x2008001000006018),
|
| 1298 |
+
B(0x8490024200123001, 0x1041400080020),
|
| 1299 |
+
B(0x810001020200014, 0x2C50500220000020),
|
| 1300 |
+
B(0x20234B8000A0080, 0x4091200200000020),
|
| 1301 |
+
B(0x400401010012600, 0xE00200000000020),
|
| 1302 |
+
B(0x8040C00804004000, 0x8208014000000083),
|
| 1303 |
+
B(0x102000410001044, 0x8200000000000),
|
| 1304 |
+
B(0x102000410001044, 0x8200000000000),
|
| 1305 |
+
B(0x242E00508040001, 0x80028000000000),
|
| 1306 |
+
B(0x40810368002080, 0x4008080000224),
|
| 1307 |
+
B(0x48200010208800, 0x1020800C000022),
|
| 1308 |
+
B(0x220C4018008000, 0x282100130000211),
|
| 1309 |
+
B(0x8008004400100, 0xC128208200020400),
|
| 1310 |
+
B(0x44C004100020, 0x4008004000011000),
|
| 1311 |
+
B(0x1008000000600008, 0x41C00180480183),
|
| 1312 |
+
B(0x10080000, 0x404090018800020A),
|
| 1313 |
+
B(0x4500000000004200, 0x45200200A0140),
|
| 1314 |
+
B(0x2040000000240003, 0x8020080288000600),
|
| 1315 |
+
B(0x2040000000240003, 0x8020080288000600),
|
| 1316 |
+
B(0x2040000000240003, 0x8020080288000600),
|
| 1317 |
+
B(0x48000000020A0080, 0x1000020200088),
|
| 1318 |
+
B(0xA00000008404200, 0x4204010101001004),
|
| 1319 |
+
B(0x10008030082, 0x2002800200100104),
|
| 1320 |
+
B(0x44080002460010, 0x8007804100082D00),
|
| 1321 |
+
B(0x98400040001802, 0x913002002020301),
|
| 1322 |
+
B(0xA0400501040028, 0x8040481824002024),
|
| 1323 |
+
B(0x4C0A0600100080A0, 0x8005000080008200),
|
| 1324 |
+
B(0x802124000860008, 0x1009081800100080),
|
| 1325 |
+
B(0x4000110040011000, 0x4080422200001081),
|
| 1326 |
+
B(0x422008008000080, 0x4001020C00000202),
|
| 1327 |
+
B(0x8000202008002101, 0xA008010000040),
|
| 1328 |
+
B(0x804200020000020, 0xE0B0008010000001),
|
| 1329 |
+
B(0x14040200002, 0x2000000006000004),
|
| 1330 |
+
B(0x45000002010020, 0xA4040008400000),
|
| 1331 |
+
B(0x800040020204184A, 0x10000402000006),
|
| 1332 |
+
B(0x908000080400004, 0x5040100038400050),
|
| 1333 |
+
B(0x3100002000040014, 0x804008008120000),
|
| 1334 |
+
B(0x6002200000020008, 0xC011409081008881),
|
| 1335 |
+
B(0xC02004060280001, 0x2003004010220254),
|
| 1336 |
+
B(0x16410101, 0x100040108600000),
|
| 1337 |
+
B(0x100000000200000, 0x201200010800200),
|
| 1338 |
+
B(0xC400000004090002, 0x808808010224000A),
|
| 1339 |
+
B(0xC400000004090002, 0x808808010224000A),
|
| 1340 |
+
B(0x1000000000890001, 0x4050002001040),
|
| 1341 |
+
B(0x618000000008484, 0x40000A0150000D4),
|
| 1342 |
+
B(0x500000400009004, 0x1100200204100A1),
|
| 1343 |
+
B(0x6006000008080480, 0x100254800C00904),
|
| 1344 |
+
B(0x6006000008080480, 0x100254800C00904),
|
| 1345 |
+
B(0x404808040044040, 0x4202020040000200),
|
| 1346 |
+
B(0x2000080440810, 0x9044008844920000),
|
| 1347 |
+
B(0x40204418040, 0x412000204080010),
|
| 1348 |
+
B(0x88400820040248, 0x408040010C040800),
|
| 1349 |
+
B(0x8110084000803, 0x102000000000),
|
| 1350 |
+
B(0x4000040140001100, 0x80808102002),
|
| 1351 |
+
B(0x100480044020008, 0x4601000100084488),
|
| 1352 |
+
B(0x6200204420840, 0x41802043B0000),
|
| 1353 |
+
B(0x540000010091010, 0x409004800A01208),
|
| 1354 |
+
B(0x300040008000008, 0x2030080800010000),
|
| 1355 |
+
B(0x408804010400090, 0x4008100800004000),
|
| 1356 |
+
B(0x401600A0000080, 0x8400200201002200),
|
| 1357 |
+
B(0x44000000100000, 0x1140040210000001),
|
| 1358 |
+
B(0xC6000000D00804, 0x1050020C0081090C),
|
| 1359 |
+
B(0x4098002, 0x900000C045008300),
|
| 1360 |
+
B(0x245190008020, 0x2000C00100041000),
|
| 1361 |
+
B(0x1000000A100046, 0x88000084800004),
|
| 1362 |
+
B(0x1000000220240002, 0x400000401001088),
|
| 1363 |
+
B(0x1000000220240002, 0x400000401001088),
|
| 1364 |
+
B(0x820000118808000, 0x8000048161004A),
|
| 1365 |
+
B(0x1100000000071A02, 0x500146102000048),
|
| 1366 |
+
B(0x610000, 0x10010080040641),
|
| 1367 |
+
B(0x2000010441A0044, 0x500800502020188),
|
| 1368 |
+
B(0xA80000000180000, 0x234402012110080),
|
| 1369 |
+
};
|
| 1370 |
+
constexpr Bitboard GrasshopperMagicHInit[SQUARE_NB] = {
|
| 1371 |
+
B(0x120000880110000, 0x1008000000020020),
|
| 1372 |
+
B(0x24200C080840A052, 0x2004004000010008),
|
| 1373 |
+
B(0xC030024000228800, 0x4000010400000020),
|
| 1374 |
+
B(0x1A0020802008802, 0x206010208000),
|
| 1375 |
+
B(0x12002000D001024, 0x80100800090138),
|
| 1376 |
+
B(0x4220010000241010, 0x3098000602001500),
|
| 1377 |
+
B(0x401010004801040, 0x8000280480100000),
|
| 1378 |
+
B(0x820082024921836, 0x220028000),
|
| 1379 |
+
B(0x100400502411400, 0x220402120240D14),
|
| 1380 |
+
B(0x880202020010404, 0xA80202510000),
|
| 1381 |
+
B(0x140002801000018, 0x1000346490040),
|
| 1382 |
+
B(0x120000880110000, 0x1008000000020020),
|
| 1383 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 1384 |
+
B(0x8420060100020000, 0x800280400000120),
|
| 1385 |
+
B(0x4010020018010, 0x40A00001100000),
|
| 1386 |
+
B(0x40006A0004000200, 0x40000000110),
|
| 1387 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 1388 |
+
B(0x8908A20028110011, 0x800080000001A114),
|
| 1389 |
+
B(0x200042000080F009, 0x20001000004000),
|
| 1390 |
+
B(0x2820008820100, 0x10002400058000B9),
|
| 1391 |
+
B(0x6083100420008050, 0x4040012600280080),
|
| 1392 |
+
B(0x216020000000446, 0x4080204000000211),
|
| 1393 |
+
B(0x340140003002089, 0x2402008000000911),
|
| 1394 |
+
B(0xD01004008030400, 0x104000408104420),
|
| 1395 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 1396 |
+
B(0x8C0488120024214, 0x8414880202291),
|
| 1397 |
+
B(0x1010000060050000, 0x4000004050002602),
|
| 1398 |
+
B(0x4022983A0060000, 0x80000040010400),
|
| 1399 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 1400 |
+
B(0x6020101802002840, 0x31000003000004),
|
| 1401 |
+
B(0x9000420008840, 0x4881300000000210),
|
| 1402 |
+
B(0xA200808865, 0x41C0048023000128),
|
| 1403 |
+
B(0x31801100400000, 0x8802DC001221240),
|
| 1404 |
+
B(0x884000080200920, 0x1004002410401001),
|
| 1405 |
+
B(0x2400040000884, 0x421006208040C0),
|
| 1406 |
+
B(0x1404040B20001000, 0x8000824010800011),
|
| 1407 |
+
B(0x24100400060009, 0x112008025042410),
|
| 1408 |
+
B(0x1800040009040200, 0x180000A1004E408A),
|
| 1409 |
+
B(0x24100400060009, 0x112008025042410),
|
| 1410 |
+
B(0x4060402008080, 0xC240080000110000),
|
| 1411 |
+
B(0x20080100920020, 0x2002248010242052),
|
| 1412 |
+
B(0x10001010802050, 0x880000001C98420),
|
| 1413 |
+
B(0x4000800100420022, 0x502022010A00D0),
|
| 1414 |
+
B(0x4C18104500200885, 0x400880800),
|
| 1415 |
+
B(0x8080810081020090, 0x8000000000000),
|
| 1416 |
+
B(0x8000062812080201, 0x8004C8300800),
|
| 1417 |
+
B(0xC010220920198, 0x85000A08000),
|
| 1418 |
+
B(0x24100400060009, 0x112008025042410),
|
| 1419 |
+
B(0x80102204040, 0x1000000900000000),
|
| 1420 |
+
B(0x2080000004202804, 0x120880003461),
|
| 1421 |
+
B(0x102004090A4030, 0x801020589240),
|
| 1422 |
+
B(0x20001100814000A0, 0x420202000820004),
|
| 1423 |
+
B(0x100800000A000120, 0x208000800010000),
|
| 1424 |
+
B(0x1008205000040802, 0x80002000400040),
|
| 1425 |
+
B(0x1480000098008401, 0xA0010000581010),
|
| 1426 |
+
B(0x30C0008200100820, 0x102800080904834),
|
| 1427 |
+
B(0x4810821884000500, 0x4400000200000212),
|
| 1428 |
+
B(0x1811D00128A0180, 0x2500848803000000),
|
| 1429 |
+
B(0x41618A0300040040, 0x21200200A421801),
|
| 1430 |
+
B(0x80102204040, 0x1000000900000000),
|
| 1431 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 1432 |
+
B(0x8C890020410000A0, 0xA010000048000400),
|
| 1433 |
+
B(0x40006002210044, 0x600008000408000),
|
| 1434 |
+
B(0x1200447220090042, 0x80001000160012),
|
| 1435 |
+
B(0x48410010AB000000, 0x9200600000000100),
|
| 1436 |
+
B(0x2040000000240003, 0x8020080288000600),
|
| 1437 |
+
B(0x9080000088848088, 0x4010210500000041),
|
| 1438 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 1439 |
+
B(0x480100400024, 0x1004800018200000),
|
| 1440 |
+
B(0x808403080080200, 0x802601000000500),
|
| 1441 |
+
B(0x8C890020410000A0, 0xA010000048000400),
|
| 1442 |
+
B(0xA1808E0100108000, 0x2008000505000002),
|
| 1443 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 1444 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 1445 |
+
B(0x400014006000000, 0x10006000810001F5),
|
| 1446 |
+
B(0xC410062001414, 0x820080041B01044),
|
| 1447 |
+
B(0x20000800310, 0x430040000201000),
|
| 1448 |
+
B(0xA40010008000008, 0x4002200028000040),
|
| 1449 |
+
B(0xC00102000008021C, 0x10C2000A010E024),
|
| 1450 |
+
B(0x80004200104008, 0x50A00800C400020),
|
| 1451 |
+
B(0x20200080012542, 0x910F0040000402C0),
|
| 1452 |
+
B(0xB040100504000300, 0x24802002000040),
|
| 1453 |
+
B(0x800001000014008, 0x400031004000),
|
| 1454 |
+
B(0x100A40000004008, 0x2800200400200480),
|
| 1455 |
+
B(0x84008002041081C0, 0x8080500200000000),
|
| 1456 |
+
B(0x440090001012001, 0x4020004010),
|
| 1457 |
+
B(0x100A0028088020, 0x80040E00010020),
|
| 1458 |
+
B(0x2180808000810, 0xB018040A00040000),
|
| 1459 |
+
B(0x40C80920304C4001, 0x42800B200800000),
|
| 1460 |
+
B(0x85000425001000, 0x4810048020001100),
|
| 1461 |
+
B(0x600C000801000004, 0x8015084010200020),
|
| 1462 |
+
B(0x20020050000240C0, 0x100202008600800),
|
| 1463 |
+
B(0x38000050001220, 0x9200010200145900),
|
| 1464 |
+
B(0x1042108040005, 0x1402A0802201001),
|
| 1465 |
+
B(0x824240000C20400, 0x1000000400080010),
|
| 1466 |
+
B(0x84008002041081C0, 0x8080500200000000),
|
| 1467 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 1468 |
+
B(0x8000402308483, 0x20006020100100),
|
| 1469 |
+
B(0x80880120000080, 0x8000240100084),
|
| 1470 |
+
B(0x5840020004882001, 0x1004528000A00010),
|
| 1471 |
+
B(0x8001018800300002, 0x84010040804),
|
| 1472 |
+
B(0x180D10004000A008, 0xA001080008020004),
|
| 1473 |
+
B(0x400080B, 0x10A0000004010000),
|
| 1474 |
+
B(0x8080000200000, 0x2001000082004E0),
|
| 1475 |
+
B(0x40040001000C2000, 0x2024800001004008),
|
| 1476 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 1477 |
+
B(0x8000402308483, 0x20006020100100),
|
| 1478 |
+
B(0x400804A1000008, 0x1024104A0200010),
|
| 1479 |
+
B(0x2000200000, 0x1201011000802),
|
| 1480 |
+
B(0x100100000000C4, 0x208004084048201),
|
| 1481 |
+
B(0x400084000044, 0x100810140300),
|
| 1482 |
+
B(0x29040C0C01010, 0x300204010820080),
|
| 1483 |
+
B(0x1A808000020200, 0x1000000005210040),
|
| 1484 |
+
B(0x20000400150000, 0x85008020),
|
| 1485 |
+
B(0x40C040008184014, 0x8002AA00024010),
|
| 1486 |
+
B(0x202000081B00804, 0x10001002008),
|
| 1487 |
+
B(0x40011000210060, 0x6080C40000021004),
|
| 1488 |
+
B(0x2000200000, 0x1201011000802),
|
| 1489 |
+
B(0x4100480203840, 0x300080100804),
|
| 1490 |
+
B(0x2000200000, 0x1201011000802),
|
| 1491 |
+
};
|
| 1492 |
+
constexpr Bitboard GrasshopperMagicVInit[SQUARE_NB] = {
|
| 1493 |
+
B(0x202000812104400, 0x24800B01C0000303),
|
| 1494 |
+
B(0x340020400010D, 0x88060150C00400),
|
| 1495 |
+
B(0x400802040609, 0x49010200501A0002),
|
| 1496 |
+
B(0x8002680301000208, 0x628006C0C020200),
|
| 1497 |
+
B(0x20400209001C0804, 0xA044000800143110),
|
| 1498 |
+
B(0xC400082060010202, 0x4000480401014000),
|
| 1499 |
+
B(0x22500200144040, 0x8204820084704C00),
|
| 1500 |
+
B(0x8C1204009030020, 0x328400805000000),
|
| 1501 |
+
B(0x84800800D0001640, 0x200080040060108),
|
| 1502 |
+
B(0x804810208020040, 0x140010108020000),
|
| 1503 |
+
B(0x1102010B008004, 0x300208006220020),
|
| 1504 |
+
B(0x140080404A0A2428, 0x6308010100080),
|
| 1505 |
+
B(0x20444002120408, 0xA080010508010001),
|
| 1506 |
+
B(0x82011044000D02, 0x4112028620110809),
|
| 1507 |
+
B(0x81010831000C02, 0x408802085000000),
|
| 1508 |
+
B(0x81010831000C02, 0x408802085000000),
|
| 1509 |
+
B(0x920008920600040, 0x8053801004000028),
|
| 1510 |
+
B(0x81140283208300, 0x10040C004200420),
|
| 1511 |
+
B(0x103080022201, 0xC01000081312620),
|
| 1512 |
+
B(0x2200221100008, 0x1000408104000A4),
|
| 1513 |
+
B(0x4402088080042008, 0x210401501040340),
|
| 1514 |
+
B(0x898400202170001, 0x80040404208000),
|
| 1515 |
+
B(0x20080004051012, 0x5100048200081800),
|
| 1516 |
+
B(0x2320020000401018, 0x108501021040210),
|
| 1517 |
+
B(0x21080410A422021, 0x83040180008800),
|
| 1518 |
+
B(0x44E8100000408224, 0x20010008040400),
|
| 1519 |
+
B(0x1800240002810405, 0x23004820000020),
|
| 1520 |
+
B(0x80A0100400110, 0x80104020100C4028),
|
| 1521 |
+
B(0x1002050001222C0, 0x5100818004024020),
|
| 1522 |
+
B(0x104000200040, 0xC010A09800102000),
|
| 1523 |
+
B(0x1020003A058120, 0x450900809000302),
|
| 1524 |
+
B(0x40040045008B1, 0x202800400383010),
|
| 1525 |
+
B(0x4640200220034, 0x8800485420304000),
|
| 1526 |
+
B(0x5001042100084288, 0x110820001240080A),
|
| 1527 |
+
B(0x2002C04004010120, 0xA15008020880001),
|
| 1528 |
+
B(0x2800004080C4190, 0x890808280020080),
|
| 1529 |
+
B(0x40C0401000104000, 0x2020880008002580),
|
| 1530 |
+
B(0x40020C002400802, 0x801104010000000),
|
| 1531 |
+
B(0x44842000040080, 0x2050011084000400),
|
| 1532 |
+
B(0x4110040800000401, 0x2023810029008000),
|
| 1533 |
+
B(0x20884000840, 0x8017102004008000),
|
| 1534 |
+
B(0x10411104000480, 0x1414042000201001),
|
| 1535 |
+
B(0x220040000008, 0x800306021000000),
|
| 1536 |
+
B(0x41400A0008080, 0x501000298ACAD10),
|
| 1537 |
+
B(0x800240012831810, 0x80120004468050E),
|
| 1538 |
+
B(0x800005020801008, 0x20102400240000),
|
| 1539 |
+
B(0x20C00040C114C010, 0x88080820200C00),
|
| 1540 |
+
B(0x1044010100820081, 0x20080841004000),
|
| 1541 |
+
B(0x8041048400022, 0x8020836040005002),
|
| 1542 |
+
B(0x2001004010205, 0x8001002884042009),
|
| 1543 |
+
B(0x128088400087, 0x20008002201002),
|
| 1544 |
+
B(0x8084108040402000, 0x80809000A080400),
|
| 1545 |
+
B(0x408081840880, 0x201002088000040),
|
| 1546 |
+
B(0xA40180010280, 0x241004006000010),
|
| 1547 |
+
B(0x4204100080048140, 0x2002C4F104202020),
|
| 1548 |
+
B(0x100140A10204, 0x980200800840060),
|
| 1549 |
+
B(0x1005140010202048, 0x1442280800202815),
|
| 1550 |
+
B(0x2000082025008600, 0x1108400040600003),
|
| 1551 |
+
B(0x1005050648000, 0x200020240008002),
|
| 1552 |
+
B(0x202010208044000, 0x8210404060008),
|
| 1553 |
+
B(0x8011040402000210, 0xC840180408016004),
|
| 1554 |
+
B(0x404098801028, 0x80020A0001000400),
|
| 1555 |
+
B(0x404098801028, 0x80020A0001000400),
|
| 1556 |
+
B(0x80101002180140, 0x40C2080820000C0),
|
| 1557 |
+
B(0x208202081260800, 0x14090E4C04000050),
|
| 1558 |
+
B(0x4221201084004C2, 0x110480A011060),
|
| 1559 |
+
B(0x8000008421090204, 0x1C01010800024),
|
| 1560 |
+
B(0x8000008421090204, 0x1C01010800024),
|
| 1561 |
+
B(0x200180C840088A0, 0x401100400820000),
|
| 1562 |
+
B(0x10084043A021070, 0x202041600080200),
|
| 1563 |
+
B(0x210E6202001040C, 0x10100800080B0),
|
| 1564 |
+
B(0x848008021204002, 0x801004308100BAD),
|
| 1565 |
+
B(0xC082C0390A000601, 0x4040080189008),
|
| 1566 |
+
B(0x431200240210402D, 0x58102820000),
|
| 1567 |
+
B(0x202020100A0019B0, 0x4010C0D018000000),
|
| 1568 |
+
B(0x800800908402203, 0x102948C84C184),
|
| 1569 |
+
B(0x26801100080845, 0x4009702022A00820),
|
| 1570 |
+
B(0x8880520010401040, 0x1060084832052000),
|
| 1571 |
+
B(0x100100022042081, 0x10000600008C121),
|
| 1572 |
+
B(0x46020384100040, 0x800200320882021),
|
| 1573 |
+
B(0xC0002010148, 0x4200800800040003),
|
| 1574 |
+
B(0x2002208020090040, 0x40820210021410),
|
| 1575 |
+
B(0x9000A41160002004, 0x2A09000100080043),
|
| 1576 |
+
B(0x800004010008001, 0x1108002020104600),
|
| 1577 |
+
B(0x800540C000A4E041, 0x18021180000401),
|
| 1578 |
+
B(0x808200900A900202, 0x8364202140012005),
|
| 1579 |
+
B(0x1DBA52000081010, 0x4008000023000010),
|
| 1580 |
+
B(0x4100110204401481, 0x800040091020001C),
|
| 1581 |
+
B(0x4100110204401481, 0x800040091020001C),
|
| 1582 |
+
B(0x4101100020400482, 0x2000402302100120),
|
| 1583 |
+
B(0x100408000A020212, 0xA000400111000020),
|
| 1584 |
+
B(0x2000010488080104, 0x3000404410208100),
|
| 1585 |
+
B(0x2684220180008DD0, 0x422040200004000A),
|
| 1586 |
+
B(0x2021200C0424, 0x1010100000080200),
|
| 1587 |
+
B(0x8908020020801006, 0x3010800020C2000),
|
| 1588 |
+
B(0x4000030008062044, 0x244010202688000),
|
| 1589 |
+
B(0x242101200408009, 0x8150040000200015),
|
| 1590 |
+
B(0x42004C02180204, 0x210208014241040),
|
| 1591 |
+
B(0x4E1A01C208410804, 0x8890041000012004),
|
| 1592 |
+
B(0x2080200401000080, 0x8001098429008004),
|
| 1593 |
+
B(0xA01400121804104, 0x280200C400000500),
|
| 1594 |
+
B(0xD0080408040420, 0x1006040100224000),
|
| 1595 |
+
B(0x28400205000800C9, 0x6021101401040075),
|
| 1596 |
+
B(0x4000900040020104, 0x88129801100D0C),
|
| 1597 |
+
B(0x8000004002180410, 0x400380200400204),
|
| 1598 |
+
B(0x4002A430043008, 0x400200340100020),
|
| 1599 |
+
B(0x401960004140A42, 0x100880710000464),
|
| 1600 |
+
B(0x58014090102, 0xB8D30004010080),
|
| 1601 |
+
B(0xA004C08000244000, 0x11280100E0000040),
|
| 1602 |
+
B(0x2102008089208804, 0x110001004080040),
|
| 1603 |
+
B(0x700010084E003004, 0x8080864112000D40),
|
| 1604 |
+
B(0x4080881000200C20, 0x30324040880E0600),
|
| 1605 |
+
B(0x2024A40401810820, 0x3000888002000000),
|
| 1606 |
+
B(0x8200100400014, 0x4400340800252844),
|
| 1607 |
+
B(0x24A00804288281, 0x410103002201140),
|
| 1608 |
+
B(0x4080005022A08, 0x1000402200100264),
|
| 1609 |
+
B(0x200080032244040, 0x200502189010001),
|
| 1610 |
+
B(0x28108110404001, 0x400600120008412),
|
| 1611 |
+
B(0xA00002102810020, 0xB1080240015408),
|
| 1612 |
+
B(0x810080200806, 0x410440804080046),
|
| 1613 |
+
};
|
| 1614 |
+
constexpr Bitboard GrasshopperMagicDInit[SQUARE_NB] = {
|
| 1615 |
+
B(0x811801000400, 0x312260280280202),
|
| 1616 |
+
B(0x44A000402022680, 0x1020224880420005),
|
| 1617 |
+
B(0x8000C80800200880, 0x2000810060080C0),
|
| 1618 |
+
B(0x2010300240428040, 0x40240002C004E30),
|
| 1619 |
+
B(0x1018010404010004, 0x1001010018081E0),
|
| 1620 |
+
B(0x2042040010080090, 0x100000008410300),
|
| 1621 |
+
B(0x400080020102000, 0x4500005300000000),
|
| 1622 |
+
B(0x2D00C80420010200, 0x804003280020008),
|
| 1623 |
+
B(0x8038820024420, 0x6010010080012040),
|
| 1624 |
+
B(0x1202028004200088, 0x50018100004000C6),
|
| 1625 |
+
B(0xA02010F0410081, 0x20013001000009A),
|
| 1626 |
+
B(0x4013002041030588, 0x4802004110000004),
|
| 1627 |
+
B(0x110020802000081, 0x202001800908002),
|
| 1628 |
+
B(0x22010404103, 0x2020882080491200),
|
| 1629 |
+
B(0x60000220400580, 0x85902800100100),
|
| 1630 |
+
B(0x100080800050100, 0x200010220021088),
|
| 1631 |
+
B(0x8088840404200080, 0x140011040104000),
|
| 1632 |
+
B(0x4008508080082015, 0x8010100200580048),
|
| 1633 |
+
B(0x4010400420201001, 0x260002080A80808),
|
| 1634 |
+
B(0xC2002004A0008008, 0x8020082000110840),
|
| 1635 |
+
B(0xA000A0820042400, 0x810408082100420),
|
| 1636 |
+
B(0x80231808100004, 0x204002000800400),
|
| 1637 |
+
B(0x8296144044004900, 0x4A1003008001840),
|
| 1638 |
+
B(0x80A0020A0011008, 0x800104846080810),
|
| 1639 |
+
B(0x803800801041000, 0x1030500102000404),
|
| 1640 |
+
B(0x240C00900800850, 0x1804000108810000),
|
| 1641 |
+
B(0x800400000088800, 0x800021801020000),
|
| 1642 |
+
B(0x84800409300082, 0x1002D40680044000),
|
| 1643 |
+
B(0xA110C0000200010, 0x401010001200260),
|
| 1644 |
+
B(0x8200160204100004, 0x8040004004002022),
|
| 1645 |
+
B(0x10001000000100C0, 0x84002811000200),
|
| 1646 |
+
B(0x2000080020014001, 0x42002020000102),
|
| 1647 |
+
B(0x109040044020018, 0x2020400202001000),
|
| 1648 |
+
B(0x620000CD0108, 0x40040201008000),
|
| 1649 |
+
B(0xA1402200A0020, 0x81400400300912),
|
| 1650 |
+
B(0x20020CF100018020, 0x801A14086404000),
|
| 1651 |
+
B(0x800801844001, 0x11621488425000),
|
| 1652 |
+
B(0x10201004A8080, 0x100A000801000010),
|
| 1653 |
+
B(0x2800411001000800, 0x80224084900020),
|
| 1654 |
+
B(0x40400024028100, 0x501000400230060),
|
| 1655 |
+
B(0x404808010080, 0x1201000400100004),
|
| 1656 |
+
B(0x80802005200, 0x2000200008A0000),
|
| 1657 |
+
B(0x20800080000022, 0x80040810002010),
|
| 1658 |
+
B(0x40016004808240, 0x400114000801100),
|
| 1659 |
+
B(0x8410004204240, 0x20011000604050),
|
| 1660 |
+
B(0x8000C1009008268, 0x201004000209000),
|
| 1661 |
+
B(0x10240C000920, 0xE000A5C14003002),
|
| 1662 |
+
B(0x10184024280008, 0x90240802000000),
|
| 1663 |
+
B(0x40889081081000, 0x8010050008800000),
|
| 1664 |
+
B(0x100008C089000019, 0x802032014020010),
|
| 1665 |
+
B(0x401C1804C00, 0x402501002002020),
|
| 1666 |
+
B(0x200022000920D0, 0x8000800081300020),
|
| 1667 |
+
B(0x801000400011, 0x400100044010226),
|
| 1668 |
+
B(0x4A04010100100000, 0x500400080400000),
|
| 1669 |
+
B(0xA000050200080000, 0x8500090001010000),
|
| 1670 |
+
B(0x40400040001812, 0x4403000400100A0),
|
| 1671 |
+
B(0x20C2250203020004, 0x210001C000080000),
|
| 1672 |
+
B(0x21000408C6020001, 0x4200830012D1001),
|
| 1673 |
+
B(0x840082016080A210, 0x2400080801081008),
|
| 1674 |
+
B(0x40001020000, 0x4041240200083120),
|
| 1675 |
+
B(0x2C04030010C0818, 0xA670002000818100),
|
| 1676 |
+
B(0x4704A07085000510, 0x914001000040),
|
| 1677 |
+
B(0x900210304100100, 0x1010004000281840),
|
| 1678 |
+
B(0x8202920002002040, 0x810012000003),
|
| 1679 |
+
B(0x4001400100050, 0x1144000408002000),
|
| 1680 |
+
B(0x5900200020008100, 0x40200020002004),
|
| 1681 |
+
B(0x301020002000480, 0x202000C0004),
|
| 1682 |
+
B(0x20D000201104040, 0x34840100020010),
|
| 1683 |
+
B(0x800004200080408, 0x40184200100240),
|
| 1684 |
+
B(0x8430080100404020, 0x90042100244500),
|
| 1685 |
+
B(0x3800100010220062, 0x50404030200218),
|
| 1686 |
+
B(0x42E20008002020, 0x2000008200200300),
|
| 1687 |
+
B(0xE488008280A004, 0x200001010CC80000),
|
| 1688 |
+
B(0x6018010041109810, 0x800002000242041A),
|
| 1689 |
+
B(0x40A8002438980, 0x8000810008208009),
|
| 1690 |
+
B(0x401000480040100, 0x286800404002212),
|
| 1691 |
+
B(0x821030000100009, 0x2000090200A00000),
|
| 1692 |
+
B(0x20000100C0008028, 0x5000000100400082),
|
| 1693 |
+
B(0x80A000048030080, 0x200000120200008),
|
| 1694 |
+
B(0x6300280800204003, 0x48000105C0040100),
|
| 1695 |
+
B(0x83008802420C0200, 0x2008020200080100),
|
| 1696 |
+
B(0x1050C3102200042, 0x20103900010008),
|
| 1697 |
+
B(0x8040902021408180, 0x12000021806200A4),
|
| 1698 |
+
B(0x3008204008C10004, 0x680110100010401),
|
| 1699 |
+
B(0x204321100421000, 0x400E204820494000),
|
| 1700 |
+
B(0x8000044022404048, 0x4024010090024021),
|
| 1701 |
+
B(0x140201424050, 0x280A000130008000),
|
| 1702 |
+
B(0x900340808004002, 0x21026008000380),
|
| 1703 |
+
B(0x82808000300444, 0x20002000A2001141),
|
| 1704 |
+
B(0x140180100406002, 0x4004480001000004),
|
| 1705 |
+
B(0x4808420800841900, 0x14008C0041000000),
|
| 1706 |
+
B(0x2008600009000480, 0x9008020001400000),
|
| 1707 |
+
B(0x2000100800100002, 0x2004100820210020),
|
| 1708 |
+
B(0x2062010401A8100, 0x12200108420090),
|
| 1709 |
+
B(0x1403188200032, 0x40048166105000),
|
| 1710 |
+
B(0x410020020140041, 0x4400348102940040),
|
| 1711 |
+
B(0x414040209208041, 0x4402400028B004),
|
| 1712 |
+
B(0x8008010100421202, 0x401418002008800),
|
| 1713 |
+
B(0x4000020010062200, 0xA02009148048000),
|
| 1714 |
+
B(0x4443080082008B, 0x104014022801010),
|
| 1715 |
+
B(0x42B440A0C000800, 0x9001009016111020),
|
| 1716 |
+
B(0x400000214002, 0x8008080209020009),
|
| 1717 |
+
B(0x480C414A001900, 0x3400100400210200),
|
| 1718 |
+
B(0x1006008800604, 0x20240004030A050),
|
| 1719 |
+
B(0x4C022401002A8300, 0x405008400000600),
|
| 1720 |
+
B(0x3104000800A1042, 0x2004800204406200),
|
| 1721 |
+
B(0xA09010280008200C, 0x4004000208C4168),
|
| 1722 |
+
B(0x2800401120C20120, 0x4A00450200022030),
|
| 1723 |
+
B(0x88001800304C0200, 0x204288102080000),
|
| 1724 |
+
B(0x8044004201440101, 0x400820080C024022),
|
| 1725 |
+
B(0xA000100C080, 0x4B40341004008081),
|
| 1726 |
+
B(0x94802001300810, 0x140206008000800),
|
| 1727 |
+
B(0x40002020202820, 0x280680404000040),
|
| 1728 |
+
B(0xA820800004200, 0x80E1401012000491),
|
| 1729 |
+
B(0x804000010020C000, 0x9403020200802000),
|
| 1730 |
+
B(0x8C0001284201400, 0xC000100C01620800),
|
| 1731 |
+
B(0x4010004002200414, 0x403080080200000),
|
| 1732 |
+
B(0x140400A100800101, 0x10054C031080400),
|
| 1733 |
+
B(0x20012C2400880082, 0x7000880020C03200),
|
| 1734 |
+
B(0x204040300004, 0x840800041101002),
|
| 1735 |
+
};
|
| 1736 |
+
#undef B
|
| 1737 |
+
#endif
|
| 1738 |
+
|
| 1739 |
+
} // namespace Stockfish
|
| 1740 |
+
|
| 1741 |
+
#endif // #ifndef MAGIC_H_INCLUDED
|
Fairy-Stockfish-master/src/main.cpp
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <iostream>
|
| 20 |
+
|
| 21 |
+
#include "bitboard.h"
|
| 22 |
+
#include "endgame.h"
|
| 23 |
+
#include "position.h"
|
| 24 |
+
#include "psqt.h"
|
| 25 |
+
#include "search.h"
|
| 26 |
+
#include "syzygy/tbprobe.h"
|
| 27 |
+
#include "thread.h"
|
| 28 |
+
#include "tt.h"
|
| 29 |
+
#include "uci.h"
|
| 30 |
+
|
| 31 |
+
#include "piece.h"
|
| 32 |
+
#include "variant.h"
|
| 33 |
+
#include "xboard.h"
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
using namespace Stockfish;
|
| 37 |
+
|
| 38 |
+
int main(int argc, char* argv[]) {
|
| 39 |
+
|
| 40 |
+
std::cout << engine_info() << std::endl;
|
| 41 |
+
|
| 42 |
+
pieceMap.init();
|
| 43 |
+
variants.init();
|
| 44 |
+
CommandLine::init(argc, argv);
|
| 45 |
+
UCI::init(Options);
|
| 46 |
+
Tune::init();
|
| 47 |
+
PSQT::init(variants.find(Options["UCI_Variant"])->second);
|
| 48 |
+
Bitboards::init();
|
| 49 |
+
Position::init();
|
| 50 |
+
Bitbases::init();
|
| 51 |
+
Endgames::init();
|
| 52 |
+
Threads.set(size_t(Options["Threads"]));
|
| 53 |
+
Search::clear(); // After threads are up
|
| 54 |
+
Eval::NNUE::init();
|
| 55 |
+
|
| 56 |
+
UCI::loop(argc, argv);
|
| 57 |
+
|
| 58 |
+
Threads.set(0);
|
| 59 |
+
variants.clear_all();
|
| 60 |
+
pieceMap.clear_all();
|
| 61 |
+
delete XBoard::stateMachine;
|
| 62 |
+
return 0;
|
| 63 |
+
}
|
Fairy-Stockfish-master/src/material.cpp
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <cassert>
|
| 20 |
+
#include <cstring> // For std::memset
|
| 21 |
+
|
| 22 |
+
#include "material.h"
|
| 23 |
+
#include "thread.h"
|
| 24 |
+
|
| 25 |
+
using namespace std;
|
| 26 |
+
|
| 27 |
+
namespace Stockfish {
|
| 28 |
+
|
| 29 |
+
namespace {
|
| 30 |
+
#define S(mg, eg) make_score(mg, eg)
|
| 31 |
+
|
| 32 |
+
// Polynomial material imbalance parameters
|
| 33 |
+
|
| 34 |
+
// One Score parameter for each pair (our piece, another of our pieces)
|
| 35 |
+
constexpr Score QuadraticOurs[][PIECE_TYPE_NB] = {
|
| 36 |
+
// OUR PIECE 2
|
| 37 |
+
// bishop pair pawn knight bishop rook queen
|
| 38 |
+
{S(1419, 1455) }, // Bishop pair
|
| 39 |
+
{S( 101, 28), S( 37, 39) }, // Pawn
|
| 40 |
+
{S( 57, 64), S(249, 187), S(-49, -62) }, // Knight OUR PIECE 1
|
| 41 |
+
{S( 0, 0), S(118, 137), S( 10, 27), S( 0, 0) }, // Bishop
|
| 42 |
+
{S( -63, -68), S( -5, 3), S(100, 81), S(132, 118), S(-246, -244) }, // Rook
|
| 43 |
+
{S(-210, -211), S( 37, 14), S(147, 141), S(161, 105), S(-158, -174), S(-9,-31) } // Queen
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
// One Score parameter for each pair (our piece, their piece)
|
| 47 |
+
constexpr Score QuadraticTheirs[][PIECE_TYPE_NB] = {
|
| 48 |
+
// THEIR PIECE
|
| 49 |
+
// bishop pair pawn knight bishop rook queen
|
| 50 |
+
{ }, // Bishop pair
|
| 51 |
+
{S( 33, 30) }, // Pawn
|
| 52 |
+
{S( 46, 18), S(106, 84) }, // Knight OUR PIECE
|
| 53 |
+
{S( 75, 35), S( 59, 44), S( 60, 15) }, // Bishop
|
| 54 |
+
{S( 26, 35), S( 6, 22), S( 38, 39), S(-12, -2) }, // Rook
|
| 55 |
+
{S( 97, 93), S(100, 163), S(-58, -91), S(112, 192), S(276, 225) } // Queen
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
#undef S
|
| 59 |
+
|
| 60 |
+
// Endgame evaluation and scaling functions are accessed directly and not through
|
| 61 |
+
// the function maps because they correspond to more than one material hash key.
|
| 62 |
+
Endgame<KFsPsK> EvaluateKFsPsK[] = { Endgame<KFsPsK>(WHITE), Endgame<KFsPsK>(BLACK) };
|
| 63 |
+
Endgame<KXK> EvaluateKXK[] = { Endgame<KXK>(WHITE), Endgame<KXK>(BLACK) };
|
| 64 |
+
Endgame<KXK, EG_EVAL_ATOMIC> EvaluateKXKAtomic[] = { Endgame<KXK, EG_EVAL_ATOMIC>(WHITE), Endgame<KXK, EG_EVAL_ATOMIC>(BLACK) };
|
| 65 |
+
Endgame<KXK, EG_EVAL_DUCK> EvaluateKXKDuck[] = { Endgame<KXK, EG_EVAL_DUCK>(WHITE), Endgame<KXK, EG_EVAL_DUCK>(BLACK) };
|
| 66 |
+
Endgame<KXKX, EG_EVAL_MISERE> EvaluateKXKXMisere[] = { Endgame<KXKX, EG_EVAL_MISERE>(WHITE), Endgame<KXKX, EG_EVAL_MISERE>(BLACK) };
|
| 67 |
+
|
| 68 |
+
Endgame<KBPsK> ScaleKBPsK[] = { Endgame<KBPsK>(WHITE), Endgame<KBPsK>(BLACK) };
|
| 69 |
+
Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) };
|
| 70 |
+
Endgame<KPsK> ScaleKPsK[] = { Endgame<KPsK>(WHITE), Endgame<KPsK>(BLACK) };
|
| 71 |
+
Endgame<KPKP> ScaleKPKP[] = { Endgame<KPKP>(WHITE), Endgame<KPKP>(BLACK) };
|
| 72 |
+
|
| 73 |
+
// Helper used to detect a given material distribution
|
| 74 |
+
bool is_KFsPsK(const Position& pos, Color us) {
|
| 75 |
+
return (pos.promotion_piece_types(us) == piece_set(FERS))
|
| 76 |
+
&& !more_than_one(pos.pieces(~us))
|
| 77 |
+
&& (pos.count<FERS>(us) || pos.count<PAWN>(us))
|
| 78 |
+
&& !(pos.count<ALL_PIECES>(us) - pos.count<FERS>(us) - pos.count<PAWN>(us) - pos.count<KING>(us));
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
bool is_KXK(const Position& pos, Color us) {
|
| 82 |
+
return !more_than_one(pos.pieces(~us))
|
| 83 |
+
&& pos.non_pawn_material(us) >= std::min(RookValueMg, 2 * SilverValueMg);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
bool is_KXK_atomic(const Position& pos, Color us) {
|
| 87 |
+
return !more_than_one(pos.pieces(~us))
|
| 88 |
+
&& pos.non_pawn_material(us) >= RookValueMg + KnightValueMg;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
bool is_KXKX(const Position& pos, Color us) {
|
| 92 |
+
return pos.non_pawn_material(us) - pos.non_pawn_material(~us) > QueenValueMg;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
bool is_KBPsK(const Position& pos, Color us) {
|
| 96 |
+
return pos.non_pawn_material(us) == BishopValueMg
|
| 97 |
+
&& pos.count<PAWN>(us) >= 1;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
bool is_KQKRPs(const Position& pos, Color us) {
|
| 101 |
+
return !pos.count<PAWN>(us)
|
| 102 |
+
&& pos.non_pawn_material(us) == QueenValueMg
|
| 103 |
+
&& pos.count<ROOK>(~us) == 1
|
| 104 |
+
&& pos.count<PAWN>(~us) >= 1;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
/// imbalance() calculates the imbalance by comparing the piece count of each
|
| 109 |
+
/// piece type for both colors.
|
| 110 |
+
|
| 111 |
+
template<Color Us>
|
| 112 |
+
Score imbalance(const Position& pos, const int pieceCount[][PIECE_TYPE_NB]) {
|
| 113 |
+
|
| 114 |
+
constexpr Color Them = ~Us;
|
| 115 |
+
|
| 116 |
+
Score bonus = SCORE_ZERO;
|
| 117 |
+
|
| 118 |
+
// Second-degree polynomial material imbalance, by Tord Romstad
|
| 119 |
+
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
|
| 120 |
+
{
|
| 121 |
+
if (!pieceCount[Us][pt1])
|
| 122 |
+
continue;
|
| 123 |
+
|
| 124 |
+
int v = QuadraticOurs[pt1][pt1] * pieceCount[Us][pt1];
|
| 125 |
+
|
| 126 |
+
for (int pt2 = NO_PIECE_TYPE; pt2 < pt1; ++pt2)
|
| 127 |
+
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
|
| 128 |
+
+ QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2];
|
| 129 |
+
|
| 130 |
+
bonus += pieceCount[Us][pt1] * v;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
if (pos.must_capture())
|
| 134 |
+
bonus += (make_score(mg_value(QuadraticOurs[PAWN][PAWN]), 0) * pieceCount[Us][PAWN]
|
| 135 |
+
+ 3 * QuadraticOurs[KNIGHT][PAWN] * pieceCount[Us][KNIGHT]
|
| 136 |
+
+ QuadraticOurs[QUEEN][PAWN] * pieceCount[Us][QUEEN]) * pieceCount[Us][PAWN]
|
| 137 |
+
+ make_score( mg_value(QuadraticOurs[KNIGHT][KNIGHT]),
|
| 138 |
+
-eg_value(QuadraticOurs[KNIGHT][KNIGHT])) * pieceCount[Us][KNIGHT] * pieceCount[Us][KNIGHT];
|
| 139 |
+
else if (pos.blast_on_capture())
|
| 140 |
+
bonus -= make_score(mg_value(QuadraticOurs[KNIGHT][PAWN]) * pieceCount[Us][KNIGHT] * pieceCount[Us][PAWN] / 2, 0);
|
| 141 |
+
else if (pos.check_counting())
|
| 142 |
+
bonus -= 2 * QuadraticOurs[PAWN][PAWN] * pieceCount[Us][PAWN] * pieceCount[Us][PAWN];
|
| 143 |
+
else if (pos.captures_to_hand())
|
| 144 |
+
bonus -= bonus / 10;
|
| 145 |
+
|
| 146 |
+
return bonus;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
} // namespace
|
| 150 |
+
|
| 151 |
+
namespace Material {
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
/// Material::probe() looks up the current position's material configuration in
|
| 155 |
+
/// the material hash table. It returns a pointer to the Entry if the position
|
| 156 |
+
/// is found. Otherwise a new Entry is computed and stored there, so we don't
|
| 157 |
+
/// have to recompute all when the same material configuration occurs again.
|
| 158 |
+
|
| 159 |
+
Entry* probe(const Position& pos) {
|
| 160 |
+
|
| 161 |
+
Key key = pos.material_key(pos.endgame_eval());
|
| 162 |
+
Entry* e = pos.this_thread()->materialTable[key];
|
| 163 |
+
|
| 164 |
+
if (e->key == key)
|
| 165 |
+
return e;
|
| 166 |
+
|
| 167 |
+
std::memset(e, 0, sizeof(Entry));
|
| 168 |
+
e->key = key;
|
| 169 |
+
e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
|
| 170 |
+
|
| 171 |
+
Value npm_w = pos.non_pawn_material(WHITE);
|
| 172 |
+
Value npm_b = pos.non_pawn_material(BLACK);
|
| 173 |
+
Value npm = std::clamp(npm_w + npm_b, EndgameLimit, MidgameLimit);
|
| 174 |
+
|
| 175 |
+
// Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME]
|
| 176 |
+
if (pos.captures_to_hand() || pos.two_boards())
|
| 177 |
+
{
|
| 178 |
+
Value npm2 = VALUE_ZERO;
|
| 179 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 180 |
+
{
|
| 181 |
+
PieceType pt = pop_lsb(ps);
|
| 182 |
+
npm2 += pos.count_in_hand(pt) * PieceValue[MG][make_piece(WHITE, pt)];
|
| 183 |
+
}
|
| 184 |
+
e->gamePhase = Phase(PHASE_MIDGAME * npm / std::max(int(npm + npm2), 1));
|
| 185 |
+
int countAll = pos.count_with_hand(WHITE, ALL_PIECES) + pos.count_with_hand(BLACK, ALL_PIECES);
|
| 186 |
+
e->materialDensity = (npm + npm2 + pos.count<PAWN>() * PawnValueMg) * countAll / (pos.files() * pos.ranks());
|
| 187 |
+
}
|
| 188 |
+
else
|
| 189 |
+
e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
|
| 190 |
+
|
| 191 |
+
// Let's look if we have a specialized evaluation function for this particular
|
| 192 |
+
// material configuration. Firstly we look for a fixed configuration one, then
|
| 193 |
+
// for a generic one if the previous search failed.
|
| 194 |
+
if (pos.endgame_eval() && (e->evaluationFunction = Endgames::probe<Value>(key)) != nullptr)
|
| 195 |
+
return e;
|
| 196 |
+
|
| 197 |
+
switch (pos.endgame_eval())
|
| 198 |
+
{
|
| 199 |
+
case EG_EVAL_CHESS:
|
| 200 |
+
for (Color c : { WHITE, BLACK })
|
| 201 |
+
if (is_KFsPsK(pos, c))
|
| 202 |
+
{
|
| 203 |
+
e->evaluationFunction = &EvaluateKFsPsK[c];
|
| 204 |
+
return e;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
for (Color c : { WHITE, BLACK })
|
| 208 |
+
if (is_KXK(pos, c))
|
| 209 |
+
{
|
| 210 |
+
e->evaluationFunction = &EvaluateKXK[c];
|
| 211 |
+
return e;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
// OK, we didn't find any special evaluation function for the current material
|
| 215 |
+
// configuration. Is there a suitable specialized scaling function?
|
| 216 |
+
{
|
| 217 |
+
const auto* sf = Endgames::probe<ScaleFactor>(key);
|
| 218 |
+
|
| 219 |
+
if (sf)
|
| 220 |
+
{
|
| 221 |
+
e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
|
| 222 |
+
return e;
|
| 223 |
+
}
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
// We didn't find any specialized scaling function, so fall back on generic
|
| 227 |
+
// ones that refer to more than one material distribution. Note that in this
|
| 228 |
+
// case we don't return after setting the function.
|
| 229 |
+
for (Color c : { WHITE, BLACK })
|
| 230 |
+
{
|
| 231 |
+
if (is_KBPsK(pos, c))
|
| 232 |
+
e->scalingFunction[c] = &ScaleKBPsK[c];
|
| 233 |
+
|
| 234 |
+
else if (is_KQKRPs(pos, c))
|
| 235 |
+
e->scalingFunction[c] = &ScaleKQKRPs[c];
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
|
| 239 |
+
{
|
| 240 |
+
if (!pos.count<PAWN>(BLACK))
|
| 241 |
+
{
|
| 242 |
+
assert(pos.count<PAWN>(WHITE) >= 2);
|
| 243 |
+
|
| 244 |
+
e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
|
| 245 |
+
}
|
| 246 |
+
else if (!pos.count<PAWN>(WHITE))
|
| 247 |
+
{
|
| 248 |
+
assert(pos.count<PAWN>(BLACK) >= 2);
|
| 249 |
+
|
| 250 |
+
e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
|
| 251 |
+
}
|
| 252 |
+
else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
|
| 253 |
+
{
|
| 254 |
+
// This is a special case because we set scaling functions
|
| 255 |
+
// for both colors instead of only one.
|
| 256 |
+
e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
|
| 257 |
+
e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
|
| 258 |
+
}
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
// Zero or just one pawn makes it difficult to win, even with a small material
|
| 262 |
+
// advantage. This catches some trivial draws like KK, KBK and KNK and gives a
|
| 263 |
+
// drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
|
| 264 |
+
if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
|
| 265 |
+
e->factor[WHITE] = uint8_t(npm_w < RookValueMg && pos.count<ALL_PIECES>(WHITE) <= 2 ? SCALE_FACTOR_DRAW :
|
| 266 |
+
npm_b <= BishopValueMg && pos.count<ALL_PIECES>(WHITE) <= 3 ? 4 : 14);
|
| 267 |
+
|
| 268 |
+
if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
|
| 269 |
+
e->factor[BLACK] = uint8_t(npm_b < RookValueMg && pos.count<ALL_PIECES>(BLACK) <= 2 ? SCALE_FACTOR_DRAW :
|
| 270 |
+
npm_w <= BishopValueMg && pos.count<ALL_PIECES>(BLACK) <= 3 ? 4 : 14);
|
| 271 |
+
break;
|
| 272 |
+
case EG_EVAL_ANTI:
|
| 273 |
+
break;
|
| 274 |
+
case EG_EVAL_ATOMIC:
|
| 275 |
+
for (Color c : { WHITE, BLACK })
|
| 276 |
+
if (is_KXK_atomic(pos, c))
|
| 277 |
+
{
|
| 278 |
+
e->evaluationFunction = &EvaluateKXKAtomic[c];
|
| 279 |
+
return e;
|
| 280 |
+
}
|
| 281 |
+
break;
|
| 282 |
+
case EG_EVAL_DUCK:
|
| 283 |
+
for (Color c : { WHITE, BLACK })
|
| 284 |
+
if (is_KXK(pos, c))
|
| 285 |
+
{
|
| 286 |
+
e->evaluationFunction = &EvaluateKXKDuck[c];
|
| 287 |
+
return e;
|
| 288 |
+
}
|
| 289 |
+
break;
|
| 290 |
+
case EG_EVAL_MISERE:
|
| 291 |
+
for (Color c : { WHITE, BLACK })
|
| 292 |
+
if (is_KXKX(pos, c))
|
| 293 |
+
{
|
| 294 |
+
e->evaluationFunction = &EvaluateKXKXMisere[c];
|
| 295 |
+
return e;
|
| 296 |
+
}
|
| 297 |
+
break;
|
| 298 |
+
case EG_EVAL_RK:
|
| 299 |
+
break;
|
| 300 |
+
case NO_EG_EVAL:
|
| 301 |
+
break;
|
| 302 |
+
default:
|
| 303 |
+
assert(false);
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
|
| 307 |
+
// for the bishop pair "extended piece", which allows us to be more flexible
|
| 308 |
+
// in defining bishop pair bonuses.
|
| 309 |
+
const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = {
|
| 310 |
+
{ pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
|
| 311 |
+
pos.count<BISHOP>(WHITE) , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
|
| 312 |
+
{ pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
|
| 313 |
+
pos.count<BISHOP>(BLACK) , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
|
| 314 |
+
|
| 315 |
+
e->score = (imbalance<WHITE>(pos, pieceCount) - imbalance<BLACK>(pos, pieceCount)) / 16;
|
| 316 |
+
return e;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
} // namespace Material
|
| 320 |
+
|
| 321 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/material.h
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef MATERIAL_H_INCLUDED
|
| 20 |
+
#define MATERIAL_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include "endgame.h"
|
| 23 |
+
#include "misc.h"
|
| 24 |
+
#include "position.h"
|
| 25 |
+
#include "types.h"
|
| 26 |
+
|
| 27 |
+
namespace Stockfish::Material {
|
| 28 |
+
|
| 29 |
+
/// Material::Entry contains various information about a material configuration.
|
| 30 |
+
/// It contains a material imbalance evaluation, a function pointer to a special
|
| 31 |
+
/// endgame evaluation function (which in most cases is NULL, meaning that the
|
| 32 |
+
/// standard evaluation function will be used), and scale factors.
|
| 33 |
+
///
|
| 34 |
+
/// The scale factors are used to scale the evaluation score up or down. For
|
| 35 |
+
/// instance, in KRB vs KR endgames, the score is scaled down by a factor of 4,
|
| 36 |
+
/// which will result in scores of absolute value less than one pawn.
|
| 37 |
+
|
| 38 |
+
struct Entry {
|
| 39 |
+
|
| 40 |
+
Score imbalance() const { return score; }
|
| 41 |
+
Phase game_phase() const { return (Phase)gamePhase; }
|
| 42 |
+
bool specialized_eval_exists() const { return evaluationFunction != nullptr; }
|
| 43 |
+
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
|
| 44 |
+
|
| 45 |
+
int material_density() const { return materialDensity; }
|
| 46 |
+
|
| 47 |
+
// scale_factor() takes a position and a color as input and returns a scale factor
|
| 48 |
+
// for the given color. We have to provide the position in addition to the color
|
| 49 |
+
// because the scale factor may also be a function which should be applied to
|
| 50 |
+
// the position. For instance, in KBP vs K endgames, the scaling function looks
|
| 51 |
+
// for rook pawns and wrong-colored bishops.
|
| 52 |
+
ScaleFactor scale_factor(const Position& pos, Color c) const {
|
| 53 |
+
ScaleFactor sf = scalingFunction[c] ? (*scalingFunction[c])(pos)
|
| 54 |
+
: SCALE_FACTOR_NONE;
|
| 55 |
+
return sf != SCALE_FACTOR_NONE ? sf : ScaleFactor(factor[c]);
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
Key key;
|
| 59 |
+
const EndgameBase<Value>* evaluationFunction;
|
| 60 |
+
const EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB]; // Could be one for each
|
| 61 |
+
// side (e.g. KPKP, KBPsK)
|
| 62 |
+
Score score;
|
| 63 |
+
int16_t gamePhase;
|
| 64 |
+
uint8_t factor[COLOR_NB];
|
| 65 |
+
|
| 66 |
+
int materialDensity;
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
typedef HashTable<Entry, 8192> Table;
|
| 70 |
+
|
| 71 |
+
Entry* probe(const Position& pos);
|
| 72 |
+
|
| 73 |
+
} // namespace Stockfish::Material
|
| 74 |
+
|
| 75 |
+
#endif // #ifndef MATERIAL_H_INCLUDED
|
Fairy-Stockfish-master/src/misc.cpp
ADDED
|
@@ -0,0 +1,656 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifdef _WIN32
|
| 20 |
+
#if _WIN32_WINNT < 0x0601
|
| 21 |
+
#undef _WIN32_WINNT
|
| 22 |
+
#define _WIN32_WINNT 0x0601 // Force to include needed API prototypes
|
| 23 |
+
#endif
|
| 24 |
+
|
| 25 |
+
#ifndef NOMINMAX
|
| 26 |
+
#define NOMINMAX
|
| 27 |
+
#endif
|
| 28 |
+
|
| 29 |
+
#include <windows.h>
|
| 30 |
+
// The needed Windows API for processor groups could be missed from old Windows
|
| 31 |
+
// versions, so instead of calling them directly (forcing the linker to resolve
|
| 32 |
+
// the calls at compile time), try to load them at runtime. To do this we need
|
| 33 |
+
// first to define the corresponding function pointers.
|
| 34 |
+
extern "C" {
|
| 35 |
+
typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP,
|
| 36 |
+
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
|
| 37 |
+
typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY);
|
| 38 |
+
typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY);
|
| 39 |
+
}
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
#include <fstream>
|
| 43 |
+
#include <iomanip>
|
| 44 |
+
#include <iostream>
|
| 45 |
+
#include <sstream>
|
| 46 |
+
#include <vector>
|
| 47 |
+
#include <cstdlib>
|
| 48 |
+
|
| 49 |
+
#if defined(__linux__) && !defined(__ANDROID__)
|
| 50 |
+
#include <stdlib.h>
|
| 51 |
+
#include <sys/mman.h>
|
| 52 |
+
#endif
|
| 53 |
+
|
| 54 |
+
#if defined(__APPLE__) || defined(__ANDROID__) || defined(__OpenBSD__) || (defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) && !defined(_WIN32)) || defined(__e2k__)
|
| 55 |
+
#define POSIXALIGNEDALLOC
|
| 56 |
+
#include <stdlib.h>
|
| 57 |
+
#endif
|
| 58 |
+
|
| 59 |
+
#include "misc.h"
|
| 60 |
+
#include "thread.h"
|
| 61 |
+
|
| 62 |
+
using namespace std;
|
| 63 |
+
|
| 64 |
+
namespace Stockfish {
|
| 65 |
+
|
| 66 |
+
namespace {
|
| 67 |
+
|
| 68 |
+
/// Version number. If Version is left empty, then compile date in the format
|
| 69 |
+
/// DD-MM-YY and show in engine_info.
|
| 70 |
+
const string Version = "";
|
| 71 |
+
|
| 72 |
+
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
| 73 |
+
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
| 74 |
+
/// can toggle the logging of std::cout and std:cin at runtime whilst preserving
|
| 75 |
+
/// usual I/O functionality, all without changing a single line of code!
|
| 76 |
+
/// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
|
| 77 |
+
|
| 78 |
+
struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
|
| 79 |
+
|
| 80 |
+
Tie(streambuf* b, streambuf* l) : buf(b), logBuf(l) {}
|
| 81 |
+
|
| 82 |
+
int sync() override { return logBuf->pubsync(), buf->pubsync(); }
|
| 83 |
+
int overflow(int c) override { return log(buf->sputc((char)c), "<< "); }
|
| 84 |
+
int underflow() override { return buf->sgetc(); }
|
| 85 |
+
int uflow() override { return log(buf->sbumpc(), ">> "); }
|
| 86 |
+
|
| 87 |
+
streambuf *buf, *logBuf;
|
| 88 |
+
|
| 89 |
+
int log(int c, const char* prefix) {
|
| 90 |
+
|
| 91 |
+
static int last = '\n'; // Single log file
|
| 92 |
+
|
| 93 |
+
if (last == '\n')
|
| 94 |
+
logBuf->sputn(prefix, 3);
|
| 95 |
+
|
| 96 |
+
return last = logBuf->sputc((char)c);
|
| 97 |
+
}
|
| 98 |
+
};
|
| 99 |
+
|
| 100 |
+
class Logger {
|
| 101 |
+
|
| 102 |
+
Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
|
| 103 |
+
~Logger() { start(""); }
|
| 104 |
+
|
| 105 |
+
ofstream file;
|
| 106 |
+
Tie in, out;
|
| 107 |
+
|
| 108 |
+
public:
|
| 109 |
+
static void start(const std::string& fname) {
|
| 110 |
+
|
| 111 |
+
static Logger l;
|
| 112 |
+
|
| 113 |
+
if (!fname.empty() && !l.file.is_open())
|
| 114 |
+
{
|
| 115 |
+
l.file.open(fname, ifstream::out);
|
| 116 |
+
|
| 117 |
+
if (!l.file.is_open())
|
| 118 |
+
{
|
| 119 |
+
cerr << "Unable to open debug log file " << fname << endl;
|
| 120 |
+
exit(EXIT_FAILURE);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
cin.rdbuf(&l.in);
|
| 124 |
+
cout.rdbuf(&l.out);
|
| 125 |
+
}
|
| 126 |
+
else if (fname.empty() && l.file.is_open())
|
| 127 |
+
{
|
| 128 |
+
cout.rdbuf(l.out.buf);
|
| 129 |
+
cin.rdbuf(l.in.buf);
|
| 130 |
+
l.file.close();
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
};
|
| 134 |
+
|
| 135 |
+
} // namespace
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
/// engine_info() returns the full name of the current Stockfish version. This
|
| 139 |
+
/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
|
| 140 |
+
/// the program was compiled) or "Stockfish <Version>", depending on whether
|
| 141 |
+
/// Version is empty.
|
| 142 |
+
|
| 143 |
+
string engine_info(bool to_uci, bool to_xboard) {
|
| 144 |
+
|
| 145 |
+
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
|
| 146 |
+
string month, day, year;
|
| 147 |
+
stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
|
| 148 |
+
|
| 149 |
+
ss << "Fairy-Stockfish " << Version << setfill('0');
|
| 150 |
+
|
| 151 |
+
if (Version.empty())
|
| 152 |
+
{
|
| 153 |
+
date >> month >> day >> year;
|
| 154 |
+
ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
#ifdef LARGEBOARDS
|
| 158 |
+
ss << " LB";
|
| 159 |
+
#endif
|
| 160 |
+
|
| 161 |
+
if (!to_xboard)
|
| 162 |
+
ss << (to_uci ? "\nid author ": " by ")
|
| 163 |
+
<< "Fabian Fichter";
|
| 164 |
+
|
| 165 |
+
return ss.str();
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
/// compiler_info() returns a string trying to describe the compiler we use
|
| 170 |
+
|
| 171 |
+
std::string compiler_info() {
|
| 172 |
+
|
| 173 |
+
#define stringify2(x) #x
|
| 174 |
+
#define stringify(x) stringify2(x)
|
| 175 |
+
#define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch)
|
| 176 |
+
|
| 177 |
+
/// Predefined macros hell:
|
| 178 |
+
///
|
| 179 |
+
/// __GNUC__ Compiler is gcc, Clang or Intel on Linux
|
| 180 |
+
/// __INTEL_COMPILER Compiler is Intel
|
| 181 |
+
/// _MSC_VER Compiler is MSVC or Intel on Windows
|
| 182 |
+
/// _WIN32 Building on Windows (any)
|
| 183 |
+
/// _WIN64 Building on Windows 64 bit
|
| 184 |
+
|
| 185 |
+
std::string compiler = "\nCompiled by ";
|
| 186 |
+
|
| 187 |
+
#ifdef __clang__
|
| 188 |
+
compiler += "clang++ ";
|
| 189 |
+
compiler += make_version_string(__clang_major__, __clang_minor__, __clang_patchlevel__);
|
| 190 |
+
#elif __INTEL_COMPILER
|
| 191 |
+
compiler += "Intel compiler ";
|
| 192 |
+
compiler += "(version ";
|
| 193 |
+
compiler += stringify(__INTEL_COMPILER) " update " stringify(__INTEL_COMPILER_UPDATE);
|
| 194 |
+
compiler += ")";
|
| 195 |
+
#elif _MSC_VER
|
| 196 |
+
compiler += "MSVC ";
|
| 197 |
+
compiler += "(version ";
|
| 198 |
+
compiler += stringify(_MSC_FULL_VER) "." stringify(_MSC_BUILD);
|
| 199 |
+
compiler += ")";
|
| 200 |
+
#elif defined(__e2k__) && defined(__LCC__)
|
| 201 |
+
#define dot_ver2(n) \
|
| 202 |
+
compiler += (char)'.'; \
|
| 203 |
+
compiler += (char)('0' + (n) / 10); \
|
| 204 |
+
compiler += (char)('0' + (n) % 10);
|
| 205 |
+
|
| 206 |
+
compiler += "MCST LCC ";
|
| 207 |
+
compiler += "(version ";
|
| 208 |
+
compiler += std::to_string(__LCC__ / 100);
|
| 209 |
+
dot_ver2(__LCC__ % 100)
|
| 210 |
+
dot_ver2(__LCC_MINOR__)
|
| 211 |
+
compiler += ")";
|
| 212 |
+
#elif __GNUC__
|
| 213 |
+
compiler += "g++ (GNUC) ";
|
| 214 |
+
compiler += make_version_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
|
| 215 |
+
#else
|
| 216 |
+
compiler += "Unknown compiler ";
|
| 217 |
+
compiler += "(unknown version)";
|
| 218 |
+
#endif
|
| 219 |
+
|
| 220 |
+
#if defined(__APPLE__)
|
| 221 |
+
compiler += " on Apple";
|
| 222 |
+
#elif defined(__CYGWIN__)
|
| 223 |
+
compiler += " on Cygwin";
|
| 224 |
+
#elif defined(__MINGW64__)
|
| 225 |
+
compiler += " on MinGW64";
|
| 226 |
+
#elif defined(__MINGW32__)
|
| 227 |
+
compiler += " on MinGW32";
|
| 228 |
+
#elif defined(__ANDROID__)
|
| 229 |
+
compiler += " on Android";
|
| 230 |
+
#elif defined(__linux__)
|
| 231 |
+
compiler += " on Linux";
|
| 232 |
+
#elif defined(_WIN64)
|
| 233 |
+
compiler += " on Microsoft Windows 64-bit";
|
| 234 |
+
#elif defined(_WIN32)
|
| 235 |
+
compiler += " on Microsoft Windows 32-bit";
|
| 236 |
+
#else
|
| 237 |
+
compiler += " on unknown system";
|
| 238 |
+
#endif
|
| 239 |
+
|
| 240 |
+
compiler += "\nCompilation settings include: ";
|
| 241 |
+
compiler += (Is64Bit ? " 64bit" : " 32bit");
|
| 242 |
+
#if defined(USE_VNNI)
|
| 243 |
+
compiler += " VNNI";
|
| 244 |
+
#endif
|
| 245 |
+
#if defined(USE_AVX512)
|
| 246 |
+
compiler += " AVX512";
|
| 247 |
+
#endif
|
| 248 |
+
compiler += (HasPext ? " BMI2" : "");
|
| 249 |
+
#if defined(USE_AVX2)
|
| 250 |
+
compiler += " AVX2";
|
| 251 |
+
#endif
|
| 252 |
+
#if defined(USE_SSE41)
|
| 253 |
+
compiler += " SSE41";
|
| 254 |
+
#endif
|
| 255 |
+
#if defined(USE_SSSE3)
|
| 256 |
+
compiler += " SSSE3";
|
| 257 |
+
#endif
|
| 258 |
+
#if defined(USE_SSE2)
|
| 259 |
+
compiler += " SSE2";
|
| 260 |
+
#endif
|
| 261 |
+
compiler += (HasPopCnt ? " POPCNT" : "");
|
| 262 |
+
#if defined(USE_MMX)
|
| 263 |
+
compiler += " MMX";
|
| 264 |
+
#endif
|
| 265 |
+
#if defined(USE_NEON)
|
| 266 |
+
compiler += " NEON";
|
| 267 |
+
#endif
|
| 268 |
+
|
| 269 |
+
#if !defined(NDEBUG)
|
| 270 |
+
compiler += " DEBUG";
|
| 271 |
+
#endif
|
| 272 |
+
|
| 273 |
+
compiler += "\n__VERSION__ macro expands to: ";
|
| 274 |
+
#ifdef __VERSION__
|
| 275 |
+
compiler += __VERSION__;
|
| 276 |
+
#else
|
| 277 |
+
compiler += "(undefined macro)";
|
| 278 |
+
#endif
|
| 279 |
+
compiler += "\n";
|
| 280 |
+
|
| 281 |
+
return compiler;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
/// Debug functions used mainly to collect run-time statistics
|
| 286 |
+
static std::atomic<int64_t> hits[2], means[2];
|
| 287 |
+
|
| 288 |
+
void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; }
|
| 289 |
+
void dbg_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); }
|
| 290 |
+
void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
|
| 291 |
+
|
| 292 |
+
void dbg_print() {
|
| 293 |
+
|
| 294 |
+
if (hits[0])
|
| 295 |
+
cerr << "Total " << hits[0] << " Hits " << hits[1]
|
| 296 |
+
<< " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
|
| 297 |
+
|
| 298 |
+
if (means[0])
|
| 299 |
+
cerr << "Total " << means[0] << " Mean "
|
| 300 |
+
<< (double)means[1] / means[0] << endl;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
/// Used to serialize access to std::cout to avoid multiple threads writing at
|
| 305 |
+
/// the same time.
|
| 306 |
+
|
| 307 |
+
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
| 308 |
+
|
| 309 |
+
static std::mutex m;
|
| 310 |
+
|
| 311 |
+
if (sc == IO_LOCK)
|
| 312 |
+
m.lock();
|
| 313 |
+
|
| 314 |
+
if (sc == IO_UNLOCK)
|
| 315 |
+
m.unlock();
|
| 316 |
+
|
| 317 |
+
return os;
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
/// Trampoline helper to avoid moving Logger to misc.h
|
| 322 |
+
void start_logger(const std::string& fname) { Logger::start(fname); }
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
|
| 326 |
+
/// function that doesn't stall the CPU waiting for data to be loaded from memory,
|
| 327 |
+
/// which can be quite slow.
|
| 328 |
+
#ifdef NO_PREFETCH
|
| 329 |
+
|
| 330 |
+
void prefetch(void*) {}
|
| 331 |
+
|
| 332 |
+
#else
|
| 333 |
+
|
| 334 |
+
void prefetch(void* addr) {
|
| 335 |
+
|
| 336 |
+
# if defined(__INTEL_COMPILER)
|
| 337 |
+
// This hack prevents prefetches from being optimized away by
|
| 338 |
+
// Intel compiler. Both MSVC and gcc seem not be affected by this.
|
| 339 |
+
__asm__ ("");
|
| 340 |
+
# endif
|
| 341 |
+
|
| 342 |
+
# if defined(__INTEL_COMPILER) || defined(_MSC_VER)
|
| 343 |
+
_mm_prefetch((char*)addr, _MM_HINT_T0);
|
| 344 |
+
# else
|
| 345 |
+
__builtin_prefetch(addr);
|
| 346 |
+
# endif
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
#endif
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
/// std_aligned_alloc() is our wrapper for systems where the c++17 implementation
|
| 353 |
+
/// does not guarantee the availability of aligned_alloc(). Memory allocated with
|
| 354 |
+
/// std_aligned_alloc() must be freed with std_aligned_free().
|
| 355 |
+
|
| 356 |
+
void* std_aligned_alloc(size_t alignment, size_t size) {
|
| 357 |
+
|
| 358 |
+
#if defined(POSIXALIGNEDALLOC)
|
| 359 |
+
void *mem;
|
| 360 |
+
return posix_memalign(&mem, alignment, size) ? nullptr : mem;
|
| 361 |
+
#elif defined(_WIN32)
|
| 362 |
+
return _mm_malloc(size, alignment);
|
| 363 |
+
#else
|
| 364 |
+
return aligned_alloc(alignment, size);
|
| 365 |
+
#endif
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
void std_aligned_free(void* ptr) {
|
| 369 |
+
|
| 370 |
+
#if defined(POSIXALIGNEDALLOC)
|
| 371 |
+
free(ptr);
|
| 372 |
+
#elif defined(_WIN32)
|
| 373 |
+
_mm_free(ptr);
|
| 374 |
+
#else
|
| 375 |
+
free(ptr);
|
| 376 |
+
#endif
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
/// aligned_large_pages_alloc() will return suitably aligned memory, if possible using large pages.
|
| 380 |
+
|
| 381 |
+
#if defined(_WIN32)
|
| 382 |
+
|
| 383 |
+
static void* aligned_large_pages_alloc_windows(size_t allocSize) {
|
| 384 |
+
|
| 385 |
+
#if !defined(_WIN64)
|
| 386 |
+
return nullptr;
|
| 387 |
+
#else
|
| 388 |
+
|
| 389 |
+
HANDLE hProcessToken { };
|
| 390 |
+
LUID luid { };
|
| 391 |
+
void* mem = nullptr;
|
| 392 |
+
|
| 393 |
+
const size_t largePageSize = GetLargePageMinimum();
|
| 394 |
+
if (!largePageSize)
|
| 395 |
+
return nullptr;
|
| 396 |
+
|
| 397 |
+
// We need SeLockMemoryPrivilege, so try to enable it for the process
|
| 398 |
+
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken))
|
| 399 |
+
return nullptr;
|
| 400 |
+
|
| 401 |
+
if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
|
| 402 |
+
{
|
| 403 |
+
TOKEN_PRIVILEGES tp { };
|
| 404 |
+
TOKEN_PRIVILEGES prevTp { };
|
| 405 |
+
DWORD prevTpLen = 0;
|
| 406 |
+
|
| 407 |
+
tp.PrivilegeCount = 1;
|
| 408 |
+
tp.Privileges[0].Luid = luid;
|
| 409 |
+
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
| 410 |
+
|
| 411 |
+
// Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
|
| 412 |
+
// we still need to query GetLastError() to ensure that the privileges were actually obtained.
|
| 413 |
+
if (AdjustTokenPrivileges(
|
| 414 |
+
hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
|
| 415 |
+
GetLastError() == ERROR_SUCCESS)
|
| 416 |
+
{
|
| 417 |
+
// Round up size to full pages and allocate
|
| 418 |
+
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
|
| 419 |
+
mem = VirtualAlloc(
|
| 420 |
+
NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
| 421 |
+
|
| 422 |
+
// Privilege no longer needed, restore previous state
|
| 423 |
+
AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL);
|
| 424 |
+
}
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
CloseHandle(hProcessToken);
|
| 428 |
+
|
| 429 |
+
return mem;
|
| 430 |
+
|
| 431 |
+
#endif
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
void* aligned_large_pages_alloc(size_t allocSize) {
|
| 435 |
+
|
| 436 |
+
// Try to allocate large pages
|
| 437 |
+
void* mem = aligned_large_pages_alloc_windows(allocSize);
|
| 438 |
+
|
| 439 |
+
// Fall back to regular, page aligned, allocation if necessary
|
| 440 |
+
if (!mem)
|
| 441 |
+
mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
| 442 |
+
|
| 443 |
+
return mem;
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
#else
|
| 447 |
+
|
| 448 |
+
void* aligned_large_pages_alloc(size_t allocSize) {
|
| 449 |
+
|
| 450 |
+
#if defined(__linux__)
|
| 451 |
+
constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page size
|
| 452 |
+
#else
|
| 453 |
+
constexpr size_t alignment = 4096; // assumed small page size
|
| 454 |
+
#endif
|
| 455 |
+
|
| 456 |
+
// round up to multiples of alignment
|
| 457 |
+
size_t size = ((allocSize + alignment - 1) / alignment) * alignment;
|
| 458 |
+
void *mem = std_aligned_alloc(alignment, size);
|
| 459 |
+
#if defined(MADV_HUGEPAGE)
|
| 460 |
+
madvise(mem, size, MADV_HUGEPAGE);
|
| 461 |
+
#endif
|
| 462 |
+
return mem;
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
#endif
|
| 466 |
+
|
| 467 |
+
|
| 468 |
+
/// aligned_large_pages_free() will free the previously allocated ttmem
|
| 469 |
+
|
| 470 |
+
#if defined(_WIN32)
|
| 471 |
+
|
| 472 |
+
void aligned_large_pages_free(void* mem) {
|
| 473 |
+
|
| 474 |
+
if (mem && !VirtualFree(mem, 0, MEM_RELEASE))
|
| 475 |
+
{
|
| 476 |
+
DWORD err = GetLastError();
|
| 477 |
+
std::cerr << "Failed to free large page memory. Error code: 0x"
|
| 478 |
+
<< std::hex << err
|
| 479 |
+
<< std::dec << std::endl;
|
| 480 |
+
exit(EXIT_FAILURE);
|
| 481 |
+
}
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
#else
|
| 485 |
+
|
| 486 |
+
void aligned_large_pages_free(void *mem) {
|
| 487 |
+
std_aligned_free(mem);
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
#endif
|
| 491 |
+
|
| 492 |
+
|
| 493 |
+
namespace WinProcGroup {
|
| 494 |
+
|
| 495 |
+
#ifndef _WIN32
|
| 496 |
+
|
| 497 |
+
void bindThisThread(size_t) {}
|
| 498 |
+
|
| 499 |
+
#else
|
| 500 |
+
|
| 501 |
+
/// best_group() retrieves logical processor information using Windows specific
|
| 502 |
+
/// API and returns the best group id for the thread with index idx. Original
|
| 503 |
+
/// code from Texel by Peter Österlund.
|
| 504 |
+
|
| 505 |
+
int best_group(size_t idx) {
|
| 506 |
+
|
| 507 |
+
int threads = 0;
|
| 508 |
+
int nodes = 0;
|
| 509 |
+
int cores = 0;
|
| 510 |
+
DWORD returnLength = 0;
|
| 511 |
+
DWORD byteOffset = 0;
|
| 512 |
+
|
| 513 |
+
// Early exit if the needed API is not available at runtime
|
| 514 |
+
HMODULE k32 = GetModuleHandle("Kernel32.dll");
|
| 515 |
+
auto fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
|
| 516 |
+
if (!fun1)
|
| 517 |
+
return -1;
|
| 518 |
+
|
| 519 |
+
// First call to get returnLength. We expect it to fail due to null buffer
|
| 520 |
+
if (fun1(RelationAll, nullptr, &returnLength))
|
| 521 |
+
return -1;
|
| 522 |
+
|
| 523 |
+
// Once we know returnLength, allocate the buffer
|
| 524 |
+
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
|
| 525 |
+
ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength);
|
| 526 |
+
|
| 527 |
+
// Second call, now we expect to succeed
|
| 528 |
+
if (!fun1(RelationAll, buffer, &returnLength))
|
| 529 |
+
{
|
| 530 |
+
free(buffer);
|
| 531 |
+
return -1;
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
while (byteOffset < returnLength)
|
| 535 |
+
{
|
| 536 |
+
if (ptr->Relationship == RelationNumaNode)
|
| 537 |
+
nodes++;
|
| 538 |
+
|
| 539 |
+
else if (ptr->Relationship == RelationProcessorCore)
|
| 540 |
+
{
|
| 541 |
+
cores++;
|
| 542 |
+
threads += (ptr->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
assert(ptr->Size);
|
| 546 |
+
byteOffset += ptr->Size;
|
| 547 |
+
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
free(buffer);
|
| 551 |
+
|
| 552 |
+
std::vector<int> groups;
|
| 553 |
+
|
| 554 |
+
// Run as many threads as possible on the same node until core limit is
|
| 555 |
+
// reached, then move on filling the next node.
|
| 556 |
+
for (int n = 0; n < nodes; n++)
|
| 557 |
+
for (int i = 0; i < cores / nodes; i++)
|
| 558 |
+
groups.push_back(n);
|
| 559 |
+
|
| 560 |
+
// In case a core has more than one logical processor (we assume 2) and we
|
| 561 |
+
// have still threads to allocate, then spread them evenly across available
|
| 562 |
+
// nodes.
|
| 563 |
+
for (int t = 0; t < threads - cores; t++)
|
| 564 |
+
groups.push_back(t % nodes);
|
| 565 |
+
|
| 566 |
+
// If we still have more threads than the total number of logical processors
|
| 567 |
+
// then return -1 and let the OS to decide what to do.
|
| 568 |
+
return idx < groups.size() ? groups[idx] : -1;
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
|
| 572 |
+
/// bindThisThread() set the group affinity of the current thread
|
| 573 |
+
|
| 574 |
+
void bindThisThread(size_t idx) {
|
| 575 |
+
|
| 576 |
+
// Use only local variables to be thread-safe
|
| 577 |
+
int group = best_group(idx);
|
| 578 |
+
|
| 579 |
+
if (group == -1)
|
| 580 |
+
return;
|
| 581 |
+
|
| 582 |
+
// Early exit if the needed API are not available at runtime
|
| 583 |
+
HMODULE k32 = GetModuleHandle("Kernel32.dll");
|
| 584 |
+
auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
|
| 585 |
+
auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity");
|
| 586 |
+
|
| 587 |
+
if (!fun2 || !fun3)
|
| 588 |
+
return;
|
| 589 |
+
|
| 590 |
+
GROUP_AFFINITY affinity;
|
| 591 |
+
if (fun2(group, &affinity))
|
| 592 |
+
fun3(GetCurrentThread(), &affinity, nullptr);
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
#endif
|
| 596 |
+
|
| 597 |
+
} // namespace WinProcGroup
|
| 598 |
+
|
| 599 |
+
#ifdef _WIN32
|
| 600 |
+
#include <direct.h>
|
| 601 |
+
#define GETCWD _getcwd
|
| 602 |
+
#else
|
| 603 |
+
#include <unistd.h>
|
| 604 |
+
#define GETCWD getcwd
|
| 605 |
+
#endif
|
| 606 |
+
|
| 607 |
+
namespace CommandLine {
|
| 608 |
+
|
| 609 |
+
string argv0; // path+name of the executable binary, as given by argv[0]
|
| 610 |
+
string binaryDirectory; // path of the executable directory
|
| 611 |
+
string workingDirectory; // path of the working directory
|
| 612 |
+
|
| 613 |
+
void init(int argc, char* argv[]) {
|
| 614 |
+
(void)argc;
|
| 615 |
+
string pathSeparator;
|
| 616 |
+
|
| 617 |
+
// extract the path+name of the executable binary
|
| 618 |
+
argv0 = argv[0];
|
| 619 |
+
|
| 620 |
+
#ifdef _WIN32
|
| 621 |
+
pathSeparator = "\\";
|
| 622 |
+
#ifdef _MSC_VER
|
| 623 |
+
// Under windows argv[0] may not have the extension. Also _get_pgmptr() had
|
| 624 |
+
// issues in some windows 10 versions, so check returned values carefully.
|
| 625 |
+
char* pgmptr = nullptr;
|
| 626 |
+
if (!_get_pgmptr(&pgmptr) && pgmptr != nullptr && *pgmptr)
|
| 627 |
+
argv0 = pgmptr;
|
| 628 |
+
#endif
|
| 629 |
+
#else
|
| 630 |
+
pathSeparator = "/";
|
| 631 |
+
#endif
|
| 632 |
+
|
| 633 |
+
// extract the working directory
|
| 634 |
+
workingDirectory = "";
|
| 635 |
+
char buff[40000];
|
| 636 |
+
char* cwd = GETCWD(buff, 40000);
|
| 637 |
+
if (cwd)
|
| 638 |
+
workingDirectory = cwd;
|
| 639 |
+
|
| 640 |
+
// extract the binary directory path from argv0
|
| 641 |
+
binaryDirectory = argv0;
|
| 642 |
+
size_t pos = binaryDirectory.find_last_of("\\/");
|
| 643 |
+
if (pos == std::string::npos)
|
| 644 |
+
binaryDirectory = "." + pathSeparator;
|
| 645 |
+
else
|
| 646 |
+
binaryDirectory.resize(pos + 1);
|
| 647 |
+
|
| 648 |
+
// pattern replacement: "./" at the start of path is replaced by the working directory
|
| 649 |
+
if (binaryDirectory.find("." + pathSeparator) == 0)
|
| 650 |
+
binaryDirectory.replace(0, 1, workingDirectory);
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
|
| 654 |
+
} // namespace CommandLine
|
| 655 |
+
|
| 656 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/misc.h
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef MISC_H_INCLUDED
|
| 20 |
+
#define MISC_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <cassert>
|
| 23 |
+
#include <chrono>
|
| 24 |
+
#include <ostream>
|
| 25 |
+
#include <string>
|
| 26 |
+
#include <vector>
|
| 27 |
+
#include <cstdint>
|
| 28 |
+
|
| 29 |
+
#include "types.h"
|
| 30 |
+
|
| 31 |
+
namespace Stockfish {
|
| 32 |
+
|
| 33 |
+
std::string engine_info(bool to_uci = false, bool to_xboard = false);
|
| 34 |
+
std::string compiler_info();
|
| 35 |
+
void prefetch(void* addr);
|
| 36 |
+
void start_logger(const std::string& fname);
|
| 37 |
+
void* std_aligned_alloc(size_t alignment, size_t size);
|
| 38 |
+
void std_aligned_free(void* ptr);
|
| 39 |
+
void* aligned_large_pages_alloc(size_t size); // memory aligned by page size, min alignment: 4096 bytes
|
| 40 |
+
void aligned_large_pages_free(void* mem); // nop if mem == nullptr
|
| 41 |
+
|
| 42 |
+
void dbg_hit_on(bool b);
|
| 43 |
+
void dbg_hit_on(bool c, bool b);
|
| 44 |
+
void dbg_mean_of(int v);
|
| 45 |
+
void dbg_print();
|
| 46 |
+
|
| 47 |
+
typedef std::chrono::milliseconds::rep TimePoint; // A value in milliseconds
|
| 48 |
+
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
|
| 49 |
+
inline TimePoint now() {
|
| 50 |
+
return std::chrono::duration_cast<std::chrono::milliseconds>
|
| 51 |
+
(std::chrono::steady_clock::now().time_since_epoch()).count();
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
template<class Entry, int Size>
|
| 55 |
+
struct HashTable {
|
| 56 |
+
Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; }
|
| 57 |
+
|
| 58 |
+
private:
|
| 59 |
+
std::vector<Entry> table = std::vector<Entry>(Size); // Allocate on the heap
|
| 60 |
+
};
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
enum SyncCout { IO_LOCK, IO_UNLOCK };
|
| 64 |
+
std::ostream& operator<<(std::ostream&, SyncCout);
|
| 65 |
+
|
| 66 |
+
#define sync_cout std::cout << IO_LOCK
|
| 67 |
+
#define sync_endl std::endl << IO_UNLOCK
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
// align_ptr_up() : get the first aligned element of an array.
|
| 71 |
+
// ptr must point to an array of size at least `sizeof(T) * N + alignment` bytes,
|
| 72 |
+
// where N is the number of elements in the array.
|
| 73 |
+
template <uintptr_t Alignment, typename T>
|
| 74 |
+
T* align_ptr_up(T* ptr)
|
| 75 |
+
{
|
| 76 |
+
static_assert(alignof(T) < Alignment);
|
| 77 |
+
|
| 78 |
+
const uintptr_t ptrint = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(ptr));
|
| 79 |
+
return reinterpret_cast<T*>(reinterpret_cast<char*>((ptrint + (Alignment - 1)) / Alignment * Alignment));
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
// IsLittleEndian : true if and only if the binary is compiled on a little endian machine
|
| 84 |
+
static inline const union { uint32_t i; char c[4]; } Le = { 0x01020304 };
|
| 85 |
+
static inline const bool IsLittleEndian = (Le.c[0] == 4);
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
template <typename T>
|
| 89 |
+
class ValueListInserter {
|
| 90 |
+
public:
|
| 91 |
+
ValueListInserter(T* v, std::size_t& s) :
|
| 92 |
+
values(v),
|
| 93 |
+
size(&s)
|
| 94 |
+
{
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
void push_back(const T& value) { values[(*size)++] = value; }
|
| 98 |
+
private:
|
| 99 |
+
T* values;
|
| 100 |
+
std::size_t* size;
|
| 101 |
+
};
|
| 102 |
+
|
| 103 |
+
template <typename T, std::size_t MaxSize>
|
| 104 |
+
class ValueList {
|
| 105 |
+
|
| 106 |
+
public:
|
| 107 |
+
std::size_t size() const { return size_; }
|
| 108 |
+
void resize(std::size_t newSize) { size_ = newSize; }
|
| 109 |
+
void push_back(const T& value) { values_[size_++] = value; }
|
| 110 |
+
T& operator[](std::size_t index) { return values_[index]; }
|
| 111 |
+
T* begin() { return values_; }
|
| 112 |
+
T* end() { return values_ + size_; }
|
| 113 |
+
const T& operator[](std::size_t index) const { return values_[index]; }
|
| 114 |
+
const T* begin() const { return values_; }
|
| 115 |
+
const T* end() const { return values_ + size_; }
|
| 116 |
+
operator ValueListInserter<T>() { return ValueListInserter(values_, size_); }
|
| 117 |
+
|
| 118 |
+
void swap(ValueList& other) {
|
| 119 |
+
const std::size_t maxSize = std::max(size_, other.size_);
|
| 120 |
+
for (std::size_t i = 0; i < maxSize; ++i) {
|
| 121 |
+
std::swap(values_[i], other.values_[i]);
|
| 122 |
+
}
|
| 123 |
+
std::swap(size_, other.size_);
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
private:
|
| 127 |
+
T values_[MaxSize];
|
| 128 |
+
std::size_t size_ = 0;
|
| 129 |
+
};
|
| 130 |
+
|
| 131 |
+
/// xorshift64star Pseudo-Random Number Generator
|
| 132 |
+
/// This class is based on original code written and dedicated
|
| 133 |
+
/// to the public domain by Sebastiano Vigna (2014).
|
| 134 |
+
/// It has the following characteristics:
|
| 135 |
+
///
|
| 136 |
+
/// - Outputs 64-bit numbers
|
| 137 |
+
/// - Passes Dieharder and SmallCrush test batteries
|
| 138 |
+
/// - Does not require warm-up, no zeroland to escape
|
| 139 |
+
/// - Internal state is a single 64-bit integer
|
| 140 |
+
/// - Period is 2^64 - 1
|
| 141 |
+
/// - Speed: 1.60 ns/call (Core i7 @3.40GHz)
|
| 142 |
+
///
|
| 143 |
+
/// For further analysis see
|
| 144 |
+
/// <http://vigna.di.unimi.it/ftp/papers/xorshift.pdf>
|
| 145 |
+
|
| 146 |
+
class PRNG {
|
| 147 |
+
|
| 148 |
+
uint64_t s;
|
| 149 |
+
|
| 150 |
+
uint64_t rand64() {
|
| 151 |
+
|
| 152 |
+
s ^= s >> 12, s ^= s << 25, s ^= s >> 27;
|
| 153 |
+
return s * 2685821657736338717LL;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
public:
|
| 157 |
+
PRNG(uint64_t seed) : s(seed) { assert(seed); }
|
| 158 |
+
|
| 159 |
+
template<typename T> T rand() { return T(rand64()); }
|
| 160 |
+
|
| 161 |
+
/// Special generator used to fast init magic numbers.
|
| 162 |
+
/// Output values only have 1/8th of their bits set on average.
|
| 163 |
+
template<typename T> T sparse_rand()
|
| 164 |
+
{ return T(rand64() & rand64() & rand64()); }
|
| 165 |
+
};
|
| 166 |
+
|
| 167 |
+
inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
| 168 |
+
#if defined(__GNUC__) && defined(IS_64BIT)
|
| 169 |
+
__extension__ typedef unsigned __int128 uint128;
|
| 170 |
+
return ((uint128)a * (uint128)b) >> 64;
|
| 171 |
+
#else
|
| 172 |
+
uint64_t aL = (uint32_t)a, aH = a >> 32;
|
| 173 |
+
uint64_t bL = (uint32_t)b, bH = b >> 32;
|
| 174 |
+
uint64_t c1 = (aL * bL) >> 32;
|
| 175 |
+
uint64_t c2 = aH * bL + c1;
|
| 176 |
+
uint64_t c3 = aL * bH + (uint32_t)c2;
|
| 177 |
+
return aH * bH + (c2 >> 32) + (c3 >> 32);
|
| 178 |
+
#endif
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
/// Under Windows it is not possible for a process to run on more than one
|
| 182 |
+
/// logical processor group. This usually means to be limited to use max 64
|
| 183 |
+
/// cores. To overcome this, some special platform specific API should be
|
| 184 |
+
/// called to set group affinity for each thread. Original code from Texel by
|
| 185 |
+
/// Peter Österlund.
|
| 186 |
+
|
| 187 |
+
namespace WinProcGroup {
|
| 188 |
+
void bindThisThread(size_t idx);
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
namespace CommandLine {
|
| 192 |
+
void init(int argc, char* argv[]);
|
| 193 |
+
|
| 194 |
+
extern std::string binaryDirectory; // path of the executable directory
|
| 195 |
+
extern std::string workingDirectory; // path of the working directory
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
} // namespace Stockfish
|
| 199 |
+
|
| 200 |
+
#endif // #ifndef MISC_H_INCLUDED
|
Fairy-Stockfish-master/src/movegen.cpp
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <cassert>
|
| 20 |
+
|
| 21 |
+
#include "movegen.h"
|
| 22 |
+
#include "position.h"
|
| 23 |
+
|
| 24 |
+
namespace Stockfish {
|
| 25 |
+
|
| 26 |
+
namespace {
|
| 27 |
+
|
| 28 |
+
template<MoveType T>
|
| 29 |
+
ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) {
|
| 30 |
+
|
| 31 |
+
// Wall placing moves
|
| 32 |
+
//if it's "wall or move", and they chose non-null move, skip even generating wall move
|
| 33 |
+
if (pos.walling() && !(pos.wall_or_move() && (from!=to)))
|
| 34 |
+
{
|
| 35 |
+
Bitboard b = pos.board_bb() & ~((pos.pieces() ^ from) | to);
|
| 36 |
+
if (T == CASTLING)
|
| 37 |
+
{
|
| 38 |
+
Square kto = make_square(to > from ? pos.castling_kingside_file() : pos.castling_queenside_file(), pos.castling_rank(us));
|
| 39 |
+
Direction step = kto > from ? EAST : WEST;
|
| 40 |
+
Square rto = kto - step;
|
| 41 |
+
b ^= square_bb(to) ^ kto ^ rto;
|
| 42 |
+
}
|
| 43 |
+
if (T == EN_PASSANT)
|
| 44 |
+
b ^= pos.capture_square(to);
|
| 45 |
+
|
| 46 |
+
if (pos.walling_rule() == ARROW)
|
| 47 |
+
b &= moves_bb(us, type_of(pos.piece_on(from)), to, pos.pieces() ^ from);
|
| 48 |
+
|
| 49 |
+
//Any current or future wall variant must follow the walling region rule if set:
|
| 50 |
+
b &= pos.walling_region(us);
|
| 51 |
+
|
| 52 |
+
if (pos.walling_rule() == PAST)
|
| 53 |
+
b &= square_bb(from);
|
| 54 |
+
if (pos.walling_rule() == EDGE)
|
| 55 |
+
{
|
| 56 |
+
Bitboard wallsquares = pos.state()->wallSquares;
|
| 57 |
+
|
| 58 |
+
b &= (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) |
|
| 59 |
+
( shift<NORTH >(wallsquares) | shift<SOUTH >(wallsquares)
|
| 60 |
+
| shift<EAST >(wallsquares) | shift<WEST >(wallsquares));
|
| 61 |
+
}
|
| 62 |
+
while (b)
|
| 63 |
+
*moveList++ = make_gating<T>(from, to, pt, pop_lsb(b));
|
| 64 |
+
return moveList;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
*moveList++ = make<T>(from, to, pt);
|
| 68 |
+
|
| 69 |
+
// Gating moves
|
| 70 |
+
if (pos.seirawan_gating() && (pos.gates(us) & from))
|
| 71 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 72 |
+
{
|
| 73 |
+
PieceType pt_gating = pop_lsb(ps);
|
| 74 |
+
if (pos.can_drop(us, pt_gating) && (pos.drop_region(us, pt_gating) & from))
|
| 75 |
+
*moveList++ = make_gating<T>(from, to, pt_gating, from);
|
| 76 |
+
}
|
| 77 |
+
if (pos.seirawan_gating() && T == CASTLING && (pos.gates(us) & to))
|
| 78 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 79 |
+
{
|
| 80 |
+
PieceType pt_gating = pop_lsb(ps);
|
| 81 |
+
if (pos.can_drop(us, pt_gating) && (pos.drop_region(us, pt_gating) & to))
|
| 82 |
+
*moveList++ = make_gating<T>(from, to, pt_gating, to);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
return moveList;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
template<Color c, GenType Type, Direction D>
|
| 89 |
+
ExtMove* make_promotions(const Position& pos, ExtMove* moveList, Square to) {
|
| 90 |
+
|
| 91 |
+
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 92 |
+
{
|
| 93 |
+
for (PieceSet promotions = pos.promotion_piece_types(c); promotions;)
|
| 94 |
+
{
|
| 95 |
+
PieceType pt = pop_msb(promotions);
|
| 96 |
+
if (!pos.promotion_limit(pt) || pos.promotion_limit(pt) > pos.count(c, pt))
|
| 97 |
+
moveList = make_move_and_gating<PROMOTION>(pos, moveList, pos.side_to_move(), to - D, to, pt);
|
| 98 |
+
}
|
| 99 |
+
PieceType pt = pos.promoted_piece_type(PAWN);
|
| 100 |
+
if (pt && !(pos.piece_promotion_on_capture() && pos.empty(to)))
|
| 101 |
+
moveList = make_move_and_gating<PIECE_PROMOTION>(pos, moveList, pos.side_to_move(), to - D, to);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
return moveList;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
template<Color Us, GenType Type>
|
| 108 |
+
ExtMove* generate_drops(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard b) {
|
| 109 |
+
assert(Type != CAPTURES);
|
| 110 |
+
// Do not generate virtual drops for perft and at root
|
| 111 |
+
if (pos.can_drop(Us, pt) || (Type != NON_EVASIONS && pos.two_boards() && pos.allow_virtual_drop(Us, pt)))
|
| 112 |
+
{
|
| 113 |
+
// Restrict to valid target
|
| 114 |
+
b &= pos.drop_region(Us, pt);
|
| 115 |
+
|
| 116 |
+
// Add to move list
|
| 117 |
+
if (pos.drop_promoted() && pos.promoted_piece_type(pt))
|
| 118 |
+
{
|
| 119 |
+
Bitboard b2 = b;
|
| 120 |
+
if (Type == QUIET_CHECKS)
|
| 121 |
+
b2 &= pos.check_squares(pos.promoted_piece_type(pt));
|
| 122 |
+
while (b2)
|
| 123 |
+
*moveList++ = make_drop(pop_lsb(b2), pt, pos.promoted_piece_type(pt));
|
| 124 |
+
}
|
| 125 |
+
if (Type == QUIET_CHECKS || !pos.can_drop(Us, pt))
|
| 126 |
+
b &= pos.check_squares(pt);
|
| 127 |
+
while (b)
|
| 128 |
+
*moveList++ = make_drop(pop_lsb(b), pt, pt);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
return moveList;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
template<Color Us, GenType Type>
|
| 135 |
+
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
|
| 136 |
+
|
| 137 |
+
if (!pos.pieces(Us, PAWN))
|
| 138 |
+
return moveList;
|
| 139 |
+
|
| 140 |
+
constexpr Color Them = ~Us;
|
| 141 |
+
constexpr Direction Up = pawn_push(Us);
|
| 142 |
+
constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
| 143 |
+
constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
| 144 |
+
|
| 145 |
+
const Bitboard promotionZone = pos.promotion_zone(Us);
|
| 146 |
+
const Bitboard standardPromotionZone = pos.sittuyin_promotion() ? Bitboard(0) : promotionZone;
|
| 147 |
+
const Bitboard doubleStepRegion = pos.double_step_region(Us);
|
| 148 |
+
const Bitboard tripleStepRegion = pos.triple_step_region(Us);
|
| 149 |
+
|
| 150 |
+
const Bitboard pawns = pos.pieces(Us, PAWN);
|
| 151 |
+
const Bitboard movable = pos.board_bb(Us, PAWN) & ~pos.pieces();
|
| 152 |
+
const Bitboard capturable = pos.board_bb(Us, PAWN) & pos.pieces(Them);
|
| 153 |
+
|
| 154 |
+
target = Type == EVASIONS ? target : AllSquares;
|
| 155 |
+
|
| 156 |
+
// Define single and double push, left and right capture, as well as respective promotion moves
|
| 157 |
+
Bitboard b1 = shift<Up>(pawns) & movable & target;
|
| 158 |
+
Bitboard b2 = shift<Up>(shift<Up>(pawns & doubleStepRegion) & movable) & movable & target;
|
| 159 |
+
Bitboard b3 = shift<Up>(shift<Up>(shift<Up>(pawns & tripleStepRegion) & movable) & movable) & movable & target;
|
| 160 |
+
Bitboard brc = shift<UpRight>(pawns) & capturable & target;
|
| 161 |
+
Bitboard blc = shift<UpLeft >(pawns) & capturable & target;
|
| 162 |
+
|
| 163 |
+
Bitboard b1p = b1 & standardPromotionZone;
|
| 164 |
+
Bitboard b2p = b2 & standardPromotionZone;
|
| 165 |
+
Bitboard b3p = b3 & standardPromotionZone;
|
| 166 |
+
Bitboard brcp = brc & standardPromotionZone;
|
| 167 |
+
Bitboard blcp = blc & standardPromotionZone;
|
| 168 |
+
|
| 169 |
+
// Restrict regions based on rules and move generation type
|
| 170 |
+
if (pos.mandatory_pawn_promotion())
|
| 171 |
+
{
|
| 172 |
+
b1 &= ~standardPromotionZone;
|
| 173 |
+
b2 &= ~standardPromotionZone;
|
| 174 |
+
b3 &= ~standardPromotionZone;
|
| 175 |
+
brc &= ~standardPromotionZone;
|
| 176 |
+
blc &= ~standardPromotionZone;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
if (Type == QUIET_CHECKS && pos.count<KING>(Them))
|
| 180 |
+
{
|
| 181 |
+
// To make a quiet check, you either make a direct check by pushing a pawn
|
| 182 |
+
// or push a blocker pawn that is not on the same file as the enemy king.
|
| 183 |
+
// Discovered check promotion has been already generated amongst the captures.
|
| 184 |
+
Square ksq = pos.square<KING>(Them);
|
| 185 |
+
Bitboard dcCandidatePawns = pos.blockers_for_king(Them) & ~file_bb(ksq);
|
| 186 |
+
b1 &= pawn_attacks_bb(Them, ksq) | shift< Up>(dcCandidatePawns);
|
| 187 |
+
b2 &= pawn_attacks_bb(Them, ksq) | shift<Up+Up>(dcCandidatePawns);
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
// Single and double pawn pushes, no promotions
|
| 191 |
+
if (Type != CAPTURES)
|
| 192 |
+
{
|
| 193 |
+
while (b1)
|
| 194 |
+
{
|
| 195 |
+
Square to = pop_lsb(b1);
|
| 196 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, to - Up, to);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
while (b2)
|
| 200 |
+
{
|
| 201 |
+
Square to = pop_lsb(b2);
|
| 202 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, to - Up - Up, to);
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
while (b3)
|
| 206 |
+
{
|
| 207 |
+
Square to = pop_lsb(b3);
|
| 208 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, to - Up - Up - Up, to);
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
// Promotions and underpromotions
|
| 213 |
+
while (brcp)
|
| 214 |
+
moveList = make_promotions<Us, Type, UpRight>(pos, moveList, pop_lsb(brcp));
|
| 215 |
+
|
| 216 |
+
while (blcp)
|
| 217 |
+
moveList = make_promotions<Us, Type, UpLeft >(pos, moveList, pop_lsb(blcp));
|
| 218 |
+
|
| 219 |
+
while (b1p)
|
| 220 |
+
moveList = make_promotions<Us, Type, Up >(pos, moveList, pop_lsb(b1p));
|
| 221 |
+
|
| 222 |
+
while (b2p)
|
| 223 |
+
moveList = make_promotions<Us, Type, Up+Up >(pos, moveList, pop_lsb(b2p));
|
| 224 |
+
|
| 225 |
+
while (b3p)
|
| 226 |
+
moveList = make_promotions<Us, Type, Up+Up+Up>(pos, moveList, pop_lsb(b3p));
|
| 227 |
+
|
| 228 |
+
// Sittuyin promotions
|
| 229 |
+
if (pos.sittuyin_promotion() && (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS))
|
| 230 |
+
{
|
| 231 |
+
// Pawns need to be in promotion zone if there is more than one pawn
|
| 232 |
+
Bitboard promotionPawns = pos.count<PAWN>(Us) > 1 ? pawns & promotionZone : pawns;
|
| 233 |
+
while (promotionPawns)
|
| 234 |
+
{
|
| 235 |
+
Square from = pop_lsb(promotionPawns);
|
| 236 |
+
for (PieceSet ps = pos.promotion_piece_types(Us); ps;)
|
| 237 |
+
{
|
| 238 |
+
PieceType pt = pop_msb(ps);
|
| 239 |
+
if (pos.promotion_limit(pt) && pos.promotion_limit(pt) <= pos.count(Us, pt))
|
| 240 |
+
continue;
|
| 241 |
+
Bitboard b = ((pos.attacks_from(Us, pt, from) & ~pos.pieces()) | from) & target;
|
| 242 |
+
while (b)
|
| 243 |
+
{
|
| 244 |
+
Square to = pop_lsb(b);
|
| 245 |
+
if (!(attacks_bb(Us, pt, to, pos.pieces() ^ from) & pos.pieces(Them)))
|
| 246 |
+
*moveList++ = make<PROMOTION>(from, to, pt);
|
| 247 |
+
}
|
| 248 |
+
}
|
| 249 |
+
}
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
// Standard and en passant captures
|
| 253 |
+
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 254 |
+
{
|
| 255 |
+
while (brc)
|
| 256 |
+
{
|
| 257 |
+
Square to = pop_lsb(brc);
|
| 258 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, to - UpRight, to);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
while (blc)
|
| 262 |
+
{
|
| 263 |
+
Square to = pop_lsb(blc);
|
| 264 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, to - UpLeft, to);
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
for (Bitboard epSquares = pos.ep_squares() & ~pos.pieces(); epSquares; )
|
| 268 |
+
{
|
| 269 |
+
Square epSquare = pop_lsb(epSquares);
|
| 270 |
+
|
| 271 |
+
// An en passant capture cannot resolve a discovered check (unless there non-sliding riders)
|
| 272 |
+
if (Type == EVASIONS && (target & (epSquare + Up)) && !pos.non_sliding_riders())
|
| 273 |
+
return moveList;
|
| 274 |
+
|
| 275 |
+
Bitboard b = pawns & pawn_attacks_bb(Them, epSquare);
|
| 276 |
+
|
| 277 |
+
// En passant square is already disabled for non-fairy variants if there is no attacker
|
| 278 |
+
assert(b || !pos.fast_attacks());
|
| 279 |
+
|
| 280 |
+
while (b)
|
| 281 |
+
moveList = make_move_and_gating<EN_PASSANT>(pos, moveList, Us, pop_lsb(b), epSquare);
|
| 282 |
+
}
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
return moveList;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
template<Color Us, GenType Type>
|
| 290 |
+
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, PieceType Pt, Bitboard target) {
|
| 291 |
+
|
| 292 |
+
assert(Pt != KING && Pt != PAWN);
|
| 293 |
+
|
| 294 |
+
Bitboard bb = pos.pieces(Us, Pt);
|
| 295 |
+
|
| 296 |
+
while (bb)
|
| 297 |
+
{
|
| 298 |
+
Square from = pop_lsb(bb);
|
| 299 |
+
|
| 300 |
+
Bitboard attacks = pos.attacks_from(Us, Pt, from);
|
| 301 |
+
Bitboard quiets = pos.moves_from(Us, Pt, from);
|
| 302 |
+
Bitboard b = ( (attacks & pos.pieces())
|
| 303 |
+
| (quiets & ~pos.pieces()));
|
| 304 |
+
Bitboard b1 = b & target;
|
| 305 |
+
Bitboard promotion_zone = pos.promotion_zone(Us);
|
| 306 |
+
PieceType promPt = pos.promoted_piece_type(Pt);
|
| 307 |
+
Bitboard b2 = promPt && (!pos.promotion_limit(promPt) || pos.promotion_limit(promPt) > pos.count(Us, promPt)) ? b1 : Bitboard(0);
|
| 308 |
+
Bitboard b3 = pos.piece_demotion() && pos.is_promoted(from) ? b1 : Bitboard(0);
|
| 309 |
+
Bitboard pawnPromotions = (pos.promotion_pawn_types(Us) & Pt) ? (b & (Type == EVASIONS ? target : ~pos.pieces(Us)) & promotion_zone) : Bitboard(0);
|
| 310 |
+
Bitboard epSquares = (pos.en_passant_types(Us) & Pt) ? (attacks & ~quiets & pos.ep_squares() & ~pos.pieces()) : Bitboard(0);
|
| 311 |
+
|
| 312 |
+
// target squares considering pawn promotions
|
| 313 |
+
if (pawnPromotions && pos.mandatory_pawn_promotion())
|
| 314 |
+
b1 &= ~pawnPromotions;
|
| 315 |
+
|
| 316 |
+
// Restrict target squares considering promotion zone
|
| 317 |
+
if (b2 | b3)
|
| 318 |
+
{
|
| 319 |
+
if (pos.mandatory_piece_promotion())
|
| 320 |
+
b1 &= (promotion_zone & from ? Bitboard(0) : ~promotion_zone) | (pos.piece_promotion_on_capture() ? ~pos.pieces() : Bitboard(0));
|
| 321 |
+
// Exclude quiet promotions/demotions
|
| 322 |
+
if (pos.piece_promotion_on_capture())
|
| 323 |
+
{
|
| 324 |
+
b2 &= pos.pieces();
|
| 325 |
+
b3 &= pos.pieces();
|
| 326 |
+
}
|
| 327 |
+
// Consider promotions/demotions into promotion zone
|
| 328 |
+
if (!(promotion_zone & from))
|
| 329 |
+
{
|
| 330 |
+
b2 &= promotion_zone;
|
| 331 |
+
b3 &= promotion_zone;
|
| 332 |
+
}
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
if (Type == QUIET_CHECKS)
|
| 336 |
+
{
|
| 337 |
+
b1 &= pos.check_squares(Pt);
|
| 338 |
+
if (b2)
|
| 339 |
+
b2 &= pos.check_squares(pos.promoted_piece_type(Pt));
|
| 340 |
+
if (b3)
|
| 341 |
+
b3 &= pos.check_squares(type_of(pos.unpromoted_piece_on(from)));
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
while (b1)
|
| 345 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, from, pop_lsb(b1));
|
| 346 |
+
|
| 347 |
+
// Shogi-style piece promotions
|
| 348 |
+
while (b2)
|
| 349 |
+
*moveList++ = make<PIECE_PROMOTION>(from, pop_lsb(b2));
|
| 350 |
+
|
| 351 |
+
// Piece demotions
|
| 352 |
+
while (b3)
|
| 353 |
+
*moveList++ = make<PIECE_DEMOTION>(from, pop_lsb(b3));
|
| 354 |
+
|
| 355 |
+
// Pawn-style promotions
|
| 356 |
+
if ((Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) && pawnPromotions)
|
| 357 |
+
for (PieceSet ps = pos.promotion_piece_types(Us); ps;)
|
| 358 |
+
{
|
| 359 |
+
PieceType ptP = pop_msb(ps);
|
| 360 |
+
if (!pos.promotion_limit(ptP) || pos.promotion_limit(ptP) > pos.count(Us, ptP))
|
| 361 |
+
for (Bitboard promotions = pawnPromotions; promotions; )
|
| 362 |
+
moveList = make_move_and_gating<PROMOTION>(pos, moveList, pos.side_to_move(), from, pop_lsb(promotions), ptP);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
// En passant captures
|
| 366 |
+
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 367 |
+
while (epSquares)
|
| 368 |
+
moveList = make_move_and_gating<EN_PASSANT>(pos, moveList, Us, from, pop_lsb(epSquares));
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
return moveList;
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
template<Color Us, GenType Type>
|
| 376 |
+
ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
|
| 377 |
+
|
| 378 |
+
static_assert(Type != LEGAL, "Unsupported type in generate_all()");
|
| 379 |
+
|
| 380 |
+
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantiations
|
| 381 |
+
const Square ksq = pos.count<KING>(Us) ? pos.square<KING>(Us) : SQ_NONE;
|
| 382 |
+
Bitboard target;
|
| 383 |
+
|
| 384 |
+
// Skip generating non-king moves when in double check
|
| 385 |
+
if (Type != EVASIONS || !more_than_one(pos.checkers() & ~pos.non_sliding_riders()))
|
| 386 |
+
{
|
| 387 |
+
target = Type == EVASIONS ? between_bb(ksq, lsb(pos.checkers()))
|
| 388 |
+
: Type == NON_EVASIONS ? ~pos.pieces( Us)
|
| 389 |
+
: Type == CAPTURES ? pos.pieces(~Us)
|
| 390 |
+
: ~pos.pieces( ); // QUIETS || QUIET_CHECKS
|
| 391 |
+
|
| 392 |
+
if (Type == EVASIONS)
|
| 393 |
+
{
|
| 394 |
+
if (pos.checkers() & pos.non_sliding_riders())
|
| 395 |
+
target = ~pos.pieces(Us);
|
| 396 |
+
// Leaper attacks can not be blocked
|
| 397 |
+
Square checksq = lsb(pos.checkers());
|
| 398 |
+
if (LeaperAttacks[~Us][type_of(pos.piece_on(checksq))][checksq] & pos.square<KING>(Us))
|
| 399 |
+
target = pos.checkers();
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
// Remove inaccessible squares (outside board + wall squares)
|
| 403 |
+
target &= pos.board_bb();
|
| 404 |
+
|
| 405 |
+
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
|
| 406 |
+
for (PieceSet ps = pos.piece_types() & ~(piece_set(PAWN) | KING); ps;)
|
| 407 |
+
moveList = generate_moves<Us, Type>(pos, moveList, pop_lsb(ps), target);
|
| 408 |
+
// generate drops
|
| 409 |
+
if (pos.piece_drops() && Type != CAPTURES && (pos.can_drop(Us, ALL_PIECES) || pos.two_boards()))
|
| 410 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 411 |
+
moveList = generate_drops<Us, Type>(pos, moveList, pop_lsb(ps), target & ~pos.pieces(~Us));
|
| 412 |
+
|
| 413 |
+
// Castling with non-king piece
|
| 414 |
+
if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(Us & ANY_CASTLING))
|
| 415 |
+
{
|
| 416 |
+
Square from = pos.castling_king_square(Us);
|
| 417 |
+
for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
|
| 418 |
+
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
|
| 419 |
+
moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(cr));
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
// Special moves
|
| 423 |
+
if (pos.cambodian_moves() && pos.gates(Us) && Type != CAPTURES)
|
| 424 |
+
{
|
| 425 |
+
if (Type != EVASIONS && (pos.pieces(Us, KING) & pos.gates(Us)))
|
| 426 |
+
{
|
| 427 |
+
Square from = pos.square<KING>(Us);
|
| 428 |
+
Bitboard b = PseudoAttacks[WHITE][KNIGHT][from] & rank_bb(rank_of(from + (Us == WHITE ? NORTH : SOUTH)))
|
| 429 |
+
& target & ~pos.pieces();
|
| 430 |
+
while (b)
|
| 431 |
+
moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, from, pop_lsb(b));
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
Bitboard b = pos.pieces(Us, FERS) & pos.gates(Us);
|
| 435 |
+
while (b)
|
| 436 |
+
{
|
| 437 |
+
Square from = pop_lsb(b);
|
| 438 |
+
Square to = from + 2 * (Us == WHITE ? NORTH : SOUTH);
|
| 439 |
+
if (is_ok(to) && (target & to & ~pos.pieces()))
|
| 440 |
+
moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, from, to);
|
| 441 |
+
}
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
// Workaround for passing: Execute a non-move with any piece
|
| 445 |
+
if (pos.pass(Us) && !pos.count<KING>(Us) && pos.pieces(Us))
|
| 446 |
+
*moveList++ = make<SPECIAL>(lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
|
| 447 |
+
|
| 448 |
+
//if "wall or move", generate walling action with null move
|
| 449 |
+
if (pos.wall_or_move())
|
| 450 |
+
{
|
| 451 |
+
moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
|
| 452 |
+
}
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
// King moves
|
| 456 |
+
if (pos.count<KING>(Us) && (!Checks || pos.blockers_for_king(~Us) & ksq))
|
| 457 |
+
{
|
| 458 |
+
Bitboard b = ( (pos.attacks_from(Us, KING, ksq) & pos.pieces())
|
| 459 |
+
| (pos.moves_from(Us, KING, ksq) & ~pos.pieces())) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
|
| 460 |
+
while (b)
|
| 461 |
+
moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(b));
|
| 462 |
+
|
| 463 |
+
// Passing move by king
|
| 464 |
+
if (pos.pass(Us))
|
| 465 |
+
*moveList++ = make<SPECIAL>(ksq, ksq);
|
| 466 |
+
|
| 467 |
+
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
|
| 468 |
+
for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
|
| 469 |
+
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
|
| 470 |
+
moveList = make_move_and_gating<CASTLING>(pos, moveList, Us,ksq, pos.castling_rook_square(cr));
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
return moveList;
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
} // namespace
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
/// <CAPTURES> Generates all pseudo-legal captures plus queen promotions
|
| 480 |
+
/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions
|
| 481 |
+
/// <EVASIONS> Generates all pseudo-legal check evasions when the side to move is in check
|
| 482 |
+
/// <QUIET_CHECKS> Generates all pseudo-legal non-captures giving check, except castling and promotions
|
| 483 |
+
/// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
|
| 484 |
+
///
|
| 485 |
+
/// Returns a pointer to the end of the move list.
|
| 486 |
+
|
| 487 |
+
template<GenType Type>
|
| 488 |
+
ExtMove* generate(const Position& pos, ExtMove* moveList) {
|
| 489 |
+
|
| 490 |
+
static_assert(Type != LEGAL, "Unsupported type in generate()");
|
| 491 |
+
assert((Type == EVASIONS) == (bool)pos.checkers());
|
| 492 |
+
|
| 493 |
+
Color us = pos.side_to_move();
|
| 494 |
+
|
| 495 |
+
return us == WHITE ? generate_all<WHITE, Type>(pos, moveList)
|
| 496 |
+
: generate_all<BLACK, Type>(pos, moveList);
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
// Explicit template instantiations
|
| 500 |
+
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
|
| 501 |
+
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
|
| 502 |
+
template ExtMove* generate<EVASIONS>(const Position&, ExtMove*);
|
| 503 |
+
template ExtMove* generate<QUIET_CHECKS>(const Position&, ExtMove*);
|
| 504 |
+
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
|
| 505 |
+
|
| 506 |
+
|
| 507 |
+
/// generate<LEGAL> generates all the legal moves in the given position
|
| 508 |
+
|
| 509 |
+
template<>
|
| 510 |
+
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
|
| 511 |
+
|
| 512 |
+
if (pos.is_immediate_game_end())
|
| 513 |
+
return moveList;
|
| 514 |
+
|
| 515 |
+
ExtMove* cur = moveList;
|
| 516 |
+
|
| 517 |
+
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
|
| 518 |
+
: generate<NON_EVASIONS>(pos, moveList);
|
| 519 |
+
while (cur != moveList)
|
| 520 |
+
if (!pos.legal(*cur) || pos.virtual_drop(*cur))
|
| 521 |
+
*cur = (--moveList)->move;
|
| 522 |
+
else
|
| 523 |
+
++cur;
|
| 524 |
+
|
| 525 |
+
return moveList;
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/movegen.h
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef MOVEGEN_H_INCLUDED
|
| 20 |
+
#define MOVEGEN_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <algorithm>
|
| 23 |
+
|
| 24 |
+
#include "types.h"
|
| 25 |
+
|
| 26 |
+
namespace Stockfish {
|
| 27 |
+
|
| 28 |
+
class Position;
|
| 29 |
+
|
| 30 |
+
enum GenType {
|
| 31 |
+
CAPTURES,
|
| 32 |
+
QUIETS,
|
| 33 |
+
QUIET_CHECKS,
|
| 34 |
+
EVASIONS,
|
| 35 |
+
NON_EVASIONS,
|
| 36 |
+
LEGAL
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
struct ExtMove {
|
| 40 |
+
Move move;
|
| 41 |
+
int value;
|
| 42 |
+
|
| 43 |
+
operator Move() const { return move; }
|
| 44 |
+
void operator=(Move m) { move = m; }
|
| 45 |
+
|
| 46 |
+
// Inhibit unwanted implicit conversions to Move
|
| 47 |
+
// with an ambiguity that yields to a compile error.
|
| 48 |
+
operator float() const = delete;
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
inline bool operator<(const ExtMove& f, const ExtMove& s) {
|
| 52 |
+
return f.value < s.value;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
template<GenType>
|
| 56 |
+
ExtMove* generate(const Position& pos, ExtMove* moveList);
|
| 57 |
+
|
| 58 |
+
constexpr size_t moveListSize = sizeof(ExtMove) * MAX_MOVES;
|
| 59 |
+
|
| 60 |
+
/// The MoveList struct is a simple wrapper around generate(). It sometimes comes
|
| 61 |
+
/// in handy to use this class instead of the low level generate() function.
|
| 62 |
+
template<GenType T>
|
| 63 |
+
struct MoveList {
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
#ifdef USE_HEAP_INSTEAD_OF_STACK_FOR_MOVE_LIST
|
| 67 |
+
explicit MoveList(const Position& pos)
|
| 68 |
+
{
|
| 69 |
+
this->moveList = (ExtMove*)malloc(moveListSize);
|
| 70 |
+
if (this->moveList == 0)
|
| 71 |
+
{
|
| 72 |
+
printf("Error: Failed to allocate memory in heap.");
|
| 73 |
+
exit(1);
|
| 74 |
+
}
|
| 75 |
+
this->last = generate<T>(pos, this->moveList);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
~MoveList()
|
| 79 |
+
{
|
| 80 |
+
free(this->moveList);
|
| 81 |
+
}
|
| 82 |
+
#else
|
| 83 |
+
explicit MoveList(const Position& pos) : last(generate<T>(pos, moveList))
|
| 84 |
+
{
|
| 85 |
+
;
|
| 86 |
+
}
|
| 87 |
+
#endif
|
| 88 |
+
|
| 89 |
+
const ExtMove* begin() const { return moveList; }
|
| 90 |
+
const ExtMove* end() const { return last; }
|
| 91 |
+
size_t size() const { return last - moveList; }
|
| 92 |
+
bool contains(Move move) const {
|
| 93 |
+
return std::find(begin(), end(), move) != end();
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
private:
|
| 97 |
+
ExtMove* last;
|
| 98 |
+
#ifdef USE_HEAP_INSTEAD_OF_STACK_FOR_MOVE_LIST
|
| 99 |
+
ExtMove* moveList = 0;
|
| 100 |
+
#else
|
| 101 |
+
ExtMove moveList[MAX_MOVES];
|
| 102 |
+
#endif
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
} // namespace Stockfish
|
| 106 |
+
|
| 107 |
+
#endif // #ifndef MOVEGEN_H_INCLUDED
|
Fairy-Stockfish-master/src/movepick.cpp
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#include <cassert>
|
| 20 |
+
|
| 21 |
+
#include "movepick.h"
|
| 22 |
+
|
| 23 |
+
namespace Stockfish {
|
| 24 |
+
|
| 25 |
+
// Since continuation history grows quadratically with the number of piece types,
|
| 26 |
+
// we need to reserve a limited number of slots and map piece types to these slots
|
| 27 |
+
// in order to reduce memory consumption to a reasonable level.
|
| 28 |
+
int history_slot(Piece pc) {
|
| 29 |
+
return pc == NO_PIECE ? 0 : (type_of(pc) == KING ? PIECE_SLOTS - 1 : type_of(pc) % (PIECE_SLOTS - 1)) + color_of(pc) * PIECE_SLOTS;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
namespace {
|
| 33 |
+
|
| 34 |
+
enum Stages {
|
| 35 |
+
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE,
|
| 36 |
+
EVASION_TT, EVASION_INIT, EVASION,
|
| 37 |
+
PROBCUT_TT, PROBCUT_INIT, PROBCUT,
|
| 38 |
+
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
// partial_insertion_sort() sorts moves in descending order up to and including
|
| 42 |
+
// a given limit. The order of moves smaller than the limit is left unspecified.
|
| 43 |
+
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
|
| 44 |
+
|
| 45 |
+
for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p)
|
| 46 |
+
if (p->value >= limit)
|
| 47 |
+
{
|
| 48 |
+
ExtMove tmp = *p, *q;
|
| 49 |
+
*p = *++sortedEnd;
|
| 50 |
+
for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
|
| 51 |
+
*q = *(q - 1);
|
| 52 |
+
*q = tmp;
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
} // namespace
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
/// Constructors of the MovePicker class. As arguments we pass information
|
| 60 |
+
/// to help it to return the (presumably) good moves first, to decide which
|
| 61 |
+
/// moves to return (in the quiescence search, for instance, we only want to
|
| 62 |
+
/// search captures, promotions, and some checks) and how important good move
|
| 63 |
+
/// ordering is at the current node.
|
| 64 |
+
|
| 65 |
+
/// MovePicker constructor for the main search
|
| 66 |
+
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const GateHistory* dh, const LowPlyHistory* lp,
|
| 67 |
+
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl)
|
| 68 |
+
: pos(p), mainHistory(mh), gateHistory(dh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch),
|
| 69 |
+
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) {
|
| 70 |
+
|
| 71 |
+
assert(d > 0);
|
| 72 |
+
|
| 73 |
+
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
|
| 74 |
+
!(ttm && pos.pseudo_legal(ttm));
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
/// MovePicker constructor for quiescence search
|
| 78 |
+
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const GateHistory* dh,
|
| 79 |
+
const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
|
| 80 |
+
: pos(p), mainHistory(mh), gateHistory(dh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) {
|
| 81 |
+
|
| 82 |
+
assert(d <= 0);
|
| 83 |
+
|
| 84 |
+
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
|
| 85 |
+
!( ttm
|
| 86 |
+
&& (pos.checkers() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
|
| 87 |
+
&& pos.pseudo_legal(ttm));
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
|
| 91 |
+
/// than or equal to the given threshold.
|
| 92 |
+
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const GateHistory* dh, const CapturePieceToHistory* cph)
|
| 93 |
+
: pos(p), gateHistory(dh), captureHistory(cph), ttMove(ttm), threshold(th) {
|
| 94 |
+
|
| 95 |
+
assert(!pos.checkers());
|
| 96 |
+
|
| 97 |
+
stage = PROBCUT_TT + !(ttm && pos.capture(ttm)
|
| 98 |
+
&& pos.pseudo_legal(ttm)
|
| 99 |
+
&& pos.see_ge(ttm, threshold));
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/// MovePicker::score() assigns a numerical value to each move in a list, used
|
| 103 |
+
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
|
| 104 |
+
/// captures with a good history. Quiets moves are ordered using the histories.
|
| 105 |
+
template<GenType Type>
|
| 106 |
+
void MovePicker::score() {
|
| 107 |
+
|
| 108 |
+
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
|
| 109 |
+
|
| 110 |
+
for (auto& m : *this)
|
| 111 |
+
if constexpr (Type == CAPTURES)
|
| 112 |
+
m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6
|
| 113 |
+
+ (*gateHistory)[pos.side_to_move()][gating_square(m)]
|
| 114 |
+
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))];
|
| 115 |
+
|
| 116 |
+
else if constexpr (Type == QUIETS)
|
| 117 |
+
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
| 118 |
+
+ (*gateHistory)[pos.side_to_move()][gating_square(m)]
|
| 119 |
+
+ 2 * (*continuationHistory[0])[history_slot(pos.moved_piece(m))][to_sq(m)]
|
| 120 |
+
+ (*continuationHistory[1])[history_slot(pos.moved_piece(m))][to_sq(m)]
|
| 121 |
+
+ (*continuationHistory[3])[history_slot(pos.moved_piece(m))][to_sq(m)]
|
| 122 |
+
+ (*continuationHistory[5])[history_slot(pos.moved_piece(m))][to_sq(m)]
|
| 123 |
+
+ (ply < MAX_LPH ? std::min(4, depth / 3) * (*lowPlyHistory)[ply][from_to(m)] : 0);
|
| 124 |
+
|
| 125 |
+
else // Type == EVASIONS
|
| 126 |
+
{
|
| 127 |
+
if (pos.capture(m))
|
| 128 |
+
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
| 129 |
+
- Value(type_of(pos.moved_piece(m)));
|
| 130 |
+
else
|
| 131 |
+
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
| 132 |
+
+ 2 * (*continuationHistory[0])[history_slot(pos.moved_piece(m))][to_sq(m)]
|
| 133 |
+
- (1 << 28);
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
/// MovePicker::select() returns the next move satisfying a predicate function.
|
| 138 |
+
/// It never returns the TT move.
|
| 139 |
+
template<MovePicker::PickType T, typename Pred>
|
| 140 |
+
Move MovePicker::select(Pred filter) {
|
| 141 |
+
|
| 142 |
+
while (cur < endMoves)
|
| 143 |
+
{
|
| 144 |
+
if (T == Best)
|
| 145 |
+
std::swap(*cur, *std::max_element(cur, endMoves));
|
| 146 |
+
|
| 147 |
+
if (*cur != ttMove && filter())
|
| 148 |
+
return *cur++;
|
| 149 |
+
|
| 150 |
+
cur++;
|
| 151 |
+
}
|
| 152 |
+
return MOVE_NONE;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
/// MovePicker::next_move() is the most important method of the MovePicker class. It
|
| 156 |
+
/// returns a new pseudo-legal move every time it is called until there are no more
|
| 157 |
+
/// moves left, picking the move with the highest score from a list of generated moves.
|
| 158 |
+
Move MovePicker::next_move(bool skipQuiets) {
|
| 159 |
+
|
| 160 |
+
top:
|
| 161 |
+
switch (stage) {
|
| 162 |
+
|
| 163 |
+
case MAIN_TT:
|
| 164 |
+
case EVASION_TT:
|
| 165 |
+
case QSEARCH_TT:
|
| 166 |
+
case PROBCUT_TT:
|
| 167 |
+
++stage;
|
| 168 |
+
assert(pos.legal(ttMove) == MoveList<LEGAL>(pos).contains(ttMove) || pos.virtual_drop(ttMove));
|
| 169 |
+
return ttMove;
|
| 170 |
+
|
| 171 |
+
case CAPTURE_INIT:
|
| 172 |
+
case PROBCUT_INIT:
|
| 173 |
+
case QCAPTURE_INIT:
|
| 174 |
+
cur = endBadCaptures = moves;
|
| 175 |
+
endMoves = generate<CAPTURES>(pos, cur);
|
| 176 |
+
|
| 177 |
+
score<CAPTURES>();
|
| 178 |
+
++stage;
|
| 179 |
+
goto top;
|
| 180 |
+
|
| 181 |
+
case GOOD_CAPTURE:
|
| 182 |
+
if (select<Best>([&](){
|
| 183 |
+
return pos.see_ge(*cur, Value(-69 * cur->value / 1024 - 500 * (pos.captures_to_hand() && pos.gives_check(*cur))))?
|
| 184 |
+
// Move losing capture to endBadCaptures to be tried later
|
| 185 |
+
true : (*endBadCaptures++ = *cur, false); }))
|
| 186 |
+
return *(cur - 1);
|
| 187 |
+
|
| 188 |
+
// Prepare the pointers to loop over the refutations array
|
| 189 |
+
cur = std::begin(refutations);
|
| 190 |
+
endMoves = std::end(refutations);
|
| 191 |
+
|
| 192 |
+
// If the countermove is the same as a killer, skip it
|
| 193 |
+
if ( refutations[0].move == refutations[2].move
|
| 194 |
+
|| refutations[1].move == refutations[2].move)
|
| 195 |
+
--endMoves;
|
| 196 |
+
|
| 197 |
+
++stage;
|
| 198 |
+
[[fallthrough]];
|
| 199 |
+
|
| 200 |
+
case REFUTATION:
|
| 201 |
+
if (select<Next>([&](){ return *cur != MOVE_NONE
|
| 202 |
+
&& !pos.capture(*cur)
|
| 203 |
+
&& pos.pseudo_legal(*cur); }))
|
| 204 |
+
return *(cur - 1);
|
| 205 |
+
++stage;
|
| 206 |
+
[[fallthrough]];
|
| 207 |
+
|
| 208 |
+
case QUIET_INIT:
|
| 209 |
+
if (!skipQuiets && !(pos.must_capture() && pos.has_capture()))
|
| 210 |
+
{
|
| 211 |
+
cur = endBadCaptures;
|
| 212 |
+
endMoves = generate<QUIETS>(pos, cur);
|
| 213 |
+
|
| 214 |
+
score<QUIETS>();
|
| 215 |
+
partial_insertion_sort(cur, endMoves, -3000 * depth);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
++stage;
|
| 219 |
+
[[fallthrough]];
|
| 220 |
+
|
| 221 |
+
case QUIET:
|
| 222 |
+
if ( !skipQuiets
|
| 223 |
+
&& select<Next>([&](){return *cur != refutations[0].move
|
| 224 |
+
&& *cur != refutations[1].move
|
| 225 |
+
&& *cur != refutations[2].move;}))
|
| 226 |
+
return *(cur - 1);
|
| 227 |
+
|
| 228 |
+
// Prepare the pointers to loop over the bad captures
|
| 229 |
+
cur = moves;
|
| 230 |
+
endMoves = endBadCaptures;
|
| 231 |
+
|
| 232 |
+
++stage;
|
| 233 |
+
[[fallthrough]];
|
| 234 |
+
|
| 235 |
+
case BAD_CAPTURE:
|
| 236 |
+
return select<Next>([](){ return true; });
|
| 237 |
+
|
| 238 |
+
case EVASION_INIT:
|
| 239 |
+
cur = moves;
|
| 240 |
+
endMoves = generate<EVASIONS>(pos, cur);
|
| 241 |
+
|
| 242 |
+
score<EVASIONS>();
|
| 243 |
+
++stage;
|
| 244 |
+
[[fallthrough]];
|
| 245 |
+
|
| 246 |
+
case EVASION:
|
| 247 |
+
return select<Best>([](){ return true; });
|
| 248 |
+
|
| 249 |
+
case PROBCUT:
|
| 250 |
+
return select<Best>([&](){ return pos.see_ge(*cur, threshold); });
|
| 251 |
+
|
| 252 |
+
case QCAPTURE:
|
| 253 |
+
if (select<Best>([&](){ return depth > DEPTH_QS_RECAPTURES
|
| 254 |
+
|| to_sq(*cur) == recaptureSquare; }))
|
| 255 |
+
return *(cur - 1);
|
| 256 |
+
|
| 257 |
+
// If we did not find any move and we do not try checks, we have finished
|
| 258 |
+
if (depth != DEPTH_QS_CHECKS)
|
| 259 |
+
return MOVE_NONE;
|
| 260 |
+
|
| 261 |
+
++stage;
|
| 262 |
+
[[fallthrough]];
|
| 263 |
+
|
| 264 |
+
case QCHECK_INIT:
|
| 265 |
+
cur = moves;
|
| 266 |
+
endMoves = generate<QUIET_CHECKS>(pos, cur);
|
| 267 |
+
|
| 268 |
+
++stage;
|
| 269 |
+
[[fallthrough]];
|
| 270 |
+
|
| 271 |
+
case QCHECK:
|
| 272 |
+
return select<Next>([](){ return true; });
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
assert(false);
|
| 276 |
+
return MOVE_NONE; // Silence warning
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
} // namespace Stockfish
|
Fairy-Stockfish-master/src/movepick.h
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
#ifndef MOVEPICK_H_INCLUDED
|
| 20 |
+
#define MOVEPICK_H_INCLUDED
|
| 21 |
+
|
| 22 |
+
#include <array>
|
| 23 |
+
#include <limits>
|
| 24 |
+
#include <type_traits>
|
| 25 |
+
|
| 26 |
+
#include "movegen.h"
|
| 27 |
+
#include "position.h"
|
| 28 |
+
#include "types.h"
|
| 29 |
+
|
| 30 |
+
namespace Stockfish {
|
| 31 |
+
|
| 32 |
+
/// StatsEntry stores the stat table value. It is usually a number but could
|
| 33 |
+
/// be a move or even a nested history. We use a class instead of naked value
|
| 34 |
+
/// to directly call history update operator<<() on the entry so to use stats
|
| 35 |
+
/// tables at caller sites as simple multi-dim arrays.
|
| 36 |
+
template<typename T, int D>
|
| 37 |
+
class StatsEntry {
|
| 38 |
+
|
| 39 |
+
T entry;
|
| 40 |
+
|
| 41 |
+
public:
|
| 42 |
+
void operator=(const T& v) { entry = v; }
|
| 43 |
+
T* operator&() { return &entry; }
|
| 44 |
+
T* operator->() { return &entry; }
|
| 45 |
+
operator const T&() const { return entry; }
|
| 46 |
+
|
| 47 |
+
void operator<<(int bonus) {
|
| 48 |
+
assert(abs(bonus) <= D); // Ensure range is [-D, D]
|
| 49 |
+
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
|
| 50 |
+
|
| 51 |
+
entry += bonus - entry * abs(bonus) / D;
|
| 52 |
+
|
| 53 |
+
assert(abs(entry) <= D);
|
| 54 |
+
}
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
/// Stats is a generic N-dimensional array used to store various statistics.
|
| 58 |
+
/// The first template parameter T is the base type of the array, the second
|
| 59 |
+
/// template parameter D limits the range of updates in [-D, D] when we update
|
| 60 |
+
/// values with the << operator, while the last parameters (Size and Sizes)
|
| 61 |
+
/// encode the dimensions of the array.
|
| 62 |
+
template <typename T, int D, int Size, int... Sizes>
|
| 63 |
+
struct Stats : public std::array<Stats<T, D, Sizes...>, Size>
|
| 64 |
+
{
|
| 65 |
+
typedef Stats<T, D, Size, Sizes...> stats;
|
| 66 |
+
|
| 67 |
+
void fill(const T& v) {
|
| 68 |
+
|
| 69 |
+
// For standard-layout 'this' points to first struct member
|
| 70 |
+
assert(std::is_standard_layout<stats>::value);
|
| 71 |
+
|
| 72 |
+
typedef StatsEntry<T, D> entry;
|
| 73 |
+
entry* p = reinterpret_cast<entry*>(this);
|
| 74 |
+
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
|
| 75 |
+
}
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
template <typename T, int D, int Size>
|
| 79 |
+
struct Stats<T, D, Size> : public std::array<StatsEntry<T, D>, Size> {};
|
| 80 |
+
|
| 81 |
+
/// In stats table, D=0 means that the template parameter is not used
|
| 82 |
+
enum StatsParams { NOT_USED = 0, PIECE_SLOTS = 8 };
|
| 83 |
+
enum StatsType { NoCaptures, Captures };
|
| 84 |
+
|
| 85 |
+
/// ButterflyHistory records how often quiet moves have been successful or
|
| 86 |
+
/// unsuccessful during the current search, and is used for reduction and move
|
| 87 |
+
/// ordering decisions. It uses 2 tables (one for each color) indexed by
|
| 88 |
+
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
|
| 89 |
+
typedef Stats<int16_t, 13365, COLOR_NB, int(SQUARE_NB + 1) * int(1 << SQUARE_BITS)> ButterflyHistory;
|
| 90 |
+
|
| 91 |
+
typedef Stats<int16_t, 13365, COLOR_NB, SQUARE_NB> GateHistory;
|
| 92 |
+
|
| 93 |
+
/// At higher depths LowPlyHistory records successful quiet moves near the root
|
| 94 |
+
/// and quiet moves which are/were in the PV (ttPv). It is cleared with each new
|
| 95 |
+
/// search and filled during iterative deepening.
|
| 96 |
+
constexpr int MAX_LPH = 4;
|
| 97 |
+
typedef Stats<int16_t, 10692, MAX_LPH, int(SQUARE_NB + 1) * int(1 << SQUARE_BITS)> LowPlyHistory;
|
| 98 |
+
|
| 99 |
+
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
| 100 |
+
/// move, see www.chessprogramming.org/Countermove_Heuristic
|
| 101 |
+
typedef Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB> CounterMoveHistory;
|
| 102 |
+
|
| 103 |
+
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
| 104 |
+
typedef Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB> CapturePieceToHistory;
|
| 105 |
+
|
| 106 |
+
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
| 107 |
+
typedef Stats<int16_t, 29952, 2 * PIECE_SLOTS, SQUARE_NB> PieceToHistory;
|
| 108 |
+
|
| 109 |
+
/// ContinuationHistory is the combined history of a given pair of moves, usually
|
| 110 |
+
/// the current one given a previous one. The nested history table is based on
|
| 111 |
+
/// PieceToHistory instead of ButterflyBoards.
|
| 112 |
+
typedef Stats<PieceToHistory, NOT_USED, 2 * PIECE_SLOTS, SQUARE_NB> ContinuationHistory;
|
| 113 |
+
|
| 114 |
+
int history_slot(Piece pc);
|
| 115 |
+
|
| 116 |
+
/// MovePicker class is used to pick one pseudo-legal move at a time from the
|
| 117 |
+
/// current position. The most important method is next_move(), which returns a
|
| 118 |
+
/// new pseudo-legal move each time it is called, until there are no moves left,
|
| 119 |
+
/// when MOVE_NONE is returned. In order to improve the efficiency of the
|
| 120 |
+
/// alpha-beta algorithm, MovePicker attempts to return the moves which are most
|
| 121 |
+
/// likely to get a cut-off first.
|
| 122 |
+
class MovePicker {
|
| 123 |
+
|
| 124 |
+
enum PickType { Next, Best };
|
| 125 |
+
|
| 126 |
+
public:
|
| 127 |
+
MovePicker(const MovePicker&) = delete;
|
| 128 |
+
MovePicker& operator=(const MovePicker&) = delete;
|
| 129 |
+
MovePicker(const Position&, Move, Value, const GateHistory*, const CapturePieceToHistory*);
|
| 130 |
+
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
|
| 131 |
+
const GateHistory*,
|
| 132 |
+
const CapturePieceToHistory*,
|
| 133 |
+
const PieceToHistory**,
|
| 134 |
+
Square);
|
| 135 |
+
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
|
| 136 |
+
const GateHistory*,
|
| 137 |
+
const LowPlyHistory*,
|
| 138 |
+
const CapturePieceToHistory*,
|
| 139 |
+
const PieceToHistory**,
|
| 140 |
+
Move,
|
| 141 |
+
const Move*,
|
| 142 |
+
int);
|
| 143 |
+
Move next_move(bool skipQuiets = false);
|
| 144 |
+
|
| 145 |
+
private:
|
| 146 |
+
template<PickType T, typename Pred> Move select(Pred);
|
| 147 |
+
template<GenType> void score();
|
| 148 |
+
ExtMove* begin() { return cur; }
|
| 149 |
+
ExtMove* end() { return endMoves; }
|
| 150 |
+
|
| 151 |
+
const Position& pos;
|
| 152 |
+
const ButterflyHistory* mainHistory;
|
| 153 |
+
const GateHistory* gateHistory;
|
| 154 |
+
const LowPlyHistory* lowPlyHistory;
|
| 155 |
+
const CapturePieceToHistory* captureHistory;
|
| 156 |
+
const PieceToHistory** continuationHistory;
|
| 157 |
+
Move ttMove;
|
| 158 |
+
ExtMove refutations[3], *cur, *endMoves, *endBadCaptures;
|
| 159 |
+
int stage;
|
| 160 |
+
Square recaptureSquare;
|
| 161 |
+
Value threshold;
|
| 162 |
+
Depth depth;
|
| 163 |
+
int ply;
|
| 164 |
+
ExtMove moves[MAX_MOVES];
|
| 165 |
+
};
|
| 166 |
+
|
| 167 |
+
} // namespace Stockfish
|
| 168 |
+
|
| 169 |
+
#endif // #ifndef MOVEPICK_H_INCLUDED
|
Fairy-Stockfish-master/src/nnue/evaluate_nnue.cpp
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
// Code for calculating NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#include <iostream>
|
| 22 |
+
#include <set>
|
| 23 |
+
#include <sstream>
|
| 24 |
+
#include <iomanip>
|
| 25 |
+
#include <fstream>
|
| 26 |
+
|
| 27 |
+
#include "../evaluate.h"
|
| 28 |
+
#include "../position.h"
|
| 29 |
+
#include "../misc.h"
|
| 30 |
+
#include "../uci.h"
|
| 31 |
+
#include "../types.h"
|
| 32 |
+
|
| 33 |
+
#include "evaluate_nnue.h"
|
| 34 |
+
|
| 35 |
+
namespace Stockfish::Eval::NNUE {
|
| 36 |
+
|
| 37 |
+
// Input feature converter
|
| 38 |
+
LargePagePtr<FeatureTransformer> featureTransformer;
|
| 39 |
+
|
| 40 |
+
// Evaluation function
|
| 41 |
+
AlignedPtr<Network> network[LayerStacks];
|
| 42 |
+
|
| 43 |
+
// Evaluation function file name
|
| 44 |
+
std::string fileName;
|
| 45 |
+
std::string netDescription;
|
| 46 |
+
|
| 47 |
+
namespace Detail {
|
| 48 |
+
|
| 49 |
+
// Initialize the evaluation function parameters
|
| 50 |
+
template <typename T>
|
| 51 |
+
void initialize(AlignedPtr<T>& pointer) {
|
| 52 |
+
|
| 53 |
+
pointer.reset(reinterpret_cast<T*>(std_aligned_alloc(alignof(T), sizeof(T))));
|
| 54 |
+
std::memset(pointer.get(), 0, sizeof(T));
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
template <typename T>
|
| 58 |
+
void initialize(LargePagePtr<T>& pointer) {
|
| 59 |
+
|
| 60 |
+
static_assert(alignof(T) <= 4096, "aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
|
| 61 |
+
pointer.reset(reinterpret_cast<T*>(aligned_large_pages_alloc(sizeof(T))));
|
| 62 |
+
std::memset(pointer.get(), 0, sizeof(T));
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
// Read evaluation function parameters
|
| 66 |
+
template <typename T>
|
| 67 |
+
bool read_parameters(std::istream& stream, T& reference) {
|
| 68 |
+
|
| 69 |
+
std::uint32_t header;
|
| 70 |
+
header = read_little_endian<std::uint32_t>(stream);
|
| 71 |
+
if (!stream || header != T::get_hash_value()) return false;
|
| 72 |
+
return reference.read_parameters(stream);
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// Write evaluation function parameters
|
| 76 |
+
template <typename T>
|
| 77 |
+
bool write_parameters(std::ostream& stream, const T& reference) {
|
| 78 |
+
|
| 79 |
+
write_little_endian<std::uint32_t>(stream, T::get_hash_value());
|
| 80 |
+
return reference.write_parameters(stream);
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
} // namespace Detail
|
| 84 |
+
|
| 85 |
+
// Initialize the evaluation function parameters
|
| 86 |
+
void initialize() {
|
| 87 |
+
|
| 88 |
+
Detail::initialize(featureTransformer);
|
| 89 |
+
for (std::size_t i = 0; i < LayerStacks; ++i)
|
| 90 |
+
Detail::initialize(network[i]);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
// Read network header
|
| 94 |
+
bool read_header(std::istream& stream, std::uint32_t* hashValue, std::string* desc)
|
| 95 |
+
{
|
| 96 |
+
std::uint32_t version, size;
|
| 97 |
+
|
| 98 |
+
version = read_little_endian<std::uint32_t>(stream);
|
| 99 |
+
*hashValue = read_little_endian<std::uint32_t>(stream);
|
| 100 |
+
size = read_little_endian<std::uint32_t>(stream);
|
| 101 |
+
if (!stream || version != Version) return false;
|
| 102 |
+
desc->resize(size);
|
| 103 |
+
stream.read(&(*desc)[0], size);
|
| 104 |
+
return !stream.fail();
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// Write network header
|
| 108 |
+
bool write_header(std::ostream& stream, std::uint32_t hashValue, const std::string& desc)
|
| 109 |
+
{
|
| 110 |
+
write_little_endian<std::uint32_t>(stream, Version);
|
| 111 |
+
write_little_endian<std::uint32_t>(stream, hashValue);
|
| 112 |
+
write_little_endian<std::uint32_t>(stream, desc.size());
|
| 113 |
+
stream.write(&desc[0], desc.size());
|
| 114 |
+
return !stream.fail();
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
// Read network parameters
|
| 118 |
+
bool read_parameters(std::istream& stream) {
|
| 119 |
+
|
| 120 |
+
std::uint32_t hashValue;
|
| 121 |
+
if (!read_header(stream, &hashValue, &netDescription)) return false;
|
| 122 |
+
if (hashValue != HashValue) return false;
|
| 123 |
+
if (!Detail::read_parameters(stream, *featureTransformer)) return false;
|
| 124 |
+
for (std::size_t i = 0; i < LayerStacks; ++i)
|
| 125 |
+
if (!Detail::read_parameters(stream, *(network[i]))) return false;
|
| 126 |
+
return stream && stream.peek() == std::ios::traits_type::eof();
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
// Write network parameters
|
| 130 |
+
bool write_parameters(std::ostream& stream) {
|
| 131 |
+
|
| 132 |
+
if (!write_header(stream, HashValue, netDescription)) return false;
|
| 133 |
+
if (!Detail::write_parameters(stream, *featureTransformer)) return false;
|
| 134 |
+
for (std::size_t i = 0; i < LayerStacks; ++i)
|
| 135 |
+
if (!Detail::write_parameters(stream, *(network[i]))) return false;
|
| 136 |
+
return (bool)stream;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
// Evaluation function. Perform differential calculation.
|
| 140 |
+
Value evaluate(const Position& pos, bool adjusted) {
|
| 141 |
+
|
| 142 |
+
// We manually align the arrays on the stack because with gcc < 9.3
|
| 143 |
+
// overaligning stack variables with alignas() doesn't work correctly.
|
| 144 |
+
|
| 145 |
+
constexpr uint64_t alignment = CacheLineSize;
|
| 146 |
+
|
| 147 |
+
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
|
| 148 |
+
TransformedFeatureType transformedFeaturesUnaligned[
|
| 149 |
+
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
|
| 150 |
+
char bufferUnaligned[Network::BufferSize + alignment];
|
| 151 |
+
|
| 152 |
+
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
|
| 153 |
+
auto* buffer = align_ptr_up<alignment>(&bufferUnaligned[0]);
|
| 154 |
+
#else
|
| 155 |
+
alignas(alignment)
|
| 156 |
+
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
| 157 |
+
alignas(alignment) char buffer[Network::BufferSize];
|
| 158 |
+
#endif
|
| 159 |
+
|
| 160 |
+
ASSERT_ALIGNED(transformedFeatures, alignment);
|
| 161 |
+
ASSERT_ALIGNED(buffer, alignment);
|
| 162 |
+
|
| 163 |
+
const std::size_t bucket = std::min((pos.count<ALL_PIECES>() - 1) * 8 / currentNnueVariant->nnueMaxPieces, 7);
|
| 164 |
+
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
|
| 165 |
+
const auto output = network[bucket]->propagate(transformedFeatures, buffer);
|
| 166 |
+
|
| 167 |
+
int materialist = psqt;
|
| 168 |
+
int positional = output[0];
|
| 169 |
+
|
| 170 |
+
int delta_npm = abs(pos.non_pawn_material(WHITE) - pos.non_pawn_material(BLACK));
|
| 171 |
+
int entertainment = (adjusted && delta_npm <= BishopValueMg - KnightValueMg ? 7 : 0);
|
| 172 |
+
|
| 173 |
+
int A = 128 - entertainment;
|
| 174 |
+
int B = 128 + entertainment;
|
| 175 |
+
|
| 176 |
+
int sum = (A * materialist + B * positional) / 128;
|
| 177 |
+
|
| 178 |
+
return static_cast<Value>( sum / OutputScale );
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
struct NnueEvalTrace {
|
| 182 |
+
static_assert(LayerStacks == PSQTBuckets);
|
| 183 |
+
|
| 184 |
+
Value psqt[LayerStacks];
|
| 185 |
+
Value positional[LayerStacks];
|
| 186 |
+
std::size_t correctBucket;
|
| 187 |
+
};
|
| 188 |
+
|
| 189 |
+
static NnueEvalTrace trace_evaluate(const Position& pos) {
|
| 190 |
+
|
| 191 |
+
// We manually align the arrays on the stack because with gcc < 9.3
|
| 192 |
+
// overaligning stack variables with alignas() doesn't work correctly.
|
| 193 |
+
|
| 194 |
+
constexpr uint64_t alignment = CacheLineSize;
|
| 195 |
+
|
| 196 |
+
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
|
| 197 |
+
TransformedFeatureType transformedFeaturesUnaligned[
|
| 198 |
+
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
|
| 199 |
+
char bufferUnaligned[Network::BufferSize + alignment];
|
| 200 |
+
|
| 201 |
+
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
|
| 202 |
+
auto* buffer = align_ptr_up<alignment>(&bufferUnaligned[0]);
|
| 203 |
+
#else
|
| 204 |
+
alignas(alignment)
|
| 205 |
+
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
| 206 |
+
alignas(alignment) char buffer[Network::BufferSize];
|
| 207 |
+
#endif
|
| 208 |
+
|
| 209 |
+
ASSERT_ALIGNED(transformedFeatures, alignment);
|
| 210 |
+
ASSERT_ALIGNED(buffer, alignment);
|
| 211 |
+
|
| 212 |
+
NnueEvalTrace t{};
|
| 213 |
+
t.correctBucket = std::min((pos.count<ALL_PIECES>() - 1) * 8 / currentNnueVariant->nnueMaxPieces, 7);
|
| 214 |
+
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket) {
|
| 215 |
+
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
|
| 216 |
+
const auto output = network[bucket]->propagate(transformedFeatures, buffer);
|
| 217 |
+
|
| 218 |
+
int materialist = psqt;
|
| 219 |
+
int positional = output[0];
|
| 220 |
+
|
| 221 |
+
t.psqt[bucket] = static_cast<Value>( materialist / OutputScale );
|
| 222 |
+
t.positional[bucket] = static_cast<Value>( positional / OutputScale );
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
return t;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
// Requires the buffer to have capacity for at least 5 values
|
| 229 |
+
static void format_cp_compact(Value v, char* buffer) {
|
| 230 |
+
|
| 231 |
+
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
|
| 232 |
+
|
| 233 |
+
int cp = std::abs(100 * v / PawnValueEg);
|
| 234 |
+
|
| 235 |
+
if (cp >= 10000)
|
| 236 |
+
{
|
| 237 |
+
buffer[1] = '0' + cp / 10000; cp %= 10000;
|
| 238 |
+
buffer[2] = '0' + cp / 1000; cp %= 1000;
|
| 239 |
+
buffer[3] = '0' + cp / 100; cp %= 100;
|
| 240 |
+
buffer[4] = ' ';
|
| 241 |
+
}
|
| 242 |
+
else if (cp >= 1000)
|
| 243 |
+
{
|
| 244 |
+
buffer[1] = '0' + cp / 1000; cp %= 1000;
|
| 245 |
+
buffer[2] = '0' + cp / 100; cp %= 100;
|
| 246 |
+
buffer[3] = '.';
|
| 247 |
+
buffer[4] = '0' + cp / 10;
|
| 248 |
+
}
|
| 249 |
+
else
|
| 250 |
+
{
|
| 251 |
+
buffer[1] = '0' + cp / 100; cp %= 100;
|
| 252 |
+
buffer[2] = '.';
|
| 253 |
+
buffer[3] = '0' + cp / 10; cp %= 10;
|
| 254 |
+
buffer[4] = '0' + cp / 1;
|
| 255 |
+
}
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
// Requires the buffer to have capacity for at least 7 values
|
| 259 |
+
static void format_cp_aligned_dot(Value v, char* buffer) {
|
| 260 |
+
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
|
| 261 |
+
|
| 262 |
+
int cp = std::abs(100 * v / PawnValueEg);
|
| 263 |
+
|
| 264 |
+
if (cp >= 10000)
|
| 265 |
+
{
|
| 266 |
+
buffer[1] = '0' + cp / 10000; cp %= 10000;
|
| 267 |
+
buffer[2] = '0' + cp / 1000; cp %= 1000;
|
| 268 |
+
buffer[3] = '0' + cp / 100; cp %= 100;
|
| 269 |
+
buffer[4] = '.';
|
| 270 |
+
buffer[5] = '0' + cp / 10; cp %= 10;
|
| 271 |
+
buffer[6] = '0' + cp;
|
| 272 |
+
}
|
| 273 |
+
else if (cp >= 1000)
|
| 274 |
+
{
|
| 275 |
+
buffer[1] = ' ';
|
| 276 |
+
buffer[2] = '0' + cp / 1000; cp %= 1000;
|
| 277 |
+
buffer[3] = '0' + cp / 100; cp %= 100;
|
| 278 |
+
buffer[4] = '.';
|
| 279 |
+
buffer[5] = '0' + cp / 10; cp %= 10;
|
| 280 |
+
buffer[6] = '0' + cp;
|
| 281 |
+
}
|
| 282 |
+
else
|
| 283 |
+
{
|
| 284 |
+
buffer[1] = ' ';
|
| 285 |
+
buffer[2] = ' ';
|
| 286 |
+
buffer[3] = '0' + cp / 100; cp %= 100;
|
| 287 |
+
buffer[4] = '.';
|
| 288 |
+
buffer[5] = '0' + cp / 10; cp %= 10;
|
| 289 |
+
buffer[6] = '0' + cp / 1;
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
// trace() returns a string with the value of each piece on a board,
|
| 295 |
+
// and a table for (PSQT, Layers) values bucket by bucket.
|
| 296 |
+
|
| 297 |
+
std::string trace(Position& pos) {
|
| 298 |
+
|
| 299 |
+
std::stringstream ss;
|
| 300 |
+
|
| 301 |
+
char board[3*RANK_NB+1][8*FILE_NB+2];
|
| 302 |
+
std::memset(board, ' ', sizeof(board));
|
| 303 |
+
for (int row = 0; row < 3*pos.ranks()+1; ++row)
|
| 304 |
+
board[row][8*FILE_NB+1] = '\0';
|
| 305 |
+
|
| 306 |
+
// A lambda to output one box of the board
|
| 307 |
+
auto writeSquare = [&board, &pos](File file, Rank rank, Piece pc, Value value) {
|
| 308 |
+
|
| 309 |
+
const int x = ((int)file) * 8;
|
| 310 |
+
const int y = (pos.max_rank() - (int)rank) * 3;
|
| 311 |
+
for (int i = 1; i < 8; ++i)
|
| 312 |
+
board[y][x+i] = board[y+3][x+i] = '-';
|
| 313 |
+
for (int i = 1; i < 3; ++i)
|
| 314 |
+
board[y+i][x] = board[y+i][x+8] = '|';
|
| 315 |
+
board[y][x] = board[y][x+8] = board[y+3][x+8] = board[y+3][x] = '+';
|
| 316 |
+
if (pc != NO_PIECE)
|
| 317 |
+
board[y+1][x+4] = pos.piece_to_char()[pc];
|
| 318 |
+
if (value != VALUE_NONE)
|
| 319 |
+
format_cp_compact(value, &board[y+2][x+2]);
|
| 320 |
+
};
|
| 321 |
+
|
| 322 |
+
// We estimate the value of each piece by doing a differential evaluation from
|
| 323 |
+
// the current base eval, simulating the removal of the piece from its square.
|
| 324 |
+
Value base = evaluate(pos);
|
| 325 |
+
base = pos.side_to_move() == WHITE ? base : -base;
|
| 326 |
+
|
| 327 |
+
for (File f = FILE_A; f <= pos.max_file(); ++f)
|
| 328 |
+
for (Rank r = RANK_1; r <= pos.max_rank(); ++r)
|
| 329 |
+
{
|
| 330 |
+
Square sq = make_square(f, r);
|
| 331 |
+
Piece pc = pos.piece_on(sq);
|
| 332 |
+
Piece unpromotedPc = pos.unpromoted_piece_on(sq);
|
| 333 |
+
bool isPromoted = pos.is_promoted(sq);
|
| 334 |
+
Value v = VALUE_NONE;
|
| 335 |
+
|
| 336 |
+
if (pc != NO_PIECE && type_of(pc) != pos.nnue_king())
|
| 337 |
+
{
|
| 338 |
+
auto st = pos.state();
|
| 339 |
+
|
| 340 |
+
pos.remove_piece(sq);
|
| 341 |
+
st->accumulator.computed[WHITE] = false;
|
| 342 |
+
st->accumulator.computed[BLACK] = false;
|
| 343 |
+
|
| 344 |
+
Value eval = evaluate(pos);
|
| 345 |
+
eval = pos.side_to_move() == WHITE ? eval : -eval;
|
| 346 |
+
v = base - eval;
|
| 347 |
+
|
| 348 |
+
pos.put_piece(pc, sq, isPromoted, unpromotedPc);
|
| 349 |
+
st->accumulator.computed[WHITE] = false;
|
| 350 |
+
st->accumulator.computed[BLACK] = false;
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
writeSquare(f, r, pc, v);
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
ss << " NNUE derived piece values:\n";
|
| 357 |
+
for (int row = 0; row < 3*pos.ranks()+1; ++row)
|
| 358 |
+
ss << board[row] << '\n';
|
| 359 |
+
ss << '\n';
|
| 360 |
+
|
| 361 |
+
auto t = trace_evaluate(pos);
|
| 362 |
+
|
| 363 |
+
ss << " NNUE network contributions "
|
| 364 |
+
<< (pos.side_to_move() == WHITE ? "(White to move)" : "(Black to move)") << std::endl
|
| 365 |
+
<< "+------------+------------+------------+------------+\n"
|
| 366 |
+
<< "| Bucket | Material | Positional | Total |\n"
|
| 367 |
+
<< "| | (PSQT) | (Layers) | |\n"
|
| 368 |
+
<< "+------------+------------+------------+------------+\n";
|
| 369 |
+
|
| 370 |
+
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket)
|
| 371 |
+
{
|
| 372 |
+
char buffer[3][8];
|
| 373 |
+
std::memset(buffer, '\0', sizeof(buffer));
|
| 374 |
+
|
| 375 |
+
format_cp_aligned_dot(t.psqt[bucket], buffer[0]);
|
| 376 |
+
format_cp_aligned_dot(t.positional[bucket], buffer[1]);
|
| 377 |
+
format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], buffer[2]);
|
| 378 |
+
|
| 379 |
+
ss << "| " << bucket << " "
|
| 380 |
+
<< " | " << buffer[0] << " "
|
| 381 |
+
<< " | " << buffer[1] << " "
|
| 382 |
+
<< " | " << buffer[2] << " "
|
| 383 |
+
<< " |";
|
| 384 |
+
if (bucket == t.correctBucket)
|
| 385 |
+
ss << " <-- this bucket is used";
|
| 386 |
+
ss << '\n';
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
ss << "+------------+------------+------------+------------+\n";
|
| 390 |
+
|
| 391 |
+
return ss.str();
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
// Load eval, from a file stream or a memory stream
|
| 396 |
+
bool load_eval(std::string name, std::istream& stream) {
|
| 397 |
+
|
| 398 |
+
initialize();
|
| 399 |
+
fileName = name;
|
| 400 |
+
return read_parameters(stream);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// Save eval, to a file stream or a memory stream
|
| 404 |
+
bool save_eval(std::ostream& stream) {
|
| 405 |
+
|
| 406 |
+
if (fileName.empty())
|
| 407 |
+
return false;
|
| 408 |
+
|
| 409 |
+
return write_parameters(stream);
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
/// Save eval, to a file given by its name
|
| 413 |
+
bool save_eval(const std::optional<std::string>& filename) {
|
| 414 |
+
|
| 415 |
+
std::string actualFilename;
|
| 416 |
+
std::string msg;
|
| 417 |
+
|
| 418 |
+
if (filename.has_value())
|
| 419 |
+
actualFilename = filename.value();
|
| 420 |
+
else
|
| 421 |
+
{
|
| 422 |
+
if (eval_file_loaded != EvalFileDefaultName)
|
| 423 |
+
{
|
| 424 |
+
msg = "Failed to export a net. A non-embedded net can only be saved if the filename is specified";
|
| 425 |
+
|
| 426 |
+
sync_cout << msg << sync_endl;
|
| 427 |
+
return false;
|
| 428 |
+
}
|
| 429 |
+
actualFilename = EvalFileDefaultName;
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
std::ofstream stream(actualFilename, std::ios_base::binary);
|
| 433 |
+
bool saved = save_eval(stream);
|
| 434 |
+
|
| 435 |
+
msg = saved ? "Network saved successfully to " + actualFilename
|
| 436 |
+
: "Failed to export a net";
|
| 437 |
+
|
| 438 |
+
sync_cout << msg << sync_endl;
|
| 439 |
+
return saved;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
} // namespace Stockfish::Eval::NNUE
|
Fairy-Stockfish-master/src/nnue/evaluate_nnue.h
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
// header used in NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
|
| 22 |
+
#define NNUE_EVALUATE_NNUE_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include "nnue_feature_transformer.h"
|
| 25 |
+
|
| 26 |
+
#include <memory>
|
| 27 |
+
|
| 28 |
+
namespace Stockfish::Eval::NNUE {
|
| 29 |
+
|
| 30 |
+
// Hash value of evaluation function structure
|
| 31 |
+
constexpr std::uint32_t HashValue =
|
| 32 |
+
FeatureTransformer::get_hash_value() ^ Network::get_hash_value();
|
| 33 |
+
|
| 34 |
+
// Deleter for automating release of memory area
|
| 35 |
+
template <typename T>
|
| 36 |
+
struct AlignedDeleter {
|
| 37 |
+
void operator()(T* ptr) const {
|
| 38 |
+
ptr->~T();
|
| 39 |
+
std_aligned_free(ptr);
|
| 40 |
+
}
|
| 41 |
+
};
|
| 42 |
+
|
| 43 |
+
template <typename T>
|
| 44 |
+
struct LargePageDeleter {
|
| 45 |
+
void operator()(T* ptr) const {
|
| 46 |
+
ptr->~T();
|
| 47 |
+
aligned_large_pages_free(ptr);
|
| 48 |
+
}
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
template <typename T>
|
| 52 |
+
using AlignedPtr = std::unique_ptr<T, AlignedDeleter<T>>;
|
| 53 |
+
|
| 54 |
+
template <typename T>
|
| 55 |
+
using LargePagePtr = std::unique_ptr<T, LargePageDeleter<T>>;
|
| 56 |
+
|
| 57 |
+
} // namespace Stockfish::Eval::NNUE
|
| 58 |
+
|
| 59 |
+
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
|
Fairy-Stockfish-master/src/nnue/features/half_ka_v2.cpp
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
//Definition of input features HalfKAv2 of NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#include "half_ka_v2.h"
|
| 22 |
+
|
| 23 |
+
#include "../../position.h"
|
| 24 |
+
|
| 25 |
+
namespace Stockfish::Eval::NNUE::Features {
|
| 26 |
+
|
| 27 |
+
// Map square to numbering on 8x8 board
|
| 28 |
+
constexpr Square to_chess_square(Square s) {
|
| 29 |
+
return Square(s - rank_of(s) * (FILE_MAX - FILE_H));
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
// Orient a square according to perspective (rotates by 180 for black)
|
| 33 |
+
inline Square HalfKAv2::orient(Color perspective, Square s) {
|
| 34 |
+
return Square(int(to_chess_square(s)) ^ (bool(perspective) * 56));
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// Index of a feature for a given king position and another piece on some square
|
| 38 |
+
inline IndexType HalfKAv2::make_index(Color perspective, Square s, Piece pc, Square ksq) {
|
| 39 |
+
return IndexType(orient(perspective, s) + PieceSquareIndex[perspective][pc] + PS_NB * ksq);
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// Get a list of indices for active features
|
| 43 |
+
void HalfKAv2::append_active_indices(
|
| 44 |
+
const Position& pos,
|
| 45 |
+
Color perspective,
|
| 46 |
+
ValueListInserter<IndexType> active
|
| 47 |
+
) {
|
| 48 |
+
Square ksq = orient(perspective, pos.square<KING>(perspective));
|
| 49 |
+
Bitboard bb = pos.pieces();
|
| 50 |
+
while (bb)
|
| 51 |
+
{
|
| 52 |
+
Square s = pop_lsb(bb);
|
| 53 |
+
active.push_back(make_index(perspective, s, pos.piece_on(s), ksq));
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
// append_changed_indices() : get a list of indices for recently changed features
|
| 59 |
+
|
| 60 |
+
void HalfKAv2::append_changed_indices(
|
| 61 |
+
Square ksq,
|
| 62 |
+
StateInfo* st,
|
| 63 |
+
Color perspective,
|
| 64 |
+
ValueListInserter<IndexType> removed,
|
| 65 |
+
ValueListInserter<IndexType> added
|
| 66 |
+
) {
|
| 67 |
+
const auto& dp = st->dirtyPiece;
|
| 68 |
+
Square oriented_ksq = orient(perspective, ksq);
|
| 69 |
+
for (int i = 0; i < dp.dirty_num; ++i) {
|
| 70 |
+
Piece pc = dp.piece[i];
|
| 71 |
+
if (dp.from[i] != SQ_NONE)
|
| 72 |
+
removed.push_back(make_index(perspective, dp.from[i], pc, oriented_ksq));
|
| 73 |
+
if (dp.to[i] != SQ_NONE)
|
| 74 |
+
added.push_back(make_index(perspective, dp.to[i], pc, oriented_ksq));
|
| 75 |
+
}
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
int HalfKAv2::update_cost(StateInfo* st) {
|
| 79 |
+
return st->dirtyPiece.dirty_num;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
int HalfKAv2::refresh_cost(const Position& pos) {
|
| 83 |
+
return pos.count<ALL_PIECES>();
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
bool HalfKAv2::requires_refresh(StateInfo* st, Color perspective) {
|
| 87 |
+
return st->dirtyPiece.piece[0] == make_piece(perspective, KING);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
} // namespace Stockfish::Eval::NNUE::Features
|
Fairy-Stockfish-master/src/nnue/features/half_ka_v2.h
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
//Definition of input features HalfKAv2 of NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#ifndef NNUE_FEATURES_HALF_KA_V2_H_INCLUDED
|
| 22 |
+
#define NNUE_FEATURES_HALF_KA_V2_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include "../nnue_common.h"
|
| 25 |
+
|
| 26 |
+
#include "../../evaluate.h"
|
| 27 |
+
#include "../../misc.h"
|
| 28 |
+
|
| 29 |
+
namespace Stockfish {
|
| 30 |
+
struct StateInfo;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
namespace Stockfish::Eval::NNUE::Features {
|
| 34 |
+
|
| 35 |
+
// Feature HalfKAv2: Combination of the position of own king
|
| 36 |
+
// and the position of pieces
|
| 37 |
+
class HalfKAv2 {
|
| 38 |
+
|
| 39 |
+
// unique number for each piece type on each square
|
| 40 |
+
enum {
|
| 41 |
+
PS_NONE = 0,
|
| 42 |
+
PS_W_PAWN = 0,
|
| 43 |
+
PS_B_PAWN = 1 * SQUARE_NB_CHESS,
|
| 44 |
+
PS_W_KNIGHT = 2 * SQUARE_NB_CHESS,
|
| 45 |
+
PS_B_KNIGHT = 3 * SQUARE_NB_CHESS,
|
| 46 |
+
PS_W_BISHOP = 4 * SQUARE_NB_CHESS,
|
| 47 |
+
PS_B_BISHOP = 5 * SQUARE_NB_CHESS,
|
| 48 |
+
PS_W_ROOK = 6 * SQUARE_NB_CHESS,
|
| 49 |
+
PS_B_ROOK = 7 * SQUARE_NB_CHESS,
|
| 50 |
+
PS_W_QUEEN = 8 * SQUARE_NB_CHESS,
|
| 51 |
+
PS_B_QUEEN = 9 * SQUARE_NB_CHESS,
|
| 52 |
+
PS_KING = 10 * SQUARE_NB_CHESS,
|
| 53 |
+
PS_NB = 11 * SQUARE_NB_CHESS
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
static constexpr uint32_t PieceSquareIndex[COLOR_NB][PIECE_NB] = {
|
| 57 |
+
// convention: W - us, B - them
|
| 58 |
+
// viewed from other side, W and B are reversed
|
| 59 |
+
{
|
| 60 |
+
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_NONE, PS_NONE,
|
| 61 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 62 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 63 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 64 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 65 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 66 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 67 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_KING,
|
| 68 |
+
|
| 69 |
+
PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_NONE, PS_NONE,
|
| 70 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 71 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 72 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 73 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 74 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 75 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 76 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_KING,
|
| 77 |
+
},
|
| 78 |
+
|
| 79 |
+
{
|
| 80 |
+
PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_NONE, PS_NONE,
|
| 81 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 82 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 83 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 84 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 85 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 86 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 87 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_KING,
|
| 88 |
+
|
| 89 |
+
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_NONE, PS_NONE,
|
| 90 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 91 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 92 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 93 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 94 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 95 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
|
| 96 |
+
PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_KING,
|
| 97 |
+
}
|
| 98 |
+
};
|
| 99 |
+
// Check that the fragile array definition is correct
|
| 100 |
+
static_assert(PieceSquareIndex[WHITE][make_piece(WHITE, PAWN)] == PS_W_PAWN);
|
| 101 |
+
static_assert(PieceSquareIndex[WHITE][make_piece(WHITE, KING)] == PS_KING);
|
| 102 |
+
static_assert(PieceSquareIndex[WHITE][make_piece(BLACK, PAWN)] == PS_B_PAWN);
|
| 103 |
+
static_assert(PieceSquareIndex[WHITE][make_piece(BLACK, KING)] == PS_KING);
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
// Orient a square according to perspective (rotates by 180 for black)
|
| 107 |
+
static Square orient(Color perspective, Square s);
|
| 108 |
+
|
| 109 |
+
// Index of a feature for a given king position and another piece on some square
|
| 110 |
+
static IndexType make_index(Color perspective, Square s, Piece pc, Square ksq);
|
| 111 |
+
|
| 112 |
+
public:
|
| 113 |
+
// Feature name
|
| 114 |
+
static constexpr const char* Name = "HalfKAv2(Friend)";
|
| 115 |
+
|
| 116 |
+
// Hash value embedded in the evaluation file
|
| 117 |
+
static constexpr std::uint32_t HashValue = 0x5f234cb8u;
|
| 118 |
+
|
| 119 |
+
// Number of feature dimensions
|
| 120 |
+
static constexpr IndexType Dimensions =
|
| 121 |
+
static_cast<IndexType>(SQUARE_NB_CHESS) * static_cast<IndexType>(PS_NB);
|
| 122 |
+
|
| 123 |
+
// Maximum number of simultaneously active features.
|
| 124 |
+
static constexpr IndexType MaxActiveDimensions = 32;
|
| 125 |
+
|
| 126 |
+
// Get a list of indices for active features
|
| 127 |
+
static void append_active_indices(
|
| 128 |
+
const Position& pos,
|
| 129 |
+
Color perspective,
|
| 130 |
+
ValueListInserter<IndexType> active);
|
| 131 |
+
|
| 132 |
+
// Get a list of indices for recently changed features
|
| 133 |
+
static void append_changed_indices(
|
| 134 |
+
Square ksq,
|
| 135 |
+
StateInfo* st,
|
| 136 |
+
Color perspective,
|
| 137 |
+
ValueListInserter<IndexType> removed,
|
| 138 |
+
ValueListInserter<IndexType> added);
|
| 139 |
+
|
| 140 |
+
// Returns the cost of updating one perspective, the most costly one.
|
| 141 |
+
// Assumes no refresh needed.
|
| 142 |
+
static int update_cost(StateInfo* st);
|
| 143 |
+
static int refresh_cost(const Position& pos);
|
| 144 |
+
|
| 145 |
+
// Returns whether the change stored in this StateInfo means that
|
| 146 |
+
// a full accumulator refresh is required.
|
| 147 |
+
static bool requires_refresh(StateInfo* st, Color perspective);
|
| 148 |
+
};
|
| 149 |
+
|
| 150 |
+
} // namespace Stockfish::Eval::NNUE::Features
|
| 151 |
+
|
| 152 |
+
#endif // #ifndef NNUE_FEATURES_HALF_KA_V2_H_INCLUDED
|
Fairy-Stockfish-master/src/nnue/features/half_ka_v2_variants.cpp
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
//Definition of input features HalfKAv2 of NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#include "half_ka_v2_variants.h"
|
| 22 |
+
|
| 23 |
+
#include "../../position.h"
|
| 24 |
+
|
| 25 |
+
namespace Stockfish::Eval::NNUE::Features {
|
| 26 |
+
|
| 27 |
+
// Map square to numbering on variant board
|
| 28 |
+
inline Square to_variant_square(Square s, const Position& pos) {
|
| 29 |
+
return Square(s - rank_of(s) * (FILE_MAX - pos.max_file()));
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
// Orient a square according to perspective (rotates by 180 for black)
|
| 33 |
+
// Missing kings map to index 0 (SQ_A1)
|
| 34 |
+
inline Square HalfKAv2Variants::orient(Color perspective, Square s, const Position& pos) {
|
| 35 |
+
return s != SQ_NONE ? to_variant_square( perspective == WHITE || (pos.flag_region(BLACK) & Rank8BB) ? s
|
| 36 |
+
: flip_rank(s, pos.max_rank()), pos) : SQ_A1;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
// Index of a feature for a given king position and another piece on some square
|
| 40 |
+
inline IndexType HalfKAv2Variants::make_index(Color perspective, Square s, Piece pc, Square ksq, const Position& pos) {
|
| 41 |
+
return IndexType(orient(perspective, s, pos) + pos.nnue_piece_square_index(perspective, pc) + pos.nnue_king_square_index(ksq));
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
// Index of a feature for a given king position and another piece on some square
|
| 45 |
+
inline IndexType HalfKAv2Variants::make_index(Color perspective, int handCount, Piece pc, Square ksq, const Position& pos) {
|
| 46 |
+
return IndexType(handCount + pos.nnue_piece_hand_index(perspective, pc) + pos.nnue_king_square_index(ksq));
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// Get a list of indices for active features
|
| 50 |
+
void HalfKAv2Variants::append_active_indices(
|
| 51 |
+
const Position& pos,
|
| 52 |
+
Color perspective,
|
| 53 |
+
ValueListInserter<IndexType> active
|
| 54 |
+
) {
|
| 55 |
+
Square oriented_ksq = orient(perspective, pos.nnue_king_square(perspective), pos);
|
| 56 |
+
Bitboard bb = pos.pieces(WHITE) | pos.pieces(BLACK);
|
| 57 |
+
while (bb)
|
| 58 |
+
{
|
| 59 |
+
Square s = pop_lsb(bb);
|
| 60 |
+
active.push_back(make_index(perspective, s, pos.piece_on(s), oriented_ksq, pos));
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
// Indices for pieces in hand
|
| 64 |
+
if (pos.nnue_use_pockets())
|
| 65 |
+
for (Color c : {WHITE, BLACK})
|
| 66 |
+
for (PieceSet ps = pos.piece_types(); ps;)
|
| 67 |
+
{
|
| 68 |
+
PieceType pt = pop_lsb(ps);
|
| 69 |
+
for (int i = 0; i < pos.count_in_hand(c, pt); i++)
|
| 70 |
+
active.push_back(make_index(perspective, i, make_piece(c, pt), oriented_ksq, pos));
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// append_changed_indices() : get a list of indices for recently changed features
|
| 76 |
+
|
| 77 |
+
void HalfKAv2Variants::append_changed_indices(
|
| 78 |
+
Square ksq,
|
| 79 |
+
StateInfo* st,
|
| 80 |
+
Color perspective,
|
| 81 |
+
ValueListInserter<IndexType> removed,
|
| 82 |
+
ValueListInserter<IndexType> added,
|
| 83 |
+
const Position& pos
|
| 84 |
+
) {
|
| 85 |
+
const auto& dp = st->dirtyPiece;
|
| 86 |
+
Square oriented_ksq = orient(perspective, ksq, pos);
|
| 87 |
+
for (int i = 0; i < dp.dirty_num; ++i) {
|
| 88 |
+
Piece pc = dp.piece[i];
|
| 89 |
+
if (dp.from[i] != SQ_NONE)
|
| 90 |
+
removed.push_back(make_index(perspective, dp.from[i], pc, oriented_ksq, pos));
|
| 91 |
+
else if (dp.handPiece[i] != NO_PIECE)
|
| 92 |
+
removed.push_back(make_index(perspective, dp.handCount[i] - 1, dp.handPiece[i], oriented_ksq, pos));
|
| 93 |
+
if (dp.to[i] != SQ_NONE)
|
| 94 |
+
added.push_back(make_index(perspective, dp.to[i], pc, oriented_ksq, pos));
|
| 95 |
+
else if (dp.handPiece[i] != NO_PIECE)
|
| 96 |
+
added.push_back(make_index(perspective, dp.handCount[i] - 1, dp.handPiece[i], oriented_ksq, pos));
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
int HalfKAv2Variants::update_cost(StateInfo* st) {
|
| 101 |
+
return st->dirtyPiece.dirty_num;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
int HalfKAv2Variants::refresh_cost(const Position& pos) {
|
| 105 |
+
return pos.count<ALL_PIECES>();
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
bool HalfKAv2Variants::requires_refresh(StateInfo* st, Color perspective, const Position& pos) {
|
| 109 |
+
return st->dirtyPiece.piece[0] == make_piece(perspective, pos.nnue_king()) || pos.flip_enclosed_pieces();
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
} // namespace Stockfish::Eval::NNUE::Features
|
Fairy-Stockfish-master/src/nnue/features/half_ka_v2_variants.h
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
//Definition of input features HalfKAv2 of NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#ifndef NNUE_FEATURES_HALF_KA_V2_VARIANTS_H_INCLUDED
|
| 22 |
+
#define NNUE_FEATURES_HALF_KA_V2_VARIANTS_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include "../nnue_common.h"
|
| 25 |
+
|
| 26 |
+
#include "../../evaluate.h"
|
| 27 |
+
#include "../../misc.h"
|
| 28 |
+
|
| 29 |
+
#include "half_ka_v2.h"
|
| 30 |
+
|
| 31 |
+
namespace Stockfish {
|
| 32 |
+
struct StateInfo;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
namespace Stockfish::Eval::NNUE::Features {
|
| 36 |
+
|
| 37 |
+
// Feature HalfKAv2: Combination of the position of own king
|
| 38 |
+
// and the position of pieces
|
| 39 |
+
class HalfKAv2Variants {
|
| 40 |
+
|
| 41 |
+
// Orient a square according to perspective (rotates by 180 for black)
|
| 42 |
+
static Square orient(Color perspective, Square s, const Position& pos);
|
| 43 |
+
|
| 44 |
+
// Index of a feature for a given king position and another piece on some square
|
| 45 |
+
static IndexType make_index(Color perspective, Square s, Piece pc, Square ksq, const Position& pos);
|
| 46 |
+
|
| 47 |
+
// Index of a feature for a given king position and another piece in hand
|
| 48 |
+
static IndexType make_index(Color perspective, int handCount, Piece pc, Square ksq, const Position& pos);
|
| 49 |
+
|
| 50 |
+
public:
|
| 51 |
+
// Feature name
|
| 52 |
+
static constexpr const char* Name = "HalfKAv2(Friend)";
|
| 53 |
+
|
| 54 |
+
// Hash value embedded in the evaluation file
|
| 55 |
+
static constexpr std::uint32_t HashValue = 0x5f234cb8u;
|
| 56 |
+
|
| 57 |
+
// Number of feature dimensions
|
| 58 |
+
static constexpr IndexType Dimensions = static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(SQUARE_NB) * 19;
|
| 59 |
+
|
| 60 |
+
static IndexType get_dimensions() {
|
| 61 |
+
return currentNnueVariant->nnueDimensions;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
// Maximum number of simultaneously active features.
|
| 65 |
+
static constexpr IndexType MaxActiveDimensions = 128;
|
| 66 |
+
|
| 67 |
+
// Get a list of indices for active features
|
| 68 |
+
static void append_active_indices(
|
| 69 |
+
const Position& pos,
|
| 70 |
+
Color perspective,
|
| 71 |
+
ValueListInserter<IndexType> active);
|
| 72 |
+
|
| 73 |
+
// Get a list of indices for recently changed features
|
| 74 |
+
static void append_changed_indices(
|
| 75 |
+
Square ksq,
|
| 76 |
+
StateInfo* st,
|
| 77 |
+
Color perspective,
|
| 78 |
+
ValueListInserter<IndexType> removed,
|
| 79 |
+
ValueListInserter<IndexType> added,
|
| 80 |
+
const Position& pos);
|
| 81 |
+
|
| 82 |
+
// Returns the cost of updating one perspective, the most costly one.
|
| 83 |
+
// Assumes no refresh needed.
|
| 84 |
+
static int update_cost(StateInfo* st);
|
| 85 |
+
static int refresh_cost(const Position& pos);
|
| 86 |
+
|
| 87 |
+
// Returns whether the change stored in this StateInfo means that
|
| 88 |
+
// a full accumulator refresh is required.
|
| 89 |
+
static bool requires_refresh(StateInfo* st, Color perspective, const Position& pos);
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
} // namespace Stockfish::Eval::NNUE::Features
|
| 93 |
+
|
| 94 |
+
#endif // #ifndef NNUE_FEATURES_HALF_KA_V2_VARIANTS_H_INCLUDED
|
Fairy-Stockfish-master/src/nnue/layers/affine_transform.h
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
// Definition of layer AffineTransform of NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
|
| 22 |
+
#define NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include <iostream>
|
| 25 |
+
#include "../nnue_common.h"
|
| 26 |
+
|
| 27 |
+
namespace Stockfish::Eval::NNUE::Layers {
|
| 28 |
+
|
| 29 |
+
// Affine transformation layer
|
| 30 |
+
template <typename PreviousLayer, IndexType OutDims>
|
| 31 |
+
class AffineTransform {
|
| 32 |
+
public:
|
| 33 |
+
// Input/output type
|
| 34 |
+
using InputType = typename PreviousLayer::OutputType;
|
| 35 |
+
using OutputType = std::int32_t;
|
| 36 |
+
static_assert(std::is_same<InputType, std::uint8_t>::value, "");
|
| 37 |
+
|
| 38 |
+
// Number of input/output dimensions
|
| 39 |
+
static constexpr IndexType InputDimensions =
|
| 40 |
+
PreviousLayer::OutputDimensions;
|
| 41 |
+
static constexpr IndexType OutputDimensions = OutDims;
|
| 42 |
+
static constexpr IndexType PaddedInputDimensions =
|
| 43 |
+
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
|
| 44 |
+
#if defined (USE_AVX512)
|
| 45 |
+
static constexpr const IndexType OutputSimdWidth = SimdWidth / 2;
|
| 46 |
+
#elif defined (USE_SSSE3)
|
| 47 |
+
static constexpr const IndexType OutputSimdWidth = SimdWidth / 4;
|
| 48 |
+
#endif
|
| 49 |
+
|
| 50 |
+
// Size of forward propagation buffer used in this layer
|
| 51 |
+
static constexpr std::size_t SelfBufferSize =
|
| 52 |
+
ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize);
|
| 53 |
+
|
| 54 |
+
// Size of the forward propagation buffer used from the input layer to this layer
|
| 55 |
+
static constexpr std::size_t BufferSize =
|
| 56 |
+
PreviousLayer::BufferSize + SelfBufferSize;
|
| 57 |
+
|
| 58 |
+
// Hash value embedded in the evaluation file
|
| 59 |
+
static constexpr std::uint32_t get_hash_value() {
|
| 60 |
+
std::uint32_t hashValue = 0xCC03DAE4u;
|
| 61 |
+
hashValue += OutputDimensions;
|
| 62 |
+
hashValue ^= PreviousLayer::get_hash_value() >> 1;
|
| 63 |
+
hashValue ^= PreviousLayer::get_hash_value() << 31;
|
| 64 |
+
return hashValue;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// Read network parameters
|
| 68 |
+
bool read_parameters(std::istream& stream) {
|
| 69 |
+
if (!previousLayer.read_parameters(stream)) return false;
|
| 70 |
+
for (std::size_t i = 0; i < OutputDimensions; ++i)
|
| 71 |
+
biases[i] = read_little_endian<BiasType>(stream);
|
| 72 |
+
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
| 73 |
+
#if !defined (USE_SSSE3)
|
| 74 |
+
weights[i] = read_little_endian<WeightType>(stream);
|
| 75 |
+
#else
|
| 76 |
+
weights[
|
| 77 |
+
(i / 4) % (PaddedInputDimensions / 4) * OutputDimensions * 4 +
|
| 78 |
+
i / PaddedInputDimensions * 4 +
|
| 79 |
+
i % 4
|
| 80 |
+
] = read_little_endian<WeightType>(stream);
|
| 81 |
+
#endif
|
| 82 |
+
|
| 83 |
+
return !stream.fail();
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// Write network parameters
|
| 87 |
+
bool write_parameters(std::ostream& stream) const {
|
| 88 |
+
if (!previousLayer.write_parameters(stream)) return false;
|
| 89 |
+
for (std::size_t i = 0; i < OutputDimensions; ++i)
|
| 90 |
+
write_little_endian<BiasType>(stream, biases[i]);
|
| 91 |
+
#if !defined (USE_SSSE3)
|
| 92 |
+
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
| 93 |
+
write_little_endian<WeightType>(stream, weights[i]);
|
| 94 |
+
#else
|
| 95 |
+
std::unique_ptr<WeightType[]> unscrambledWeights = std::make_unique<WeightType[]>(OutputDimensions * PaddedInputDimensions);
|
| 96 |
+
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) {
|
| 97 |
+
unscrambledWeights[i] =
|
| 98 |
+
weights[
|
| 99 |
+
(i / 4) % (PaddedInputDimensions / 4) * OutputDimensions * 4 +
|
| 100 |
+
i / PaddedInputDimensions * 4 +
|
| 101 |
+
i % 4
|
| 102 |
+
];
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
| 106 |
+
write_little_endian<WeightType>(stream, unscrambledWeights[i]);
|
| 107 |
+
#endif
|
| 108 |
+
|
| 109 |
+
return !stream.fail();
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
// Forward propagation
|
| 113 |
+
const OutputType* propagate(
|
| 114 |
+
const TransformedFeatureType* transformedFeatures, char* buffer) const {
|
| 115 |
+
const auto input = previousLayer.propagate(
|
| 116 |
+
transformedFeatures, buffer + SelfBufferSize);
|
| 117 |
+
|
| 118 |
+
#if defined (USE_AVX512)
|
| 119 |
+
|
| 120 |
+
[[maybe_unused]] const __m512i Ones512 = _mm512_set1_epi16(1);
|
| 121 |
+
|
| 122 |
+
[[maybe_unused]] auto m512_hadd = [](__m512i sum, int bias) -> int {
|
| 123 |
+
return _mm512_reduce_add_epi32(sum) + bias;
|
| 124 |
+
};
|
| 125 |
+
|
| 126 |
+
[[maybe_unused]] auto m512_add_dpbusd_epi32 = [=](__m512i& acc, __m512i a, __m512i b) {
|
| 127 |
+
#if defined (USE_VNNI)
|
| 128 |
+
acc = _mm512_dpbusd_epi32(acc, a, b);
|
| 129 |
+
#else
|
| 130 |
+
__m512i product0 = _mm512_maddubs_epi16(a, b);
|
| 131 |
+
product0 = _mm512_madd_epi16(product0, Ones512);
|
| 132 |
+
acc = _mm512_add_epi32(acc, product0);
|
| 133 |
+
#endif
|
| 134 |
+
};
|
| 135 |
+
|
| 136 |
+
[[maybe_unused]] auto m512_add_dpbusd_epi32x4 = [=](__m512i& acc, __m512i a0, __m512i b0, __m512i a1, __m512i b1,
|
| 137 |
+
__m512i a2, __m512i b2, __m512i a3, __m512i b3) {
|
| 138 |
+
#if defined (USE_VNNI)
|
| 139 |
+
acc = _mm512_dpbusd_epi32(acc, a0, b0);
|
| 140 |
+
acc = _mm512_dpbusd_epi32(acc, a1, b1);
|
| 141 |
+
acc = _mm512_dpbusd_epi32(acc, a2, b2);
|
| 142 |
+
acc = _mm512_dpbusd_epi32(acc, a3, b3);
|
| 143 |
+
#else
|
| 144 |
+
__m512i product0 = _mm512_maddubs_epi16(a0, b0);
|
| 145 |
+
__m512i product1 = _mm512_maddubs_epi16(a1, b1);
|
| 146 |
+
__m512i product2 = _mm512_maddubs_epi16(a2, b2);
|
| 147 |
+
__m512i product3 = _mm512_maddubs_epi16(a3, b3);
|
| 148 |
+
product0 = _mm512_adds_epi16(product0, product1);
|
| 149 |
+
product0 = _mm512_madd_epi16(product0, Ones512);
|
| 150 |
+
product2 = _mm512_adds_epi16(product2, product3);
|
| 151 |
+
product2 = _mm512_madd_epi16(product2, Ones512);
|
| 152 |
+
acc = _mm512_add_epi32(acc, _mm512_add_epi32(product0, product2));
|
| 153 |
+
#endif
|
| 154 |
+
};
|
| 155 |
+
|
| 156 |
+
#endif
|
| 157 |
+
#if defined (USE_AVX2)
|
| 158 |
+
|
| 159 |
+
[[maybe_unused]] const __m256i Ones256 = _mm256_set1_epi16(1);
|
| 160 |
+
|
| 161 |
+
[[maybe_unused]] auto m256_hadd = [](__m256i sum, int bias) -> int {
|
| 162 |
+
__m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum), _mm256_extracti128_si256(sum, 1));
|
| 163 |
+
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_BADC));
|
| 164 |
+
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_CDAB));
|
| 165 |
+
return _mm_cvtsi128_si32(sum128) + bias;
|
| 166 |
+
};
|
| 167 |
+
|
| 168 |
+
[[maybe_unused]] auto m256_add_dpbusd_epi32 = [=](__m256i& acc, __m256i a, __m256i b) {
|
| 169 |
+
#if defined (USE_VNNI)
|
| 170 |
+
acc = _mm256_dpbusd_epi32(acc, a, b);
|
| 171 |
+
#else
|
| 172 |
+
__m256i product0 = _mm256_maddubs_epi16(a, b);
|
| 173 |
+
product0 = _mm256_madd_epi16(product0, Ones256);
|
| 174 |
+
acc = _mm256_add_epi32(acc, product0);
|
| 175 |
+
#endif
|
| 176 |
+
};
|
| 177 |
+
|
| 178 |
+
[[maybe_unused]] auto m256_add_dpbusd_epi32x4 = [=](__m256i& acc, __m256i a0, __m256i b0, __m256i a1, __m256i b1,
|
| 179 |
+
__m256i a2, __m256i b2, __m256i a3, __m256i b3) {
|
| 180 |
+
#if defined (USE_VNNI)
|
| 181 |
+
acc = _mm256_dpbusd_epi32(acc, a0, b0);
|
| 182 |
+
acc = _mm256_dpbusd_epi32(acc, a1, b1);
|
| 183 |
+
acc = _mm256_dpbusd_epi32(acc, a2, b2);
|
| 184 |
+
acc = _mm256_dpbusd_epi32(acc, a3, b3);
|
| 185 |
+
#else
|
| 186 |
+
__m256i product0 = _mm256_maddubs_epi16(a0, b0);
|
| 187 |
+
__m256i product1 = _mm256_maddubs_epi16(a1, b1);
|
| 188 |
+
__m256i product2 = _mm256_maddubs_epi16(a2, b2);
|
| 189 |
+
__m256i product3 = _mm256_maddubs_epi16(a3, b3);
|
| 190 |
+
product0 = _mm256_adds_epi16(product0, product1);
|
| 191 |
+
product0 = _mm256_madd_epi16(product0, Ones256);
|
| 192 |
+
product2 = _mm256_adds_epi16(product2, product3);
|
| 193 |
+
product2 = _mm256_madd_epi16(product2, Ones256);
|
| 194 |
+
acc = _mm256_add_epi32(acc, _mm256_add_epi32(product0, product2));
|
| 195 |
+
#endif
|
| 196 |
+
};
|
| 197 |
+
|
| 198 |
+
#endif
|
| 199 |
+
#if defined (USE_SSSE3)
|
| 200 |
+
|
| 201 |
+
[[maybe_unused]] const __m128i Ones128 = _mm_set1_epi16(1);
|
| 202 |
+
|
| 203 |
+
[[maybe_unused]] auto m128_hadd = [](__m128i sum, int bias) -> int {
|
| 204 |
+
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0x4E)); //_MM_PERM_BADC
|
| 205 |
+
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0xB1)); //_MM_PERM_CDAB
|
| 206 |
+
return _mm_cvtsi128_si32(sum) + bias;
|
| 207 |
+
};
|
| 208 |
+
|
| 209 |
+
[[maybe_unused]] auto m128_add_dpbusd_epi32 = [=](__m128i& acc, __m128i a, __m128i b) {
|
| 210 |
+
__m128i product0 = _mm_maddubs_epi16(a, b);
|
| 211 |
+
product0 = _mm_madd_epi16(product0, Ones128);
|
| 212 |
+
acc = _mm_add_epi32(acc, product0);
|
| 213 |
+
};
|
| 214 |
+
|
| 215 |
+
[[maybe_unused]] auto m128_add_dpbusd_epi32x4 = [=](__m128i& acc, __m128i a0, __m128i b0, __m128i a1, __m128i b1,
|
| 216 |
+
__m128i a2, __m128i b2, __m128i a3, __m128i b3) {
|
| 217 |
+
__m128i product0 = _mm_maddubs_epi16(a0, b0);
|
| 218 |
+
__m128i product1 = _mm_maddubs_epi16(a1, b1);
|
| 219 |
+
__m128i product2 = _mm_maddubs_epi16(a2, b2);
|
| 220 |
+
__m128i product3 = _mm_maddubs_epi16(a3, b3);
|
| 221 |
+
product0 = _mm_adds_epi16(product0, product1);
|
| 222 |
+
product0 = _mm_madd_epi16(product0, Ones128);
|
| 223 |
+
product2 = _mm_adds_epi16(product2, product3);
|
| 224 |
+
product2 = _mm_madd_epi16(product2, Ones128);
|
| 225 |
+
acc = _mm_add_epi32(acc, _mm_add_epi32(product0, product2));
|
| 226 |
+
};
|
| 227 |
+
|
| 228 |
+
#endif
|
| 229 |
+
|
| 230 |
+
#if defined (USE_AVX512)
|
| 231 |
+
using vec_t = __m512i;
|
| 232 |
+
#define vec_setzero _mm512_setzero_si512
|
| 233 |
+
#define vec_set_32 _mm512_set1_epi32
|
| 234 |
+
auto& vec_add_dpbusd_32 = m512_add_dpbusd_epi32;
|
| 235 |
+
auto& vec_add_dpbusd_32x4 = m512_add_dpbusd_epi32x4;
|
| 236 |
+
auto& vec_hadd = m512_hadd;
|
| 237 |
+
#elif defined (USE_AVX2)
|
| 238 |
+
using vec_t = __m256i;
|
| 239 |
+
#define vec_setzero _mm256_setzero_si256
|
| 240 |
+
#define vec_set_32 _mm256_set1_epi32
|
| 241 |
+
auto& vec_add_dpbusd_32 = m256_add_dpbusd_epi32;
|
| 242 |
+
auto& vec_add_dpbusd_32x4 = m256_add_dpbusd_epi32x4;
|
| 243 |
+
auto& vec_hadd = m256_hadd;
|
| 244 |
+
#elif defined (USE_SSSE3)
|
| 245 |
+
using vec_t = __m128i;
|
| 246 |
+
#define vec_setzero _mm_setzero_si128
|
| 247 |
+
#define vec_set_32 _mm_set1_epi32
|
| 248 |
+
auto& vec_add_dpbusd_32 = m128_add_dpbusd_epi32;
|
| 249 |
+
auto& vec_add_dpbusd_32x4 = m128_add_dpbusd_epi32x4;
|
| 250 |
+
auto& vec_hadd = m128_hadd;
|
| 251 |
+
#endif
|
| 252 |
+
|
| 253 |
+
#if defined (USE_SSSE3)
|
| 254 |
+
// Different layout, we process 4 inputs at a time, always.
|
| 255 |
+
static_assert(InputDimensions % 4 == 0);
|
| 256 |
+
|
| 257 |
+
const auto output = reinterpret_cast<OutputType*>(buffer);
|
| 258 |
+
const auto inputVector = reinterpret_cast<const vec_t*>(input);
|
| 259 |
+
|
| 260 |
+
static_assert(OutputDimensions % OutputSimdWidth == 0 || OutputDimensions == 1);
|
| 261 |
+
|
| 262 |
+
// OutputDimensions is either 1 or a multiple of SimdWidth
|
| 263 |
+
// because then it is also an input dimension.
|
| 264 |
+
if constexpr (OutputDimensions % OutputSimdWidth == 0)
|
| 265 |
+
{
|
| 266 |
+
constexpr IndexType NumChunks = InputDimensions / 4;
|
| 267 |
+
|
| 268 |
+
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
|
| 269 |
+
vec_t* outptr = reinterpret_cast<vec_t*>(output);
|
| 270 |
+
std::memcpy(output, biases, OutputDimensions * sizeof(OutputType));
|
| 271 |
+
|
| 272 |
+
for (int i = 0; i < (int)NumChunks - 3; i += 4)
|
| 273 |
+
{
|
| 274 |
+
const vec_t in0 = vec_set_32(input32[i + 0]);
|
| 275 |
+
const vec_t in1 = vec_set_32(input32[i + 1]);
|
| 276 |
+
const vec_t in2 = vec_set_32(input32[i + 2]);
|
| 277 |
+
const vec_t in3 = vec_set_32(input32[i + 3]);
|
| 278 |
+
const auto col0 = reinterpret_cast<const vec_t*>(&weights[(i + 0) * OutputDimensions * 4]);
|
| 279 |
+
const auto col1 = reinterpret_cast<const vec_t*>(&weights[(i + 1) * OutputDimensions * 4]);
|
| 280 |
+
const auto col2 = reinterpret_cast<const vec_t*>(&weights[(i + 2) * OutputDimensions * 4]);
|
| 281 |
+
const auto col3 = reinterpret_cast<const vec_t*>(&weights[(i + 3) * OutputDimensions * 4]);
|
| 282 |
+
for (int j = 0; j * OutputSimdWidth < OutputDimensions; ++j)
|
| 283 |
+
vec_add_dpbusd_32x4(outptr[j], in0, col0[j], in1, col1[j], in2, col2[j], in3, col3[j]);
|
| 284 |
+
}
|
| 285 |
+
}
|
| 286 |
+
else if constexpr (OutputDimensions == 1)
|
| 287 |
+
{
|
| 288 |
+
#if defined (USE_AVX512)
|
| 289 |
+
if constexpr (PaddedInputDimensions % (SimdWidth * 2) != 0)
|
| 290 |
+
{
|
| 291 |
+
constexpr IndexType NumChunks = PaddedInputDimensions / SimdWidth;
|
| 292 |
+
const auto inputVector256 = reinterpret_cast<const __m256i*>(input);
|
| 293 |
+
|
| 294 |
+
__m256i sum0 = _mm256_setzero_si256();
|
| 295 |
+
const auto row0 = reinterpret_cast<const __m256i*>(&weights[0]);
|
| 296 |
+
|
| 297 |
+
for (int j = 0; j < (int)NumChunks; ++j)
|
| 298 |
+
{
|
| 299 |
+
const __m256i in = inputVector256[j];
|
| 300 |
+
m256_add_dpbusd_epi32(sum0, in, row0[j]);
|
| 301 |
+
}
|
| 302 |
+
output[0] = m256_hadd(sum0, biases[0]);
|
| 303 |
+
}
|
| 304 |
+
else
|
| 305 |
+
#endif
|
| 306 |
+
{
|
| 307 |
+
#if defined (USE_AVX512)
|
| 308 |
+
constexpr IndexType NumChunks = PaddedInputDimensions / (SimdWidth * 2);
|
| 309 |
+
#else
|
| 310 |
+
constexpr IndexType NumChunks = PaddedInputDimensions / SimdWidth;
|
| 311 |
+
#endif
|
| 312 |
+
vec_t sum0 = vec_setzero();
|
| 313 |
+
const auto row0 = reinterpret_cast<const vec_t*>(&weights[0]);
|
| 314 |
+
|
| 315 |
+
for (int j = 0; j < (int)NumChunks; ++j)
|
| 316 |
+
{
|
| 317 |
+
const vec_t in = inputVector[j];
|
| 318 |
+
vec_add_dpbusd_32(sum0, in, row0[j]);
|
| 319 |
+
}
|
| 320 |
+
output[0] = vec_hadd(sum0, biases[0]);
|
| 321 |
+
}
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
#else
|
| 325 |
+
|
| 326 |
+
// Use old implementation for the other architectures.
|
| 327 |
+
|
| 328 |
+
auto output = reinterpret_cast<OutputType*>(buffer);
|
| 329 |
+
|
| 330 |
+
#if defined(USE_SSE2)
|
| 331 |
+
// At least a multiple of 16, with SSE2.
|
| 332 |
+
static_assert(InputDimensions % SimdWidth == 0);
|
| 333 |
+
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
| 334 |
+
const __m128i Zeros = _mm_setzero_si128();
|
| 335 |
+
const auto inputVector = reinterpret_cast<const __m128i*>(input);
|
| 336 |
+
|
| 337 |
+
#elif defined(USE_MMX)
|
| 338 |
+
static_assert(InputDimensions % SimdWidth == 0);
|
| 339 |
+
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
| 340 |
+
const __m64 Zeros = _mm_setzero_si64();
|
| 341 |
+
const auto inputVector = reinterpret_cast<const __m64*>(input);
|
| 342 |
+
|
| 343 |
+
#elif defined(USE_NEON)
|
| 344 |
+
static_assert(InputDimensions % SimdWidth == 0);
|
| 345 |
+
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
| 346 |
+
const auto inputVector = reinterpret_cast<const int8x8_t*>(input);
|
| 347 |
+
#endif
|
| 348 |
+
|
| 349 |
+
for (IndexType i = 0; i < OutputDimensions; ++i) {
|
| 350 |
+
const IndexType offset = i * PaddedInputDimensions;
|
| 351 |
+
|
| 352 |
+
#if defined(USE_SSE2)
|
| 353 |
+
__m128i sumLo = _mm_cvtsi32_si128(biases[i]);
|
| 354 |
+
__m128i sumHi = Zeros;
|
| 355 |
+
const auto row = reinterpret_cast<const __m128i*>(&weights[offset]);
|
| 356 |
+
for (IndexType j = 0; j < NumChunks; ++j) {
|
| 357 |
+
__m128i row_j = _mm_load_si128(&row[j]);
|
| 358 |
+
__m128i input_j = _mm_load_si128(&inputVector[j]);
|
| 359 |
+
__m128i extendedRowLo = _mm_srai_epi16(_mm_unpacklo_epi8(row_j, row_j), 8);
|
| 360 |
+
__m128i extendedRowHi = _mm_srai_epi16(_mm_unpackhi_epi8(row_j, row_j), 8);
|
| 361 |
+
__m128i extendedInputLo = _mm_unpacklo_epi8(input_j, Zeros);
|
| 362 |
+
__m128i extendedInputHi = _mm_unpackhi_epi8(input_j, Zeros);
|
| 363 |
+
__m128i productLo = _mm_madd_epi16(extendedRowLo, extendedInputLo);
|
| 364 |
+
__m128i productHi = _mm_madd_epi16(extendedRowHi, extendedInputHi);
|
| 365 |
+
sumLo = _mm_add_epi32(sumLo, productLo);
|
| 366 |
+
sumHi = _mm_add_epi32(sumHi, productHi);
|
| 367 |
+
}
|
| 368 |
+
__m128i sum = _mm_add_epi32(sumLo, sumHi);
|
| 369 |
+
__m128i sumHigh_64 = _mm_shuffle_epi32(sum, _MM_SHUFFLE(1, 0, 3, 2));
|
| 370 |
+
sum = _mm_add_epi32(sum, sumHigh_64);
|
| 371 |
+
__m128i sum_second_32 = _mm_shufflelo_epi16(sum, _MM_SHUFFLE(1, 0, 3, 2));
|
| 372 |
+
sum = _mm_add_epi32(sum, sum_second_32);
|
| 373 |
+
output[i] = _mm_cvtsi128_si32(sum);
|
| 374 |
+
|
| 375 |
+
#elif defined(USE_MMX)
|
| 376 |
+
__m64 sumLo = _mm_cvtsi32_si64(biases[i]);
|
| 377 |
+
__m64 sumHi = Zeros;
|
| 378 |
+
const auto row = reinterpret_cast<const __m64*>(&weights[offset]);
|
| 379 |
+
for (IndexType j = 0; j < NumChunks; ++j) {
|
| 380 |
+
__m64 row_j = row[j];
|
| 381 |
+
__m64 input_j = inputVector[j];
|
| 382 |
+
__m64 extendedRowLo = _mm_srai_pi16(_mm_unpacklo_pi8(row_j, row_j), 8);
|
| 383 |
+
__m64 extendedRowHi = _mm_srai_pi16(_mm_unpackhi_pi8(row_j, row_j), 8);
|
| 384 |
+
__m64 extendedInputLo = _mm_unpacklo_pi8(input_j, Zeros);
|
| 385 |
+
__m64 extendedInputHi = _mm_unpackhi_pi8(input_j, Zeros);
|
| 386 |
+
__m64 productLo = _mm_madd_pi16(extendedRowLo, extendedInputLo);
|
| 387 |
+
__m64 productHi = _mm_madd_pi16(extendedRowHi, extendedInputHi);
|
| 388 |
+
sumLo = _mm_add_pi32(sumLo, productLo);
|
| 389 |
+
sumHi = _mm_add_pi32(sumHi, productHi);
|
| 390 |
+
}
|
| 391 |
+
__m64 sum = _mm_add_pi32(sumLo, sumHi);
|
| 392 |
+
sum = _mm_add_pi32(sum, _mm_unpackhi_pi32(sum, sum));
|
| 393 |
+
output[i] = _mm_cvtsi64_si32(sum);
|
| 394 |
+
|
| 395 |
+
#elif defined(USE_NEON)
|
| 396 |
+
int32x4_t sum = {biases[i]};
|
| 397 |
+
const auto row = reinterpret_cast<const int8x8_t*>(&weights[offset]);
|
| 398 |
+
for (IndexType j = 0; j < NumChunks; ++j) {
|
| 399 |
+
int16x8_t product = vmull_s8(inputVector[j * 2], row[j * 2]);
|
| 400 |
+
product = vmlal_s8(product, inputVector[j * 2 + 1], row[j * 2 + 1]);
|
| 401 |
+
sum = vpadalq_s16(sum, product);
|
| 402 |
+
}
|
| 403 |
+
output[i] = sum[0] + sum[1] + sum[2] + sum[3];
|
| 404 |
+
|
| 405 |
+
#else
|
| 406 |
+
OutputType sum = biases[i];
|
| 407 |
+
for (IndexType j = 0; j < InputDimensions; ++j) {
|
| 408 |
+
sum += weights[offset + j] * input[j];
|
| 409 |
+
}
|
| 410 |
+
output[i] = sum;
|
| 411 |
+
#endif
|
| 412 |
+
|
| 413 |
+
}
|
| 414 |
+
#if defined(USE_MMX)
|
| 415 |
+
_mm_empty();
|
| 416 |
+
#endif
|
| 417 |
+
|
| 418 |
+
#endif
|
| 419 |
+
|
| 420 |
+
return output;
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
private:
|
| 424 |
+
using BiasType = OutputType;
|
| 425 |
+
using WeightType = std::int8_t;
|
| 426 |
+
|
| 427 |
+
PreviousLayer previousLayer;
|
| 428 |
+
|
| 429 |
+
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
| 430 |
+
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
| 431 |
+
};
|
| 432 |
+
|
| 433 |
+
} // namespace Stockfish::Eval::NNUE::Layers
|
| 434 |
+
|
| 435 |
+
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_H_INCLUDED
|
Fairy-Stockfish-master/src/nnue/layers/clipped_relu.h
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file)
|
| 4 |
+
|
| 5 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
it under the terms of the GNU General Public License as published by
|
| 7 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
(at your option) any later version.
|
| 9 |
+
|
| 10 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
You should have received a copy of the GNU General Public License
|
| 16 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
*/
|
| 18 |
+
|
| 19 |
+
// Definition of layer ClippedReLU of NNUE evaluation function
|
| 20 |
+
|
| 21 |
+
#ifndef NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
|
| 22 |
+
#define NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include "../nnue_common.h"
|
| 25 |
+
|
| 26 |
+
namespace Stockfish::Eval::NNUE::Layers {
|
| 27 |
+
|
| 28 |
+
// Clipped ReLU
|
| 29 |
+
template <typename PreviousLayer>
|
| 30 |
+
class ClippedReLU {
|
| 31 |
+
public:
|
| 32 |
+
// Input/output type
|
| 33 |
+
using InputType = typename PreviousLayer::OutputType;
|
| 34 |
+
using OutputType = std::uint8_t;
|
| 35 |
+
static_assert(std::is_same<InputType, std::int32_t>::value, "");
|
| 36 |
+
|
| 37 |
+
// Number of input/output dimensions
|
| 38 |
+
static constexpr IndexType InputDimensions =
|
| 39 |
+
PreviousLayer::OutputDimensions;
|
| 40 |
+
static constexpr IndexType OutputDimensions = InputDimensions;
|
| 41 |
+
|
| 42 |
+
// Size of forward propagation buffer used in this layer
|
| 43 |
+
static constexpr std::size_t SelfBufferSize =
|
| 44 |
+
ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize);
|
| 45 |
+
|
| 46 |
+
// Size of the forward propagation buffer used from the input layer to this layer
|
| 47 |
+
static constexpr std::size_t BufferSize =
|
| 48 |
+
PreviousLayer::BufferSize + SelfBufferSize;
|
| 49 |
+
|
| 50 |
+
// Hash value embedded in the evaluation file
|
| 51 |
+
static constexpr std::uint32_t get_hash_value() {
|
| 52 |
+
std::uint32_t hashValue = 0x538D24C7u;
|
| 53 |
+
hashValue += PreviousLayer::get_hash_value();
|
| 54 |
+
return hashValue;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
// Read network parameters
|
| 58 |
+
bool read_parameters(std::istream& stream) {
|
| 59 |
+
return previousLayer.read_parameters(stream);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// Write network parameters
|
| 63 |
+
bool write_parameters(std::ostream& stream) const {
|
| 64 |
+
return previousLayer.write_parameters(stream);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// Forward propagation
|
| 68 |
+
const OutputType* propagate(
|
| 69 |
+
const TransformedFeatureType* transformedFeatures, char* buffer) const {
|
| 70 |
+
const auto input = previousLayer.propagate(
|
| 71 |
+
transformedFeatures, buffer + SelfBufferSize);
|
| 72 |
+
const auto output = reinterpret_cast<OutputType*>(buffer);
|
| 73 |
+
|
| 74 |
+
#if defined(USE_AVX2)
|
| 75 |
+
if constexpr (InputDimensions % SimdWidth == 0) {
|
| 76 |
+
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
| 77 |
+
const __m256i Zero = _mm256_setzero_si256();
|
| 78 |
+
const __m256i Offsets = _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0);
|
| 79 |
+
const auto in = reinterpret_cast<const __m256i*>(input);
|
| 80 |
+
const auto out = reinterpret_cast<__m256i*>(output);
|
| 81 |
+
for (IndexType i = 0; i < NumChunks; ++i) {
|
| 82 |
+
const __m256i words0 = _mm256_srai_epi16(_mm256_packs_epi32(
|
| 83 |
+
_mm256_load_si256(&in[i * 4 + 0]),
|
| 84 |
+
_mm256_load_si256(&in[i * 4 + 1])), WeightScaleBits);
|
| 85 |
+
const __m256i words1 = _mm256_srai_epi16(_mm256_packs_epi32(
|
| 86 |
+
_mm256_load_si256(&in[i * 4 + 2]),
|
| 87 |
+
_mm256_load_si256(&in[i * 4 + 3])), WeightScaleBits);
|
| 88 |
+
_mm256_store_si256(&out[i], _mm256_permutevar8x32_epi32(_mm256_max_epi8(
|
| 89 |
+
_mm256_packs_epi16(words0, words1), Zero), Offsets));
|
| 90 |
+
}
|
| 91 |
+
} else {
|
| 92 |
+
constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2);
|
| 93 |
+
const __m128i Zero = _mm_setzero_si128();
|
| 94 |
+
const auto in = reinterpret_cast<const __m128i*>(input);
|
| 95 |
+
const auto out = reinterpret_cast<__m128i*>(output);
|
| 96 |
+
for (IndexType i = 0; i < NumChunks; ++i) {
|
| 97 |
+
const __m128i words0 = _mm_srai_epi16(_mm_packs_epi32(
|
| 98 |
+
_mm_load_si128(&in[i * 4 + 0]),
|
| 99 |
+
_mm_load_si128(&in[i * 4 + 1])), WeightScaleBits);
|
| 100 |
+
const __m128i words1 = _mm_srai_epi16(_mm_packs_epi32(
|
| 101 |
+
_mm_load_si128(&in[i * 4 + 2]),
|
| 102 |
+
_mm_load_si128(&in[i * 4 + 3])), WeightScaleBits);
|
| 103 |
+
const __m128i packedbytes = _mm_packs_epi16(words0, words1);
|
| 104 |
+
_mm_store_si128(&out[i], _mm_max_epi8(packedbytes, Zero));
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
constexpr IndexType Start =
|
| 108 |
+
InputDimensions % SimdWidth == 0
|
| 109 |
+
? InputDimensions / SimdWidth * SimdWidth
|
| 110 |
+
: InputDimensions / (SimdWidth / 2) * (SimdWidth / 2);
|
| 111 |
+
|
| 112 |
+
#elif defined(USE_SSE2)
|
| 113 |
+
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
| 114 |
+
|
| 115 |
+
#ifdef USE_SSE41
|
| 116 |
+
const __m128i Zero = _mm_setzero_si128();
|
| 117 |
+
#else
|
| 118 |
+
const __m128i k0x80s = _mm_set1_epi8(-128);
|
| 119 |
+
#endif
|
| 120 |
+
|
| 121 |
+
const auto in = reinterpret_cast<const __m128i*>(input);
|
| 122 |
+
const auto out = reinterpret_cast<__m128i*>(output);
|
| 123 |
+
for (IndexType i = 0; i < NumChunks; ++i) {
|
| 124 |
+
const __m128i words0 = _mm_srai_epi16(_mm_packs_epi32(
|
| 125 |
+
_mm_load_si128(&in[i * 4 + 0]),
|
| 126 |
+
_mm_load_si128(&in[i * 4 + 1])), WeightScaleBits);
|
| 127 |
+
const __m128i words1 = _mm_srai_epi16(_mm_packs_epi32(
|
| 128 |
+
_mm_load_si128(&in[i * 4 + 2]),
|
| 129 |
+
_mm_load_si128(&in[i * 4 + 3])), WeightScaleBits);
|
| 130 |
+
const __m128i packedbytes = _mm_packs_epi16(words0, words1);
|
| 131 |
+
_mm_store_si128(&out[i],
|
| 132 |
+
|
| 133 |
+
#ifdef USE_SSE41
|
| 134 |
+
_mm_max_epi8(packedbytes, Zero)
|
| 135 |
+
#else
|
| 136 |
+
_mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s)
|
| 137 |
+
#endif
|
| 138 |
+
|
| 139 |
+
);
|
| 140 |
+
}
|
| 141 |
+
constexpr IndexType Start = NumChunks * SimdWidth;
|
| 142 |
+
|
| 143 |
+
#elif defined(USE_MMX)
|
| 144 |
+
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
| 145 |
+
const __m64 k0x80s = _mm_set1_pi8(-128);
|
| 146 |
+
const auto in = reinterpret_cast<const __m64*>(input);
|
| 147 |
+
const auto out = reinterpret_cast<__m64*>(output);
|
| 148 |
+
for (IndexType i = 0; i < NumChunks; ++i) {
|
| 149 |
+
const __m64 words0 = _mm_srai_pi16(
|
| 150 |
+
_mm_packs_pi32(in[i * 4 + 0], in[i * 4 + 1]),
|
| 151 |
+
WeightScaleBits);
|
| 152 |
+
const __m64 words1 = _mm_srai_pi16(
|
| 153 |
+
_mm_packs_pi32(in[i * 4 + 2], in[i * 4 + 3]),
|
| 154 |
+
WeightScaleBits);
|
| 155 |
+
const __m64 packedbytes = _mm_packs_pi16(words0, words1);
|
| 156 |
+
out[i] = _mm_subs_pi8(_mm_adds_pi8(packedbytes, k0x80s), k0x80s);
|
| 157 |
+
}
|
| 158 |
+
_mm_empty();
|
| 159 |
+
constexpr IndexType Start = NumChunks * SimdWidth;
|
| 160 |
+
|
| 161 |
+
#elif defined(USE_NEON)
|
| 162 |
+
constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2);
|
| 163 |
+
const int8x8_t Zero = {0};
|
| 164 |
+
const auto in = reinterpret_cast<const int32x4_t*>(input);
|
| 165 |
+
const auto out = reinterpret_cast<int8x8_t*>(output);
|
| 166 |
+
for (IndexType i = 0; i < NumChunks; ++i) {
|
| 167 |
+
int16x8_t shifted;
|
| 168 |
+
const auto pack = reinterpret_cast<int16x4_t*>(&shifted);
|
| 169 |
+
pack[0] = vqshrn_n_s32(in[i * 2 + 0], WeightScaleBits);
|
| 170 |
+
pack[1] = vqshrn_n_s32(in[i * 2 + 1], WeightScaleBits);
|
| 171 |
+
out[i] = vmax_s8(vqmovn_s16(shifted), Zero);
|
| 172 |
+
}
|
| 173 |
+
constexpr IndexType Start = NumChunks * (SimdWidth / 2);
|
| 174 |
+
#else
|
| 175 |
+
constexpr IndexType Start = 0;
|
| 176 |
+
#endif
|
| 177 |
+
|
| 178 |
+
for (IndexType i = Start; i < InputDimensions; ++i) {
|
| 179 |
+
output[i] = static_cast<OutputType>(
|
| 180 |
+
std::max(0, std::min(127, input[i] >> WeightScaleBits)));
|
| 181 |
+
}
|
| 182 |
+
return output;
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
private:
|
| 186 |
+
PreviousLayer previousLayer;
|
| 187 |
+
};
|
| 188 |
+
|
| 189 |
+
} // namespace Stockfish::Eval::NNUE::Layers
|
| 190 |
+
|
| 191 |
+
#endif // NNUE_LAYERS_CLIPPED_RELU_H_INCLUDED
|