Esempio n. 1
0
        /// <summary>
        /// Returns a string that describes the given principal variation.
        /// </summary>
        /// <param name="position">The position the principal variation is to be played on.</param>
        /// <param name="depth">The depth of the search that yielded the principal variation.</param>
        /// <param name="value">The value of the search that yielded the principal variation.</param>
        /// <returns>A string that describes the given principal variation.</returns>
        private String CreatePVString(Position position, Int32 depth, Int32 value)
        {
            List <Int32> pv          = GetCurrentPV();
            Boolean      isMate      = Math.Abs(value) > NearCheckmateValue;
            Int32        movesToMate = (CheckmateValue - Math.Abs(value) + 1) / 2;

            switch (Restrictions.Output)
            {
            // Return standard output.
            case OutputType.GUI:
                String depthString = depth.ToString();
                String valueString = isMate ? (value > 0 ? "+Mate " : "-Mate ") + movesToMate :
                                     (value / 100.0).ToString("+0.00;-0.00");
                String movesString = Stringify.MovesAlgebraically(position, pv);

                return(String.Format(PVFormat, depthString, valueString, movesString));

            // Return UCI output.
            case OutputType.UCI:
                String score = isMate ? "mate " + (value < 0 ? "-" : "") + movesToMate :
                               "cp " + value;
                Double elapsed = _stopwatch.Elapsed.TotalMilliseconds;
                Int64  nps     = (Int64)(1000 * _totalNodes / elapsed);

                return(String.Format("info depth {0} score {1} time {2} nodes {3} nps {4} pv {5}", depth, score, (Int32)elapsed, _totalNodes, nps, Stringify.Moves(pv)));
            }
            return(null);
        }
Esempio n. 2
0
 /// <summary>
 /// Returns a move to be played on the given position that has the given
 /// representation in coordinate notation.
 /// </summary>
 /// <param name="position">The position the move is to be played on.</param>
 /// <param name="name">The representation of the move in coordinate notation.</param>
 /// <returns>A move that has the given representation in coordinate notation.</returns>
 public static Int32 Create(Position position, String name)
 {
     foreach (Int32 move in position.LegalMoves())
     {
         if (name == Stringify.Move(move))
         {
             return(move);
         }
     }
     return(Invalid);
 }
Esempio n. 3
0
        /// <summary>
        /// Returns a text drawing of the position with the given comments displayed.
        /// </summary>
        /// <param name="comments">The comments to display.</param>
        /// <returns>A text drawing of the position with the given comments displayed</returns>
        public String ToString(params String[] comments)
        {
            StringBuilder sb    = new StringBuilder("   +------------------------+ ", 400);
            Int32         index = 0;

            if (index < comments.Length)
            {
                sb.Append(comments[index++]);
            }

            for (Int32 rank = 0; rank < 8; rank++)
            {
                sb.Append(Environment.NewLine);
                sb.Append(' ');
                sb.Append(8 - rank);
                sb.Append(" |");
                for (Int32 file = 0; file < 8; file++)
                {
                    Int32 piece = Square[file + rank * 8];
                    if (piece != Piece.Empty)
                    {
                        sb.Append((piece & Colour.Mask) == Colour.White ? '<' : '[');
                        sb.Append(Stringify.PieceInitial(piece));
                        sb.Append((piece & Colour.Mask) == Colour.White ? '>' : ']');
                    }
                    else
                    {
                        sb.Append((file + rank) % 2 == 1 ? ":::" : "   ");
                    }
                }
                sb.Append("| ");
                if (index < comments.Length)
                {
                    sb.Append(comments[index++]);
                }
            }

            sb.Append(Environment.NewLine);
            sb.Append("   +------------------------+ ");
            if (index < comments.Length)
            {
                sb.Append(comments[index++]);
            }

            sb.Append(Environment.NewLine);
            sb.Append("     a  b  c  d  e  f  g  h   ");
            if (index < comments.Length)
            {
                sb.Append(comments[index++]);
            }

            return(sb.ToString());
        }
