mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-08 23:22:40 +01:00
DroidFish: Implemented DTZ/WDL tablebase hints in the GUI when only syzygy tablebases are available.
This commit is contained in:
@@ -10,3 +10,5 @@ include $(BUILD_SHARED_LIBRARY)
|
|||||||
include jni/stockfish/Android.mk
|
include jni/stockfish/Android.mk
|
||||||
|
|
||||||
include jni/gtb/Android.mk
|
include jni/gtb/Android.mk
|
||||||
|
|
||||||
|
include jni/rtb/Android.mk
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
APP_ABI := armeabi armeabi-v7a x86 mips
|
APP_ABI := armeabi armeabi-v7a x86 mips
|
||||||
APP_STL := gnustl_static
|
APP_STL := gnustl_static
|
||||||
APP_OPTIM := release
|
APP_OPTIM := release
|
||||||
|
NDK_TOOLCHAIN_VERSION := 4.8
|
||||||
|
|||||||
17
DroidFish/jni/rtb/Android.mk
Normal file
17
DroidFish/jni/rtb/Android.mk
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL_MODULE := rtb
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
bitBoard.cpp material.cpp moveGen.cpp position.cpp rtb-probe.cpp tbprobe.cpp \
|
||||||
|
RtbProbe.cpp
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := --std=c++11 \
|
||||||
|
-I $(LOCAL_PATH)/sysport/ -I -DNDEBUG -Wall \
|
||||||
|
-mandroid -DTARGET_OS=android -D__ANDROID__ \
|
||||||
|
-D__STDC_INT64__ -D_GLIBCXX_USE_C99_STDINT_TR1 \
|
||||||
|
-D_GLIBCXX_HAS_GTHREADS -D_GLIBCXX__PTHREADS
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
82
DroidFish/jni/rtb/RtbProbe.cpp
Normal file
82
DroidFish/jni/rtb/RtbProbe.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
DroidFish - An Android chess program.
|
||||||
|
Copyright (C) 2011-2012 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "RtbProbe.h"
|
||||||
|
#include "tbprobe.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
static bool initOk = false;
|
||||||
|
|
||||||
|
JNIEXPORT jboolean
|
||||||
|
JNICALL Java_org_petero_droidfish_gtb_RtbProbe_init(
|
||||||
|
JNIEnv* env, jclass cls, jstring jTbPath)
|
||||||
|
{
|
||||||
|
initOk = false;
|
||||||
|
const char* tbPath = (*env).GetStringUTFChars(jTbPath, NULL);
|
||||||
|
if (!tbPath)
|
||||||
|
return false;
|
||||||
|
std::string rtbPath(tbPath);
|
||||||
|
(*env).ReleaseStringUTFChars(jTbPath, tbPath);
|
||||||
|
|
||||||
|
TBProbe::initialize(rtbPath);
|
||||||
|
initOk = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void
|
||||||
|
JNICALL Java_org_petero_droidfish_gtb_RtbProbe_probe(
|
||||||
|
JNIEnv* env, jobject ths, jbyteArray jSquares, jboolean wtm,
|
||||||
|
jint epSq, jint castleMask,
|
||||||
|
jint halfMoveClock, jint fullMoveCounter,
|
||||||
|
jintArray result)
|
||||||
|
{
|
||||||
|
if ((*env).GetArrayLength(result) < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
jint res[2];
|
||||||
|
res[0] = 1000;
|
||||||
|
res[1] = 1000;
|
||||||
|
(*env).SetIntArrayRegion(result, 0, 2, res);
|
||||||
|
|
||||||
|
if (!initOk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int len = (*env).GetArrayLength(jSquares);
|
||||||
|
if (len != 64)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Position pos;
|
||||||
|
jbyte* jbPtr = (*env).GetByteArrayElements(jSquares, NULL);
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
pos.setPiece(i, jbPtr[i]);
|
||||||
|
(*env).ReleaseByteArrayElements(jSquares, jbPtr, 0);
|
||||||
|
|
||||||
|
pos.setWhiteMove(wtm);
|
||||||
|
pos.setEpSquare(epSq);
|
||||||
|
pos.setCastleMask(castleMask);
|
||||||
|
pos.setHalfMoveClock(halfMoveClock);
|
||||||
|
pos.setFullMoveCounter(fullMoveCounter);
|
||||||
|
|
||||||
|
int score;
|
||||||
|
if (TBProbe::rtbProbeWDL(pos, score))
|
||||||
|
res[0] = score;
|
||||||
|
if (TBProbe::rtbProbeDTZ(pos, score))
|
||||||
|
res[1] = score;
|
||||||
|
|
||||||
|
(*env).SetIntArrayRegion(result, 0, 2, res);
|
||||||
|
}
|
||||||
29
DroidFish/jni/rtb/RtbProbe.h
Normal file
29
DroidFish/jni/rtb/RtbProbe.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class org_petero_droidfish_gtb_RtbProbe */
|
||||||
|
|
||||||
|
#ifndef _Included_org_petero_droidfish_gtb_RtbProbe
|
||||||
|
#define _Included_org_petero_droidfish_gtb_RtbProbe
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: org_petero_droidfish_gtb_RtbProbe
|
||||||
|
* Method: probe
|
||||||
|
* Signature: ([BZIIII[I)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_org_petero_droidfish_gtb_RtbProbe_probe
|
||||||
|
(JNIEnv *, jobject, jbyteArray, jboolean, jint, jint, jint, jint, jintArray);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_petero_droidfish_gtb_RtbProbe
|
||||||
|
* Method: init
|
||||||
|
* Signature: (Ljava/lang/String;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL Java_org_petero_droidfish_gtb_RtbProbe_init
|
||||||
|
(JNIEnv *, jclass, jstring);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
364
DroidFish/jni/rtb/bitBoard.cpp
Normal file
364
DroidFish/jni/rtb/bitBoard.cpp
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bitBoard.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bitBoard.hpp"
|
||||||
|
#include "position.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
U64 BitBoard::kingAttacks[64];
|
||||||
|
U64 BitBoard::knightAttacks[64];
|
||||||
|
U64 BitBoard::wPawnAttacks[64];
|
||||||
|
U64 BitBoard::bPawnAttacks[64];
|
||||||
|
|
||||||
|
const U64 BitBoard::maskFile[8] = {
|
||||||
|
0x0101010101010101ULL,
|
||||||
|
0x0202020202020202ULL,
|
||||||
|
0x0404040404040404ULL,
|
||||||
|
0x0808080808080808ULL,
|
||||||
|
0x1010101010101010ULL,
|
||||||
|
0x2020202020202020ULL,
|
||||||
|
0x4040404040404040ULL,
|
||||||
|
0x8080808080808080ULL
|
||||||
|
};
|
||||||
|
|
||||||
|
U64 BitBoard::epMaskW[8];
|
||||||
|
U64 BitBoard::epMaskB[8];
|
||||||
|
|
||||||
|
const U64 BitBoard::maskRow1;
|
||||||
|
const U64 BitBoard::maskRow2;
|
||||||
|
const U64 BitBoard::maskRow3;
|
||||||
|
const U64 BitBoard::maskRow4;
|
||||||
|
const U64 BitBoard::maskRow5;
|
||||||
|
const U64 BitBoard::maskRow6;
|
||||||
|
const U64 BitBoard::maskRow7;
|
||||||
|
const U64 BitBoard::maskRow8;
|
||||||
|
const U64 BitBoard::maskRow1Row8;
|
||||||
|
const U64 BitBoard::maskDarkSq;
|
||||||
|
const U64 BitBoard::maskLightSq;
|
||||||
|
const U64 BitBoard::maskCorners;
|
||||||
|
|
||||||
|
U64* BitBoard::rTables[64];
|
||||||
|
U64 BitBoard::rMasks[64];
|
||||||
|
int BitBoard::rBits[64] = { 12, 11, 11, 11, 11, 11, 11, 12,
|
||||||
|
11, 10, 10, 11, 10, 10, 10, 11,
|
||||||
|
11, 10, 10, 10, 10, 10, 10, 11,
|
||||||
|
11, 10, 10, 10, 10, 10, 10, 11,
|
||||||
|
11, 10, 10, 10, 10, 10, 10, 11,
|
||||||
|
11, 10, 10, 11, 10, 10, 10, 11,
|
||||||
|
10, 9, 9, 9, 9, 9, 10, 10,
|
||||||
|
11, 10, 10, 10, 10, 11, 10, 11 };
|
||||||
|
const U64 BitBoard::rMagics[64] = {
|
||||||
|
0x19a80065ff2bffffULL, 0x3fd80075ffebffffULL, 0x4010000df6f6fffeULL, 0x0050001faffaffffULL,
|
||||||
|
0x0050028004ffffb0ULL, 0x7f600280089ffff1ULL, 0x7f5000b0029ffffcULL, 0x5b58004848a7fffaULL,
|
||||||
|
0x002a90005547ffffULL, 0x000050007f13ffffULL, 0x007fa0006013ffffULL, 0x006a9005656fffffULL,
|
||||||
|
0x007f600f600affffULL, 0x007ec007e6bfffe2ULL, 0x007ec003eebffffbULL, 0x0071d002382fffdaULL,
|
||||||
|
0x009f803000e7fffaULL, 0x00680030008bffffULL, 0x00606060004f3ffcULL, 0x001a00600bff9ffdULL,
|
||||||
|
0x000d006005ff9fffULL, 0x0001806003005fffULL, 0x00000300040bfffaULL, 0x000192500065ffeaULL,
|
||||||
|
0x00fff112d0006800ULL, 0x007ff037d000c004ULL, 0x003fd062001a3ff8ULL, 0x00087000600e1ffcULL,
|
||||||
|
0x000fff0100100804ULL, 0x0007ff0100080402ULL, 0x0003ffe0c0060003ULL, 0x0001ffd53000d300ULL,
|
||||||
|
0x00fffd3000600061ULL, 0x007fff7f95900040ULL, 0x003fff8c00600060ULL, 0x001ffe2587a01860ULL,
|
||||||
|
0x000fff3fbf40180cULL, 0x0007ffc73f400c06ULL, 0x0003ff86d2c01405ULL, 0x0001fffeaa700100ULL,
|
||||||
|
0x00fffdfdd8005000ULL, 0x007fff80ebffb000ULL, 0x003fffdf603f6000ULL, 0x001fffe050405000ULL,
|
||||||
|
0x000fff400700c00cULL, 0x0007ff6007bf600aULL, 0x0003ffeebffec005ULL, 0x0001fffdf3feb001ULL,
|
||||||
|
0x00ffff39ff484a00ULL, 0x007fff3fff486300ULL, 0x003fff99ffac2e00ULL, 0x001fff31ff2a6a00ULL,
|
||||||
|
0x000fff19ff15b600ULL, 0x0007fff5fff28600ULL, 0x0003fffddffbfee0ULL, 0x0001fff5f63c96a0ULL,
|
||||||
|
0x00ffff5dff65cfb6ULL, 0x007fffbaffd1c5aeULL, 0x003fff71ff6cbceaULL, 0x001fffd9ffd4756eULL,
|
||||||
|
0x000ffff5fff338e6ULL, 0x0007fffdfffe24f6ULL, 0x0003ffef27eebe74ULL, 0x0001ffff23ff605eULL
|
||||||
|
};
|
||||||
|
|
||||||
|
U64* BitBoard::bTables[64];
|
||||||
|
U64 BitBoard::bMasks[64];
|
||||||
|
const int BitBoard::bBits[64] = { 5, 4, 5, 5, 5, 5, 4, 5,
|
||||||
|
4, 4, 5, 5, 5, 5, 4, 4,
|
||||||
|
4, 4, 7, 7, 7, 7, 4, 4,
|
||||||
|
5, 5, 7, 9, 9, 7, 5, 5,
|
||||||
|
5, 5, 7, 9, 9, 7, 5, 5,
|
||||||
|
4, 4, 7, 7, 7, 7, 4, 4,
|
||||||
|
4, 4, 5, 5, 5, 5, 4, 4,
|
||||||
|
5, 4, 5, 5, 5, 5, 4, 5 };
|
||||||
|
const U64 BitBoard::bMagics[64] = {
|
||||||
|
0x0006eff5367ff600ULL, 0x00345835ba77ff2bULL, 0x00145f68a3f5dab6ULL, 0x003a1863fb56f21dULL,
|
||||||
|
0x0012eb6bfe9d93cdULL, 0x000d82827f3420d6ULL, 0x00074bcd9c7fec97ULL, 0x000034fe99f9ffffULL,
|
||||||
|
0x0000746f8d6717f6ULL, 0x00003acb32e1a3f7ULL, 0x0000185daf1ffb8aULL, 0x00003a1867f17067ULL,
|
||||||
|
0x0000038ee0ccf92eULL, 0x000002a2b7ff926eULL, 0x000006c9aa93ff14ULL, 0x00000399b5e5bf87ULL,
|
||||||
|
0x00400f342c951ffcULL, 0x0020230579ed8ff0ULL, 0x007b008a0077dbfdULL, 0x001d00010c13fd46ULL,
|
||||||
|
0x00040022031c1ffbULL, 0x000fa00fd1cbff79ULL, 0x000400a4bc9affdfULL, 0x000200085e9cffdaULL,
|
||||||
|
0x002a14560a3dbfbdULL, 0x000a0a157b9eafd1ULL, 0x00060600fd002ffaULL, 0x004006000c009010ULL,
|
||||||
|
0x001a002042008040ULL, 0x001a00600fd1ffc0ULL, 0x000d0ace50bf3f8dULL, 0x000183a48434efd1ULL,
|
||||||
|
0x001fbd7670982a0dULL, 0x000fe24301d81a0fULL, 0x0007fbf82f040041ULL, 0x000040c800008200ULL,
|
||||||
|
0x007fe17018086006ULL, 0x003b7ddf0ffe1effULL, 0x001f92f861df4a0aULL, 0x000fd713ad98a289ULL,
|
||||||
|
0x000fd6aa751e400cULL, 0x0007f2a63ae9600cULL, 0x0003ff7dfe0e3f00ULL, 0x000003fd2704ce04ULL,
|
||||||
|
0x00007fc421601d40ULL, 0x007fff5f70900120ULL, 0x003fa66283556403ULL, 0x001fe31969aec201ULL,
|
||||||
|
0x0007fdfc18ac14bbULL, 0x0003fb96fb568a47ULL, 0x000003f72ea4954dULL, 0x00000003f8dc0383ULL,
|
||||||
|
0x0000007f3a814490ULL, 0x00007dc5c9cf62a6ULL, 0x007f23d3342897acULL, 0x003fee36eee1565cULL,
|
||||||
|
0x0003ff3e99fcccc7ULL, 0x000003ecfcfac5feULL, 0x00000003f97f7453ULL, 0x0000000003f8dc03ULL,
|
||||||
|
0x000000007efa8146ULL, 0x0000007ed3e2ef60ULL, 0x00007f47243adcd6ULL, 0x007fb65afabfb3b5ULL
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<U64> BitBoard::tableData;
|
||||||
|
|
||||||
|
const S8 BitBoard::dirTable[] = {
|
||||||
|
-9, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, -7,
|
||||||
|
0, 0, -9, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, -7, 0,
|
||||||
|
0, 0, 0, -9, 0, 0, 0, 0, -8, 0, 0, 0, 0, -7, 0, 0,
|
||||||
|
0, 0, 0, 0, -9, 0, 0, 0, -8, 0, 0, 0, -7, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, -9, 0, 0, -8, 0, 0, -7, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, -9,-17, -8,-15, -7, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,-10, -9, -8, -7, -6, 0, 0, 0, 0, 0,
|
||||||
|
0, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 7, 15, 8, 17, 9, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0,
|
||||||
|
0, 0, 0, 7, 0, 0, 0, 0, 8, 0, 0, 0, 0, 9, 0, 0,
|
||||||
|
0, 0, 7, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 9, 0,
|
||||||
|
0, 7, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9
|
||||||
|
};
|
||||||
|
|
||||||
|
const S8 BitBoard::kingDistTable[] = {
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
0, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||||
|
0, 7, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 2, 1, 1, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 2, 1, 1, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7,
|
||||||
|
0, 7, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7,
|
||||||
|
0, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||||
|
0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
|
||||||
|
};
|
||||||
|
|
||||||
|
const S8 BitBoard::taxiDistTable[] = {
|
||||||
|
14,13,12,11,10, 9, 8, 7, 8, 9,10,11,12,13,14,
|
||||||
|
0,13,12,11,10, 9, 8, 7, 6, 7, 8, 9,10,11,12,13,
|
||||||
|
0,12,11,10, 9, 8, 7, 6, 5, 6, 7, 8, 9,10,11,12,
|
||||||
|
0,11,10, 9, 8, 7, 6, 5, 4, 5, 6, 7, 8, 9,10,11,
|
||||||
|
0,10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7, 8, 9,10,
|
||||||
|
0, 9, 8, 7, 6, 5, 4, 3, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
|
0, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||||
|
0, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||||
|
0, 9, 8, 7, 6, 5, 4, 3, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
|
0,10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7, 8, 9,10,
|
||||||
|
0,11,10, 9, 8, 7, 6, 5, 4, 5, 6, 7, 8, 9,10,11,
|
||||||
|
0,12,11,10, 9, 8, 7, 6, 5, 6, 7, 8, 9,10,11,12,
|
||||||
|
0,13,12,11,10, 9, 8, 7, 6, 7, 8, 9,10,11,12,13,
|
||||||
|
0,14,13,12,11,10, 9, 8, 7, 8, 9,10,11,12,13,14
|
||||||
|
};
|
||||||
|
|
||||||
|
const int BitBoard::trailingZ[64] = {
|
||||||
|
63, 0, 58, 1, 59, 47, 53, 2,
|
||||||
|
60, 39, 48, 27, 54, 33, 42, 3,
|
||||||
|
61, 51, 37, 40, 49, 18, 28, 20,
|
||||||
|
55, 30, 34, 11, 43, 14, 22, 4,
|
||||||
|
62, 57, 46, 52, 38, 26, 32, 41,
|
||||||
|
50, 36, 17, 19, 29, 10, 13, 21,
|
||||||
|
56, 45, 25, 31, 35, 16, 9, 12,
|
||||||
|
44, 24, 15, 8, 23, 7, 6, 5
|
||||||
|
};
|
||||||
|
|
||||||
|
U64 BitBoard::squaresBetween[64][64];
|
||||||
|
|
||||||
|
static U64 createPattern(int i, U64 mask) {
|
||||||
|
U64 ret = 0ULL;
|
||||||
|
for (int j = 0; ; j++) {
|
||||||
|
U64 nextMask = mask & (mask - 1);
|
||||||
|
U64 bit = mask ^ nextMask;
|
||||||
|
if ((i & (1ULL << j)) != 0)
|
||||||
|
ret |= bit;
|
||||||
|
mask = nextMask;
|
||||||
|
if (mask == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 addRay(U64 mask, int x, int y, int dx, int dy,
|
||||||
|
U64 occupied, bool inner) {
|
||||||
|
int lo = inner ? 1 : 0;
|
||||||
|
int hi = inner ? 6 : 7;
|
||||||
|
while (true) {
|
||||||
|
if (dx != 0) {
|
||||||
|
x += dx; if ((x < lo) || (x > hi)) break;
|
||||||
|
}
|
||||||
|
if (dy != 0) {
|
||||||
|
y += dy; if ((y < lo) || (y > hi)) break;
|
||||||
|
}
|
||||||
|
int sq = Position::getSquare(x, y);
|
||||||
|
mask |= 1ULL << sq;
|
||||||
|
if ((occupied & (1ULL << sq)) != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 addRookRays(int x, int y, U64 occupied, bool inner) {
|
||||||
|
U64 mask = 0;
|
||||||
|
mask = addRay(mask, x, y, 1, 0, occupied, inner);
|
||||||
|
mask = addRay(mask, x, y, -1, 0, occupied, inner);
|
||||||
|
mask = addRay(mask, x, y, 0, 1, occupied, inner);
|
||||||
|
mask = addRay(mask, x, y, 0, -1, occupied, inner);
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 addBishopRays(int x, int y, U64 occupied, bool inner) {
|
||||||
|
U64 mask = 0;
|
||||||
|
mask = addRay(mask, x, y, 1, 1, occupied, inner);
|
||||||
|
mask = addRay(mask, x, y, -1, -1, occupied, inner);
|
||||||
|
mask = addRay(mask, x, y, 1, -1, occupied, inner);
|
||||||
|
mask = addRay(mask, x, y, -1, 1, occupied, inner);
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StaticInitializer<BitBoard> bbInit;
|
||||||
|
|
||||||
|
void
|
||||||
|
BitBoard::staticInitialize() {
|
||||||
|
for (int f = 0; f < 8; f++) {
|
||||||
|
U64 m = 0;
|
||||||
|
if (f > 0) m |= 1ULL << Position::getSquare(f-1, 3);
|
||||||
|
if (f < 7) m |= 1ULL << Position::getSquare(f+1, 3);
|
||||||
|
epMaskW[f] = m;
|
||||||
|
|
||||||
|
m = 0;
|
||||||
|
if (f > 0) m |= 1ULL << Position::getSquare(f-1, 4);
|
||||||
|
if (f < 7) m |= 1ULL << Position::getSquare(f+1, 4);
|
||||||
|
epMaskB[f] = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute king attacks
|
||||||
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
|
U64 m = 1ULL << sq;
|
||||||
|
U64 mask = (((m >> 1) | (m << 7) | (m >> 9)) & maskAToGFiles) |
|
||||||
|
(((m << 1) | (m << 9) | (m >> 7)) & maskBToHFiles) |
|
||||||
|
(m << 8) | (m >> 8);
|
||||||
|
kingAttacks[sq] = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute knight attacks
|
||||||
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
|
U64 m = 1ULL << sq;
|
||||||
|
U64 mask = (((m << 6) | (m >> 10)) & maskAToFFiles) |
|
||||||
|
(((m << 15) | (m >> 17)) & maskAToGFiles) |
|
||||||
|
(((m << 17) | (m >> 15)) & maskBToHFiles) |
|
||||||
|
(((m << 10) | (m >> 6)) & maskCToHFiles);
|
||||||
|
knightAttacks[sq] = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute pawn attacks
|
||||||
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
|
U64 m = 1ULL << sq;
|
||||||
|
U64 mask = ((m << 7) & maskAToGFiles) | ((m << 9) & maskBToHFiles);
|
||||||
|
wPawnAttacks[sq] = mask;
|
||||||
|
mask = ((m >> 9) & maskAToGFiles) | ((m >> 7) & maskBToHFiles);
|
||||||
|
bPawnAttacks[sq] = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rook magics
|
||||||
|
int rTableSize = 0;
|
||||||
|
for (int sq = 0; sq < 64; sq++)
|
||||||
|
rTableSize += 1 << rBits[sq];
|
||||||
|
int bTableSize = 0;
|
||||||
|
for (int sq = 0; sq < 64; sq++)
|
||||||
|
bTableSize += 1 << bBits[sq];
|
||||||
|
tableData.resize(rTableSize + bTableSize);
|
||||||
|
|
||||||
|
int tableUsed = 0;
|
||||||
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
|
int x = Position::getX(sq);
|
||||||
|
int y = Position::getY(sq);
|
||||||
|
rMasks[sq] = addRookRays(x, y, 0ULL, true);
|
||||||
|
int tableSize = 1 << rBits[sq];
|
||||||
|
U64* table = &tableData[tableUsed];
|
||||||
|
tableUsed += tableSize;
|
||||||
|
const U64 unInit = 0xffffffffffffffffULL;
|
||||||
|
for (int i = 0; i < tableSize; i++) table[i] = unInit;
|
||||||
|
int nPatterns = 1 << BitBoard::bitCount(rMasks[sq]);
|
||||||
|
for (int i = 0; i < nPatterns; i++) {
|
||||||
|
U64 p = createPattern(i, rMasks[sq]);
|
||||||
|
int entry = (int)((p * rMagics[sq]) >> (64 - rBits[sq]));
|
||||||
|
U64 atks = addRookRays(x, y, p, false);
|
||||||
|
if (table[entry] == unInit) {
|
||||||
|
table[entry] = atks;
|
||||||
|
} else {
|
||||||
|
assert(table[entry] == atks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rTables[sq] = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bishop magics
|
||||||
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
|
int x = Position::getX(sq);
|
||||||
|
int y = Position::getY(sq);
|
||||||
|
bMasks[sq] = addBishopRays(x, y, 0ULL, true);
|
||||||
|
int tableSize = 1 << bBits[sq];
|
||||||
|
U64* table = &tableData[tableUsed];
|
||||||
|
tableUsed += tableSize;
|
||||||
|
const U64 unInit = 0xffffffffffffffffULL;
|
||||||
|
for (int i = 0; i < tableSize; i++) table[i] = unInit;
|
||||||
|
int nPatterns = 1 << BitBoard::bitCount(bMasks[sq]);
|
||||||
|
for (int i = 0; i < nPatterns; i++) {
|
||||||
|
U64 p = createPattern(i, bMasks[sq]);
|
||||||
|
int entry = (int)((p * bMagics[sq]) >> (64 - bBits[sq]));
|
||||||
|
U64 atks = addBishopRays(x, y, p, false);
|
||||||
|
if (table[entry] == unInit) {
|
||||||
|
table[entry] = atks;
|
||||||
|
} else {
|
||||||
|
assert(table[entry] == atks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bTables[sq] = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
// squaresBetween
|
||||||
|
for (int sq1 = 0; sq1 < 64; sq1++) {
|
||||||
|
for (int j = 0; j < 64; j++)
|
||||||
|
squaresBetween[sq1][j] = 0;
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
|
if ((dx == 0) && (dy == 0))
|
||||||
|
continue;
|
||||||
|
U64 m = 0;
|
||||||
|
int x = Position::getX(sq1);
|
||||||
|
int y = Position::getY(sq1);
|
||||||
|
while (true) {
|
||||||
|
x += dx; y += dy;
|
||||||
|
if ((x < 0) || (x > 7) || (y < 0) || (y > 7))
|
||||||
|
break;
|
||||||
|
int sq2 = Position::getSquare(x, y);
|
||||||
|
squaresBetween[sq1][sq2] = m;
|
||||||
|
m |= 1ULL << sq2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
132
DroidFish/jni/rtb/bitBoard.hpp
Normal file
132
DroidFish/jni/rtb/bitBoard.hpp
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bitBoard.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BITBOARD_HPP_
|
||||||
|
#define BITBOARD_HPP_
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum Square {
|
||||||
|
A1, B1, C1, D1, E1, F1, G1, H1,
|
||||||
|
A2, B2, C2, D2, E2, F2, G2, H2,
|
||||||
|
A3, B3, C3, D3, E3, F3, G3, H3,
|
||||||
|
A4, B4, C4, D4, E4, F4, G4, H4,
|
||||||
|
A5, B5, C5, D5, E5, F5, G5, H5,
|
||||||
|
A6, B6, C6, D6, E6, F6, G6, H6,
|
||||||
|
A7, B7, C7, D7, E7, F7, G7, H7,
|
||||||
|
A8, B8, C8, D8, E8, F8, G8, H8
|
||||||
|
};
|
||||||
|
|
||||||
|
class BitBoard {
|
||||||
|
public:
|
||||||
|
/** Squares attacked by a king on a given square. */
|
||||||
|
static U64 kingAttacks[64];
|
||||||
|
static U64 knightAttacks[64];
|
||||||
|
static U64 wPawnAttacks[64], bPawnAttacks[64];
|
||||||
|
|
||||||
|
static const U64 maskAToGFiles = 0x7F7F7F7F7F7F7F7FULL;
|
||||||
|
static const U64 maskBToHFiles = 0xFEFEFEFEFEFEFEFEULL;
|
||||||
|
static const U64 maskAToFFiles = 0x3F3F3F3F3F3F3F3FULL;
|
||||||
|
static const U64 maskCToHFiles = 0xFCFCFCFCFCFCFCFCULL;
|
||||||
|
|
||||||
|
static const U64 maskFile[8];
|
||||||
|
|
||||||
|
// Masks for squares where enemy pawn can capture en passant, indexed by file
|
||||||
|
static U64 epMaskW[8], epMaskB[8];
|
||||||
|
|
||||||
|
static const U64 maskRow1 = 0x00000000000000FFULL;
|
||||||
|
static const U64 maskRow2 = 0x000000000000FF00ULL;
|
||||||
|
static const U64 maskRow3 = 0x0000000000FF0000ULL;
|
||||||
|
static const U64 maskRow4 = 0x00000000FF000000ULL;
|
||||||
|
static const U64 maskRow5 = 0x000000FF00000000ULL;
|
||||||
|
static const U64 maskRow6 = 0x0000FF0000000000ULL;
|
||||||
|
static const U64 maskRow7 = 0x00FF000000000000ULL;
|
||||||
|
static const U64 maskRow8 = 0xFF00000000000000ULL;
|
||||||
|
static const U64 maskRow1Row8 = 0xFF000000000000FFULL;
|
||||||
|
|
||||||
|
static const U64 maskDarkSq = 0xAA55AA55AA55AA55ULL;
|
||||||
|
static const U64 maskLightSq = 0x55AA55AA55AA55AAULL;
|
||||||
|
|
||||||
|
static const U64 maskCorners = 0x8100000000000081ULL;
|
||||||
|
|
||||||
|
|
||||||
|
static U64 bishopAttacks(int sq, U64 occupied) {
|
||||||
|
return bTables[sq][(int)(((occupied & bMasks[sq]) * bMagics[sq]) >> (64 - bBits[sq]))];
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 rookAttacks(int sq, U64 occupied) {
|
||||||
|
return rTables[sq][(int)(((occupied & rMasks[sq]) * rMagics[sq]) >> (64 - rBits[sq]))];
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64 squaresBetween[64][64];
|
||||||
|
|
||||||
|
static int getDirection(int from, int to) {
|
||||||
|
int offs = to + (to|7) - from - (from|7) + 0x77;
|
||||||
|
return dirTable[offs];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int numberOfTrailingZeros(U64 mask) {
|
||||||
|
return trailingZ[(int)(((mask & -mask) * 0x07EDD5E59A4E28C2ULL) >> 58)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return number of 1 bits in mask. */
|
||||||
|
static int bitCount(U64 mask) {
|
||||||
|
const U64 k1 = 0x5555555555555555ULL;
|
||||||
|
const U64 k2 = 0x3333333333333333ULL;
|
||||||
|
const U64 k4 = 0x0f0f0f0f0f0f0f0fULL;
|
||||||
|
const U64 kf = 0x0101010101010101ULL;
|
||||||
|
U64 t = mask;
|
||||||
|
t -= (t >> 1) & k1;
|
||||||
|
t = (t & k2) + ((t >> 2) & k2);
|
||||||
|
t = (t + (t >> 4)) & k4;
|
||||||
|
t = (t * kf) >> 56;
|
||||||
|
return (int)t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize static data. */
|
||||||
|
static void staticInitialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static U64* rTables[64];
|
||||||
|
static U64 rMasks[64];
|
||||||
|
static int rBits[64];
|
||||||
|
static const U64 rMagics[64];
|
||||||
|
|
||||||
|
static U64* bTables[64];
|
||||||
|
static U64 bMasks[64];
|
||||||
|
static const int bBits[64];
|
||||||
|
static const U64 bMagics[64];
|
||||||
|
|
||||||
|
static std::vector<U64> tableData;
|
||||||
|
|
||||||
|
static const S8 dirTable[];
|
||||||
|
static const S8 kingDistTable[];
|
||||||
|
static const S8 taxiDistTable[];
|
||||||
|
static const int trailingZ[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BITBOARD_HPP_ */
|
||||||
32
DroidFish/jni/rtb/material.cpp
Normal file
32
DroidFish/jni/rtb/material.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2013 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* material.cpp
|
||||||
|
*
|
||||||
|
* Created on: May 1, 2013
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "material.hpp"
|
||||||
|
|
||||||
|
const int MatId::materialId[] = {
|
||||||
|
0,
|
||||||
|
0, WQ, WR, WB, WN, WP,
|
||||||
|
0, BQ, BR, BB, BN, BP
|
||||||
|
};
|
||||||
97
DroidFish/jni/rtb/material.hpp
Normal file
97
DroidFish/jni/rtb/material.hpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2013-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* material.hpp
|
||||||
|
*
|
||||||
|
* Created on: May 1, 2013
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MATERIAL_HPP_
|
||||||
|
#define MATERIAL_HPP_
|
||||||
|
|
||||||
|
#include "piece.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An incrementally updated material identifier.
|
||||||
|
* For each legal piece configuration, a unique identifier is computed.
|
||||||
|
*/
|
||||||
|
class MatId {
|
||||||
|
public:
|
||||||
|
static const int WP = 1;
|
||||||
|
static const int WR = 9;
|
||||||
|
static const int WN = 91;
|
||||||
|
static const int WB = 767;
|
||||||
|
static const int WQ = 5903;
|
||||||
|
|
||||||
|
static const int BP = 1 << 16;
|
||||||
|
static const int BR = 9 << 16;
|
||||||
|
static const int BN = 91 << 16;
|
||||||
|
static const int BB = 767 << 16;
|
||||||
|
static const int BQ = 5903 << 16;
|
||||||
|
|
||||||
|
MatId() : hash(0) {}
|
||||||
|
|
||||||
|
/** Add a piece to the material configuration. */
|
||||||
|
void addPiece(int pType);
|
||||||
|
|
||||||
|
/** Remove a piece from the material configuration. */
|
||||||
|
void removePiece(int pType);
|
||||||
|
|
||||||
|
/** Add cnt pieces of tyep ptype to the material configuration. */
|
||||||
|
void addPieceCnt(int pType, int cnt);
|
||||||
|
|
||||||
|
/** Get the material configuration identifier. */
|
||||||
|
int operator()() const;
|
||||||
|
|
||||||
|
/** Get ID for black/white mirror position. */
|
||||||
|
static int mirror(int id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int hash;
|
||||||
|
static const int materialId[Piece::nPieceTypes];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void
|
||||||
|
MatId::addPiece(int pType) {
|
||||||
|
hash += materialId[pType];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
MatId::removePiece(int pType) {
|
||||||
|
hash -= materialId[pType];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
MatId::addPieceCnt(int pType, int cnt) {
|
||||||
|
hash += materialId[pType] * cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
MatId::operator()() const {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
MatId::mirror(int h) {
|
||||||
|
unsigned int ret = h;
|
||||||
|
return (ret >> 16) | ((ret & 0xffff) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MATERIAL_HPP_ */
|
||||||
90
DroidFish/jni/rtb/move.hpp
Normal file
90
DroidFish/jni/rtb/move.hpp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* move.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MOVE_HPP_
|
||||||
|
#define MOVE_HPP_
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
/** Represents a chess move. */
|
||||||
|
class Move {
|
||||||
|
public:
|
||||||
|
/** Create empty move object. */
|
||||||
|
Move() : from_(0), to_(0), promoteTo_(0) { }
|
||||||
|
|
||||||
|
/** Create a move object. */
|
||||||
|
Move(int from, int to, int promoteTo);
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
Move(const Move& m);
|
||||||
|
|
||||||
|
int from() const;
|
||||||
|
int to() const;
|
||||||
|
int promoteTo() const;
|
||||||
|
|
||||||
|
/** Not declared "nothrow". Avoids nullptr check in generated assembly code when using placement new. */
|
||||||
|
void* operator new (std::size_t size, void* ptr) { return ptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** From square, 0-63. */
|
||||||
|
int from_;
|
||||||
|
|
||||||
|
/** To square, 0-63. */
|
||||||
|
int to_;
|
||||||
|
|
||||||
|
/** Promotion piece. */
|
||||||
|
int promoteTo_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
Move::Move(int from, int to, int promoteTo) {
|
||||||
|
from_ = from;
|
||||||
|
to_ = to;
|
||||||
|
promoteTo_ = promoteTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
Move::Move(const Move& m) {
|
||||||
|
from_ = m.from_;
|
||||||
|
to_ = m.to_;
|
||||||
|
promoteTo_ = m.promoteTo_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Move::from() const {
|
||||||
|
return from_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Move::to() const {
|
||||||
|
return to_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Move::promoteTo() const {
|
||||||
|
return promoteTo_;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MOVE_HPP_ */
|
||||||
344
DroidFish/jni/rtb/moveGen.cpp
Normal file
344
DroidFish/jni/rtb/moveGen.cpp
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* moveGen.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "moveGen.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
template void MoveGen::pseudoLegalMoves<true>(const Position& pos, MoveList& moveList);
|
||||||
|
template void MoveGen::pseudoLegalMoves<false>(const Position& pos, MoveList& moveList);
|
||||||
|
|
||||||
|
template <bool wtm>
|
||||||
|
void
|
||||||
|
MoveGen::pseudoLegalMoves(const Position& pos, MoveList& moveList) {
|
||||||
|
typedef ColorTraits<wtm> MyColor;
|
||||||
|
const U64 occupied = pos.occupiedBB();
|
||||||
|
|
||||||
|
// Queen moves
|
||||||
|
U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied)) & ~pos.colorBB(wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rook moves
|
||||||
|
squares = pos.pieceTypeBB(MyColor::ROOK);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = BitBoard::rookAttacks(sq, occupied) & ~pos.colorBB(wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bishop moves
|
||||||
|
squares = pos.pieceTypeBB(MyColor::BISHOP);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = BitBoard::bishopAttacks(sq, occupied) & ~pos.colorBB(wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// King moves
|
||||||
|
{
|
||||||
|
int sq = pos.getKingSq(wtm);
|
||||||
|
U64 m = BitBoard::kingAttacks[sq] & ~pos.colorBB(wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
const int k0 = wtm ? 4 : 60;
|
||||||
|
if (sq == k0) {
|
||||||
|
const U64 OO_SQ = wtm ? 0x60ULL : 0x6000000000000000ULL;
|
||||||
|
const U64 OOO_SQ = wtm ? 0xEULL : 0xE00000000000000ULL;
|
||||||
|
const int hCastle = wtm ? Position::H1_CASTLE : Position::H8_CASTLE;
|
||||||
|
const int aCastle = wtm ? Position::A1_CASTLE : Position::A8_CASTLE;
|
||||||
|
if (((pos.getCastleMask() & (1 << hCastle)) != 0) &&
|
||||||
|
((OO_SQ & occupied) == 0) &&
|
||||||
|
(pos.getPiece(k0 + 3) == MyColor::ROOK) &&
|
||||||
|
!sqAttacked(pos, k0) &&
|
||||||
|
!sqAttacked(pos, k0 + 1)) {
|
||||||
|
moveList.addMove(k0, k0 + 2, Piece::EMPTY);
|
||||||
|
}
|
||||||
|
if (((pos.getCastleMask() & (1 << aCastle)) != 0) &&
|
||||||
|
((OOO_SQ & occupied) == 0) &&
|
||||||
|
(pos.getPiece(k0 - 4) == MyColor::ROOK) &&
|
||||||
|
!sqAttacked(pos, k0) &&
|
||||||
|
!sqAttacked(pos, k0 - 1)) {
|
||||||
|
moveList.addMove(k0, k0 - 2, Piece::EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Knight moves
|
||||||
|
U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
|
||||||
|
while (knights != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(knights);
|
||||||
|
U64 m = BitBoard::knightAttacks[sq] & ~pos.colorBB(wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
knights &= knights-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pawn moves
|
||||||
|
const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
|
||||||
|
const int epSquare = pos.getEpSquare();
|
||||||
|
const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
|
||||||
|
if (wtm) {
|
||||||
|
U64 m = (pawns << 8) & ~occupied;
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -8, true);
|
||||||
|
m = ((m & BitBoard::maskRow3) << 8) & ~occupied;
|
||||||
|
addPawnDoubleMovesByMask(moveList, m, -16);
|
||||||
|
|
||||||
|
m = (pawns << 7) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -7, true);
|
||||||
|
|
||||||
|
m = (pawns << 9) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -9, true);
|
||||||
|
} else {
|
||||||
|
U64 m = (pawns >> 8) & ~occupied;
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 8, true);
|
||||||
|
m = ((m & BitBoard::maskRow6) >> 8) & ~occupied;
|
||||||
|
addPawnDoubleMovesByMask(moveList, m, 16);
|
||||||
|
|
||||||
|
m = (pawns >> 9) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 9, true);
|
||||||
|
|
||||||
|
m = (pawns >> 7) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 7, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template void MoveGen::checkEvasions<true>(const Position& pos, MoveList& moveList);
|
||||||
|
template void MoveGen::checkEvasions<false>(const Position& pos, MoveList& moveList);
|
||||||
|
|
||||||
|
template <bool wtm>
|
||||||
|
void
|
||||||
|
MoveGen::checkEvasions(const Position& pos, MoveList& moveList) {
|
||||||
|
typedef ColorTraits<wtm> MyColor;
|
||||||
|
typedef ColorTraits<!wtm> OtherColor;
|
||||||
|
const U64 occupied = pos.occupiedBB();
|
||||||
|
|
||||||
|
const int kingSq = pos.getKingSq(wtm);
|
||||||
|
U64 kingThreats = pos.pieceTypeBB(OtherColor::KNIGHT) & BitBoard::knightAttacks[kingSq];
|
||||||
|
U64 rookPieces = pos.pieceTypeBB(OtherColor::ROOK, OtherColor::QUEEN);
|
||||||
|
if (rookPieces != 0)
|
||||||
|
kingThreats |= rookPieces & BitBoard::rookAttacks(kingSq, occupied);
|
||||||
|
U64 bishPieces = pos.pieceTypeBB(OtherColor::BISHOP, OtherColor::QUEEN);
|
||||||
|
if (bishPieces != 0)
|
||||||
|
kingThreats |= bishPieces & BitBoard::bishopAttacks(kingSq, occupied);
|
||||||
|
const U64 myPawnAttacks = wtm ? BitBoard::wPawnAttacks[kingSq] : BitBoard::bPawnAttacks[kingSq];
|
||||||
|
kingThreats |= pos.pieceTypeBB(OtherColor::PAWN) & myPawnAttacks;
|
||||||
|
U64 validTargets = 0;
|
||||||
|
if ((kingThreats != 0) && ((kingThreats & (kingThreats-1)) == 0)) { // Exactly one attacking piece
|
||||||
|
int threatSq = BitBoard::numberOfTrailingZeros(kingThreats);
|
||||||
|
validTargets = kingThreats | BitBoard::squaresBetween[kingSq][threatSq];
|
||||||
|
}
|
||||||
|
validTargets |= pos.pieceTypeBB(OtherColor::KING);
|
||||||
|
// Queen moves
|
||||||
|
U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied)) &
|
||||||
|
~pos.colorBB(wtm) & validTargets;
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rook moves
|
||||||
|
squares = pos.pieceTypeBB(MyColor::ROOK);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = BitBoard::rookAttacks(sq, occupied) & ~pos.colorBB(wtm) & validTargets;
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bishop moves
|
||||||
|
squares = pos.pieceTypeBB(MyColor::BISHOP);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = BitBoard::bishopAttacks(sq, occupied) & ~pos.colorBB(wtm) & validTargets;
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// King moves
|
||||||
|
{
|
||||||
|
int sq = pos.getKingSq(wtm);
|
||||||
|
U64 m = BitBoard::kingAttacks[sq] & ~pos.colorBB(wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Knight moves
|
||||||
|
U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
|
||||||
|
while (knights != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(knights);
|
||||||
|
U64 m = BitBoard::knightAttacks[sq] & ~pos.colorBB(wtm) & validTargets;
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
knights &= knights-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pawn moves
|
||||||
|
const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
|
||||||
|
const int epSquare = pos.getEpSquare();
|
||||||
|
const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
|
||||||
|
if (wtm) {
|
||||||
|
U64 m = (pawns << 8) & ~occupied;
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m & validTargets, -8, true);
|
||||||
|
m = ((m & BitBoard::maskRow3) << 8) & ~occupied;
|
||||||
|
addPawnDoubleMovesByMask(moveList, m & validTargets, -16);
|
||||||
|
|
||||||
|
m = (pawns << 7) & BitBoard::maskAToGFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -7, true);
|
||||||
|
|
||||||
|
m = (pawns << 9) & BitBoard::maskBToHFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -9, true);
|
||||||
|
} else {
|
||||||
|
U64 m = (pawns >> 8) & ~occupied;
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m & validTargets, 8, true);
|
||||||
|
m = ((m & BitBoard::maskRow6) >> 8) & ~occupied;
|
||||||
|
addPawnDoubleMovesByMask(moveList, m & validTargets, 16);
|
||||||
|
|
||||||
|
m = (pawns >> 9) & BitBoard::maskAToGFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 9, true);
|
||||||
|
|
||||||
|
m = (pawns >> 7) & BitBoard::maskBToHFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 7, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template void MoveGen::pseudoLegalCaptures<true>(const Position& pos, MoveList& moveList);
|
||||||
|
template void MoveGen::pseudoLegalCaptures<false>(const Position& pos, MoveList& moveList);
|
||||||
|
|
||||||
|
template <bool wtm>
|
||||||
|
void
|
||||||
|
MoveGen::pseudoLegalCaptures(const Position& pos, MoveList& moveList) {
|
||||||
|
typedef ColorTraits<wtm> MyColor;
|
||||||
|
const U64 occupied = pos.occupiedBB();
|
||||||
|
|
||||||
|
// Queen moves
|
||||||
|
U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied)) & pos.colorBB(!wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rook moves
|
||||||
|
squares = pos.pieceTypeBB(MyColor::ROOK);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = BitBoard::rookAttacks(sq, occupied) & pos.colorBB(!wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bishop moves
|
||||||
|
squares = pos.pieceTypeBB(MyColor::BISHOP);
|
||||||
|
while (squares != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(squares);
|
||||||
|
U64 m = BitBoard::bishopAttacks(sq, occupied) & pos.colorBB(!wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
squares &= squares-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Knight moves
|
||||||
|
U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
|
||||||
|
while (knights != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(knights);
|
||||||
|
U64 m = BitBoard::knightAttacks[sq] & pos.colorBB(!wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
knights &= knights-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// King moves
|
||||||
|
int sq = pos.getKingSq(wtm);
|
||||||
|
U64 m = BitBoard::kingAttacks[sq] & pos.colorBB(!wtm);
|
||||||
|
addMovesByMask(moveList, sq, m);
|
||||||
|
|
||||||
|
// Pawn moves
|
||||||
|
const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
|
||||||
|
const int epSquare = pos.getEpSquare();
|
||||||
|
const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
|
||||||
|
if (wtm) {
|
||||||
|
m = (pawns << 8) & ~occupied;
|
||||||
|
m &= BitBoard::maskRow8;
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -8, false);
|
||||||
|
|
||||||
|
m = (pawns << 7) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -7, false);
|
||||||
|
m = (pawns << 9) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, -9, false);
|
||||||
|
} else {
|
||||||
|
m = (pawns >> 8) & ~occupied;
|
||||||
|
m &= BitBoard::maskRow1;
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 8, false);
|
||||||
|
|
||||||
|
m = (pawns >> 9) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 9, false);
|
||||||
|
m = (pawns >> 7) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
|
||||||
|
addPawnMovesByMask<wtm>(moveList, m, 7, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MoveGen::isLegal(Position& pos, const Move& m, bool isInCheck) {
|
||||||
|
UndoInfo ui;
|
||||||
|
int kSq = pos.getKingSq(pos.isWhiteMove());
|
||||||
|
const int epSquare = pos.getEpSquare();
|
||||||
|
if (isInCheck) {
|
||||||
|
if ((m.from() != kSq) && (m.to() != epSquare)) {
|
||||||
|
U64 occupied = pos.occupiedBB();
|
||||||
|
U64 toMask = 1ULL << m.to();
|
||||||
|
Piece::Type knight = pos.isWhiteMove() ? Piece::BKNIGHT : Piece::WKNIGHT;
|
||||||
|
if (((BitBoard::rookAttacks(kSq, occupied) & toMask) == 0) &&
|
||||||
|
((BitBoard::bishopAttacks(kSq, occupied) & toMask) == 0) &&
|
||||||
|
((BitBoard::knightAttacks[kSq] & pos.pieceTypeBB(knight) & toMask) == 0))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pos.makeMove(m, ui);
|
||||||
|
bool legal = !canTakeKing(pos);
|
||||||
|
pos.unMakeMove(m, ui);
|
||||||
|
return legal;
|
||||||
|
} else {
|
||||||
|
if (m.from() == kSq) {
|
||||||
|
U64 occupied = pos.occupiedBB() & ~(1ULL<<m.from());
|
||||||
|
return !MoveGen::sqAttacked(pos, m.to(), occupied);
|
||||||
|
} else {
|
||||||
|
if (m.to() != epSquare) {
|
||||||
|
U64 occupied = pos.occupiedBB();
|
||||||
|
U64 fromMask = 1ULL << m.from();
|
||||||
|
if (((BitBoard::rookAttacks(kSq, occupied) & fromMask) == 0) &&
|
||||||
|
((BitBoard::bishopAttacks(kSq, occupied) & fromMask) == 0))
|
||||||
|
return true;
|
||||||
|
else if (BitBoard::getDirection(kSq, m.from()) == BitBoard::getDirection(kSq, m.to()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pos.makeMove(m, ui);
|
||||||
|
bool legal = !canTakeKing(pos);
|
||||||
|
pos.unMakeMove(m, ui);
|
||||||
|
return legal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
216
DroidFish/jni/rtb/moveGen.hpp
Normal file
216
DroidFish/jni/rtb/moveGen.hpp
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* moveGen.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MOVEGEN_HPP_
|
||||||
|
#define MOVEGEN_HPP_
|
||||||
|
|
||||||
|
#include "move.hpp"
|
||||||
|
#include "position.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
//#define MOVELIST_DEBUG
|
||||||
|
|
||||||
|
#ifdef MOVELIST_DEBUG
|
||||||
|
# include <set>
|
||||||
|
# include "textio.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates move lists (pseudo-legal, legal, check evasions, captures).
|
||||||
|
*/
|
||||||
|
class MoveGen {
|
||||||
|
private:
|
||||||
|
static const int MAX_MOVES = 256;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** A stack-allocated move list object. */
|
||||||
|
class MoveList {
|
||||||
|
private:
|
||||||
|
int buf[sizeof(Move[MAX_MOVES])/sizeof(int)];
|
||||||
|
public:
|
||||||
|
int size;
|
||||||
|
|
||||||
|
MoveList() : size(0) { }
|
||||||
|
void clear() { size = 0; }
|
||||||
|
|
||||||
|
Move& operator[](int i) { return ((Move*)&buf[0])[i]; }
|
||||||
|
const Move& operator[](int i) const { return ((Move*)&buf[0])[i]; }
|
||||||
|
|
||||||
|
void addMove(int from, int to, int promoteTo) {
|
||||||
|
Move& m = (*this)[size++];
|
||||||
|
new (&m) Move(from, to, promoteTo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and return a list of pseudo-legal moves.
|
||||||
|
* Pseudo-legal means that the moves don't necessarily defend from check threats.
|
||||||
|
*/
|
||||||
|
template <bool wtm>
|
||||||
|
static void pseudoLegalMoves(const Position& pos, MoveList& moveList);
|
||||||
|
static void pseudoLegalMoves(const Position& pos, MoveList& moveList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and return a list of pseudo-legal check evasion moves.
|
||||||
|
* Pseudo-legal means that the moves don't necessarily defend from check threats.
|
||||||
|
*/
|
||||||
|
template <bool wtm>
|
||||||
|
static void checkEvasions(const Position& pos, MoveList& moveList);
|
||||||
|
static void checkEvasions(const Position& pos, MoveList& moveList);
|
||||||
|
|
||||||
|
/** Generate and return a list of pseudo-legal capture moves. */
|
||||||
|
template <bool wtm>
|
||||||
|
static void pseudoLegalCaptures(const Position& pos, MoveList& moveList);
|
||||||
|
static void pseudoLegalCaptures(const Position& pos, MoveList& moveList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the side to move is in check.
|
||||||
|
*/
|
||||||
|
static bool inCheck(const Position& pos) {
|
||||||
|
int kingSq = pos.getKingSq(pos.isWhiteMove());
|
||||||
|
return sqAttacked(pos, kingSq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the side to move can take the opponents king.
|
||||||
|
*/
|
||||||
|
static bool canTakeKing(Position& pos) {
|
||||||
|
pos.setWhiteMove(!pos.isWhiteMove());
|
||||||
|
bool ret = inCheck(pos);
|
||||||
|
pos.setWhiteMove(!pos.isWhiteMove());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if a square is attacked by the opposite side.
|
||||||
|
*/
|
||||||
|
static bool sqAttacked(const Position& pos, int sq) {
|
||||||
|
const U64 occupied = pos.occupiedBB();
|
||||||
|
return sqAttacked(pos, sq, occupied);
|
||||||
|
}
|
||||||
|
static bool sqAttacked(const Position& pos, int sq, U64 occupied) {
|
||||||
|
return pos.isWhiteMove() ? sqAttacked<true>(pos, sq, occupied)
|
||||||
|
: sqAttacked<false>(pos, sq, occupied);
|
||||||
|
}
|
||||||
|
template <bool wtm>
|
||||||
|
static bool sqAttacked(const Position& pos, int sq, U64 occupied) {
|
||||||
|
typedef ColorTraits<!wtm> OtherColor;
|
||||||
|
if ((BitBoard::knightAttacks[sq] & pos.pieceTypeBB(OtherColor::KNIGHT)) != 0)
|
||||||
|
return true;
|
||||||
|
if ((BitBoard::kingAttacks[sq] & pos.pieceTypeBB(OtherColor::KING)) != 0)
|
||||||
|
return true;
|
||||||
|
if (wtm) {
|
||||||
|
if ((BitBoard::wPawnAttacks[sq] & pos.pieceTypeBB(OtherColor::PAWN)) != 0)
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if ((BitBoard::bPawnAttacks[sq] & pos.pieceTypeBB(OtherColor::PAWN)) != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
U64 bbQueen = pos.pieceTypeBB(OtherColor::QUEEN);
|
||||||
|
if ((BitBoard::bishopAttacks(sq, occupied) & (pos.pieceTypeBB(OtherColor::BISHOP) | bbQueen)) != 0)
|
||||||
|
return true;
|
||||||
|
if ((BitBoard::rookAttacks(sq, occupied) & (pos.pieceTypeBB(OtherColor::ROOK) | bbQueen)) != 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true if the pseudo-legal move "move" is legal is position "pos".
|
||||||
|
* isInCheck must be equal to inCheck(pos). */
|
||||||
|
static bool isLegal(Position& pos, const Move& move, bool isInCheck);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <bool wtm>
|
||||||
|
static void addPawnMovesByMask(MoveList& moveList, U64 mask, int delta, bool allPromotions) {
|
||||||
|
typedef ColorTraits<wtm> MyColor;
|
||||||
|
if (mask == 0)
|
||||||
|
return;
|
||||||
|
U64 promMask = mask & BitBoard::maskRow1Row8;
|
||||||
|
mask &= ~promMask;
|
||||||
|
while (promMask != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(promMask);
|
||||||
|
int sq0 = sq + delta;
|
||||||
|
moveList.addMove(sq0, sq, MyColor::QUEEN);
|
||||||
|
moveList.addMove(sq0, sq, MyColor::KNIGHT);
|
||||||
|
if (allPromotions) {
|
||||||
|
moveList.addMove(sq0, sq, MyColor::ROOK);
|
||||||
|
moveList.addMove(sq0, sq, MyColor::BISHOP);
|
||||||
|
}
|
||||||
|
promMask &= (promMask - 1);
|
||||||
|
}
|
||||||
|
while (mask != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(mask);
|
||||||
|
moveList.addMove(sq + delta, sq, Piece::EMPTY);
|
||||||
|
mask &= (mask - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addPawnDoubleMovesByMask(MoveList& moveList, U64 mask, int delta) {
|
||||||
|
while (mask != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(mask);
|
||||||
|
moveList.addMove(sq + delta, sq, Piece::EMPTY);
|
||||||
|
mask &= (mask - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addMovesByMask(MoveList& moveList, int sq0, U64 mask) {
|
||||||
|
while (mask != 0) {
|
||||||
|
int sq = BitBoard::numberOfTrailingZeros(mask);
|
||||||
|
moveList.addMove(sq0, sq, Piece::EMPTY);
|
||||||
|
mask &= (mask - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveGen() = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
MoveGen::pseudoLegalMoves(const Position& pos, MoveList& moveList) {
|
||||||
|
if (pos.isWhiteMove())
|
||||||
|
pseudoLegalMoves<true>(pos, moveList);
|
||||||
|
else
|
||||||
|
pseudoLegalMoves<false>(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
MoveGen::checkEvasions(const Position& pos, MoveList& moveList) {
|
||||||
|
if (pos.isWhiteMove())
|
||||||
|
checkEvasions<true>(pos, moveList);
|
||||||
|
else
|
||||||
|
checkEvasions<false>(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
MoveGen::pseudoLegalCaptures(const Position& pos, MoveList& moveList) {
|
||||||
|
if (pos.isWhiteMove())
|
||||||
|
pseudoLegalCaptures<true>(pos, moveList);
|
||||||
|
else
|
||||||
|
pseudoLegalCaptures<false>(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MOVEGEN_HPP_ */
|
||||||
86
DroidFish/jni/rtb/piece.hpp
Normal file
86
DroidFish/jni/rtb/piece.hpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2013 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* piece.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PIECE_HPP_
|
||||||
|
#define PIECE_HPP_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants for different piece types.
|
||||||
|
*/
|
||||||
|
class Piece {
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
EMPTY = 0,
|
||||||
|
WKING = 1,
|
||||||
|
WQUEEN = 2,
|
||||||
|
WROOK = 3,
|
||||||
|
WBISHOP = 4,
|
||||||
|
WKNIGHT = 5,
|
||||||
|
WPAWN = 6,
|
||||||
|
|
||||||
|
BKING = 7,
|
||||||
|
BQUEEN = 8,
|
||||||
|
BROOK = 9,
|
||||||
|
BBISHOP = 10,
|
||||||
|
BKNIGHT = 11,
|
||||||
|
BPAWN = 12,
|
||||||
|
|
||||||
|
nPieceTypes = 13
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if p is a white piece, false otherwise.
|
||||||
|
* Note that if p is EMPTY, an unspecified value is returned.
|
||||||
|
*/
|
||||||
|
static bool isWhite(int pType);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool wtm> struct ColorTraits {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct ColorTraits<true> {
|
||||||
|
static const Piece::Type KING = Piece::WKING;
|
||||||
|
static const Piece::Type QUEEN = Piece::WQUEEN;
|
||||||
|
static const Piece::Type ROOK = Piece::WROOK;
|
||||||
|
static const Piece::Type BISHOP = Piece::WBISHOP;
|
||||||
|
static const Piece::Type KNIGHT = Piece::WKNIGHT;
|
||||||
|
static const Piece::Type PAWN = Piece::WPAWN;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct ColorTraits<false> {
|
||||||
|
static const Piece::Type KING = Piece::BKING;
|
||||||
|
static const Piece::Type QUEEN = Piece::BQUEEN;
|
||||||
|
static const Piece::Type ROOK = Piece::BROOK;
|
||||||
|
static const Piece::Type BISHOP = Piece::BBISHOP;
|
||||||
|
static const Piece::Type KNIGHT = Piece::BKNIGHT;
|
||||||
|
static const Piece::Type PAWN = Piece::BPAWN;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
Piece::isWhite(int pType) {
|
||||||
|
return pType < BKING;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* PIECE_HPP_ */
|
||||||
211
DroidFish/jni/rtb/position.cpp
Normal file
211
DroidFish/jni/rtb/position.cpp
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* position.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "position.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
Position::Position() {
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
squares[i] = Piece::EMPTY;
|
||||||
|
for (int i = 0; i < Piece::nPieceTypes; i++)
|
||||||
|
pieceTypeBB_[i] = 0;
|
||||||
|
whiteBB_ = blackBB_ = 0;
|
||||||
|
whiteMove = true;
|
||||||
|
castleMask = 0;
|
||||||
|
epSquare = -1;
|
||||||
|
halfMoveClock = 0;
|
||||||
|
fullMoveCounter = 1;
|
||||||
|
matId = {};
|
||||||
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
|
int p = squares[sq];
|
||||||
|
matId.addPiece(p);
|
||||||
|
}
|
||||||
|
wKingSq_ = bKingSq_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Position::setPiece(int square, int piece) {
|
||||||
|
int removedPiece = squares[square];
|
||||||
|
squares[square] = piece;
|
||||||
|
|
||||||
|
// Update material identifier
|
||||||
|
matId.removePiece(removedPiece);
|
||||||
|
matId.addPiece(piece);
|
||||||
|
|
||||||
|
// Update bitboards
|
||||||
|
const U64 sqMask = 1ULL << square;
|
||||||
|
pieceTypeBB_[removedPiece] &= ~sqMask;
|
||||||
|
pieceTypeBB_[piece] |= sqMask;
|
||||||
|
|
||||||
|
if (removedPiece != Piece::EMPTY) {
|
||||||
|
if (Piece::isWhite(removedPiece)) {
|
||||||
|
whiteBB_ &= ~sqMask;
|
||||||
|
} else {
|
||||||
|
blackBB_ &= ~sqMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (piece != Piece::EMPTY) {
|
||||||
|
if (Piece::isWhite(piece)) {
|
||||||
|
whiteBB_ |= sqMask;
|
||||||
|
if (piece == Piece::WKING)
|
||||||
|
wKingSq_ = square;
|
||||||
|
} else {
|
||||||
|
blackBB_ |= sqMask;
|
||||||
|
if (piece == Piece::BKING)
|
||||||
|
bKingSq_ = square;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Position::makeMove(const Move& move, UndoInfo& ui) {
|
||||||
|
ui.capturedPiece = squares[move.to()];
|
||||||
|
ui.castleMask = castleMask;
|
||||||
|
ui.epSquare = epSquare;
|
||||||
|
ui.halfMoveClock = halfMoveClock;
|
||||||
|
bool wtm = whiteMove;
|
||||||
|
|
||||||
|
const int p = squares[move.from()];
|
||||||
|
int capP = squares[move.to()];
|
||||||
|
U64 fromMask = 1ULL << move.from();
|
||||||
|
|
||||||
|
int prevEpSquare = epSquare;
|
||||||
|
setEpSquare(-1);
|
||||||
|
|
||||||
|
if ((capP != Piece::EMPTY) || ((pieceTypeBB(Piece::WPAWN, Piece::BPAWN) & fromMask) != 0)) {
|
||||||
|
halfMoveClock = 0;
|
||||||
|
|
||||||
|
// Handle en passant and epSquare
|
||||||
|
if (p == Piece::WPAWN) {
|
||||||
|
if (move.to() - move.from() == 2 * 8) {
|
||||||
|
int x = getX(move.to());
|
||||||
|
if (BitBoard::epMaskW[x] & pieceTypeBB(Piece::BPAWN))
|
||||||
|
setEpSquare(move.from() + 8);
|
||||||
|
} else if (move.to() == prevEpSquare) {
|
||||||
|
setPiece(move.to() - 8, Piece::EMPTY);
|
||||||
|
}
|
||||||
|
} else if (p == Piece::BPAWN) {
|
||||||
|
if (move.to() - move.from() == -2 * 8) {
|
||||||
|
int x = getX(move.to());
|
||||||
|
if (BitBoard::epMaskB[x] & pieceTypeBB(Piece::WPAWN))
|
||||||
|
setEpSquare(move.from() - 8);
|
||||||
|
} else if (move.to() == prevEpSquare) {
|
||||||
|
setPiece(move.to() + 8, Piece::EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pieceTypeBB(Piece::WKING, Piece::BKING) & fromMask) != 0) {
|
||||||
|
if (wtm) {
|
||||||
|
setCastleMask(castleMask & ~(1 << A1_CASTLE));
|
||||||
|
setCastleMask(castleMask & ~(1 << H1_CASTLE));
|
||||||
|
} else {
|
||||||
|
setCastleMask(castleMask & ~(1 << A8_CASTLE));
|
||||||
|
setCastleMask(castleMask & ~(1 << H8_CASTLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform move
|
||||||
|
setPiece(move.from(), Piece::EMPTY);
|
||||||
|
// Handle promotion
|
||||||
|
if (move.promoteTo() != Piece::EMPTY) {
|
||||||
|
setPiece(move.to(), move.promoteTo());
|
||||||
|
} else {
|
||||||
|
setPiece(move.to(), p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
halfMoveClock++;
|
||||||
|
|
||||||
|
// Handle castling
|
||||||
|
if ((pieceTypeBB(Piece::WKING, Piece::BKING) & fromMask) != 0) {
|
||||||
|
int k0 = move.from();
|
||||||
|
if (move.to() == k0 + 2) { // O-O
|
||||||
|
movePieceNotPawn(k0 + 3, k0 + 1);
|
||||||
|
} else if (move.to() == k0 - 2) { // O-O-O
|
||||||
|
movePieceNotPawn(k0 - 4, k0 - 1);
|
||||||
|
}
|
||||||
|
if (wtm) {
|
||||||
|
setCastleMask(castleMask & ~(1 << A1_CASTLE));
|
||||||
|
setCastleMask(castleMask & ~(1 << H1_CASTLE));
|
||||||
|
} else {
|
||||||
|
setCastleMask(castleMask & ~(1 << A8_CASTLE));
|
||||||
|
setCastleMask(castleMask & ~(1 << H8_CASTLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform move
|
||||||
|
movePieceNotPawn(move.from(), move.to());
|
||||||
|
}
|
||||||
|
if (wtm) {
|
||||||
|
// Update castling rights when rook moves
|
||||||
|
if ((BitBoard::maskCorners & fromMask) != 0) {
|
||||||
|
if (p == Piece::WROOK)
|
||||||
|
removeCastleRights(move.from());
|
||||||
|
}
|
||||||
|
if ((BitBoard::maskCorners & (1ULL << move.to())) != 0) {
|
||||||
|
if (capP == Piece::BROOK)
|
||||||
|
removeCastleRights(move.to());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fullMoveCounter++;
|
||||||
|
// Update castling rights when rook moves
|
||||||
|
if ((BitBoard::maskCorners & fromMask) != 0) {
|
||||||
|
if (p == Piece::BROOK)
|
||||||
|
removeCastleRights(move.from());
|
||||||
|
}
|
||||||
|
if ((BitBoard::maskCorners & (1ULL << move.to())) != 0) {
|
||||||
|
if (capP == Piece::WROOK)
|
||||||
|
removeCastleRights(move.to());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
whiteMove = !wtm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Position::movePieceNotPawn(int from, int to) {
|
||||||
|
const int piece = squares[from];
|
||||||
|
|
||||||
|
squares[from] = Piece::EMPTY;
|
||||||
|
squares[to] = piece;
|
||||||
|
|
||||||
|
const U64 sqMaskF = 1ULL << from;
|
||||||
|
const U64 sqMaskT = 1ULL << to;
|
||||||
|
pieceTypeBB_[piece] &= ~sqMaskF;
|
||||||
|
pieceTypeBB_[piece] |= sqMaskT;
|
||||||
|
if (Piece::isWhite(piece)) {
|
||||||
|
whiteBB_ &= ~sqMaskF;
|
||||||
|
whiteBB_ |= sqMaskT;
|
||||||
|
if (piece == Piece::WKING)
|
||||||
|
wKingSq_ = to;
|
||||||
|
} else {
|
||||||
|
blackBB_ &= ~sqMaskF;
|
||||||
|
blackBB_ |= sqMaskT;
|
||||||
|
if (piece == Piece::BKING)
|
||||||
|
bKingSq_ = to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
318
DroidFish/jni/rtb/position.hpp
Normal file
318
DroidFish/jni/rtb/position.hpp
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* position.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POSITION_HPP_
|
||||||
|
#define POSITION_HPP_
|
||||||
|
|
||||||
|
#include "move.hpp"
|
||||||
|
#include "undoInfo.hpp"
|
||||||
|
#include "bitBoard.hpp"
|
||||||
|
#include "piece.hpp"
|
||||||
|
#include "material.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the state of a chess position.
|
||||||
|
* All required state is stored, except for all previous positions
|
||||||
|
* since the last capture or pawn move. That state is only needed
|
||||||
|
* for three-fold repetition draw detection, and is better stored
|
||||||
|
* in a separate hash table.
|
||||||
|
*/
|
||||||
|
class Position {
|
||||||
|
public:
|
||||||
|
/** Bit definitions for the castleMask bit mask. */
|
||||||
|
static const int A1_CASTLE = 0; /** White long castle. */
|
||||||
|
static const int H1_CASTLE = 1; /** White short castle. */
|
||||||
|
static const int A8_CASTLE = 2; /** Black long castle. */
|
||||||
|
static const int H8_CASTLE = 3; /** Black short castle. */
|
||||||
|
|
||||||
|
/** Initialize board to empty position. */
|
||||||
|
Position();
|
||||||
|
|
||||||
|
/** Return the material identifier. */
|
||||||
|
int materialId() const;
|
||||||
|
|
||||||
|
bool isWhiteMove() const;
|
||||||
|
void setWhiteMove(bool whiteMove);
|
||||||
|
|
||||||
|
/** Return piece occupying a square. */
|
||||||
|
int getPiece(int square) const;
|
||||||
|
|
||||||
|
/** Set a square to a piece value. */
|
||||||
|
void setPiece(int square, int piece);
|
||||||
|
|
||||||
|
/** Bitmask describing castling rights. */
|
||||||
|
int getCastleMask() const;
|
||||||
|
void setCastleMask(int castleMask);
|
||||||
|
|
||||||
|
/** En passant square, or -1 if no en passant possible. */
|
||||||
|
int getEpSquare() const;
|
||||||
|
|
||||||
|
void setEpSquare(int epSquare);
|
||||||
|
|
||||||
|
int getKingSq(bool white) const;
|
||||||
|
|
||||||
|
/** Apply a move to the current position. */
|
||||||
|
void makeMove(const Move& move, UndoInfo& ui);
|
||||||
|
|
||||||
|
void unMakeMove(const Move& move, const UndoInfo& ui);
|
||||||
|
|
||||||
|
int getFullMoveCounter() const;
|
||||||
|
void setFullMoveCounter(int fm);
|
||||||
|
int getHalfMoveClock() const;
|
||||||
|
void setHalfMoveClock(int hm);
|
||||||
|
|
||||||
|
/** BitBoard for all squares occupied by a piece type. */
|
||||||
|
U64 pieceTypeBB(Piece::Type piece) const;
|
||||||
|
/** BitBoard for all squares occupied by several piece types. */
|
||||||
|
template <typename Piece0, typename... Pieces> U64 pieceTypeBB(Piece0 piece0, Pieces... pieces) const;
|
||||||
|
|
||||||
|
/** BitBoard for all squares occupied by white pieces. */
|
||||||
|
U64 whiteBB() const;
|
||||||
|
/** BitBoard for all squares occupied by black pieces. */
|
||||||
|
U64 blackBB() const;
|
||||||
|
/** BitBoard for all squares occupied by white or black pieces. */
|
||||||
|
U64 colorBB(int wtm) const;
|
||||||
|
|
||||||
|
/** BitBoard for all squares occupied by white and black pieces. */
|
||||||
|
U64 occupiedBB() const;
|
||||||
|
|
||||||
|
int wKingSq() const;
|
||||||
|
int bKingSq() const;
|
||||||
|
|
||||||
|
/** Return index in squares[] vector corresponding to (x,y). */
|
||||||
|
static int getSquare(int x, int y);
|
||||||
|
|
||||||
|
/** Return x position (file) corresponding to a square. */
|
||||||
|
static int getX(int square);
|
||||||
|
|
||||||
|
/** Return y position (rank) corresponding to a square. */
|
||||||
|
static int getY(int square);
|
||||||
|
|
||||||
|
/** Return true if (x,y) is a dark square. */
|
||||||
|
static bool darkSquare(int x, int y);
|
||||||
|
|
||||||
|
/** Initialize static data. */
|
||||||
|
static void staticInitialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Move a non-pawn piece to an empty square. */
|
||||||
|
void movePieceNotPawn(int from, int to);
|
||||||
|
|
||||||
|
void removeCastleRights(int square);
|
||||||
|
|
||||||
|
|
||||||
|
int wKingSq_, bKingSq_; // Cached king positions
|
||||||
|
|
||||||
|
int squares[64];
|
||||||
|
|
||||||
|
// Bitboards
|
||||||
|
U64 pieceTypeBB_[Piece::nPieceTypes];
|
||||||
|
U64 whiteBB_, blackBB_;
|
||||||
|
|
||||||
|
bool whiteMove;
|
||||||
|
|
||||||
|
/** Number of half-moves since last 50-move reset. */
|
||||||
|
int halfMoveClock;
|
||||||
|
|
||||||
|
/** Game move number, starting from 1. */
|
||||||
|
int fullMoveCounter;
|
||||||
|
|
||||||
|
int castleMask;
|
||||||
|
int epSquare;
|
||||||
|
|
||||||
|
MatId matId; // Cached material identifier
|
||||||
|
};
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Position::materialId() const {
|
||||||
|
return matId();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
Position::isWhiteMove() const {
|
||||||
|
return whiteMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Position::setWhiteMove(bool whiteMove) {
|
||||||
|
this->whiteMove = whiteMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Position::getPiece(int square) const {
|
||||||
|
return squares[square];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Position::getCastleMask() const {
|
||||||
|
return castleMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Position::setCastleMask(int castleMask) {
|
||||||
|
this->castleMask = castleMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Position::getEpSquare() const {
|
||||||
|
return epSquare;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Position::setEpSquare(int epSquare) {
|
||||||
|
this->epSquare = epSquare;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Position::getKingSq(bool white) const {
|
||||||
|
return white ? wKingSq() : bKingSq();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Position::unMakeMove(const Move& move, const UndoInfo& ui) {
|
||||||
|
whiteMove = !whiteMove;
|
||||||
|
int p = squares[move.to()];
|
||||||
|
setPiece(move.from(), p);
|
||||||
|
setPiece(move.to(), ui.capturedPiece);
|
||||||
|
setCastleMask(ui.castleMask);
|
||||||
|
setEpSquare(ui.epSquare);
|
||||||
|
halfMoveClock = ui.halfMoveClock;
|
||||||
|
bool wtm = whiteMove;
|
||||||
|
if (move.promoteTo() != Piece::EMPTY) {
|
||||||
|
p = wtm ? Piece::WPAWN : Piece::BPAWN;
|
||||||
|
setPiece(move.from(), p);
|
||||||
|
}
|
||||||
|
if (!wtm)
|
||||||
|
fullMoveCounter--;
|
||||||
|
|
||||||
|
// Handle castling
|
||||||
|
int king = wtm ? Piece::WKING : Piece::BKING;
|
||||||
|
if (p == king) {
|
||||||
|
int k0 = move.from();
|
||||||
|
if (move.to() == k0 + 2) { // O-O
|
||||||
|
movePieceNotPawn(k0 + 1, k0 + 3);
|
||||||
|
} else if (move.to() == k0 - 2) { // O-O-O
|
||||||
|
movePieceNotPawn(k0 - 1, k0 - 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle en passant
|
||||||
|
if (move.to() == epSquare) {
|
||||||
|
if (p == Piece::WPAWN) {
|
||||||
|
setPiece(move.to() - 8, Piece::BPAWN);
|
||||||
|
} else if (p == Piece::BPAWN) {
|
||||||
|
setPiece(move.to() + 8, Piece::WPAWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
Position::getSquare(int x, int y) {
|
||||||
|
return y * 8 + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return x position (file) corresponding to a square. */
|
||||||
|
inline int
|
||||||
|
Position::getX(int square) {
|
||||||
|
return square & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return y position (rank) corresponding to a square. */
|
||||||
|
inline int
|
||||||
|
Position::getY(int square) {
|
||||||
|
return square >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true if (x,y) is a dark square. */
|
||||||
|
inline bool
|
||||||
|
Position::darkSquare(int x, int y) {
|
||||||
|
return (x & 1) == (y & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Position::removeCastleRights(int square) {
|
||||||
|
if (square == getSquare(0, 0)) {
|
||||||
|
setCastleMask(castleMask & ~(1 << A1_CASTLE));
|
||||||
|
} else if (square == getSquare(7, 0)) {
|
||||||
|
setCastleMask(castleMask & ~(1 << H1_CASTLE));
|
||||||
|
} else if (square == getSquare(0, 7)) {
|
||||||
|
setCastleMask(castleMask & ~(1 << A8_CASTLE));
|
||||||
|
} else if (square == getSquare(7, 7)) {
|
||||||
|
setCastleMask(castleMask & ~(1 << H8_CASTLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Position::getFullMoveCounter() const {
|
||||||
|
return fullMoveCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Position::setFullMoveCounter(int fm) {
|
||||||
|
fullMoveCounter = fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Position::getHalfMoveClock() const {
|
||||||
|
return halfMoveClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Position::setHalfMoveClock(int hm) {
|
||||||
|
halfMoveClock = hm;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U64 Position::pieceTypeBB(Piece::Type piece) const {
|
||||||
|
return pieceTypeBB_[piece];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Piece0, typename... Pieces>
|
||||||
|
inline U64 Position::pieceTypeBB(Piece0 piece0, Pieces... pieces) const {
|
||||||
|
return pieceTypeBB(piece0) | pieceTypeBB(pieces...);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U64 Position::whiteBB() const {
|
||||||
|
return whiteBB_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U64 Position::blackBB() const {
|
||||||
|
return blackBB_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline U64 Position::colorBB(int wtm) const {
|
||||||
|
return wtm ? whiteBB_ : blackBB_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U64 Position::occupiedBB() const {
|
||||||
|
return whiteBB() | blackBB();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Position::wKingSq() const {
|
||||||
|
return wKingSq_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Position::bKingSq() const {
|
||||||
|
return bKingSq_;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* POSITION_HPP_ */
|
||||||
1619
DroidFish/jni/rtb/rtb-core-impl.hpp
Normal file
1619
DroidFish/jni/rtb/rtb-core-impl.hpp
Normal file
File diff suppressed because it is too large
Load Diff
142
DroidFish/jni/rtb/rtb-core.hpp
Normal file
142
DroidFish/jni/rtb/rtb-core.hpp
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011-2013 Ronald de Man
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTB_CORE_HPP_
|
||||||
|
#define RTB_CORE_HPP_
|
||||||
|
|
||||||
|
#ifndef __WIN32__
|
||||||
|
#define SEP_CHAR ':'
|
||||||
|
#define FD int
|
||||||
|
#define FD_ERR -1
|
||||||
|
#else
|
||||||
|
#include <windows.h>
|
||||||
|
#define SEP_CHAR ';'
|
||||||
|
#define FD HANDLE
|
||||||
|
#define FD_ERR INVALID_HANDLE_VALUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#define WDLSUFFIX ".rtbw"
|
||||||
|
#define DTZSUFFIX ".rtbz"
|
||||||
|
#define TBPIECES 6
|
||||||
|
|
||||||
|
#define WDL_MAGIC 0x5d23e871
|
||||||
|
#define DTZ_MAGIC 0xa50c66d7
|
||||||
|
|
||||||
|
#define TBHASHBITS 11
|
||||||
|
|
||||||
|
typedef unsigned char ubyte;
|
||||||
|
typedef unsigned short ushort;
|
||||||
|
|
||||||
|
struct TBHashEntry;
|
||||||
|
|
||||||
|
typedef uint64_t base_t;
|
||||||
|
|
||||||
|
struct PairsData {
|
||||||
|
char *indextable;
|
||||||
|
ushort *sizetable;
|
||||||
|
ubyte *data;
|
||||||
|
ushort *offset;
|
||||||
|
ubyte *symlen;
|
||||||
|
ubyte *sympat;
|
||||||
|
int blocksize;
|
||||||
|
int idxbits;
|
||||||
|
int min_len;
|
||||||
|
base_t base[1]; // C++ complains about base[]...
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TBEntry {
|
||||||
|
char *data;
|
||||||
|
uint64_t key;
|
||||||
|
uint64_t mapping;
|
||||||
|
std::atomic<ubyte> ready;
|
||||||
|
ubyte num;
|
||||||
|
ubyte symmetric;
|
||||||
|
ubyte has_pawns;
|
||||||
|
} __attribute__((__may_alias__));
|
||||||
|
|
||||||
|
struct TBEntry_piece {
|
||||||
|
char *data;
|
||||||
|
uint64_t key;
|
||||||
|
uint64_t mapping;
|
||||||
|
std::atomic<ubyte> ready;
|
||||||
|
ubyte num;
|
||||||
|
ubyte symmetric;
|
||||||
|
ubyte has_pawns;
|
||||||
|
ubyte enc_type;
|
||||||
|
struct PairsData *precomp[2];
|
||||||
|
int factor[2][TBPIECES];
|
||||||
|
ubyte pieces[2][TBPIECES];
|
||||||
|
ubyte norm[2][TBPIECES];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TBEntry_pawn {
|
||||||
|
char *data;
|
||||||
|
uint64_t key;
|
||||||
|
uint64_t mapping;
|
||||||
|
std::atomic<ubyte> ready;
|
||||||
|
ubyte num;
|
||||||
|
ubyte symmetric;
|
||||||
|
ubyte has_pawns;
|
||||||
|
ubyte pawns[2];
|
||||||
|
struct {
|
||||||
|
struct PairsData *precomp[2];
|
||||||
|
int factor[2][TBPIECES];
|
||||||
|
ubyte pieces[2][TBPIECES];
|
||||||
|
ubyte norm[2][TBPIECES];
|
||||||
|
} file[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DTZEntry_piece {
|
||||||
|
char *data;
|
||||||
|
uint64_t key;
|
||||||
|
uint64_t mapping;
|
||||||
|
std::atomic<ubyte> ready;
|
||||||
|
ubyte num;
|
||||||
|
ubyte symmetric;
|
||||||
|
ubyte has_pawns;
|
||||||
|
ubyte enc_type;
|
||||||
|
struct PairsData *precomp;
|
||||||
|
int factor[TBPIECES];
|
||||||
|
ubyte pieces[TBPIECES];
|
||||||
|
ubyte norm[TBPIECES];
|
||||||
|
ubyte flags; // accurate, mapped, side
|
||||||
|
ushort map_idx[4];
|
||||||
|
ubyte *map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DTZEntry_pawn {
|
||||||
|
char *data;
|
||||||
|
uint64_t key;
|
||||||
|
uint64_t mapping;
|
||||||
|
std::atomic<ubyte> ready;
|
||||||
|
ubyte num;
|
||||||
|
ubyte symmetric;
|
||||||
|
ubyte has_pawns;
|
||||||
|
ubyte pawns[2];
|
||||||
|
struct {
|
||||||
|
struct PairsData *precomp;
|
||||||
|
int factor[TBPIECES];
|
||||||
|
ubyte pieces[TBPIECES];
|
||||||
|
ubyte norm[TBPIECES];
|
||||||
|
} file[4];
|
||||||
|
ubyte flags[4];
|
||||||
|
ushort map_idx[4][4];
|
||||||
|
ubyte *map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TBHashEntry {
|
||||||
|
uint64_t key;
|
||||||
|
struct TBEntry *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DTZTableEntry {
|
||||||
|
uint64_t key1;
|
||||||
|
uint64_t key2;
|
||||||
|
std::atomic<TBEntry*> entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
604
DroidFish/jni/rtb/rtb-probe.cpp
Normal file
604
DroidFish/jni/rtb/rtb-probe.cpp
Normal file
@@ -0,0 +1,604 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 Ronald de Man
|
||||||
|
This file may be redistributed and/or modified without restrictions.
|
||||||
|
|
||||||
|
tbprobe.cpp contains the Stockfish-specific routines of the
|
||||||
|
tablebase probing code. It should be relatively easy to adapt
|
||||||
|
this code to other chess engines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "piece.hpp"
|
||||||
|
#include "position.hpp"
|
||||||
|
#include "moveGen.hpp"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "rtb-probe.hpp"
|
||||||
|
#include "rtb-core.hpp"
|
||||||
|
|
||||||
|
#include "rtb-core-impl.hpp"
|
||||||
|
|
||||||
|
int Syzygy::TBLargest = 0;
|
||||||
|
|
||||||
|
// Given a position with 6 or fewer pieces, produce a text string
|
||||||
|
// of the form KQPvKRP, where "KQP" represents the white pieces if
|
||||||
|
// mirror == false and the black pieces if mirror == true.
|
||||||
|
static void prt_str(Position& pos, char *str, bool mirror)
|
||||||
|
{
|
||||||
|
static_assert(Piece::WQUEEN == Piece::WKING + 1, "");
|
||||||
|
static_assert(Piece::WROOK == Piece::WQUEEN + 1, "");
|
||||||
|
static_assert(Piece::WBISHOP == Piece::WROOK + 1, "");
|
||||||
|
static_assert(Piece::WKNIGHT == Piece::WBISHOP + 1, "");
|
||||||
|
static_assert(Piece::WPAWN == Piece::WKNIGHT + 1, "");
|
||||||
|
static_assert(Piece::BQUEEN == Piece::BKING + 1, "");
|
||||||
|
static_assert(Piece::BROOK == Piece::BQUEEN + 1, "");
|
||||||
|
static_assert(Piece::BBISHOP == Piece::BROOK + 1, "");
|
||||||
|
static_assert(Piece::BKNIGHT == Piece::BBISHOP + 1, "");
|
||||||
|
static_assert(Piece::BPAWN == Piece::BKNIGHT + 1, "");
|
||||||
|
|
||||||
|
static char pchr[Piece::nPieceTypes+1] = " KQRBNPKQRBNP";
|
||||||
|
|
||||||
|
int p1Beg = mirror ? Piece::BKING : Piece::WKING;
|
||||||
|
int p1End = mirror ? Piece::BPAWN : Piece::WPAWN;
|
||||||
|
int p2Beg = mirror ? Piece::WKING : Piece::BKING;
|
||||||
|
int p2End = mirror ? Piece::WPAWN : Piece::BPAWN;
|
||||||
|
|
||||||
|
for (int p = p1Beg; p <= p1End; p++) {
|
||||||
|
int cnt = BitBoard::bitCount(pos.pieceTypeBB((Piece::Type)p));
|
||||||
|
for (int i = 0; i < cnt; i++)
|
||||||
|
*str++ = pchr[p];
|
||||||
|
}
|
||||||
|
*str++ = 'v';
|
||||||
|
for (int p = p2Beg; p <= p2End; p++) {
|
||||||
|
int cnt = BitBoard::bitCount(pos.pieceTypeBB((Piece::Type)p));
|
||||||
|
for (int i = 0; i < cnt; i++)
|
||||||
|
*str++ = pchr[p];
|
||||||
|
}
|
||||||
|
*str++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a position, produce a 64-bit material signature key.
|
||||||
|
// If the engine supports such a key, it should equal the engine's key.
|
||||||
|
static uint64_t calc_key(const Position& pos, bool mirror)
|
||||||
|
{
|
||||||
|
uint64_t h = mirror ? MatId::mirror(pos.materialId()) : pos.materialId();
|
||||||
|
h *= 0x842c2f50a7ac0ae1ULL;
|
||||||
|
h = ((h >> 32) ^ h) * 0xace7b66dbad28265ULL;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produce a 64-bit material key corresponding to the material combination
|
||||||
|
// defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
|
||||||
|
// pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
|
||||||
|
// pawns, ..., kings.
|
||||||
|
static uint64_t calc_key_from_pcs(const int *pcs, bool mirror)
|
||||||
|
{
|
||||||
|
MatId key;
|
||||||
|
key.addPieceCnt(Piece::WPAWN, pcs[1]);
|
||||||
|
key.addPieceCnt(Piece::WKNIGHT, pcs[2]);
|
||||||
|
key.addPieceCnt(Piece::WBISHOP, pcs[3]);
|
||||||
|
key.addPieceCnt(Piece::WROOK, pcs[4]);
|
||||||
|
key.addPieceCnt(Piece::WQUEEN, pcs[5]);
|
||||||
|
key.addPieceCnt(Piece::BPAWN, pcs[8+1]);
|
||||||
|
key.addPieceCnt(Piece::BKNIGHT, pcs[8+2]);
|
||||||
|
key.addPieceCnt(Piece::BBISHOP, pcs[8+3]);
|
||||||
|
key.addPieceCnt(Piece::BROOK, pcs[8+4]);
|
||||||
|
key.addPieceCnt(Piece::BQUEEN, pcs[8+5]);
|
||||||
|
|
||||||
|
uint64_t h = mirror ? MatId::mirror(key()) : key();
|
||||||
|
h *= 0x842c2f50a7ac0ae1ULL;
|
||||||
|
h = ((h >> 32) ^ h) * 0xace7b66dbad28265ULL;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t get_pieces(const Position& pos, int color, int piece) {
|
||||||
|
int p = 7 - piece;
|
||||||
|
if (color)
|
||||||
|
p += Piece::BKING - Piece::WKING;
|
||||||
|
return pos.pieceTypeBB((Piece::Type)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pop_lsb(uint64_t& bb) {
|
||||||
|
int ret = BitBoard::numberOfTrailingZeros(bb);
|
||||||
|
bb &= bb - 1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// probe_wdl_table and probe_dtz_table require similar adaptations.
|
||||||
|
static int probe_wdl_table(Position& pos, int *success)
|
||||||
|
{
|
||||||
|
struct TBEntry *ptr;
|
||||||
|
struct TBHashEntry *ptr2;
|
||||||
|
uint64_t idx;
|
||||||
|
uint64_t key;
|
||||||
|
int i;
|
||||||
|
ubyte res;
|
||||||
|
int p[TBPIECES];
|
||||||
|
|
||||||
|
// Obtain the position's material signature key.
|
||||||
|
key = calc_key(pos, false);
|
||||||
|
|
||||||
|
// Test for KvK.
|
||||||
|
if (!key) return 0;
|
||||||
|
|
||||||
|
ptr2 = WDL_hash[key >> (64 - TBHASHBITS)];
|
||||||
|
for (i = 0; i < HSHMAX; i++)
|
||||||
|
if (ptr2[i].key == key) break;
|
||||||
|
if (i == HSHMAX) {
|
||||||
|
*success = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = ptr2[i].ptr;
|
||||||
|
ubyte ready = ptr->ready.load(std::memory_order_relaxed);
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
if (!ready) {
|
||||||
|
std::lock_guard<std::mutex> L(TB_mutex);
|
||||||
|
ready = ptr->ready.load(std::memory_order_relaxed);
|
||||||
|
if (!ready) {
|
||||||
|
char str[16];
|
||||||
|
prt_str(pos, str, ptr->key != key);
|
||||||
|
if (!init_table_wdl(ptr, str)) {
|
||||||
|
ptr2[i].key = 0ULL;
|
||||||
|
*success = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
ptr->ready.store(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bside, mirror, cmirror;
|
||||||
|
if (!ptr->symmetric) {
|
||||||
|
if (key != ptr->key) {
|
||||||
|
cmirror = 8;
|
||||||
|
mirror = 0x38;
|
||||||
|
bside = pos.isWhiteMove();
|
||||||
|
} else {
|
||||||
|
cmirror = mirror = 0;
|
||||||
|
bside = !pos.isWhiteMove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmirror = pos.isWhiteMove() ? 0 : 8;
|
||||||
|
mirror = pos.isWhiteMove() ? 0 : 0x38;
|
||||||
|
bside = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// p[i] is to contain the square 0-63 (A1-H8) for a piece of type
|
||||||
|
// pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
|
||||||
|
// Pieces of the same type are guaranteed to be consecutive.
|
||||||
|
if (!ptr->has_pawns) {
|
||||||
|
struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
|
||||||
|
ubyte *pc = entry->pieces[bside];
|
||||||
|
for (i = 0; i < entry->num;) {
|
||||||
|
uint64_t bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
|
||||||
|
do {
|
||||||
|
p[i++] = pop_lsb(bb);
|
||||||
|
} while (bb);
|
||||||
|
}
|
||||||
|
idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
|
||||||
|
res = decompress_pairs(entry->precomp[bside], idx);
|
||||||
|
} else {
|
||||||
|
struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
|
||||||
|
int k = entry->file[0].pieces[0][0] ^ cmirror;
|
||||||
|
uint64_t bb = get_pieces(pos, k >> 3, k & 0x07);
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
p[i++] = pop_lsb(bb) ^ mirror;
|
||||||
|
} while (bb);
|
||||||
|
int f = pawn_file(entry, p);
|
||||||
|
ubyte *pc = entry->file[f].pieces[bside];
|
||||||
|
for (; i < entry->num;) {
|
||||||
|
bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
|
||||||
|
do {
|
||||||
|
p[i++] = pop_lsb(bb) ^ mirror;
|
||||||
|
} while (bb);
|
||||||
|
}
|
||||||
|
idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
|
||||||
|
res = decompress_pairs(entry->file[f].precomp[bside], idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((int)res) - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int probe_dtz_table(Position& pos, int wdl, int *success)
|
||||||
|
{
|
||||||
|
uint64_t idx;
|
||||||
|
int i, res;
|
||||||
|
int p[TBPIECES];
|
||||||
|
|
||||||
|
// Obtain the position's material signature key.
|
||||||
|
uint64_t key = calc_key(pos, false);
|
||||||
|
|
||||||
|
DTZTableEntry* dtzTabEnt;
|
||||||
|
{
|
||||||
|
dtzTabEnt = DTZ_hash[key >> (64 - TBHASHBITS)];
|
||||||
|
for (i = 0; i < HSHMAX; i++)
|
||||||
|
if (dtzTabEnt[i].key1 == key) break;
|
||||||
|
if (i == HSHMAX) {
|
||||||
|
uint64_t key2 = calc_key(pos, true);
|
||||||
|
dtzTabEnt = DTZ_hash[key2 >> (64 - TBHASHBITS)];
|
||||||
|
for (i = 0; i < HSHMAX; i++)
|
||||||
|
if (dtzTabEnt[i].key2 == key) break;
|
||||||
|
}
|
||||||
|
if (i == HSHMAX) {
|
||||||
|
*success = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dtzTabEnt += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
TBEntry* ptr = dtzTabEnt->entry.load(std::memory_order_relaxed);
|
||||||
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
|
if (!ptr) {
|
||||||
|
std::lock_guard<std::mutex> L(TB_mutex);
|
||||||
|
ptr = dtzTabEnt->entry.load(std::memory_order_relaxed);
|
||||||
|
if (!ptr) {
|
||||||
|
struct TBHashEntry *ptr2 = WDL_hash[key >> (64 - TBHASHBITS)];
|
||||||
|
for (i = 0; i < HSHMAX; i++)
|
||||||
|
if (ptr2[i].key == key) break;
|
||||||
|
if (i == HSHMAX) {
|
||||||
|
*success = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char str[16];
|
||||||
|
bool mirror = (ptr2[i].ptr->key != key);
|
||||||
|
prt_str(pos, str, mirror);
|
||||||
|
ptr = load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
|
||||||
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
dtzTabEnt->entry.store(ptr, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ptr) {
|
||||||
|
*success = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bside, mirror, cmirror;
|
||||||
|
if (!ptr->symmetric) {
|
||||||
|
if (key != ptr->key) {
|
||||||
|
cmirror = 8;
|
||||||
|
mirror = 0x38;
|
||||||
|
bside = pos.isWhiteMove();
|
||||||
|
} else {
|
||||||
|
cmirror = mirror = 0;
|
||||||
|
bside = !pos.isWhiteMove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmirror = pos.isWhiteMove() ? 0 : 8;
|
||||||
|
mirror = pos.isWhiteMove() ? 0 : 0x38;
|
||||||
|
bside = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ptr->has_pawns) {
|
||||||
|
struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
|
||||||
|
if ((entry->flags & 1) != bside && !entry->symmetric) {
|
||||||
|
*success = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ubyte *pc = entry->pieces;
|
||||||
|
for (i = 0; i < entry->num;) {
|
||||||
|
uint64_t bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
|
||||||
|
do {
|
||||||
|
p[i++] = pop_lsb(bb);
|
||||||
|
} while (bb);
|
||||||
|
}
|
||||||
|
idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
|
||||||
|
res = decompress_pairs(entry->precomp, idx);
|
||||||
|
|
||||||
|
if (entry->flags & 2)
|
||||||
|
res = entry->map[entry->map_idx[wdl_to_map[wdl + 2]] + res];
|
||||||
|
|
||||||
|
if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
|
||||||
|
res *= 2;
|
||||||
|
} else {
|
||||||
|
struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
|
||||||
|
int k = entry->file[0].pieces[0] ^ cmirror;
|
||||||
|
uint64_t bb = get_pieces(pos, k >> 3, k & 0x07);
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
p[i++] = pop_lsb(bb) ^ mirror;
|
||||||
|
} while (bb);
|
||||||
|
int f = pawn_file((struct TBEntry_pawn *)entry, p);
|
||||||
|
if ((entry->flags[f] & 1) != bside) {
|
||||||
|
*success = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ubyte *pc = entry->file[f].pieces;
|
||||||
|
for (; i < entry->num;) {
|
||||||
|
bb = get_pieces(pos, (pc[i] ^ cmirror) >> 3, pc[i] & 0x07);
|
||||||
|
do {
|
||||||
|
p[i++] = pop_lsb(bb) ^ mirror;
|
||||||
|
} while (bb);
|
||||||
|
}
|
||||||
|
idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
|
||||||
|
res = decompress_pairs(entry->file[f].precomp, idx);
|
||||||
|
|
||||||
|
if (entry->flags[f] & 2)
|
||||||
|
res = entry->map[entry->map_idx[f][wdl_to_map[wdl + 2]] + res];
|
||||||
|
|
||||||
|
if (!(entry->flags[f] & pa_flags[wdl + 2]) || (wdl & 1))
|
||||||
|
res *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add bishop and rook underpromotion captures to move list.
|
||||||
|
static void add_underprom_caps(Position& pos, MoveGen::MoveList& moveList)
|
||||||
|
{
|
||||||
|
const int nMoves = moveList.size;
|
||||||
|
const bool wtm = pos.isWhiteMove();
|
||||||
|
const int queen = wtm ? Piece::WQUEEN : Piece::BQUEEN;
|
||||||
|
for (int i = 0; i < nMoves; i++) {
|
||||||
|
const Move& m = moveList[i];
|
||||||
|
if ((m.promoteTo() == queen) && (pos.getPiece(m.to()) != Piece::EMPTY)) {
|
||||||
|
moveList.addMove(m.from(), m.to(), wtm ? Piece::WROOK : Piece::BROOK);
|
||||||
|
moveList.addMove(m.from(), m.to(), wtm ? Piece::WBISHOP : Piece::BBISHOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int probe_ab(Position& pos, int alpha, int beta, int *success)
|
||||||
|
{
|
||||||
|
// Generate (at least) all legal non-ep captures including (under)promotions.
|
||||||
|
// It is OK to generate more, as long as they are filtered out below.
|
||||||
|
MoveGen::MoveList moveList;
|
||||||
|
const bool inCheck = MoveGen::inCheck(pos);
|
||||||
|
if (inCheck) {
|
||||||
|
MoveGen::checkEvasions(pos, moveList);
|
||||||
|
} else {
|
||||||
|
MoveGen::pseudoLegalCaptures(pos, moveList);
|
||||||
|
// Since bishop and rook promotions are not included, we need to add them.
|
||||||
|
add_underprom_caps(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
UndoInfo ui;
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& capture = moveList[m];
|
||||||
|
if ((pos.getPiece(capture.to()) == Piece::EMPTY) ||
|
||||||
|
!MoveGen::isLegal(pos, capture, inCheck))
|
||||||
|
continue;
|
||||||
|
pos.makeMove(capture, ui);
|
||||||
|
int v = -probe_ab(pos, -beta, -alpha, success);
|
||||||
|
pos.unMakeMove(capture, ui);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (v > alpha) {
|
||||||
|
if (v >= beta) {
|
||||||
|
*success = 2;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
alpha = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int v = probe_wdl_table(pos, success);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (alpha >= v) {
|
||||||
|
*success = 1 + (alpha > 0);
|
||||||
|
return alpha;
|
||||||
|
} else {
|
||||||
|
*success = 1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Syzygy::probe_wdl(Position& pos, int *success)
|
||||||
|
{
|
||||||
|
*success = 1;
|
||||||
|
int v = probe_ab(pos, -2, 2, success);
|
||||||
|
|
||||||
|
// If en passant is not possible, we are done.
|
||||||
|
if (pos.getEpSquare() == -1)
|
||||||
|
return v;
|
||||||
|
if (!(*success)) return 0;
|
||||||
|
|
||||||
|
// Now handle en passant.
|
||||||
|
int v1 = -3;
|
||||||
|
// Generate (at least) all legal en passant captures.
|
||||||
|
MoveGen::MoveList moveList;
|
||||||
|
|
||||||
|
const bool inCheck = MoveGen::inCheck(pos);
|
||||||
|
if (inCheck) {
|
||||||
|
MoveGen::checkEvasions(pos, moveList);
|
||||||
|
} else {
|
||||||
|
MoveGen::pseudoLegalMoves(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int pawn = pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN;
|
||||||
|
UndoInfo ui;
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& capture = moveList[m];
|
||||||
|
if ((capture.to() != pos.getEpSquare()) || (pos.getPiece(capture.from()) != pawn) ||
|
||||||
|
!MoveGen::isLegal(pos, capture, inCheck))
|
||||||
|
continue;
|
||||||
|
pos.makeMove(capture, ui);
|
||||||
|
int v0 = -probe_ab(pos, -2, 2, success);
|
||||||
|
pos.unMakeMove(capture, ui);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (v0 > v1) v1 = v0;
|
||||||
|
}
|
||||||
|
if (v1 > -3) {
|
||||||
|
if (v1 >= v) v = v1;
|
||||||
|
else if (v == 0) {
|
||||||
|
// Check whether there is at least one legal non-ep move.
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& capture = moveList[m];
|
||||||
|
if ((capture.to() == pos.getEpSquare()) &&
|
||||||
|
(pos.getPiece(capture.from()) == pawn))
|
||||||
|
continue;
|
||||||
|
if (MoveGen::isLegal(pos, capture, inCheck))
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
// If not, then we are forced to play the losing ep capture.
|
||||||
|
v = v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This routine treats a position with en passant captures as one without.
|
||||||
|
static int probe_dtz_no_ep(Position& pos, int *success)
|
||||||
|
{
|
||||||
|
const int wdl = probe_ab(pos, -2, 2, success);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
|
||||||
|
if (wdl == 0) return 0;
|
||||||
|
|
||||||
|
if (*success == 2)
|
||||||
|
return wdl == 2 ? 1 : 101;
|
||||||
|
|
||||||
|
MoveGen::MoveList moveList;
|
||||||
|
const bool inCheck = MoveGen::inCheck(pos);
|
||||||
|
const int pawn = pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN;
|
||||||
|
UndoInfo ui;
|
||||||
|
|
||||||
|
if (wdl > 0) {
|
||||||
|
// Generate at least all legal non-capturing pawn moves
|
||||||
|
// including non-capturing promotions.
|
||||||
|
if (inCheck) {
|
||||||
|
MoveGen::checkEvasions(pos, moveList);
|
||||||
|
} else {
|
||||||
|
MoveGen::pseudoLegalMoves(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& move = moveList[m];
|
||||||
|
if ((pos.getPiece(move.from()) != pawn) ||
|
||||||
|
(Position::getX(move.from()) != Position::getX(move.to())) ||
|
||||||
|
!MoveGen::isLegal(pos, move, inCheck))
|
||||||
|
continue;
|
||||||
|
pos.makeMove(move, ui);
|
||||||
|
int v = -probe_ab(pos, -2, -wdl + 1, success);
|
||||||
|
pos.unMakeMove(move, ui);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (v == wdl)
|
||||||
|
return v == 2 ? 1 : 101;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtz = 1 + probe_dtz_table(pos, wdl, success);
|
||||||
|
|
||||||
|
if (*success >= 0) {
|
||||||
|
if (wdl & 1) dtz += 100;
|
||||||
|
return wdl >= 0 ? dtz : -dtz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wdl > 0) {
|
||||||
|
int best = 0xffff;
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& move = moveList[m];
|
||||||
|
if ((pos.getPiece(move.to()) != Piece::EMPTY) ||
|
||||||
|
(pos.getPiece(move.from()) == pawn) ||
|
||||||
|
!MoveGen::isLegal(pos, move, inCheck))
|
||||||
|
continue;
|
||||||
|
pos.makeMove(move, ui);
|
||||||
|
int v = -Syzygy::probe_dtz(pos, success);
|
||||||
|
pos.unMakeMove(move, ui);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (v > 0 && v + 1 < best)
|
||||||
|
best = v + 1;
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
} else {
|
||||||
|
int best = -1;
|
||||||
|
if (inCheck) {
|
||||||
|
MoveGen::checkEvasions(pos, moveList);
|
||||||
|
} else {
|
||||||
|
MoveGen::pseudoLegalMoves(pos, moveList);
|
||||||
|
}
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& move = moveList[m];
|
||||||
|
if (!MoveGen::isLegal(pos, move, inCheck))
|
||||||
|
continue;
|
||||||
|
pos.makeMove(move, ui);
|
||||||
|
int v;
|
||||||
|
if (pos.getHalfMoveClock() == 0) {
|
||||||
|
if (wdl == -2) v = -1;
|
||||||
|
else {
|
||||||
|
v = probe_ab(pos, 1, 2, success);
|
||||||
|
v = (v == 2) ? 0 : -101;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = -Syzygy::probe_dtz(pos, success) - 1;
|
||||||
|
}
|
||||||
|
pos.unMakeMove(move, ui);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (v < best)
|
||||||
|
best = v;
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wdl_to_dtz[] = {
|
||||||
|
-1, -101, 0, 101, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
int Syzygy::probe_dtz(Position& pos, int *success)
|
||||||
|
{
|
||||||
|
*success = 1;
|
||||||
|
int v = probe_dtz_no_ep(pos, success);
|
||||||
|
|
||||||
|
if (pos.getEpSquare() == -1)
|
||||||
|
return v;
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
|
||||||
|
// Now handle en passant.
|
||||||
|
int v1 = -3;
|
||||||
|
|
||||||
|
MoveGen::MoveList moveList;
|
||||||
|
const bool inCheck = MoveGen::inCheck(pos);
|
||||||
|
const int pawn = pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN;
|
||||||
|
UndoInfo ui;
|
||||||
|
|
||||||
|
if (!inCheck) {
|
||||||
|
MoveGen::pseudoLegalMoves(pos, moveList);
|
||||||
|
} else {
|
||||||
|
MoveGen::checkEvasions(pos, moveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& capture = moveList[m];
|
||||||
|
if ((capture.to() != pos.getEpSquare()) ||
|
||||||
|
(pos.getPiece(capture.from()) != pawn) ||
|
||||||
|
!MoveGen::isLegal(pos, capture, inCheck))
|
||||||
|
continue;
|
||||||
|
pos.makeMove(capture, ui);
|
||||||
|
int v0 = -probe_ab(pos, -2, 2, success);
|
||||||
|
pos.unMakeMove(capture, ui);
|
||||||
|
if (*success == 0) return 0;
|
||||||
|
if (v0 > v1) v1 = v0;
|
||||||
|
}
|
||||||
|
if (v1 > -3) {
|
||||||
|
v1 = wdl_to_dtz[v1 + 2];
|
||||||
|
if (v < -100) {
|
||||||
|
if (v1 >= 0)
|
||||||
|
v = v1;
|
||||||
|
} else if (v < 0) {
|
||||||
|
if (v1 >= 0 || v1 < 100)
|
||||||
|
v = v1;
|
||||||
|
} else if (v > 100) {
|
||||||
|
if (v1 > 0)
|
||||||
|
v = v1;
|
||||||
|
} else if (v > 0) {
|
||||||
|
if (v1 == 1)
|
||||||
|
v = v1;
|
||||||
|
} else if (v1 >= 0) {
|
||||||
|
v = v1;
|
||||||
|
} else {
|
||||||
|
for (int m = 0; m < moveList.size; m++) {
|
||||||
|
const Move& move = moveList[m];
|
||||||
|
if ((move.to() == pos.getEpSquare()) && (pos.getPiece(move.from()) == pawn))
|
||||||
|
continue;
|
||||||
|
if (MoveGen::isLegal(pos, move, inCheck))
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
v = v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
54
DroidFish/jni/rtb/rtb-probe.hpp
Normal file
54
DroidFish/jni/rtb/rtb-probe.hpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#ifndef RTB_PROBE_HPP_
|
||||||
|
#define RTB_PROBE_HPP_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Position;
|
||||||
|
|
||||||
|
namespace Syzygy {
|
||||||
|
|
||||||
|
extern int TBLargest;
|
||||||
|
|
||||||
|
void init(const std::string& path);
|
||||||
|
|
||||||
|
// Probe the WDL table for a particular position.
|
||||||
|
// If *success != 0, the probe was successful.
|
||||||
|
// The return value is from the point of view of the side to move:
|
||||||
|
// -2 : loss
|
||||||
|
// -1 : loss, but draw under 50-move rule
|
||||||
|
// 0 : draw
|
||||||
|
// 1 : win, but draw under 50-move rule
|
||||||
|
// 2 : win
|
||||||
|
int probe_wdl(Position& pos, int *success);
|
||||||
|
|
||||||
|
// Probe the DTZ table for a particular position.
|
||||||
|
// If *success != 0, the probe was successful.
|
||||||
|
// The return value is from the point of view of the side to move:
|
||||||
|
// n < -100 : loss, but draw under 50-move rule
|
||||||
|
// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
|
||||||
|
// 0 : draw
|
||||||
|
// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
|
||||||
|
// 100 < n : win, but draw under 50-move rule
|
||||||
|
//
|
||||||
|
// The return value n can be off by 1: a return value -n can mean a loss
|
||||||
|
// in n+1 ply and a return value +n can mean a win in n+1 ply. This
|
||||||
|
// cannot happen for tables with positions exactly on the "edge" of
|
||||||
|
// the 50-move rule.
|
||||||
|
//
|
||||||
|
// This implies that if dtz > 0 is returned, the position is certainly
|
||||||
|
// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
|
||||||
|
// picks moves that preserve dtz + 50-move-counter <= 99.
|
||||||
|
//
|
||||||
|
// If n = 100 immediately after a capture or pawn move, then the position
|
||||||
|
// is also certainly a win, and during the whole phase until the next
|
||||||
|
// capture or pawn move, the inequality to be preserved is
|
||||||
|
// dtz + 50-movecounter <= 100.
|
||||||
|
//
|
||||||
|
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
|
||||||
|
// then do not accept moves leading to dtz + 50-move-counter == 100.
|
||||||
|
//
|
||||||
|
int probe_dtz(Position& pos, int *success);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
108
DroidFish/jni/rtb/tbprobe.cpp
Normal file
108
DroidFish/jni/rtb/tbprobe.cpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tbprobe.cpp
|
||||||
|
*
|
||||||
|
* Created on: Jun 2, 2014
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tbprobe.hpp"
|
||||||
|
#include "rtb-probe.hpp"
|
||||||
|
#include "bitBoard.hpp"
|
||||||
|
#include "position.hpp"
|
||||||
|
#include "moveGen.hpp"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
static std::string currentRtbPath;
|
||||||
|
|
||||||
|
void
|
||||||
|
TBProbe::initialize(const std::string& rtbPath) {
|
||||||
|
if (rtbPath != currentRtbPath) {
|
||||||
|
Syzygy::init(rtbPath);
|
||||||
|
currentRtbPath = rtbPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TBProbe::rtbProbeDTZ(Position& pos, int& score) {
|
||||||
|
const int nPieces = BitBoard::bitCount(pos.occupiedBB());
|
||||||
|
if (nPieces > Syzygy::TBLargest)
|
||||||
|
return false;
|
||||||
|
if (pos.getCastleMask())
|
||||||
|
return false;
|
||||||
|
if (MoveGen::canTakeKing(pos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int success;
|
||||||
|
const int dtz = Syzygy::probe_dtz(pos, &success);
|
||||||
|
if (!success)
|
||||||
|
return false;
|
||||||
|
if (dtz == 0) {
|
||||||
|
score = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const int maxHalfMoveClock = std::abs(dtz) + pos.getHalfMoveClock();
|
||||||
|
if (abs(dtz) <= 2) {
|
||||||
|
if (maxHalfMoveClock > 101) {
|
||||||
|
score = 0;
|
||||||
|
return true;
|
||||||
|
} else if (maxHalfMoveClock == 101)
|
||||||
|
return false; // DTZ can be wrong when mate-in-1
|
||||||
|
} else {
|
||||||
|
if (maxHalfMoveClock > 100) {
|
||||||
|
score = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
score = dtz;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TBProbe::rtbProbeWDL(Position& pos, int& score) {
|
||||||
|
if (BitBoard::bitCount(pos.occupiedBB()) > Syzygy::TBLargest)
|
||||||
|
return false;
|
||||||
|
if (pos.getCastleMask())
|
||||||
|
return false;
|
||||||
|
if (MoveGen::canTakeKing(pos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int success;
|
||||||
|
int wdl = Syzygy::probe_wdl(pos, &success);
|
||||||
|
if (!success)
|
||||||
|
return false;
|
||||||
|
switch (wdl) {
|
||||||
|
case 0: case 1: case -1:
|
||||||
|
score = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
score = 1;
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
score = -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
66
DroidFish/jni/rtb/tbprobe.hpp
Normal file
66
DroidFish/jni/rtb/tbprobe.hpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tbprobe.hpp
|
||||||
|
*
|
||||||
|
* Created on: Jun 2, 2014
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TBPROBE_HPP_
|
||||||
|
#define TBPROBE_HPP_
|
||||||
|
|
||||||
|
#include "moveGen.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
class Position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle tablebase probing.
|
||||||
|
*/
|
||||||
|
class TBProbe {
|
||||||
|
public:
|
||||||
|
/** Initialize tablebases. */
|
||||||
|
static void initialize(const std::string& rtbPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe syzygy DTZ tablebases.
|
||||||
|
* @param pos The position to probe. The position can be temporarily modified
|
||||||
|
* but is restored to original state before function returns.
|
||||||
|
* @param score The tablebase score. Only modified for tablebase hits.
|
||||||
|
* The returned score is either 0 or a mate bound. The bound
|
||||||
|
* is computed by considering the DTZ value and the maximum number
|
||||||
|
* of zeroing moves before mate.
|
||||||
|
*/
|
||||||
|
static bool rtbProbeDTZ(Position& pos, int& score);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe syzygy WDL tablebases.
|
||||||
|
* @param pos The position to probe. The position can be temporarily modified
|
||||||
|
* but is restored to original state before function returns.
|
||||||
|
* @param score The tablebase score. Only modified for tablebase hits.
|
||||||
|
* The returned score is either 0 or +/- 1.
|
||||||
|
*/
|
||||||
|
static bool rtbProbeWDL(Position& pos, int& score);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* TBPROBE_HPP_ */
|
||||||
40
DroidFish/jni/rtb/undoInfo.hpp
Normal file
40
DroidFish/jni/rtb/undoInfo.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* undoInfo.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 25, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UNDOINFO_HPP_
|
||||||
|
#define UNDOINFO_HPP_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains enough information to undo a previous move.
|
||||||
|
* Set by makeMove(). Used by unMakeMove().
|
||||||
|
*/
|
||||||
|
struct UndoInfo {
|
||||||
|
int capturedPiece;
|
||||||
|
int castleMask;
|
||||||
|
int epSquare;
|
||||||
|
int halfMoveClock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* UNDOINFO_HPP_ */
|
||||||
50
DroidFish/jni/rtb/util.hpp
Normal file
50
DroidFish/jni/rtb/util.hpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
Texel - A UCI chess engine.
|
||||||
|
Copyright (C) 2012-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* util.hpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 26, 2012
|
||||||
|
* Author: petero
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_HPP_
|
||||||
|
#define UTIL_HPP_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
typedef uint64_t U64;
|
||||||
|
typedef int64_t S64;
|
||||||
|
typedef uint32_t U32;
|
||||||
|
typedef int32_t S32;
|
||||||
|
typedef uint16_t U16;
|
||||||
|
typedef int16_t S16;
|
||||||
|
typedef int8_t S8;
|
||||||
|
typedef uint8_t U8;
|
||||||
|
|
||||||
|
|
||||||
|
/** Helper class to perform static initialization of a class T. */
|
||||||
|
template <typename T>
|
||||||
|
class StaticInitializer {
|
||||||
|
public:
|
||||||
|
StaticInitializer() {
|
||||||
|
T::staticInitialize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* UTIL_HPP_ */
|
||||||
@@ -26,6 +26,7 @@ import org.petero.droidfish.gamelogic.Move;
|
|||||||
import org.petero.droidfish.gamelogic.Piece;
|
import org.petero.droidfish.gamelogic.Piece;
|
||||||
import org.petero.droidfish.gamelogic.Position;
|
import org.petero.droidfish.gamelogic.Position;
|
||||||
import org.petero.droidfish.gamelogic.UndoInfo;
|
import org.petero.droidfish.gamelogic.UndoInfo;
|
||||||
|
import org.petero.droidfish.gtb.ProbeResult;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -57,22 +58,17 @@ public abstract class ChessBoard extends View {
|
|||||||
|
|
||||||
List<Move> moveHints;
|
List<Move> moveHints;
|
||||||
|
|
||||||
/** Decoration for a square. Currently the only possible decoration is a number. */
|
/** Decoration for a square. Currently the only possible decoration is a tablebase probe result. */
|
||||||
public final static class SquareDecoration implements Comparable<SquareDecoration> {
|
public final static class SquareDecoration implements Comparable<SquareDecoration> {
|
||||||
int sq;
|
int sq;
|
||||||
int number;
|
ProbeResult tbData;
|
||||||
public SquareDecoration(int sq, int number) {
|
public SquareDecoration(int sq, ProbeResult tbData) {
|
||||||
this.sq = sq;
|
this.sq = sq;
|
||||||
this.number = number;
|
this.tbData = tbData;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(SquareDecoration another) {
|
public int compareTo(SquareDecoration another) {
|
||||||
int M0 = 100000;
|
return tbData.compareTo(another.tbData);
|
||||||
int n = number;
|
|
||||||
int s1 = (n > 0) ? M0 - n : ((n == 0) ? 0 : -M0-n);
|
|
||||||
n = another.number;
|
|
||||||
int s2 = (n > 0) ? M0 - n : ((n == 0) ? 0 : -M0-n);
|
|
||||||
return s2 - s1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private ArrayList<SquareDecoration> decorations;
|
private ArrayList<SquareDecoration> decorations;
|
||||||
@@ -681,15 +677,36 @@ public abstract class ChessBoard extends View {
|
|||||||
int xCrd = getXCrd(Position.getX(sq));
|
int xCrd = getXCrd(Position.getX(sq));
|
||||||
int yCrd = getYCrd(Position.getY(sq));
|
int yCrd = getYCrd(Position.getY(sq));
|
||||||
|
|
||||||
int num = sd.number;
|
String s = null;
|
||||||
String s;
|
int wdl = sd.tbData.wdl;
|
||||||
if (num > 0)
|
int num = (sd.tbData.score + 1) / 2;
|
||||||
|
switch (sd.tbData.type) {
|
||||||
|
case DTM:
|
||||||
|
if (wdl > 0)
|
||||||
s = "+" + String.valueOf(num);
|
s = "+" + String.valueOf(num);
|
||||||
else if (num < 0)
|
else if (wdl < 0)
|
||||||
s = String.valueOf(num);
|
s = "-" + String.valueOf(num);
|
||||||
else
|
else
|
||||||
s = "0";
|
s = "0";
|
||||||
|
break;
|
||||||
|
case DTZ:
|
||||||
|
if (wdl > 0)
|
||||||
|
s = "W" + String.valueOf(num);
|
||||||
|
else if (wdl < 0)
|
||||||
|
s = "L" + String.valueOf(num);
|
||||||
|
else
|
||||||
|
s = "0";
|
||||||
|
break;
|
||||||
|
case WDL:
|
||||||
|
if (wdl > 0)
|
||||||
|
s = "W";
|
||||||
|
else if (wdl < 0)
|
||||||
|
s = "L";
|
||||||
|
else
|
||||||
|
s = "0";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s != null) {
|
||||||
Rect bounds = new Rect();
|
Rect bounds = new Rect();
|
||||||
decorationPaint.getTextBounds(s, 0, s.length(), bounds);
|
decorationPaint.getTextBounds(s, 0, s.length(), bounds);
|
||||||
xCrd += (sqSize - (bounds.left + bounds.right)) / 2;
|
xCrd += (sqSize - (bounds.left + bounds.right)) / 2;
|
||||||
@@ -697,6 +714,7 @@ public abstract class ChessBoard extends View {
|
|||||||
canvas.drawText(s, xCrd, yCrd, decorationPaint);
|
canvas.drawText(s, xCrd, yCrd, decorationPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final int getSelectedSquare() {
|
public final int getSelectedSquare() {
|
||||||
return selectedSquare;
|
return selectedSquare;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import org.petero.droidfish.gamelogic.PgnToken;
|
|||||||
import org.petero.droidfish.gamelogic.GameTree.Node;
|
import org.petero.droidfish.gamelogic.GameTree.Node;
|
||||||
import org.petero.droidfish.gamelogic.TimeControlData;
|
import org.petero.droidfish.gamelogic.TimeControlData;
|
||||||
import org.petero.droidfish.gtb.Probe;
|
import org.petero.droidfish.gtb.Probe;
|
||||||
|
import org.petero.droidfish.gtb.ProbeResult;
|
||||||
|
|
||||||
import com.kalab.chess.enginesupport.ChessEngine;
|
import com.kalab.chess.enginesupport.ChessEngine;
|
||||||
import com.kalab.chess.enginesupport.ChessEngineResolver;
|
import com.kalab.chess.enginesupport.ChessEngineResolver;
|
||||||
@@ -147,7 +148,6 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||||||
// FIXME!!! Computer clock should stop if phone turned off (computer stops thinking if unplugged)
|
// FIXME!!! Computer clock should stop if phone turned off (computer stops thinking if unplugged)
|
||||||
// FIXME!!! Add support for "no time control" and "hour-glass time control" as defined by the PGN standard
|
// FIXME!!! Add support for "no time control" and "hour-glass time control" as defined by the PGN standard
|
||||||
|
|
||||||
// FIXME!!! Online play on FICS
|
|
||||||
// FIXME!!! Add chess960 support
|
// FIXME!!! Add chess960 support
|
||||||
// FIXME!!! Implement "hint" feature
|
// FIXME!!! Implement "hint" feature
|
||||||
|
|
||||||
@@ -1234,7 +1234,8 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||||||
private final void setEngineOptions(boolean restart) {
|
private final void setEngineOptions(boolean restart) {
|
||||||
computeNetEngineID();
|
computeNetEngineID();
|
||||||
ctrl.setEngineOptions(new EngineOptions(engineOptions), restart);
|
ctrl.setEngineOptions(new EngineOptions(engineOptions), restart);
|
||||||
Probe.getInstance().setPath(engineOptions.gtbPath, egtbForceReload);
|
Probe.getInstance().setPath(engineOptions.gtbPath, engineOptions.rtbPath,
|
||||||
|
egtbForceReload);
|
||||||
egtbForceReload = false;
|
egtbForceReload = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1259,14 +1260,14 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Probe gtbProbe = Probe.getInstance();
|
Probe gtbProbe = Probe.getInstance();
|
||||||
ArrayList<Pair<Integer, Integer>> x = gtbProbe.movePieceProbe(cb.pos, sq);
|
ArrayList<Pair<Integer,ProbeResult>> x = gtbProbe.movePieceProbe(cb.pos, sq);
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
cb.setSquareDecorations(null);
|
cb.setSquareDecorations(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<SquareDecoration> sd = new ArrayList<SquareDecoration>();
|
ArrayList<SquareDecoration> sd = new ArrayList<SquareDecoration>();
|
||||||
for (Pair<Integer,Integer> p : x)
|
for (Pair<Integer,ProbeResult> p : x)
|
||||||
sd.add(new SquareDecoration(p.first, p.second));
|
sd.add(new SquareDecoration(p.first, p.second));
|
||||||
cb.setSquareDecorations(sd);
|
cb.setSquareDecorations(sd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.petero.droidfish.gamelogic.Piece;
|
|||||||
import org.petero.droidfish.gamelogic.Position;
|
import org.petero.droidfish.gamelogic.Position;
|
||||||
import org.petero.droidfish.gamelogic.TextIO;
|
import org.petero.droidfish.gamelogic.TextIO;
|
||||||
import org.petero.droidfish.gtb.Probe;
|
import org.petero.droidfish.gtb.Probe;
|
||||||
|
import org.petero.droidfish.gtb.ProbeResult;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -256,14 +257,14 @@ public class EditBoard extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Probe gtbProbe = Probe.getInstance();
|
Probe gtbProbe = Probe.getInstance();
|
||||||
ArrayList<Pair<Integer, Integer>> x = gtbProbe.relocatePieceProbe(cb.pos, sq);
|
ArrayList<Pair<Integer,ProbeResult>> x = gtbProbe.relocatePieceProbe(cb.pos, sq);
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
cb.setSquareDecorations(null);
|
cb.setSquareDecorations(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<SquareDecoration> sd = new ArrayList<SquareDecoration>();
|
ArrayList<SquareDecoration> sd = new ArrayList<SquareDecoration>();
|
||||||
for (Pair<Integer,Integer> p : x)
|
for (Pair<Integer,ProbeResult> p : x)
|
||||||
sd.add(new SquareDecoration(p.first, p.second));
|
sd.add(new SquareDecoration(p.first, p.second));
|
||||||
cb.setSquareDecorations(sd);
|
cb.setSquareDecorations(sd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,15 +214,21 @@ public class Position {
|
|||||||
return whiteMove ? wKingSq : bKingSq;
|
return whiteMove ? wKingSq : bKingSq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Count number of pieces of a certain type. */
|
||||||
* Count number of pieces of a certain type.
|
|
||||||
*/
|
|
||||||
public final int nPieces(int pType) {
|
public final int nPieces(int pType) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
for (int sq = 0; sq < 64; sq++) {
|
for (int sq = 0; sq < 64; sq++)
|
||||||
if (squares[sq] == pType)
|
if (squares[sq] == pType)
|
||||||
ret++;
|
ret++;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Count total number of pieces. */
|
||||||
|
public final int nPieces() {
|
||||||
|
int ret = 0;
|
||||||
|
for (int sq = 0; sq < 64; sq++)
|
||||||
|
if (squares[sq] != Piece.EMPTY)
|
||||||
|
ret++;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,53 +27,56 @@ import org.petero.droidfish.gamelogic.Piece;
|
|||||||
import org.petero.droidfish.gamelogic.Position;
|
import org.petero.droidfish.gamelogic.Position;
|
||||||
import org.petero.droidfish.gamelogic.UndoInfo;
|
import org.petero.droidfish.gamelogic.UndoInfo;
|
||||||
|
|
||||||
/** Interface between Position class and GTB probing code. */
|
/** Interface between Position class and GTB/RTB probing code. */
|
||||||
public class Probe {
|
public class Probe {
|
||||||
private final GtbProbe gtb;
|
private final GtbProbe gtb;
|
||||||
|
private final RtbProbe rtb;
|
||||||
private final int whiteSquares[];
|
private final int whiteSquares[];
|
||||||
private final int blackSquares[];
|
private final int blackSquares[];
|
||||||
private final byte whitePieces[];
|
private final byte whitePieces[];
|
||||||
private final byte blackPieces[];
|
private final byte blackPieces[];
|
||||||
|
|
||||||
private static final Probe INSTANCE = new Probe();
|
private static final Probe instance = new Probe();
|
||||||
|
|
||||||
/** Get singleton instance. */
|
/** Get singleton instance. */
|
||||||
public static Probe getInstance() {
|
public static Probe getInstance() {
|
||||||
return INSTANCE;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructor. */
|
/** Constructor. */
|
||||||
private Probe() {
|
private Probe() {
|
||||||
gtb = new GtbProbe();
|
gtb = new GtbProbe();
|
||||||
|
rtb = new RtbProbe();
|
||||||
whiteSquares = new int[65];
|
whiteSquares = new int[65];
|
||||||
blackSquares = new int[65];
|
blackSquares = new int[65];
|
||||||
whitePieces = new byte[65];
|
whitePieces = new byte[65];
|
||||||
blackPieces = new byte[65];
|
blackPieces = new byte[65];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPath(String tbPath, boolean forceReload) {
|
public void setPath(String gtbPath, String rtbPath, boolean forceReload) {
|
||||||
gtb.setPath(tbPath, forceReload);
|
gtb.setPath(gtbPath, forceReload);
|
||||||
|
rtb.setPath(rtbPath, forceReload);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ProbeResult {
|
private static final class GtbProbeResult {
|
||||||
public final static int DRAW = 0;
|
public final static int DRAW = 0;
|
||||||
public final static int WMATE = 1;
|
public final static int WMATE = 1;
|
||||||
public final static int BMATE = 2;
|
public final static int BMATE = 2;
|
||||||
public final static int UNKNOWN = 3;
|
public final static int UNKNOWN = 3;
|
||||||
|
|
||||||
public int result;
|
public int result;
|
||||||
public int movesToMate; // Full moves to mate, or 0 if DRAW or UNKNOWN.
|
public int pliesToMate; // Plies to mate, or 0 if DRAW or UNKNOWN.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Probe table bases.
|
* Probe GTB tablebases.
|
||||||
* @param pos The position to probe.
|
* @param pos The position to probe.
|
||||||
* @param result Two element array. Set to [tbinfo, plies].
|
* @param result Two element array. Set to [tbinfo, plies].
|
||||||
* @return True if success.
|
* @return True if success.
|
||||||
*/
|
*/
|
||||||
public final ProbeResult probeHard(Position pos) {
|
private final GtbProbeResult gtbProbe(Position pos) {
|
||||||
ProbeResult ret = probeHardRaw(pos);
|
GtbProbeResult ret = gtbProbeRaw(pos);
|
||||||
if (ret.result == ProbeResult.DRAW && pos.getEpSquare() != -1) {
|
if (ret.result == GtbProbeResult.DRAW && pos.getEpSquare() != -1) {
|
||||||
ArrayList<Move> moveList = MoveGen.instance.legalMoves(pos);
|
ArrayList<Move> moveList = MoveGen.instance.legalMoves(pos);
|
||||||
int pawn = pos.whiteMove ? Piece.WPAWN : Piece.BPAWN;
|
int pawn = pos.whiteMove ? Piece.WPAWN : Piece.BPAWN;
|
||||||
int maxMate = -1;
|
int maxMate = -1;
|
||||||
@@ -82,29 +85,29 @@ public class Probe {
|
|||||||
if ((move.to != pos.getEpSquare()) || (pos.getPiece(move.from) != pawn))
|
if ((move.to != pos.getEpSquare()) || (pos.getPiece(move.from) != pawn))
|
||||||
return ret;
|
return ret;
|
||||||
pos.makeMove(move, ui);
|
pos.makeMove(move, ui);
|
||||||
ProbeResult ret2 = probeHard(pos);
|
GtbProbeResult ret2 = gtbProbe(pos);
|
||||||
pos.unMakeMove(move, ui);
|
pos.unMakeMove(move, ui);
|
||||||
switch (ret2.result) {
|
switch (ret2.result) {
|
||||||
case ProbeResult.DRAW:
|
case GtbProbeResult.DRAW:
|
||||||
break;
|
break;
|
||||||
case ProbeResult.WMATE:
|
case GtbProbeResult.WMATE:
|
||||||
case ProbeResult.BMATE:
|
case GtbProbeResult.BMATE:
|
||||||
maxMate = Math.max(maxMate, ret2.movesToMate);
|
maxMate = Math.max(maxMate, ret2.pliesToMate);
|
||||||
break;
|
break;
|
||||||
case ProbeResult.UNKNOWN:
|
case GtbProbeResult.UNKNOWN:
|
||||||
ret.result = ProbeResult.UNKNOWN;
|
ret.result = GtbProbeResult.UNKNOWN;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (maxMate != -1) {
|
if (maxMate != -1) {
|
||||||
ret.result = pos.whiteMove ? ProbeResult.BMATE : ProbeResult.WMATE;
|
ret.result = pos.whiteMove ? GtbProbeResult.BMATE : GtbProbeResult.WMATE;
|
||||||
ret.movesToMate = maxMate;
|
ret.pliesToMate = maxMate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ProbeResult probeHardRaw(Position pos) {
|
private final GtbProbeResult gtbProbeRaw(Position pos) {
|
||||||
int castleMask = 0;
|
int castleMask = 0;
|
||||||
if (pos.a1Castle()) castleMask |= GtbProbe.A1_CASTLE;
|
if (pos.a1Castle()) castleMask |= GtbProbe.A1_CASTLE;
|
||||||
if (pos.h1Castle()) castleMask |= GtbProbe.H1_CASTLE;
|
if (pos.h1Castle()) castleMask |= GtbProbe.H1_CASTLE;
|
||||||
@@ -183,33 +186,81 @@ public class Probe {
|
|||||||
whiteSquares, blackSquares, whitePieces, blackPieces,
|
whiteSquares, blackSquares, whitePieces, blackPieces,
|
||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
ProbeResult ret = new ProbeResult();
|
GtbProbeResult ret = new GtbProbeResult();
|
||||||
if (res) {
|
if (res) {
|
||||||
switch (result[0]) {
|
switch (result[0]) {
|
||||||
case GtbProbe.DRAW:
|
case GtbProbe.DRAW:
|
||||||
ret.result = ProbeResult.DRAW;
|
ret.result = GtbProbeResult.DRAW;
|
||||||
ret.movesToMate = 0;
|
ret.pliesToMate = 0;
|
||||||
break;
|
break;
|
||||||
case GtbProbe.WMATE:
|
case GtbProbe.WMATE:
|
||||||
ret.result = ProbeResult.WMATE;
|
ret.result = GtbProbeResult.WMATE;
|
||||||
ret.movesToMate = (result[1] + 1) / 2;
|
ret.pliesToMate = result[1];
|
||||||
break;
|
break;
|
||||||
case GtbProbe.BMATE:
|
case GtbProbe.BMATE:
|
||||||
ret.result = ProbeResult.BMATE;
|
ret.result = GtbProbeResult.BMATE;
|
||||||
ret.movesToMate = (result[1] + 1) / 2;
|
ret.pliesToMate = result[1];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret.result = ProbeResult.UNKNOWN;
|
ret.result = GtbProbeResult.UNKNOWN;
|
||||||
ret.movesToMate = 0;
|
ret.pliesToMate = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret.result = ProbeResult.UNKNOWN;
|
ret.result = GtbProbeResult.UNKNOWN;
|
||||||
ret.movesToMate = 0;
|
ret.pliesToMate = 0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ProbeResult rtbProbe(Position pos) {
|
||||||
|
if (pos.nPieces() > 6)
|
||||||
|
return new ProbeResult(ProbeResult.Type.NONE, 0, 0);
|
||||||
|
|
||||||
|
rtb.initIfNeeded();
|
||||||
|
|
||||||
|
byte[] squares = new byte[64];
|
||||||
|
for (int sq = 0; sq < 64; sq++)
|
||||||
|
squares[sq] = (byte)pos.getPiece(sq);
|
||||||
|
int[] result = new int[2];
|
||||||
|
rtb.probe(squares, pos.whiteMove, pos.getEpSquare(), pos.getCastleMask(),
|
||||||
|
pos.halfMoveClock, pos.fullMoveCounter, result);
|
||||||
|
int wdl = 0;
|
||||||
|
if (result[1] != RtbProbe.NOINFO) {
|
||||||
|
int score = result[1];
|
||||||
|
if (score > 0) {
|
||||||
|
wdl = 1;
|
||||||
|
} else if (score < 0) {
|
||||||
|
wdl = -1;
|
||||||
|
score = -score;
|
||||||
|
}
|
||||||
|
return new ProbeResult(ProbeResult.Type.DTZ, wdl, score);
|
||||||
|
} else if (result[0] != RtbProbe.NOINFO) {
|
||||||
|
return new ProbeResult(ProbeResult.Type.WDL, result[0], 0);
|
||||||
|
} else {
|
||||||
|
return new ProbeResult(ProbeResult.Type.NONE, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ProbeResult probe(Position pos) {
|
||||||
|
GtbProbeResult gtbRes = gtbProbe(pos);
|
||||||
|
if (gtbRes.result != GtbProbeResult.UNKNOWN) {
|
||||||
|
int wdl = 0;
|
||||||
|
int score = 0;
|
||||||
|
if (gtbRes.result == GtbProbeResult.WMATE) {
|
||||||
|
wdl = 1;
|
||||||
|
score = gtbRes.pliesToMate;
|
||||||
|
} else if (gtbRes.result == GtbProbeResult.BMATE) {
|
||||||
|
wdl = -1;
|
||||||
|
score = gtbRes.pliesToMate;
|
||||||
|
}
|
||||||
|
if (!pos.whiteMove)
|
||||||
|
wdl = -wdl;
|
||||||
|
return new ProbeResult(ProbeResult.Type.DTM, wdl, score);
|
||||||
|
}
|
||||||
|
return rtbProbe(pos);
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a list of all moves in moveList that are not known to be non-optimal.
|
/** Return a list of all moves in moveList that are not known to be non-optimal.
|
||||||
* Returns null if no legal move could be excluded. */
|
* Returns null if no legal move could be excluded. */
|
||||||
public final ArrayList<Move> removeNonOptimal(Position pos, ArrayList<Move> moveList) {
|
public final ArrayList<Move> removeNonOptimal(Position pos, ArrayList<Move> moveList) {
|
||||||
@@ -220,16 +271,16 @@ public class Probe {
|
|||||||
UndoInfo ui = new UndoInfo();
|
UndoInfo ui = new UndoInfo();
|
||||||
for (Move m : moveList) {
|
for (Move m : moveList) {
|
||||||
pos.makeMove(m, ui);
|
pos.makeMove(m, ui);
|
||||||
ProbeResult res = probeHard(pos);
|
GtbProbeResult res = gtbProbe(pos);
|
||||||
pos.unMakeMove(m, ui);
|
pos.unMakeMove(m, ui);
|
||||||
if (res.result == ProbeResult.UNKNOWN) {
|
if (res.result == GtbProbeResult.UNKNOWN) {
|
||||||
unknownMoves.add(m);
|
unknownMoves.add(m);
|
||||||
} else {
|
} else {
|
||||||
int wScore;
|
int wScore;
|
||||||
if (res.result == ProbeResult.WMATE)
|
if (res.result == GtbProbeResult.WMATE)
|
||||||
wScore = MATE0 - res.movesToMate;
|
wScore = MATE0 - res.pliesToMate;
|
||||||
else if (res.result == ProbeResult.BMATE)
|
else if (res.result == GtbProbeResult.BMATE)
|
||||||
wScore = -(MATE0 - res.movesToMate);
|
wScore = -(MATE0 - res.pliesToMate);
|
||||||
else
|
else
|
||||||
wScore = 0;
|
wScore = 0;
|
||||||
int score = pos.whiteMove ? wScore : -wScore;
|
int score = pos.whiteMove ? wScore : -wScore;
|
||||||
@@ -251,11 +302,11 @@ public class Probe {
|
|||||||
|
|
||||||
/** For a given position and from square, return EGTB information
|
/** For a given position and from square, return EGTB information
|
||||||
* about all legal destination squares. Return null if no information available. */
|
* about all legal destination squares. Return null if no information available. */
|
||||||
public final ArrayList<Pair<Integer,Integer>> movePieceProbe(Position pos, int fromSq) {
|
public final ArrayList<Pair<Integer,ProbeResult>> movePieceProbe(Position pos, int fromSq) {
|
||||||
int p = pos.getPiece(fromSq);
|
int p = pos.getPiece(fromSq);
|
||||||
if ((p == Piece.EMPTY) || (pos.whiteMove != Piece.isWhite(p)))
|
if ((p == Piece.EMPTY) || (pos.whiteMove != Piece.isWhite(p)))
|
||||||
return null;
|
return null;
|
||||||
ArrayList<Pair<Integer,Integer>> ret = new ArrayList<Pair<Integer,Integer>>();
|
ArrayList<Pair<Integer,ProbeResult>> ret = new ArrayList<Pair<Integer,ProbeResult>>();
|
||||||
|
|
||||||
ArrayList<Move> moveList = new MoveGen().legalMoves(pos);
|
ArrayList<Move> moveList = new MoveGen().legalMoves(pos);
|
||||||
UndoInfo ui = new UndoInfo();
|
UndoInfo ui = new UndoInfo();
|
||||||
@@ -263,17 +314,18 @@ public class Probe {
|
|||||||
if (m.from != fromSq)
|
if (m.from != fromSq)
|
||||||
continue;
|
continue;
|
||||||
pos.makeMove(m, ui);
|
pos.makeMove(m, ui);
|
||||||
ProbeResult res = probeHard(pos);
|
boolean isZeroing = pos.halfMoveClock == 0;
|
||||||
|
ProbeResult res = probe(pos);
|
||||||
pos.unMakeMove(m, ui);
|
pos.unMakeMove(m, ui);
|
||||||
if (res.result == ProbeResult.UNKNOWN)
|
if (res.type == ProbeResult.Type.NONE)
|
||||||
continue;
|
continue;
|
||||||
int score = 0;
|
res.wdl = -res.wdl;
|
||||||
if (res.result == ProbeResult.WMATE) {
|
if (isZeroing && (res.type == ProbeResult.Type.DTZ)) {
|
||||||
score = pos.whiteMove ? res.movesToMate + 1 : -res.movesToMate;
|
res.score = 1;
|
||||||
} else if (res.result == ProbeResult.BMATE) {
|
} else if (res.type != ProbeResult.Type.WDL) {
|
||||||
score = pos.whiteMove ? -res.movesToMate : res.movesToMate + 1;
|
res.score++;
|
||||||
}
|
}
|
||||||
ret.add(new Pair<Integer,Integer>(m.to, score));
|
ret.add(new Pair<Integer,ProbeResult>(m.to, res));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -281,12 +333,12 @@ public class Probe {
|
|||||||
/** For a given position and from square, return EGTB information
|
/** For a given position and from square, return EGTB information
|
||||||
* about all legal alternative positions for the piece on from square.
|
* about all legal alternative positions for the piece on from square.
|
||||||
* Return null if no information is available. */
|
* Return null if no information is available. */
|
||||||
public final ArrayList<Pair<Integer, Integer>> relocatePieceProbe(Position pos, int fromSq) {
|
public final ArrayList<Pair<Integer,ProbeResult>> relocatePieceProbe(Position pos, int fromSq) {
|
||||||
int p = pos.getPiece(fromSq);
|
int p = pos.getPiece(fromSq);
|
||||||
if (p == Piece.EMPTY)
|
if (p == Piece.EMPTY)
|
||||||
return null;
|
return null;
|
||||||
boolean isPawn = (Piece.makeWhite(p) == Piece.WPAWN);
|
boolean isPawn = (Piece.makeWhite(p) == Piece.WPAWN);
|
||||||
ArrayList<Pair<Integer,Integer>> ret = new ArrayList<Pair<Integer,Integer>>();
|
ArrayList<Pair<Integer,ProbeResult>> ret = new ArrayList<Pair<Integer,ProbeResult>>();
|
||||||
for (int sq = 0; sq < 64; sq++) {
|
for (int sq = 0; sq < 64; sq++) {
|
||||||
if ((sq != fromSq) && (pos.getPiece(sq) != Piece.EMPTY))
|
if ((sq != fromSq) && (pos.getPiece(sq) != Piece.EMPTY))
|
||||||
continue;
|
continue;
|
||||||
@@ -294,18 +346,14 @@ public class Probe {
|
|||||||
continue;
|
continue;
|
||||||
pos.setPiece(fromSq, Piece.EMPTY);
|
pos.setPiece(fromSq, Piece.EMPTY);
|
||||||
pos.setPiece(sq, p);
|
pos.setPiece(sq, p);
|
||||||
ProbeResult res = probeHard(pos);
|
ProbeResult res = probe(pos);
|
||||||
pos.setPiece(sq, Piece.EMPTY);
|
pos.setPiece(sq, Piece.EMPTY);
|
||||||
pos.setPiece(fromSq, p);
|
pos.setPiece(fromSq, p);
|
||||||
if (res.result == ProbeResult.UNKNOWN)
|
if (res.type == ProbeResult.Type.NONE)
|
||||||
continue;
|
continue;
|
||||||
int score = 0;
|
if (!pos.whiteMove)
|
||||||
if (res.result == ProbeResult.WMATE) {
|
res.wdl = -res.wdl;
|
||||||
score = res.movesToMate;
|
ret.add(new Pair<Integer,ProbeResult>(sq, res));
|
||||||
} else if (res.result == ProbeResult.BMATE) {
|
|
||||||
score = -res.movesToMate;
|
|
||||||
}
|
|
||||||
ret.add(new Pair<Integer,Integer>(sq, score));
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
96
DroidFish/src/org/petero/droidfish/gtb/ProbeResult.java
Normal file
96
DroidFish/src/org/petero/droidfish/gtb/ProbeResult.java
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package org.petero.droidfish.gtb;
|
||||||
|
|
||||||
|
/** Tablebase probe result. */
|
||||||
|
public final class ProbeResult implements Comparable<ProbeResult> {
|
||||||
|
public static enum Type {
|
||||||
|
DTM, // score is distance (full moves) to mate, or 0
|
||||||
|
DTZ, // score is distance (full moves) to zeroing move, or 0
|
||||||
|
WDL, // score is +-1 or 0
|
||||||
|
NONE, // No info available, score is 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type type;
|
||||||
|
public int wdl; // +1 if if side to move wins, 0 for draw, -1 for loss
|
||||||
|
public int score; // Distance to win in plies. Always >= 0.
|
||||||
|
// Note! Zero if side to move is checkmated.
|
||||||
|
|
||||||
|
ProbeResult(Type type, int wdl, int score) {
|
||||||
|
this.type = type;
|
||||||
|
this.wdl = wdl;
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return > 0 if other is "better" than this.
|
||||||
|
* A win is better than a draw, which is better than a loss.
|
||||||
|
* A DTM win is better than a DTZ win, which is better than a WDL win.
|
||||||
|
* A WDL loss is better than a DTZ loss, which is better than a DTM loss.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final int compareTo(ProbeResult other) {
|
||||||
|
final Type type1 = this.type;
|
||||||
|
final Type type2 = other.type;
|
||||||
|
final boolean none1 = type1 == Type.NONE;
|
||||||
|
final boolean none2 = type2 == Type.NONE;
|
||||||
|
if (none1 != none2)
|
||||||
|
return none2 ? -1 : 1;
|
||||||
|
if (none1)
|
||||||
|
return 0;
|
||||||
|
final int wdl1 = this.wdl;
|
||||||
|
final int wdl2 = other.wdl;
|
||||||
|
final boolean win1 = wdl1 > 0;
|
||||||
|
final boolean win2 = wdl2 > 0;
|
||||||
|
if (win1 != win2)
|
||||||
|
return win2 ? 1 : -1;
|
||||||
|
final boolean draw1 = wdl1 == 0;
|
||||||
|
final boolean draw2 = wdl2 == 0;
|
||||||
|
if (draw1 != draw2)
|
||||||
|
return draw2 ? 1 : -1;
|
||||||
|
final int score1 = this.score;
|
||||||
|
final int score2 = other.score;
|
||||||
|
if (win1) {
|
||||||
|
final boolean dtm1 = type1 == Type.DTM;
|
||||||
|
final boolean dtm2 = type2 == Type.DTM;
|
||||||
|
if (dtm1 != dtm2)
|
||||||
|
return dtm2 ? 1 : -1;
|
||||||
|
if (dtm1)
|
||||||
|
return -compareScore(wdl1, score1, wdl2, score2);
|
||||||
|
final boolean dtz1 = type1 == Type.DTZ;
|
||||||
|
final boolean dtz2 = type2 == Type.DTZ;
|
||||||
|
if (dtz1 != dtz2)
|
||||||
|
return dtz2 ? 1 : -1;
|
||||||
|
return -compareScore(wdl1, score1, wdl2, score2);
|
||||||
|
} else if (draw1) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
final boolean wdlType1 = type1 == Type.WDL;
|
||||||
|
final boolean wdlType2 = type2 == Type.WDL;
|
||||||
|
if (wdlType1 != wdlType2)
|
||||||
|
return wdlType2 ? 1 : -1;
|
||||||
|
if (wdlType1)
|
||||||
|
return -compareScore(wdl1, score1, wdl2, score2);
|
||||||
|
final boolean dtzType1 = type1 == Type.DTZ;
|
||||||
|
final boolean dtzType2 = type2 == Type.DTZ;
|
||||||
|
if (dtzType1 != dtzType2)
|
||||||
|
return dtzType2 ? 1 : -1;
|
||||||
|
return -compareScore(wdl1, score1, wdl2, score2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return f((wdl1,score1)) - f((wdl2,score2)), where f(x) modifies
|
||||||
|
* the score so that larger values are better. */
|
||||||
|
final static int compareScore(int wdl1, int score1,
|
||||||
|
int wdl2, int score2) {
|
||||||
|
final int M = 1000;
|
||||||
|
if (wdl1 > 0)
|
||||||
|
score1 = M - score1;
|
||||||
|
else if (wdl1 < 0)
|
||||||
|
score1 = -M + score1;
|
||||||
|
|
||||||
|
if (wdl2 > 0)
|
||||||
|
score2 = M - score2;
|
||||||
|
else if (wdl2 < 0)
|
||||||
|
score2 = -M + score2;
|
||||||
|
return score1 - score2;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
DroidFish/src/org/petero/droidfish/gtb/RtbProbe.java
Normal file
95
DroidFish/src/org/petero/droidfish/gtb/RtbProbe.java
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
DroidFish - An Android chess program.
|
||||||
|
Copyright (C) 2011-2014 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.petero.droidfish.gtb;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
import org.petero.droidfish.engine.EngineUtil;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
public class RtbProbe {
|
||||||
|
static {
|
||||||
|
System.loadLibrary("rtb");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currTbPath = "";
|
||||||
|
private ConcurrentLinkedQueue<String> tbPathQueue = new ConcurrentLinkedQueue<String>();
|
||||||
|
|
||||||
|
RtbProbe() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setPath(String tbPath, boolean forceReload) {
|
||||||
|
if (forceReload || !tbPathQueue.isEmpty() || !currTbPath.equals(tbPath)) {
|
||||||
|
tbPathQueue.add(tbPath);
|
||||||
|
Thread t = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Sleep 0.4s to increase probability that engine
|
||||||
|
// is initialized before TB.
|
||||||
|
try { Thread.sleep(400); } catch (InterruptedException e) { }
|
||||||
|
initIfNeeded();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final synchronized void initIfNeeded() {
|
||||||
|
String path = tbPathQueue.poll();
|
||||||
|
while (!tbPathQueue.isEmpty())
|
||||||
|
path = tbPathQueue.poll();
|
||||||
|
if (path != null) {
|
||||||
|
currTbPath = path;
|
||||||
|
synchronized (EngineUtil.nativeLock) {
|
||||||
|
init(currTbPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static int NOINFO = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe table bases.
|
||||||
|
* @param squares Array of length 64, see Position class.
|
||||||
|
* @param wtm True if white to move.
|
||||||
|
* @param epSq En passant square, see Position class.
|
||||||
|
* @param castleMask Castle mask, see Position class.
|
||||||
|
* @param halfMoveClock half move clock, see Position class.
|
||||||
|
* @param fullMoveCounter Full move counter, see Position class.
|
||||||
|
* @param result Two element array. Set to [wdlScore, dtzScore].
|
||||||
|
* The wdl score is one of: 0: Draw
|
||||||
|
* 1: win for side to move
|
||||||
|
* -1: loss for side to move
|
||||||
|
* NOINFO: No info available
|
||||||
|
* The dtz score is one of: 0: Draw
|
||||||
|
* x>0: Win in x plies
|
||||||
|
* x<0: Loss in -x plies
|
||||||
|
* NOINFO: No info available
|
||||||
|
* @return True if success.
|
||||||
|
*/
|
||||||
|
public final native void probe(byte[] squares,
|
||||||
|
boolean wtm,
|
||||||
|
int epSq, int castleMask,
|
||||||
|
int halfMoveClock,
|
||||||
|
int fullMoveCounter,
|
||||||
|
int[] result);
|
||||||
|
|
||||||
|
private final native static boolean init(String tbPath);
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="1.0" >
|
android:versionName="1.0" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="3" />
|
<uses-sdk android:minSdkVersion="4" />
|
||||||
|
|
||||||
<instrumentation
|
<instrumentation
|
||||||
android:name="android.test.InstrumentationTestRunner"
|
android:name="android.test.InstrumentationTestRunner"
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
<application
|
<application
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name" >
|
android:label="@string/app_name"
|
||||||
|
android:allowBackup="true">
|
||||||
<uses-library android:name="android.test.runner" />
|
<uses-library android:name="android.test.runner" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|||||||
214
DroidFishTest/src/org/petero/droidfish/gtb/ProbeResultTest.java
Normal file
214
DroidFishTest/src/org/petero/droidfish/gtb/ProbeResultTest.java
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package org.petero.droidfish.gtb;
|
||||||
|
|
||||||
|
import org.petero.droidfish.gtb.ProbeResult.Type;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class ProbeResultTest extends TestCase {
|
||||||
|
public ProbeResultTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCompareScore() {
|
||||||
|
assertEquals(0, ProbeResult.compareScore(0, 0, 0, 0));
|
||||||
|
assertEquals(0, ProbeResult.compareScore(1, 3, 1, 3));
|
||||||
|
assertEquals(0, ProbeResult.compareScore(-1, 4, -1, 4));
|
||||||
|
assertEquals(true, ProbeResult.compareScore(0, 0, 1, 1) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(1, 1, 1, 2) > 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 1, 0, 0) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 20, -1, 10) > 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 20, 1, 21) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 20, 1, 19) < 0);
|
||||||
|
|
||||||
|
assertEquals(true, ProbeResult.compareScore(1, 0, 0, 0) > 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(1, 0, 1, 1) > 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(0, 0, 1, 0) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(1, 1, 1, 0) < 0);
|
||||||
|
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 0, 0, 0) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 0, -1, 1) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(0, 0, -1, 0) > 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 1, -1, 0) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, ProbeResult.compareScore(-1, 0, 1, 0) < 0);
|
||||||
|
assertEquals(true, ProbeResult.compareScore(1, 0, -1, 0) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCompareProbeResult() {
|
||||||
|
// NONE vs NONE
|
||||||
|
assertEquals(0, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.NONE, 0, 0)));
|
||||||
|
assertEquals(0, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.NONE, 1, 2)));
|
||||||
|
assertEquals(0, new ProbeResult(Type.NONE, 1, 2).compareTo(new ProbeResult(Type.NONE, -1, 3)));
|
||||||
|
assertEquals(0, new ProbeResult(Type.NONE, 1, 2).compareTo(new ProbeResult(Type.NONE, 0, 0)));
|
||||||
|
assertEquals(0, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.NONE, 1, 2)));
|
||||||
|
|
||||||
|
// NONE vs DTM,DTZ,WDL
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.WDL, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.DTM, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.DTZ, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.DTM, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.DTZ, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 0, 0).compareTo(new ProbeResult(Type.WDL, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 1).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 1).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 1).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 1).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.NONE, 0, 0)) < 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.WDL, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.DTM, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.DTZ, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.DTM, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.DTZ, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, 1, 1).compareTo(new ProbeResult(Type.WDL, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 1).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 1).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 1).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 1).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.NONE, 1, 1)) < 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.WDL, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.DTM, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.DTZ, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.DTM, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.DTZ, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.NONE, -1, 1).compareTo(new ProbeResult(Type.WDL, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 1).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 1).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 1).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 1).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.NONE, -1, 1)) < 0);
|
||||||
|
|
||||||
|
// DTM vs DTM
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTM, 1, 10)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTM, 1, 11)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 11).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTM, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTM, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 1).compareTo(new ProbeResult(Type.DTM, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 1).compareTo(new ProbeResult(Type.DTM, -1, 1)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 1).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTM, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 3).compareTo(new ProbeResult(Type.DTM, -1, 3)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 3).compareTo(new ProbeResult(Type.DTM, -1, 5)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 5).compareTo(new ProbeResult(Type.DTM, -1, 3)) < 0);
|
||||||
|
|
||||||
|
// DTZ vs DTZ
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 10).compareTo(new ProbeResult(Type.DTZ, 1, 10)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 10).compareTo(new ProbeResult(Type.DTZ, 1, 11)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 11).compareTo(new ProbeResult(Type.DTZ, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTZ, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTZ, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 1).compareTo(new ProbeResult(Type.DTZ, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 1).compareTo(new ProbeResult(Type.DTZ, -1, 1)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 1).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTZ, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 3).compareTo(new ProbeResult(Type.DTZ, -1, 3)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 3).compareTo(new ProbeResult(Type.DTZ, -1, 5)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 5).compareTo(new ProbeResult(Type.DTZ, -1, 3)) < 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.WDL, -1, 1)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.WDL, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.WDL, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.WDL, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.WDL, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.WDL, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.WDL, 1, 1)) == 0);
|
||||||
|
|
||||||
|
// DTM vs DTZ
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTZ, 1, 11)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTZ, 1, 9)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTZ, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTZ, -1, 11)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.DTZ, -1, 9)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 11).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 9).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 11).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 9).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTZ, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTZ, 1, 3)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTZ, -1, 4)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTM, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 3).compareTo(new ProbeResult(Type.DTM, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 4).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.DTZ, -1, 7)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.DTZ, -1, 9)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.DTZ, 1, 7)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.DTZ, 1, 9)) > 0);
|
||||||
|
|
||||||
|
// DTM vs WDL
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.WDL, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.WDL, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 10).compareTo(new ProbeResult(Type.WDL, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.DTM, 1, 10)) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.WDL, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.WDL, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.DTM, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.DTM, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.WDL, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.WDL, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 8).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
|
||||||
|
// DTZ vs WDL
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 10).compareTo(new ProbeResult(Type.WDL, 1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 10).compareTo(new ProbeResult(Type.WDL, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 10).compareTo(new ProbeResult(Type.WDL, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.DTZ, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.DTZ, 1, 10)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.DTZ, 1, 10)) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.WDL, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.WDL, -1, 1)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 0, 0).compareTo(new ProbeResult(Type.DTZ, 0, 0)) == 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, 1, 1).compareTo(new ProbeResult(Type.DTZ, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.WDL, -1, 1).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 8).compareTo(new ProbeResult(Type.WDL, -1, 1)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 8).compareTo(new ProbeResult(Type.WDL, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 8).compareTo(new ProbeResult(Type.WDL, 1, 1)) > 0);
|
||||||
|
|
||||||
|
// Win-in-zero and loss-in-zero
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 1, 0).compareTo(new ProbeResult(Type.DTM, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTM, 1, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, -1, 0).compareTo(new ProbeResult(Type.DTM, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTM, 0, 0).compareTo(new ProbeResult(Type.DTM, -1, 0)) < 0);
|
||||||
|
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 1, 0).compareTo(new ProbeResult(Type.DTZ, 0, 0)) < 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTZ, 1, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, -1, 0).compareTo(new ProbeResult(Type.DTZ, 0, 0)) > 0);
|
||||||
|
assertEquals(true, new ProbeResult(Type.DTZ, 0, 0).compareTo(new ProbeResult(Type.DTZ, -1, 0)) < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
DroidFishTest/src/org/petero/droidfish/gtb/ProbeTest.java
Normal file
31
DroidFishTest/src/org/petero/droidfish/gtb/ProbeTest.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package org.petero.droidfish.gtb;
|
||||||
|
|
||||||
|
import org.petero.droidfish.gamelogic.Position;
|
||||||
|
import org.petero.droidfish.gamelogic.TextIO;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class ProbeTest extends TestCase {
|
||||||
|
public ProbeTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDTZProbe() throws Throwable {
|
||||||
|
Probe probe = Probe.getInstance();
|
||||||
|
String sd = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||||
|
probe.setPath("", sd + "/DroidFish/rtb", true);
|
||||||
|
|
||||||
|
Position pos = TextIO.readFEN("K7/P1k2b2/8/3N4/8/8/8/8 b - - 0 1");
|
||||||
|
ProbeResult res = probe.probe(pos);
|
||||||
|
assertEquals(ProbeResult.Type.DTZ, res.type);
|
||||||
|
assertEquals(1, res.wdl);
|
||||||
|
assertEquals(1, res.score);
|
||||||
|
|
||||||
|
pos = TextIO.readFEN("8/5N2/8/8/p1N2k2/3K4/8/8 w - - 0 1"); // Draw because of 50-move rule
|
||||||
|
res = probe.probe(pos);
|
||||||
|
assertEquals(ProbeResult.Type.DTZ, res.type);
|
||||||
|
assertEquals(0, res.wdl);
|
||||||
|
assertEquals(0, res.score);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user