BlueMoonBot commited on
Commit
1f80264
·
verified ·
1 Parent(s): 372a761

Upload 109 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Fairy-Stockfish-master/.gitattributes +1 -0
  2. Fairy-Stockfish-master/.github/FUNDING.yml +2 -0
  3. Fairy-Stockfish-master/.github/dependabot.yml +13 -0
  4. Fairy-Stockfish-master/.github/workflows/fairy.yml +93 -0
  5. Fairy-Stockfish-master/.github/workflows/ffishjs.yml +90 -0
  6. Fairy-Stockfish-master/.github/workflows/release.yml +116 -0
  7. Fairy-Stockfish-master/.github/workflows/stockfish.yml +213 -0
  8. Fairy-Stockfish-master/.github/workflows/wheels.yml +57 -0
  9. Fairy-Stockfish-master/.gitignore +43 -0
  10. Fairy-Stockfish-master/AGENTS.md +158 -0
  11. Fairy-Stockfish-master/AUTHORS +231 -0
  12. Fairy-Stockfish-master/Copying.txt +674 -0
  13. Fairy-Stockfish-master/MANIFEST.in +2 -0
  14. Fairy-Stockfish-master/README.md +126 -0
  15. Fairy-Stockfish-master/Top CPU Contributors.txt +205 -0
  16. Fairy-Stockfish-master/appveyor.yml +91 -0
  17. Fairy-Stockfish-master/pyffish.pyi +39 -0
  18. Fairy-Stockfish-master/setup.py +56 -0
  19. Fairy-Stockfish-master/src/Makefile +982 -0
  20. Fairy-Stockfish-master/src/Makefile_js +95 -0
  21. Fairy-Stockfish-master/src/apiutil.h +1165 -0
  22. Fairy-Stockfish-master/src/benchmark.cpp +195 -0
  23. Fairy-Stockfish-master/src/bitbase.cpp +177 -0
  24. Fairy-Stockfish-master/src/bitboard.cpp +501 -0
  25. Fairy-Stockfish-master/src/bitboard.h +787 -0
  26. Fairy-Stockfish-master/src/endgame.cpp +1321 -0
  27. Fairy-Stockfish-master/src/endgame.h +148 -0
  28. Fairy-Stockfish-master/src/evaluate.cpp +1736 -0
  29. Fairy-Stockfish-master/src/evaluate.h +66 -0
  30. Fairy-Stockfish-master/src/ffishjs.cpp +767 -0
  31. Fairy-Stockfish-master/src/incbin/UNLICENCE +26 -0
  32. Fairy-Stockfish-master/src/incbin/incbin.h +368 -0
  33. Fairy-Stockfish-master/src/magic.h +1741 -0
  34. Fairy-Stockfish-master/src/main.cpp +63 -0
  35. Fairy-Stockfish-master/src/material.cpp +321 -0
  36. Fairy-Stockfish-master/src/material.h +75 -0
  37. Fairy-Stockfish-master/src/misc.cpp +656 -0
  38. Fairy-Stockfish-master/src/misc.h +200 -0
  39. Fairy-Stockfish-master/src/movegen.cpp +528 -0
  40. Fairy-Stockfish-master/src/movegen.h +107 -0
  41. Fairy-Stockfish-master/src/movepick.cpp +279 -0
  42. Fairy-Stockfish-master/src/movepick.h +169 -0
  43. Fairy-Stockfish-master/src/nnue/evaluate_nnue.cpp +443 -0
  44. Fairy-Stockfish-master/src/nnue/evaluate_nnue.h +59 -0
  45. Fairy-Stockfish-master/src/nnue/features/half_ka_v2.cpp +90 -0
  46. Fairy-Stockfish-master/src/nnue/features/half_ka_v2.h +152 -0
  47. Fairy-Stockfish-master/src/nnue/features/half_ka_v2_variants.cpp +112 -0
  48. Fairy-Stockfish-master/src/nnue/features/half_ka_v2_variants.h +94 -0
  49. Fairy-Stockfish-master/src/nnue/layers/affine_transform.h +435 -0
  50. 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
+ [![Build Status](https://github.com/fairy-stockfish/Fairy-Stockfish/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/fairy-stockfish/Fairy-Stockfish/actions?query=workflow%3ARelease)
6
+ [![Build Status](https://github.com/fairy-stockfish/Fairy-Stockfish/actions/workflows/fairy.yml/badge.svg?branch=master)](https://github.com/fairy-stockfish/Fairy-Stockfish/actions?query=workflow%3Afairy)
7
+ [![Build Status](https://ci.appveyor.com/api/projects/status/github/fairy-stockfish/Fairy-Stockfish?branch=master&svg=true)](https://ci.appveyor.com/project/ianfab/Fairy-Stockfish/branch/master)
8
+ [![PyPI version](https://badge.fury.io/py/pyffish.svg)](https://badge.fury.io/py/pyffish)
9
+ [![NPM version](https://img.shields.io/npm/v/ffish.svg?sanitize=true)](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