public string getCommand(Position pos, bool drawOffer, List<Position> history)
        {
            // Create a search object
            ulong[] posHashList = new ulong[200 + history.Count];
            int posHashListSize = 0;
            for(int i=0;i<history.Count;i++)
            {
            Position p = history[i];
            posHashList[posHashListSize++] = p.zobristHash();
            }
            tt.nextGeneration();
            Search sc = new Search(pos, posHashList, posHashListSize, tt);

            // Determine all legal moves
            MoveGen.MoveList moves = new MoveGen().pseudoLegalMoves(pos);
            MoveGen.RemoveIllegal(pos, moves);
            sc.scoreMoveList(moves, 0);

            // Test for "game over"
            if (moves.size == 0) {
            // Switch sides so that the human can decide what to do next.
            return "swap";
            }

            if (bookEnabled) {
            Move bookMove = book.getBookMove(pos);
            if (bookMove != null) {
                SystemHelper.printf("Book moves: " + book.getAllBookMoves(pos));
                return TextIO.moveTostring(pos, bookMove, true);
            }
            }

            // Find best move using iterative deepening
            currentSearch = sc;
            sc.setListener(listener);
            Move bestM;
            if ((moves.size == 1) && (canClaimDraw(pos, posHashList, posHashListSize, moves.m[0]) == "")) {
            bestM = moves.m[0];
            bestM.score = 0;
            } else if (randomMode) {
            bestM = findSemiRandomMove(sc, moves);
            } else {
            sc.timeLimit(minTimeMillis, maxTimeMillis);
            bestM = sc.iterativeDeepening(moves, maxDepth, maxNodes, verbose);
            }
            currentSearch = null;
            //        tt.printStats();
            string strMove = TextIO.moveTostring(pos, bestM, true);
            bestmv = bestM;

            // Claim draw if appropriate
            if (bestM.score <= 0) {
            string drawClaim = canClaimDraw(pos, posHashList, posHashListSize, bestM);
            if (drawClaim != "")
                strMove = drawClaim;
            }
            return strMove;
        }
示例#2
0
 // 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;
 }
示例#4
0
 /**
  * Get the current state of the game.
  */
 public static GameState getGameState()
 {
     MoveGen.MoveList moves = new MoveGen().pseudoLegalMoves(pos);
     MoveGen.RemoveIllegal(pos, moves);
     if (moves.size == 0) {
     if (MoveGen.inCheck(pos)) {
         return pos.whiteMove ? GameState.BLACK_MATE : GameState.WHITE_MATE;
     } else {
         return pos.whiteMove ? GameState.WHITE_STALEMATE : GameState.BLACK_STALEMATE;
     }
     }
     if (insufficientMaterial()) {
     return GameState.DRAW_NO_MATE;
     }
     if (resignState != GameState.ALIVE) {
     return resignState;
     }
     return drawState;
 }
示例#5
0
        /** Return a random book move for a position, or null if out of book. */
        public Move getBookMove(Position pos)
        {
            long t0 = SystemHelper.currentTimeMillis();
            Random rndGen = new Random((int)t0);
            ulong key = pos.zobristHash();
            bool iskey = bookMap.ContainsKey(key);
            List<BookEntry> bookMoves = (iskey ? bookMap[key] : null);
            if (bookMoves == null) {
            return null;
            }

            MoveGen.MoveList legalMoves = new MoveGen().pseudoLegalMoves(pos);
            MoveGen.RemoveIllegal(pos, legalMoves);
            int sum = 0;
            for (int i = 0; i < bookMoves.Count; i++) {
            BookEntry be = bookMoves[i];
            bool contains = false;
            for (int mi = 0; mi < legalMoves.size; mi++)
                if (legalMoves.m[mi].equals(be.move)) {
                    contains = true;
                    break;
                }
            if  (!contains) {
                // If an illegal move was found, it means there was a hash collision.
                return null;
            }
            sum += getWeight(bookMoves[i].count);
            }
            if (sum <= 0) {
            return null;
            }
            int rnd = rndGen.Next(sum);
            sum = 0;
            for (int i = 0; i < bookMoves.Count; i++) {
            sum += getWeight(bookMoves[i].count);
            if (rnd < sum) {
                return bookMoves[i].move;
            }
            }
            // Should never get here
            throw new RuntimeException();
        }
