private Move findSemiRandomMove(Search sc, MoveGen.MoveList moves) { sc.timeLimit(minTimeMillis, maxTimeMillis); Move bestM = sc.iterativeDeepening(moves, 1, maxNodes, verbose); int bestScore = bestM.score; long t0 = SystemHelper.currentTimeMillis(); Random rndGen = new Random((int)t0); int sum = 0; for (int mi = 0; mi < moves.size; mi++) { sum += moveProbWeight(moves.m[mi].score, bestScore); } int rnd = rndGen.Next(sum); for (int mi = 0; mi < moves.size; mi++) { int weight = moveProbWeight(moves.m[mi].score, bestScore); if (rnd < weight) { return(moves.m[mi]); } rnd -= weight; } SystemHelper.println("Assert error. Should never get here!"); return(null); }
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); }
/// <summary> /// Remove pseudo-legal EP square if it is not legal, ie would leave king in check. /// </summary> /// <param name="pos"></param> 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); } } }
/// <summary> /// Convert a chess move to human readable form. /// </summary> /// <param name="pos">The chess position.</param> /// <param name="move">The executed move.</param> /// <param name="ulongForm">If true, use ulong notation, eg Ng1-f3. Otherwise, use short notation, eg Nf3</param> /// <returns></returns> 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)); }
/// <summary> /// To get all valid moves in one text-string /// </summary> /// <param name="pos"></param> /// <param name="ulongForm"></param> /// <returns></returns> 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); }
/// <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); }
/// <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); }
/// <summary> /// 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. /// </summary> /// <param name="pos"></param> /// <param name="strMove"></param> /// <returns></returns> 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) { // More than one match, not ok return(null); } else { move = m; } } } if (move != null) { return(move); } } return(move); }
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) { // Only file info needed ret += ((char)(x1 + 'a')); } else if (numSameRow < 2) { // Only row info needed ret += ((char)(y1 + '1')); } else { // File and row info needed ret += ((char)(x1 + 'a')); 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); }