// To get all valid moves in one text-string public static string AllMovesTostring(Position pos, bool ulongForm) { string ret = ""; MoveGen MG = new MoveGen(); MoveGen.MoveList moves = MG.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); for (int i = 0; i < moves.size; i++) { ret += moveTostring(pos, moves.m[i], ulongForm, moves) + ";"; } 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; }
/** Remove pseudo-legal EP square if it is not legal, ie would leave king in check. */ public static void fixupEPSquare(Position pos) { int epSquare = pos.getEpSquare(); if (epSquare >= 0) { MoveGen MG = new MoveGen(); MoveGen.MoveList moves = MG.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); bool epValid = false; for (int mi = 0; mi < moves.size; mi++) { Move m = moves.m[mi]; if (m.to == epSquare) { if (pos.getPiece(m.from) == (pos.whiteMove ? Piece.WPAWN : Piece.BPAWN)) { epValid = true; break; } } } if (!epValid) { pos.setEpSquare(-1); } } }
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; }
/** * Convert a chess move string to a Move object. * Any prefix of the string representation of a valid move counts as a legal move string, * as ulong as the string only matches one valid move. */ public static Move stringToMove(Position pos, string strMove) { strMove = strMove.Replace("=", ""); Move move = null; if (strMove.Length == 0) return move; MoveGen MG = new MoveGen(); MoveGen.MoveList moves = MG.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); { char lastChar = strMove[strMove.Length - 1]; if ((lastChar == '#') || (lastChar == '+')) { MoveGen.MoveList subMoves = new MoveGen.MoveList(); int len = 0; for (int mi = 0; mi < moves.size; mi++) { Move m = moves.m[mi]; string str1 = TextIO.moveTostring(pos, m, true, moves); if (str1[str1.Length - 1] == lastChar) { subMoves.m[len++] = m; } } subMoves.size = len; moves = subMoves; strMove = normalizeMovestring(strMove); } } for (int i = 0; i < 2; i++) { // Search for full match for (int mi = 0; mi < moves.size; mi++) { Move m = moves.m[mi]; string str1 = normalizeMovestring(TextIO.moveTostring(pos, m, true, moves)); string str2 = normalizeMovestring(TextIO.moveTostring(pos, m, false, moves)); if (i == 0) { if ((str1 == strMove) || (str2 == strMove)) { return m; } } else { if ((strMove.ToLower() == str1.ToLower()) || (strMove.ToLower() == str2.ToLower())) { return m; } } } } for (int i = 0; i < 2; i++) { // Search for unique substring match for (int mi = 0; mi < moves.size; mi++) { Move m = moves.m[mi]; string str1 = normalizeMovestring(TextIO.moveTostring(pos, m, true)); string str2 = normalizeMovestring(TextIO.moveTostring(pos, m, false)); bool match; if (i == 0) { match = (str1.StartsWith(strMove) || str2.StartsWith(strMove)); } else { match = (str1.ToLower().StartsWith(strMove.ToLower()) || str2.ToLower().StartsWith(strMove.ToLower())); } if (match) { if (move != null) { return null; // More than one match, not ok } else { move = m; } } } if (move != null) return move; } return move; }
/** * Convert a chess move to human readable form. * @param pos The chess position. * @param move The executed move. * @param ulongForm If true, use ulong notation, eg Ng1-f3. * Otherwise, use short notation, eg Nf3 */ public static string moveTostring(Position pos, Move move, bool ulongForm) { MoveGen MG = new MoveGen(); MoveGen.MoveList moves = MG.pseudoLegalMoves(pos); MoveGen.RemoveIllegal(pos, moves); return moveTostring(pos, move, ulongForm, moves); }
/** * 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; }
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; }