static ulong perfT(MoveGen moveGen, Position pos, int depth) { if (depth == 0) { return(1); } ulong nodes = 0; MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); if (depth == 1) { int ret = moves.size; moveGen.returnMoveList(moves); return((ulong)ret); } UndoInfo ui = new UndoInfo(); for (int mi = 0; mi < moves.size; mi++) { Move m = moves.m[mi]; pos.makeMove(m, ui); nodes += perfT(moveGen, pos, depth - 1); pos.unMakeMove(m, ui); } moveGen.returnMoveList(moves); return(nodes); }
/** * Update the game state according to move/command string from a player. * @param str The move or command to process. * @return True if str was understood, false otherwise. */ public bool processstring(string str) { if (handleCommand(str)) { return(true); } if (getGameState() != GameState.ALIVE) { return(false); } Move m = TextIO.stringToMove(pos, str); if (m == null) { return(false); } UndoInfo ui = new UndoInfo(); pos.makeMove(m, ui); TextIO.fixupEPSquare(pos); while (currentMove < moveList.Count) { moveList.RemoveAt(currentMove); uiInfoList.RemoveAt(currentMove); drawOfferList.RemoveAt(currentMove); } moveList.Add(m); uiInfoList.Add(ui); drawOfferList.Add(pendingDrawOffer); pendingDrawOffer = false; currentMove++; return(true); }
public List <string> getPosHistory() { List <string> ret = new List <string>(); Position pos2 = new Position(pos /*this.pos*/); for (int i = currentMove; i > 0; i--) { pos2.unMakeMove(moveList[i - 1], uiInfoList[i - 1]); } ret.Add(TextIO.toFEN(pos2)); // Store initial FEN string moves = ""; for (int i = 0; i < moveList.Count; i++) { Move move = moveList[i]; string strMove = TextIO.moveTostring(pos2, move, false); moves += " " + strMove; UndoInfo ui = new UndoInfo(); pos2.makeMove(move, ui); } ret.Add(moves); // Store move list string int numUndo = moveList.Count - currentMove; ret.Add(((int)numUndo).ToString()); return(ret); }
/** Search a position and return the best move and score. Used for test suite processing. */ public TwoReturnValues <Move, string> searchPosition(Position pos, int maxTimeMillis) { // Create a search object ulong[] posHashList = new ulong[200]; tt.nextGeneration(); Search sc = new Search(pos, posHashList, 0, tt); // Determine all legal moves MoveGen.MoveList moves = new MoveGen().pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); sc.scoreMoveList(moves, 0); // Find best move using iterative deepening sc.timeLimit(maxTimeMillis, maxTimeMillis); Move bestM = sc.iterativeDeepening(moves, -1, -1, false); // Extract PV string PV = TextIO.moveTostring(pos, bestM, false) + " "; UndoInfo ui = new UndoInfo(); pos.makeMove(bestM, ui); PV += tt.extractPV(pos); pos.unMakeMove(bestM, ui); // tt.printStats(); // Return best move and PV return(new TwoReturnValues <Move, string>(bestM, PV)); }
/** Check if a draw claim is allowed, possibly after playing "move". * @param move The move that may have to be made before claiming draw. * @return The draw string that claims the draw, or empty string if draw claim not valid. */ private string canClaimDraw(Position pos, ulong[] posHashList, int posHashListSize, Move move) { string drawStr = ""; if (Search.canClaimDraw50(pos)) { drawStr = "draw 50"; } else if (Search.canClaimDrawRep(pos, posHashList, posHashListSize, posHashListSize)) { drawStr = "draw rep"; } else { string strMove = TextIO.moveTostring(pos, move, false); posHashList[posHashListSize++] = pos.zobristHash(); UndoInfo ui = new UndoInfo(); pos.makeMove(move, ui); if (Search.canClaimDraw50(pos)) { drawStr = "draw 50 " + strMove; } else if (Search.canClaimDrawRep(pos, posHashList, posHashListSize, posHashListSize)) { drawStr = "draw rep " + strMove; } pos.unMakeMove(move, ui); } return(drawStr); }
private void initBook(bool verbose) { bookMap = new Dictionary <ulong, List <BookEntry> >(); long t0 = SystemHelper.currentTimeMillis(); numBookMoves = 0; try { /* read /book.bin into buf */ Byte[] buf = Bookbin.DATA; Position startPos = TextIO.readFEN(TextIO.startPosFEN); Position pos = new Position(startPos); UndoInfo ui = new UndoInfo(); int len = buf.Length; for (int i = 0; i < len; i += 2) { int b0 = buf[i]; if (b0 < 0) { b0 += 256; } int b1 = buf[i + 1]; if (b1 < 0) { b1 += 256; } int move = (b0 << 8) + b1; if (move == 0) { pos = new Position(startPos); } else { bool bad = ((move >> 15) & 1) != 0; int prom = (move >> 12) & 7; Move m = new Move(move & 63, (move >> 6) & 63, promToPiece(prom, pos.whiteMove)); if (!bad) { addToBook(pos, m); } pos.makeMove(m, ui); } } } catch { SystemHelper.println("Can't read opening book resource"); throw new RuntimeException(); } if (verbose) { long t1 = SystemHelper.currentTimeMillis(); SystemHelper.println("Book moves: " + numBookMoves.ToString() + "(parse time: " + ((t1 - t0) / 1000).ToString() + ")"); } }
public void unMakeMove(Move move, UndoInfo ui) { hashKey ^= whiteHashKey; 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); } } }
/// <summary> /// Extract a list of PV moves, starting from "rootPos" and first move "m". /// </summary> /// <param name="rootPos"></param> /// <param name="m"></param> /// <returns></returns> public List <Move> extractPVMoves(Position rootPos, Move m) { Position pos = new Position(rootPos); m = new Move(m); List <Move> ret = new List <Move>(); UndoInfo ui = new UndoInfo(); List <ulong> hashHistory = new List <ulong>(); MoveGen moveGen = new MoveGen(); while (true) { ret.Add(m); pos.makeMove(m, ui); if (hashHistory.Contains(pos.zobristHash())) { break; } hashHistory.Add(pos.zobristHash()); TTEntry ent = probe(pos.historyHash()); if (ent.type == TTEntry.T_EMPTY) { break; } m = new Move(0, 0, 0); ent.getMove(m); MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); bool contains = false; for (int mi = 0; mi < moves.size; mi++) { if (moves.m[mi].equals(m)) { contains = true; break; } } if (!contains) { break; } } return(ret); }
/** * Apply a move to the current position. * Special version that only updates enough of the state for the SEE function to be happy. */ public void makeSEEMove(Move move, UndoInfo ui) { ui.capturedPiece = squares[move.to]; bool wtm = whiteMove; int p = squares[move.from]; ulong fromMask = 1UL << 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) { if (p == Piece.WPAWN) { setSEEPiece(move.to - 8, Piece.EMPTY); } else if (p == Piece.BPAWN) { setSEEPiece(move.to + 8, Piece.EMPTY); } } // Perform move setSEEPiece(move.from, Piece.EMPTY); setSEEPiece(move.to, p); whiteMove = !wtm; }
public void unMakeSEEMove(Move move, UndoInfo ui) { whiteMove = !whiteMove; int p = squares[move.to]; setSEEPiece(move.from, p); setSEEPiece(move.to, ui.capturedPiece); bool 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) { if (p == Piece.WPAWN) { setSEEPiece(move.to - 8, Piece.BPAWN); } else if (p == Piece.BPAWN) { setSEEPiece(move.to + 8, Piece.WPAWN); } } }
/** Apply a move to the current position. */ public void makeMove(Move move, UndoInfo ui) { ui.capturedPiece = squares[move.to]; ui.castleMask = castleMask; ui.epSquare = epSquare; ui.halfMoveClock = halfMoveClock; bool wtm = whiteMove; int p = squares[move.from]; int capP = squares[move.to]; ulong fromMask = 1UL << move.from; int prevEpSquare = epSquare; setEpSquare(-1); if ((capP != Piece.EMPTY) || (((pieceTypeBB[Piece.WPAWN] | pieceTypeBB[Piece.BPAWN]) & fromMask) != 0)) { halfMoveClock = 0; // Handle en passant and epSquare if (p == Piece.WPAWN) { if (move.to - move.from == 2 * 8) { int x = Position.getX(move.to); if (((x > 0) && (squares[move.to - 1] == Piece.BPAWN)) || ((x < 7) && (squares[move.to + 1] == 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 = Position.getX(move.to); if (((x > 0) && (squares[move.to - 1] == Piece.WPAWN)) || ((x < 7) && (squares[move.to + 1] == Piece.WPAWN))) { setEpSquare(move.from - 8); } } else if (move.to == prevEpSquare) { setPiece(move.to + 8, Piece.EMPTY); } } if (((pieceTypeBB[Piece.WKING] | pieceTypeBB[Piece.BKING]) & fromMask) != 0) { if (wtm) { setCastleMask(castleMask & ~(1 << Position.A1_CASTLE)); setCastleMask(castleMask & ~(1 << Position.H1_CASTLE)); } else { setCastleMask(castleMask & ~(1 << Position.A8_CASTLE)); setCastleMask(castleMask & ~(1 << Position.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] | pieceTypeBB[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 << Position.A1_CASTLE)); setCastleMask(castleMask & ~(1 << Position.H1_CASTLE)); } else { setCastleMask(castleMask & ~(1 << Position.A8_CASTLE)); setCastleMask(castleMask & ~(1 << Position.H8_CASTLE)); } } // Perform move movePieceNotPawn(move.from, move.to); } if (!wtm) { fullMoveCounter++; } // Update castling rights when rook moves if ((BitBoard.maskCorners & fromMask) != 0) { int rook = wtm ? Piece.WROOK : Piece.BROOK; if (p == rook) { removeCastleRights(move.from); } } if ((BitBoard.maskCorners & (1UL << move.to)) != 0) { int oRook = wtm ? Piece.BROOK : Piece.WROOK; if (capP == oRook) { removeCastleRights(move.to); } } hashKey ^= whiteHashKey; whiteMove = !wtm; }
private bool handleDrawCmd(string drawCmd) { if (drawCmd.StartsWith("rep") || drawCmd.StartsWith("50")) { bool rep = drawCmd.StartsWith("rep"); Move m = null; string ms = drawCmd.Substring(drawCmd.IndexOf(" ") + 1); if (ms.Length > 0) { m = TextIO.stringToMove(pos, ms); } bool valid; if (rep) { valid = false; List <Position> oldPositions = new List <Position>(); Position tmpPos; if (m != null) { UndoInfo ui = new UndoInfo(); tmpPos = new Position(pos); tmpPos.makeMove(m, ui); oldPositions.Add(tmpPos); } oldPositions.Add(pos); tmpPos = pos; for (int i = currentMove - 1; i >= 0; i--) { tmpPos = new Position(tmpPos); tmpPos.unMakeMove(moveList[i], uiInfoList[i]); oldPositions.Add(tmpPos); } int repetitions = 0; Position firstPos = oldPositions[0]; for (int i = 0; i < oldPositions.Count; i++) { Position p = oldPositions[i]; if (p.drawRuleEquals(firstPos)) { repetitions++; } } if (repetitions >= 3) { valid = true; } } else { Position tmpPos = new Position(pos); if (m != null) { UndoInfo ui = new UndoInfo(); tmpPos.makeMove(m, ui); } valid = tmpPos.halfMoveClock >= 100; } if (valid) { drawState = rep ? GameState.DRAW_REP : GameState.DRAW_50; drawStateMoveStr = null; if (m != null) { drawStateMoveStr = TextIO.moveTostring(pos, m, false); } } else { pendingDrawOffer = true; if (m != null) { processstring(ms); } } return(true); } else if (drawCmd.StartsWith("offer ")) { pendingDrawOffer = true; string ms = drawCmd.Substring(drawCmd.IndexOf(" ") + 1); if (TextIO.stringToMove(pos, ms) != null) { processstring(ms); } return(true); } else if (drawCmd == "accept") { if (haveDrawOffer()) { drawState = GameState.DRAW_AGREE; } return(true); } else { return(false); } }
public string getMoveListstring(bool compressed) { string ret = ""; // Undo all moves in move history. Position pos2 = new Position(pos /*this.pos*/); for (int i = currentMove; i > 0; i--) { pos2.unMakeMove(moveList[i - 1], uiInfoList[i - 1]); } // Print all moves string whiteMove = ""; string blackMove = ""; for (int i = 0; i < currentMove; i++) { Move move = moveList[i]; string strMove = TextIO.moveTostring(pos2, move, false); if (drawOfferList[i]) { strMove += " (d)"; } if (pos2.whiteMove) { whiteMove = strMove; } else { blackMove = strMove; if (whiteMove.Length == 0) { whiteMove = "..."; } if (compressed) { ret += pos2.fullMoveCounter.ToString() + ". " + whiteMove + " " + blackMove + " "; } else { ret += pos2.fullMoveCounter.ToString() + ". " + whiteMove.PadRight(10) + " " + blackMove.PadRight(10) + " "; } whiteMove = ""; blackMove = ""; } UndoInfo ui = new UndoInfo(); pos2.makeMove(move, ui); } if ((whiteMove.Length > 0) || (blackMove.Length > 0)) { if (whiteMove.Length == 0) { whiteMove = "..."; } if (compressed) { ret += pos2.fullMoveCounter.ToString() + ". " + whiteMove + " " + blackMove + " "; } else { ret += pos2.fullMoveCounter.ToString() + ". " + whiteMove.PadRight(10) + " " + blackMove.PadRight(10) + " "; } } string gameResult = getPGNResultstring(); if (gameResult != "*") { ret += gameResult; } return(ret); }
/// <summary> /// Extract the PV starting from pos, using hash entries, both exact scores and bounds. /// </summary> /// <param name="pos"></param> /// <returns></returns> public string extractPV(Position pos) { pos = new Position(pos); string ret = ""; bool first = true; TTEntry ent = probe(pos.historyHash()); UndoInfo ui = new UndoInfo(); List <ulong> hashHistory = new List <ulong>(); bool repetition = false; while (ent.type != TTEntry.T_EMPTY) { string type = ""; if (ent.type == TTEntry.T_LE) { type = "<"; } else if (ent.type == TTEntry.T_GE) { type = ">"; } Move m = new Move(0, 0, 0); ent.getMove(m); MoveGen MG = new MoveGen(); MoveGen.MoveList moves = MG.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); bool contains = false; for (int mi = 0; mi < moves.size; mi++) { if (moves.m[mi].equals(m)) { contains = true; break; } } if (!contains) { break; } string moveStr = TextIO.moveTostring(pos, m, false); if (repetition) { break; } if (!first) { ret += " "; } ret += type + moveStr; pos.makeMove(m, ui); if (hashHistory.Contains(pos.zobristHash())) { repetition = true; } hashHistory.Add(pos.zobristHash()); ent = probe(pos.historyHash()); first = false; } return(ret); }