Esempio n. 4
0
        /// <summary>
        /// Returns the PGN string of the game.
        /// </summary>
        /// <returns>The PGN string of the game.</returns>
        public String GetPGN()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("[Date \"" + _date + "\"]");
            sb.Append(Environment.NewLine);
            sb.Append("[White \"" + White.Name + "\"]");
            sb.Append(Environment.NewLine);
            sb.Append("[Black \"" + Black.Name + "\"]");
            sb.Append(Environment.NewLine);
            String result = "*";

            switch (_state)
            {
            case GameState.WhiteWon:
                result = "1-0";
                break;

            case GameState.BlackWon:
                result = "0-1";
                break;

            case GameState.Draw:
                result = "1/2-1/2";
                break;
            }
            sb.Append("[Result \"" + result + "\"]");
            sb.Append(Environment.NewLine);

            String initialFEN = _initialPosition.GetFEN();

            if (initialFEN != Position.StartingFEN)
            {
                sb.Append("[SetUp \"1\"]");
                sb.Append(Environment.NewLine);
                sb.Append("[FEN \"" + initialFEN + "\"]");
                sb.Append(Environment.NewLine);
            }

            sb.Append(Environment.NewLine);
            sb.Append(Stringify.MovesAlgebraically(_initialPosition, _moves, StringifyOptions.Proper));
            if (result != "*")
            {
                sb.Append(" " + result);
            }

            return(sb.ToString());
        }