示例#6
0
 /** 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);
     }
     }
 }
示例#7
0
        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;
        }
示例#8
0
        /**
         * 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;
        }
示例#9
0
 /**
  * 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;
 }
示例#11
0
        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;
        }
示例#12
0
        /** 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);
        }
示例#13
0
 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;
 }
示例#14
0
 /**
  * Handle a special command.
  * @param moveStr  The command to handle
  * @return  True if command handled, false otherwise.
  */
 public bool handleCommand(string moveStr)
 {
     if (moveStr=="new") {
     moveList = new List<Move>();
     uiInfoList = new List<UndoInfo>();
     drawOfferList = new List<bool>();
     currentMove = 0;
     pendingDrawOffer = false;
     drawState = GameState.ALIVE;
     resignState = GameState.ALIVE;
     try {
         pos = TextIO.readFEN(TextIO.startPosFEN);
     } catch (ChessParseError ex) {
         throw new RuntimeException();
     }
     whitePlayer.clearTT();
     blackPlayer.clearTT();
     activateHumanPlayer();
     return true;
     } else if (moveStr=="undo") {
     if (currentMove > 0) {
         pos.unMakeMove(moveList[currentMove - 1], uiInfoList[currentMove - 1]);
         currentMove--;
         pendingDrawOffer = false;
         drawState = GameState.ALIVE;
         resignState = GameState.ALIVE;
         return handleCommand("swap");
     } else {
         SystemHelper.println("Nothing to undo");
     }
     return true;
     } else if (moveStr=="redo") {
     if (currentMove < moveList.Count) {
         pos.makeMove(moveList[currentMove], uiInfoList[currentMove]);
         currentMove++;
         pendingDrawOffer = false;
         return handleCommand("swap");
     } else {
         SystemHelper.println("Nothing to redo");
     }
     return true;
     } else if ((moveStr=="swap") || (moveStr=="go")) {
     Player tmp = whitePlayer;
     whitePlayer = blackPlayer;
     blackPlayer = tmp;
     return true;
     } else if (moveStr=="list") {
     listMoves();
     return true;
     } else if (moveStr.StartsWith("setpos ")) {
     string fen = moveStr.Substring(moveStr.IndexOf(" ") + 1);
     Position newPos = null;
     try {
         newPos = TextIO.readFEN(fen);
     } catch (ChessParseError ex) {
         SystemHelper.printf("Invalid FEN: " + fen);
     }
     if (newPos != null) {
         handleCommand("new");
         pos = newPos;
         activateHumanPlayer();
     }
     return true;
     } else if (moveStr=="getpos") {
     string fen = TextIO.toFEN(pos);
     SystemHelper.println(fen);
     return true;
     } else if (moveStr.StartsWith("draw ")) {
     if (getGameState() == GameState.ALIVE) {
         string drawCmd = moveStr.Substring(moveStr.IndexOf(" ") + 1);
         return handleDrawCmd(drawCmd);
     } else {
         return true;
     }
     } else if (moveStr=="resign") {
     if (getGameState()== GameState.ALIVE) {
         resignState = pos.whiteMove ? GameState.RESIGN_WHITE : GameState.RESIGN_BLACK;
         return true;
     } else {
         return true;
     }
     } else if (moveStr.StartsWith("book")) {
     string bookCmd = moveStr.Substring(moveStr.IndexOf(" ") + 1);
     return handleBookCmd(bookCmd);
     } else if (moveStr.StartsWith("time")) {
     try {
         string timeStr = moveStr.Substring(moveStr.IndexOf(" ") + 1);
         int timeLimit = int.Parse(timeStr);
         whitePlayer.timeLimit(timeLimit, timeLimit, false);
         blackPlayer.timeLimit(timeLimit, timeLimit, false);
         return true;
     }
     catch (NumberFormatException nfe) {
         SystemHelper.printf("Number format exception: " + moveStr);
         return false;
     }
     } else if (moveStr.StartsWith("perft ")) {
     try {
         string depthStr = moveStr.Substring(moveStr.IndexOf(" ") + 1);
         int depth = int.Parse(depthStr);
         MoveGen moveGen = new MoveGen();
         long t0 = SystemHelper.currentTimeMillis();
         ulong nodes = perfT(moveGen, pos, depth);
         long t1 = SystemHelper.currentTimeMillis();
         SystemHelper.printf("perft(" + depth.ToString() + ") = " +
             nodes.ToString() + " t=" + ((t1 - t0)/1000).ToString() + "s" );
     }
     catch (NumberFormatException nfe) {
         SystemHelper.printf("Number format exception: " + moveStr);
         return false;
     }
     return true;
     } else {
     return false;
     }
 }