private static string moveTostring(Position pos, Move move, bool ulongForm, MoveGen.MoveList moves) { string ret = ""; int wKingOrigPos = Position.getSquare(4, 0); int bKingOrigPos = Position.getSquare(4, 7); if (move.from == wKingOrigPos && pos.getPiece(wKingOrigPos) == Piece.WKING) { // Check white castle if (move.to == Position.getSquare(6, 0)) { ret += ("O-O"); } else if (move.to == Position.getSquare(2, 0)) { ret += ("O-O-O"); } } else if (move.from == bKingOrigPos && pos.getPiece(bKingOrigPos) == Piece.BKING) { // Check white castle if (move.to == Position.getSquare(6, 7)) { ret += ("O-O"); } else if (move.to == Position.getSquare(2, 7)) { ret += ("O-O-O"); } } if (ret.Length == 0) { int p = pos.getPiece(move.from); ret += pieceToChar(p); int x1 = Position.getX(move.from); int y1 = Position.getY(move.from); int x2 = Position.getX(move.to); int y2 = Position.getY(move.to); if (ulongForm) { ret += ((char)(x1 + 'a')); ret += ((char)(y1 + '1')); ret += (isCapture(pos, move) ? 'x' : '-'); } else { if (p == (pos.whiteMove ? Piece.WPAWN : Piece.BPAWN)) { if (isCapture(pos, move)) { ret += ((char)(x1 + 'a')); } } else { int numSameTarget = 0; int numSameFile = 0; int numSameRow = 0; for (int mi = 0; mi < moves.size; mi++) { Move m = moves.m[mi]; if (m == null) break; if ((pos.getPiece(m.from) == p) && (m.to == move.to)) { numSameTarget++; if (Position.getX(m.from) == x1) numSameFile++; if (Position.getY(m.from) == y1) numSameRow++; } } if (numSameTarget < 2) { // No file/row info needed } else if (numSameFile < 2) { ret += ((char)(x1 + 'a')); // Only file info needed } else if (numSameRow < 2) { ret += ((char)(y1 + '1')); // Only row info needed } else { ret += ((char)(x1 + 'a')); // File and row info needed ret += ((char)(y1 + '1')); } } if (isCapture(pos, move)) { ret += ('x'); } } ret += ((char)(x2 + 'a')); ret += ((char)(y2 + '1')); if (move.promoteTo != Piece.EMPTY) { ret += (pieceToChar(move.promoteTo)); } } UndoInfo ui = new UndoInfo(); if (MoveGen.givesCheck(pos, move)) { pos.makeMove(move, ui); MoveGen MG = new MoveGen(); MoveGen.MoveList nextMoves = MG.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, nextMoves); if (nextMoves.size == 0) { ret += ('#'); } else { ret += ('+'); } pos.unMakeMove(move, ui); } return ret; }
/** * Extract a list of PV moves, starting from "rootPos" and first move "m". */ 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; }
/** Extract the PV starting from pos, using hash entries, both exact scores and bounds. */ public string extractPV(Position pos) { string ret = ""; pos = new Position(pos); // To avoid modifying the input parameter 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; }
/** 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; }
/** * Remove all illegal moves from moveList. * "moveList" is assumed to be a list of pseudo-legal moves. * This function removes the moves that don't defend from check threats. */ public static void RemoveIllegal(Position pos, MoveList moveList) { int length = 0; UndoInfo ui = new UndoInfo(); for (int mi = 0; mi < moveList.size; mi++) { Move m = moveList.m[mi]; pos.makeMove(m, ui); pos.setWhiteMove(!pos.whiteMove); if (!inCheck(pos)) moveList.m[length++].copyFrom(m); pos.setWhiteMove(!pos.whiteMove); pos.unMakeMove(m, ui); } moveList.size = length; }
/** 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); }
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; } }
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; }
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; }
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; }