Esempio n. 5
0
        /// <summary>
        /// Returns the text representation of the given move in coordinate notation.
        /// </summary>
        /// <param name="move">The move to identify.</param>
        /// <returns>The text representation of the given move in coordinate notation.</returns>
        public static String Move(Int32 move)
        {
            String coordinates = Stringify.Square(MoveClass.From(move)) + Stringify.Square(MoveClass.To(move));
            Int32  special     = MoveClass.Special(move);

            switch (special & PieceClass.Mask)
            {
            default:
                return(coordinates);

            case PieceClass.Queen:
            case PieceClass.Rook:
            case PieceClass.Bishop:
            case PieceClass.Knight:
                return(coordinates + PieceInitial(special).ToLowerInvariant());
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Performs divide on the given position with the given depth. This
        /// essentially performs perft on each of the positions arising from the
        /// legal moves for the given position. This method writes the results to
        /// the terminal.
        /// </summary>
        /// <param name="position">The position to perform divide on.</param>
        /// <param name="depth">The depth to perform divide with.</param>
        public static void Divide(Position position, Int32 depth)
        {
            const Int32 MoveWidth = 8;
            String      format    = "{0,-" + MoveWidth + "}{1}";

            Terminal.WriteLine(format, "Move", "Nodes");
            Terminal.WriteLine("-----------------------------------------------------------------------");

            List <Int32> moves      = position.LegalMoves();
            Int64        totalNodes = 0;

            foreach (Int32 move in moves)
            {
                position.Make(move);
                Int64 nodes = Nodes(position, depth - 1);
                position.Unmake(move);
                totalNodes += nodes;

                Terminal.WriteLine(format, Stringify.Move(move), nodes);
            }
            Terminal.WriteLine("-----------------------------------------------------------------------");
            Terminal.WriteLine("Moves: " + moves.Count);
            Terminal.WriteLine("Nodes: " + totalNodes);
        }
Esempio n. 7
0
        /// <summary>
        /// Begins the test with the given positions.
        /// </summary>
        /// <param name="epd">A list of positions in EPD format.</param>
        public static void Run(List <String> epd)
        {
            // Perform testing on a background thread.
            new Thread(new ThreadStart(() => {
                IEngine engine       = new Zero();
                Restrictions.Output  = OutputType.None;
                Int32 totalPositions = 0;
                Int32 totalSolved    = 0;
                Int64 totalNodes     = 0;
                Double totalTime     = 0;

                Terminal.WriteLine(ResultFormat, "Position", "Result", "Time", "Nodes");
                Terminal.WriteLine("-----------------------------------------------------------------------");

                foreach (String line in epd)
                {
                    List <String> terms = new List <String>(line.Replace(";", " ;").Split(' '));

                    // Strip everything to get the FEN.
                    Int32 bmIndex = line.IndexOf("bm ");
                    bmIndex       = bmIndex < 0 ? Int32.MaxValue : bmIndex;
                    Int32 amIndex = line.IndexOf("am ");
                    amIndex       = amIndex < 0 ? Int32.MaxValue : amIndex;
                    String fen    = line.Remove(Math.Min(bmIndex, amIndex));

                    // Get the best moves.
                    List <String> solutions = new List <String>();
                    for (Int32 i = terms.IndexOf("bm") + 1; i >= 0 && i < terms.Count && terms[i] != ";"; i++)
                    {
                        solutions.Add(terms[i]);
                    }

                    // Get the ID of the position.
                    Int32 idIndex = line.IndexOf("id ") + 3;
                    String id     = line.Substring(idIndex, line.IndexOf(';', idIndex) - idIndex).Replace(@"\", "");
                    if (id.Length > IDWidthLimit)
                    {
                        id = id.Remove(IDWidthLimit) + "..";
                    }

                    // Set the position and invoke a search on it.
                    Position position = new Position(fen);
                    VisualPosition.Set(position);
                    engine.Reset();

                    Stopwatch stopwatch = Stopwatch.StartNew();
                    Int32 move          = engine.GetMove(position);
                    stopwatch.Stop();

                    Double elapsed = stopwatch.Elapsed.TotalMilliseconds;
                    totalPositions++;
                    totalTime  += elapsed;
                    totalNodes += engine.Nodes;

                    // Determine whether the engine found a solution.
                    String result = "fail";
                    if (solutions.Contains(Stringify.MoveAlgebraically(position, move)))
                    {
                        result = "pass";
                        totalSolved++;
                    }

                    // Print the result for the search on the position.
                    Terminal.WriteLine(ResultFormat, id, result, String.Format("{0:0} ms", elapsed), engine.Nodes);
                }

                // Print final results after all positions have been searched.
                Terminal.WriteLine("-----------------------------------------------------------------------");
                Terminal.WriteLine("Result         {0} / {1}", totalSolved, totalPositions);
                Terminal.WriteLine("Time           {0:0} ms", totalTime);
                Terminal.WriteLine("Average nodes  {0:0}", (Double)totalNodes / totalPositions);
            }))
            {
                IsBackground = true
            }.Start();

            // Open the GUI window to draw positions.
            Application.Run(new Window());
        }
Esempio n. 8
0
        /// <summary>
        /// Returns the FEN string that describes the position.
        /// </summary>
        /// <returns>The FEN string that describes the position.</returns>
        public String GetFEN()
        {
            StringBuilder sb = new StringBuilder();

            for (Int32 rank = 0; rank < 8; rank++)
            {
                Int32 spaces = 0;
                for (Int32 file = 0; file < 8; file++)
                {
                    Int32 square = file + rank * 8;
                    if (Square[square] == Piece.Empty)
                    {
                        spaces++;
                    }
                    else
                    {
                        if (spaces > 0)
                        {
                            sb.Append(spaces);
                            spaces = 0;
                        }
                        String piece = Stringify.PieceInitial(Square[square]);
                        if ((Square[square] & Colour.Mask) == Colour.Black)
                        {
                            piece = piece.ToLowerInvariant();
                        }
                        sb.Append(piece);
                    }
                }
                if (spaces > 0)
                {
                    sb.Append(spaces);
                }
                if (rank < 7)
                {
                    sb.Append('/');
                }
            }

            sb.Append(' ');
            sb.Append(SideToMove == Colour.White ? 'w' : 'b');
            sb.Append(' ');

            if (CastleKingside[Colour.White] > 0)
            {
                sb.Append('K');
            }
            if (CastleQueenside[Colour.White] > 0)
            {
                sb.Append('Q');
            }
            if (CastleKingside[Colour.Black] > 0)
            {
                sb.Append('k');
            }
            if (CastleQueenside[Colour.Black] > 0)
            {
                sb.Append('q');
            }
            if (sb[sb.Length - 1] == ' ')
            {
                sb.Append('-');
            }
            sb.Append(' ');

            if (EnPassantSquare != InvalidSquare)
            {
                sb.Append(Stringify.Square(EnPassantSquare));
            }
            else
            {
                sb.Append('-');
            }
            sb.Append(' ');

            sb.Append(FiftyMovesClock);
            sb.Append(' ');
            sb.Append(HalfMoves / 2 + 1);

            return(sb.ToString());
        }
Esempio n. 9
0
        /// <summary>
        /// Starts play between the two players on the current position for the game.
        /// This method is non-blocking and does not modify the given position.
        /// </summary>
        /// <param name="p">The position to start playing from.</param>
        private void Play(Position p)
        {
            Position position = p.DeepClone();

            VisualPosition.Set(position);
            _state = GameState.Ingame;
            _waitForStop.Reset();

            new Thread(new ThreadStart(() => {
                while (true)
                {
                    IPlayer player          = (position.SideToMove == Colour.White) ? White : Black;
                    List <Int32> legalMoves = position.LegalMoves();

                    // Adjudicate checkmate and stalemate.
                    if (legalMoves.Count == 0)
                    {
                        if (position.InCheck(position.SideToMove))
                        {
                            _message = "Checkmate. " + Stringify.Colour(1 - position.SideToMove) + " wins!";
                            _state   = player.Equals(White) ? GameState.BlackWon : GameState.WhiteWon;
                        }
                        else
                        {
                            _message = "Stalemate. It's a draw!";
                            _state   = GameState.Draw;
                        }
                    }

                    // Adjudicate draw.
                    if (position.InsufficientMaterial())
                    {
                        _message = "Draw by insufficient material!";
                        _state   = GameState.Draw;
                    }
                    if (player is IEngine && player.AcceptsDraw)
                    {
                        if (position.FiftyMovesClock >= 100)
                        {
                            _message = "Draw by fifty-move rule!";
                            _state   = GameState.Draw;
                        }
                        if (position.HasRepeated(3))
                        {
                            _message = "Draw by threefold repetition!";
                            _state   = GameState.Draw;
                        }
                    }

                    // Consider game end.
                    if (_state != GameState.Ingame)
                    {
                        _waitForStop.Set();
                        return;
                    }

                    // Get move from player.
                    Position copy = position.DeepClone();
                    Int32 move    = player.GetMove(copy);
                    if (!position.Equals(copy))
                    {
                        Terminal.WriteLine("Board modified!");
                    }

                    // Consider game stop.
                    if (_state != GameState.Ingame)
                    {
                        _waitForStop.Set();
                        return;
                    }

                    // Make the move.
                    position.Make(move);
                    VisualPosition.Make(move);
                    _moves.Add(move);
                    _types.Add(player.GetType());
                }
            }))
            {
                IsBackground = true
            }.Start();
        }
Esempio n. 10
0
        /// <summary>
        /// Executes the parsing.
        /// </summary>
        public static void Run()
        {
            Restrictions.Output = OutputType.Universal;
            IEngine  engine   = new Zero();
            Position position = new Position(Position.StartingFEN);

            String command;

            while ((command = Console.ReadLine()) != null)
            {
                List <String> terms = new List <String>(command.Split(' '));

                switch (terms[0])
                {
                default:
                    Terminal.WriteLine("Unknown command: {0}", terms[0]);
                    Terminal.WriteLine("Enter \"help\" for assistance.");
                    break;

                case "uci":
                    Terminal.WriteLine("id name " + engine.Name);
                    Terminal.WriteLine("id author Zong Zheng Li");
                    Terminal.WriteLine("option name Hash type spin default " + Zero.DefaultHashAllocation + " min 1 max 2047");
                    Terminal.WriteLine("uciok");
                    break;

                case "ucinewgame":
                    engine.Reset();
                    break;

                case "setoption":
                    if (terms.Contains("Hash"))
                    {
                        engine.HashAllocation = Int32.Parse(terms[terms.IndexOf("value") + 1]);
                    }
                    break;

                case "position":
                    String fen = Position.StartingFEN;
                    if (terms[1] != "startpos")
                    {
                        fen = command.Substring(command.IndexOf("fen") + 4);
                    }
                    position = new Position(fen);

                    Int32 movesIndex = terms.IndexOf("moves");
                    if (movesIndex >= 0)
                    {
                        for (Int32 i = movesIndex + 1; i < terms.Count; i++)
                        {
                            position.Make(Move.Create(position, terms[i]));
                        }
                    }
                    break;

                case "go":
                    Restrictions.Reset();
                    for (Int32 i = 1; i < terms.Count; i++)
                    {
                        switch (terms[i])
                        {
                        default:
                        case "infinite":
                            break;

                        case "depth":
                            Restrictions.Depth           = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls = false;
                            break;

                        case "movetime":
                            Restrictions.MoveTime        = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls = false;
                            break;

                        case "wtime":
                            Restrictions.TimeControl[Colour.White] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls           = true;
                            break;

                        case "btime":
                            Restrictions.TimeControl[Colour.Black] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls           = true;
                            break;

                        case "winc":
                            Restrictions.TimeIncrement[Colour.White] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls             = true;
                            break;

                        case "binc":
                            Restrictions.TimeIncrement[Colour.Black] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls             = true;
                            break;

                        case "nodes":
                            Restrictions.Nodes           = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls = false;
                            break;

                        case "ponder":
                            // TODO: implement command.
                            break;

                        case "mate":
                            // TODO: implement command.
                            break;

                        case "movestogo":
                            // TODO: implement command.
                            break;
                        }
                    }
                    new Thread(new ThreadStart(() => {
                        Int32 bestMove = engine.GetMove(position);
                        Terminal.WriteLine("bestmove " + Stringify.Move(bestMove));
                    }))
                    {
                        IsBackground = true
                    }.Start();
                    break;

                case "stop":
                    engine.Stop();
                    break;

                case "isready":
                    Terminal.WriteLine("readyok");
                    break;

                case "quit":
                    return;

                case "perft":
                    Perft.Iterate(position, Int32.Parse(terms[1]));
                    break;

                case "divide":
                    Perft.Divide(position, Int32.Parse(terms[1]));
                    break;

                case "draw":
                    Terminal.WriteLine(position);
                    break;

                case "fen":
                    Terminal.WriteLine(position.GetFEN());
                    break;

                case "ponderhit":
                    // TODO: implement command.
                    break;

                case "register":
                    // TODO: implement command.
                    break;

                case "help":
                    Terminal.WriteLine("Command             Function");
                    Terminal.WriteLine("-----------------------------------------------------------------------");
                    Terminal.WriteLine("position [fen]      Sets the current position to the position denoted");
                    Terminal.WriteLine("                    by the given FEN. \"startpos\" is accepted for the");
                    Terminal.WriteLine("                    starting position");
                    Terminal.WriteLine("go [type] [number]  Searches the current position. Search types include");
                    Terminal.WriteLine("                    \"movetime\", \"depth\", \"nodes\", \"wtime\", \"btime\",");
                    Terminal.WriteLine("                    \"winc\", and \"binc\"");
                    Terminal.WriteLine("perft [number]      Runs perft() on the current position to the given");
                    Terminal.WriteLine("                    depth");
                    Terminal.WriteLine("divide [number]     Runs divide() on the current position for the given");
                    Terminal.WriteLine("                    depth");
                    Terminal.WriteLine("fen                 Prints the FEN of the current position.");
                    Terminal.WriteLine("draw                Draws the current position");
                    Terminal.WriteLine("stop                Stops an ongoing search");
                    Terminal.WriteLine("quit                Exits the application");
                    Terminal.WriteLine("-----------------------------------------------------------------------");
                    break;
                }
            }
        }