Skip to content

Commit

Permalink
Version 1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Senders authored and Senders committed Mar 19, 2017
1 parent 0a6b9d7 commit 713d029
Show file tree
Hide file tree
Showing 32 changed files with 1,729 additions and 1,363 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ Uses Ed Schroder's king safety idea but this has been disabled for the moment.

Features
- (magic) bitboards
- transposition table
- transposition tables
- (internal) iterative-deepening
- killer-moves and history-heuristics for move ordering
- principal variation search
- null-move pruning
- late move reductions
- static exchange evaluation
- aspiration window
- no openingbook or endgame tablebases
- no pondering

Future
- improved time-management
- NEVER loses on time
- fix certain node-explosions in endgames
- futility pruning
- improve evaluation function (king-safety, ...)
- 2 transposition tables: always replace, depth replacement scheme
- tapered eval
- ...

If you want to build this project yourself, you have to set the artifact name in the pom.xml (to chess22k).
I have made this configurable so I can easily build an experimental version but maven does not seem to like this.



"Simplicity is the soul of efficiency"
Expand Down
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
<groupId>nl.s22k</groupId>

<!-- so we can simply build other (experimental) artifacts -->
<artifactId>${engineName}</artifactId>
<version>1.1</version>
<!-- artifactId>${engineName}</artifactId -->
<artifactId>chess22k</artifactId>
<version>1.2</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
10 changes: 10 additions & 0 deletions release-notes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
1.2 - 19-03-2017 - 2400 elo, this time for real? :P
- improved passed-pawn scoring in endgames
- added time to UCI output
- improved time control: x moves in y minutes
- 2 transposition tables: always replace and depth replacement scheme
- made transposition-table-size configurable
- all draw scores are now exactly 0 and stored in the TT
- bugs, again ;)


1.1 09-02-2017 (2400 elo)
- re-enabled mobility evaluation
- knight outposts
Expand Down
10 changes: 0 additions & 10 deletions src/main/java/nl/s22k/chess/CheckUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,4 @@ public static boolean isInCheckIncludingKing(final int kingIndex, final int colo
| enemyPieces[KING] & StaticMoves.KING_MOVES[kingIndex]
)!= 0;
}

public static boolean isInDiscoveredCheckBySlidingVHPiece(final long checkingPieces, final long vHEnemySlidingPieces, final int kingIndex, final long friendlyPieces, final long allPieces) {
// put 'super-piece' in kings position
return (~checkingPieces & vHEnemySlidingPieces & MagicUtil.getRookMoves(kingIndex, allPieces, friendlyPieces)) != 0;
}

public static boolean isInDiscoveredCheckBySlidingDiagonalPiece(final long checkingPieces, final long diagonalEnemySlidingPieces, final int kingIndex, final long friendlyPieces, final long allPieces) {
// put 'super-piece' in kings position
return (~checkingPieces & diagonalEnemySlidingPieces & MagicUtil.getBishopMoves(kingIndex, allPieces, friendlyPieces)) != 0;
}
}
116 changes: 31 additions & 85 deletions src/main/java/nl/s22k/chess/ChessBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,6 @@ public final class ChessBoard {
/** which piece is on which square */
public final int[] pieceIndexes = new int[64];

/** used for quickly determining if king is in check. updated whenever that piece moves */
public final long[] queenRayAttacks = new long[2];
public final long[] rookRayAttacks = new long[2];
public final long[] bishopRayAttacks = new long[2];

public static ChessBoard getInstance() {
return instance;
}
Expand Down Expand Up @@ -149,6 +144,20 @@ public boolean isDrawByMaterial(final int color) {
}
}

public boolean isDrawByMaterial() {
if (Long.bitCount(allPieces) > 3) {
return false;
}
if (Long.bitCount(allPieces) == 2) {
// KK
return true;
}

// KKB or KKN?
return pieces[WHITE][BISHOP] != 0 || pieces[BLACK][BISHOP] != 0 || pieces[WHITE][NIGHT] != 0 || pieces[BLACK][NIGHT] != 0;

}

