mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-12-11 20:30:54 +01:00
493 lines
20 KiB
Java
493 lines
20 KiB
Java
|
/*
|
||
|
CuckooChess - A java chess program.
|
||
|
Copyright (C) 2011 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 chess;
|
||
|
|
||
|
import org.junit.AfterClass;
|
||
|
import org.junit.BeforeClass;
|
||
|
import org.junit.Test;
|
||
|
import static org.junit.Assert.*;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @author petero
|
||
|
*/
|
||
|
public class EvaluateTest {
|
||
|
|
||
|
public EvaluateTest() {
|
||
|
}
|
||
|
|
||
|
@BeforeClass
|
||
|
public static void setUpClass() throws Exception {
|
||
|
}
|
||
|
|
||
|
@AfterClass
|
||
|
public static void tearDownClass() throws Exception {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of evalPos method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testEvalPos() throws ChessParseError {
|
||
|
System.out.println("evalPos");
|
||
|
Position pos = TextIO.readFEN(TextIO.startPosFEN);
|
||
|
UndoInfo ui = new UndoInfo();
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "e4"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "e5"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nf3"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nc6"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Bb5"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nge7"), ui);
|
||
|
assertTrue(moveScore(pos, "O-O") > 0); // Castling is good
|
||
|
assertTrue(moveScore(pos, "Ke2") < 0); // Losing right to castle is bad
|
||
|
assertTrue(moveScore(pos, "Kf1") < 0);
|
||
|
assertTrue(moveScore(pos, "Rg1") < 0);
|
||
|
assertTrue(moveScore(pos, "Rf1") < 0);
|
||
|
|
||
|
pos = TextIO.readFEN("8/8/8/1r3k2/4pP2/4P3/8/4K2R w K - 0 1");
|
||
|
assertEquals(true, pos.h1Castle());
|
||
|
int cs1 = evalWhite(pos);
|
||
|
pos.setCastleMask(pos.getCastleMask() & ~(1 << Position.H1_CASTLE));
|
||
|
assertEquals(false, pos.h1Castle());
|
||
|
int cs2 = evalWhite(pos);
|
||
|
assertTrue(cs2 >= cs1); // No bonus for useless castle right
|
||
|
|
||
|
// Test rook open file bonus
|
||
|
pos = TextIO.readFEN("r4rk1/1pp1qppp/3b1n2/4p3/2B1P1b1/1QN2N2/PP3PPP/R3R1K1 w - - 0 1");
|
||
|
int ms1 = moveScore(pos, "Red1");
|
||
|
int ms2 = moveScore(pos, "Rec1");
|
||
|
int ms3 = moveScore(pos, "Rac1");
|
||
|
int ms4 = moveScore(pos, "Rad1");
|
||
|
assertTrue(ms1 > 0); // Good to have rook on open file
|
||
|
assertTrue(ms2 > 0); // Good to have rook on half-open file
|
||
|
assertTrue(ms1 > ms2); // Open file better than half-open file
|
||
|
assertTrue(ms3 > 0);
|
||
|
assertTrue(ms4 > 0);
|
||
|
assertTrue(ms4 > ms1);
|
||
|
assertTrue(ms3 > ms2);
|
||
|
|
||
|
pos = TextIO.readFEN("r3kb1r/p3pp1p/bpPq1np1/4N3/2pP4/2N1PQ2/P1PB1PPP/R3K2R b KQkq - 0 12");
|
||
|
assertTrue(moveScore(pos, "O-O-O") > 0); // Black long castle is bad for black
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "O-O-O"), ui);
|
||
|
assertTrue(moveScore(pos, "O-O") > 0); // White short castle is good for white
|
||
|
|
||
|
pos = TextIO.readFEN("8/3k4/2p5/1pp5/1P1P4/3K4/8/8 w - - 0 1");
|
||
|
int sc1 = moveScore(pos, "bxc5");
|
||
|
int sc2 = moveScore(pos, "dxc5");
|
||
|
assertTrue(sc1 < sc2); // Don't give opponent a passed pawn.
|
||
|
|
||
|
pos = TextIO.readFEN("8/pp1bk3/8/8/8/8/PPPBK3/8 w - - 0 1");
|
||
|
sc1 = evalWhite(pos);
|
||
|
pos.setPiece(Position.getSquare(3, 1), Piece.EMPTY);
|
||
|
pos.setPiece(Position.getSquare(3, 0), Piece.WBISHOP);
|
||
|
sc2 = evalWhite(pos);
|
||
|
assertTrue(sc2 > sc1); // Easier to win if bishops on same color
|
||
|
|
||
|
// Test bishop mobility
|
||
|
pos = TextIO.readFEN("r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3");
|
||
|
sc1 = moveScore(pos, "Bd3");
|
||
|
sc2 = moveScore(pos, "Bc4");
|
||
|
assertTrue(sc2 > sc1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of pieceSquareEval method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testPieceSquareEval() throws ChessParseError {
|
||
|
System.out.println("pieceSquareEval");
|
||
|
Position pos = TextIO.readFEN(TextIO.startPosFEN);
|
||
|
int score = evalWhite(pos);
|
||
|
assertEquals(0, score); // Should be zero, by symmetry
|
||
|
UndoInfo ui = new UndoInfo();
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "e4"), ui);
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(score > 0); // Centralizing a pawn is a good thing
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "e5"), ui);
|
||
|
score = evalWhite(pos);
|
||
|
assertEquals(0, score); // Should be zero, by symmetry
|
||
|
assertTrue(moveScore(pos, "Nf3") > 0); // Developing knight is good
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nf3"), ui);
|
||
|
assertTrue(moveScore(pos, "Nc6") < 0); // Developing knight is good
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nc6"), ui);
|
||
|
assertTrue(moveScore(pos, "Bb5") > 0); // Developing bishop is good
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Bb5"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nge7"), ui);
|
||
|
assertTrue(moveScore(pos, "Qe2") > 0); // Queen away from edge is good
|
||
|
score = evalWhite(pos);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Bxc6"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nxc6"), ui);
|
||
|
int score2 = evalWhite(pos);
|
||
|
assertTrue(score2 < score); // Bishop worth more than knight in this case
|
||
|
|
||
|
pos = TextIO.readFEN("5k2/4nppp/p1n5/1pp1p3/4P3/2P1BN2/PP3PPP/3R2K1 w - - 0 1");
|
||
|
assertTrue(moveScore(pos, "Rd7") > 0); // Rook on 7:th rank is good
|
||
|
assertTrue(moveScore(pos, "Rd8") <= 0); // Rook on 8:th rank not particularly good
|
||
|
pos.setPiece(TextIO.getSquare("a1"), Piece.WROOK);
|
||
|
assertTrue(moveScore(pos, "Rac1") > 0); // Rook on c-f files considered good
|
||
|
|
||
|
pos = TextIO.readFEN("r4rk1/pppRRppp/1q4b1/n7/8/2N3B1/PPP1QPPP/6K1 w - - 0 1");
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(score > 100); // Two rooks on 7:th rank is very good
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of tradeBonus method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testTradeBonus() throws ChessParseError {
|
||
|
System.out.println("tradeBonus");
|
||
|
String fen = "8/5k2/6r1/2p1p3/3p4/2P2N2/3PPP2/4K1R1 w - - 0 1";
|
||
|
Position pos = TextIO.readFEN(fen);
|
||
|
int score1 = evalWhite(pos);
|
||
|
UndoInfo ui = new UndoInfo();
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Rxg6"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Kxg6"), ui);
|
||
|
int score2 = evalWhite(pos);
|
||
|
assertTrue(score2 > score1); // White ahead, trading pieces is good
|
||
|
|
||
|
pos = TextIO.readFEN(fen);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "cxd4"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "cxd4"), ui);
|
||
|
score2 = evalWhite(pos);
|
||
|
assertTrue(score2 < score1); // White ahead, trading pawns is bad
|
||
|
|
||
|
pos = TextIO.readFEN("8/8/1b2b3/4kp2/5N2/4NKP1/6B1/8 w - - 0 62");
|
||
|
score1 = evalWhite(pos);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nxe6"), ui);
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Kxe6"), ui);
|
||
|
score2 = evalWhite(pos);
|
||
|
assertTrue(score2 > score1); // White ahead, trading pieces is good
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of material method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testMaterial() throws ChessParseError {
|
||
|
System.out.println("material");
|
||
|
Position pos = TextIO.readFEN(TextIO.startPosFEN);
|
||
|
assertEquals(0, Evaluate.material(pos));
|
||
|
|
||
|
final int pV = Evaluate.pV;
|
||
|
final int qV = Evaluate.qV;
|
||
|
assertTrue(pV != 0);
|
||
|
assertTrue(qV != 0);
|
||
|
assertTrue(qV > pV);
|
||
|
|
||
|
UndoInfo ui = new UndoInfo();
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "e4"), ui);
|
||
|
assertEquals(0, Evaluate.material(pos));
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "d5"), ui);
|
||
|
assertEquals(0, Evaluate.material(pos));
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "exd5"), ui);
|
||
|
assertEquals(pV, Evaluate.material(pos));
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Qxd5"), ui);
|
||
|
assertEquals(0, Evaluate.material(pos));
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nc3"), ui);
|
||
|
assertEquals(0, Evaluate.material(pos));
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Qxd2"), ui);
|
||
|
assertEquals(-pV, Evaluate.material(pos));
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Qxd2"), ui);
|
||
|
assertEquals(-pV+qV, Evaluate.material(pos));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of kingSafety method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testKingSafety() throws ChessParseError {
|
||
|
System.out.println("kingSafety");
|
||
|
Position pos = TextIO.readFEN("r3kb1r/p1p1pppp/b2q1n2/4N3/3P4/2N1PQ2/P2B1PPP/R3R1K1 w kq - 0 1");
|
||
|
int s1 = evalWhite(pos);
|
||
|
pos.setPiece(TextIO.getSquare("g7"), Piece.EMPTY);
|
||
|
pos.setPiece(TextIO.getSquare("b7"), Piece.BPAWN);
|
||
|
int s2 = evalWhite(pos);
|
||
|
assertTrue(s2 < s1); // Half-open g-file is bad for white
|
||
|
|
||
|
// Trapping rook with own king is bad
|
||
|
pos = TextIO.readFEN("rnbqk1nr/pppp1ppp/8/8/1bBpP3/8/PPP2PPP/RNBQK1NR w KQkq - 2 4");
|
||
|
s1 = evalWhite(pos);
|
||
|
pos.setPiece(TextIO.getSquare("e1"), Piece.EMPTY);
|
||
|
pos.setPiece(TextIO.getSquare("f1"), Piece.WKING);
|
||
|
s2 = evalWhite(pos);
|
||
|
assertTrue(s2 < s1);
|
||
|
|
||
|
pos = TextIO.readFEN("rnbqk1nr/pppp1ppp/8/8/1bBpPB2/8/PPP1QPPP/RN1K2NR w kq - 0 1");
|
||
|
s1 = evalWhite(pos);
|
||
|
pos.setPiece(TextIO.getSquare("d1"), Piece.EMPTY);
|
||
|
pos.setPiece(TextIO.getSquare("c1"), Piece.WKING);
|
||
|
s2 = evalWhite(pos);
|
||
|
assertTrue(s2 < s1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of endGameEval method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testEndGameEval() throws ChessParseError {
|
||
|
System.out.println("endGameEval");
|
||
|
Position pos = new Position();
|
||
|
pos.setPiece(Position.getSquare(4, 1), Piece.WKING);
|
||
|
pos.setPiece(Position.getSquare(4, 6), Piece.BKING);
|
||
|
int score = evalWhite(pos);
|
||
|
assertEquals(0, score);
|
||
|
|
||
|
pos.setPiece(Position.getSquare(3, 1), Piece.WBISHOP);
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(Math.abs(score) < 50); // Insufficient material to mate
|
||
|
|
||
|
pos.setPiece(Position.getSquare(3, 1), Piece.WKNIGHT);
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(Math.abs(score) < 50); // Insufficient material to mate
|
||
|
|
||
|
pos.setPiece(Position.getSquare(3, 1), Piece.WROOK);
|
||
|
score = evalWhite(pos);
|
||
|
final int rV = Evaluate.rV;
|
||
|
assertTrue(Math.abs(score) > rV + 100); // Enough material to force mate
|
||
|
|
||
|
pos.setPiece(Position.getSquare(3, 6), Piece.BBISHOP);
|
||
|
score = evalWhite(pos);
|
||
|
final int bV = Evaluate.bV;
|
||
|
assertTrue(score >= 0);
|
||
|
assertTrue(score < rV - bV); // Insufficient excess material to mate
|
||
|
|
||
|
pos.setPiece(Position.getSquare(5, 6), Piece.BROOK);
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(score <= 0);
|
||
|
assertTrue(-score < bV);
|
||
|
|
||
|
pos.setPiece(Position.getSquare(2, 6), Piece.BBISHOP);
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(-score > bV * 2 + 100);
|
||
|
|
||
|
// 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;
|
||
|
assertTrue(score > rV + pV - bV - 100);
|
||
|
|
||
|
// KNNK is a draw
|
||
|
pos = TextIO.readFEN("8/8/4k3/8/8/3NK3/3N4/8 w - - 0 1");
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(Math.abs(score) < 50);
|
||
|
|
||
|
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
|
||
|
score = moveScore(pos, "Ke6");
|
||
|
assertTrue(score < 0); // Black king going away from wrong corner, good for black
|
||
|
|
||
|
// KRN vs KR is generally drawn
|
||
|
pos = TextIO.readFEN("rk/p/8/8/8/8/NKR/8 w - - 0 1");
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(score < nV - 2 * pV);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of endGameEval method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testPassedPawns() throws ChessParseError {
|
||
|
System.out.println("passedPawns");
|
||
|
Position pos = TextIO.readFEN("8/8/8/P3k/8/8/p/K w");
|
||
|
int score = evalWhite(pos);
|
||
|
assertTrue(score > 300); // Unstoppable passed pawn
|
||
|
pos.whiteMove = false;
|
||
|
score = evalWhite(pos);
|
||
|
assertTrue(score <= 0); // Not unstoppable
|
||
|
|
||
|
pos = TextIO.readFEN("4R3/8/8/3K4/8/4pk2/8/8 w - - 0 1");
|
||
|
score = evalWhite(pos);
|
||
|
pos.setPiece(TextIO.getSquare("d5"), Piece.EMPTY);
|
||
|
pos.setPiece(TextIO.getSquare("d4"), Piece.WKING);
|
||
|
int score2 = evalWhite(pos);
|
||
|
assertTrue(score2 > score); // King closer to passed pawn promotion square
|
||
|
|
||
|
// Connected passed pawn test. Disabled because it didn't help in tests
|
||
|
// pos = TextIO.readFEN("4k3/8/8/4P3/3P1K2/8/8/8 w - - 0 1");
|
||
|
// score = evalWhite(pos);
|
||
|
// pos.setPiece(TextIO.getSquare("d4"), Piece.EMPTY);
|
||
|
// pos.setPiece(TextIO.getSquare("d5"), Piece.WPAWN);
|
||
|
// score2 = evalWhite(pos);
|
||
|
// assertTrue(score2 > score); // Advancing passed pawn is good
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of endGameEval method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testBishAndRookPawns() throws ChessParseError {
|
||
|
System.out.println("bishAndRookPawns");
|
||
|
final int pV = Evaluate.pV;
|
||
|
final int bV = Evaluate.bV;
|
||
|
final int winScore = pV + bV;
|
||
|
final int drawish = (pV + bV) / 20;
|
||
|
Position pos = TextIO.readFEN("k7/8/8/8/2B5/2K5/P7/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
pos = TextIO.readFEN("k7/8/8/8/3B4/2K5/P7/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
|
||
|
pos = TextIO.readFEN("8/2k5/8/8/3B4/2K5/P7/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
pos = TextIO.readFEN("8/2k5/8/8/3B4/2K4P/8/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
pos = TextIO.readFEN("8/2k5/8/8/4B3/2K4P/8/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
pos = TextIO.readFEN("8/6k1/8/8/4B3/2K4P/8/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
|
||
|
pos = TextIO.readFEN("8/6k1/8/8/4B3/2K4P/7P/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
|
||
|
pos = TextIO.readFEN("8/6k1/8/8/2B1B3/2K4P/7P/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
|
||
|
pos = TextIO.readFEN("8/6k1/8/2B5/4B3/2K4P/7P/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
pos = TextIO.readFEN("8/6k1/8/8/4B3/2K4P/P7/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
pos = TextIO.readFEN("8/6k1/8/8/4B3/2K3PP/8/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
public void testTrappedBishop() throws ChessParseError {
|
||
|
Position pos = TextIO.readFEN("r2q1rk1/ppp2ppp/3p1n2/8/3P4/1P1Q1NP1/b1P2PBP/2KR3R w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > 0); // Black has trapped bishop
|
||
|
|
||
|
pos = TextIO.readFEN("r2q2k1/pp1b1p1p/2p2np1/3p4/3P4/1BNQ2P1/PPPB1P1b/2KR4 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > 0); // Black has trapped bishop
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test of endGameEval method, of class Evaluate.
|
||
|
*/
|
||
|
@Test
|
||
|
public void testKQKP() throws ChessParseError {
|
||
|
System.out.println("KQKP");
|
||
|
final int pV = Evaluate.pV;
|
||
|
final int qV = Evaluate.qV;
|
||
|
final int winScore = qV - pV - 200;
|
||
|
final int drawish = (pV + qV) / 20;
|
||
|
|
||
|
// Pawn on a2
|
||
|
Position pos = TextIO.readFEN("8/8/1K6/8/8/Q7/p7/1k6 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
pos = TextIO.readFEN("8/8/8/1K6/8/Q7/p7/1k6 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
pos = TextIO.readFEN("3Q4/8/8/8/K7/8/1kp5/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
|
||
|
// Pawn on c2
|
||
|
pos = TextIO.readFEN("3Q4/8/8/8/3K4/8/1kp5/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
pos = TextIO.readFEN("3Q4/8/8/8/8/4K3/1kp5/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
public void testKRKP() throws ChessParseError {
|
||
|
System.out.println("KRKP");
|
||
|
final int pV = Evaluate.pV;
|
||
|
final int rV = Evaluate.rV;
|
||
|
final int winScore = rV - pV;
|
||
|
final int drawish = (pV + rV) / 20;
|
||
|
Position pos = TextIO.readFEN("6R1/8/8/8/5K2/2kp4/8/8 w - - 0 1");
|
||
|
assertTrue(evalWhite(pos) > winScore);
|
||
|
pos.whiteMove = !pos.whiteMove;
|
||
|
assertTrue(evalWhite(pos) < drawish);
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
public void testCantWin() throws ChessParseError {
|
||
|
Position pos = TextIO.readFEN("8/8/8/3k4/3p4/3K4/4N3/8 w - - 0 1");
|
||
|
int score1 = evalWhite(pos);
|
||
|
assertTrue(score1 < 0);
|
||
|
UndoInfo ui = new UndoInfo();
|
||
|
pos.makeMove(TextIO.stringToMove(pos, "Nxd4"), ui);
|
||
|
int score2 = evalWhite(pos);
|
||
|
assertTrue(score2 <= 0);
|
||
|
assertTrue(score2 > score1);
|
||
|
}
|
||
|
|
||
|
/** Return static evaluation score for white, regardless of whose turn it is to move. */
|
||
|
final static int evalWhite(Position pos) {
|
||
|
Evaluate eval = new Evaluate();
|
||
|
int ret = eval.evalPos(pos);
|
||
|
Position symPos = swapColors(pos);
|
||
|
int symScore = eval.evalPos(symPos);
|
||
|
assertEquals(ret, symScore);
|
||
|
if (!pos.whiteMove) {
|
||
|
ret = -ret;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
final static Position swapColors(Position pos) {
|
||
|
Position sym = new Position();
|
||
|
sym.whiteMove = !pos.whiteMove;
|
||
|
for (int x = 0; x < 8; x++) {
|
||
|
for (int y = 0; y < 8; y++) {
|
||
|
int p = pos.getPiece(Position.getSquare(x, y));
|
||
|
p = Piece.isWhite(p) ? Piece.makeBlack(p) : Piece.makeWhite(p);
|
||
|
sym.setPiece(Position.getSquare(x, 7-y), p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int castleMask = 0;
|
||
|
if (pos.a1Castle()) castleMask |= 1 << Position.A8_CASTLE;
|
||
|
if (pos.h1Castle()) castleMask |= 1 << Position.H8_CASTLE;
|
||
|
if (pos.a8Castle()) castleMask |= 1 << Position.A1_CASTLE;
|
||
|
if (pos.h8Castle()) castleMask |= 1 << Position.H1_CASTLE;
|
||
|
sym.setCastleMask(castleMask);
|
||
|
|
||
|
if (pos.getEpSquare() >= 0) {
|
||
|
int x = Position.getX(pos.getEpSquare());
|
||
|
int y = Position.getY(pos.getEpSquare());
|
||
|
sym.setEpSquare(Position.getSquare(x, 7-y));
|
||
|
}
|
||
|
|
||
|
sym.halfMoveClock = pos.halfMoveClock;
|
||
|
sym.fullMoveCounter = pos.fullMoveCounter;
|
||
|
|
||
|
return sym;
|
||
|
}
|
||
|
|
||
|
/** Compute change in eval score for white after making "moveStr" in position "pos". */
|
||
|
private final int moveScore(Position pos, String moveStr) {
|
||
|
int score1 = evalWhite(pos);
|
||
|
Position tmpPos = new Position(pos);
|
||
|
UndoInfo ui = new UndoInfo();
|
||
|
tmpPos.makeMove(TextIO.stringToMove(tmpPos, moveStr), ui);
|
||
|
int score2 = evalWhite(tmpPos);
|
||
|
// System.out.printf("move:%s s1:%d s2:%d\n", moveStr, score1, score2);
|
||
|
return score2 - score1;
|
||
|
}
|
||
|
}
|