CuckooChess: Back-ported Texel improvements to CuckooChess. +24 ELO against previous version after 1894 games at 60/6 time control.

This commit is contained in:
Peter Osterlund 2012-07-15 10:39:23 +00:00
parent 6861e6d266
commit ab87bb9ae8
12 changed files with 292 additions and 185 deletions

View File

@ -20,6 +20,7 @@ package uci;
import chess.Book;
import chess.ComputerPlayer;
import chess.History;
import chess.Move;
import chess.MoveGen;
import chess.Parameters;
@ -51,6 +52,7 @@ public class EngineControl {
private final Object threadMutex;
Search sc;
TranspositionTable tt;
History ht;
MoveGen moveGen;
Position pos;
@ -120,6 +122,7 @@ public class EngineControl {
this.os = os;
threadMutex = new Object();
setupTT();
ht = new History();
moveGen = new MoveGen();
}
@ -163,6 +166,7 @@ public class EngineControl {
final public void newGame() {
randomSeed = new Random().nextLong();
tt.clear();
ht.init();
}
/**
@ -222,7 +226,7 @@ public class EngineControl {
final private void startThread(final int minTimeLimit, final int maxTimeLimit,
int maxDepth, final int maxNodes) {
synchronized (threadMutex) {} // Must not start new search until old search is finished
sc = new Search(pos, posHashList, posHashListSize, tt);
sc = new Search(pos, posHashList, posHashListSize, tt, ht);
sc.timeLimit(minTimeLimit, maxTimeLimit);
sc.setListener(new SearchListener(os));
sc.setStrength(strength, randomSeed);

View File

@ -116,30 +116,30 @@ public class BitBoard {
private final static long[][] rTables;
private final static long[] rMasks;
private final static int[] rBits = { 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, 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, 11, 11 };
11, 10, 10, 10, 10, 11, 10, 11 };
private final static long[] rMagics = {
0x0080011084624000L, 0x1440031000200141L, 0x2080082004801000L, 0x0100040900100020L,
0x0200020010200408L, 0x0300010008040002L, 0x040024081000a102L, 0x0080003100054680L,
0x1100800040008024L, 0x8440401000200040L, 0x0432001022008044L, 0x0402002200100840L,
0x4024808008000400L, 0x100a000410820008L, 0x8042001144020028L, 0x2451000041002082L,
0x1080004000200056L, 0xd41010c020004000L, 0x0004410020001104L, 0x0000818050000800L,
0x0000050008010010L, 0x0230808002000400L, 0x2000440090022108L, 0x0488020000811044L,
0x8000410100208006L, 0x2000a00240100140L, 0x2088802200401600L, 0x0a10100180080082L,
0x0000080100110004L, 0x0021002300080400L, 0x8400880400010230L, 0x2001008200004401L,
0x0000400022800480L, 0x00200040e2401000L, 0x4004100084802000L, 0x0218800800801002L,
0x0420800800800400L, 0x002a000402001008L, 0x0e0b000401008200L, 0x0815908072000401L,
0x1840008002498021L, 0x1070122002424000L, 0x1040200100410010L, 0x0600080010008080L,
0x0215001008010004L, 0x0000020004008080L, 0x1300021051040018L, 0x0004040040820001L,
0x48fffe99fecfaa00L, 0x48fffe99fecfaa00L, 0x497fffadff9c2e00L, 0x613fffddffce9200L,
0xffffffe9ffe7ce00L, 0xfffffff5fff3e600L, 0x2000080281100400L, 0x510ffff5f63c96a0L,
0xebffffb9ff9fc526L, 0x61fffeddfeedaeaeL, 0x53bfffedffdeb1a2L, 0x127fffb9ffdfb5f6L,
0x411fffddffdbf4d6L, 0x0005000208040001L, 0x264038060100d004L, 0x7645fffecbfea79eL,
0x19a80065ff2bffffL, 0x3fd80075ffebffffL, 0x4010000df6f6fffeL, 0x0050001faffaffffL,
0x0050028004ffffb0L, 0x7f600280089ffff1L, 0x7f5000b0029ffffcL, 0x5b58004848a7fffaL,
0x002a90005547ffffL, 0x000050007f13ffffL, 0x007fa0006013ffffL, 0x006a9005656fffffL,
0x007f600f600affffL, 0x007ec007e6bfffe2L, 0x007ec003eebffffbL, 0x0071d002382fffdaL,
0x009f803000e7fffaL, 0x00680030008bffffL, 0x00606060004f3ffcL, 0x001a00600bff9ffdL,
0x000d006005ff9fffL, 0x0001806003005fffL, 0x00000300040bfffaL, 0x000192500065ffeaL,
0x00fff112d0006800L, 0x007ff037d000c004L, 0x003fd062001a3ff8L, 0x00087000600e1ffcL,
0x000fff0100100804L, 0x0007ff0100080402L, 0x0003ffe0c0060003L, 0x0001ffd53000d300L,
0x00fffd3000600061L, 0x007fff7f95900040L, 0x003fff8c00600060L, 0x001ffe2587a01860L,
0x000fff3fbf40180cL, 0x0007ffc73f400c06L, 0x0003ff86d2c01405L, 0x0001fffeaa700100L,
0x00fffdfdd8005000L, 0x007fff80ebffb000L, 0x003fffdf603f6000L, 0x001fffe050405000L,
0x000fff400700c00cL, 0x0007ff6007bf600aL, 0x0003ffeebffec005L, 0x0001fffdf3feb001L,
0x00ffff39ff484a00L, 0x007fff3fff486300L, 0x003fff99ffac2e00L, 0x001fff31ff2a6a00L,
0x000fff19ff15b600L, 0x0007fff5fff28600L, 0x0003fffddffbfee0L, 0x0001fff5f63c96a0L,
0x00ffff5dff65cfb6L, 0x007fffbaffd1c5aeL, 0x003fff71ff6cbceaL, 0x001fffd9ffd4756eL,
0x000ffff5fff338e6L, 0x0007fffdfffe24f6L, 0x0003ffef27eebe74L, 0x0001ffff23ff605eL
};
private final static long[][] bTables;
private final static long[] bMasks;
@ -152,22 +152,22 @@ public class BitBoard {
4, 4, 5, 5, 5, 5, 4, 4,
5, 4, 5, 5, 5, 5, 4, 5 };
private final static long[] bMagics = {
0xffedf9fd7cfcffffL, 0xfc0962854a77f576L, 0x9010210041047000L, 0x52242420800c0000L,
0x884404220480004aL, 0x0002080248000802L, 0xfc0a66c64a7ef576L, 0x7ffdfdfcbd79ffffL,
0xfc0846a64a34fff6L, 0xfc087a874a3cf7f6L, 0x02000888010a2211L, 0x0040044040801808L,
0x0880040420000000L, 0x0000084110109000L, 0xfc0864ae59b4ff76L, 0x3c0860af4b35ff76L,
0x73c01af56cf4cffbL, 0x41a01cfad64aaffcL, 0x1010000200841104L, 0x802802142a006000L,
0x0a02000412020020L, 0x0000800040504030L, 0x7c0c028f5b34ff76L, 0xfc0a028e5ab4df76L,
0x0020082044905488L, 0xa572211102080220L, 0x0014020001280300L, 0x0220208058008042L,
0x0001010000104016L, 0x0005114028080800L, 0x0202640000848800L, 0x040040900a008421L,
0x400e094000600208L, 0x800a100400120890L, 0x0041229001480020L, 0x0000020080880082L,
0x0040002020060080L, 0x1819100100c02400L, 0x04112a4082c40400L, 0x0001240130210500L,
0xdcefd9b54bfcc09fL, 0xf95ffa765afd602bL, 0x008200222800a410L, 0x0100020102406400L,
0x80a8040094000200L, 0x002002006200a041L, 0x43ff9a5cf4ca0c01L, 0x4bffcd8e7c587601L,
0xfc0ff2865334f576L, 0xfc0bf6ce5924f576L, 0x0900420442088104L, 0x0062042084040010L,
0x01380810220a0240L, 0x0000101002082800L, 0xc3ffb7dc36ca8c89L, 0xc3ff8a54f4ca2c89L,
0xfffffcfcfd79edffL, 0xfc0863fccb147576L, 0x0050009040441000L, 0x00139a0000840400L,
0x9080000412220a00L, 0x0000002020010a42L, 0xfc087e8e4bb2f736L, 0x43ff9e4ef4ca2c89L,
0x0006eff5367ff600L, 0x00345835ba77ff2bL, 0x00145f68a3f5dab6L, 0x003a1863fb56f21dL,
0x0012eb6bfe9d93cdL, 0x000d82827f3420d6L, 0x00074bcd9c7fec97L, 0x000034fe99f9ffffL,
0x0000746f8d6717f6L, 0x00003acb32e1a3f7L, 0x0000185daf1ffb8aL, 0x00003a1867f17067L,
0x0000038ee0ccf92eL, 0x000002a2b7ff926eL, 0x000006c9aa93ff14L, 0x00000399b5e5bf87L,
0x00400f342c951ffcL, 0x0020230579ed8ff0L, 0x007b008a0077dbfdL, 0x001d00010c13fd46L,
0x00040022031c1ffbL, 0x000fa00fd1cbff79L, 0x000400a4bc9affdfL, 0x000200085e9cffdaL,
0x002a14560a3dbfbdL, 0x000a0a157b9eafd1L, 0x00060600fd002ffaL, 0x004006000c009010L,
0x001a002042008040L, 0x001a00600fd1ffc0L, 0x000d0ace50bf3f8dL, 0x000183a48434efd1L,
0x001fbd7670982a0dL, 0x000fe24301d81a0fL, 0x0007fbf82f040041L, 0x000040c800008200L,
0x007fe17018086006L, 0x003b7ddf0ffe1effL, 0x001f92f861df4a0aL, 0x000fd713ad98a289L,
0x000fd6aa751e400cL, 0x0007f2a63ae9600cL, 0x0003ff7dfe0e3f00L, 0x000003fd2704ce04L,
0x00007fc421601d40L, 0x007fff5f70900120L, 0x003fa66283556403L, 0x001fe31969aec201L,
0x0007fdfc18ac14bbL, 0x0003fb96fb568a47L, 0x000003f72ea4954dL, 0x00000003f8dc0383L,
0x0000007f3a814490L, 0x00007dc5c9cf62a6L, 0x007f23d3342897acL, 0x003fee36eee1565cL,
0x0003ff3e99fcccc7L, 0x000003ecfcfac5feL, 0x00000003f97f7453L, 0x0000000003f8dc03L,
0x000000007efa8146L, 0x0000007ed3e2ef60L, 0x00007f47243adcd6L, 0x007fb65afabfb3b5L
};
private static final long createPattern(int i, long mask) {
@ -306,21 +306,21 @@ public class BitBoard {
}
private static final byte 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
-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
};
static public final int getDirection(int from, int to) {
@ -328,6 +328,29 @@ public class BitBoard {
return dirTable[offs];
}
private static final byte distTable[] = {
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
};
public static final int getDistance(int from, int to) {
int offs = to + (to|7) - from - (from|7) + 0x77;
return distTable[offs];
}
public static final long southFill(long mask) {
mask |= (mask >>> 8);
mask |= (mask >>> 16);

View File

@ -30,7 +30,7 @@ public class ComputerPlayer implements Player {
public static final String engineName;
static {
String name = "CuckooChess 1.13a8";
String name = "CuckooChess 1.13a9";
String m = System.getProperty("sun.arch.data.model");
if ("32".equals(m))
name += " 32-bit";
@ -80,7 +80,8 @@ public class ComputerPlayer implements Player {
posHashList[posHashListSize++] = p.zobristHash();
}
tt.nextGeneration();
Search sc = new Search(pos, posHashList, posHashListSize, tt);
History ht = new History();
Search sc = new Search(pos, posHashList, posHashListSize, tt, ht);
// Determine all legal moves
MoveGen.MoveList moves = new MoveGen().pseudoLegalMoves(pos);
@ -186,7 +187,8 @@ public class ComputerPlayer implements Player {
// Create a search object
long[] posHashList = new long[200];
tt.nextGeneration();
Search sc = new Search(pos, posHashList, 0, tt);
History ht = new History();
Search sc = new Search(pos, posHashList, 0, tt, ht);
// Determine all legal moves
MoveGen.MoveList moves = new MoveGen().pseudoLegalMoves(pos);

View File

@ -484,61 +484,88 @@ public class Evaluate {
score -= interpolate(pos.wMtrl - pos.wMtrlPawns, 0, 2 * phd.passedBonusB, hiMtrl, phd.passedBonusB);
// Passed pawns are more dangerous if enemy king is far away
int mtrlNoPawns;
final int highMtrl = qV + rV;
int bestWPawnDist = 8;
int bestWPromSq = -1;
long m = phd.passedPawnsW;
if (m != 0) {
mtrlNoPawns = pos.bMtrl - pos.bMtrlPawns;
if (mtrlNoPawns < highMtrl) {
int mtrlNoPawns = pos.bMtrl - pos.bMtrlPawns;
if (mtrlNoPawns < hiMtrl) {
int kingPos = pos.getKingSq(false);
int kingX = Position.getX(kingPos);
int kingY = Position.getY(kingPos);
while (m != 0) {
int sq = BitBoard.numberOfTrailingZeros(m);
int x = Position.getX(sq);
int y = Position.getY(sq);
int pawnDist = Math.min(5, 7 - y);
int kingDistX = Math.abs(kingX - x);
int kingDistY = Math.abs(kingY - 7);
int kingDist = Math.max(kingDistX, kingDistY);
int kingDist = BitBoard.getDistance(kingPos, Position.getSquare(x, 7));
int kScore = kingDist * 4;
if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist);
score += interpolate(mtrlNoPawns, 0, kScore, highMtrl, 0);
score += interpolate(mtrlNoPawns, 0, kScore, hiMtrl, 0);
if (!pos.whiteMove)
kingDist--;
if ((pawnDist < kingDist) && (mtrlNoPawns == 0))
score += 500; // King can't stop pawn
if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) {
if ((BitBoard.northFill(1L<<sq) & (1L << pos.getKingSq(true))) != 0)
pawnDist++; // Own king blocking pawn
if (pawnDist < bestWPawnDist) {
bestWPawnDist = pawnDist;
bestWPromSq = Position.getSquare(x, 7);
}
}
m &= m-1;
}
}
}
int bestBPawnDist = 8;
int bestBPromSq = -1;
m = phd.passedPawnsB;
if (m != 0) {
mtrlNoPawns = pos.wMtrl - pos.wMtrlPawns;
if (mtrlNoPawns < highMtrl) {
int mtrlNoPawns = pos.wMtrl - pos.wMtrlPawns;
if (mtrlNoPawns < hiMtrl) {
int kingPos = pos.getKingSq(true);
int kingX = Position.getX(kingPos);
int kingY = Position.getY(kingPos);
while (m != 0) {
int sq = BitBoard.numberOfTrailingZeros(m);
int x = Position.getX(sq);
int y = Position.getY(sq);
int pawnDist = Math.min(5, y);
int kingDistX = Math.abs(kingX - x);
int kingDistY = Math.abs(kingY - 0);
int kingDist = Math.max(kingDistX, kingDistY);
int kingDist = BitBoard.getDistance(kingPos, Position.getSquare(x, 0));
int kScore = kingDist * 4;
if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist);
score -= interpolate(mtrlNoPawns, 0, kScore, highMtrl, 0);
score -= interpolate(mtrlNoPawns, 0, kScore, hiMtrl, 0);
if (pos.whiteMove)
kingDist--;
if ((pawnDist < kingDist) && (mtrlNoPawns == 0))
score -= 500; // King can't stop pawn
if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) {
if ((BitBoard.southFill(1L<<sq) & (1L << pos.getKingSq(false))) != 0)
pawnDist++; // Own king blocking pawn
if (pawnDist < bestBPawnDist) {
bestBPawnDist = pawnDist;
bestBPromSq = Position.getSquare(x, 0);
}
}
m &= m-1;
}
}
}
// Evaluate pawn races in pawn end games
if (bestWPromSq >= 0) {
if (bestBPromSq >= 0) {
int wPly = bestWPawnDist * 2; if (pos.whiteMove) wPly--;
int bPly = bestBPawnDist * 2; if (!pos.whiteMove) bPly--;
if (wPly < bPly - 1) {
score += 500;
} else if (wPly == bPly - 1) {
if (BitBoard.getDirection(bestWPromSq, pos.getKingSq(false)) != 0)
score += 500;
} else if (wPly == bPly + 1) {
if (BitBoard.getDirection(bestBPromSq, pos.getKingSq(true)) != 0)
score -= 500;
} else {
score -= 500;
}
} else
score += 500;
} else if (bestBPromSq >= 0)
score -= 500;
return score;
}
@ -585,7 +612,7 @@ public class Evaluate {
// Evaluate passed pawn bonus, white
long passedPawnsW = wPawns & ~BitBoard.southFill(bPawns | bPawnAttacks | (wPawns >>> 8));
final int[] ppBonus = {-1,24,26,30,36,47,64,-1};
final int[] ppBonus = {-1,24,26,30,36,55,100,-1};
int passedBonusW = 0;
if (passedPawnsW != 0) {
long guardedPassedW = passedPawnsW & (((wPawns & BitBoard.maskBToHFiles) << 7) |
@ -616,11 +643,19 @@ public class Evaluate {
}
}
// Connected passed pawn bonus. Seems logical but doesn't help in tests
// if (passedPawnsW != 0)
// passedBonusW += 15 * Long.bitCount(passedPawnsW & ((passedPawnsW & BitBoard.maskBToHFiles) >>> 1));
// if (passedPawnsB != 0)
// passedBonusB += 15 * Long.bitCount(passedPawnsB & ((passedPawnsB & BitBoard.maskBToHFiles) >>> 1));
// Connected passed pawn bonus. Seems logical but scored -8 elo in tests
// if (passedPawnsW != 0) {
// long mask = passedPawnsW;
// mask = (((mask >> 7) | (mask << 1) | (mask << 9)) & BitBoard.maskBToHFiles) |
// (((mask >> 9) | (mask >> 1) | (mask << 7)) & BitBoard.maskAToGFiles);
// passedBonusW += 13 * Long.bitCount(passedPawnsW & mask);
// }
// if (passedPawnsB != 0) {
// long mask = passedPawnsB;
// mask = (((mask >> 7) | (mask << 1) | (mask << 9)) & BitBoard.maskBToHFiles) |
// (((mask >> 9) | (mask >> 1) | (mask << 7)) & BitBoard.maskAToGFiles);
// passedBonusB += 13 * Long.bitCount(passedPawnsB & mask);
// }
ph.key = pos.pawnZobristHash();
ph.score = score;
@ -954,7 +989,7 @@ public class Evaluate {
int wq = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WQUEEN]);
int bk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BKING]);
int bp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BPAWN]);
score = evalKQKP(wk, wq, bk, bp);
score = evalKQKP(wk, wq, bk, bp, pos.whiteMove);
handled = true;
}
if (!handled && (pos.wMtrl == rV) && (pos.pieceTypeBB[Piece.WROOK] != 0)) {
@ -981,7 +1016,7 @@ public class Evaluate {
int bq = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BQUEEN]);
int wk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WKING]);
int wp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WPAWN]);
score = -evalKQKP(63-bk, 63-bq, 63-wk, 63-wp);
score = -evalKQKP(63-bk, 63-bq, 63-wk, 63-wp, !pos.whiteMove);
handled = true;
}
if (!handled && (pos.bMtrl == rV) && (pos.pieceTypeBB[Piece.BROOK] != 0)) {
@ -1031,7 +1066,7 @@ public class Evaluate {
if (wMtrlNoPawns - bMtrlNoPawns > bV) {
int wKnights = Long.bitCount(pos.pieceTypeBB[Piece.WKNIGHT]);
int wBishops = Long.bitCount(pos.pieceTypeBB[Piece.WBISHOP]);
if ((wKnights == 2) && (wMtrlNoPawns == 2 * nV) && (bMtrlNoPawns == 0)) {
if ((wKnights == 2) && (pos.wMtrl == 2 * nV) && (bMtrlNoPawns == 0)) {
score /= 50; // KNNK is a draw
} else if ((wKnights == 1) && (wBishops == 1) && (wMtrlNoPawns == nV + bV) && (bMtrlNoPawns == 0)) {
score /= 10;
@ -1084,7 +1119,7 @@ public class Evaluate {
if (bMtrlNoPawns - wMtrlNoPawns > bV) {
int bKnights = Long.bitCount(pos.pieceTypeBB[Piece.BKNIGHT]);
int bBishops = Long.bitCount(pos.pieceTypeBB[Piece.BBISHOP]);
if ((bKnights == 2) && (bMtrlNoPawns == 2 * nV) && (wMtrlNoPawns == 0)) {
if ((bKnights == 2) && (pos.bMtrl == 2 * nV) && (wMtrlNoPawns == 0)) {
score /= 50; // KNNK is a draw
} else if ((bKnights == 1) && (bBishops == 1) && (bMtrlNoPawns == nV + bV) && (wMtrlNoPawns == 0)) {
score /= 10;
@ -1115,7 +1150,7 @@ public class Evaluate {
// FIXME! KRBKR is very hard to draw
}
private static final int evalKQKP(int wKing, int wQueen, int bKing, int bPawn) {
private static final int evalKQKP(int wKing, int wQueen, int bKing, int bPawn, boolean whiteMove) {
boolean canWin = false;
if (((1L << bKing) & 0xFFFF) == 0) {
canWin = true; // King doesn't support pawn
@ -1125,6 +1160,8 @@ public class Evaluate {
switch (bPawn) {
case 8: // a2
canWin = ((1L << wKing) & 0x0F1F1F1F1FL) != 0;
if (canWin && (bKing == 0) && (Position.getX(wQueen) == 1) && !whiteMove)
canWin = false; // Stale-mate
break;
case 10: // c2
canWin = ((1L << wKing) & 0x071F1F1FL) != 0;
@ -1134,6 +1171,8 @@ public class Evaluate {
break;
case 15: // h2
canWin = ((1L << wKing) & 0xF0F8F8F8F8L) != 0;
if (canWin && (bKing == 7) && (Position.getX(wQueen) == 6) && !whiteMove)
canWin = false; // Stale-mate
break;
default:
canWin = true;
@ -1141,8 +1180,7 @@ public class Evaluate {
}
}
final int dist = Math.max(Math.abs(Position.getX(wKing)-Position.getX(bPawn)),
Math.abs(Position.getY(wKing)-Position.getY(bPawn)));
final int dist = BitBoard.getDistance(wKing, bPawn);
int score = qV - pV - 20 * dist;
if (!canWin)
score /= 50;

View File

@ -23,11 +23,15 @@ package chess;
* @author petero
*/
public final class History {
private final int countSuccess[][];
private final int countFail[][];
private final int score[][];
private int countSuccess[][];
private int countFail[][];
private int score[][];
public History() {
init();
}
public void init() {
countSuccess = new int[Piece.nPieceTypes][64];
countFail = new int[Piece.nPieceTypes][64];
score = new int[Piece.nPieceTypes][64];

View File

@ -64,13 +64,27 @@ public class Move {
this.score = m.score;
}
public void copyFrom(Move m) {
public final void copyFrom(Move m) {
from = m.from;
to = m.to;
promoteTo = m.promoteTo;
// score = m.score;
}
public final void clear() {
from = 0;
to = 0;
promoteTo = 0;
score = 0;
}
public final void setMove(int from, int to, int promoteTo, int score) {
this.from = from;
this.to = to;
this.promoteTo = promoteTo;
this.score = score;
}
/** Note that score is not included in the comparison. */
@Override
public boolean equals(Object o) {

View File

@ -529,22 +529,8 @@ public class Position {
*/
public final void makeSEEMove(Move move, UndoInfo ui) {
ui.capturedPiece = squares[move.to];
boolean wtm = whiteMove;
int p = squares[move.from];
long fromMask = 1L << move.from;
// Handle castling
if (((pieceTypeBB[Piece.WKING] | pieceTypeBB[Piece.BKING]) & fromMask) != 0) {
int k0 = move.from;
if (move.to == k0 + 2) { // O-O
setSEEPiece(k0 + 1, squares[k0 + 3]);
setSEEPiece(k0 + 3, Piece.EMPTY);
} else if (move.to == k0 - 2) { // O-O-O
setSEEPiece(k0 - 1, squares[k0 - 4]);
setSEEPiece(k0 - 4, Piece.EMPTY);
}
}
// Handle en passant
if (move.to == epSquare) {
@ -558,7 +544,7 @@ public class Position {
// Perform move
setSEEPiece(move.from, Piece.EMPTY);
setSEEPiece(move.to, p);
whiteMove = !wtm;
whiteMove = !whiteMove;
}
public final void unMakeSEEMove(Move move, UndoInfo ui) {
@ -566,20 +552,6 @@ public class Position {
int p = squares[move.to];
setSEEPiece(move.from, p);
setSEEPiece(move.to, ui.capturedPiece);
boolean wtm = whiteMove;
// Handle castling
int king = wtm ? Piece.WKING : Piece.BKING;
if (p == king) {
int k0 = move.from;
if (move.to == k0 + 2) { // O-O
setSEEPiece(k0 + 3, squares[k0 + 1]);
setSEEPiece(k0 + 1, Piece.EMPTY);
} else if (move.to == k0 - 2) { // O-O-O
setSEEPiece(k0 - 4, squares[k0 - 1]);
setSEEPiece(k0 - 1, Piece.EMPTY);
}
}
// Handle en passant
if (move.to == epSquare) {

View File

@ -87,15 +87,16 @@ public class Search {
public final static int UNKNOWN_SCORE = -32767; // Represents unknown static eval score
int q0Eval; // Static eval score at first level of quiescence search
public Search(Position pos, long[] posHashList, int posHashListSize, TranspositionTable tt) {
public Search(Position pos, long[] posHashList, int posHashListSize, TranspositionTable tt,
History ht) {
this.pos = new Position(pos);
this.moveGen = new MoveGen();
this.posHashList = posHashList;
this.posHashListSize = posHashListSize;
this.tt = tt;
this.ht = ht;
eval = new Evaluate();
kt = new KillerTable();
ht = new History();
posHashFirstNew = posHashListSize;
initNodeStats();
minTimeMillis = -1;
@ -519,23 +520,23 @@ public class Search {
evalScore = ent.evalScore;
int plyToMate = MATE0 - Math.abs(score);
int eDepth = ent.getDepth();
hashMove = sti.hashMove;
ent.getMove(hashMove);
if ((beta == alpha + 1) && ((eDepth >= depth) || (eDepth >= plyToMate*plyScale))) {
if ( (ent.type == TTEntry.T_EXACT) ||
(ent.type == TTEntry.T_GE) && (score >= beta) ||
(ent.type == TTEntry.T_LE) && (score <= alpha)) {
if (score >= beta) {
hashMove = sti.hashMove;
ent.getMove(hashMove);
if ((hashMove != null) && (hashMove.from != hashMove.to))
if (pos.getPiece(hashMove.to) == Piece.EMPTY)
kt.addKiller(ply, hashMove);
}
sti.bestMove = hashMove;
if (log != null) log.logNodeEnd(searchTreeInfo[ply].nodeIdx, score, ent.type, evalScore, hKey);
return score;
}
}
hashMove = sti.hashMove;
ent.getMove(hashMove);
}
int posExtend = inCheck ? plyScale : 0; // Check extension
@ -543,6 +544,7 @@ public class Search {
// If out of depth, perform quiescence search
if (depth + posExtend <= 0) {
q0Eval = evalScore;
sti.bestMove.clear();
int score = quiesce(alpha, beta, ply, 0, inCheck);
int type = TTEntry.T_EXACT;
if (score <= alpha) {
@ -550,8 +552,8 @@ public class Search {
} else if (score >= beta) {
type = TTEntry.T_GE;
}
emptyMove.score = score;
tt.insert(hKey, emptyMove, type, ply, depth, q0Eval);
sti.bestMove.score = score;
tt.insert(hKey, sti.bestMove, type, ply, depth, q0Eval);
if (log != null) log.logNodeEnd(sti.nodeIdx, score, type, q0Eval, hKey);
return score;
}
@ -628,6 +630,7 @@ public class Search {
int epSquare = pos.getEpSquare();
pos.setEpSquare(-1);
searchTreeInfo[ply+1].allowNullMove = false;
searchTreeInfo[ply+1].bestMove.clear();
int score = -negaScout(-beta, -(beta - 1), ply + 1, depth - R, -1, false);
searchTreeInfo[ply+1].allowNullMove = true;
pos.setEpSquare(epSquare);
@ -955,7 +958,7 @@ public class Search {
if (score > alpha)
alpha = score;
int bestScore = score;
final boolean tryChecks = (depth > -3);
final boolean tryChecks = (depth > -1);
MoveGen.MoveList moves;
if (inCheck) {
moves = moveGen.checkEvasions(pos);
@ -1001,7 +1004,7 @@ public class Search {
if (optimisticScore < alpha) { // Delta pruning
if ((pos.wMtrlPawns > 0) && (pos.wMtrl > capt + pos.wMtrlPawns) &&
(pos.bMtrlPawns > 0) && (pos.bMtrl > capt + pos.bMtrlPawns)) {
if (depth -1 > -4) {
if (depth -1 > -2) {
givesCheck = MoveGen.givesCheck(pos, m);
givesCheckComputed = true;
}
@ -1016,11 +1019,11 @@ public class Search {
}
if (!givesCheckComputed) {
if (depth - 1 > -4) {
if (depth - 1 > -2) {
givesCheck = MoveGen.givesCheck(pos, m);
}
}
final boolean nextInCheck = (depth - 1) > -4 ? givesCheck : false;
final boolean nextInCheck = (depth - 1) > -2 ? givesCheck : false;
pos.makeMove(m, ui);
qNodes++;
@ -1030,6 +1033,10 @@ public class Search {
if (score > bestScore) {
bestScore = score;
if (score > alpha) {
if (depth == 0) {
SearchTreeInfo sti = searchTreeInfo[ply];
sti.bestMove.setMove(m.from, m.to, m.promoteTo, score);
}
alpha = score;
if (alpha >= beta) {
moveGen.returnMoveList(moves);

View File

@ -71,7 +71,7 @@ public class TranspositionTable {
this.move = (short)(move.from + (move.to << 6) + (move.promoteTo << 12));
}
/** Get the score from the hash entry, and convert from "mate in x" to "mate at ply". */
/** Get the score from the hash entry and convert from "mate in x" to "mate at ply". */
public final int getScore(int ply) {
int sc = score;
if (sc > Search.MATE0 - 1000) {
@ -82,7 +82,7 @@ public class TranspositionTable {
return sc;
}
/** Convert score from "mate at ply" to "mate in x", and store in hash entry. */
/** Convert score from "mate at ply" to "mate in x" and store in hash entry. */
public final void setScore(int score, int ply) {
if (score > Search.MATE0 - 1000) {
score += ply;

View File

@ -125,6 +125,19 @@ public class BitBoardTest {
}
}
private static final int computeDistance(int from, int to) {
int dx = Position.getX(to) - Position.getX(from);
int dy = Position.getY(to) - Position.getY(from);
return Math.max(Math.abs(dx), Math.abs(dy));
}
@Test
public void testGetDistance() {
for (int from = 0; from < 64; from++)
for (int to = 0; to < 64; to++)
assertEquals(computeDistance(from, to), BitBoard.getDistance(from, to));
}
@Test
public void testTrailingZeros() {
System.out.println("trailingZeros");

View File

@ -277,7 +277,7 @@ public class EvaluateTest {
score = evalWhite(pos);
assertTrue(-score > bV * 2 + 100);
// KrpKn is win for white
// KRPKN is win for white
pos = TextIO.readFEN("8/3bk3/8/8/8/3P4/3RK3/8 w - - 0 1");
score = evalWhite(pos);
final int pV = Evaluate.pV;
@ -287,10 +287,14 @@ public class EvaluateTest {
pos = TextIO.readFEN("8/8/4k3/8/8/3NK3/3N4/8 w - - 0 1");
score = evalWhite(pos);
assertTrue(Math.abs(score) < 50);
final int nV = Evaluate.nV;
pos = TextIO.readFEN("8/8/8/4k3/N6N/P2K4/8/8 b - - 0 66");
score = evalWhite(pos);
assertTrue(score > nV * 2);
pos = TextIO.readFEN("8/8/3k4/8/8/3NK3/2B5/8 b - - 0 1");
score = evalWhite(pos);
final int nV = Evaluate.nV;
assertTrue(score > bV + nV + 150); // KBNK is won, should have a bonus
score = moveScore(pos, "Kc6");
assertTrue(score > 0); // Black king going into wrong corner, good for white
@ -412,6 +416,8 @@ public class EvaluateTest {
assertTrue(evalWhite(pos) > winScore);
pos = TextIO.readFEN("3Q4/8/8/8/K7/8/1kp5/8 w - - 0 1");
assertTrue(evalWhite(pos) > winScore);
pos = TextIO.readFEN("8/8/8/8/8/1Q6/p3K3/k7 b - - 0 1");
assertTrue(evalWhite(pos) < drawish);
// Pawn on c2
pos = TextIO.readFEN("3Q4/8/8/8/3K4/8/1kp5/8 w - - 0 1");
@ -445,6 +451,29 @@ public class EvaluateTest {
assertTrue(score2 > score1);
}
@Test
public void testPawnRace() throws ChessParseError {
final int pV = Evaluate.pV;
final int winScore = 400;
final int drawish = 100;
Position pos = TextIO.readFEN("8/8/K7/1P3p2/8/6k1/8/8 w - - 0 1");
assertTrue(evalWhite(pos) > winScore);
pos = TextIO.readFEN("8/8/K7/1P3p2/8/6k1/8/8 b - - 0 1");
assertTrue(evalWhite(pos) > winScore);
pos = TextIO.readFEN("8/8/K7/1P3p2/6k1/8/8/8 b - - 0 1");
assertTrue(Math.abs(evalWhite(pos)) < drawish);
pos = TextIO.readFEN("8/8/K7/1P6/5pk1/8/8/8 b - - 0 1");
assertTrue(evalWhite(pos) < -winScore);
pos = TextIO.readFEN("8/K7/8/1P6/5pk1/8/8/8 b - - 0 1");
assertTrue(Math.abs(evalWhite(pos)) < drawish);
pos = TextIO.readFEN("8/K7/8/8/1PP2p1k/8/8/8 w - - 0 1");
assertTrue(evalWhite(pos) < drawish + pV);
assertTrue(evalWhite(pos) > 0);
pos = TextIO.readFEN("8/K7/8/8/1PP2p1k/8/8/8 b - - 0 1");
assertTrue(evalWhite(pos) < -winScore + pV);
}
/** Return static evaluation score for white, regardless of whose turn it is to move. */
final static int evalWhite(Position pos) {
Evaluate eval = new Evaluate();

View File

@ -32,6 +32,7 @@ import static org.junit.Assert.*;
public class SearchTest {
static final long[] nullHist = new long[200];
static TranspositionTable tt = new TranspositionTable(19);
static History ht = new History();
public SearchTest() {
}
@ -53,7 +54,7 @@ public class SearchTest {
final int mate0 = Search.MATE0;
Position pos = TextIO.readFEN("3k4/8/3K2R1/8/8/8/8/8 w - - 0 1");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
final int plyScale = Search.plyScale;
int score = sc.negaScout(-mate0, mate0, 0, 2*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(mate0 - 2, score); // depth 2 is enough to find mate in 1
@ -61,33 +62,33 @@ public class SearchTest {
assertEquals(score, score2);
pos = TextIO.readFEN("8/1P6/k7/2K5/8/8/8/8 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
score = sc.negaScout(-mate0, mate0, 0, 4*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(mate0 - 4, score); // depth 4 is enough to find mate in 2
score2 = idSearch(sc, 4).score;
assertEquals(score, score2);
pos = TextIO.readFEN("8/5P1k/5K2/8/8/8/8/8 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
score = sc.negaScout(-mate0, mate0, 0, 5*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(mate0 - 4, score); // must avoid stale-mate after f8Q
score2 = idSearch(sc, 5).score;
assertEquals(score, score2);
pos = TextIO.readFEN("4k3/8/3K1Q2/8/8/8/8/8 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
score = sc.negaScout(-mate0, mate0, 0, 2*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(0, score); // Position is stale-mate
pos = TextIO.readFEN("3kB3/8/1N1K4/8/8/8/8/8 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
score = sc.negaScout(-mate0, mate0, 0, 3*plyScale, -1, MoveGen.inCheck(pos));
assertTrue(Math.abs(score) < 50); // Stale-mate trap
score2 = idSearch(sc, 5).score;
assertEquals(score, score2);
pos = TextIO.readFEN("8/8/2K5/3QP3/P6P/1q6/8/k7 w - - 31 51");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
Move bestM = idSearch(sc, 2);
assertTrue(!TextIO.moveToString(pos, bestM, false).equals("Qxb3"));
}
@ -105,50 +106,50 @@ public class SearchTest {
final int mateInThree = mate0 - 6;
Position pos = TextIO.readFEN("8/1R2k3/R7/8/8/8/8/1K6 b - - 0 1");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
final int plyScale = Search.plyScale;
int score = sc.negaScout(-mate0, mate0, 0, 2*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(matedInOne, score);
pos = TextIO.readFEN("8/1R2k3/R7/8/8/8/8/1K6 b - - 99 80");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = sc.negaScout(-mate0, mate0, 0, 2*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(0, score); // Draw by 50-move rule
pos = TextIO.readFEN("8/1R2k3/R7/8/8/8/8/1K6 b - - 98 80");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = sc.negaScout(-mate0, mate0, 0, 2*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(matedInOne, score); // No draw
pos = TextIO.readFEN("8/1R2k3/R7/8/8/8/8/1K6 b - - 99 80");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 3).score;
assertEquals(0, score);
pos = TextIO.readFEN("3k4/1R6/R7/8/8/8/8/1K6 w - - 100 80");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 2).score;
assertEquals(mateInOne, score); // Black forgot to claim draw. Now it's too late.
pos = TextIO.readFEN("8/7k/1R6/R7/8/7P/8/1K6 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 3).score;
assertEquals(mateInTwo, score);
pos = TextIO.readFEN("8/7k/1R6/R7/8/7P/8/1K6 w - - 98 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 6).score;
assertEquals(mateInThree, score); // Need an extra pawn move to avoid 50-move rule
pos = TextIO.readFEN("8/7k/1R6/R7/8/7P/8/1K6 w - - 125 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 6).score;
assertEquals(mateInThree, score); // Need an extra pawn move to avoid 50-move rule
@ -162,32 +163,32 @@ public class SearchTest {
System.out.println("drawRep");
final int mate0 = Search.MATE0;
Position pos = TextIO.readFEN("7k/5RR1/8/8/8/8/q3q3/2K5 w - - 0 1");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
final int plyScale = Search.plyScale;
int score = sc.negaScout(-mate0, mate0, 0, 3*plyScale, -1, MoveGen.inCheck(pos));
assertEquals(0, score);
pos = TextIO.readFEN("7k/5RR1/8/8/8/8/q3q3/2K5 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 3).score;
assertEquals(0, score);
pos = TextIO.readFEN("7k/5RR1/8/8/8/8/1q3q2/3K4 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 4).score;
assertTrue(score < 0);
pos = TextIO.readFEN("7k/5RR1/8/8/8/8/1q3q2/3K4 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = sc.negaScout(-mate0, mate0, 0, 3*plyScale, -1, MoveGen.inCheck(pos));
assertTrue(score < 0);
pos = TextIO.readFEN("qn6/qn4k1/pp3R2/5R2/8/8/8/K7 w - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
sc.maxTimeMillis = -1;
score = idSearch(sc, 7).score;
assertEquals(0, score); // Draw, black can not escape from perpetual checks
@ -200,7 +201,7 @@ public class SearchTest {
public void testHashing() throws ChessParseError {
System.out.println("hashing");
Position pos = TextIO.readFEN("/k/3p/p2P1p/P2P1P///K/ w - -"); // Fine #70
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
Move bestM = idSearch(sc, 28);
assertEquals(TextIO.stringToMove(pos, "Kb1"), new Move(bestM));
}
@ -211,7 +212,7 @@ public class SearchTest {
@Test
public void testLMP() throws ChessParseError {
Position pos = TextIO.readFEN("2r2rk1/6p1/p3pq1p/1p1b1p2/3P1n2/PP3N2/3N1PPP/1Q2RR1K b"); // WAC 174
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
Move bestM = idSearch(sc, 2);
assertTrue(bestM.score < Search.MATE0 / 2);
}
@ -220,12 +221,12 @@ public class SearchTest {
public void testCheckEvasion() throws ChessParseError {
System.out.println("check evasion");
Position pos = TextIO.readFEN("6r1/R5PK/2p5/1k6/8/8/p7/8 b - - 0 62");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
Move bestM = idSearch(sc, 3);
assertTrue(bestM.score < 0);
pos = TextIO.readFEN("r1bq2rk/pp3pbp/2p1p1pQ/7P/3P4/2PB1N2/PP3PPR/2KR4 w - -"); // WAC 004
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
bestM = idSearch(sc, 1);
assertEquals(Search.MATE0 - 4, bestM.score);
assertEquals(TextIO.stringToMove(pos, "Qxh7+"), new Move(bestM));
@ -235,7 +236,7 @@ public class SearchTest {
public void testStalemateTrap() throws ChessParseError {
System.out.println("stalemate trap");
Position pos = TextIO.readFEN("7k/1P3R1P/6r1/5K2/8/8/6R1/8 b - - 98 194");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
Move bestM = idSearch(sc, 3);
assertEquals(0, bestM.score);
}
@ -244,7 +245,7 @@ public class SearchTest {
public void testKQKRNullMove() throws ChessParseError {
System.out.println("kqkrNullMove");
Position pos = TextIO.readFEN("7K/6R1/5k2/3q4/8/8/8/8 b - - 0 1");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
Move bestM = idSearch(sc, 10);
assertEquals(Search.MATE0-18, bestM.score);
}
@ -286,7 +287,7 @@ public class SearchTest {
// Basic tests
Position pos = TextIO.readFEN("r2qk2r/ppp2ppp/1bnp1nb1/1N2p3/3PP3/1PP2N2/1P3PPP/R1BQRBK1 w kq - 0 1");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(0, getSEE(sc, TextIO.stringToMove(pos, "dxe5")));
assertEquals(pV - nV, getSEE(sc, TextIO.stringToMove(pos, "Nxe5")));
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxa7")));
@ -299,7 +300,7 @@ public class SearchTest {
assertEquals(-rV, getSEE(sc, TextIO.stringToMove(pos, "Ra6")));
pos.setWhiteMove(false);
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertTrue(nV <= bV); // Assumed by following test
assertEquals(pV - nV, getSEE(sc, TextIO.stringToMove(pos, "Nxd4")));
assertEquals(pV - bV, getSEE(sc, TextIO.stringToMove(pos, "Bxd4")));
@ -312,7 +313,7 @@ public class SearchTest {
// Test X-ray attacks
pos = TextIO.readFEN("3r2k1/pp1q1ppp/1bnr1nb1/1Np1p3/1P1PP3/2P1BN2/1Q1R1PPP/3R1BK1 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 1 1 1 3 3 3 3 3 5 5 9 5 5
// 0 1 0 1 0 3 0 3 0 5 0 9 0 5
assertEquals(0, getSEE(sc, TextIO.stringToMove(pos, "exd4")));
@ -321,38 +322,38 @@ public class SearchTest {
assertEquals(2 * pV - nV, getSEE(sc, TextIO.stringToMove(pos, "Nxd4")));
pos.setPiece(TextIO.getSquare("b2"), Piece.EMPTY); // Remove white queen
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 1 1 1 3 3 3 3 3 5 5 9 5
// 0 1 0 1 0 3 0 3 0 4 1 4 5
assertEquals(0, getSEE(sc, TextIO.stringToMove(pos, "exd4")));
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "cxb4")));
pos.setPiece(TextIO.getSquare("b5"), Piece.EMPTY); // Remove white knight
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 1 1 1 3 3 3 3 5 5 5
// 1 0 1 0 3 0 3 0 5 0 5
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "exd4")));
pos.setPiece(TextIO.getSquare("b2"), Piece.WQUEEN); // Restore white queen
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 1 1 1 3 3 3 3 5 5 5 9 9
// 1 0 1 0 3 0 3 0 5 0 5 0 9
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "exd4")));
pos.setPiece(TextIO.getSquare("b6"), Piece.EMPTY); // Remove black bishop
pos.setPiece(TextIO.getSquare("c6"), Piece.EMPTY); // Remove black knight
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(-pV, getSEE(sc, TextIO.stringToMove(pos, "a5")));
// Test EP capture
pos = TextIO.readFEN("2b3k1/1p3ppp/8/pP6/8/2PB4/5PPP/6K1 w - a6 0 2");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 1 1 3
// 0 1 0 3
assertEquals(0, getSEE(sc, TextIO.stringToMove(pos, "bxa6")));
pos.setPiece(TextIO.getSquare("b7"), Piece.EMPTY); // Remove black pawn
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 1 3
// 1 0 3
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "bxa6")));
@ -360,14 +361,14 @@ public class SearchTest {
// Test king capture
pos = TextIO.readFEN("8/8/8/4k3/r3P3/4K3/8/4R3 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 5 99
// 1 0 99
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "Rxe4+")));
pos = TextIO.readFEN("8/8/8/4k3/r3P1R1/4K3/8/8 b - - 0 1");
final int kV = Evaluate.kV;
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
// 1 5 5 99
//-4 5 0 99
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxe4+")));
@ -376,47 +377,47 @@ public class SearchTest {
assertEquals(pV - kV, getSEE(sc, new Move(TextIO.getSquare("e5"), TextIO.getSquare("e4"), Piece.EMPTY)));
pos = TextIO.readFEN("8/8/4k3/8/r3P3/4K3/8/8 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxe4+")));
// Test king too far away
pos = TextIO.readFEN("8/8/4k3/8/r3P3/8/4K3/8 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "Rxe4+")));
pos = TextIO.readFEN("8/3k4/8/8/r1K5/8/8/2R5 w - - 0 1");
pos.setWhiteMove(false);
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(kV, getSEE(sc, new Move(TextIO.getSquare("a4"), TextIO.getSquare("c4"), Piece.EMPTY)));
// Test blocking pieces
pos = TextIO.readFEN("r7/p2k4/8/r7/P7/8/4K3/R7 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxa4"))); // Ra8 doesn't help
pos.setPiece(TextIO.getSquare("a7"), Piece.BBISHOP);
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxa4"))); // Ra8 doesn't help
pos.setPiece(TextIO.getSquare("a7"), Piece.BPAWN);
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxa4"))); // Ra8 doesn't help
pos.setPiece(TextIO.getSquare("a7"), Piece.BQUEEN);
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV, getSEE(sc, TextIO.stringToMove(pos, "Rxa4"))); // Ra8 does help
pos = TextIO.readFEN("8/3k4/R7/r7/P7/8/4K3/8 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxa4")));
pos = TextIO.readFEN("Q7/q6k/R7/r7/P7/8/4K3/8 b - - 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
assertEquals(pV - rV, getSEE(sc, TextIO.stringToMove(pos, "Rxa4")));
pos = TextIO.readFEN("8/3k4/5R2/8/4pP2/8/8/3K4 b - f3 0 1");
sc = new Search(pos, nullHist, 0, tt);
sc = new Search(pos, nullHist, 0, tt, ht);
int score1 = EvaluateTest.evalWhite(sc.pos);
long h1 = sc.pos.zobristHash();
assertEquals(0, getSEE(sc, TextIO.stringToMove(pos, "exf3")));
@ -433,7 +434,7 @@ public class SearchTest {
public void testScoreMoveList() throws ChessParseError {
System.out.println("SEEorder");
Position pos = TextIO.readFEN("r2qk2r/ppp2ppp/1bnp1nb1/1N2p3/3PP3/1PP2N2/1P3PPP/R1BQRBK1 w kq - 0 1");
Search sc = new Search(pos, nullHist, 0, tt);
Search sc = new Search(pos, nullHist, 0, tt, ht);
MoveGen moveGen = new MoveGen();
MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos);
sc.scoreMoveList(moves, 0);