public boolean isBadBishopEndgame() {
if (Long.bitCount(allPieces) != 4) {
return false;
Expand Down Expand Up @@ -286,7 +295,6 @@ public void doMove(int move) {
pieces[colorToMove][QUEEN] |= toMask;
zobristKey ^= zkPieceValues[toIndex][colorToMove][zkSourcePieceIndex] ^ zkPieceValues[toIndex][colorToMove][QUEEN];
pieceIndexes[toIndex] = QUEEN;
updateQueenRayAttacks(colorToMove);
}
// update other players endgame
if (isEndGame(colorToMoveInverse) != isEndGame[colorToMoveInverse]) {
Expand Down Expand Up @@ -316,7 +324,6 @@ public void doMove(int move) {
pieces[colorToMove][zkSourcePieceIndex] ^= fromToMask;
psqtScore += colorFactor
* (EvalConstants.BISHOP_POSITION_SCORES[colorToMove][toIndex] - EvalConstants.BISHOP_POSITION_SCORES[colorToMove][fromIndex]);
updateBishopRayAttacks(colorToMove);
break;

case ROOK:
Expand All @@ -325,12 +332,10 @@ public void doMove(int move) {
zobristKey ^= zkCastling[castlingRights];
CastlingUtil.setRookMovedOrAttackedCastlingRights(this, fromIndex);
zobristKey ^= zkCastling[castlingRights];
updateRookRayAttacks(colorToMove);
break;

case QUEEN:
pieces[colorToMove][zkSourcePieceIndex] ^= fromToMask;
updateQueenRayAttacks(colorToMove);
break;

case KING:
Expand All @@ -344,7 +349,6 @@ public void doMove(int move) {
}
if (MoveUtil.isCastling(move)) {
CastlingUtil.castleRookUpdateKeyAndPsqt(this, toIndex);
updateRookRayAttacks(colorToMove);
}
zobristKey ^= zkCastling[castlingRights];
CastlingUtil.setKingMovedCastlingRights(this, fromIndex);
Expand Down Expand Up @@ -382,7 +386,6 @@ public void doMove(int move) {
psqtScore += colorFactor * EvalConstants.BISHOP_POSITION_SCORES[colorToMoveInverse][toIndex];
zobristKey ^= zkPieceValues[toIndex][colorToMoveInverse][zkAttackedPieceIndex];
friendlyPieces[colorToMoveInverse] ^= toMask;
updateBishopRayAttacks(colorToMoveInverse);
break;

case ROOK:
Expand All @@ -392,14 +395,12 @@ public void doMove(int move) {
CastlingUtil.setRookMovedOrAttackedCastlingRights(this, toIndex);
zobristKey ^= zkCastling[castlingRights] ^ zkPieceValues[toIndex][colorToMoveInverse][zkAttackedPieceIndex];
friendlyPieces[colorToMoveInverse] ^= toMask;
updateRookRayAttacks(colorToMoveInverse);
break;

case QUEEN:
pieces[colorToMoveInverse][zkAttackedPieceIndex] ^= toMask;
zobristKey ^= zkPieceValues[toIndex][colorToMoveInverse][zkAttackedPieceIndex];
friendlyPieces[colorToMoveInverse] ^= toMask;
updateQueenRayAttacks(colorToMoveInverse);
}

// update current players endgame
Expand Down Expand Up @@ -444,73 +445,33 @@ public void doMove(int move) {

}

public void updateQueenRayAttacks(final int color) {
queenRayAttacks[color] = 0;
long piece = pieces[color][QUEEN];
while (piece != 0) {
queenRayAttacks[color] |= MagicUtil.queenMovesEmptyBoard[Long.numberOfTrailingZeros(piece)];
piece &= piece - 1;
}
}

public void updateRookRayAttacks(final int color) {
rookRayAttacks[color] = 0;
long piece = pieces[color][ROOK];
while (piece != 0) {
rookRayAttacks[color] |= MagicUtil.rookMovesEmptyBoard[Long.numberOfTrailingZeros(piece)];
piece &= piece - 1;
}
}

public void updateBishopRayAttacks(final int color) {
bishopRayAttacks[color] = 0;
long piece = pieces[color][BISHOP];
while (piece != 0) {
bishopRayAttacks[color] |= MagicUtil.bishopMovesEmptyBoard[Long.numberOfTrailingZeros(piece)];
piece &= piece - 1;
}
}

public void updatePinnedPieces(final int color) {

pinnedPieces[color] = 0;

final int colorInverse = color * -1 + 1;
int pieceIndex;

if (((bishopRayAttacks[colorInverse] | queenRayAttacks[colorInverse]) & Util.POWER_LOOKUP[kingIndex[color]]) != 0) {
// iterate over all friendly pieces at diagonal blockingpositions
long piecesLong = friendlyPieces[color] & MagicUtil.getBishopMoves(kingIndex[color], allPieces, friendlyPieces[colorInverse]);
while (piecesLong != 0) {
pieceIndex = Long.numberOfTrailingZeros(piecesLong);

// temporary remove piece and check if is now in check by sliding piece
if (CheckUtil.isInDiscoveredCheckBySlidingDiagonalPiece(checkingPieces, pieces[colorInverse][BISHOP] | pieces[colorInverse][QUEEN],
kingIndex[color], friendlyPieces[color] ^ Util.POWER_LOOKUP[pieceIndex], allPieces ^ Util.POWER_LOOKUP[pieceIndex])) {
// (partially) pinned
pinnedPieces[color] |= Util.POWER_LOOKUP[pieceIndex];
}
long checkedPinnedPiece;
long piece;

piecesLong &= piecesLong - 1;
// bishop and queen
piece = pieces[colorInverse][BISHOP] | pieces[colorInverse][QUEEN];
while (piece != 0) {
checkedPinnedPiece = ChessConstants.BISHOP_IN_BETWEEN[kingIndex[color]][Long.numberOfTrailingZeros(piece)] & allPieces;
if (Long.bitCount(checkedPinnedPiece) == 1) {
pinnedPieces[color] |= checkedPinnedPiece & friendlyPieces[color];
}
piece &= piece - 1;
}
if (((rookRayAttacks[colorInverse] | queenRayAttacks[colorInverse]) & Util.POWER_LOOKUP[kingIndex[color]]) != 0) {
// iterate over all friendly pieces at vertical and horizontal blockingpositions
long piecesLong = friendlyPieces[color] & MagicUtil.getRookMoves(kingIndex[color], allPieces, friendlyPieces[colorInverse]);
while (piecesLong != 0) {
pieceIndex = Long.numberOfTrailingZeros(piecesLong);

// temporary remove piece and check if is now in check by sliding piece
if (CheckUtil.isInDiscoveredCheckBySlidingVHPiece(checkingPieces, pieces[colorInverse][ROOK] | pieces[colorInverse][QUEEN], kingIndex[color],
friendlyPieces[color] ^ Util.POWER_LOOKUP[pieceIndex], allPieces ^ Util.POWER_LOOKUP[pieceIndex])) {
// (partially) pinned
pinnedPieces[color] |= Util.POWER_LOOKUP[pieceIndex];
}

piecesLong &= piecesLong - 1;
// rook and queen
piece = pieces[colorInverse][ROOK] | pieces[colorInverse][QUEEN];
while (piece != 0) {
checkedPinnedPiece = ChessConstants.ROOK_IN_BETWEEN[kingIndex[color]][Long.numberOfTrailingZeros(piece)] & allPieces;
if (Long.bitCount(checkedPinnedPiece) == 1) {
pinnedPieces[color] |= checkedPinnedPiece & friendlyPieces[color];
}
piece &= piece - 1;
}

}

public void undoMove(int move) {
Expand Down Expand Up @@ -547,7 +508,6 @@ public void undoMove(int move) {
pieces[colorToMoveInverse][NIGHT] ^= toMask;
} else {
pieces[colorToMoveInverse][QUEEN] ^= toMask;
updateQueenRayAttacks(colorToMoveInverse);
}
// update other players endgame
isEndGame[colorToMove] = isEndGame(colorToMove);
Expand All @@ -560,21 +520,18 @@ public void undoMove(int move) {
break;
case ROOK:
pieces[colorToMoveInverse][zkSourcePieceIndex] ^= fromToMask;
updateRookRayAttacks(colorToMoveInverse);
break;
case BISHOP:
pieces[colorToMoveInverse][zkSourcePieceIndex] ^= fromToMask;
updateBishopRayAttacks(colorToMoveInverse);
break;
case QUEEN:
pieces[colorToMoveInverse][zkSourcePieceIndex] ^= fromToMask;
updateQueenRayAttacks(colorToMoveInverse);
break;
case KING:
if (MoveUtil.isCastling(move)) {
pieces[colorToMoveInverse][KING] = fromMask;
CastlingUtil.uncastleRook(this, toIndex);
updateRookRayAttacks(colorToMoveInverse);
// updateRookRayAttacks(colorToMoveInverse);
} else {
pieces[colorToMoveInverse][zkSourcePieceIndex] ^= fromToMask;
}
Expand All @@ -591,17 +548,6 @@ public void undoMove(int move) {
} else {
pieces[colorToMove][zkAttackedPieceIndex] |= toMask;
friendlyPieces[colorToMove] |= toMask;

switch (zkAttackedPieceIndex) {
case ROOK:
updateRookRayAttacks(colorToMove);
break;
case BISHOP:
updateBishopRayAttacks(colorToMove);
break;
case QUEEN:
updateQueenRayAttacks(colorToMove);
}
}
// update current players endgame
isEndGame[colorToMoveInverse] = isEndGame(colorToMoveInverse);
Expand Down
33 changes: 4 additions & 29 deletions src/main/java/nl/s22k/chess/ChessBoardTestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ public static void testValues(ChessBoard cb, String method) {
long iterativeWhitePieces = cb.friendlyPieces[WHITE];
long iterativeBlackPieces = cb.friendlyPieces[BLACK];
long iterativeAllPieces = cb.allPieces;
long iterativeWhiteBishopAttacks = cb.bishopRayAttacks[WHITE];
long iterativeBlackBishopAttacks = cb.bishopRayAttacks[BLACK];
long iterativeWhiteRookAttacks = cb.rookRayAttacks[WHITE];
long iterativeBlackRookAttacks = cb.rookRayAttacks[BLACK];
long iterativeWhiteQueenAttacks = cb.queenRayAttacks[WHITE];
long iterativeBlackQueenAttacks = cb.queenRayAttacks[BLACK];
long pinnedPiecesWhite = cb.pinnedPieces[WHITE];
long pinnedPiecesBlack = cb.pinnedPieces[BLACK];
int iterativePsqt = cb.psqtScore;
Expand Down Expand Up @@ -56,26 +50,6 @@ public static void testValues(ChessBoard cb, String method) {
System.out.println(String.format("Incorrect black pinned-pieces calculated in chessBoard.%s()", method));
}

// attack-pieces
if (iterativeBlackBishopAttacks != cb.bishopRayAttacks[BLACK]) {
System.out.println(String.format("Incorrect black bishop attacks calculated in chessBoard.%s()", method));
}
if (iterativeWhiteBishopAttacks != cb.bishopRayAttacks[WHITE]) {
System.out.println(String.format("Incorrect white bishop attacks calculated in chessBoard.%s()", method));
}
if (iterativeBlackRookAttacks != cb.rookRayAttacks[BLACK]) {
System.out.println(String.format("Incorrect black rook attacks calculated in chessBoard.%s()", method));
}
if (iterativeWhiteRookAttacks != cb.rookRayAttacks[WHITE]) {
System.out.println(String.format("Incorrect white rook attacks calculated in chessBoard.%s()", method));
}
if (iterativeBlackQueenAttacks != cb.queenRayAttacks[BLACK]) {
System.out.println(String.format("Incorrect black queen attacks calculated in chessBoard.%s()", method));
}
if (iterativeWhiteQueenAttacks != cb.queenRayAttacks[WHITE]) {
System.out.println(String.format("Incorrect white queen attacks calculated in chessBoard.%s()", method));
}

// combined pieces
if (iterativeWhitePieces != cb.friendlyPieces[WHITE]) {
System.out.println(String.format("Incorrect whitePieces calculated in chessBoard.%s()", method));
Expand All @@ -96,10 +70,11 @@ public static void testValues(ChessBoard cb, String method) {
}

// piece-indexes
int[] iterativePieceScores = new int[64];
System.arraycopy(cb.pieceIndexes, 0, iterativePieceScores, 0, 64);
for (int i = 0; i < 64; i++) {
if (iterativePieceScores[i] != cb.pieceIndexes[i]) {
if ((cb.allPieces & Util.POWER_LOOKUP[i]) != 0 && cb.pieceIndexes[i] == ChessConstants.EMPTY) {
System.out.println(String.format("Incorrect pieceScores calculated in chessBoard.%s()", method));
}
if ((cb.allPieces & Util.POWER_LOOKUP[i]) == 0 && cb.pieceIndexes[i] != ChessConstants.EMPTY) {
System.out.println(String.format("Incorrect pieceScores calculated in chessBoard.%s()", method));
}
}
Expand Down
Loading

0 comments on commit 713d029

Please sign in to comment.