mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Merge commit '315f8ba4bf7d846b35f984d5e6040c14a512d9b9' into cluster
This is the last commit before there are more conflicts.
This commit is contained in:
+26
-26
@@ -8,11 +8,11 @@
|
|||||||
"comp": "gcc",
|
"comp": "gcc",
|
||||||
"shell": "bash",
|
"shell": "bash",
|
||||||
"archive_ext": "tar",
|
"archive_ext": "tar",
|
||||||
"sde": "/home/runner/work/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.27.0-2023-09-13-lin/sde -future --"
|
"sde": "/home/runner/work/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.33.0-2024-01-07-lin/sde -future --"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "MacOS 13 Apple Clang",
|
"name": "macOS 15 Apple Clang",
|
||||||
"os": "macos-13",
|
"os": "macos-15-intel",
|
||||||
"simple_name": "macos",
|
"simple_name": "macos",
|
||||||
"compiler": "clang++",
|
"compiler": "clang++",
|
||||||
"comp": "clang",
|
"comp": "clang",
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"archive_ext": "tar"
|
"archive_ext": "tar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "MacOS 14 Apple Clang M1",
|
"name": "macOS 14 Apple Clang M1",
|
||||||
"os": "macos-14",
|
"os": "macos-14",
|
||||||
"simple_name": "macos-m1",
|
"simple_name": "macos-m1",
|
||||||
"compiler": "clang++",
|
"compiler": "clang++",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"msys_env": "x86_64-gcc",
|
"msys_env": "x86_64-gcc",
|
||||||
"shell": "msys2 {0}",
|
"shell": "msys2 {0}",
|
||||||
"ext": ".exe",
|
"ext": ".exe",
|
||||||
"sde": "/d/a/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.27.0-2023-09-13-win/sde.exe -future --",
|
"sde": "/d/a/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.33.0-2024-01-07-win/sde.exe -future --",
|
||||||
"archive_ext": "zip"
|
"archive_ext": "zip"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -61,8 +61,8 @@
|
|||||||
"x86-64-bmi2",
|
"x86-64-bmi2",
|
||||||
"x86-64-avxvnni",
|
"x86-64-avxvnni",
|
||||||
"x86-64-avx512",
|
"x86-64-avx512",
|
||||||
"x86-64-vnni256",
|
|
||||||
"x86-64-vnni512",
|
"x86-64-vnni512",
|
||||||
|
"x86-64-avx512icl",
|
||||||
"apple-silicon",
|
"apple-silicon",
|
||||||
"armv8",
|
"armv8",
|
||||||
"armv8-dotprod"
|
"armv8-dotprod"
|
||||||
@@ -105,13 +105,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"binaries": "x86-64-vnni256",
|
"binaries": "x86-64-vnni512",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-14"
|
"os": "macos-14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"binaries": "x86-64-vnni512",
|
"binaries": "x86-64-avx512icl",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-14"
|
"os": "macos-14"
|
||||||
}
|
}
|
||||||
@@ -119,25 +119,25 @@
|
|||||||
{
|
{
|
||||||
"binaries": "x86-64-avxvnni",
|
"binaries": "x86-64-avxvnni",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-13"
|
"os": "macos-15-intel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"binaries": "x86-64-avx512",
|
"binaries": "x86-64-avx512",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-13"
|
"os": "macos-15-intel"
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"binaries": "x86-64-vnni256",
|
|
||||||
"config": {
|
|
||||||
"os": "macos-13"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"binaries": "x86-64-vnni512",
|
"binaries": "x86-64-vnni512",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-13"
|
"os": "macos-15-intel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": "x86-64-avx512icl",
|
||||||
|
"config": {
|
||||||
|
"os": "macos-15-intel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -176,18 +176,18 @@
|
|||||||
"os": "windows-11-arm"
|
"os": "windows-11-arm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"binaries": "x86-64-vnni256",
|
|
||||||
"config": {
|
|
||||||
"os": "windows-11-arm"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"binaries": "x86-64-vnni512",
|
"binaries": "x86-64-vnni512",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "windows-11-arm"
|
"os": "windows-11-arm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"binaries": "x86-64-avx512icl",
|
||||||
|
"config": {
|
||||||
|
"os": "windows-11-arm"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"binaries": "apple-silicon",
|
"binaries": "apple-silicon",
|
||||||
"config": {
|
"config": {
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
{
|
{
|
||||||
"binaries": "apple-silicon",
|
"binaries": "apple-silicon",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-13"
|
"os": "macos-15-intel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -239,7 +239,7 @@
|
|||||||
{
|
{
|
||||||
"binaries": "armv8",
|
"binaries": "armv8",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-13"
|
"os": "macos-15-intel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -269,7 +269,7 @@
|
|||||||
{
|
{
|
||||||
"binaries": "armv8-dotprod",
|
"binaries": "armv8-dotprod",
|
||||||
"config": {
|
"config": {
|
||||||
"os": "macos-13"
|
"os": "macos-15-intel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Download SDE package
|
- name: Download SDE package
|
||||||
if: runner.os == 'Linux' || runner.os == 'Windows'
|
if: runner.os == 'Linux' || runner.os == 'Windows'
|
||||||
uses: petarpetrovt/setup-sde@91a1a03434384e064706634125a15f7446d2aafb # @v2.3
|
uses: petarpetrovt/setup-sde@f0fa5971dc275704531e94264dd23250c442aa41 # @v2.4
|
||||||
with:
|
with:
|
||||||
environmentVariableName: SDE_DIR
|
environmentVariableName: SDE_DIR
|
||||||
sdeVersion: 9.27.0
|
sdeVersion: 9.33.0
|
||||||
|
|
||||||
- name: Download the used network from the fishtest framework
|
- name: Download the used network from the fishtest framework
|
||||||
run: make net
|
run: make net
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: vondele/matetrack
|
repository: vondele/matetrack
|
||||||
path: matetrack
|
path: matetrack
|
||||||
ref: 4f8a80860ed8f3607f05a9195df8b40203bdc360
|
ref: 2d96fa3373f90edb032b7ea7468473fb9e6f0343
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: matetrack install deps
|
- name: matetrack install deps
|
||||||
@@ -47,25 +47,44 @@ jobs:
|
|||||||
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-wdl/
|
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-wdl/
|
||||||
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-dtz/
|
wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-dtz/
|
||||||
|
|
||||||
- name: Run matetrack
|
- name: Run matetrack th1
|
||||||
working-directory: matetrack
|
working-directory: matetrack
|
||||||
run: |
|
run: |
|
||||||
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out
|
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout1.out
|
||||||
! grep "issues were detected" matecheckout.out > /dev/null
|
! grep "issues were detected" matecheckout1.out > /dev/null
|
||||||
|
|
||||||
- name: Run matetrack with --syzygy50MoveRule false
|
- name: Run matetrack th4
|
||||||
|
working-directory: matetrack
|
||||||
|
run: |
|
||||||
|
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 --threads 4 | tee matecheckout4.out
|
||||||
|
! grep "issues were detected" matecheckout4.out > /dev/null
|
||||||
|
|
||||||
|
- name: Run matetrack th1 with --syzygy50MoveRule false
|
||||||
working-directory: matetrack
|
working-directory: matetrack
|
||||||
run: |
|
run: |
|
||||||
grep 5men cursed.epd > cursed5.epd
|
grep 5men cursed.epd > cursed5.epd
|
||||||
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed.out
|
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed1.out
|
||||||
! grep "issues were detected" matecheckcursed.out > /dev/null
|
! grep "issues were detected" matecheckcursed1.out > /dev/null
|
||||||
|
|
||||||
- name: Verify mate and TB win count for matecheckcursed.out
|
- name: Run matetrack th4 with --syzygy50MoveRule false
|
||||||
working-directory: matetrack
|
working-directory: matetrack
|
||||||
run: |
|
run: |
|
||||||
mates=$(grep "Found mates:" matecheckcursed.out | awk '{print $3}')
|
grep 5men cursed.epd > cursed5.epd
|
||||||
tbwins=$(grep "Found TB wins:" matecheckcursed.out | awk '{print $4}')
|
python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --threads 4 --syzygy50MoveRule false | tee matecheckcursed4.out
|
||||||
|
! grep "issues were detected" matecheckcursed4.out > /dev/null
|
||||||
|
|
||||||
|
- name: Verify mate and TB win count for matecheckcursed[14].out
|
||||||
|
working-directory: matetrack
|
||||||
|
run: |
|
||||||
|
mates=$(grep "Found mates:" matecheckcursed1.out | awk '{print $3}')
|
||||||
|
tbwins=$(grep "Found TB wins:" matecheckcursed1.out | awk '{print $4}')
|
||||||
if [ $(($mates + $tbwins)) -ne 32 ]; then
|
if [ $(($mates + $tbwins)) -ne 32 ]; then
|
||||||
echo "Sum of mates and TB wins is not 32 in matecheckcursed.out" >&2
|
echo "Sum of mates and TB wins is not 32 in matecheckcursed1.out" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mates=$(grep "Found mates:" matecheckcursed4.out | awk '{print $3}')
|
||||||
|
tbwins=$(grep "Found TB wins:" matecheckcursed4.out | awk '{print $4}')
|
||||||
|
if [ $(($mates + $tbwins)) -ne 32 ]; then
|
||||||
|
echo "Sum of mates and TB wins is not 32 in matecheckcursed4.out" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- name: Run with glibcxx assertions
|
- name: Run with glibcxx assertions
|
||||||
make_option: ""
|
make_option: ""
|
||||||
cxx_extra_flags: -D_GLIBCXX_ASSERTIONS
|
cxx_extra_flags: -D_GLIBCXX_ASSERTIONS
|
||||||
instrumented_option: non
|
instrumented_option: none
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: src
|
working-directory: src
|
||||||
|
|||||||
@@ -56,21 +56,21 @@ jobs:
|
|||||||
base_image: "ppc64le/alpine:latest"
|
base_image: "ppc64le/alpine:latest"
|
||||||
platform: linux/ppc64le
|
platform: linux/ppc64le
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: MacOS 13 Apple Clang
|
- name: macOS 15 Apple Clang
|
||||||
os: macos-13
|
os: macos-15-intel
|
||||||
compiler: clang++
|
compiler: clang++
|
||||||
comp: clang
|
comp: clang
|
||||||
run_64bit_tests: true
|
run_64bit_tests: true
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: MacOS 14 Apple Clang M1
|
- name: macOS 14 Apple Clang M1
|
||||||
os: macos-14
|
os: macos-14
|
||||||
compiler: clang++
|
compiler: clang++
|
||||||
comp: clang
|
comp: clang
|
||||||
run_64bit_tests: false
|
run_64bit_tests: false
|
||||||
run_m1_tests: true
|
run_m1_tests: true
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: MacOS 13 GCC 11
|
- name: macOS 15 GCC 11
|
||||||
os: macos-13
|
os: macos-15-intel
|
||||||
compiler: g++-11
|
compiler: g++-11
|
||||||
comp: gcc
|
comp: gcc
|
||||||
run_64bit_tests: true
|
run_64bit_tests: true
|
||||||
|
|||||||
@@ -12,20 +12,17 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
Artifacts:
|
Artifacts:
|
||||||
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
|
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
|
||||||
runs-on: ${{ matrix.config.os }}
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
COMPCXX: ${{ matrix.config.compiler }}
|
|
||||||
COMP: ${{ matrix.config.comp }}
|
|
||||||
EXT: ${{ matrix.config.ext }}
|
EXT: ${{ matrix.config.ext }}
|
||||||
NAME: ${{ matrix.config.simple_name }}
|
NAME: ${{ matrix.config.simple_name }}
|
||||||
BINARY: ${{ matrix.binaries }}
|
BINARY: ${{ matrix.binaries }}
|
||||||
SDE: ${{ matrix.config.sde }}
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix: ${{ fromJson(inputs.matrix) }}
|
matrix: ${{ fromJson(inputs.matrix) }}
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: ${{ matrix.config.shell }}
|
shell: bash
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -37,13 +34,6 @@ jobs:
|
|||||||
name: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
|
name: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
|
||||||
path: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
|
path: ${{ matrix.config.simple_name }} ${{ matrix.binaries }}
|
||||||
|
|
||||||
- name: Setup msys and install required packages
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
uses: msys2/setup-msys2@v2
|
|
||||||
with:
|
|
||||||
msystem: ${{ matrix.config.msys_sys }}
|
|
||||||
install: mingw-w64-${{ matrix.config.msys_env }} make git zip
|
|
||||||
|
|
||||||
- name: Create Package
|
- name: Create Package
|
||||||
run: |
|
run: |
|
||||||
mkdir stockfish
|
mkdir stockfish
|
||||||
@@ -69,13 +59,13 @@ jobs:
|
|||||||
cp CONTRIBUTING.md ../stockfish/
|
cp CONTRIBUTING.md ../stockfish/
|
||||||
|
|
||||||
- name: Create tar
|
- name: Create tar
|
||||||
if: runner.os != 'Windows'
|
if: ${{ !startsWith(matrix.config.os, 'windows') }}
|
||||||
run: |
|
run: |
|
||||||
chmod +x ./stockfish/stockfish-$NAME-$BINARY$EXT
|
chmod +x ./stockfish/stockfish-$NAME-$BINARY$EXT
|
||||||
tar -cvf stockfish-$NAME-$BINARY.tar stockfish
|
tar -cvf stockfish-$NAME-$BINARY.tar stockfish
|
||||||
|
|
||||||
- name: Create zip
|
- name: Create zip
|
||||||
if: runner.os == 'Windows'
|
if: ${{ startsWith(matrix.config.os, 'windows') }}
|
||||||
run: |
|
run: |
|
||||||
zip -r stockfish-$NAME-$BINARY.zip stockfish
|
zip -r stockfish-$NAME-$BINARY.zip stockfish
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ Andy Duplain
|
|||||||
Antoine Champion (antoinechampion)
|
Antoine Champion (antoinechampion)
|
||||||
Aram Tumanian (atumanian)
|
Aram Tumanian (atumanian)
|
||||||
Arjun Temurnikar
|
Arjun Temurnikar
|
||||||
|
Aron Petkovski (fury)
|
||||||
|
Arseniy Surkov (codedeliveryservice)
|
||||||
Artem Solopiy (EntityFX)
|
Artem Solopiy (EntityFX)
|
||||||
Auguste Pop
|
Auguste Pop
|
||||||
Balazs Szilagyi
|
Balazs Szilagyi
|
||||||
@@ -56,10 +58,11 @@ Ciekce
|
|||||||
clefrks
|
clefrks
|
||||||
Clemens L. (rn5f107s2)
|
Clemens L. (rn5f107s2)
|
||||||
Cody Ho (aesrentai)
|
Cody Ho (aesrentai)
|
||||||
|
CSTENTOR
|
||||||
Dale Weiler (graphitemaster)
|
Dale Weiler (graphitemaster)
|
||||||
Daniel Axtens (daxtens)
|
Daniel Axtens (daxtens)
|
||||||
Daniel Dugovic (ddugovic)
|
Daniel Dugovic (ddugovic)
|
||||||
Daniel Monroe (Ergodice)
|
Daniel Monroe (daniel-monroe)
|
||||||
Daniel Samek (DanSamek)
|
Daniel Samek (DanSamek)
|
||||||
Dan Schmidt (dfannius)
|
Dan Schmidt (dfannius)
|
||||||
Dariusz Orzechowski (dorzechowski)
|
Dariusz Orzechowski (dorzechowski)
|
||||||
@@ -123,6 +126,7 @@ Jonathan McDermid (jonathanmcdermid)
|
|||||||
Joost VandeVondele (vondele)
|
Joost VandeVondele (vondele)
|
||||||
Joseph Ellis (jhellis3)
|
Joseph Ellis (jhellis3)
|
||||||
Joseph R. Prostko
|
Joseph R. Prostko
|
||||||
|
Jost Triller (tsoj)
|
||||||
Jörg Oster (joergoster)
|
Jörg Oster (joergoster)
|
||||||
Julian Willemer (NightlyKing)
|
Julian Willemer (NightlyKing)
|
||||||
jundery
|
jundery
|
||||||
@@ -130,6 +134,7 @@ Justin Blanchard (UncombedCoconut)
|
|||||||
Kelly Wilson
|
Kelly Wilson
|
||||||
Ken Takusagawa
|
Ken Takusagawa
|
||||||
Kenneth Lee (kennethlee33)
|
Kenneth Lee (kennethlee33)
|
||||||
|
kevlu8
|
||||||
Kian E (KJE-98)
|
Kian E (KJE-98)
|
||||||
kinderchocolate
|
kinderchocolate
|
||||||
Kiran Panditrao (Krgp)
|
Kiran Panditrao (Krgp)
|
||||||
@@ -178,6 +183,7 @@ Nathan Rugg (nmrugg)
|
|||||||
Nguyen Pham (nguyenpham)
|
Nguyen Pham (nguyenpham)
|
||||||
Nicklas Persson (NicklasPersson)
|
Nicklas Persson (NicklasPersson)
|
||||||
Nick Pelling (nickpelling)
|
Nick Pelling (nickpelling)
|
||||||
|
Nicolas Duhamel (nikloskoda)
|
||||||
Niklas Fiekas (niklasf)
|
Niklas Fiekas (niklasf)
|
||||||
Nikolay Kostov (NikolayIT)
|
Nikolay Kostov (NikolayIT)
|
||||||
Norman Schmidt (FireFather)
|
Norman Schmidt (FireFather)
|
||||||
@@ -211,6 +217,7 @@ Ronald de Man (syzygy1, syzygy)
|
|||||||
Ron Britvich (Britvich)
|
Ron Britvich (Britvich)
|
||||||
rqs
|
rqs
|
||||||
Rui Coelho (ruicoelhopedro)
|
Rui Coelho (ruicoelhopedro)
|
||||||
|
rustam-cpp
|
||||||
Ryan Schmitt
|
Ryan Schmitt
|
||||||
Ryan Takker
|
Ryan Takker
|
||||||
Sami Kiminki (skiminki)
|
Sami Kiminki (skiminki)
|
||||||
@@ -230,12 +237,15 @@ Stefano Di Martino (StefanoD)
|
|||||||
Steinar Gunderson (sesse)
|
Steinar Gunderson (sesse)
|
||||||
Stéphane Nicolet (snicolet)
|
Stéphane Nicolet (snicolet)
|
||||||
Stephen Touset (stouset)
|
Stephen Touset (stouset)
|
||||||
|
Stockfisher69
|
||||||
|
Styx (styxdoto)
|
||||||
Syine Mineta (MinetaS)
|
Syine Mineta (MinetaS)
|
||||||
Taras Vuk (TarasVuk)
|
Taras Vuk (TarasVuk)
|
||||||
Thanar2
|
Thanar2
|
||||||
thaspel
|
thaspel
|
||||||
theo77186
|
theo77186
|
||||||
TierynnB
|
TierynnB
|
||||||
|
Timothy Herchen (anematode)
|
||||||
Ting-Hsuan Huang (fffelix-huang)
|
Ting-Hsuan Huang (fffelix-huang)
|
||||||
Tobias Steinmann
|
Tobias Steinmann
|
||||||
Tomasz Sobczyk (Sopel97)
|
Tomasz Sobczyk (Sopel97)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ set_arch_loongarch64() {
|
|||||||
if check_flags 'lasx'; then
|
if check_flags 'lasx'; then
|
||||||
true_arch='loongarch64-lasx'
|
true_arch='loongarch64-lasx'
|
||||||
elif check_flags 'lsx'; then
|
elif check_flags 'lsx'; then
|
||||||
true_arch='lonngarch64-lsx'
|
true_arch='loongarch64-lsx'
|
||||||
else
|
else
|
||||||
true_arch='loongarch64'
|
true_arch='loongarch64'
|
||||||
fi
|
fi
|
||||||
@@ -42,9 +42,11 @@ set_arch_x86_64() {
|
|||||||
if check_flags 'avx512f' 'avx512cd' 'avx512vl' 'avx512dq' 'avx512bw' 'avx512ifma' 'avx512vbmi' 'avx512vbmi2' 'avx512vpopcntdq' 'avx512bitalg' 'avx512vnni' 'vpclmulqdq' 'gfni' 'vaes'; then
|
if check_flags 'avx512f' 'avx512cd' 'avx512vl' 'avx512dq' 'avx512bw' 'avx512ifma' 'avx512vbmi' 'avx512vbmi2' 'avx512vpopcntdq' 'avx512bitalg' 'avx512vnni' 'vpclmulqdq' 'gfni' 'vaes'; then
|
||||||
true_arch='x86-64-avx512icl'
|
true_arch='x86-64-avx512icl'
|
||||||
elif check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then
|
elif check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then
|
||||||
true_arch='x86-64-vnni256'
|
true_arch='x86-64-vnni512'
|
||||||
elif check_flags 'avx512f' 'avx512bw'; then
|
elif check_flags 'avx512f' 'avx512bw'; then
|
||||||
true_arch='x86-64-avx512'
|
true_arch='x86-64-avx512'
|
||||||
|
elif check_flags 'avxvnni'; then
|
||||||
|
true_arch='x86-64-avxvnni'
|
||||||
elif [ -z "${znver_1_2+1}" ] && check_flags 'bmi2'; then
|
elif [ -z "${znver_1_2+1}" ] && check_flags 'bmi2'; then
|
||||||
true_arch='x86-64-bmi2'
|
true_arch='x86-64-bmi2'
|
||||||
elif check_flags 'avx2'; then
|
elif check_flags 'avx2'; then
|
||||||
@@ -57,7 +59,7 @@ set_arch_x86_64() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_arch_ppc_64() {
|
set_arch_ppc_64() {
|
||||||
if $(grep -q -w "altivec" /proc/cpuinfo); then
|
if grep -q -w "altivec" /proc/cpuinfo; then
|
||||||
power=$(grep -oP -m 1 'cpu\t+: POWER\K\d+' /proc/cpuinfo)
|
power=$(grep -oP -m 1 'cpu\t+: POWER\K\d+' /proc/cpuinfo)
|
||||||
if [ "0$power" -gt 7 ]; then
|
if [ "0$power" -gt 7 ]; then
|
||||||
# VSX started with POWER8
|
# VSX started with POWER8
|
||||||
@@ -83,7 +85,7 @@ case $uname_s in
|
|||||||
'x86_64')
|
'x86_64')
|
||||||
flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.')
|
flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.')
|
||||||
set_arch_x86_64
|
set_arch_x86_64
|
||||||
if [ "$true_arch" = 'x86-64-vnni256' ] || [ "$true_arch" = 'x86-64-avx512' ]; then
|
if [ "$true_arch" = 'x86-64-avx512' ]; then
|
||||||
file_arch='x86-64-bmi2'
|
file_arch='x86-64-bmi2'
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|||||||
+8
-27
@@ -98,7 +98,6 @@ VPATH = syzygy:nnue:nnue/features
|
|||||||
# avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2
|
# avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2
|
||||||
# avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX
|
# avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX
|
||||||
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
|
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
|
||||||
# vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands
|
|
||||||
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
|
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
|
||||||
# avx512icl = yes/no --- ... multiple ... --- Use All AVX-512 features available on both Intel Ice Lake and AMD Zen 4
|
# avx512icl = yes/no --- ... multiple ... --- Use All AVX-512 features available on both Intel Ice Lake and AMD Zen 4
|
||||||
# altivec = yes/no --- -maltivec --- Use PowerPC Altivec SIMD extension
|
# altivec = yes/no --- -maltivec --- Use PowerPC Altivec SIMD extension
|
||||||
@@ -130,7 +129,7 @@ endif
|
|||||||
# explicitly check for the list of supported architectures (as listed with make help),
|
# explicitly check for the list of supported architectures (as listed with make help),
|
||||||
# the user can override with `make ARCH=x86-64-avx512icl SUPPORTED_ARCH=true`
|
# the user can override with `make ARCH=x86-64-avx512icl SUPPORTED_ARCH=true`
|
||||||
ifeq ($(ARCH), $(filter $(ARCH), \
|
ifeq ($(ARCH), $(filter $(ARCH), \
|
||||||
x86-64-avx512icl x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni \
|
x86-64-avx512icl x86-64-vnni512 x86-64-avx512 x86-64-avxvnni \
|
||||||
x86-64-bmi2 x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
|
x86-64-bmi2 x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
|
||||||
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-64-altivec ppc-64-vsx ppc-32 e2k \
|
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-64-altivec ppc-64-vsx ppc-32 e2k \
|
||||||
armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 \
|
armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 \
|
||||||
@@ -155,7 +154,6 @@ sse41 = no
|
|||||||
avx2 = no
|
avx2 = no
|
||||||
avxvnni = no
|
avxvnni = no
|
||||||
avx512 = no
|
avx512 = no
|
||||||
vnni256 = no
|
|
||||||
vnni512 = no
|
vnni512 = no
|
||||||
avx512icl = no
|
avx512icl = no
|
||||||
altivec = no
|
altivec = no
|
||||||
@@ -272,17 +270,6 @@ ifeq ($(findstring -avx512,$(ARCH)),-avx512)
|
|||||||
avx512 = yes
|
avx512 = yes
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(findstring -vnni256,$(ARCH)),-vnni256)
|
|
||||||
popcnt = yes
|
|
||||||
sse = yes
|
|
||||||
sse2 = yes
|
|
||||||
ssse3 = yes
|
|
||||||
sse41 = yes
|
|
||||||
avx2 = yes
|
|
||||||
pext = yes
|
|
||||||
vnni256 = yes
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(findstring -vnni512,$(ARCH)),-vnni512)
|
ifeq ($(findstring -vnni512,$(ARCH)),-vnni512)
|
||||||
popcnt = yes
|
popcnt = yes
|
||||||
sse = yes
|
sse = yes
|
||||||
@@ -593,6 +580,10 @@ endif
|
|||||||
# Locate the version in the same directory as the compiler used,
|
# Locate the version in the same directory as the compiler used,
|
||||||
# with fallback to a generic one if it can't be located
|
# with fallback to a generic one if it can't be located
|
||||||
LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))llvm-profdata
|
LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))llvm-profdata
|
||||||
|
# for icx
|
||||||
|
ifeq ($(wildcard $(LLVM_PROFDATA)),)
|
||||||
|
LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))/compiler/llvm-profdata
|
||||||
|
endif
|
||||||
ifeq ($(wildcard $(LLVM_PROFDATA)),)
|
ifeq ($(wildcard $(LLVM_PROFDATA)),)
|
||||||
LLVM_PROFDATA := llvm-profdata
|
LLVM_PROFDATA := llvm-profdata
|
||||||
endif
|
endif
|
||||||
@@ -723,17 +714,10 @@ ifeq ($(avx512),yes)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(vnni256),yes)
|
|
||||||
CXXFLAGS += -DUSE_VNNI
|
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
|
||||||
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(vnni512),yes)
|
ifeq ($(vnni512),yes)
|
||||||
CXXFLAGS += -DUSE_VNNI
|
CXXFLAGS += -DUSE_VNNI
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=512
|
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -911,9 +895,8 @@ help:
|
|||||||
echo "Supported archs:" && \
|
echo "Supported archs:" && \
|
||||||
echo "" && \
|
echo "" && \
|
||||||
echo "native > select the best architecture for the host processor (default)" && \
|
echo "native > select the best architecture for the host processor (default)" && \
|
||||||
echo "x86-64-avx512icl > x86 64-bit with minimum avx512 support of Intel Ice Lane or AMD Zen 4" && \
|
echo "x86-64-avx512icl > x86 64-bit with minimum avx512 support of Intel Ice Lake or AMD Zen 4" && \
|
||||||
echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
|
echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \
|
||||||
echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \
|
|
||||||
echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
|
echo "x86-64-avx512 > x86 64-bit with avx512 support" && \
|
||||||
echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
|
echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \
|
||||||
echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
|
echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \
|
||||||
@@ -1058,7 +1041,6 @@ config-sanity: net
|
|||||||
echo "avx2: '$(avx2)'" && \
|
echo "avx2: '$(avx2)'" && \
|
||||||
echo "avxvnni: '$(avxvnni)'" && \
|
echo "avxvnni: '$(avxvnni)'" && \
|
||||||
echo "avx512: '$(avx512)'" && \
|
echo "avx512: '$(avx512)'" && \
|
||||||
echo "vnni256: '$(vnni256)'" && \
|
|
||||||
echo "vnni512: '$(vnni512)'" && \
|
echo "vnni512: '$(vnni512)'" && \
|
||||||
echo "avx512icl: '$(avx512icl)'" && \
|
echo "avx512icl: '$(avx512icl)'" && \
|
||||||
echo "altivec: '$(altivec)'" && \
|
echo "altivec: '$(altivec)'" && \
|
||||||
@@ -1096,7 +1078,6 @@ config-sanity: net
|
|||||||
(test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \
|
(test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \
|
||||||
(test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \
|
(test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \
|
||||||
(test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \
|
(test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \
|
||||||
(test "$(vnni256)" = "yes" || test "$(vnni256)" = "no") && \
|
|
||||||
(test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \
|
(test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \
|
||||||
(test "$(avx512icl)" = "yes" || test "$(avx512icl)" = "no") && \
|
(test "$(avx512icl)" = "yes" || test "$(avx512icl)" = "no") && \
|
||||||
(test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \
|
(test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \
|
||||||
@@ -1150,7 +1131,7 @@ icx-profile-make:
|
|||||||
all
|
all
|
||||||
|
|
||||||
icx-profile-use:
|
icx-profile-use:
|
||||||
$(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw
|
$(XCRUN) $(LLVM_PROFDATA) merge -output=stockfish.profdata *.profraw
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
||||||
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \
|
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \
|
||||||
EXTRALDFLAGS='-fprofile-use ' \
|
EXTRALDFLAGS='-fprofile-use ' \
|
||||||
|
|||||||
@@ -179,11 +179,6 @@ inline Bitboard between_bb(Square s1, Square s2) {
|
|||||||
return BetweenBB[s1][s2];
|
return BetweenBB[s1][s2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the squares s1, s2 and s3 are aligned either on a
|
|
||||||
// straight or on a diagonal line.
|
|
||||||
inline bool aligned(Square s1, Square s2, Square s3) { return line_bb(s1, s2) & s3; }
|
|
||||||
|
|
||||||
|
|
||||||
// distance() functions return the distance between x and y, defined as the
|
// distance() functions return the distance between x and y, defined as the
|
||||||
// number of steps for a king in x to reach y.
|
// number of steps for a king in x to reach y.
|
||||||
|
|
||||||
|
|||||||
+7
-10
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2
|
constexpr int PAWN_HISTORY_SIZE = 8192; // has to be a power of 2
|
||||||
constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2
|
||||||
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
|
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
|
||||||
constexpr int LOW_PLY_HISTORY_SIZE = 5;
|
constexpr int LOW_PLY_HISTORY_SIZE = 5;
|
||||||
@@ -44,14 +44,12 @@ static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0,
|
|||||||
static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0,
|
static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0,
|
||||||
"CORRECTION_HISTORY_SIZE has to be a power of 2");
|
"CORRECTION_HISTORY_SIZE has to be a power of 2");
|
||||||
|
|
||||||
enum PawnHistoryType {
|
inline int pawn_history_index(const Position& pos) {
|
||||||
Normal,
|
return pos.pawn_key() & (PAWN_HISTORY_SIZE - 1);
|
||||||
Correction
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<PawnHistoryType T = Normal>
|
inline int pawn_correction_history_index(const Position& pos) {
|
||||||
inline int pawn_structure_index(const Position& pos) {
|
return pos.pawn_key() & (CORRECTION_HISTORY_SIZE - 1);
|
||||||
return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int minor_piece_index(const Position& pos) {
|
inline int minor_piece_index(const Position& pos) {
|
||||||
@@ -103,7 +101,7 @@ using Stats = MultiArray<StatsEntry<T, D>, Sizes...>;
|
|||||||
// ButterflyHistory records how often quiet moves have been successful or unsuccessful
|
// ButterflyHistory records how often quiet moves have been successful or unsuccessful
|
||||||
// during the current search, and is used for reduction and move ordering decisions.
|
// during the current search, and is used for reduction and move ordering decisions.
|
||||||
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
|
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
|
||||||
// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo)
|
// see https://www.chessprogramming.org/Butterfly_Boards
|
||||||
using ButterflyHistory = Stats<std::int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
|
using ButterflyHistory = Stats<std::int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
|
||||||
|
|
||||||
// LowPlyHistory is adressed by play and move's from and to squares, used
|
// LowPlyHistory is adressed by play and move's from and to squares, used
|
||||||
@@ -120,7 +118,6 @@ using PieceToHistory = Stats<std::int16_t, 30000, PIECE_NB, SQUARE_NB>;
|
|||||||
// ContinuationHistory is the combined history of a given pair of moves, usually
|
// ContinuationHistory is the combined history of a given pair of moves, usually
|
||||||
// the current one given a previous one. The nested history table is based on
|
// the current one given a previous one. The nested history table is based on
|
||||||
// PieceToHistory instead of ButterflyBoards.
|
// PieceToHistory instead of ButterflyBoards.
|
||||||
// (~63 elo)
|
|
||||||
using ContinuationHistory = MultiArray<PieceToHistory, PIECE_NB, SQUARE_NB>;
|
using ContinuationHistory = MultiArray<PieceToHistory, PIECE_NB, SQUARE_NB>;
|
||||||
|
|
||||||
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
|
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ namespace {
|
|||||||
#if defined(USE_AVX512ICL)
|
#if defined(USE_AVX512ICL)
|
||||||
|
|
||||||
inline Move* write_moves(Move* moveList, uint32_t mask, __m512i vector) {
|
inline Move* write_moves(Move* moveList, uint32_t mask, __m512i vector) {
|
||||||
|
// Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4
|
||||||
_mm512_storeu_si512(reinterpret_cast<__m512i*>(moveList),
|
_mm512_storeu_si512(reinterpret_cast<__m512i*>(moveList),
|
||||||
_mm512_maskz_compress_epi16(mask, vector));
|
_mm512_maskz_compress_epi16(mask, vector));
|
||||||
return moveList + popcount(mask);
|
return moveList + popcount(mask);
|
||||||
|
|||||||
+10
-25
@@ -115,8 +115,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, int th, const CapturePieceTo
|
|||||||
threshold(th) {
|
threshold(th) {
|
||||||
assert(!pos.checkers());
|
assert(!pos.checkers());
|
||||||
|
|
||||||
stage = PROBCUT_TT
|
stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm));
|
||||||
+ !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assigns a numerical value to each move in a list, used for sorting.
|
// Assigns a numerical value to each move in a list, used for sorting.
|
||||||
@@ -129,13 +128,15 @@ ExtMove* MovePicker::score(MoveList<Type>& ml) {
|
|||||||
|
|
||||||
Color us = pos.side_to_move();
|
Color us = pos.side_to_move();
|
||||||
|
|
||||||
[[maybe_unused]] Bitboard threatByLesser[QUEEN + 1];
|
[[maybe_unused]] Bitboard threatByLesser[KING + 1];
|
||||||
if constexpr (Type == QUIETS)
|
if constexpr (Type == QUIETS)
|
||||||
{
|
{
|
||||||
|
threatByLesser[PAWN] = 0;
|
||||||
threatByLesser[KNIGHT] = threatByLesser[BISHOP] = pos.attacks_by<PAWN>(~us);
|
threatByLesser[KNIGHT] = threatByLesser[BISHOP] = pos.attacks_by<PAWN>(~us);
|
||||||
threatByLesser[ROOK] =
|
threatByLesser[ROOK] =
|
||||||
pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatByLesser[KNIGHT];
|
pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatByLesser[KNIGHT];
|
||||||
threatByLesser[QUEEN] = pos.attacks_by<ROOK>(~us) | threatByLesser[ROOK];
|
threatByLesser[QUEEN] = pos.attacks_by<ROOK>(~us) | threatByLesser[ROOK];
|
||||||
|
threatByLesser[KING] = pos.attacks_by<QUEEN>(~us) | threatByLesser[QUEEN];
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtMove* it = cur;
|
ExtMove* it = cur;
|
||||||
@@ -158,7 +159,7 @@ ExtMove* MovePicker::score(MoveList<Type>& ml) {
|
|||||||
{
|
{
|
||||||
// histories
|
// histories
|
||||||
m.value = 2 * (*mainHistory)[us][m.from_to()];
|
m.value = 2 * (*mainHistory)[us][m.from_to()];
|
||||||
m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to];
|
m.value += 2 * (*pawnHistory)[pawn_history_index(pos)][pc][to];
|
||||||
m.value += (*continuationHistory[0])[pc][to];
|
m.value += (*continuationHistory[0])[pc][to];
|
||||||
m.value += (*continuationHistory[1])[pc][to];
|
m.value += (*continuationHistory[1])[pc][to];
|
||||||
m.value += (*continuationHistory[2])[pc][to];
|
m.value += (*continuationHistory[2])[pc][to];
|
||||||
@@ -170,12 +171,10 @@ ExtMove* MovePicker::score(MoveList<Type>& ml) {
|
|||||||
|
|
||||||
// penalty for moving to a square threatened by a lesser piece
|
// penalty for moving to a square threatened by a lesser piece
|
||||||
// or bonus for escaping an attack by a lesser piece.
|
// or bonus for escaping an attack by a lesser piece.
|
||||||
if (KNIGHT <= pt && pt <= QUEEN)
|
static constexpr int bonus[KING + 1] = {0, 0, 144, 144, 256, 517, 10000};
|
||||||
{
|
int v = threatByLesser[pt] & to ? -95 : 100 * bool(threatByLesser[pt] & from);
|
||||||
static constexpr int bonus[QUEEN + 1] = {0, 0, 144, 144, 256, 517};
|
m.value += bonus[pt] * v;
|
||||||
int v = threatByLesser[pt] & to ? -95 : 100 * bool(threatByLesser[pt] & from);
|
|
||||||
m.value += bonus[pt] * v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ply < LOW_PLY_HISTORY_SIZE)
|
if (ply < LOW_PLY_HISTORY_SIZE)
|
||||||
m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + ply);
|
m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + ply);
|
||||||
@@ -189,7 +188,7 @@ ExtMove* MovePicker::score(MoveList<Type>& ml) {
|
|||||||
{
|
{
|
||||||
m.value = (*mainHistory)[us][m.from_to()] + (*continuationHistory[0])[pc][to];
|
m.value = (*mainHistory)[us][m.from_to()] + (*continuationHistory[0])[pc][to];
|
||||||
if (ply < LOW_PLY_HISTORY_SIZE)
|
if (ply < LOW_PLY_HISTORY_SIZE)
|
||||||
m.value += 2 * (*lowPlyHistory)[ply][m.from_to()] / (1 + ply);
|
m.value += (*lowPlyHistory)[ply][m.from_to()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,18 +315,4 @@ top:
|
|||||||
|
|
||||||
void MovePicker::skip_quiet_moves() { skipQuiets = true; }
|
void MovePicker::skip_quiet_moves() { skipQuiets = true; }
|
||||||
|
|
||||||
// this function must be called after all quiet moves and captures have been generated
|
|
||||||
bool MovePicker::can_move_king_or_pawn() const {
|
|
||||||
// SEE negative captures shouldn't be returned in GOOD_CAPTURE stage
|
|
||||||
assert(stage > GOOD_CAPTURE && stage != EVASION_INIT);
|
|
||||||
|
|
||||||
for (const ExtMove* m = moves; m < endGenerated; ++m)
|
|
||||||
{
|
|
||||||
PieceType movedPieceType = type_of(pos.moved_piece(*m));
|
|
||||||
if ((movedPieceType == PAWN || movedPieceType == KING) && pos.legal(*m))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ class MovePicker {
|
|||||||
MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
|
MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
|
||||||
Move next_move();
|
Move next_move();
|
||||||
void skip_quiet_moves();
|
void skip_quiet_moves();
|
||||||
bool can_move_king_or_pawn() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Pred>
|
template<typename Pred>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
|
#define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -82,7 +83,37 @@ void find_nnz(const std::int32_t* RESTRICT input,
|
|||||||
std::uint16_t* RESTRICT out,
|
std::uint16_t* RESTRICT out,
|
||||||
IndexType& count_out) {
|
IndexType& count_out) {
|
||||||
|
|
||||||
#ifdef USE_AVX512
|
#if defined(USE_AVX512ICL)
|
||||||
|
|
||||||
|
constexpr IndexType SimdWidthIn = 16; // 512 bits / 32 bits
|
||||||
|
constexpr IndexType SimdWidthOut = 32; // 512 bits / 16 bits
|
||||||
|
constexpr IndexType NumChunks = InputDimensions / SimdWidthOut;
|
||||||
|
const __m512i increment = _mm512_set1_epi16(SimdWidthOut);
|
||||||
|
__m512i base = _mm512_set_epi16( // Same permute order as _mm512_packus_epi32()
|
||||||
|
31, 30, 29, 28, 15, 14, 13, 12, 27, 26, 25, 24, 11, 10, 9, 8, 23, 22, 21, 20, 7, 6, 5, 4, 19,
|
||||||
|
18, 17, 16, 3, 2, 1, 0);
|
||||||
|
|
||||||
|
IndexType count = 0;
|
||||||
|
for (IndexType i = 0; i < NumChunks; ++i)
|
||||||
|
{
|
||||||
|
const __m512i inputV0 = _mm512_load_si512(input + i * 2 * SimdWidthIn);
|
||||||
|
const __m512i inputV1 = _mm512_load_si512(input + i * 2 * SimdWidthIn + SimdWidthIn);
|
||||||
|
|
||||||
|
// Get a bitmask and gather non zero indices
|
||||||
|
const __m512i inputV01 = _mm512_packus_epi32(inputV0, inputV1);
|
||||||
|
const __mmask32 nnzMask = _mm512_test_epi16_mask(inputV01, inputV01);
|
||||||
|
|
||||||
|
// Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4
|
||||||
|
__m512i nnz = _mm512_maskz_compress_epi16(nnzMask, base);
|
||||||
|
_mm512_storeu_si512(out + count, nnz);
|
||||||
|
|
||||||
|
count += popcount(nnzMask);
|
||||||
|
base = _mm512_add_epi16(base, increment);
|
||||||
|
}
|
||||||
|
count_out = count;
|
||||||
|
|
||||||
|
#elif defined(USE_AVX512)
|
||||||
|
|
||||||
constexpr IndexType SimdWidth = 16; // 512 bits / 32 bits
|
constexpr IndexType SimdWidth = 16; // 512 bits / 32 bits
|
||||||
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
||||||
const __m512i increment = _mm512_set1_epi32(SimdWidth);
|
const __m512i increment = _mm512_set1_epi32(SimdWidth);
|
||||||
@@ -217,11 +248,13 @@ class AffineTransformSparseInput {
|
|||||||
#if defined(USE_AVX512)
|
#if defined(USE_AVX512)
|
||||||
using invec_t = __m512i;
|
using invec_t = __m512i;
|
||||||
using outvec_t = __m512i;
|
using outvec_t = __m512i;
|
||||||
|
#define vec_add_32 _mm512_add_epi32
|
||||||
#define vec_set_32 _mm512_set1_epi32
|
#define vec_set_32 _mm512_set1_epi32
|
||||||
#define vec_add_dpbusd_32 SIMD::m512_add_dpbusd_epi32
|
#define vec_add_dpbusd_32 SIMD::m512_add_dpbusd_epi32
|
||||||
#elif defined(USE_AVX2)
|
#elif defined(USE_AVX2)
|
||||||
using invec_t = __m256i;
|
using invec_t = __m256i;
|
||||||
using outvec_t = __m256i;
|
using outvec_t = __m256i;
|
||||||
|
#define vec_add_32 _mm256_add_epi32
|
||||||
#define vec_set_32 _mm256_set1_epi32
|
#define vec_set_32 _mm256_set1_epi32
|
||||||
#define vec_add_dpbusd_32 SIMD::m256_add_dpbusd_epi32
|
#define vec_add_dpbusd_32 SIMD::m256_add_dpbusd_epi32
|
||||||
#elif defined(USE_SSSE3)
|
#elif defined(USE_SSSE3)
|
||||||
@@ -240,12 +273,19 @@ class AffineTransformSparseInput {
|
|||||||
#define vec_set_32(a) vreinterpretq_s8_u32(vdupq_n_u32(a))
|
#define vec_set_32(a) vreinterpretq_s8_u32(vdupq_n_u32(a))
|
||||||
#define vec_add_dpbusd_32 SIMD::neon_m128_add_dpbusd_epi32
|
#define vec_add_dpbusd_32 SIMD::neon_m128_add_dpbusd_epi32
|
||||||
#endif
|
#endif
|
||||||
static constexpr IndexType OutputSimdWidth = sizeof(outvec_t) / sizeof(OutputType);
|
constexpr IndexType OutputSimdWidth = sizeof(outvec_t) / sizeof(OutputType);
|
||||||
|
|
||||||
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / ChunkSize;
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / ChunkSize;
|
||||||
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
|
constexpr IndexType NumAccums = OutputDimensions / OutputSimdWidth;
|
||||||
std::uint16_t nnz[NumChunks];
|
// If we're using high-latency dot product instructions, split the accumulators
|
||||||
IndexType count;
|
// to create 3 separate dependency chains and merge at the end
|
||||||
|
constexpr IndexType NumRegs =
|
||||||
|
#if defined(USE_VNNI)
|
||||||
|
3 * NumAccums;
|
||||||
|
#else
|
||||||
|
NumAccums;
|
||||||
|
#endif
|
||||||
|
std::uint16_t nnz[NumChunks];
|
||||||
|
IndexType count;
|
||||||
|
|
||||||
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
|
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
|
||||||
|
|
||||||
@@ -254,24 +294,61 @@ class AffineTransformSparseInput {
|
|||||||
|
|
||||||
const outvec_t* biasvec = reinterpret_cast<const outvec_t*>(biases);
|
const outvec_t* biasvec = reinterpret_cast<const outvec_t*>(biases);
|
||||||
outvec_t acc[NumRegs];
|
outvec_t acc[NumRegs];
|
||||||
for (IndexType k = 0; k < NumRegs; ++k)
|
for (IndexType k = 0; k < NumAccums; ++k)
|
||||||
acc[k] = biasvec[k];
|
acc[k] = biasvec[k];
|
||||||
|
|
||||||
for (IndexType j = 0; j < count; ++j)
|
const auto* start = nnz;
|
||||||
|
const auto* end = nnz + count;
|
||||||
|
|
||||||
|
// convince GCC to not do weird pointer arithmetic in the following loop
|
||||||
|
const std::int8_t* weights_cp = weights;
|
||||||
|
#if defined(USE_VNNI)
|
||||||
|
for (IndexType k = NumAccums; k < NumRegs; ++k)
|
||||||
|
acc[k] = vec_zero();
|
||||||
|
|
||||||
|
while (start < end - 2)
|
||||||
{
|
{
|
||||||
const auto i = nnz[j];
|
const std::ptrdiff_t i0 = *start++;
|
||||||
const invec_t in = vec_set_32(input32[i]);
|
const std::ptrdiff_t i1 = *start++;
|
||||||
const auto col =
|
const std::ptrdiff_t i2 = *start++;
|
||||||
reinterpret_cast<const invec_t*>(&weights[i * OutputDimensions * ChunkSize]);
|
const invec_t in0 = vec_set_32(input32[i0]);
|
||||||
for (IndexType k = 0; k < NumRegs; ++k)
|
const invec_t in1 = vec_set_32(input32[i1]);
|
||||||
|
const invec_t in2 = vec_set_32(input32[i2]);
|
||||||
|
const auto col0 =
|
||||||
|
reinterpret_cast<const invec_t*>(&weights_cp[i0 * OutputDimensions * ChunkSize]);
|
||||||
|
const auto col1 =
|
||||||
|
reinterpret_cast<const invec_t*>(&weights_cp[i1 * OutputDimensions * ChunkSize]);
|
||||||
|
const auto col2 =
|
||||||
|
reinterpret_cast<const invec_t*>(&weights_cp[i2 * OutputDimensions * ChunkSize]);
|
||||||
|
for (IndexType k = 0; k < NumAccums; ++k)
|
||||||
|
{
|
||||||
|
vec_add_dpbusd_32(acc[k], in0, col0[k]);
|
||||||
|
vec_add_dpbusd_32(acc[k + NumAccums], in1, col1[k]);
|
||||||
|
vec_add_dpbusd_32(acc[k + 2 * NumAccums], in2, col2[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (IndexType k = 0; k < NumAccums; ++k)
|
||||||
|
acc[k] = vec_add_32(vec_add_32(acc[k], acc[k + NumAccums]), acc[k + 2 * NumAccums]);
|
||||||
|
#endif
|
||||||
|
while (start < end)
|
||||||
|
{
|
||||||
|
const std::ptrdiff_t i = *start++;
|
||||||
|
const invec_t in = vec_set_32(input32[i]);
|
||||||
|
const auto col =
|
||||||
|
reinterpret_cast<const invec_t*>(&weights_cp[i * OutputDimensions * ChunkSize]);
|
||||||
|
for (IndexType k = 0; k < NumAccums; ++k)
|
||||||
vec_add_dpbusd_32(acc[k], in, col[k]);
|
vec_add_dpbusd_32(acc[k], in, col[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
outvec_t* outptr = reinterpret_cast<outvec_t*>(output);
|
outvec_t* outptr = reinterpret_cast<outvec_t*>(output);
|
||||||
for (IndexType k = 0; k < NumRegs; ++k)
|
for (IndexType k = 0; k < NumAccums; ++k)
|
||||||
outptr[k] = acc[k];
|
outptr[k] = acc[k];
|
||||||
|
|
||||||
#undef vec_set_32
|
#undef vec_set_32
|
||||||
#undef vec_add_dpbusd_32
|
#undef vec_add_dpbusd_32
|
||||||
|
#ifdef vec_add_32
|
||||||
|
#undef vec_add_32
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
// Use dense implementation for the other architectures.
|
// Use dense implementation for the other architectures.
|
||||||
affine_transform_non_ssse3<InputDimensions, PaddedInputDimensions, OutputDimensions>(
|
affine_transform_non_ssse3<InputDimensions, PaddedInputDimensions, OutputDimensions>(
|
||||||
|
|||||||
+3
-3
@@ -57,9 +57,9 @@ uint64_t perft(Position& pos, Depth depth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t perft(const std::string& fen, Depth depth, bool isChess960) {
|
inline uint64_t perft(const std::string& fen, Depth depth, bool isChess960) {
|
||||||
StateListPtr states(new std::deque<StateInfo>(1));
|
StateInfo st;
|
||||||
Position p;
|
Position p;
|
||||||
p.set(fen, isChess960, &states->back());
|
p.set(fen, isChess960, &st);
|
||||||
|
|
||||||
return perft<true>(p, depth);
|
return perft<true>(p, depth);
|
||||||
}
|
}
|
||||||
|
|||||||
+65
-16
@@ -79,7 +79,7 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) {
|
|||||||
for (Bitboard b = pos.checkers(); b;)
|
for (Bitboard b = pos.checkers(); b;)
|
||||||
os << UCIEngine::square(pop_lsb(b)) << " ";
|
os << UCIEngine::square(pop_lsb(b)) << " ";
|
||||||
|
|
||||||
if (int(Tablebases::MaxCardinality) >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
|
if (Tablebases::MaxCardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
|
||||||
{
|
{
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
|
|
||||||
@@ -717,6 +717,8 @@ DirtyPiece Position::do_move(Move m,
|
|||||||
Piece pc = piece_on(from);
|
Piece pc = piece_on(from);
|
||||||
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
|
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
|
||||||
|
|
||||||
|
bool checkEP = false;
|
||||||
|
|
||||||
DirtyPiece dp;
|
DirtyPiece dp;
|
||||||
dp.pc = pc;
|
dp.pc = pc;
|
||||||
dp.from = from;
|
dp.from = from;
|
||||||
@@ -804,21 +806,14 @@ DirtyPiece Position::do_move(Move m,
|
|||||||
|
|
||||||
// Move the piece. The tricky Chess960 castling is handled earlier
|
// Move the piece. The tricky Chess960 castling is handled earlier
|
||||||
if (m.type_of() != CASTLING)
|
if (m.type_of() != CASTLING)
|
||||||
{
|
|
||||||
|
|
||||||
move_piece(from, to);
|
move_piece(from, to);
|
||||||
}
|
|
||||||
|
|
||||||
// If the moving piece is a pawn do some special extra work
|
// If the moving piece is a pawn do some special extra work
|
||||||
if (type_of(pc) == PAWN)
|
if (type_of(pc) == PAWN)
|
||||||
{
|
{
|
||||||
// Set en passant square if the moved pawn can be captured
|
// Check later if the en passant square needs to be set
|
||||||
if ((int(to) ^ int(from)) == 16
|
if ((int(to) ^ int(from)) == 16)
|
||||||
&& (attacks_bb<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
|
checkEP = true;
|
||||||
{
|
|
||||||
st->epSquare = to - pawn_push(us);
|
|
||||||
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (m.type_of() == PROMOTION)
|
else if (m.type_of() == PROMOTION)
|
||||||
{
|
{
|
||||||
@@ -863,11 +858,6 @@ DirtyPiece Position::do_move(Move m,
|
|||||||
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the key with the final value
|
|
||||||
st->key = k;
|
|
||||||
if (tt)
|
|
||||||
prefetch(tt->first_entry(key()));
|
|
||||||
|
|
||||||
// Set capture piece
|
// Set capture piece
|
||||||
st->capturedPiece = captured;
|
st->capturedPiece = captured;
|
||||||
|
|
||||||
@@ -879,6 +869,63 @@ DirtyPiece Position::do_move(Move m,
|
|||||||
// Update king attacks used for fast check detection
|
// Update king attacks used for fast check detection
|
||||||
set_check_info();
|
set_check_info();
|
||||||
|
|
||||||
|
// Accurate e.p. info is needed for correct zobrist key generation and 3-fold checking
|
||||||
|
while (checkEP)
|
||||||
|
{
|
||||||
|
auto updateEpSquare = [&] {
|
||||||
|
st->epSquare = to - pawn_push(us);
|
||||||
|
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitboard pawns = attacks_bb<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN);
|
||||||
|
|
||||||
|
// If there are no pawns attacking the ep square, ep is not possible
|
||||||
|
if (!pawns)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If there are checkers other than the to be captured pawn, ep is never legal
|
||||||
|
if (checkers() & ~square_bb(to))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (more_than_one(pawns))
|
||||||
|
{
|
||||||
|
// If there are two pawns potentially being abled to capture and at least one
|
||||||
|
// is not pinned, ep is legal as there are no horizontal exposed checks
|
||||||
|
if (!more_than_one(blockers_for_king(them) & pawns))
|
||||||
|
{
|
||||||
|
updateEpSquare();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no pawn on our king's file, and thus both pawns are pinned
|
||||||
|
// by bishops, ep is not legal as the king square must be in front of the to square.
|
||||||
|
// And because the ep square and the king are not on a common diagonal, either ep capture
|
||||||
|
// would expose the king to a check from one of the bishops
|
||||||
|
if (!(file_bb(square<KING>(them)) & pawns))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Otherwise remove the pawn on the king file, as an ep capture by it can never be legal and the
|
||||||
|
// check below relies on there only being one pawn
|
||||||
|
pawns &= ~file_bb(square<KING>(them));
|
||||||
|
}
|
||||||
|
|
||||||
|
Square ksq = square<KING>(them);
|
||||||
|
Square capsq = to;
|
||||||
|
Bitboard occupied = (pieces() ^ lsb(pawns) ^ capsq) | (to - pawn_push(us));
|
||||||
|
|
||||||
|
// If our king is not attacked after making the move, ep is legal.
|
||||||
|
if (!(attacks_bb<ROOK>(ksq, occupied) & pieces(us, QUEEN, ROOK))
|
||||||
|
&& !(attacks_bb<BISHOP>(ksq, occupied) & pieces(us, QUEEN, BISHOP)))
|
||||||
|
updateEpSquare();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the key with the final value
|
||||||
|
st->key = k;
|
||||||
|
if (tt)
|
||||||
|
prefetch(tt->first_entry(key()));
|
||||||
|
|
||||||
// Calculate the repetition info. It is the ply distance from the previous
|
// Calculate the repetition info. It is the ply distance from the previous
|
||||||
// occurrence of the same position, negative in the 3-fold case, or zero
|
// occurrence of the same position, negative in the 3-fold case, or zero
|
||||||
// if the position was not repeated.
|
// if the position was not repeated.
|
||||||
@@ -1058,6 +1105,8 @@ bool Position::see_ge(Move m, int threshold) const {
|
|||||||
|
|
||||||
Square from = m.from_sq(), to = m.to_sq();
|
Square from = m.from_sq(), to = m.to_sq();
|
||||||
|
|
||||||
|
assert(piece_on(from) != NO_PIECE);
|
||||||
|
|
||||||
int swap = PieceValue[piece_on(to)] - threshold;
|
int swap = PieceValue[piece_on(to)] - threshold;
|
||||||
if (swap < 0)
|
if (swap < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+6
-13
@@ -103,10 +103,9 @@ class Position {
|
|||||||
Square square(Color c) const;
|
Square square(Color c) const;
|
||||||
|
|
||||||
// Castling
|
// Castling
|
||||||
CastlingRights castling_rights(Color c) const;
|
bool can_castle(CastlingRights cr) const;
|
||||||
bool can_castle(CastlingRights cr) const;
|
bool castling_impeded(CastlingRights cr) const;
|
||||||
bool castling_impeded(CastlingRights cr) const;
|
Square castling_rook_square(CastlingRights cr) const;
|
||||||
Square castling_rook_square(CastlingRights cr) const;
|
|
||||||
|
|
||||||
// Checking
|
// Checking
|
||||||
Bitboard checkers() const;
|
Bitboard checkers() const;
|
||||||
@@ -184,8 +183,7 @@ class Position {
|
|||||||
Square& rfrom,
|
Square& rfrom,
|
||||||
Square& rto,
|
Square& rto,
|
||||||
DirtyPiece* const dp = nullptr);
|
DirtyPiece* const dp = nullptr);
|
||||||
template<bool AfterMove>
|
Key adjust_key50(Key k) const;
|
||||||
Key adjust_key50(Key k) const;
|
|
||||||
|
|
||||||
// Data members
|
// Data members
|
||||||
Piece board[SQUARE_NB];
|
Piece board[SQUARE_NB];
|
||||||
@@ -248,10 +246,6 @@ inline Square Position::ep_square() const { return st->epSquare; }
|
|||||||
|
|
||||||
inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; }
|
inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; }
|
||||||
|
|
||||||
inline CastlingRights Position::castling_rights(Color c) const {
|
|
||||||
return c & CastlingRights(st->castlingRights);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Position::castling_impeded(CastlingRights cr) const {
|
inline bool Position::castling_impeded(CastlingRights cr) const {
|
||||||
assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO);
|
assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO);
|
||||||
return pieces() & castlingPath[cr];
|
return pieces() & castlingPath[cr];
|
||||||
@@ -288,11 +282,10 @@ inline Bitboard Position::pinners(Color c) const { return st->pinners[c]; }
|
|||||||
|
|
||||||
inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; }
|
inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; }
|
||||||
|
|
||||||
inline Key Position::key() const { return adjust_key50<false>(st->key); }
|
inline Key Position::key() const { return adjust_key50(st->key); }
|
||||||
|
|
||||||
template<bool AfterMove>
|
|
||||||
inline Key Position::adjust_key50(Key k) const {
|
inline Key Position::adjust_key50(Key k) const {
|
||||||
return st->rule50 < 14 - AfterMove ? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8);
|
return st->rule50 < 14 ? k : k ^ make_key((st->rule50 - 14) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Key Position::pawn_key() const { return st->pawnKey; }
|
inline Key Position::pawn_key() const { return st->pawnKey; }
|
||||||
|
|||||||
+178
-205
@@ -73,18 +73,22 @@ using SearchedList = ValueList<Move, SEARCHEDLIST_CAPACITY>;
|
|||||||
// so changing them or adding conditions that are similar requires
|
// so changing them or adding conditions that are similar requires
|
||||||
// tests at these types of time controls.
|
// tests at these types of time controls.
|
||||||
|
|
||||||
|
// (*Scaler) All tuned parameters at time controls shorter than
|
||||||
|
// optimized for require verifications at longer time controls
|
||||||
|
|
||||||
int correction_value(const Worker& w, const Position& pos, const Stack* const ss) {
|
int correction_value(const Worker& w, const Position& pos, const Stack* const ss) {
|
||||||
const Color us = pos.side_to_move();
|
const Color us = pos.side_to_move();
|
||||||
const auto m = (ss - 1)->currentMove;
|
const auto m = (ss - 1)->currentMove;
|
||||||
const auto pcv = w.pawnCorrectionHistory[pawn_structure_index<Correction>(pos)][us];
|
const auto pcv = w.pawnCorrectionHistory[pawn_correction_history_index(pos)][us];
|
||||||
const auto micv = w.minorPieceCorrectionHistory[minor_piece_index(pos)][us];
|
const auto micv = w.minorPieceCorrectionHistory[minor_piece_index(pos)][us];
|
||||||
const auto wnpcv = w.nonPawnCorrectionHistory[non_pawn_index<WHITE>(pos)][WHITE][us];
|
const auto wnpcv = w.nonPawnCorrectionHistory[non_pawn_index<WHITE>(pos)][WHITE][us];
|
||||||
const auto bnpcv = w.nonPawnCorrectionHistory[non_pawn_index<BLACK>(pos)][BLACK][us];
|
const auto bnpcv = w.nonPawnCorrectionHistory[non_pawn_index<BLACK>(pos)][BLACK][us];
|
||||||
const auto cntcv =
|
const auto cntcv =
|
||||||
m.is_ok() ? (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()]
|
m.is_ok() ? (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()]
|
||||||
: 0;
|
+ (*(ss - 4)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()]
|
||||||
|
: 8;
|
||||||
|
|
||||||
return 7696 * pcv + 7689 * micv + 9708 * (wnpcv + bnpcv) + 6978 * cntcv;
|
return 9536 * pcv + 8494 * micv + 10132 * (wnpcv + bnpcv) + 7156 * cntcv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add correctionHistory value to raw staticEval and guarantee evaluation
|
// Add correctionHistory value to raw staticEval and guarantee evaluation
|
||||||
@@ -100,19 +104,22 @@ void update_correction_history(const Position& pos,
|
|||||||
const Move m = (ss - 1)->currentMove;
|
const Move m = (ss - 1)->currentMove;
|
||||||
const Color us = pos.side_to_move();
|
const Color us = pos.side_to_move();
|
||||||
|
|
||||||
static constexpr int nonPawnWeight = 172;
|
constexpr int nonPawnWeight = 165;
|
||||||
|
|
||||||
workerThread.pawnCorrectionHistory[pawn_structure_index<Correction>(pos)][us]
|
workerThread.pawnCorrectionHistory[pawn_correction_history_index(pos)][us] << bonus;
|
||||||
<< bonus * 111 / 128;
|
workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 145 / 128;
|
||||||
workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 151 / 128;
|
|
||||||
workerThread.nonPawnCorrectionHistory[non_pawn_index<WHITE>(pos)][WHITE][us]
|
workerThread.nonPawnCorrectionHistory[non_pawn_index<WHITE>(pos)][WHITE][us]
|
||||||
<< bonus * nonPawnWeight / 128;
|
<< bonus * nonPawnWeight / 128;
|
||||||
workerThread.nonPawnCorrectionHistory[non_pawn_index<BLACK>(pos)][BLACK][us]
|
workerThread.nonPawnCorrectionHistory[non_pawn_index<BLACK>(pos)][BLACK][us]
|
||||||
<< bonus * nonPawnWeight / 128;
|
<< bonus * nonPawnWeight / 128;
|
||||||
|
|
||||||
if (m.is_ok())
|
if (m.is_ok())
|
||||||
(*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()]
|
{
|
||||||
<< bonus * 141 / 128;
|
const Square to = m.to_sq();
|
||||||
|
const Piece pc = pos.piece_on(m.to_sq());
|
||||||
|
(*(ss - 2)->continuationCorrectionHistory)[pc][to] << bonus * 137 / 128;
|
||||||
|
(*(ss - 4)->continuationCorrectionHistory)[pc][to] << bonus * 64 / 128;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a small random component to draw evaluations to avoid 3-fold blindness
|
// Add a small random component to draw evaluations to avoid 3-fold blindness
|
||||||
@@ -131,8 +138,7 @@ void update_all_stats(const Position& pos,
|
|||||||
SearchedList& quietsSearched,
|
SearchedList& quietsSearched,
|
||||||
SearchedList& capturesSearched,
|
SearchedList& capturesSearched,
|
||||||
Depth depth,
|
Depth depth,
|
||||||
Move TTMove,
|
Move TTMove);
|
||||||
int moveCount);
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -330,7 +336,7 @@ void Search::Worker::iterative_deepening() {
|
|||||||
|
|
||||||
int searchAgainCounter = 0;
|
int searchAgainCounter = 0;
|
||||||
|
|
||||||
lowPlyHistory.fill(86);
|
lowPlyHistory.fill(97);
|
||||||
|
|
||||||
// Iterative deepening loop until requested to stop or the target depth is reached
|
// Iterative deepening loop until requested to stop or the target depth is reached
|
||||||
while (++rootDepth < MAX_PLY && !threads.stop
|
while (++rootDepth < MAX_PLY && !threads.stop
|
||||||
@@ -366,7 +372,7 @@ void Search::Worker::iterative_deepening() {
|
|||||||
selDepth = 0;
|
selDepth = 0;
|
||||||
|
|
||||||
// Reset aspiration window starting size
|
// Reset aspiration window starting size
|
||||||
delta = 5 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 11134;
|
delta = 5 + threadIdx % 8 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 9000;
|
||||||
Value avg = rootMoves[pvIdx].averageScore;
|
Value avg = rootMoves[pvIdx].averageScore;
|
||||||
alpha = std::max(avg - delta, -VALUE_INFINITE);
|
alpha = std::max(avg - delta, -VALUE_INFINITE);
|
||||||
beta = std::min(avg + delta, VALUE_INFINITE);
|
beta = std::min(avg + delta, VALUE_INFINITE);
|
||||||
@@ -416,7 +422,7 @@ void Search::Worker::iterative_deepening() {
|
|||||||
// otherwise exit the loop.
|
// otherwise exit the loop.
|
||||||
if (bestValue <= alpha)
|
if (bestValue <= alpha)
|
||||||
{
|
{
|
||||||
beta = (alpha + beta) / 2;
|
beta = alpha;
|
||||||
alpha = std::max(bestValue - delta, -VALUE_INFINITE);
|
alpha = std::max(bestValue - delta, -VALUE_INFINITE);
|
||||||
|
|
||||||
failedHighCnt = 0;
|
failedHighCnt = 0;
|
||||||
@@ -425,7 +431,8 @@ void Search::Worker::iterative_deepening() {
|
|||||||
}
|
}
|
||||||
else if (bestValue >= beta)
|
else if (bestValue >= beta)
|
||||||
{
|
{
|
||||||
beta = std::min(bestValue + delta, VALUE_INFINITE);
|
alpha = std::max(beta - delta, alpha);
|
||||||
|
beta = std::min(bestValue + delta, VALUE_INFINITE);
|
||||||
++failedHighCnt;
|
++failedHighCnt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -507,29 +514,29 @@ void Search::Worker::iterative_deepening() {
|
|||||||
rootMoves[0].effort * 100000 / std::max(size_t(1), size_t(nodes));
|
rootMoves[0].effort * 100000 / std::max(size_t(1), size_t(nodes));
|
||||||
|
|
||||||
double fallingEval =
|
double fallingEval =
|
||||||
(11.396 + 2.035 * (mainThread->bestPreviousAverageScore - bestValue)
|
(11.325 + 2.115 * (mainThread->bestPreviousAverageScore - bestValue)
|
||||||
+ 0.968 * (mainThread->iterValue[iterIdx] - bestValue))
|
+ 0.987 * (mainThread->iterValue[iterIdx] - bestValue))
|
||||||
/ 100.0;
|
/ 100.0;
|
||||||
fallingEval = std::clamp(fallingEval, 0.5786, 1.6752);
|
fallingEval = std::clamp(fallingEval, 0.5688, 1.5698);
|
||||||
|
|
||||||
// If the bestMove is stable over several iterations, reduce time accordingly
|
// If the bestMove is stable over several iterations, reduce time accordingly
|
||||||
double k = 0.527;
|
double k = 0.5189;
|
||||||
double center = lastBestMoveDepth + 11;
|
double center = lastBestMoveDepth + 11.57;
|
||||||
timeReduction = 0.8 + 0.84 / (1.077 + std::exp(-k * (completedDepth - center)));
|
timeReduction = 0.723 + 0.79 / (1.104 + std::exp(-k * (completedDepth - center)));
|
||||||
double reduction =
|
double reduction =
|
||||||
(1.4540 + mainThread->previousTimeReduction) / (2.1593 * timeReduction);
|
(1.455 + mainThread->previousTimeReduction) / (2.2375 * timeReduction);
|
||||||
double bestMoveInstability = 0.9929 + 1.8519 * totBestMoveChanges / threads.size();
|
double bestMoveInstability = 1.04 + 1.8956 * totBestMoveChanges / threads.size();
|
||||||
|
|
||||||
double totalTime =
|
double totalTime =
|
||||||
mainThread->tm.optimum() * fallingEval * reduction * bestMoveInstability;
|
mainThread->tm.optimum() * fallingEval * reduction * bestMoveInstability;
|
||||||
|
|
||||||
// Cap used time in case of a single legal move for a better viewer experience
|
// Cap used time in case of a single legal move for a better viewer experience
|
||||||
if (rootMoves.size() == 1)
|
if (rootMoves.size() == 1)
|
||||||
totalTime = std::min(500.0, totalTime);
|
totalTime = std::min(502.0, totalTime);
|
||||||
|
|
||||||
auto elapsedTime = elapsed();
|
auto elapsedTime = elapsed();
|
||||||
|
|
||||||
if (completedDepth >= 10 && nodesEffort >= 97056 && elapsedTime > totalTime * 0.6540
|
if (completedDepth >= 10 && nodesEffort >= 92425 && elapsedTime > totalTime * 0.666
|
||||||
&& !mainThread->ponder)
|
&& !mainThread->ponder)
|
||||||
threads.stop = true;
|
threads.stop = true;
|
||||||
|
|
||||||
@@ -544,7 +551,7 @@ void Search::Worker::iterative_deepening() {
|
|||||||
threads.stop = true;
|
threads.stop = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
threads.increaseDepth = mainThread->ponder || elapsedTime <= totalTime * 0.5138;
|
threads.increaseDepth = mainThread->ponder || elapsedTime <= totalTime * 0.503;
|
||||||
}
|
}
|
||||||
|
|
||||||
mainThread->iterValue[iterIdx] = bestValue;
|
mainThread->iterValue[iterIdx] = bestValue;
|
||||||
@@ -564,14 +571,22 @@ void Search::Worker::iterative_deepening() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st) {
|
void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, Stack* const ss) {
|
||||||
do_move(pos, move, st, pos.gives_check(move));
|
do_move(pos, move, st, pos.gives_check(move), ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck) {
|
void Search::Worker::do_move(
|
||||||
DirtyPiece dp = pos.do_move(move, st, givesCheck, &tt);
|
Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss) {
|
||||||
|
bool capture = pos.capture_stage(move);
|
||||||
|
DirtyPiece dp = pos.do_move(move, st, givesCheck, &tt);
|
||||||
nodes.fetch_add(1, std::memory_order_relaxed);
|
nodes.fetch_add(1, std::memory_order_relaxed);
|
||||||
accumulatorStack.push(dp);
|
accumulatorStack.push(dp);
|
||||||
|
if (ss != nullptr)
|
||||||
|
{
|
||||||
|
ss->currentMove = move;
|
||||||
|
ss->continuationHistory = &continuationHistory[ss->inCheck][capture][dp.pc][move.to_sq()];
|
||||||
|
ss->continuationCorrectionHistory = &continuationCorrectionHistory[dp.pc][move.to_sq()];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Search::Worker::do_null_move(Position& pos, StateInfo& st) { pos.do_null_move(st, tt); }
|
void Search::Worker::do_null_move(Position& pos, StateInfo& st) { pos.do_null_move(st, tt); }
|
||||||
@@ -586,9 +601,9 @@ void Search::Worker::undo_null_move(Position& pos) { pos.undo_null_move(); }
|
|||||||
|
|
||||||
// Reset histories, usually before a new game
|
// Reset histories, usually before a new game
|
||||||
void Search::Worker::clear() {
|
void Search::Worker::clear() {
|
||||||
mainHistory.fill(67);
|
mainHistory.fill(68);
|
||||||
captureHistory.fill(-688);
|
captureHistory.fill(-689);
|
||||||
pawnHistory.fill(-1287);
|
pawnHistory.fill(-1238);
|
||||||
pawnCorrectionHistory.fill(5);
|
pawnCorrectionHistory.fill(5);
|
||||||
minorPieceCorrectionHistory.fill(0);
|
minorPieceCorrectionHistory.fill(0);
|
||||||
nonPawnCorrectionHistory.fill(0);
|
nonPawnCorrectionHistory.fill(0);
|
||||||
@@ -603,10 +618,10 @@ void Search::Worker::clear() {
|
|||||||
for (StatsType c : {NoCaptures, Captures})
|
for (StatsType c : {NoCaptures, Captures})
|
||||||
for (auto& to : continuationHistory[inCheck][c])
|
for (auto& to : continuationHistory[inCheck][c])
|
||||||
for (auto& h : to)
|
for (auto& h : to)
|
||||||
h.fill(-473);
|
h.fill(-529);
|
||||||
|
|
||||||
for (size_t i = 1; i < reductions.size(); ++i)
|
for (size_t i = 1; i < reductions.size(); ++i)
|
||||||
reductions[i] = int(2796 / 128.0 * std::log(i));
|
reductions[i] = int(2809 / 128.0 * std::log(i));
|
||||||
|
|
||||||
refreshTable.clear(networks[numaAccessToken]);
|
refreshTable.clear(networks[numaAccessToken]);
|
||||||
}
|
}
|
||||||
@@ -623,10 +638,7 @@ Value Search::Worker::search(
|
|||||||
|
|
||||||
// Dive into quiescence search when the depth reaches zero
|
// Dive into quiescence search when the depth reaches zero
|
||||||
if (depth <= 0)
|
if (depth <= 0)
|
||||||
{
|
return qsearch<PvNode ? PV : NonPV>(pos, ss, alpha, beta);
|
||||||
constexpr auto nt = PvNode ? PV : NonPV;
|
|
||||||
return qsearch<nt>(pos, ss, alpha, beta);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit the depth if extensions made it too large
|
// Limit the depth if extensions made it too large
|
||||||
depth = std::min(depth, MAX_PLY - 1);
|
depth = std::min(depth, MAX_PLY - 1);
|
||||||
@@ -721,7 +733,10 @@ Value Search::Worker::search(
|
|||||||
if (!PvNode && !excludedMove && ttData.depth > depth - (ttData.value <= beta)
|
if (!PvNode && !excludedMove && ttData.depth > depth - (ttData.value <= beta)
|
||||||
&& is_valid(ttData.value) // Can happen when !ttHit or when access race in probe()
|
&& is_valid(ttData.value) // Can happen when !ttHit or when access race in probe()
|
||||||
&& (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER))
|
&& (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER))
|
||||||
&& (cutNode == (ttData.value >= beta) || depth > 5))
|
&& (cutNode == (ttData.value >= beta) || depth > 5)
|
||||||
|
// avoid a TT cutoff if the rule50 count is high and the TT move is zeroing
|
||||||
|
&& (depth > 8 || ttData.move == Move::none() || pos.rule50_count() < 80
|
||||||
|
|| (!ttCapture && type_of(pos.moved_piece(ttData.move)) != PAWN)))
|
||||||
{
|
{
|
||||||
// If ttMove is quiet, update move sorting heuristics on TT hit
|
// If ttMove is quiet, update move sorting heuristics on TT hit
|
||||||
if (ttData.move && ttData.value >= beta)
|
if (ttData.move && ttData.value >= beta)
|
||||||
@@ -729,24 +744,24 @@ Value Search::Worker::search(
|
|||||||
// Bonus for a quiet ttMove that fails high
|
// Bonus for a quiet ttMove that fails high
|
||||||
if (!ttCapture)
|
if (!ttCapture)
|
||||||
update_quiet_histories(pos, ss, *this, ttData.move,
|
update_quiet_histories(pos, ss, *this, ttData.move,
|
||||||
std::min(125 * depth - 77, 1157));
|
std::min(130 * depth - 71, 1043));
|
||||||
|
|
||||||
// Extra penalty for early quiet moves of the previous ply
|
// Extra penalty for early quiet moves of the previous ply
|
||||||
if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 3 && !priorCapture)
|
if (prevSq != SQ_NONE && (ss - 1)->moveCount < 4 && !priorCapture)
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -2301);
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -2142);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial workaround for the graph history interaction problem
|
// Partial workaround for the graph history interaction problem
|
||||||
// For high rule50 counts don't produce transposition table cutoffs.
|
// For high rule50 counts don't produce transposition table cutoffs.
|
||||||
if (pos.rule50_count() < 90)
|
if (pos.rule50_count() < 96)
|
||||||
{
|
{
|
||||||
if (depth >= 8 && ttData.move && pos.pseudo_legal(ttData.move) && pos.legal(ttData.move)
|
if (depth >= 8 && ttData.move && pos.pseudo_legal(ttData.move) && pos.legal(ttData.move)
|
||||||
&& !is_decisive(ttData.value))
|
&& !is_decisive(ttData.value))
|
||||||
{
|
{
|
||||||
do_move(pos, ttData.move, st);
|
pos.do_move(ttData.move, st);
|
||||||
Key nextPosKey = pos.key();
|
Key nextPosKey = pos.key();
|
||||||
auto [ttHitNext, ttDataNext, ttWriterNext] = tt.probe(nextPosKey);
|
auto [ttHitNext, ttDataNext, ttWriterNext] = tt.probe(nextPosKey);
|
||||||
undo_move(pos, ttData.move);
|
pos.undo_move(ttData.move);
|
||||||
|
|
||||||
// Check that the ttValue after the tt move would also trigger a cutoff
|
// Check that the ttValue after the tt move would also trigger a cutoff
|
||||||
if (!is_valid(ttDataNext.value))
|
if (!is_valid(ttDataNext.value))
|
||||||
@@ -849,61 +864,60 @@ Value Search::Worker::search(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use static evaluation difference to improve quiet move ordering
|
// Use static evaluation difference to improve quiet move ordering
|
||||||
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture && !ttHit)
|
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture)
|
||||||
{
|
{
|
||||||
int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1858, 1492) + 661;
|
int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -2023, 1563) + 583;
|
||||||
mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 1057 / 1024;
|
mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 944 / 1024;
|
||||||
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN
|
||||||
pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
&& ((ss - 1)->currentMove).type_of() != PROMOTION)
|
||||||
<< bonus * 1266 / 1024;
|
pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq]
|
||||||
|
<< bonus * 1438 / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the improving flag, which is true if current static evaluation is
|
// Set up the improving flag, which is true if current static evaluation is
|
||||||
// bigger than the previous static evaluation at our turn (if we were in
|
// bigger than the previous static evaluation at our turn (if we were in
|
||||||
// check at our previous move we go back until we weren't in check) and is
|
// check at our previous move we go back until we weren't in check) and is
|
||||||
// false otherwise. The improving flag is used in various pruning heuristics.
|
// false otherwise. The improving flag is used in various pruning heuristics.
|
||||||
improving = ss->staticEval > (ss - 2)->staticEval;
|
improving = ss->staticEval > (ss - 2)->staticEval;
|
||||||
|
|
||||||
opponentWorsening = ss->staticEval > -(ss - 1)->staticEval;
|
opponentWorsening = ss->staticEval > -(ss - 1)->staticEval;
|
||||||
|
|
||||||
if (priorReduction >= 3 && !opponentWorsening)
|
if (priorReduction >= 3 && !opponentWorsening)
|
||||||
depth++;
|
depth++;
|
||||||
if (priorReduction >= 1 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 175)
|
if (priorReduction >= 2 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 173)
|
||||||
depth--;
|
depth--;
|
||||||
|
|
||||||
// Step 7. Razoring
|
// Step 7. Razoring
|
||||||
// If eval is really low, skip search entirely and return the qsearch value.
|
// If eval is really low, skip search entirely and return the qsearch value.
|
||||||
// For PvNodes, we must have a guard against mates being returned.
|
// For PvNodes, we must have a guard against mates being returned.
|
||||||
if (!PvNode && eval < alpha - 486 - 325 * depth * depth)
|
if (!PvNode && eval < alpha - 514 - 294 * depth * depth)
|
||||||
return qsearch<NonPV>(pos, ss, alpha, beta);
|
return qsearch<NonPV>(pos, ss, alpha, beta);
|
||||||
|
|
||||||
// Step 8. Futility pruning: child node
|
// Step 8. Futility pruning: child node
|
||||||
// The depth condition is important for mate finding.
|
// The depth condition is important for mate finding.
|
||||||
{
|
{
|
||||||
auto futility_margin = [&](Depth d) {
|
auto futility_margin = [&](Depth d) {
|
||||||
Value futilityMult = 93 - 20 * (cutNode && !ss->ttHit);
|
Value futilityMult = 91 - 21 * !ss->ttHit;
|
||||||
|
|
||||||
return futilityMult * d //
|
return futilityMult * d //
|
||||||
- improving * futilityMult * 2 //
|
- 2094 * improving * futilityMult / 1024 //
|
||||||
- opponentWorsening * futilityMult / 3 //
|
- 1324 * opponentWorsening * futilityMult / 4096 //
|
||||||
+ (ss - 1)->statScore / 376 //
|
+ (ss - 1)->statScore / 331 //
|
||||||
+ std::abs(correctionValue) / 168639;
|
+ std::abs(correctionValue) / 158105;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!ss->ttPv && depth < 14 && eval - futility_margin(depth) >= beta && eval >= beta
|
if (!ss->ttPv && depth < 14 && eval - futility_margin(depth) >= beta && eval >= beta
|
||||||
&& (!ttData.move || ttCapture) && !is_loss(beta) && !is_win(eval))
|
&& (!ttData.move || ttCapture) && !is_loss(beta) && !is_win(eval))
|
||||||
return beta + (eval - beta) / 3;
|
return (2 * beta + eval) / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9. Null move search with verification search
|
// Step 9. Null move search with verification search
|
||||||
if (cutNode && (ss - 1)->currentMove != Move::null() && eval >= beta
|
if (cutNode && ss->staticEval >= beta - 18 * depth + 390 && !excludedMove
|
||||||
&& ss->staticEval >= beta - 19 * depth + 389 && !excludedMove && pos.non_pawn_material(us)
|
&& pos.non_pawn_material(us) && ss->ply >= nmpMinPly && !is_loss(beta))
|
||||||
&& ss->ply >= nmpMinPly && !is_loss(beta))
|
|
||||||
{
|
{
|
||||||
assert(eval - beta >= 0);
|
assert((ss - 1)->currentMove != Move::null());
|
||||||
|
|
||||||
// Null move dynamic reduction based on depth
|
// Null move dynamic reduction based on depth
|
||||||
Depth R = 7 + depth / 3;
|
Depth R = 6 + depth / 3;
|
||||||
|
|
||||||
ss->currentMove = Move::null();
|
ss->currentMove = Move::null();
|
||||||
ss->continuationHistory = &continuationHistory[0][0][NO_PIECE][0];
|
ss->continuationHistory = &continuationHistory[0][0][NO_PIECE][0];
|
||||||
@@ -936,18 +950,18 @@ Value Search::Worker::search(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
improving |= ss->staticEval >= beta + 94;
|
improving |= ss->staticEval >= beta;
|
||||||
|
|
||||||
// Step 10. Internal iterative reductions
|
// Step 10. Internal iterative reductions
|
||||||
// For PV nodes without a ttMove as well as for deep enough cutNodes, we decrease depth.
|
// At sufficient depth, reduce depth for PV/Cut nodes without a TTMove.
|
||||||
// (*Scaler) Especially if they make IIR less aggressive.
|
// (*Scaler) Especially if they make IIR less aggressive.
|
||||||
if (!allNode && depth >= 6 && !ttData.move)
|
if (!allNode && depth >= 6 && !ttData.move && priorReduction <= 3)
|
||||||
depth--;
|
depth--;
|
||||||
|
|
||||||
// Step 11. ProbCut
|
// Step 11. ProbCut
|
||||||
// If we have a good enough capture (or queen promotion) and a reduced search
|
// If we have a good enough capture (or queen promotion) and a reduced search
|
||||||
// returns a value much above beta, we can (almost) safely prune the previous move.
|
// returns a value much above beta, we can (almost) safely prune the previous move.
|
||||||
probCutBeta = beta + 201 - 58 * improving;
|
probCutBeta = beta + 224 - 64 * improving;
|
||||||
if (depth >= 3
|
if (depth >= 3
|
||||||
&& !is_decisive(beta)
|
&& !is_decisive(beta)
|
||||||
// If value from transposition table is lower than probCutBeta, don't attempt
|
// If value from transposition table is lower than probCutBeta, don't attempt
|
||||||
@@ -957,7 +971,7 @@ Value Search::Worker::search(
|
|||||||
assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta);
|
assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta);
|
||||||
|
|
||||||
MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory);
|
MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory);
|
||||||
Depth probCutDepth = std::max(depth - 5, 0);
|
Depth probCutDepth = std::clamp(depth - 5 - (ss->staticEval - beta) / 306, 0, depth);
|
||||||
|
|
||||||
while ((move = mp.next_move()) != Move::none())
|
while ((move = mp.next_move()) != Move::none())
|
||||||
{
|
{
|
||||||
@@ -968,15 +982,7 @@ Value Search::Worker::search(
|
|||||||
|
|
||||||
assert(pos.capture_stage(move));
|
assert(pos.capture_stage(move));
|
||||||
|
|
||||||
movedPiece = pos.moved_piece(move);
|
do_move(pos, move, st, ss);
|
||||||
|
|
||||||
do_move(pos, move, st);
|
|
||||||
|
|
||||||
ss->currentMove = move;
|
|
||||||
ss->continuationHistory =
|
|
||||||
&continuationHistory[ss->inCheck][true][movedPiece][move.to_sq()];
|
|
||||||
ss->continuationCorrectionHistory =
|
|
||||||
&continuationCorrectionHistory[movedPiece][move.to_sq()];
|
|
||||||
|
|
||||||
// Perform a preliminary qsearch to verify that the move holds
|
// Perform a preliminary qsearch to verify that the move holds
|
||||||
value = -qsearch<NonPV>(pos, ss + 1, -probCutBeta, -probCutBeta + 1);
|
value = -qsearch<NonPV>(pos, ss + 1, -probCutBeta, -probCutBeta + 1);
|
||||||
@@ -1004,7 +1010,7 @@ Value Search::Worker::search(
|
|||||||
moves_loop: // When in check, search starts here
|
moves_loop: // When in check, search starts here
|
||||||
|
|
||||||
// Step 12. A small Probcut idea
|
// Step 12. A small Probcut idea
|
||||||
probCutBeta = beta + 400;
|
probCutBeta = beta + 418;
|
||||||
if ((ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 4 && ttData.value >= probCutBeta
|
if ((ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 4 && ttData.value >= probCutBeta
|
||||||
&& !is_decisive(beta) && is_valid(ttData.value) && !is_decisive(ttData.value))
|
&& !is_decisive(beta) && is_valid(ttData.value) && !is_decisive(ttData.value))
|
||||||
return probCutBeta;
|
return probCutBeta;
|
||||||
@@ -1055,8 +1061,6 @@ moves_loop: // When in check, search starts here
|
|||||||
movedPiece = pos.moved_piece(move);
|
movedPiece = pos.moved_piece(move);
|
||||||
givesCheck = pos.gives_check(move);
|
givesCheck = pos.gives_check(move);
|
||||||
|
|
||||||
(ss + 1)->quietMoveStreak = (!capture && !givesCheck) ? (ss->quietMoveStreak + 1) : 0;
|
|
||||||
|
|
||||||
// Calculate new depth for this move
|
// Calculate new depth for this move
|
||||||
newDepth = depth - 1;
|
newDepth = depth - 1;
|
||||||
|
|
||||||
@@ -1068,7 +1072,7 @@ moves_loop: // When in check, search starts here
|
|||||||
// Smaller or even negative value is better for short time controls
|
// Smaller or even negative value is better for short time controls
|
||||||
// Bigger value is better for long time controls
|
// Bigger value is better for long time controls
|
||||||
if (ss->ttPv)
|
if (ss->ttPv)
|
||||||
r += 968;
|
r += 946;
|
||||||
|
|
||||||
// Step 14. Pruning at shallow depth.
|
// Step 14. Pruning at shallow depth.
|
||||||
// Depth conditions are important for mate finding.
|
// Depth conditions are important for mate finding.
|
||||||
@@ -1087,52 +1091,44 @@ moves_loop: // When in check, search starts here
|
|||||||
int captHist = captureHistory[movedPiece][move.to_sq()][type_of(capturedPiece)];
|
int captHist = captureHistory[movedPiece][move.to_sq()][type_of(capturedPiece)];
|
||||||
|
|
||||||
// Futility pruning for captures
|
// Futility pruning for captures
|
||||||
if (!givesCheck && lmrDepth < 7 && !ss->inCheck)
|
if (!givesCheck && lmrDepth < 7)
|
||||||
{
|
{
|
||||||
Value futilityValue = ss->staticEval + 232 + 224 * lmrDepth
|
Value futilityValue = ss->staticEval + 231 + 211 * lmrDepth
|
||||||
+ PieceValue[capturedPiece] + 131 * captHist / 1024;
|
+ PieceValue[capturedPiece] + 130 * captHist / 1024;
|
||||||
|
|
||||||
if (futilityValue <= alpha)
|
if (futilityValue <= alpha)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEE based pruning for captures and checks
|
// SEE based pruning for captures and checks
|
||||||
int seeHist = std::clamp(captHist / 31, -137 * depth, 125 * depth);
|
// Avoid pruning sacrifices of our last piece for stalemate
|
||||||
if (!pos.see_ge(move, -158 * depth - seeHist))
|
int margin = std::max(157 * depth + captHist / 29, 0);
|
||||||
{
|
if ((alpha >= VALUE_DRAW || pos.non_pawn_material(us) != PieceValue[movedPiece])
|
||||||
bool mayStalemateTrap =
|
&& !pos.see_ge(move, -margin))
|
||||||
depth > 2 && alpha < 0 && pos.non_pawn_material(us) == PieceValue[movedPiece]
|
continue;
|
||||||
&& PieceValue[movedPiece] >= RookValue
|
|
||||||
// it can't be stalemate if we moved a piece adjacent to the king
|
|
||||||
&& !(attacks_bb<KING>(pos.square<KING>(us)) & move.from_sq())
|
|
||||||
&& !mp.can_move_king_or_pawn();
|
|
||||||
|
|
||||||
// avoid pruning sacrifices of our last piece for stalemate
|
|
||||||
if (!mayStalemateTrap)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int history = (*contHist[0])[movedPiece][move.to_sq()]
|
int history = (*contHist[0])[movedPiece][move.to_sq()]
|
||||||
+ (*contHist[1])[movedPiece][move.to_sq()]
|
+ (*contHist[1])[movedPiece][move.to_sq()]
|
||||||
+ pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()];
|
+ pawnHistory[pawn_history_index(pos)][movedPiece][move.to_sq()];
|
||||||
|
|
||||||
// Continuation history based pruning
|
// Continuation history based pruning
|
||||||
if (history < -4229 * depth)
|
if (history < -4312 * depth)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
history += 68 * mainHistory[us][move.from_to()] / 32;
|
history += 76 * mainHistory[us][move.from_to()] / 32;
|
||||||
|
|
||||||
lmrDepth += history / 3388;
|
// (*Scaler): Generally, a lower divisor scales well
|
||||||
|
lmrDepth += history / 3220;
|
||||||
|
|
||||||
Value baseFutility = (bestMove ? 46 : 230);
|
Value futilityValue = ss->staticEval + 47 + 171 * !bestMove + 134 * lmrDepth
|
||||||
Value futilityValue =
|
+ 90 * (ss->staticEval > alpha);
|
||||||
ss->staticEval + baseFutility + 117 * lmrDepth + 102 * (ss->staticEval > alpha);
|
|
||||||
|
|
||||||
// Futility pruning: parent node
|
// Futility pruning: parent node
|
||||||
// (*Scaler): Generally, more frequent futility pruning
|
// (*Scaler): Generally, more frequent futility pruning
|
||||||
// scales well with respect to time and threads
|
// scales well with respect to time and threads
|
||||||
if (!ss->inCheck && lmrDepth < 12 && futilityValue <= alpha)
|
if (!ss->inCheck && lmrDepth < 11 && futilityValue <= alpha)
|
||||||
{
|
{
|
||||||
if (bestValue <= futilityValue && !is_decisive(bestValue)
|
if (bestValue <= futilityValue && !is_decisive(bestValue)
|
||||||
&& !is_win(futilityValue))
|
&& !is_win(futilityValue))
|
||||||
@@ -1159,12 +1155,11 @@ moves_loop: // When in check, search starts here
|
|||||||
// (*Scaler) Generally, higher singularBeta (i.e closer to ttValue)
|
// (*Scaler) Generally, higher singularBeta (i.e closer to ttValue)
|
||||||
// and lower extension margins scale well.
|
// and lower extension margins scale well.
|
||||||
|
|
||||||
if (!rootNode && move == ttData.move && !excludedMove
|
if (!rootNode && move == ttData.move && !excludedMove && depth >= 6 + ss->ttPv
|
||||||
&& depth >= 6 - (completedDepth > 27) + ss->ttPv && is_valid(ttData.value)
|
&& is_valid(ttData.value) && !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER)
|
||||||
&& !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER)
|
|
||||||
&& ttData.depth >= depth - 3)
|
&& ttData.depth >= depth - 3)
|
||||||
{
|
{
|
||||||
Value singularBeta = ttData.value - (58 + 76 * (ss->ttPv && !PvNode)) * depth / 57;
|
Value singularBeta = ttData.value - (56 + 81 * (ss->ttPv && !PvNode)) * depth / 60;
|
||||||
Depth singularDepth = newDepth / 2;
|
Depth singularDepth = newDepth / 2;
|
||||||
|
|
||||||
ss->excludedMove = move;
|
ss->excludedMove = move;
|
||||||
@@ -1173,11 +1168,11 @@ moves_loop: // When in check, search starts here
|
|||||||
|
|
||||||
if (value < singularBeta)
|
if (value < singularBeta)
|
||||||
{
|
{
|
||||||
int corrValAdj = std::abs(correctionValue) / 248400;
|
int corrValAdj = std::abs(correctionValue) / 229958;
|
||||||
int doubleMargin = -4 + 244 * PvNode - 206 * !ttCapture - corrValAdj
|
int doubleMargin = -4 + 198 * PvNode - 212 * !ttCapture - corrValAdj
|
||||||
- 997 * ttMoveHistory / 131072 - (ss->ply > rootDepth) * 47;
|
- 921 * ttMoveHistory / 127649 - (ss->ply > rootDepth) * 45;
|
||||||
int tripleMargin = 84 + 269 * PvNode - 253 * !ttCapture + 91 * ss->ttPv - corrValAdj
|
int tripleMargin = 76 + 308 * PvNode - 250 * !ttCapture + 92 * ss->ttPv - corrValAdj
|
||||||
- (ss->ply * 2 > rootDepth * 3) * 54;
|
- (ss->ply * 2 > rootDepth * 3) * 52;
|
||||||
|
|
||||||
extension =
|
extension =
|
||||||
1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin);
|
1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin);
|
||||||
@@ -1192,7 +1187,10 @@ moves_loop: // When in check, search starts here
|
|||||||
// singular (multiple moves fail high), and we can prune the whole
|
// singular (multiple moves fail high), and we can prune the whole
|
||||||
// subtree by returning a softbound.
|
// subtree by returning a softbound.
|
||||||
else if (value >= beta && !is_decisive(value))
|
else if (value >= beta && !is_decisive(value))
|
||||||
|
{
|
||||||
|
ttMoveHistory << std::max(-400 - 100 * depth, -4000);
|
||||||
return value;
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// Negative extensions
|
// Negative extensions
|
||||||
// If other moves failed high over (ttValue - margin) without the
|
// If other moves failed high over (ttValue - margin) without the
|
||||||
@@ -1212,50 +1210,41 @@ moves_loop: // When in check, search starts here
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 16. Make the move
|
// Step 16. Make the move
|
||||||
do_move(pos, move, st, givesCheck);
|
do_move(pos, move, st, givesCheck, ss);
|
||||||
|
|
||||||
// Add extension to new depth
|
// Add extension to new depth
|
||||||
newDepth += extension;
|
newDepth += extension;
|
||||||
|
|
||||||
// Update the current move (this must be done after singular extension search)
|
|
||||||
ss->currentMove = move;
|
|
||||||
ss->continuationHistory =
|
|
||||||
&continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()];
|
|
||||||
ss->continuationCorrectionHistory =
|
|
||||||
&continuationCorrectionHistory[movedPiece][move.to_sq()];
|
|
||||||
uint64_t nodeCount = rootNode ? uint64_t(nodes) : 0;
|
uint64_t nodeCount = rootNode ? uint64_t(nodes) : 0;
|
||||||
|
|
||||||
// Decrease reduction for PvNodes (*Scaler)
|
// Decrease reduction for PvNodes (*Scaler)
|
||||||
if (ss->ttPv)
|
if (ss->ttPv)
|
||||||
r -= 2437 + PvNode * 926 + (ttData.value > alpha) * 901
|
r -= 2618 + PvNode * 991 + (ttData.value > alpha) * 903
|
||||||
+ (ttData.depth >= depth) * (943 + cutNode * 1180);
|
+ (ttData.depth >= depth) * (978 + cutNode * 1051);
|
||||||
|
|
||||||
// These reduction adjustments have no proven non-linear scaling
|
// These reduction adjustments have no proven non-linear scaling
|
||||||
|
|
||||||
r += 650; // Base reduction offset to compensate for other tweaks
|
r += 843; // Base reduction offset to compensate for other tweaks
|
||||||
r -= moveCount * 66;
|
r -= moveCount * 66;
|
||||||
r -= std::abs(correctionValue) / 28047;
|
r -= std::abs(correctionValue) / 30450;
|
||||||
|
|
||||||
// Increase reduction for cut nodes
|
// Increase reduction for cut nodes
|
||||||
if (cutNode)
|
if (cutNode)
|
||||||
r += 2864 + 966 * !ttData.move;
|
r += 3094 + 1056 * !ttData.move;
|
||||||
|
|
||||||
// Increase reduction if ttMove is a capture
|
// Increase reduction if ttMove is a capture
|
||||||
if (ttCapture)
|
if (ttCapture)
|
||||||
r += 1350;
|
r += 1415;
|
||||||
|
|
||||||
// Increase reduction if next ply has a lot of fail high
|
// Increase reduction if next ply has a lot of fail high
|
||||||
if ((ss + 1)->cutoffCnt > 2)
|
if ((ss + 1)->cutoffCnt > 2)
|
||||||
r += 1036 + allNode * 848;
|
r += 1051 + allNode * 814;
|
||||||
|
|
||||||
r += (ss + 1)->quietMoveStreak * 50;
|
|
||||||
|
|
||||||
// For first picked move (ttMove) reduce reduction
|
// For first picked move (ttMove) reduce reduction
|
||||||
if (move == ttData.move)
|
if (move == ttData.move)
|
||||||
r -= 2006;
|
r -= 2018;
|
||||||
|
|
||||||
if (capture)
|
if (capture)
|
||||||
ss->statScore = 826 * int(PieceValue[pos.captured_piece()]) / 128
|
ss->statScore = 803 * int(PieceValue[pos.captured_piece()]) / 128
|
||||||
+ captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())];
|
+ captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())];
|
||||||
else
|
else
|
||||||
ss->statScore = 2 * mainHistory[us][move.from_to()]
|
ss->statScore = 2 * mainHistory[us][move.from_to()]
|
||||||
@@ -1263,7 +1252,7 @@ moves_loop: // When in check, search starts here
|
|||||||
+ (*contHist[1])[movedPiece][move.to_sq()];
|
+ (*contHist[1])[movedPiece][move.to_sq()];
|
||||||
|
|
||||||
// Decrease/increase reduction for moves with a good/bad history
|
// Decrease/increase reduction for moves with a good/bad history
|
||||||
r -= ss->statScore * 826 / 8192;
|
r -= ss->statScore * 794 / 8192;
|
||||||
|
|
||||||
// Step 17. Late moves reduction / extension (LMR)
|
// Step 17. Late moves reduction / extension (LMR)
|
||||||
if (depth >= 2 && moveCount > 1)
|
if (depth >= 2 && moveCount > 1)
|
||||||
@@ -1273,9 +1262,7 @@ moves_loop: // When in check, search starts here
|
|||||||
// beyond the first move depth.
|
// beyond the first move depth.
|
||||||
// To prevent problems when the max value is less than the min value,
|
// To prevent problems when the max value is less than the min value,
|
||||||
// std::clamp has been replaced by a more robust implementation.
|
// std::clamp has been replaced by a more robust implementation.
|
||||||
Depth d = std::max(1, std::min(newDepth - r / 1024,
|
Depth d = std::max(1, std::min(newDepth - r / 1024, newDepth + 2)) + PvNode;
|
||||||
newDepth + !allNode + (PvNode && !bestMove)))
|
|
||||||
+ PvNode;
|
|
||||||
|
|
||||||
ss->reduction = newDepth - d;
|
ss->reduction = newDepth - d;
|
||||||
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, d, true);
|
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, d, true);
|
||||||
@@ -1284,11 +1271,11 @@ moves_loop: // When in check, search starts here
|
|||||||
// Do a full-depth search when reduced LMR search fails high
|
// Do a full-depth search when reduced LMR search fails high
|
||||||
// (*Scaler) Usually doing more shallower searches
|
// (*Scaler) Usually doing more shallower searches
|
||||||
// doesn't scale well to longer TCs
|
// doesn't scale well to longer TCs
|
||||||
if (value > alpha && d < newDepth)
|
if (value > alpha)
|
||||||
{
|
{
|
||||||
// Adjust full-depth search based on LMR results - if the result was
|
// Adjust full-depth search based on LMR results - if the result was
|
||||||
// good enough search deeper, if it was bad enough search shallower.
|
// good enough search deeper, if it was bad enough search shallower.
|
||||||
const bool doDeeperSearch = value > (bestValue + 42 + 2 * newDepth);
|
const bool doDeeperSearch = d < newDepth && value > (bestValue + 43 + 2 * newDepth);
|
||||||
const bool doShallowerSearch = value < bestValue + 9;
|
const bool doShallowerSearch = value < bestValue + 9;
|
||||||
|
|
||||||
newDepth += doDeeperSearch - doShallowerSearch;
|
newDepth += doDeeperSearch - doShallowerSearch;
|
||||||
@@ -1297,10 +1284,8 @@ moves_loop: // When in check, search starts here
|
|||||||
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode);
|
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode);
|
||||||
|
|
||||||
// Post LMR continuation history updates
|
// Post LMR continuation history updates
|
||||||
update_continuation_histories(ss, movedPiece, move.to_sq(), 1508);
|
update_continuation_histories(ss, movedPiece, move.to_sq(), 1365);
|
||||||
}
|
}
|
||||||
else if (value > alpha && value < bestValue + 9)
|
|
||||||
newDepth--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 18. Full-depth search when LMR is skipped
|
// Step 18. Full-depth search when LMR is skipped
|
||||||
@@ -1308,11 +1293,11 @@ moves_loop: // When in check, search starts here
|
|||||||
{
|
{
|
||||||
// Increase reduction if ttMove is not present
|
// Increase reduction if ttMove is not present
|
||||||
if (!ttData.move)
|
if (!ttData.move)
|
||||||
r += 1128;
|
r += 1118;
|
||||||
|
|
||||||
// Note that if expected reduction is high, we reduce search depth here
|
// Note that if expected reduction is high, we reduce search depth here
|
||||||
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha,
|
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha,
|
||||||
newDepth - (r > 3200) - (r > 4600 && newDepth > 2), !cutNode);
|
newDepth - (r > 3212) - (r > 4784 && newDepth > 2), !cutNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For PV nodes only, do a full PV search on the first move or after a fail high,
|
// For PV nodes only, do a full PV search on the first move or after a fail high,
|
||||||
@@ -1323,7 +1308,7 @@ moves_loop: // When in check, search starts here
|
|||||||
(ss + 1)->pv[0] = Move::none();
|
(ss + 1)->pv[0] = Move::none();
|
||||||
|
|
||||||
// Extend move from transposition table if we are about to dive into qsearch.
|
// Extend move from transposition table if we are about to dive into qsearch.
|
||||||
if (move == ttData.move && rootDepth > 8)
|
if (move == ttData.move && ttData.depth > 1 && rootDepth > 8)
|
||||||
newDepth = std::max(newDepth, 1);
|
newDepth = std::max(newDepth, 1);
|
||||||
|
|
||||||
value = -search<PV>(pos, ss + 1, -beta, -alpha, newDepth, false);
|
value = -search<PV>(pos, ss + 1, -beta, -alpha, newDepth, false);
|
||||||
@@ -1394,7 +1379,7 @@ moves_loop: // When in check, search starts here
|
|||||||
|
|
||||||
// In case we have an alternative move equal in eval to the current bestmove,
|
// In case we have an alternative move equal in eval to the current bestmove,
|
||||||
// promote it to bestmove by pretending it just exceeds alpha (but not beta).
|
// promote it to bestmove by pretending it just exceeds alpha (but not beta).
|
||||||
int inc = (value == bestValue && ss->ply + 2 >= rootDepth && (int(nodes) & 15) == 0
|
int inc = (value == bestValue && ss->ply + 2 >= rootDepth && (int(nodes) & 14) == 0
|
||||||
&& !is_win(std::abs(value) + 1));
|
&& !is_win(std::abs(value) + 1));
|
||||||
|
|
||||||
if (value + inc > bestValue)
|
if (value + inc > bestValue)
|
||||||
@@ -1410,14 +1395,14 @@ moves_loop: // When in check, search starts here
|
|||||||
|
|
||||||
if (value >= beta)
|
if (value >= beta)
|
||||||
{
|
{
|
||||||
// (* Scaler) Especially if they make cutoffCnt increment more often.
|
// (*Scaler) Especially if they make cutoffCnt increment more often.
|
||||||
ss->cutoffCnt += (extension < 2) || PvNode;
|
ss->cutoffCnt += (extension < 2) || PvNode;
|
||||||
assert(value >= beta); // Fail high
|
assert(value >= beta); // Fail high
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce other moves if we have found at least one score improvement
|
// Reduce other moves if we have found at least one score improvement
|
||||||
if (depth > 2 && depth < 16 && !is_decisive(value))
|
if (depth > 2 && depth < 14 && !is_decisive(value))
|
||||||
depth -= 2;
|
depth -= 2;
|
||||||
|
|
||||||
assert(depth > 0);
|
assert(depth > 0);
|
||||||
@@ -1455,33 +1440,33 @@ moves_loop: // When in check, search starts here
|
|||||||
else if (bestMove)
|
else if (bestMove)
|
||||||
{
|
{
|
||||||
update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth,
|
update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth,
|
||||||
ttData.move, moveCount);
|
ttData.move);
|
||||||
if (!PvNode)
|
if (!PvNode)
|
||||||
ttMoveHistory << (bestMove == ttData.move ? 800 : -879);
|
ttMoveHistory << (bestMove == ttData.move ? 809 : -865);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bonus for prior quiet countermove that caused the fail low
|
// Bonus for prior quiet countermove that caused the fail low
|
||||||
else if (!priorCapture && prevSq != SQ_NONE)
|
else if (!priorCapture && prevSq != SQ_NONE)
|
||||||
{
|
{
|
||||||
int bonusScale = -220;
|
int bonusScale = -228;
|
||||||
bonusScale += std::min(-(ss - 1)->statScore / 103, 323);
|
bonusScale -= (ss - 1)->statScore / 104;
|
||||||
bonusScale += std::min(73 * depth, 531);
|
bonusScale += std::min(63 * depth, 508);
|
||||||
bonusScale += 174 * ((ss - 1)->moveCount > 8);
|
bonusScale += 184 * ((ss - 1)->moveCount > 8);
|
||||||
bonusScale += 144 * (!ss->inCheck && bestValue <= ss->staticEval - 104);
|
bonusScale += 143 * (!ss->inCheck && bestValue <= ss->staticEval - 92);
|
||||||
bonusScale += 128 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 82);
|
bonusScale += 149 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 70);
|
||||||
|
|
||||||
bonusScale = std::max(bonusScale, 0);
|
bonusScale = std::max(bonusScale, 0);
|
||||||
|
|
||||||
const int scaledBonus = std::min(159 * depth - 94, 1501) * bonusScale;
|
const int scaledBonus = std::min(144 * depth - 92, 1365) * bonusScale;
|
||||||
|
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
||||||
scaledBonus * 412 / 32768);
|
scaledBonus * 400 / 32768);
|
||||||
|
|
||||||
mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 203 / 32768;
|
mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 220 / 32768;
|
||||||
|
|
||||||
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
||||||
pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq]
|
||||||
<< scaledBonus * 1040 / 32768;
|
<< scaledBonus * 1164 / 32768;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bonus for prior capture countermove that caused the fail low
|
// Bonus for prior capture countermove that caused the fail low
|
||||||
@@ -1489,7 +1474,7 @@ moves_loop: // When in check, search starts here
|
|||||||
{
|
{
|
||||||
Piece capturedPiece = pos.captured_piece();
|
Piece capturedPiece = pos.captured_piece();
|
||||||
assert(capturedPiece != NO_PIECE);
|
assert(capturedPiece != NO_PIECE);
|
||||||
captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 1080;
|
captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 964;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PvNode)
|
if (PvNode)
|
||||||
@@ -1516,9 +1501,11 @@ moves_loop: // When in check, search starts here
|
|||||||
&& ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high
|
&& ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high
|
||||||
|| (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low
|
|| (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low
|
||||||
{
|
{
|
||||||
auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8,
|
auto bonus =
|
||||||
-CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4);
|
std::clamp(int(bestValue - ss->staticEval) * depth / (8 + (bestValue > ss->staticEval)),
|
||||||
update_correction_history(pos, ss, *this, bonus);
|
-CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4);
|
||||||
|
update_correction_history(pos, ss, *this,
|
||||||
|
(1088 - 180 * (bestValue > ss->staticEval)) * bonus / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
||||||
@@ -1642,7 +1629,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
|||||||
if (bestValue > alpha)
|
if (bestValue > alpha)
|
||||||
alpha = bestValue;
|
alpha = bestValue;
|
||||||
|
|
||||||
futilityBase = ss->staticEval + 376;
|
futilityBase = ss->staticEval + 352;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory,
|
const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory,
|
||||||
@@ -1699,29 +1686,17 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continuation history based pruning
|
// Skip non-captures
|
||||||
if (!capture
|
if (!capture)
|
||||||
&& (*contHist[0])[pos.moved_piece(move)][move.to_sq()]
|
|
||||||
+ pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)][move.to_sq()]
|
|
||||||
<= 6218)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Do not search moves with bad enough SEE values
|
// Do not search moves with bad enough SEE values
|
||||||
if (!pos.see_ge(move, -74))
|
if (!pos.see_ge(move, -78))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7. Make and search the move
|
// Step 7. Make and search the move
|
||||||
Piece movedPiece = pos.moved_piece(move);
|
do_move(pos, move, st, givesCheck, ss);
|
||||||
|
|
||||||
do_move(pos, move, st, givesCheck);
|
|
||||||
|
|
||||||
// Update the current move
|
|
||||||
ss->currentMove = move;
|
|
||||||
ss->continuationHistory =
|
|
||||||
&continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()];
|
|
||||||
ss->continuationCorrectionHistory =
|
|
||||||
&continuationCorrectionHistory[movedPiece][move.to_sq()];
|
|
||||||
|
|
||||||
value = -qsearch<nodeType>(pos, ss + 1, -beta, -alpha);
|
value = -qsearch<nodeType>(pos, ss + 1, -beta, -alpha);
|
||||||
undo_move(pos, move);
|
undo_move(pos, move);
|
||||||
@@ -1789,7 +1764,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
|||||||
|
|
||||||
Depth Search::Worker::reduction(bool i, Depth d, int mn, int delta) const {
|
Depth Search::Worker::reduction(bool i, Depth d, int mn, int delta) const {
|
||||||
int reductionScale = reductions[d] * reductions[mn];
|
int reductionScale = reductions[d] * reductions[mn];
|
||||||
return reductionScale - delta * 794 / rootDelta + !i * reductionScale * 205 / 512 + 1086;
|
return reductionScale - delta * 757 / rootDelta + !i * reductionScale * 218 / 512 + 1200;
|
||||||
}
|
}
|
||||||
|
|
||||||
// elapsed() returns the time elapsed since the search started. If the
|
// elapsed() returns the time elapsed since the search started. If the
|
||||||
@@ -1878,42 +1853,41 @@ void update_all_stats(const Position& pos,
|
|||||||
SearchedList& quietsSearched,
|
SearchedList& quietsSearched,
|
||||||
SearchedList& capturesSearched,
|
SearchedList& capturesSearched,
|
||||||
Depth depth,
|
Depth depth,
|
||||||
Move ttMove,
|
Move ttMove) {
|
||||||
int moveCount) {
|
|
||||||
|
|
||||||
CapturePieceToHistory& captureHistory = workerThread.captureHistory;
|
CapturePieceToHistory& captureHistory = workerThread.captureHistory;
|
||||||
Piece movedPiece = pos.moved_piece(bestMove);
|
Piece movedPiece = pos.moved_piece(bestMove);
|
||||||
PieceType capturedPiece;
|
PieceType capturedPiece;
|
||||||
|
|
||||||
int bonus = std::min(143 * depth - 89, 1496) + 302 * (bestMove == ttMove);
|
int bonus = std::min(151 * depth - 91, 1730) + 302 * (bestMove == ttMove);
|
||||||
int malus = std::min(737 * depth - 179, 3141) - 30 * moveCount;
|
int malus = std::min(951 * depth - 156, 2468) - 30 * quietsSearched.size();
|
||||||
|
|
||||||
if (!pos.capture_stage(bestMove))
|
if (!pos.capture_stage(bestMove))
|
||||||
{
|
{
|
||||||
update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 1059 / 1024);
|
update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 957 / 1024);
|
||||||
|
|
||||||
// Decrease stats for all non-best quiet moves
|
// Decrease stats for all non-best quiet moves
|
||||||
for (Move move : quietsSearched)
|
for (Move move : quietsSearched)
|
||||||
update_quiet_histories(pos, ss, workerThread, move, -malus * 1310 / 1024);
|
update_quiet_histories(pos, ss, workerThread, move, -malus);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Increase stats for the best move in case it was a capture move
|
// Increase stats for the best move in case it was a capture move
|
||||||
capturedPiece = type_of(pos.piece_on(bestMove.to_sq()));
|
capturedPiece = type_of(pos.piece_on(bestMove.to_sq()));
|
||||||
captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus * 1213 / 1024;
|
captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra penalty for a quiet early move that was not a TT move in
|
// Extra penalty for a quiet early move that was not a TT move in
|
||||||
// previous ply when it gets refuted.
|
// previous ply when it gets refuted.
|
||||||
if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece())
|
if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece())
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 580 / 1024);
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 503 / 1024);
|
||||||
|
|
||||||
// Decrease stats for all non-best capture moves
|
// Decrease stats for all non-best capture moves
|
||||||
for (Move move : capturesSearched)
|
for (Move move : capturesSearched)
|
||||||
{
|
{
|
||||||
movedPiece = pos.moved_piece(move);
|
movedPiece = pos.moved_piece(move);
|
||||||
capturedPiece = type_of(pos.piece_on(move.to_sq()));
|
capturedPiece = type_of(pos.piece_on(move.to_sq()));
|
||||||
captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1388 / 1024;
|
captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1157 / 1024;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1922,7 +1896,7 @@ void update_all_stats(const Position& pos,
|
|||||||
// at ply -1, -2, -3, -4, and -6 with current move.
|
// at ply -1, -2, -3, -4, and -6 with current move.
|
||||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
||||||
static constexpr std::array<ConthistBonus, 6> conthist_bonuses = {
|
static constexpr std::array<ConthistBonus, 6> conthist_bonuses = {
|
||||||
{{1, 1092}, {2, 631}, {3, 294}, {4, 517}, {5, 126}, {6, 445}}};
|
{{1, 1157}, {2, 648}, {3, 288}, {4, 576}, {5, 140}, {6, 441}}};
|
||||||
|
|
||||||
for (const auto [i, weight] : conthist_bonuses)
|
for (const auto [i, weight] : conthist_bonuses)
|
||||||
{
|
{
|
||||||
@@ -1930,7 +1904,7 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
|||||||
if (ss->inCheck && i > 2)
|
if (ss->inCheck && i > 2)
|
||||||
break;
|
break;
|
||||||
if (((ss - i)->currentMove).is_ok())
|
if (((ss - i)->currentMove).is_ok())
|
||||||
(*(ss - i)->continuationHistory)[pc][to] << bonus * weight / 1024;
|
(*(ss - i)->continuationHistory)[pc][to] << (bonus * weight / 1024) + 88 * (i < 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1943,14 +1917,13 @@ void update_quiet_histories(
|
|||||||
workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort
|
workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort
|
||||||
|
|
||||||
if (ss->ply < LOW_PLY_HISTORY_SIZE)
|
if (ss->ply < LOW_PLY_HISTORY_SIZE)
|
||||||
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 792 / 1024;
|
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 761 / 1024;
|
||||||
|
|
||||||
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(),
|
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * 955 / 1024);
|
||||||
bonus * (bonus > 0 ? 1082 : 784) / 1024);
|
|
||||||
|
|
||||||
int pIndex = pawn_structure_index(pos);
|
int pIndex = pawn_history_index(pos);
|
||||||
workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()]
|
workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()]
|
||||||
<< bonus * (bonus > 0 ? 705 : 450) / 1024;
|
<< (bonus * (bonus > 0 ? 800 : 500) / 1024) + 70;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -77,7 +77,6 @@ struct Stack {
|
|||||||
bool ttHit;
|
bool ttHit;
|
||||||
int cutoffCnt;
|
int cutoffCnt;
|
||||||
int reduction;
|
int reduction;
|
||||||
int quietMoveStreak;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -331,8 +330,9 @@ class Worker {
|
|||||||
private:
|
private:
|
||||||
void iterative_deepening();
|
void iterative_deepening();
|
||||||
|
|
||||||
void do_move(Position& pos, const Move move, StateInfo& st);
|
void do_move(Position& pos, const Move move, StateInfo& st, Stack* const ss);
|
||||||
void do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck);
|
void
|
||||||
|
do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss);
|
||||||
void do_null_move(Position& pos, StateInfo& st);
|
void do_null_move(Position& pos, StateInfo& st);
|
||||||
void undo_move(Position& pos, const Move move);
|
void undo_move(Position& pos, const Move move);
|
||||||
void undo_null_move(Position& pos);
|
void undo_null_move(Position& pos);
|
||||||
|
|||||||
+10
-1
@@ -170,11 +170,20 @@ class Tune {
|
|||||||
static OptionsMap* options;
|
static OptionsMap* options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
constexpr void tune_check_args(Args&&...) {
|
||||||
|
static_assert((!std::is_fundamental_v<Args> && ...), "TUNE macro arguments wrong");
|
||||||
|
}
|
||||||
|
|
||||||
// Some macro magic :-) we define a dummy int variable that the compiler initializes calling Tune::add()
|
// Some macro magic :-) we define a dummy int variable that the compiler initializes calling Tune::add()
|
||||||
#define STRINGIFY(x) #x
|
#define STRINGIFY(x) #x
|
||||||
#define UNIQUE2(x, y) x##y
|
#define UNIQUE2(x, y) x##y
|
||||||
#define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__
|
#define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__
|
||||||
#define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__)
|
#define TUNE(...) \
|
||||||
|
int UNIQUE(p, __LINE__) = []() -> int { \
|
||||||
|
tune_check_args(__VA_ARGS__); \
|
||||||
|
return Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__); \
|
||||||
|
}();
|
||||||
|
|
||||||
#define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true
|
#define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -637,12 +637,12 @@ void UCIEngine::on_update_full(const Engine::InfoFull& info, bool showWDL) {
|
|||||||
<< " multipv " << info.multiPV //
|
<< " multipv " << info.multiPV //
|
||||||
<< " score " << format_score(info.score); //
|
<< " score " << format_score(info.score); //
|
||||||
|
|
||||||
if (showWDL)
|
|
||||||
ss << " wdl " << info.wdl;
|
|
||||||
|
|
||||||
if (!info.bound.empty())
|
if (!info.bound.empty())
|
||||||
ss << " " << info.bound;
|
ss << " " << info.bound;
|
||||||
|
|
||||||
|
if (showWDL)
|
||||||
|
ss << " wdl " << info.wdl;
|
||||||
|
|
||||||
ss << " nodes " << info.nodes //
|
ss << " nodes " << info.nodes //
|
||||||
<< " nps " << info.nps //
|
<< " nps " << info.nps //
|
||||||
<< " hashfull " << info.hashfull //
|
<< " hashfull " << info.hashfull //
|
||||||
|
|||||||
+3
-3
@@ -111,7 +111,7 @@ Option::Option(OnChange f) :
|
|||||||
max(0),
|
max(0),
|
||||||
on_change(std::move(f)) {}
|
on_change(std::move(f)) {}
|
||||||
|
|
||||||
Option::Option(double v, int minv, int maxv, OnChange f) :
|
Option::Option(int v, int minv, int maxv, OnChange f) :
|
||||||
type("spin"),
|
type("spin"),
|
||||||
min(minv),
|
min(minv),
|
||||||
max(maxv),
|
max(maxv),
|
||||||
@@ -155,7 +155,7 @@ Option& Option::operator=(const std::string& v) {
|
|||||||
|
|
||||||
if ((type != "button" && type != "string" && v.empty())
|
if ((type != "button" && type != "string" && v.empty())
|
||||||
|| (type == "check" && v != "true" && v != "false")
|
|| (type == "check" && v != "true" && v != "false")
|
||||||
|| (type == "spin" && (std::stof(v) < min || std::stof(v) > max)))
|
|| (type == "spin" && (std::stoi(v) < min || std::stoi(v) > max)))
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
if (type == "combo")
|
if (type == "combo")
|
||||||
@@ -203,7 +203,7 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (o.type == "spin")
|
else if (o.type == "spin")
|
||||||
os << " default " << int(stof(o.defaultValue)) << " min " << o.min << " max "
|
os << " default " << stoi(o.defaultValue) << " min " << o.min << " max "
|
||||||
<< o.max;
|
<< o.max;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ class Option {
|
|||||||
Option(OnChange = nullptr);
|
Option(OnChange = nullptr);
|
||||||
Option(bool v, OnChange = nullptr);
|
Option(bool v, OnChange = nullptr);
|
||||||
Option(const char* v, OnChange = nullptr);
|
Option(const char* v, OnChange = nullptr);
|
||||||
Option(double v, int minv, int maxv, OnChange = nullptr);
|
Option(int v, int minv, int maxv, OnChange = nullptr);
|
||||||
Option(const char* v, const char* cur, OnChange = nullptr);
|
Option(const char* v, const char* cur, OnChange = nullptr);
|
||||||
|
|
||||||
Option& operator=(const std::string&);
|
Option& operator=(const std::string&);
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ EXPECT_SCRIPT=$(mktemp)
|
|||||||
|
|
||||||
cat << 'EOF' > $EXPECT_SCRIPT
|
cat << 'EOF' > $EXPECT_SCRIPT
|
||||||
#!/usr/bin/expect -f
|
#!/usr/bin/expect -f
|
||||||
set timeout 30
|
set timeout 120
|
||||||
lassign [lrange $argv 0 4] pos depth result chess960 logfile
|
lassign [lrange $argv 0 4] pos depth result chess960 logfile
|
||||||
log_file -noappend $logfile
|
log_file -noappend $logfile
|
||||||
spawn ./stockfish
|
spawn ./stockfish
|
||||||
|
|||||||
Reference in New Issue
Block a user