--- /dev/null
+name: Report issue
+description: Create a report to help us fix issues with the engine
+body:
+- type: textarea
+ attributes:
+ label: Describe the issue
+ description: A clear and concise description of what you're experiencing.
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Expected behavior
+ description: A clear and concise description of what you expected to happen.
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Steps to reproduce
+ description: |
+ Steps to reproduce the behavior.
+ You can also use this section to paste the command line output.
+ placeholder: |
+ ```
+ position startpos moves g2g4 e7e5 f2f3
+ go mate 1
+ info string NNUE evaluation using nn-6877cd24400e.nnue enabled
+ info depth 1 seldepth 1 multipv 1 score mate 1 nodes 33 nps 11000 tbhits 0 time 3 pv d8h4
+ bestmove d8h4
+ ```
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Anything else?
+ description: |
+ Anything that will give us more context about the issue you are encountering.
+ You can also use this section to propose ideas on how to solve the issue.
+ validations:
+ required: false
+
+- type: dropdown
+ attributes:
+ label: Operating system
+ options:
+ - All
+ - Windows
+ - Linux
+ - MacOS
+ - Android
+ - Other or N/A
+ validations:
+ required: true
+
+- type: input
+ attributes:
+ label: Stockfish version
+ description: |
+ This can be found by running the engine.
+ You can also use the commit ID.
+ placeholder: Stockfish 15 / e6e324e
+ validations:
+ required: true
--- /dev/null
+blank_issues_enabled: false
+contact_links:
+ - name: Discord server
+ url: https://discord.gg/GWDRS3kU6R
+ about: Feel free to ask for support or have a chat with us in our Discord server!
+ - name: Discussions, Q&A, ideas, show us something...
+ url: https://github.com/official-stockfish/Stockfish/discussions/new
+ about: Do you have an idea for Stockfish? Do you want to show something that you made? Please open a discussion about it!
- master
- tools
jobs:
- Stockfish:
- name: ${{ matrix.config.name }}
- runs-on: ${{ matrix.config.os }}
- env:
- COMPILER: ${{ matrix.config.compiler }}
- COMP: ${{ matrix.config.comp }}
- CXXFLAGS: "-Werror"
- strategy:
- matrix:
- config:
- # set the variable for the required tests:
- # run_expensive_tests: true
- # run_32bit_tests: true
- # run_64bit_tests: true
- # run_armv8_tests: true
- # run_armv7_tests: true
- - {
- name: "Ubuntu 20.04 GCC",
- os: ubuntu-20.04,
- compiler: g++,
- comp: gcc,
- run_expensive_tests: true,
- run_32bit_tests: true,
- run_64bit_tests: true,
- shell: 'bash {0}'
- }
- - {
- name: "Ubuntu 20.04 Clang",
- os: ubuntu-20.04,
- compiler: clang++,
- comp: clang,
- run_32bit_tests: true,
- run_64bit_tests: true,
- shell: 'bash {0}'
- }
- - {
- name: "Ubuntu 20.04 NDK armv8",
- os: ubuntu-20.04,
- compiler: aarch64-linux-android21-clang++,
- comp: ndk,
- run_armv8_tests: false,
- shell: 'bash {0}'
- }
- - {
- name: "Ubuntu 20.04 NDK armv7",
- os: ubuntu-20.04,
- compiler: armv7a-linux-androideabi21-clang++,
- comp: ndk,
- run_armv7_tests: false,
- shell: 'bash {0}'
- }
- - {
- name: "MacOS 10.15 Apple Clang",
- os: macos-10.15,
- compiler: clang++,
- comp: clang,
- run_64bit_tests: true,
- shell: 'bash {0}'
- }
- - {
- name: "MacOS 10.15 GCC 10",
- os: macos-10.15,
- compiler: g++-10,
- comp: gcc,
- run_64bit_tests: true,
- shell: 'bash {0}'
- }
- - {
- name: "Windows 2022 Mingw-w64 GCC x86_64",
- os: windows-2022,
- compiler: g++,
- comp: mingw,
- run_64bit_tests: true,
- msys_sys: 'mingw64',
- msys_env: 'x86_64-gcc',
- shell: 'msys2 {0}'
- }
- - {
- name: "Windows 2022 Mingw-w64 GCC i686",
- os: windows-2022,
- compiler: g++,
- comp: mingw,
- run_32bit_tests: true,
- msys_sys: 'mingw32',
- msys_env: 'i686-gcc',
- shell: 'msys2 {0}'
- }
- - {
- name: "Windows 2022 Mingw-w64 Clang x86_64",
- os: windows-2022,
- compiler: clang++,
- comp: clang,
- run_64bit_tests: true,
- msys_sys: 'clang64',
- msys_env: 'clang-x86_64-clang',
- shell: 'msys2 {0}'
- }
-
- defaults:
- run:
- working-directory: src
- shell: ${{ matrix.config.shell }}
- steps:
- - uses: actions/checkout@v2
- with:
- fetch-depth: 0
-
- - name: Download required linux packages
- if: runner.os == 'Linux'
- run: |
- sudo apt update
- sudo apt install expect valgrind g++-multilib qemu-user
-
- - 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 expect
-
- - name: Download the used network from the fishtest framework
- run: |
- make net
-
- - name: Extract the bench number from the commit history
- run: |
- git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig
- [ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
-
- - name: Check compiler
- run: |
- export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
- $COMPILER -v
-
- - name: Test help target
- run: |
- make help
-
- # x86-32 tests
-
- - name: Test debug x86-32 build
- if: ${{ matrix.config.run_32bit_tests }}
- run: |
- export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
- make clean
- make -j2 ARCH=x86-32 optimize=no debug=yes build
- ../tests/signature.sh $benchref
-
- - name: Test x86-32 build
- if: ${{ matrix.config.run_32bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-32 build
- ../tests/signature.sh $benchref
-
- - name: Test x86-32-sse41-popcnt build
- if: ${{ matrix.config.run_32bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-32-sse41-popcnt build
- ../tests/signature.sh $benchref
-
- - name: Test x86-32-sse2 build
- if: ${{ matrix.config.run_32bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-32-sse2 build
- ../tests/signature.sh $benchref
-
- - name: Test general-32 build
- if: ${{ matrix.config.run_32bit_tests }}
- run: |
- make clean
- make -j2 ARCH=general-32 build
- ../tests/signature.sh $benchref
-
- # x86-64 tests
-
- - name: Test debug x86-64-modern build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
- make clean
- make -j2 ARCH=x86-64-modern optimize=no debug=yes build
- ../tests/signature.sh $benchref
-
- - name: Test x86-64-modern build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-modern build
- ../tests/signature.sh $benchref
-
- - name: Test x86-64-ssse3 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-ssse3 build
- ../tests/signature.sh $benchref
-
- - name: Test x86-64-sse3-popcnt build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-sse3-popcnt build
- ../tests/signature.sh $benchref
-
- - name: Test x86-64 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64 build
- ../tests/signature.sh $benchref
-
- - name: Test general-64 build
- if: matrix.config.run_64bit_tests
- run: |
- make clean
- make -j2 ARCH=general-64 build
- ../tests/signature.sh $benchref
-
- # x86-64 with newer extensions tests
-
- - name: Compile x86-64-avx2 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-avx2 build
-
- - name: Compile x86-64-bmi2 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-bmi2 build
-
- - name: Compile x86-64-avx512 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-avx512 build
-
- - name: Compile x86-64-vnni512 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-vnni512 build
-
- - name: Compile x86-64-vnni256 build
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-vnni256 build
-
- # armv8 tests
-
- - name: Test armv8 build
- if: ${{ matrix.config.run_armv8_tests }}
- run: |
- ANDROID_ROOT=/usr/local/lib/android
- ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
- SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
- echo "y" | $SDKMANAGER "ndk;21.4.7075529"
- ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
- ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
- export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
- export LDFLAGS="-static -Wno-unused-command-line-argument"
- make clean
- make -j2 ARCH=armv8 build
- ../tests/signature.sh $benchref
-
- # armv7 tests
-
- - name: Test armv7 build
- if: ${{ matrix.config.run_armv7_tests }}
- run: |
- ANDROID_ROOT=/usr/local/lib/android
- ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
- SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
- echo "y" | $SDKMANAGER "ndk;21.4.7075529"
- ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
- ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
- export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
- export LDFLAGS="-static -Wno-unused-command-line-argument"
- make clean
- make -j2 ARCH=armv7 build
- ../tests/signature.sh $benchref
-
- - name: Test armv7-neon build
- if: ${{ matrix.config.run_armv7_tests }}
- run: |
- ANDROID_ROOT=/usr/local/lib/android
- ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
- SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
- echo "y" | $SDKMANAGER "ndk;21.4.7075529"
- ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
- ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
- export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
- export LDFLAGS="-static -Wno-unused-command-line-argument"
- make clean
- make -j2 ARCH=armv7-neon build
- ../tests/signature.sh $benchref
-
- # Other tests
-
- - name: Check perft and search reproducibility
- if: ${{ matrix.config.run_64bit_tests }}
- run: |
- make clean
- make -j2 ARCH=x86-64-modern build
- ../tests/perft.sh
- ../tests/reprosearch.sh
-
- # Sanitizers
-
- - name: Run under valgrind
- if: ${{ matrix.config.run_expensive_tests }}
- run: |
- export CXXFLAGS="-O1 -fno-inline"
- make clean
- make -j2 ARCH=x86-64-modern debug=yes optimize=no build > /dev/null
- ../tests/instrumented.sh --valgrind
- ../tests/instrumented.sh --valgrind-thread
-
- - name: Run with UB sanitizer
- if: ${{ matrix.config.run_expensive_tests }}
- run: |
- export CXXFLAGS="-O1 -fno-inline"
- make clean
- make -j2 ARCH=x86-64-modern sanitize=undefined optimize=no debug=yes build > /dev/null
- ../tests/instrumented.sh --sanitizer-undefined
-
- - name: Run with thread sanitizer
- if: ${{ matrix.config.run_expensive_tests }}
- run: |
- export CXXFLAGS="-O1 -fno-inline"
- make clean
- make -j2 ARCH=x86-64-modern sanitize=thread optimize=no debug=yes build > /dev/null
- ../tests/instrumented.sh --sanitizer-thread
+ Sanitizers:
+ uses: ./.github/workflows/stockfish_sanitizers.yml
+ Tests:
+ uses: ./.github/workflows/stockfish_test.yml
+ Compiles:
+ uses: ./.github/workflows/stockfish_compile_test.yml
+ Binaries:
+ if: github.ref == 'refs/heads/master'
+ uses: ./.github/workflows/stockfish_binaries.yml
+ ARM_Binaries:
+ if: github.ref == 'refs/heads/master'
+ uses: ./.github/workflows/stockfish_arm_binaries.yml
--- /dev/null
+name: Stockfish
+on:
+ workflow_call:
+jobs:
+ Stockfish:
+ name: ${{ matrix.config.name }} ${{ matrix.binaries }}
+ runs-on: ${{ matrix.config.os }}
+ env:
+ COMPILER: ${{ matrix.config.compiler }}
+ COMP: ${{ matrix.config.comp }}
+ EMU: ${{ matrix.config.emu }}
+ EXT: ${{ matrix.config.ext }}
+ OS: ${{ matrix.config.os }}
+ BINARY: ${{ matrix.binaries }}
+ strategy:
+ matrix:
+ config:
+ - name: Android NDK aarch64
+ os: ubuntu-22.04
+ compiler: aarch64-linux-android21-clang++
+ emu: qemu-aarch64
+ comp: ndk
+ shell: bash {0}
+ - name: Android NDK arm
+ os: ubuntu-22.04
+ compiler: armv7a-linux-androideabi21-clang++
+ emu: qemu-arm
+ comp: ndk
+ shell: bash {0}
+ binaries:
+ - armv8
+ - armv7
+ - armv7-neon
+ exclude:
+ - binaries: armv8
+ config: {compiler: armv7a-linux-androideabi21-clang++}
+ - binaries: armv7
+ config: {compiler: aarch64-linux-android21-clang++}
+ - binaries: armv7-neon
+ config: {compiler: aarch64-linux-android21-clang++}
+ defaults:
+ run:
+ working-directory: src
+ shell: ${{ matrix.config.shell }}
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Download required linux packages
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt update
+ sudo apt install qemu-user
+
+ - name: Install NDK
+ if: runner.os == 'Linux'
+ run: |
+ if [ $COMP == ndk ]; then
+ NDKV="21.4.7075529"
+ ANDROID_ROOT=/usr/local/lib/android
+ ANDROID_SDK_ROOT=$ANDROID_ROOT/sdk
+ SDKMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager
+ echo "y" | $SDKMANAGER "ndk;$NDKV"
+ ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
+ ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
+ echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
+ fi
+
+ - name: Download the used network from the fishtest framework
+ run: make net
+
+ - name: Check compiler
+ run: |
+ if [ $COMP == ndk ]; then
+ export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
+ fi
+ $COMPILER -v
+
+ - name: Test help target
+ run: make help
+
+ - name: Check git
+ run: git --version
+
+ # Compile profile guided builds
+
+ - name: Compile ${{ matrix.binaries }} build
+ run: |
+ if [ $COMP == ndk ]; then
+ export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
+ export LDFLAGS="-static -Wno-unused-command-line-argument"
+ fi
+ make clean
+ make -j2 profile-build ARCH=$BINARY COMP=$COMP WINE_PATH=$EMU
+ make strip ARCH=$BINARY COMP=$COMP
+ mv ./stockfish$EXT ../stockfish-android-$BINARY$EXT
+
+ - name: Remove non src files
+ run: rm -f *.o .depend *.nnue
+
+ - name: Create tar archive.
+ run: |
+ cd ..
+ mkdir stockfish
+ cp -r src stockfish/
+ cp stockfish-android-$BINARY$EXT stockfish/
+ cp "Top CPU Contributors.txt" stockfish/
+ cp Copying.txt stockfish/
+ cp AUTHORS stockfish/
+ tar -cvf stockfish-android-$BINARY.tar stockfish
+
+ - name: Upload binaries
+ uses: actions/upload-artifact@v3
+ with:
+ name: stockfish-android-${{ matrix.binaries }}
+ path: stockfish-android-${{ matrix.binaries }}.tar
--- /dev/null
+name: Stockfish
+on:
+ workflow_call:
+jobs:
+ Stockfish:
+ name: ${{ matrix.config.name }} ${{ matrix.binaries }}
+ runs-on: ${{ matrix.config.os }}
+ env:
+ COMPILER: ${{ matrix.config.compiler }}
+ COMP: ${{ matrix.config.comp }}
+ EXT: ${{ matrix.config.ext }}
+ OS: ${{ matrix.config.os }}
+ BINARY: ${{ matrix.binaries }}
+ strategy:
+ matrix:
+ config:
+ - name: Ubuntu 20.04 GCC
+ os: ubuntu-20.04
+ compiler: g++
+ comp: gcc
+ shell: bash {0}
+ - name: MacOS 12 Apple Clang
+ os: macos-12
+ compiler: clang++
+ comp: clang
+ shell: bash {0}
+ - name: Windows 2022 Mingw-w64 GCC x86_64
+ os: windows-2022
+ compiler: g++
+ comp: mingw
+ msys_sys: mingw64
+ msys_env: x86_64-gcc
+ shell: msys2 {0}
+ ext: .exe
+ binaries:
+ - x86-64
+ - x86-64-modern
+ - x86-64-avx2
+ exclude:
+ - binaries: x86-64-avx2
+ config: {os: macos-12}
+ defaults:
+ run:
+ working-directory: src
+ shell: ${{ matrix.config.shell }}
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Download required linux packages
+ if: runner.os == 'Linux'
+ run: sudo apt update
+
+ - 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
+
+ - name: Download the used network from the fishtest framework
+ run: make net
+
+ - name: Check compiler
+ run: $COMPILER -v
+
+ - name: Test help target
+ run: make help
+
+ - name: Check git
+ run: git --version
+
+ # Compile profile guided builds
+
+ - name: Compile ${{ matrix.binaries }} build
+ run: |
+ make clean
+ make -j2 profile-build ARCH=$BINARY COMP=$COMP
+ make strip ARCH=$BINARY COMP=$COMP
+ mv ./stockfish$EXT ../stockfish-$OS-$BINARY$EXT
+
+ - name: Remove non src files
+ run: rm -f *.o .depend *.nnue
+
+ - name: Create tar archive.
+ run: |
+ cd ..
+ mkdir stockfish
+ cp -r src stockfish/
+ cp stockfish-$OS-$BINARY$EXT stockfish/
+ cp "Top CPU Contributors.txt" stockfish/
+ cp Copying.txt stockfish/
+ cp AUTHORS stockfish/
+ tar -cvf stockfish-$OS-$BINARY.tar stockfish
+
+ - name: Upload binaries
+ uses: actions/upload-artifact@v3
+ with:
+ name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
+ path: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}.tar
--- /dev/null
+name: Stockfish
+on:
+ workflow_call:
+jobs:
+ Stockfish:
+ name: ${{ matrix.config.name }}
+ runs-on: ${{ matrix.config.os }}
+ env:
+ COMPILER: ${{ matrix.config.compiler }}
+ COMP: ${{ matrix.config.comp }}
+ strategy:
+ matrix:
+ config:
+ - name: Ubuntu 20.04 GCC
+ os: ubuntu-20.04
+ compiler: g++
+ comp: gcc
+ shell: bash {0}
+ - name: Ubuntu 20.04 Clang
+ os: ubuntu-20.04
+ compiler: clang++
+ comp: clang
+ shell: bash {0}
+ - name: MacOS 12 Apple Clang
+ os: macos-12
+ compiler: clang++
+ comp: clang
+ shell: bash {0}
+ - name: MacOS 12 GCC 11
+ os: macos-12
+ compiler: g++-11
+ comp: gcc
+ shell: bash {0}
+ - name: Windows 2022 Mingw-w64 GCC x86_64
+ os: windows-2022
+ compiler: g++
+ comp: mingw
+ msys_sys: mingw64
+ msys_env: x86_64-gcc
+ shell: msys2 {0}
+ - name: Windows 2022 Mingw-w64 Clang x86_64
+ os: windows-2022
+ compiler: clang++
+ comp: clang
+ msys_sys: clang64
+ msys_env: clang-x86_64-clang
+ shell: msys2 {0}
+
+ defaults:
+ run:
+ working-directory: src
+ shell: ${{ matrix.config.shell }}
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - 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
+
+ - name: Download the used network from the fishtest framework
+ run: make net
+
+ - name: Check compiler
+ run: $COMPILER -v
+
+ - name: Test help target
+ run: make help
+
+ - name: Check git
+ run: git --version
+
+ # x86-64 with newer extensions tests
+
+ - name: Compile x86-64-avx2 build
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-avx2 build
+
+ - name: Compile x86-64-bmi2 build
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-bmi2 build
+
+ - name: Compile x86-64-avx512 build
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-avx512 build
+
+ - name: Compile x86-64-vnni512 build
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-vnni512 build
+
+ - name: Compile x86-64-vnni256 build
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-vnni256 build
--- /dev/null
+name: Stockfish
+on:
+ workflow_call:
+jobs:
+ Stockfish:
+ name: ${{ matrix.sanitizers.name }}
+ runs-on: ${{ matrix.config.os }}
+ env:
+ COMPILER: ${{ matrix.config.compiler }}
+ COMP: ${{ matrix.config.comp }}
+ CXXFLAGS: "-Werror"
+ strategy:
+ matrix:
+ config:
+ - name: Ubuntu 20.04 GCC
+ os: ubuntu-20.04
+ compiler: g++
+ comp: gcc
+ shell: bash {0}
+ sanitizers:
+ - name: Run with thread sanitizer
+ make_option: sanitize=thread
+ instrumented_option: sanitizer-thread
+ - name: Run with UB sanitizer
+ make_option: sanitize=undefined
+ instrumented_option: sanitizer-undefined
+ - name: Run under valgrind
+ make_option: ""
+ instrumented_option: valgrind
+ - name: Run under valgrind-thread
+ make_option: ""
+ instrumented_option: valgrind-thread
+ defaults:
+ run:
+ working-directory: src
+ shell: ${{ matrix.config.shell }}
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Download required linux packages
+ run: |
+ sudo apt update
+ sudo apt install expect valgrind g++-multilib
+
+ - name: Download the used network from the fishtest framework
+ run: make net
+
+ - name: Check compiler
+ run: $COMPILER -v
+
+ - name: Test help target
+ run: make help
+
+ - name: Check git
+ run: git --version
+
+ # Sanitizers
+
+ - name: ${{ matrix.sanitizers.name }}
+ run: |
+ export CXXFLAGS="-O1 -fno-inline"
+ make clean
+ make -j2 ARCH=x86-64-modern ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
+ ../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }}
--- /dev/null
+name: Stockfish
+on:
+ workflow_call:
+jobs:
+ Stockfish:
+ name: ${{ matrix.config.name }}
+ runs-on: ${{ matrix.config.os }}
+ env:
+ COMPILER: ${{ matrix.config.compiler }}
+ COMP: ${{ matrix.config.comp }}
+ CXXFLAGS: "-Werror"
+ strategy:
+ matrix:
+ config:
+ - name: Ubuntu 20.04 GCC
+ os: ubuntu-20.04
+ compiler: g++
+ comp: gcc
+ run_32bit_tests: true
+ run_64bit_tests: true
+ shell: bash {0}
+ - name: Ubuntu 20.04 Clang
+ os: ubuntu-20.04
+ compiler: clang++
+ comp: clang
+ run_32bit_tests: true
+ run_64bit_tests: true
+ shell: bash {0}
+ - name: Android NDK aarch64
+ os: ubuntu-22.04
+ compiler: aarch64-linux-android21-clang++
+ comp: ndk
+ run_armv8_tests: true
+ shell: bash {0}
+ - name: Android NDK arm
+ os: ubuntu-22.04
+ compiler: armv7a-linux-androideabi21-clang++
+ comp: ndk
+ run_armv7_tests: true
+ shell: bash {0}
+ - name: MacOS 12 Apple Clang
+ os: macos-12
+ compiler: clang++
+ comp: clang
+ run_64bit_tests: true
+ shell: bash {0}
+ - name: MacOS 12 GCC 11
+ os: macos-12
+ compiler: g++-11
+ comp: gcc
+ run_64bit_tests: true
+ shell: bash {0}
+ - name: Windows 2022 Mingw-w64 GCC x86_64
+ os: windows-2022
+ compiler: g++
+ comp: mingw
+ run_64bit_tests: true
+ msys_sys: mingw64
+ msys_env: x86_64-gcc
+ shell: msys2 {0}
+ - name: Windows 2022 Mingw-w64 GCC i686
+ os: windows-2022
+ compiler: g++
+ comp: mingw
+ run_32bit_tests: true
+ msys_sys: mingw32
+ msys_env: i686-gcc
+ shell: msys2 {0}
+ - name: Windows 2022 Mingw-w64 Clang x86_64
+ os: windows-2022
+ compiler: clang++
+ comp: clang
+ run_64bit_tests: true
+ msys_sys: clang64
+ msys_env: clang-x86_64-clang
+ shell: msys2 {0}
+ defaults:
+ run:
+ working-directory: src
+ shell: ${{ matrix.config.shell }}
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Download required linux packages
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt update
+ sudo apt install expect valgrind g++-multilib qemu-user
+
+ - name: Install NDK
+ if: runner.os == 'Linux'
+ run: |
+ if [ $COMP == ndk ]; then
+ NDKV="21.4.7075529"
+ ANDROID_ROOT=/usr/local/lib/android
+ ANDROID_SDK_ROOT=$ANDROID_ROOT/sdk
+ SDKMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager
+ echo "y" | $SDKMANAGER "ndk;$NDKV"
+ ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
+ ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
+ echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
+ fi
+
+ - 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 expect
+
+ - name: Download the used network from the fishtest framework
+ run: make net
+
+ - name: Extract the bench number from the commit history
+ run: |
+ git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig
+ [ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
+
+ - name: Check compiler
+ run: |
+ if [ $COMP == ndk ]; then
+ export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
+ fi
+ $COMPILER -v
+
+ - name: Test help target
+ run: make help
+
+ - name: Check git
+ run: git --version
+
+ # x86-32 tests
+
+ - name: Test debug x86-32 build
+ if: ${{ matrix.config.run_32bit_tests }}
+ run: |
+ export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
+ make clean
+ make -j2 ARCH=x86-32 optimize=no debug=yes build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-32 build
+ if: ${{ matrix.config.run_32bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-32 build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-32-sse41-popcnt build
+ if: ${{ matrix.config.run_32bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-32-sse41-popcnt build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-32-sse2 build
+ if: ${{ matrix.config.run_32bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-32-sse2 build
+ ../tests/signature.sh $benchref
+
+ - name: Test general-32 build
+ if: ${{ matrix.config.run_32bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=general-32 build
+ ../tests/signature.sh $benchref
+
+ # x86-64 tests
+
+ - name: Test debug x86-64-modern build
+ if: ${{ matrix.config.run_64bit_tests }}
+ run: |
+ export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
+ make clean
+ make -j2 ARCH=x86-64-modern optimize=no debug=yes build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-64-modern build
+ if: ${{ matrix.config.run_64bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-modern build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-64-ssse3 build
+ if: ${{ matrix.config.run_64bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-ssse3 build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-64-sse3-popcnt build
+ if: ${{ matrix.config.run_64bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-sse3-popcnt build
+ ../tests/signature.sh $benchref
+
+ - name: Test x86-64 build
+ if: ${{ matrix.config.run_64bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-64 build
+ ../tests/signature.sh $benchref
+
+ - name: Test general-64 build
+ if: matrix.config.run_64bit_tests
+ run: |
+ make clean
+ make -j2 ARCH=general-64 build
+ ../tests/signature.sh $benchref
+
+ # armv8 tests
+
+ - name: Test armv8 build
+ if: ${{ matrix.config.run_armv8_tests }}
+ run: |
+ export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
+ export LDFLAGS="-static -Wno-unused-command-line-argument"
+ make clean
+ make -j2 ARCH=armv8 build
+ ../tests/signature.sh $benchref
+
+ # armv7 tests
+
+ - name: Test armv7 build
+ if: ${{ matrix.config.run_armv7_tests }}
+ run: |
+ export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
+ export LDFLAGS="-static -Wno-unused-command-line-argument"
+ make clean
+ make -j2 ARCH=armv7 build
+ ../tests/signature.sh $benchref
+
+ - name: Test armv7-neon build
+ if: ${{ matrix.config.run_armv7_tests }}
+ run: |
+ export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
+ export LDFLAGS="-static -Wno-unused-command-line-argument"
+ make clean
+ make -j2 ARCH=armv7-neon build
+ ../tests/signature.sh $benchref
+
+ # Other tests
+
+ - name: Check perft and search reproducibility
+ if: ${{ matrix.config.run_64bit_tests }}
+ run: |
+ make clean
+ make -j2 ARCH=x86-64-modern build
+ ../tests/perft.sh
+ ../tests/reprosearch.sh
braich
Brian Sheppard (SapphireBrand, briansheppard-toast)
Bruno de Melo Costa (BM123499)
+Bruno Pellanda (pellanda)
Bryan Cross (crossbr)
candirufish
Chess13234
Chris Cain (ceebo)
+clefrks
Dale Weiler (graphitemaster)
Dan Schmidt (dfannius)
Daniel Axtens (daxtens)
Daniel Dugovic (ddugovic)
Dariusz Orzechowski (dorzechowski)
David Zar
+David (dav1312)
Daylen Yang (daylen)
Deshawn Mohan-Smith (GoldenRare)
Dieter Dobbelaere (ddobbelaere)
Ivan Ivec (IIvec)
Jacques B. (Timshel)
Jan Ondruš (hxim)
-Jared Kish (Kurtbusch)
+Jared Kish (Kurtbusch, kurt22i)
Jarrod Torriero (DU-jdto)
Jean Gauthier (OuaisBla)
Jean-Francois Romang (jromang)
Miroslav Fontán (Hexik)
Moez Jellouli (MJZ1977)
Mohammed Li (tthsqe12)
+Muzhen J (XInTheDark)
Nathan Rugg (nmrugg)
Nick Pelling (nickpelling)
Nicklas Persson (NicklasPersson)
Pascal Romaret
Pasquale Pigazzini (ppigazzini)
Patrick Jansen (mibere)
-pellanda
Peter Schneider (pschneider1968)
Peter Zsifkovits (CoffeeOne)
+PikaCat
Praveen Kumar Tummala (praveentml)
Rahul Dsilva (silversolver1)
Ralph Stößer (Ralph Stoesser)
Raminder Singh
renouve
-Reuven Peleg
-Richard Lloyd
+Reuven Peleg (R-Peleg)
+Richard Lloyd (Richard-Lloyd)
Rodrigo Exterckötter Tjäder
+Rodrigo Roim (roim)
Ron Britvich (Britvich)
Ronald de Man (syzygy1, syzygy)
rqs
Stefano Cardanobile (Stefano80)
Steinar Gunderson (sesse)
Stéphane Nicolet (snicolet)
+Syine Mineta (MinetaS)
Prokop Randáček (ProkopRandacek)
Thanar2
thaspel
<div align="center">
-
+
[![Stockfish][stockfish128-logo]][website-link]
-
+
[![Build][build-badge]][build-link]
[![License][license-badge]][license-link]
<br>
[![Website][website-badge]][website-link]
[![Fishtest][fishtest-badge]][fishtest-link]
[![Discord][discord-badge]][discord-link]
-
+
</div>
## Overview
Glaurung 2.1. Stockfish is not a complete chess program and requires a UCI-compatible
graphical user interface (GUI) (e.g. XBoard with PolyGlot, Scid, Cute Chess, eboard,
Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in order to be used comfortably.
-Read the documentation for your GUI of choice for informationabout how to use
+Read the documentation for your GUI of choice for information about how to use
Stockfish with it.
-The Stockfish engine features two evaluation functions for chess. The efficiently
+The Stockfish engine features two evaluation functions for chess. The efficiently
updatable neural network (NNUE) based evaluation is the default and by far the strongest.
-The classical evaluation based on handcrafted terms remains available. The strongest
+The classical evaluation based on handcrafted terms remains available. The strongest
network is integrated in the binary and downloaded automatically during the build process.
-The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2,
+The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2,
avx2, neon, or similar).
## Files
For developers the following non-standard commands might be of interest, mainly useful for debugging:
* #### bench *ttSize threads limit fenFile limitType evalType*
- Performs a standard benchmark using various options. The signature of a version
- (standard node count) is obtained using all defaults. `bench` is currently
+ Performs a standard benchmark using various options. The signature of a version
+ (standard node count) is obtained using all defaults. `bench` is currently
`bench 16 1 13 default depth mixed`.
* #### compiler
Notes:
-1) the NNUE evaluation depends on the Stockfish binary and the network parameter file
+1) the NNUE evaluation depends on the Stockfish binary and the network parameter file
(see the EvalFile UCI option). Not every parameter file is compatible with a given
-Stockfish binary, but the default value of the EvalFile UCI option is the name of a
+Stockfish binary, but the default value of the EvalFile UCI option is the name of a
network that is guaranteed to be compatible with that binary.
2) to use the NNUE evaluation, the additional data file with neural network parameters
The only real limitation is that whenever you distribute Stockfish in
some way, you MUST always include the license and the full source code
-(or a pointer to where the source code can be found) to generate the
+(or a pointer to where the source code can be found) to generate the
exact binary you are distributing. If you make any changes to the
source code, these changes must also be made available under the GPL v3.
For full details, read the copy of the GPL v3 found in the file named
[*Copying.txt*][license-link].
-[authors-link]:https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
-[build-badge]:https://img.shields.io/github/workflow/status/official-stockfish/Stockfish/Stockfish?style=for-the-badge&label=stockfish&logo=github
-[build-link]:https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
-[commits-badge]:https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
-[commits-link]:https://github.com/official-stockfish/Stockfish/commits/master
-[discord-badge]:https://img.shields.io/discord/435943710472011776?style=for-the-badge&label=discord&logo=Discord
-[discord-link]:https://discord.com/invite/aefaxmq
-[fishcooking-link]:https://groups.google.com/g/fishcooking
-[fishtest-badge]:https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=Fishtest&up_color=success&up_message=Online&url=https%3A%2F%2Ftests.stockfishchess.org%2Ftests
-[fishtest-link]:https://tests.stockfishchess.org/tests
-[github-link]:https://github.com/official-stockfish/Stockfish
-[guideline-link]:https://github.com/glinscott/fishtest/wiki/Creating-my-first-test
-[license-badge]:https://img.shields.io/github/license/official-stockfish/Stockfish?style=for-the-badge&label=license&color=success
-[license-link]:https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
-[lockpages-link]:https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows
-[nodchip-link]:https://github.com/nodchip/Stockfish
-[programming-link]:https://www.chessprogramming.org/Main_Page
-[programmingsf-link]:https://www.chessprogramming.org/Stockfish
-[pytorch-link]:https://github.com/glinscott/nnue-pytorch
-[rammap-link]:https://docs.microsoft.com/en-us/sysinternals/downloads/rammap
-[readme-link]:https://github.com/official-stockfish/Stockfish/blob/master/README.md
-[release-badge]:https://img.shields.io/github/v/release/official-stockfish/Stockfish?style=for-the-badge&label=official%20release
-[release-link]:https://github.com/official-stockfish/Stockfish/releases/latest
-[src-link]:https://github.com/official-stockfish/Stockfish/tree/master/src
-[stockfish128-logo]:https://stockfishchess.org/images/logo/icon_128x128.png
-[tools-link]:https://github.com/official-stockfish/Stockfish/tree/tools
-[uci-link]:https://www.shredderchess.com/download/div/uci.zip
-[website-badge]:https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=website&up_color=success&up_message=Online&url=https%3A%2F%2Fstockfishchess.org
-[website-link]:https://stockfishchess.org
-[worker-link]:https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview
+
+[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
+[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
+[commits-link]: https://github.com/official-stockfish/Stockfish/commits/master
+[discord-link]: https://discord.gg/GWDRS3kU6R
+[fishcooking-link]: https://groups.google.com/g/fishcooking
+[fishtest-link]: https://tests.stockfishchess.org/tests
+[github-link]: https://github.com/official-stockfish/Stockfish
+[guideline-link]: https://github.com/glinscott/fishtest/wiki/Creating-my-first-test
+[license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
+[lockpages-link]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows
+[nodchip-link]: https://github.com/nodchip/Stockfish
+[programming-link]: https://www.chessprogramming.org/Main_Page
+[programmingsf-link]: https://www.chessprogramming.org/Stockfish
+[pytorch-link]: https://github.com/glinscott/nnue-pytorch
+[rammap-link]: https://docs.microsoft.com/en-us/sysinternals/downloads/rammap
+[readme-link]: https://github.com/official-stockfish/Stockfish/blob/master/README.md
+[release-link]: https://github.com/official-stockfish/Stockfish/releases/latest
+[src-link]: https://github.com/official-stockfish/Stockfish/tree/master/src
+[stockfish128-logo]: https://stockfishchess.org/images/logo/icon_128x128.png
+[tools-link]: https://github.com/official-stockfish/Stockfish/tree/tools
+[uci-link]: https://www.shredderchess.com/download/div/uci.zip
+[website-link]: https://stockfishchess.org
+[worker-link]: https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview
+
+[build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github
+[commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
+[discord-badge]: https://img.shields.io/discord/435943710472011776?style=for-the-badge&label=discord&logo=Discord
+[fishtest-badge]: https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=Fishtest&up_color=success&up_message=Online&url=https%3A%2F%2Ftests.stockfishchess.org%2Ftests%2Ffinished
+[license-badge]: https://img.shields.io/github/license/official-stockfish/Stockfish?style=for-the-badge&label=license&color=success
+[release-badge]: https://img.shields.io/github/v/release/official-stockfish/Stockfish?style=for-the-badge&label=official%20release
+[website-badge]: https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=website&up_color=success&up_message=Online&url=https%3A%2F%2Fstockfishchess.org
-Contributors to Fishtest with >10,000 CPU hours, as of 2022-07-31.
+Contributors to Fishtest with >10,000 CPU hours, as of 2022-11-19.
Thank you!
Username CPU Hours Games played
------------------------------------------------------------------
-noobpwnftw 33202707 2423743815
-technologov 5064327 270208248
-mlang 2963357 198937430
-dew 1677196 99717674
-grandphish2 1231326 74551309
-okrout 1102747 98977462
-TueRens 925904 57404676
-pemo 911980 35581261
-tvijlbrief 795993 51894442
-JojoM 774270 47311084
+noobpwnftw 36475307 2748033975
+technologov 14570711 760073590
+mlang 3026000 200065824
+dew 1689222 100034318
+grandphish2 1442171 86798057
+okrout 1439985 133471766
+pemo 1405374 44189811
+linrock 1299003 28382783
+TueRens 1163420 71159522
+JojoM 897158 55177114
+tvijlbrief 796125 51897690
mibere 703840 46867607
-linrock 697283 18804969
-gvreuls 564284 36392236
-cw 515739 34775505
-fastgm 500949 30101898
-oz 439015 31794460
-CSU_Dynasty 438017 29369136
+gvreuls 635982 40652394
+oz 590763 41201352
+sebastronomy 581517 23307132
+cw 517915 34865769
+fastgm 504266 30264740
+CSU_Dynasty 479901 31846710
+ctoks 433503 28180725
crunchy 427035 27344275
-ctoks 422671 27812261
-bcross 363335 25108521
-leszek 360149 22674005
-velislav 333325 21444360
+leszek 416883 27493447
+bcross 409982 28062127
+velislav 345954 22232274
Fisherman 327231 21829379
-Dantist 292327 17951982
-mgrabiak 247220 16137378
-nordlandia 226543 14601042
-robal 224740 14314972
-glinscott 217799 13780820
-ncfish1 207751 13909639
-drabel 203884 13922680
-mhoram 200022 12533963
+Dantist 296386 18031762
+mgrabiak 288928 18869896
+rpngn 259965 16281463
+robal 237653 15148350
+ncfish1 231764 15275003
+nordlandia 226923 14624832
+glinscott 208125 13277240
+drabel 204167 13930674
+mhoram 202894 12601997
bking_US 198894 11876016
-rpngn 191764 12236583
+thirdlife 198844 5453268
Thanar 179852 12365359
vdv 175544 9904472
+armo9494 168201 11136452
spams 157128 10319326
-marrco 150300 9402229
+marrco 151599 9551115
sqrt2 147963 9724586
-vdbergh 137480 8958795
+vdbergh 137690 8971569
CoffeeOne 137100 5024116
malala 136182 8002293
+DesolatedDodo 135276 8657464
xoto 133759 9159372
-davar 128645 8367253
-DesolatedDodo 124877 8056482
+davar 129023 8376525
dsmith 122059 7570238
amicic 119661 7938029
Data 113305 8220352
BrunoBanani 112960 7436849
-CypressChess 108321 7759588
+CypressChess 108331 7759788
+skiminki 106518 7062598
MaZePallas 102823 6633619
-skiminki 102168 6778440
sterni1971 100532 5880772
sunu 100167 7040199
+zeryl 99331 6221261
ElbertoOne 99028 7023771
-zeryl 96984 6162287
+DMBK 97572 6950312
+Calis007 96779 5611552
+cuistot 93111 5536500
brabos 92118 6186135
-cuistot 91738 5447070
+Wolfgang 91769 5720158
psk 89957 5984901
-racerschmacer 85712 6119648
+racerschmacer 85805 6122790
+jcAEie 85527 5630616
Vizvezdenec 83761 5344740
-sschnee 83003 4840890
+sschnee 83557 4853690
0x3C33 82614 5271253
-armo9494 82501 5806056
BRAVONE 81239 5054681
+Dubslow 78461 5042980
nssy 76497 5259388
-thirdlife 76478 1544524
-Calis007 76457 4281018
-jromang 75885 5230523
+jromang 76106 5236025
teddybaer 75125 5407666
+yurikvelo 73933 5031096
+tolkki963 73885 4721430
Pking_cda 73776 5293873
-Wolfgang 72750 4538670
-sebastronomy 70784 1329428
+Bobo1239 71675 4860987
solarlight 70517 5028306
dv8silencer 70287 3883992
-Bobo1239 68515 4652287
-yurikvelo 67651 4578970
+Gelma 69304 3980932
manap 66273 4121774
+megaman7de 65419 4120200
+markkulix 65331 4114860
+bigpen0r 64932 4683883
tinker 64333 4268790
qurashee 61208 3429862
+AGI 58325 4258646
robnjr 57262 4053117
-megaman7de 57023 3525850
Freja 56938 3733019
-MaxKlaxxMiner 56279 3410158
+MaxKlaxxMiner 56879 3423958
ttruscott 56010 3680085
rkl 55132 4164467
renouve 53811 3501516
-tolkki963 53294 3354682
-DMBK 52963 3933332
+Spprtr 52736 3410019
finfish 51360 3370515
eva42 51272 3599691
-Spprtr 51139 3299983
-eastorwest 51058 3451555
+eastorwest 51117 3454811
rap 49985 3219146
+unixwizard 49734 2536230
pb00067 49727 3298270
-bigpen0r 47667 3336927
ronaldjerum 47654 3240695
biffhero 46564 3111352
+GPUex 45861 2926502
Fifis 45843 3088497
+oryx 45578 3493978
VoyagerOne 45476 3452465
+Wencey 44943 2654490
speedycpu 43842 3003273
jbwiebe 43305 2805433
Antihistamine 41788 2761312
mhunt 41735 2691355
+olafm 41277 3284344
homyur 39893 2850481
gri 39871 2515779
-oryx 39602 3024830
+MarcusTullius 38303 2251097
+Garf 37741 2999686
+kdave 37424 2557406
SC 37299 2731694
-Garf 37213 2986270
-Dubslow 36714 2409254
csnodgrass 36207 2688994
jmdana 36157 2210661
-markkulix 35994 2226860
strelock 34716 2074055
EthanOConnor 33370 2090311
slakovv 32915 2021889
-gopeto 31078 2033362
+gopeto 31669 2060958
manapbk 30987 1810399
Prcuvu 30377 2170122
anst 30301 2190091
jkiiski 30136 1904470
+spcc 30135 1903728
hyperbolic.tom 29840 2017394
+xwziegtm 29763 2347412
chuckstablers 29659 2093438
Pyafue 29650 1902349
-MarcusTullius 28611 1646671
-spcc 28241 1821198
-belzedar94 27935 1789106
+belzedar94 28846 1811530
OuaisBla 27636 1578800
chriswk 26902 1868317
achambord 26582 1767323
Patrick_G 26276 1801617
yorkman 26193 1992080
+Ulysses 25289 1674274
SFTUser 25182 1675689
nabildanial 24942 1519409
Sharaf_DG 24765 1786697
-rodneyc 24375 1416258
-Ulysses 24017 1626140
+rodneyc 24376 1416402
agg177 23890 1395014
+Ente 23747 1674582
+Karpovbot 23629 1313186
JanErik 23408 1703875
-Ente 23403 1660988
-kdave 23392 1630462
Isidor 23388 1680691
-Norabor 23339 1602636
-cisco2015 22897 1762669
-Wencey 22573 1121406
+Norabor 23371 1603244
+cisco2015 22934 1763773
Zirie 22542 1472937
team-oh 22272 1636708
+Roady 22220 1465606
MazeOfGalious 21978 1629593
-sg4032 21947 1643265
+sg4032 21947 1643353
ianh2105 21725 1632562
xor12 21628 1680365
dex 21612 1467203
nesoneg 21494 1463031
-Roady 21323 1433822
+user213718 21454 1404128
+AndreasKrug 21227 1577833
sphinx 21211 1384728
-user213718 21196 1397710
jjoshua2 21001 1423089
horst.prack 20878 1465656
+jsys14 20729 1221010
0xB00B1ES 20590 1208666
j3corre 20405 941444
Adrian.Schmidt123 20316 1281436
-jcAEie 20221 1504162
+bonsi 20022 1300682
wei 19973 1745989
+dapper 19754 1167758
+Zake9298 19745 1458416
+fishtester 19617 1257388
rstoesser 19569 1293588
eudhan 19274 1283717
-fishtester 19145 1242668
vulcan 18871 1729392
+Jopo12321 18803 1036284
jundery 18445 1115855
-iisiraider 18247 1101015
ville 17883 1384026
+5t0ckf15hTr4in3r 17809 1105858
chris 17698 1487385
+dju 17697 994333
purplefishies 17595 1092533
-dju 17353 978595
-AndreasKrug 17191 1317997
+iisiraider 17275 1049015
DragonLord 17014 1162790
-Jopo12321 16966 944924
-GPUex 16744 1077826
-xwziegtm 16608 1276372
+Karby 16457 1010138
+Goatminola 16278 1145026
IgorLeMasson 16064 1147232
+Gaster319 16056 1109070
+redstone59 15953 1161664
+scuzzi 15757 968735
ako027ako 15671 1173203
-jsys14 15474 917092
Nikolay.IT 15154 1068349
Andrew Grant 15114 895539
-scuzzi 15112 960373
+Naven94 15054 834762
OssumOpossum 14857 1007129
-Karby 14808 867120
+qoo_charly_cai 14490 847865
enedene 14476 905279
-bpfliegel 14298 884523
+szupaw 14252 929130
+bpfliegel 14233 882523
mpx86 14019 759568
jpulman 13982 870599
-Naven94 13879 811552
-Karpovbot 13808 734276
crocogoat 13803 1117422
-joster 13794 950160
Nesa92 13786 1114691
+joster 13710 946160
mbeier 13650 1044928
Hjax 13535 915487
Dark_wizzie 13422 1007152
Rudolphous 13244 883140
Machariel 13010 863104
+infinigon 12991 943216
+pirt 12925 985437
+Skiff84 12923 649994
mabichito 12903 749391
thijsk 12886 722107
AdrianSA 12860 804972
-infinigon 12807 937332
Flopzee 12698 894821
-pirt 12551 965597
fatmurphy 12547 853210
+woutboat 12419 836696
SapphireBrand 12416 969604
+Oakwen 12406 840961
+deflectooor 12386 579392
modolief 12386 896470
Farseer 12249 694108
pgontarz 12151 848794
stocky 11954 699440
mschmidt 11941 803401
-Oakwen 11925 818865
-MooTheCow 11851 772628
-deflectooor 11642 565132
-dbernier 11609 818636
-Skiff84 11604 602786
+MooTheCow 11871 773654
+Jackfish 11867 773550
+dbernier 11705 821780
+whelanh 11557 245188
Maxim 11543 836024
+Nullvalue 11534 731410
+icewulf 11528 650470
+FormazChar 11523 861599
infinity 11470 727027
-FormazChar 11430 856559
-aga 11409 695071
-Jackfish 11403 750526
+aga 11412 695127
torbjo 11395 729145
Thomas A. Anderson 11372 732094
savage84 11358 670860
+ali-al-zhrani 11272 781310
d64 11263 789184
-qoo_charly_cai 11127 671959
+Bourbaki 11108 709144
snicolet 11106 869170
-ali-al-zhrani 11098 768494
-whelanh 11067 235676
+Alb11747 10855 696920
basepi 10637 744851
Cubox 10621 826448
-Alb11747 10558 689794
+Karmatron 10616 674818
michaelrpg 10509 739239
OIVAS7572 10420 995586
-Garruk 10343 704723
+Garruk 10348 704905
dzjp 10343 732529
ols 10259 570669
-lbraesch 10252 647825
-Karmatron 10195 661432
x86-64-vnni512 x86-64-vnni256 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 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \
- armv7 armv7-neon armv8 apple-silicon general-64 general-32))
+ armv7 armv7-neon armv8 apple-silicon general-64 general-32 riscv64))
SUPPORTED_ARCH=true
else
SUPPORTED_ARCH=false
popcnt = yes
endif
+ifeq ($(ARCH),riscv64)
+ arch = riscv64
endif
+endif
+
### ==========================================================================
### Section 3. Low-level Configuration
CXX=g++
CXXFLAGS += -pedantic -Wextra
- ifeq ($(arch),$(filter $(arch),armv7 armv8))
+ ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
+ ifeq ($(ARCH),riscv64)
+ CXXFLAGS += -latomic
+ endif
else
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
endif
- ifeq ($(arch),$(filter $(arch),armv7 armv8))
+ ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
+ ifeq ($(ARCH),riscv64)
+ CXXFLAGS += -latomic
+ endif
else
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
### Sometimes gcc is really clang
ifeq ($(COMP),gcc)
- gccversion = $(shell $(CXX) --version)
+ gccversion = $(shell $(CXX) --version 2>/dev/null)
gccisclang = $(findstring clang,$(gccversion))
ifneq ($(gccisclang),)
profile_make = clang-profile-make
ifeq ($(avx2),yes)
CXXFLAGS += -DUSE_AVX2
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
- CXXFLAGS += -mavx2
+ CXXFLAGS += -mavx2 -mbmi
endif
endif
endif
endif
+### 3.7.1 Try to include git commit sha for versioning
+GIT_SHA = $(shell git rev-parse --short HEAD 2>/dev/null)
+ifneq ($(GIT_SHA), )
+ CXXFLAGS += -DGIT_SHA=\"$(GIT_SHA)\"
+endif
+
+### 3.7.2 Try to include git commit date for versioning
+GIT_DATE = $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null)
+ifneq ($(GIT_DATE), )
+ CXXFLAGS += -DGIT_DATE=\"$(GIT_DATE)\"
+endif
+
### 3.8 Link Time Optimization
### This is a mix of compile and link time options because the lto link phase
### needs access to the optimization flags.
ifeq ($(optimize),yes)
ifeq ($(debug), no)
ifeq ($(comp),clang)
- CXXFLAGS += -flto
+ CXXFLAGS += -flto=full
ifeq ($(target_windows),yes)
CXXFLAGS += -fuse-ld=lld
endif
# GCC on some systems.
else ifeq ($(comp),gcc)
ifeq ($(gccisclang),)
- CXXFLAGS += -flto
+ CXXFLAGS += -flto -flto-partition=one
LDFLAGS += $(CXXFLAGS) -flto=jobserver
else
- CXXFLAGS += -flto
+ CXXFLAGS += -flto=full
LDFLAGS += $(CXXFLAGS)
endif
# To use LTO and static linking on Windows,
# the tool chain requires gcc version 10.1 or later.
else ifeq ($(comp),mingw)
- ifneq ($(arch),i386)
- CXXFLAGS += -flto
+ CXXFLAGS += -flto -flto-partition=one
LDFLAGS += $(CXXFLAGS) -save-temps
endif
- endif
endif
endif
@echo "Supported targets:"
@echo ""
@echo "help > Display architecture details"
- @echo "build > Standard build"
+ @echo "profile-build > standard build with profile-guided optimization"
+ @echo "build > skip profile-guided optimization"
@echo "net > Download the default nnue net"
- @echo "profile-build > Faster build (with profile-guided optimization)"
@echo "strip > Strip executable"
@echo "install > Install executable"
@echo "clean > Clean up"
@echo "apple-silicon > Apple silicon ARM64"
@echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit"
+ @echo "riscv64 > RISC-V 64-bit"
@echo ""
@echo "Supported compilers:"
@echo ""
@echo "icc > Intel compiler"
@echo "ndk > Google NDK to cross-compile for Android"
@echo ""
- @echo "Simple examples. If you don't know what to do, you likely want to run: "
+ @echo "Simple examples. If you don't know what to do, you likely want to run one of: "
@echo ""
- @echo "make -j build ARCH=x86-64 (A portable, slow compile for 64-bit systems)"
- @echo "make -j build ARCH=x86-32 (A portable, slow compile for 32-bit systems)"
+ @echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems "
+ @echo "make -j profile-build ARCH=x86-64-modern # A more portable compile for 64-bit systems "
+ @echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems "
@echo ""
- @echo "Advanced examples, for experienced users looking for performance: "
+ @echo "Advanced examples, for experienced users: "
@echo ""
- @echo "make help ARCH=x86-64-bmi2"
+ @echo "make -j profile-build ARCH=x86-64-bmi2"
@echo "make -j profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-9.0"
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang"
@echo ""
.PHONY: help build profile-build strip install clean net objclean profileclean \
config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
- clang-profile-use clang-profile-make
+ clang-profile-use clang-profile-make FORCE
build: net config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
@if [ "x$(curl_or_wget)" = "x" ]; then \
- echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
+ echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
fi
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
@if [ "x$(shasum_command)" = "x" ]; then \
echo "$(nnuenet) available."; \
else \
if [ "x$(curl_or_wget)" != "x" ]; then \
- echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
+ echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
+ else \
+ echo "No net found and download not possible"; exit 1;\
fi; \
fi; \
if [ "x$(shasum_command)" != "x" ]; then \
@test "$(SUPPORTED_ARCH)" = "true"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
- test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64"
+ test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || test "$(arch)" = "riscv64"
@test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
$(EXE): $(OBJS)
+$(CXX) -o $@ $(OBJS) $(LDFLAGS)
+# Force recompilation to ensure version info is up-to-date
+misc.o: FORCE
+FORCE:
+
clang-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-generate ' \
.depend: $(SRCS)
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
+ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean config-sanity))
-include .depend
+endif
Score scores[TERM_NB][COLOR_NB];
- double to_cp(Value v) { return double(v) / PawnValueEg; }
+ double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; }
void add(int idx, Color c, Score s) {
scores[idx][c] = s;
// Initialize score by reading the incrementally updated scores included in
// the position object (material + piece square tables) and the material
// imbalance. Score is computed internally from the white point of view.
- Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->trend;
+ Score score = pos.psq_score() + me->imbalance();
// Probe the pawn hash table
pe = Pawns::probe(pos);
Value Eval::evaluate(const Position& pos, int* complexity) {
Value v;
- Color stm = pos.side_to_move();
Value psq = pos.psq_eg_stm();
// We use the much less accurate but faster Classical eval when the NNUE
// option is set to false. Otherwise we use the NNUE eval unless the
- // PSQ advantage is decisive and several pieces remain (~3 Elo)
+ // PSQ advantage is decisive and several pieces remain. (~3 Elo)
bool useClassical = !useNNUE || (pos.count<ALL_PIECES>() > 7 && abs(psq) > 1760);
+
if (useClassical)
v = Evaluation<NO_TRACE>(pos).value();
else
{
int nnueComplexity;
- int scale = 1064 + 106 * pos.non_pawn_material() / 5120;
+ int scale = 1076 + 96 * pos.non_pawn_material() / 5120;
+
+ Color stm = pos.side_to_move();
Value optimism = pos.this_thread()->optimism[stm];
Value nnue = NNUE::evaluate(pos, true, &nnueComplexity);
+
// Blend nnue complexity with (semi)classical complexity
- nnueComplexity = (104 * nnueComplexity + 131 * abs(nnue - psq)) / 256;
- if (complexity) // Return hybrid NNUE complexity to caller
+ nnueComplexity = ( 412 * nnueComplexity
+ + 428 * abs(psq - nnue)
+ + (optimism > 0 ? int(optimism) * int(psq - nnue) : 0)
+ ) / 1024;
+
+ // Return hybrid NNUE complexity to caller
+ if (complexity)
*complexity = nnueComplexity;
- optimism = optimism * (269 + nnueComplexity) / 256;
- v = (nnue * scale + optimism * (scale - 754)) / 1024;
+ optimism = optimism * (278 + nnueComplexity) / 256;
+ v = (nnue * scale + optimism * (scale - 755)) / 1024;
}
// Damp down the evaluation linearly when shuffling
- v = v * (195 - pos.rule50_count()) / 211;
+ v = v * (197 - pos.rule50_count()) / 214;
// Guarantee evaluation does not hit the tablebase range
v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
// When not using NNUE, return classical complexity to caller
- if (complexity && (!useNNUE || useClassical))
+ if (complexity && useClassical)
*complexity = abs(v - psq);
return v;
std::memset(scores, 0, sizeof(scores));
// Reset any global variable used in eval
- pos.this_thread()->trend = SCORE_ZERO;
pos.this_thread()->bestValue = VALUE_ZERO;
pos.this_thread()->optimism[WHITE] = VALUE_ZERO;
pos.this_thread()->optimism[BLACK] = VALUE_ZERO;
// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
// for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro, as it is used in the Makefile.
- #define EvalFileDefaultName "nn-ad9b42354671.nnue"
+ #define EvalFileDefaultName "nn-335a9b2d8a80.nnue"
namespace NNUE {
namespace {
-/// Version number. If Version is left empty, then compile date in the format
-/// DD-MM-YY and show in engine_info.
-const string Version = "";
+/// Version number or dev.
+const string version = "dev";
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
} // namespace
-/// engine_info() returns the full name of the current Stockfish version. This
-/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
-/// the program was compiled) or "Stockfish <Version>", depending on whether
-/// Version is empty.
+/// engine_info() returns the full name of the current Stockfish version.
+/// For local dev compiles we try to append the commit sha and commit date
+/// from git if that fails only the local compilation date is set and "nogit" is specified:
+/// Stockfish dev-YYYYMMDD-SHA
+/// or
+/// Stockfish dev-YYYYMMDD-nogit
+///
+/// For releases (non dev builds) we only include the version number:
+/// Stockfish version
string engine_info(bool to_uci) {
+ stringstream ss;
+ ss << "Stockfish " << version << setfill('0');
- const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
- string month, day, year;
- stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
-
- ss << "Stockfish " << Version << setfill('0');
-
- if (Version.empty())
+ if (version == "dev")
{
+ ss << "-";
+ #ifdef GIT_DATE
+ ss << GIT_DATE;
+ #else
+ const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
+ string month, day, year;
+ stringstream date(__DATE__); // From compiler, format is "Sep 21 2008"
+
date >> month >> day >> year;
- ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
+ ss << year << setw(2) << setfill('0') << (1 + months.find(month) / 4) << setw(2) << setfill('0') << day;
+ #endif
+
ss << "-asn";
}
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
!( ttm
- && (pos.checkers() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
&& pos.pseudo_legal(ttm));
}
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
/// than or equal to the given threshold.
-MovePicker::MovePicker(const Position& p, Move ttm, Value th, Depth d, const CapturePieceToHistory* cph)
- : pos(p), captureHistory(cph), ttMove(ttm), threshold(th), depth(d)
+MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
+ : pos(p), captureHistory(cph), ttMove(ttm), threshold(th)
{
assert(!pos.checkers());
/// MovePicker::score() assigns a numerical value to each move in a list, used
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
-/// captures with a good history. Quiets moves are ordered using the histories.
+/// captures with a good history. Quiets moves are ordered using the history tables.
template<GenType Type>
void MovePicker::score() {
for (auto& m : *this)
if constexpr (Type == CAPTURES)
- m.value = 6 * int(PieceValue[MG][pos.piece_on(to_sq(m))])
- + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))];
+ m.value = (7 * int(PieceValue[MG][pos.piece_on(to_sq(m))])
+ + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]) / 16;
else if constexpr (Type == QUIETS)
m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)]
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
- partial_insertion_sort(cur, endMoves, -3000 * depth);
+ partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage;
goto top;
case GOOD_CAPTURE:
if (select<Next>([&](){
- return pos.see_ge(*cur, Value(-69 * cur->value / 1024)) ?
+ return pos.see_ge(*cur, Value(-cur->value)) ?
// Move losing capture to endBadCaptures to be tried later
true : (*endBadCaptures++ = *cur, false); }))
return *(cur - 1);
const CapturePieceToHistory*,
const PieceToHistory**,
Square);
- MovePicker(const Position&, Move, Value, Depth, const CapturePieceToHistory*);
+ MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false);
Bitboard threatenedPieces;
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
- int cp = std::abs(100 * v / PawnValueEg);
+ int cp = std::abs(100 * v / UCI::NormalizeToPawnValue);
if (cp >= 10000)
{
buffer[1] = '0' + cp / 10000; cp %= 10000;
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
- double cp = 1.0 * std::abs(int(v)) / PawnValueEg;
+ double cp = 1.0 * std::abs(int(v)) / UCI::NormalizeToPawnValue;
sprintf(&buffer[1], "%6.2f", cp);
}
namespace Stockfish::Eval::NNUE::Features {
- // Orient a square according to perspective (rotates by 180 for black)
- inline Square HalfKAv2_hm::orient(Color perspective, Square s, Square ksq) {
- return Square(int(s) ^ (bool(perspective) * SQ_A8) ^ ((file_of(ksq) < FILE_E) * SQ_H1));
- }
-
// Index of a feature for a given king position and another piece on some square
- inline IndexType HalfKAv2_hm::make_index(Color perspective, Square s, Piece pc, Square ksq) {
- Square o_ksq = orient(perspective, ksq, ksq);
- return IndexType(orient(perspective, s, ksq) + PieceSquareIndex[perspective][pc] + PS_NB * KingBuckets[o_ksq]);
+ template<Color Perspective>
+ inline IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) {
+ return IndexType((int(s) ^ OrientTBL[Perspective][ksq]) + PieceSquareIndex[Perspective][pc] + KingBuckets[Perspective][ksq]);
}
// Get a list of indices for active features
+ template<Color Perspective>
void HalfKAv2_hm::append_active_indices(
const Position& pos,
- Color perspective,
IndexList& active
) {
- Square ksq = pos.square<KING>(perspective);
+ Square ksq = pos.square<KING>(Perspective);
Bitboard bb = pos.pieces();
while (bb)
{
Square s = pop_lsb(bb);
- active.push_back(make_index(perspective, s, pos.piece_on(s), ksq));
+ active.push_back(make_index<Perspective>(s, pos.piece_on(s), ksq));
}
}
+ // Explicit template instantiations
+ template void HalfKAv2_hm::append_active_indices<WHITE>(const Position& pos, IndexList& active);
+ template void HalfKAv2_hm::append_active_indices<BLACK>(const Position& pos, IndexList& active);
// append_changed_indices() : get a list of indices for recently changed features
-
+ template<Color Perspective>
void HalfKAv2_hm::append_changed_indices(
Square ksq,
const DirtyPiece& dp,
- Color perspective,
IndexList& removed,
IndexList& added
) {
for (int i = 0; i < dp.dirty_num; ++i) {
if (dp.from[i] != SQ_NONE)
- removed.push_back(make_index(perspective, dp.from[i], dp.piece[i], ksq));
+ removed.push_back(make_index<Perspective>(dp.from[i], dp.piece[i], ksq));
if (dp.to[i] != SQ_NONE)
- added.push_back(make_index(perspective, dp.to[i], dp.piece[i], ksq));
+ added.push_back(make_index<Perspective>(dp.to[i], dp.piece[i], ksq));
}
}
+ // Explicit template instantiations
+ template void HalfKAv2_hm::append_changed_indices<WHITE>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
+ template void HalfKAv2_hm::append_changed_indices<BLACK>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
+
int HalfKAv2_hm::update_cost(const StateInfo* st) {
return st->dirtyPiece.dirty_num;
}
PS_B_ROOK = 7 * SQUARE_NB,
PS_W_QUEEN = 8 * SQUARE_NB,
PS_B_QUEEN = 9 * SQUARE_NB,
- PS_KING = 10 * SQUARE_NB,
- PS_NB = 11 * SQUARE_NB
+ PS_KING = 10 * SQUARE_NB,
+ PS_NB = 11 * SQUARE_NB
};
static constexpr IndexType PieceSquareIndex[COLOR_NB][PIECE_NB] = {
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE }
};
- // Orient a square according to perspective (rotates by 180 for black)
- static Square orient(Color perspective, Square s, Square ksq);
-
// Index of a feature for a given king position and another piece on some square
- static IndexType make_index(Color perspective, Square s, Piece pc, Square ksq);
+ template<Color Perspective>
+ static IndexType make_index(Square s, Piece pc, Square ksq);
public:
// Feature name
static constexpr IndexType Dimensions =
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_NB) / 2;
- static constexpr int KingBuckets[64] = {
- -1, -1, -1, -1, 31, 30, 29, 28,
- -1, -1, -1, -1, 27, 26, 25, 24,
- -1, -1, -1, -1, 23, 22, 21, 20,
- -1, -1, -1, -1, 19, 18, 17, 16,
- -1, -1, -1, -1, 15, 14, 13, 12,
- -1, -1, -1, -1, 11, 10, 9, 8,
- -1, -1, -1, -1, 7, 6, 5, 4,
- -1, -1, -1, -1, 3, 2, 1, 0
+#define B(v) (v * PS_NB)
+ static constexpr int KingBuckets[COLOR_NB][SQUARE_NB] = {
+ { B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28),
+ B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
+ B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20),
+ B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16),
+ B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12),
+ B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8),
+ B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4),
+ B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0) },
+ { B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0),
+ B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4),
+ B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8),
+ B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12),
+ B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16),
+ B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20),
+ B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
+ B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28) }
+ };
+#undef B
+
+ // Orient a square according to perspective (rotates by 180 for black)
+ static constexpr int OrientTBL[COLOR_NB][SQUARE_NB] = {
+ { SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
+ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1 },
+ { SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
+ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8 }
};
// Maximum number of simultaneously active features.
using IndexList = ValueList<IndexType, MaxActiveDimensions>;
// Get a list of indices for active features
+ template<Color Perspective>
static void append_active_indices(
const Position& pos,
- Color perspective,
IndexList& active);
// Get a list of indices for recently changed features
+ template<Color Perspective>
static void append_changed_indices(
Square ksq,
const DirtyPiece& dp,
- Color perspective,
IndexList& removed,
IndexList& added
);
// Convert input features
std::int32_t transform(const Position& pos, OutputType* output, int bucket) const {
- update_accumulator(pos, WHITE);
- update_accumulator(pos, BLACK);
+ update_accumulator<WHITE>(pos);
+ update_accumulator<BLACK>(pos);
const Color perspectives[2] = {pos.side_to_move(), ~pos.side_to_move()};
const auto& accumulation = pos.state()->accumulator.accumulation;
private:
- void update_accumulator(const Position& pos, const Color perspective) const {
+ template<Color Perspective>
+ void update_accumulator(const Position& pos) const {
// The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the
// of the estimated gain in terms of features to be added/subtracted.
StateInfo *st = pos.state(), *next = nullptr;
int gain = FeatureSet::refresh_cost(pos);
- while (st->previous && !st->accumulator.computed[perspective])
+ while (st->previous && !st->accumulator.computed[Perspective])
{
// This governs when a full feature refresh is needed and how many
// updates are better than just one full refresh.
- if ( FeatureSet::requires_refresh(st, perspective)
+ if ( FeatureSet::requires_refresh(st, Perspective)
|| (gain -= FeatureSet::update_cost(st) + 1) < 0)
break;
next = st;
st = st->previous;
}
- if (st->accumulator.computed[perspective])
+ if (st->accumulator.computed[Perspective])
{
if (next == nullptr)
return;
// accumulator. Then, we update the current accumulator (pos.state()).
// Gather all features to be updated.
- const Square ksq = pos.square<KING>(perspective);
+ const Square ksq = pos.square<KING>(Perspective);
FeatureSet::IndexList removed[2], added[2];
- FeatureSet::append_changed_indices(
- ksq, next->dirtyPiece, perspective, removed[0], added[0]);
+ FeatureSet::append_changed_indices<Perspective>(
+ ksq, next->dirtyPiece, removed[0], added[0]);
for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous)
- FeatureSet::append_changed_indices(
- ksq, st2->dirtyPiece, perspective, removed[1], added[1]);
+ FeatureSet::append_changed_indices<Perspective>(
+ ksq, st2->dirtyPiece, removed[1], added[1]);
// Mark the accumulators as computed.
- next->accumulator.computed[perspective] = true;
- pos.state()->accumulator.computed[perspective] = true;
+ next->accumulator.computed[Perspective] = true;
+ pos.state()->accumulator.computed[Perspective] = true;
// Now update the accumulators listed in states_to_update[], where the last element is a sentinel.
StateInfo *states_to_update[3] =
{
// Load accumulator
auto accTile = reinterpret_cast<vec_t*>(
- &st->accumulator.accumulation[perspective][j * TileHeight]);
+ &st->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_load(&accTile[k]);
// Store accumulator
accTile = reinterpret_cast<vec_t*>(
- &states_to_update[i]->accumulator.accumulation[perspective][j * TileHeight]);
+ &states_to_update[i]->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_store(&accTile[k], acc[k]);
}
{
// Load accumulator
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
- &st->accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]);
+ &st->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_load_psqt(&accTilePsqt[k]);
// Store accumulator
accTilePsqt = reinterpret_cast<psqt_vec_t*>(
- &states_to_update[i]->accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]);
+ &states_to_update[i]->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]);
}
#else
for (IndexType i = 0; states_to_update[i]; ++i)
{
- std::memcpy(states_to_update[i]->accumulator.accumulation[perspective],
- st->accumulator.accumulation[perspective],
+ std::memcpy(states_to_update[i]->accumulator.accumulation[Perspective],
+ st->accumulator.accumulation[Perspective],
HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k)
- states_to_update[i]->accumulator.psqtAccumulation[perspective][k] = st->accumulator.psqtAccumulation[perspective][k];
+ states_to_update[i]->accumulator.psqtAccumulation[Perspective][k] = st->accumulator.psqtAccumulation[Perspective][k];
st = states_to_update[i];
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
- st->accumulator.accumulation[perspective][j] -= weights[offset + j];
+ st->accumulator.accumulation[Perspective][j] -= weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
- st->accumulator.psqtAccumulation[perspective][k] -= psqtWeights[index * PSQTBuckets + k];
+ st->accumulator.psqtAccumulation[Perspective][k] -= psqtWeights[index * PSQTBuckets + k];
}
// Difference calculation for the activated features
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
- st->accumulator.accumulation[perspective][j] += weights[offset + j];
+ st->accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
- st->accumulator.psqtAccumulation[perspective][k] += psqtWeights[index * PSQTBuckets + k];
+ st->accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
}
}
#endif
{
// Refresh the accumulator
auto& accumulator = pos.state()->accumulator;
- accumulator.computed[perspective] = true;
+ accumulator.computed[Perspective] = true;
FeatureSet::IndexList active;
- FeatureSet::append_active_indices(pos, perspective, active);
+ FeatureSet::append_active_indices<Perspective>(pos, active);
#ifdef VECTOR
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
}
auto accTile = reinterpret_cast<vec_t*>(
- &accumulator.accumulation[perspective][j * TileHeight]);
+ &accumulator.accumulation[Perspective][j * TileHeight]);
for (unsigned k = 0; k < NumRegs; k++)
vec_store(&accTile[k], acc[k]);
}
}
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
- &accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]);
+ &accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]);
}
#else
- std::memcpy(accumulator.accumulation[perspective], biases,
+ std::memcpy(accumulator.accumulation[Perspective], biases,
HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k)
- accumulator.psqtAccumulation[perspective][k] = 0;
+ accumulator.psqtAccumulation[Perspective][k] = 0;
for (const auto index : active)
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
- accumulator.accumulation[perspective][j] += weights[offset + j];
+ accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
- accumulator.psqtAccumulation[perspective][k] += psqtWeights[index * PSQTBuckets + k];
+ accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
}
#endif
}
// Prepare the cuckoo tables
std::memset(cuckoo, 0, sizeof(cuckoo));
std::memset(cuckooMove, 0, sizeof(cuckooMove));
- int count = 0;
+ [[maybe_unused]] int count = 0;
for (Piece pc : Pieces)
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
// History and stats update bonus, based on depth
int stat_bonus(Depth d) {
- return std::min((12 * d + 282) * d - 349 , 1594);
+ return std::min((12 * d + 282) * d - 349 , 1480);
}
// Add a small random component to draw evaluations to avoid 3-fold blindness
// Send again PV info if we have a new best thread
if (bestThread != this)
- sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl;
+ sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth) << sync_endl;
sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
complexityAverage.set(155, 1);
- trend = SCORE_ZERO;
optimism[us] = optimism[~us] = VALUE_ZERO;
int searchAgainCounter = 0;
alpha = std::max(prev - delta,-VALUE_INFINITE);
beta = std::min(prev + delta, VALUE_INFINITE);
- // Adjust trend and optimism based on root move's previousScore
- int tr = 116 * prev / (std::abs(prev) + 89);
- trend = (us == WHITE ? make_score(tr, tr / 2)
- : -make_score(tr, tr / 2));
-
+ // Adjust optimism based on root move's previousScore
int opt = 118 * prev / (std::abs(prev) + 169);
optimism[ us] = Value(opt);
optimism[~us] = -optimism[us];
&& multiPV == 1
&& (bestValue <= alpha || bestValue >= beta)
&& Time.elapsed() > 3000)
- sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+ sync_cout << UCI::pv(rootPos, rootDepth) << sync_endl;
// In case of failing low/high increase aspiration window and
// re-search, otherwise exit the loop.
if ( mainThread
&& (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000))
- sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+ sync_cout << UCI::pv(rootPos, rootDepth) << sync_endl;
}
if (!Threads.stop)
else
Threads.stop = true;
}
- else if ( Threads.increaseDepth
- && !mainThread->ponder
+ else if ( !mainThread->ponder
&& Time.elapsed() > totalTime * 0.53)
- Threads.increaseDepth = false;
+ Threads.increaseDepth = false;
else
- Threads.increaseDepth = true;
+ Threads.increaseDepth = true;
}
mainThread->iterValue[iterIdx] = bestValue;
&& ttValue != VALUE_NONE // Possible in case of TT access race
&& (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
{
- // If ttMove is quiet, update move sorting heuristics on TT hit (~1 Elo)
+ // If ttMove is quiet, update move sorting heuristics on TT hit (~2 Elo)
if (ttMove)
{
if (ttValue >= beta)
{
- // Bonus for a quiet ttMove that fails high (~3 Elo)
+ // Bonus for a quiet ttMove that fails high (~2 Elo)
if (!ttCapture)
update_quiet_stats(pos, ss, ttMove, stat_bonus(depth));
- // Extra penalty for early quiet moves of the previous ply (~0 Elo)
+ // Extra penalty for early quiet moves of the previous ply (~0 Elo on STC, ~2 Elo on LTC)
if ((ss-1)->moveCount <= 2 && !priorCapture)
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1));
}
else // Fall back to (semi)classical complexity for TT hits, the NNUE complexity is lost
complexity = abs(ss->staticEval - pos.psq_eg_stm());
- // ttValue can be used as a better position evaluation (~4 Elo)
+ // ttValue can be used as a better position evaluation (~7 Elo)
if ( ttValue != VALUE_NONE
&& (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER)))
eval = ttValue;
thisThread->complexityAverage.update(complexity);
- // Use static evaluation difference to improve quiet move ordering (~3 Elo)
+ // Use static evaluation difference to improve quiet move ordering (~4 Elo)
if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture)
{
int bonus = std::clamp(-19 * int((ss-1)->staticEval + ss->staticEval), -1914, 1914);
: 168;
improving = improvement > 0;
- // Step 7. Razoring.
+ // Step 7. Razoring (~1 Elo).
// If eval is really low check with qsearch if it can exceed alpha, if it can't,
// return a fail low.
- if ( depth <= 7
- && eval < alpha - 369 - 254 * depth * depth)
+ if (eval < alpha - 369 - 254 * depth * depth)
{
value = qsearch<NonPV>(pos, ss, alpha - 1, alpha);
if (value < alpha)
return value;
}
- // Step 8. Futility pruning: child node (~25 Elo).
+ // Step 8. Futility pruning: child node (~40 Elo).
// The depth condition is important for mate finding.
if ( !ss->ttPv
&& depth < 8
&& eval < 28031) // larger than VALUE_KNOWN_WIN, but smaller than TB wins
return eval;
- // Step 9. Null move search with verification search (~22 Elo)
+ // Step 9. Null move search with verification search (~35 Elo)
if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL
&& (ss-1)->statScore < 17139
probCutBeta = beta + 191 - 54 * improving;
- // Step 10. ProbCut (~4 Elo)
+ // Step 10. ProbCut (~10 Elo)
// If we have a good enough capture and a reduced search returns a value
// much above beta, we can (almost) safely prune the previous move.
if ( !PvNode
{
assert(probCutBeta < VALUE_INFINITE);
- MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, depth - 3, &captureHistory);
+ MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
while ((move = mp.next_move()) != MOVE_NONE)
if (move != excludedMove && pos.legal(move))
}
// Step 11. If the position is not in TT, decrease depth by 3.
- // Use qsearch if depth is equal or below zero (~4 Elo)
+ // Use qsearch if depth is equal or below zero (~9 Elo)
if ( PvNode
&& !ttMove)
depth -= 3;
moves_loop: // When in check, search starts here
- // Step 12. A small Probcut idea, when we are in check (~0 Elo)
+ // Step 12. A small Probcut idea, when we are in check (~4 Elo)
probCutBeta = beta + 417;
if ( ss->inCheck
&& !PvNode
Value delta = beta - alpha;
- // Step 14. Pruning at shallow depth (~98 Elo). Depth conditions are important for mate finding.
+ // Step 14. Pruning at shallow depth (~120 Elo). Depth conditions are important for mate finding.
if ( !rootNode
&& pos.non_pawn_material(us)
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY)
{
- // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~7 Elo)
+ // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~8 Elo)
moveCountPruning = moveCount >= futility_move_count(improving, depth);
// Reduced depth of the next LMR search
if ( capture
|| givesCheck)
{
- // Futility pruning for captures (~0 Elo)
+ // Futility pruning for captures (~2 Elo)
if ( !givesCheck
&& !PvNode
&& lmrDepth < 7
+ captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 6 < alpha)
continue;
- // SEE based pruning (~9 Elo)
+ // SEE based pruning (~11 Elo)
if (!pos.see_ge(move, Value(-222) * depth))
continue;
}
history += 2 * thisThread->mainHistory[us][from_to(move)];
- // Futility pruning: parent node (~9 Elo)
+ // Futility pruning: parent node (~13 Elo)
if ( !ss->inCheck
&& lmrDepth < 13
&& ss->staticEval + 106 + 145 * lmrDepth + history / 52 <= alpha)
continue;
- // Prune moves with negative SEE (~3 Elo)
+ // Prune moves with negative SEE (~4 Elo)
if (!pos.see_ge(move, Value(-24 * lmrDepth * lmrDepth - 15 * lmrDepth)))
continue;
}
}
- // Step 15. Extensions (~66 Elo)
+ // Step 15. Extensions (~100 Elo)
// We take care to not overdo to avoid search getting stuck.
if (ss->ply < thisThread->rootDepth * 2)
{
- // Singular extension search (~58 Elo). If all moves but one fail low on a
+ // Singular extension search (~94 Elo). If all moves but one fail low on a
// search of (alpha-s, beta-s), and just one fails high on (alpha, beta),
// then that move is singular and should be extended. To verify this we do
// a reduced search on all the other moves but the ttMove and if the
// Avoid search explosion by limiting the number of double extensions
if ( !PvNode
&& value < singularBeta - 25
- && ss->doubleExtensions <= 9)
+ && ss->doubleExtensions <= 10)
+ {
extension = 2;
+ depth += depth < 12;
+ }
}
// Multi-cut pruning
&& abs(ss->staticEval) > 82)
extension = 1;
- // Quiet ttMove extensions (~0 Elo)
+ // Quiet ttMove extensions (~1 Elo)
else if ( PvNode
&& move == ttMove
&& move == ss->killers[0]
// Step 16. Make the move
pos.do_move(move, st, givesCheck);
- // Step 17. Late moves reduction / extension (LMR, ~98 Elo)
- // We use various heuristics for the sons of a node after the first son has
- // been searched. In general we would like to reduce them, but there are many
- // cases where we extend a son if it has good chances to be "interesting".
- if ( depth >= 2
- && moveCount > 1 + (PvNode && ss->ply <= 1)
- && ( !ss->ttPv
- || !capture
- || (cutNode && (ss-1)->moveCount > 1)))
- {
- Depth r = reduction(improving, depth, moveCount, delta, thisThread->rootDelta);
+ Depth r = reduction(improving, depth, moveCount, delta, thisThread->rootDelta);
- // Decrease reduction if position is or has been on the PV
- // and node is not likely to fail low. (~3 Elo)
- if ( ss->ttPv
- && !likelyFailLow)
- r -= 2;
+ // Decrease reduction if position is or has been on the PV
+ // and node is not likely to fail low. (~3 Elo)
+ if ( ss->ttPv
+ && !likelyFailLow)
+ r -= 2;
- // Decrease reduction if opponent's move count is high (~1 Elo)
- if ((ss-1)->moveCount > 7)
- r--;
+ // Decrease reduction if opponent's move count is high (~1 Elo)
+ if ((ss-1)->moveCount > 7)
+ r--;
- // Increase reduction for cut nodes (~3 Elo)
- if (cutNode)
- r += 2;
+ // Increase reduction for cut nodes (~3 Elo)
+ if (cutNode)
+ r += 2;
- // Increase reduction if ttMove is a capture (~3 Elo)
- if (ttCapture)
- r++;
+ // Increase reduction if ttMove is a capture (~3 Elo)
+ if (ttCapture)
+ r++;
- // Decrease reduction for PvNodes based on depth
- if (PvNode)
- r -= 1 + 11 / (3 + depth);
+ // Decrease reduction for PvNodes based on depth
+ if (PvNode)
+ r -= 1 + 11 / (3 + depth);
- // Decrease reduction if ttMove has been singularly extended (~1 Elo)
- if (singularQuietLMR)
- r--;
+ // Decrease reduction if ttMove has been singularly extended (~1 Elo)
+ if (singularQuietLMR)
+ r--;
- // Dicrease reduction if we move a threatened piece (~1 Elo)
- if ( depth > 9
- && (mp.threatenedPieces & from_sq(move)))
- r--;
+ // Decrease reduction if we move a threatened piece (~1 Elo)
+ if ( depth > 9
+ && (mp.threatenedPieces & from_sq(move)))
+ r--;
- // Increase reduction if next ply has a lot of fail high
- if ((ss+1)->cutoffCnt > 3 && !PvNode)
- r++;
+ // Increase reduction if next ply has a lot of fail high
+ if ((ss+1)->cutoffCnt > 3)
+ r++;
- ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
- + (*contHist[0])[movedPiece][to_sq(move)]
- + (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)]
- - 4433;
+ ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
+ + (*contHist[0])[movedPiece][to_sq(move)]
+ + (*contHist[1])[movedPiece][to_sq(move)]
+ + (*contHist[3])[movedPiece][to_sq(move)]
+ - 4433;
- // Decrease/increase reduction for moves with a good/bad history (~30 Elo)
- r -= ss->statScore / 13628;
+ // Decrease/increase reduction for moves with a good/bad history (~30 Elo)
+ r -= ss->statScore / (13000 + 4152 * (depth > 7 && depth < 19));
+ // Step 17. Late moves reduction / extension (LMR, ~117 Elo)
+ // We use various heuristics for the sons of a node after the first son has
+ // been searched. In general we would like to reduce them, but there are many
+ // cases where we extend a son if it has good chances to be "interesting".
+ if ( depth >= 2
+ && moveCount > 1 + (PvNode && ss->ply <= 1)
+ && ( !ss->ttPv
+ || !capture
+ || (cutNode && (ss-1)->moveCount > 1)))
+ {
// In general we want to cap the LMR depth search at newDepth, but when
// reduction is negative, we allow this move a limited search extension
// beyond the first move depth. This may lead to hidden double extensions.
// Do full depth search when reduced LMR search fails high
if (value > alpha && d < newDepth)
{
+ // Adjust full depth search based on LMR results - if result
+ // was good enough search deeper, if it was bad enough search shallower
const bool doDeeperSearch = value > (alpha + 64 + 11 * (newDepth - d));
- value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode);
+ const bool doEvenDeeperSearch = value > alpha + 582 && ss->doubleExtensions <= 5;
+ const bool doShallowerSearch = value < bestValue + newDepth;
+
+ ss->doubleExtensions = ss->doubleExtensions + doEvenDeeperSearch;
+
+ newDepth += doDeeperSearch - doShallowerSearch + doEvenDeeperSearch;
+
+ if (newDepth > d)
+ value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
int bonus = value > alpha ? stat_bonus(newDepth)
: -stat_bonus(newDepth);
}
}
- // Step 18. Full depth search when LMR is skipped
+ // Step 18. Full depth search when LMR is skipped. If expected reduction is high, reduce its depth by 1.
else if (!PvNode || moveCount > 1)
{
- value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
+ value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth - (r > 4), !cutNode);
}
// For PV nodes only, do a full PV search on the first move or after a fail
// PV move or new best move?
if (moveCount == 1 || value > alpha)
{
- rm.score = value;
+ rm.score = rm.uciScore = value;
rm.selDepth = thisThread->selDepth;
+ rm.scoreLowerbound = rm.scoreUpperbound = false;
+
+ if (value >= beta) {
+ rm.scoreLowerbound = true;
+ rm.uciScore = beta;
+ }
+ else if (value <= alpha) {
+ rm.scoreUpperbound = true;
+ rm.uciScore = alpha;
+ }
rm.pv.resize(1);
assert((ss+1)->pv);
&& depth < 6
&& beta < VALUE_KNOWN_WIN
&& alpha > -VALUE_KNOWN_WIN)
- depth -= 1;
+ depth -= 1;
assert(depth > 0);
}
}
}
}
- else
- ss->cutoffCnt = 0;
// If the move is worse than some previously searched move, remember it to update its stats later
quietsSearched, quietCount, capturesSearched, captureCount, depth);
// Bonus for prior countermove that caused the fail low
- else if ( (depth >= 5 || PvNode)
+ else if ( (depth >= 5 || PvNode || bestValue < alpha - 62 * depth)
&& !priorCapture)
{
//Assign extra bonus if current node is PvNode or cutNode
//or fail low was really bad
bool extraBonus = PvNode
- || cutNode
- || bestValue < alpha - 62 * depth;
+ || cutNode;
- update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus));
+ bool doubleExtraBonus = extraBonus && bestValue < alpha - 85 * depth;
+
+ update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus + doubleExtraBonus));
}
if (PvNode)
if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE)
ss->staticEval = bestValue = evaluate(pos);
- // ttValue can be used as a better position evaluation (~7 Elo)
+ // ttValue can be used as a better position evaluation (~13 Elo)
if ( ttValue != VALUE_NONE
&& (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER)))
bestValue = ttValue;
moveCount++;
- // Futility pruning and moveCount pruning (~5 Elo)
+ // Futility pruning and moveCount pruning (~10 Elo)
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !givesCheck
&& to_sq(move) != prevSq
&& futilityBase > -VALUE_KNOWN_WIN
&& type_of(move) != PROMOTION)
{
-
if (moveCount > 2)
continue;
[pos.moved_piece(move)]
[to_sq(move)];
- // Continuation history based pruning (~2 Elo)
+ // Continuation history based pruning (~3 Elo)
if ( !capture
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < 0
&& (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < 0)
continue;
- // movecount pruning for quiet check evasions
+ // We prune after 2nd quiet check evasion where being 'in check' is implicitly checked through the counter
+ // and being a 'quiet' apart from being a tt move is assumed after an increment because captures are pushed ahead.
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
- && quietCheckEvasions > 1
- && !capture
- && ss->inCheck)
- continue;
+ && quietCheckEvasions > 1)
+ break;
quietCheckEvasions += !capture && ss->inCheck;
/// UCI::pv() formats PV information according to the UCI protocol. UCI requires
/// that all (if any) unsearched PV lines are sent using a previous search score.
-string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
+string UCI::pv(const Position& pos, Depth depth) {
std::stringstream ss;
TimePoint elapsed = Time.elapsed() + 1;
continue;
Depth d = updated ? depth : std::max(1, depth - 1);
- Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore;
+ Value v = updated ? rootMoves[i].uciScore : rootMoves[i].previousScore;
if (v == -VALUE_INFINITE)
v = VALUE_ZERO;
if (Options["UCI_ShowWDL"])
ss << UCI::wdl(v, pos.game_ply());
- if (!tb && i == pvIdx)
- ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
+ if (i == pvIdx && !tb && updated) // tablebase- and previous-scores are exact
+ ss << (rootMoves[i].scoreLowerbound ? " lowerbound" : (rootMoves[i].scoreUpperbound ? " upperbound" : ""));
ss << " nodes " << nodesSearched
<< " nps " << nodesSearched * 1000 / elapsed
Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE;
+ Value uciScore = -VALUE_INFINITE;
+ bool scoreLowerbound = false;
+ bool scoreUpperbound = false;
int selDepth = 0;
int tbRank = 0;
Value tbScore;
namespace {
constexpr int TBPIECES = 7; // Max number of supported pieces
+constexpr int MAX_DTZ = 1 << 18; // Max DTZ supported, large enough to deal with the syzygy TB limit.
enum { BigEndian, LittleEndian };
enum TBType { WDL, DTZ }; // Used as template parameter
// Check whether a position was repeated since the last zeroing move.
bool rep = pos.has_repeated();
- int dtz, bound = Options["Syzygy50MoveRule"] ? 900 : 1;
+ int dtz, bound = Options["Syzygy50MoveRule"] ? (MAX_DTZ - 100) : 1;
// Probe and rank each move
for (auto& m : rootMoves)
// Better moves are ranked higher. Certain wins are ranked equally.
// Losing moves are ranked equally unless a 50-move draw is in sight.
- int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? 1000 : 1000 - (dtz + cnt50))
- : dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -1000 : -1000 + (-dtz + cnt50))
+ int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? MAX_DTZ : MAX_DTZ - (dtz + cnt50))
+ : dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -MAX_DTZ : -MAX_DTZ + (-dtz + cnt50))
: 0;
m.tbRank = r;
// 1 cp to cursed wins and let it grow to 49 cp as the positions gets
// closer to a real win.
m.tbScore = r >= bound ? VALUE_MATE - MAX_PLY - 1
- : r > 0 ? Value((std::max( 3, r - 800) * int(PawnValueEg)) / 200)
+ : r > 0 ? Value((std::max( 3, r - (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
: r == 0 ? VALUE_DRAW
- : r > -bound ? Value((std::min(-3, r + 800) * int(PawnValueEg)) / 200)
+ : r > -bound ? Value((std::min(-3, r + (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
: -VALUE_MATE + MAX_PLY + 1;
}
// A return value false indicates that not all probes were successful.
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
- static const int WDL_to_rank[] = { -1000, -899, 0, 899, 1000 };
+ static const int WDL_to_rank[] = { -MAX_DTZ, -MAX_DTZ + 101, 0, MAX_DTZ - 101, MAX_DTZ };
ProbeState result;
StateInfo st;
WDLDraw = 0, // Draw
WDLCursedWin = 1, // Win, but draw under 50-move rule
WDLWin = 2, // Win
-
- WDLScoreNone = -1000
};
// Possible states after a probing operation
minScore = std::min(minScore, th->rootMoves[0].score);
// Vote according to score and depth, and select the best thread
+ auto thread_value = [minScore](Thread* th) {
+ return (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
+ };
+
for (Thread* th : *this)
- {
- votes[th->rootMoves[0].pv[0]] +=
- (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
+ votes[th->rootMoves[0].pv[0]] += thread_value(th);
+ for (Thread* th : *this)
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY)
{
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY
&& ( votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]
|| ( votes[th->rootMoves[0].pv[0]] == votes[bestThread->rootMoves[0].pv[0]]
- && th->rootMoves[0].pv.size() > bestThread->rootMoves[0].pv.size()))))
+ && thread_value(th) * int(th->rootMoves[0].pv.size() > 2)
+ > thread_value(bestThread) * int(bestThread->rootMoves[0].pv.size() > 2)))))
bestThread = th;
- }
return bestThread;
}
ButterflyHistory mainHistory;
CapturePieceToHistory captureHistory;
ContinuationHistory continuationHistory[2][2];
- Score trend;
};
// game time for the current move, so also cap to 20% of available game time.
if (limits.movestogo == 0)
{
- optScale = std::min(0.0084 + std::pow(ply + 3.0, 0.5) * 0.0042,
+ optScale = std::min(0.0120 + std::pow(ply + 3.0, 0.45) * 0.0039,
0.2 * limits.time[us] / double(timeLeft))
* optExtra;
maxScale = std::min(7.0, 4.0 + ply / 12.0);
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY,
+ // In the code, we make the assumption that these values
+ // are such that non_pawn_material() can be used to uniquely
+ // identify the material on the board.
PawnValueMg = 126, PawnValueEg = 208,
KnightValueMg = 781, KnightValueEg = 854,
BishopValueMg = 825, BishopValueEg = 915,
// The coefficients of a third-order polynomial fit is based on the fishtest data
// for two parameters that need to transform eval to the argument of a logistic
// function.
- double as[] = { 0.50379905, -4.12755858, 18.95487051, 152.00733652};
- double bs[] = {-1.71790378, 10.71543602, -17.05515898, 41.15680404};
+ constexpr double as[] = { -0.58270499, 2.68512549, 15.24638015, 344.49745382};
+ constexpr double bs[] = { -2.65734562, 15.96509799, -20.69040836, 73.61029937 };
+
+ // Enforce that NormalizeToPawnValue corresponds to a 50% win rate at ply 64
+ static_assert(UCI::NormalizeToPawnValue == int(as[0] + as[1] + as[2] + as[3]));
+
double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3];
double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
// Transform the eval to centipawns with limited range
- double x = std::clamp(double(100 * v) / PawnValueEg, -2000.0, 2000.0);
+ double x = std::clamp(double(v), -4000.0, 4000.0);
// Return the win rate in per mille units rounded to the nearest value
return int(0.5 + 1000 / (1 + std::exp((a - x) / b)));
stringstream ss;
if (abs(v) < VALUE_MATE_IN_MAX_PLY)
- ss << "cp " << v * 100 / PawnValueEg;
+ ss << "cp " << v * 100 / NormalizeToPawnValue;
else
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
namespace UCI {
+// Normalizes the internal value as reported by evaluate or search
+// to the UCI centipawn result used in output. This value is derived from
+// the win_rate_model() such that Stockfish outputs an advantage of
+// "100 centipawns" for a position if the engine has a 50% probability to win
+// from this position in selfplay at fishtest LTC time control.
+const int NormalizeToPawnValue = 361;
+
class Option;
/// Define a custom comparator, because the UCI options should be case-insensitive
std::string value(Value v);
std::string square(Square s);
std::string move(Move m, bool chess960);
-std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
+std::string pv(const Position& pos, Depth depth);
std::string wdl(Value v, int ply);
Move to_move(const Position& pos, std::string& str);