Example #1
0
 public void Init(MoveGen.Move move, Sprite sprite)
 {
     transform.localScale = Vector3.one;
     GetComponent<Image>().sprite = sprite;
     GetComponent<RectTransform>().anchoredPosition = new Vector2(200, 0);
     _move = move;
     _move.Used += _move_Used;
 }
 private void NewMoveGenerated(MoveGen.Move move)
 {
     var arrow = Instantiate(Prefab);
     arrow.transform.SetParent(transform, true);
     arrow.Init(move, ArrowsSprites[((int)move.Direction)]);
 }
Example #3
0
        private int AlphaBetaMin(int alpha, int beta, int depthLeft, int initialDepth)
        {
            if (depthLeft == 0)
            {
                int score = QuiescenceMin(alpha, beta, 0);
                return(score);
            }
            numNodes++;
            MoveGen.numNodes++;
            ulong currentKey = board.key;

            //draw by repetition
            if (initialDepth != depthLeft && AddPositionW(currentKey))
            {
                return(0);
            }
            //null move pruning
            if (depthLeft == initialDepth - 1 && !board.InCheck && !board.endGame)
            {
                //try null move
                board.MakeMove(-3, 0);
                int score = AlphaBetaMax(alpha, beta, 0, initialDepth);
                board.ReverseMove(-3, 0);
                //if null move causes cutoff, its assumed another move will also

                if (score <= alpha)
                {
                    RemPositionW(currentKey);
                    return(alpha);
                }
                if (score < beta)
                {
                    beta = score;
                }
            }

            //set up PV
            int PV            = 0;
            int nodeBestMove  = 0;
            int nodeBestScore = 0;

            if (ttpvb.ContainsKey(currentKey))
            {
                PV = ttpvb[currentKey];
            }
            foreach (int move in MoveGen.GenerateMove(board, false, PV))
            {
                //no PV
                if (move == 0)
                {
                    continue;
                }
                int captured = board.MakeMove(move, 0);
                int score    = AlphaBetaMax(alpha, beta, depthLeft - 1, initialDepth);
                board.ReverseMove(move, captured);
                if (nodeBestMove == 0 || nodeBestScore > score)
                {
                    nodeBestMove  = move;
                    nodeBestScore = score;
                }
                if (score <= alpha)
                {
                    if (initialDepth == depthLeft)
                    {
                        bestMove = move;
                    }
                    else
                    {
                        RemPositionW(currentKey);
                    }
                    UpdatePVB(currentKey, nodeBestMove);
                    if (score == int.MinValue)
                    {
                        return(score);
                    }
                    return(alpha);
                }
                if (score < beta)
                {
                    if (initialDepth == depthLeft)
                    {
                        inWindow = true;
                        bestMove = move;
                    }
                    beta = score;
                }
            }
            if (initialDepth != depthLeft)
            {
                RemPositionW(currentKey);
            }
            UpdatePVB(currentKey, nodeBestMove);
            //no legal moves
            if (nodeBestMove == 0)
            {
                if (board.InCheck)
                {
                    return(int.MaxValue);
                }
                else
                {
                    return(0);
                }
            }
            if (nodeBestScore == int.MaxValue)
            {
                return(int.MaxValue);
            }
            return(beta);
        }
 // Use this for initialization
 void Start()
 {
     _input = GetComponent<PlayerInput>();
     animator = GetComponent<Animator>();
     _generator = GetComponent<MoveGen>();
 }
Example #5
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)
                        {
                            // 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);
        }
Example #6
0
    // executes quiescence search
    public static int QSearch(int alpha, int beta, int player)
    {
        // initialize variables
        int value = SMALL_NUM, bestValue = SMALL_NUM;
        List <ChessMove> moves = new List <ChessMove>(0);

        if (player != AI.board.myColor)
        {
            bestValue = LARGE_NUM;
        }

        // check to see if we have time left
        if (AI.timer.ElapsedMilliseconds > TIME_PER_MOVE)
        {
            AI.TIME_EXPIRED = true;
            return(Score.TIME_EXPIRED_SCORE);
        }

        // check for draw by insufficient material
        if (Score.IsDrawByInsufficientMaterial())
        {
            return(Score.DRAW_SCORE);
        }

        // update evaluated node count
        AI.nodes++;

        // generate all capturing and promoting moves (all unquiet moves)
        moves = MoveGen.GenerateMoves(player, true);

        // iterate through generated moves
        for (int i = 0; i < moves.Count; i++)
        {
            // make current move
            moves[i].DoMove(MAKE);

            // if current move is illegal, unmake move; continue otherwise
            if (!MoveGen.IsKingAttacked(player))
            {
                // get value of next quiescence search recursion
                value = QSearch(alpha, beta, AI.GetOtherPlayer(player));

                // check to see if time has expired
                if (value == Score.TIME_EXPIRED_SCORE)
                {
                    return(Score.TIME_EXPIRED_SCORE);
                }

                // unmake current move
                moves[i].DoMove(UNMAKE);

                // evaluate quiescence search value
                if (player == AI.board.myColor) // maximize
                {
                    if (value >= beta)          // fail-high, prune
                    {
                        return(value + 1);
                    }
                    if (value > alpha) // set new alpha
                    {
                        alpha = value;
                    }
                    if (value > bestValue) // set new best action, best value
                    {
                        bestValue = value;
                    }
                }
                else if (player == AI.board.oppColor) // minimize
                {
                    if (value <= alpha)               // fail-low, prune
                    {
                        return(value - 1);
                    }
                    if (value < beta) // set new beta
                    {
                        beta = value;
                    }
                    if (value < bestValue) // set new best action, best value
                    {
                        bestValue = value;
                    }
                }
            }
            else
            {
                moves[i].DoMove(UNMAKE);
            }
        }

        // if no capturing or promoting moves for this state, set best value to node's heuristic value
        if (value == SMALL_NUM)
        {
            bestValue = Score.Evaluate(AI.board.myColor);
        }

        // return best value from the current depth
        return(bestValue);
    }
Example #7
0
        /// <summary>
        /// Search all capture positions, to help avoid the Horizon effect.
        /// </summary>
        private int Quiescence(int alpha, int beta, ref S_SearchInfo info)
        {
            Debug.Assert(BoardOperations.CheckBoard(board));

            if ((info.Nodes & 2047) == 0)
            {
                CheckUp(ref info);
            }

            info.Nodes++;

            // If position is a draw.
            if ((IsRepetition() || board.FiftyMoves >= 100) && board.Ply != 0)
            {
                return(0);
            }

            int score = Evaluate.Position(board); // Stand_pat.

            if (board.Ply > Variables.MAX_DEPTH - 1)
            {
                return(score);
            }

            if (score >= beta)
            {
                return(beta);
            }

            if (score > alpha)
            {
                alpha = score;
            }


            MoveList list = new MoveList();

            MoveGen.GenerateAllMoves(board, list, true); // Only capture moves

            int oldAlpha = alpha;

            score = -infinite;
            int legal    = 0; // Will increment when we find a legal move.
            int bestMove = Variables.NO_MOVE;
            int PvMove   = PvTable.Probe(board);

            for (int i = 0; i < list.Count; ++i)
            {
                PickNextMove(i, list);

                var move = list.Moves[i].Move;

                if (!MakeMove.Make_Move(board, move))
                {
                    continue;
                }

                legal++;
                score = -Quiescence(-beta, -alpha, ref info);
                MakeMove.TakeMove(board); // Take back the made move.

                if (info.Stopped)
                {
                    return(0);
                }

                // We have a new alpha or beta cutoff.
                if (score > alpha)
                {
                    bool isCaptureMove = (move & MoveOperations.MoveFlagCapture) != 0;
                    // beta cutoff?
                    if (score >= beta)
                    {
                        if (legal == 1)
                        {
                            info.Fhf++; // We searched the best move first.
                        }

                        info.Fh++;
                        return(beta);
                    }

                    // Alpha cutoff
                    alpha    = score;
                    bestMove = move;
                }
            }

            if (alpha != oldAlpha)
            {
                PvTable.StoreMove(board, bestMove);
            }

            return(alpha);
        }
Example #8
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
         {
             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
         {
             SystemHelper.println("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
         {
             SystemHelper.println("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.println("perft(" + depth.ToString() + ") = " +
                                  nodes.ToString() + " t=" + ((t1 - t0) / 1000).ToString() + "s");
         }
         catch
         {
             SystemHelper.println("Number format exception: " + moveStr);
             return(false);
         }
         return(true);
     }
     else
     {
         return(false);
     }
 }
Example #9
0
    /// <summary>
    /// Negamax alpha beta recursion.
    /// </summary>
    public int AlphaBeta(int alpha, int beta, int depth)
    {
        if (depth == 0)
        {
            return(Quiescence(alpha, beta, 63)); //Try to find calm position
        }

        NodesEvaluated++;

        //If there is repetition
        if (board.IsRepetition() || board.FiftyMove >= 100)
        {
            return(0);
        }

        //Check time
        CheckTime();

        //Have we run of time yet?
        if (RunOutOfTime)
        {
            return(0);
        }


        int OldAlpha       = alpha;
        int BestMove       = 0;
        int Score          = -5000000;
        int MadeALegalMove = 0;

        int add = depth * Defs.MaxMoves;
        int num = MoveGen.GenerateMoves(board, Moves, add, depth) + add;
        int move;

        //Score the move from previous search with the highest score - will be searched first
        int PvMove = board.ProbePVTable();

        if (PvMove != 0)
        {
            for (int i = add; i < num; i++)
            {
                if (Moves[i].move == PvMove)
                {
                    Moves[i].score = 2000000;
                }
            }
        }

        for (int i = add; i < num; i++)
        {
            PickBestMove(i, num);
            move = Moves[i].move;
            board.MakeMove(move);
            if (!board.MoveWasIllegal())
            {
                MadeALegalMove++;
                Score = -AlphaBeta(-beta, -alpha, depth - 1);
                board.UndoMove();

                if (Score > alpha)
                {
                    if (Score >= beta)
                    {
                        if (MadeALegalMove == 1)
                        {
                            FailHighFirst++;
                        }
                        FailHigh++;

                        if (!move.IsCapture())
                        {
                            //Not a capturing move
                            board.SearchKillers[1][depth] = board.SearchKillers[0][depth];
                            board.SearchKillers[0][depth] = move;
                        }

                        return(beta);
                    }

                    if (!move.IsCapture())
                    {
                        //Not a capturing move
                        board.SearchHistory[board.pieces[move.GetFrom()]][move.GetTo()] += depth;
                    }

                    alpha    = Score;
                    BestMove = move;
                }
            }
            else
            {
                board.UndoMove();
            }
        }


        //Check if mate
        if (MadeALegalMove == 0)
        {
            if (board.IsAttacked(board.BKing, 1))
            {
                //Mate
                if ((int)board.SideToPlay == 0) //Black
                {
                    return(-32767 - depth);
                }

                return(32767 + depth);
            }
            else if (board.IsAttacked(board.WKing, 0))
            {
                //Mate
                if ((int)board.SideToPlay == 0) //Black
                {
                    return(32767 + depth);
                }

                return(-32767 - depth);
            }
            else
            {
                //Stale mate
                return(0);
            }
        }

        //Store move
        if (alpha != OldAlpha)
        {
            board.StorePVMove(BestMove);
        }


        return(alpha);
    }
Example #10
0
    static string TestRandomGames(State state)
    {
        // run random game, check FEN
        var r = new Random(1234); // make repeatable

        for (int game = 0; game < 100; ++game)
        {
            state.Reset();
            for (int moveCount = 1; moveCount < 300; ++moveCount)
            {
                var moves1 = MoveGen.GenMoves(state);
                if (!moves1.Any())
                {
                    break;
                }

                // check can do/undo all
                var fs = state.ToFEN();
                foreach (var m in moves1)
                {
                    state.DoMove(m);
                    state.UndoMove();
                    var fe = state.ToFEN();
                    if (fe != fs)
                    {
                        return($"FEN mismatch trying move {m} \n{fs} != \n{fe}");
                    }
                }

                var move = moves1[r.Next(moves1.Count)];

                System.Console.WriteLine($"{(moveCount + 1) / 2}: {move:5}");

                // move do/undo checks
                var f1 = state.ToFEN();
                state.DoMove(move);
                var f2 = state.ToFEN();
                System.Console.WriteLine(f2);
                state.UndoMove();
                var f3 = state.ToFEN();
                state.DoMove(move);
                var f4 = state.ToFEN();

                if (f1 != f3)
                {
                    return($"FEN mismatch move {moveCount} : {move} \n{f1} != \n{f3}");
                }
                if (f2 != f4)
                {
                    return($"FEN mismatch move {moveCount} : {move} \n{f2} != \n{f4}");
                }

#if true
                // test FEN parsing
                State s2;
                if (!State.TryParseFEN(f1, out s2))
                {
                    return($"FEN parse failed {f1}");
                }
                var f5 = s2.ToFEN();
                if (f1 != f5)
                {
                    return($"FEN parse mismatch \n{f1} != \n{f5}");
                }
                var moves2 = MoveGen.GenMoves(s2);
                var mt1    = MoveGen.MoveListToText(moves1);
                var mt2    = MoveGen.MoveListToText(moves2);

                if (mt1 != mt2)
                {
                    return($"Move compare failed \n{mt1} != \n{mt2}\n{f1}==\n{f5}");
                }
#endif
                if (move.checkmate)
                {
                    Chess.Draw(state);
                }
            }
        }
        return("");
    }
Example #11
0
    // test perf counts from various positions
    public static bool PerfTests()
    {
#if false
        // for chasing down bugs. Compare to stockfish command line is useful
        State state2;
        State.TryParseFEN("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", out state2);
        State.TryParseFEN("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/5Q1p/PPPBBPPP/RN2K2R b KQkq - 0 1", out state2);
        State.TryParseFEN("r3k2r/p1ppqpb1/1n2pnp1/1b1PN3/1p2P3/5Q1p/PPPBBPPP/RN2K2R w KQkq - 0 1", out state2);
        //var mm = MoveGen.GenMoves(state2);

        MoveGen.Perft(state2, 2, true);
        return(true);
#endif

        var regex = new Regex(@"^D(\d+) (\d+)");
        var(errors, successes) = (0, 0);
        var filename = "data/perft.txt";
        foreach (var line1 in File.ReadLines(filename))
        {
            var line = line1;
            if (string.IsNullOrEmpty(line))
            {
                continue;
            }
            var index = line.IndexOf('#');
            if (index != -1)
            {
                line = line.Substring(0, index);
            }
            if (string.IsNullOrEmpty(line))
            {
                continue;
            }
            var words = line.Split(';', Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries);
            if (words.Length > 1 && State.TryParseFEN(words[0], out var state))
            {
                for (var i = 1; i < words.Length; ++i)
                {
                    var m = regex.Match(words[i].Trim());
                    if (
                        m.Success &&
                        Int32.TryParse(m.Groups[1].Value, out var depth) &&
                        UInt64.TryParse(m.Groups[2].Value, out var count)
                        )
                    {
                        if (depth > 5)
                        {
                            break;            // todo - allow
                        }
                        var pinfo  = PerftCount(state, depth);
                        var tested = pinfo.count;
                        if (tested != count)
                        {
                            Console.WriteLine($"ERROR: Me {tested} != Truth {count} depth {depth} FEN {words[0]}");
                            ++errors;
                        }
                        else
                        {
                            Console.WriteLine($"OK: {tested} == {count} depth {depth} FEN {words[0]}");
                            ++successes;
                        }
                        State.TryParseFEN(words[0], out state);
                    }
                }
            }
        }
        Console.WriteLine($"Perft testing {successes} successes, {errors} errors");
        return(errors == 0);
    }
Example #12
0
        public static void Test1()
        {
            Piece p = Piece.GOLD;

            Console.WriteLine(p.Pretty());
            Console.WriteLine(p.ToUsi());
            Piece p2 = Shogi.Core.Util.MakePiecePromote(Color.WHITE, p);

            Console.WriteLine(p2.ToUsi());

#if false
            // Squareのテスト
            Square sq = Square.SQ_56;
            //Console.WriteLine(sq.ToFile().ToUSI() + sq.ToRank().ToUSI());
            Console.WriteLine(sq.ToUsi());
            Console.WriteLine(sq.Pretty());
#endif

            Move m = Shogi.Core.Util.MakeMove(Square.SQ_56, Square.SQ_45);
            Console.WriteLine(m.ToUsi());

            Move m2 = Shogi.Core.Util.MakeMoveDrop(Piece.SILVER, Square.SQ_45);
            Console.WriteLine(m2.ToUsi());

            Move m3 = Shogi.Core.Util.MakeMovePromote(Square.SQ_84, Square.SQ_83);
            Console.WriteLine(m3.ToUsi());

            Move m4 = Shogi.Core.Util.FromUsiMove("8h2b+");
            Console.WriteLine(m4.Pretty());

            Move m5 = Shogi.Core.Util.FromUsiMove("G*3b");
            Console.WriteLine(m5.Pretty());

            Move m6 = Shogi.Core.Util.FromUsiMove("7g7f");

            Hand h = Hand.ZERO;
            h.Add(Piece.PAWN, 5);
            h.Add(Piece.KNIGHT, 1);
            Console.WriteLine(h.Pretty());
            Console.WriteLine(h.ToUsi(Color.BLACK));
            Console.WriteLine(h.ToUsi(Color.WHITE));

            var pos = new Position();
            //pos.UsiPositionCmd("startpos moves 7g7f 3c3d 8h3c+");

            pos.InitBoard(BoardType.NoHandicap);
            MoveGen.GenTest(pos);

            pos.UsiPositionCmd("sfen lnsgkgsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 moves 5a6b 7g7f 3a3b");

            Console.WriteLine(pos.Pretty());

#if false
            // UndoMove()のテスト
            pos.UndoMove();
            Console.WriteLine(pos.Pretty());

            pos.UndoMove();
            Console.WriteLine(pos.Pretty());

            pos.UndoMove();
            Console.WriteLine(pos.Pretty());
            Console.WriteLine(pos.PrettyPieceNo());
#endif

            // 駒番号のテスト
            //Console.WriteLine(pos.PrettyPieceNo());

            //  Console.WriteLine(pos.Pieces().Pretty());
            //  Console.WriteLine(pos.Pieces(Color.BLACK).Pretty());


#if false
            // Bitboard(Square)のテスト
            for (Square sq = Square.ZERO; sq < Square.NB; ++sq)
            {
                Console.WriteLine("sq = " + sq.Pretty());
                Bitboard b = new Bitboard(sq);
                Console.WriteLine(b.Pretty());
            }
#endif

#if false
            // 角・馬の利きのテスト
            Bitboard occupied = new Bitboard(Square.SQ_33);
            Console.WriteLine(occupied.Pretty());
            Bitboard bb = Bitboard.BishopEffect(Square.SQ_55, occupied);
            Console.WriteLine(bb.Pretty());

            Bitboard bb2 = Bitboard.BishopStepEffect(Square.SQ_56);
            Console.WriteLine(bb2.Pretty());

            Bitboard bb3 = Bitboard.BishopEffect(Square.SQ_56, Bitboard.AllBB());
            Console.WriteLine(bb3.Pretty());

            Bitboard bb4 = Bitboard.HorseEffect(Square.SQ_55, occupied);
            Console.WriteLine(bb4.Pretty());
#endif

#if false
            // 飛車・龍の利きのテスト
            Bitboard occupied = new Bitboard(Square.SQ_53);
            Console.WriteLine(occupied.Pretty());
            Bitboard bb = Bitboard.RookEffect(Square.SQ_55, occupied);
            Console.WriteLine(bb.Pretty());

            Bitboard bb2 = Bitboard.RookStepEffect(Square.SQ_56);
            Console.WriteLine(bb2.Pretty());

            Bitboard bb3 = Bitboard.RookEffect(Square.SQ_56, Bitboard.AllBB());
            Console.WriteLine(bb3.Pretty());

            Bitboard bb4 = Bitboard.DragonEffect(Square.SQ_55, occupied);
            Console.WriteLine(bb4.Pretty());
#endif

#if false
            // 香りの利きのテスト
            Bitboard occupied = new Bitboard(Square.SQ_53);
            Bitboard bb       = Bitboard.LanceEffect(Color.BLACK, Square.SQ_55, occupied);
            Console.WriteLine(bb.Pretty());

            Bitboard bb3 = Bitboard.LanceStepEffect(Color.BLACK, Square.SQ_56);
            Console.WriteLine(bb3.Pretty());
#endif

#if false
            // 歩、桂、銀、金、玉の利きのテスト
            Bitboard bb = Bitboard.PawnEffect(Color.BLACK, Square.SQ_55);
            Console.WriteLine(bb.Pretty());

            Bitboard bb2 = Bitboard.KnightEffect(Color.BLACK, Square.SQ_55);
            Console.WriteLine(bb2.Pretty());

            Bitboard bb3 = Bitboard.SilverEffect(Color.BLACK, Square.SQ_55);
            Console.WriteLine(bb3.Pretty());

            Bitboard bb4 = Bitboard.GoldEffect(Color.BLACK, Square.SQ_55);
            Console.WriteLine(bb4.Pretty());

            Bitboard bb5 = Bitboard.KingEffect(Square.SQ_55);
            Console.WriteLine(bb5.Pretty());
#endif

#if false
            // EffectsFrom()のテスト
            var bb = Bitboard.EffectsFrom(Piece.W_DRAGON, Square.SQ_54, pos.Pieces());
            Console.WriteLine(bb.Pretty());

            var bb2 = Bitboard.EffectsFrom(Piece.W_GOLD, Square.SQ_54, pos.Pieces());
            Console.WriteLine(bb2.Pretty());
#endif

#if false
            // BitboardのPop()のテスト
            for (Square sq = Square.ZERO; sq < Square.NB; ++sq)
            {
                Console.Write("sq = " + sq.Pretty() + " ");
                Bitboard b = new Bitboard(sq);
                Square   r = b.Pop();
                Console.WriteLine(r.Pretty());
            }
#endif

#if false
            // 駒落ちの局面のテスト
            pos.InitBoard(BoardType.Handicap2); // 2枚落ち
            Console.WriteLine(pos.Pretty());

            pos.InitBoard(BoardType.Handicap10); // 10枚落ち
            Console.WriteLine(pos.Pretty());
#endif

#if false
            pos.SetSfen(Position.SFEN_HIRATE);
            Console.WriteLine(pos.ToSfen());
            Console.WriteLine(pos.Pretty());
            pos.DoMove(m6);
            Console.WriteLine(pos.Pretty());
#endif

#if false
            // sfen化して、setしてhash keyが変わらないかのテスト
            //pos.SetSfen(pos.ToSfen());
            //Console.WriteLine(pos.Pretty());
#endif

#if false
            // 指し手生成祭りの局面
            pos.SetSfen("l6nl/5+P1gk/2np1S3/p1p4Pp/3P2Sp1/1PPb2P1P/P5GS1/R8/LN4bKL w RGgsn5p 1");
            Console.WriteLine(pos.ToSfen());
            Console.WriteLine(pos.Pretty());
#endif

#if false
            // 駒番号のデバッグ
            Console.WriteLine(pos.PrettyPieceNo());

            //            Console.WriteLine(pos.Pieces().Pretty());
            //           Console.WriteLine(pos.Pieces(Color.BLACK).Pretty());
#endif

#if false
            // BitweenBB()のテスト
            var bb = Bitboard.BetweenBB(Square.SQ_77, Square.SQ_33);
            Console.WriteLine(bb.Pretty());

            var bb2 = Bitboard.BetweenBB(Square.SQ_58, Square.SQ_52);
            Console.WriteLine(bb2.Pretty());
#endif

#if false
            // 乱数テスト
            var rand = new PRNG(1234);
            Console.WriteLine(rand.Rand());
            Console.WriteLine(rand.Rand());
            Console.WriteLine(rand.Rand());

            var key_side = Zobrist.Side;
            Console.WriteLine(key_side.ToString());
#endif

#if false
            // serialization test

            var csa        = new Model.CsaConnectData();
            var serializer = new DataContractJsonSerializer(typeof(Model.CsaConnectData));
            var ms         = new MemoryStream();
            serializer.WriteObject(ms, csa);
            var json = Encoding.UTF8.GetString(ms.ToArray());
            MessageBox.Show(json);
#endif

#if false
            // UsiPositionCmdのテスト。非合法手が混じっているパターン

            var pos2 = new Position();
            try
            {
                pos2.UsiPositionCmd("startpos moves 7g7f 3c4d 2g2f "); // 2手目が非合法手
            } catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
#endif

#if false
            {
                // 千日手の引き分けのテスト
                var pos2 = new Position();
                pos.UsiPositionCmd("startpos moves");

                var moves = new[] {
                    Util.MakeMove(Square.SQ_59, Square.SQ_58),
                    Util.MakeMove(Square.SQ_51, Square.SQ_52),
                    Util.MakeMove(Square.SQ_58, Square.SQ_59),
                    Util.MakeMove(Square.SQ_52, Square.SQ_51),
                };

                int ply = 0;
                for (int j = 0; j < 5; ++j)
                {
                    for (int i = 0; i < moves.Length; ++i)
                    {
                        pos.DoMove(moves[i]);
                        var rep = pos.IsRepetition();

                        ply++;
                        Console.WriteLine(string.Format("ply = {0} , rep = {1} ", ply, rep.ToString()));

                        // 16手目を指した局面(17手目)が先手番で千日手引き分けの局面になるはず
                    }
                }
            }
#endif

#if false
            {
                // 連続王手の千日手の負けのテスト
                var pos2 = new Position();
                pos.UsiPositionCmd("startpos moves 7g7f 5c5d 8h3c 5a6b");

                var moves = new[] {
                    Util.MakeMove(Square.SQ_33, Square.SQ_44),
                    Util.MakeMove(Square.SQ_62, Square.SQ_51),
                    Util.MakeMove(Square.SQ_44, Square.SQ_33),
                    Util.MakeMove(Square.SQ_51, Square.SQ_62),
                };

                int ply = 4;
                for (int j = 0; j < 5; ++j)
                {
                    for (int i = 0; i < moves.Length; ++i)
                    {
                        pos.DoMove(moves[i]);
                        //Console.WriteLine(pos.Pretty());
                        //Console.WriteLine(pos.State().checkersBB.Pretty());

                        var rep = pos.IsRepetition();

                        ply++;
                        Console.WriteLine(string.Format("ply = {0} , rep = {1} ", ply, rep.ToString()));

                        // 19手目の局面(を指した直後の局面=20手目,後手番)で、ここで後手勝ちになるはず。
                    }
                }
            }
#endif

#if false
            //  UndoMove()でcapture,promoteが戻るかのテスト
            var pos2 = new Position();
            pos2.UsiPositionCmd("startpos moves 7g7f 3c3d 8h2b+");
            Console.WriteLine(pos2.Pretty());
            pos2.UndoMove();
            Console.WriteLine(pos2.Pretty());
            pos2.UndoMove();
            Console.WriteLine(pos2.Pretty());
            pos2.UndoMove();
            Console.WriteLine(pos2.Pretty());
            Console.WriteLine(pos2.PrettyPieceNo());
#endif

#if true
            {
                // -- 局面の合法性のチェック

                // 平手
                pos.SetSfen("lnsgkgsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 先手2歩
                pos.SetSfen("lnsgkgsnl/9/9/P8/9/9/P8/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 後手2歩
                pos.SetSfen("lnsgkgsnl/9/8p/8p/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 玉なし
                pos.SetSfen("lnsg1gsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSG1GSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 片玉
                pos.SetSfen("lnsg1gsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 片玉(詰将棋時) これは合法
                pos.SetSfen("lnsg1gsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine("詰将棋片玉 : " + pos.IsValid(true));

                // 先手玉が2枚
                pos.SetSfen("lnsgKgsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 玉3枚
                pos.SetSfen("lnsgkksnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 非手番側に王手
                pos.SetSfen("lnsgkgsnl/9/ppppppBpp/9/9/9/PPPPPPPPP/25R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());

                // 行き場の無い駒
                pos.SetSfen("Lnsgkgsnl/9/pppppp1pp/9/9/9/PPPPPPPPP/25R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());
                pos.SetSfen("l1sgkgsnl/N8/pppppp1pp/9/9/9/PPPPPPPPP/25R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());
                pos.SetSfen("P1sgkgsnl/9/pppppp1pp/9/9/9/9/25R1/LNSGKGSNL b - 1");
                Console.WriteLine(pos.IsValid());
                pos.SetSfen("2sgkgsnl/9/9/9/9/9/9/25R1/LNSGKGSNp b - 1");
                Console.WriteLine(pos.IsValid());
            }
#endif
        }
Example #13
0
File: AI.CS Project: mhs294/Csharp
    //This function is called each time it is your turn
    //Return true to end your turn, return false to ask the server for updated information
    public override bool run()
    {
        // Print out the current board state
        Console.WriteLine("+---+---+---+---+---+---+---+---+");
        for (int rank = 8; rank > 0; rank--)
        {
            Console.Write("|");
            for (int file = 1; file <= 8; file++)
            {
                bool found = false;
                // Loops through all of the pieces
                for (int p = 0; !found && p < pieces.Length; p++)
                {
                    // determines if that piece is at the current rank and file
                    if (pieces[p].getRank() == rank && pieces[p].getFile() == file)
                    {
                        found = true;
                        // Checks if the piece is black
                        if (pieces[p].getOwner() == 1)
                        {
                            Console.Write("*");
                        }
                        else
                        {
                            Console.Write(" ");
                        }
                        // prints the piece's type
                        Console.Write((char)pieces[p].getType() + " ");
                    }
                }
                if (!found)
                {
                    Console.Write("   ");
                }
                Console.Write("|");
            }
            Console.WriteLine("\n+---+---+---+---+---+---+---+---+");
        }

        // Looks through information about the players
        for (int p = 0; p < players.Length; p++)
        {
            Console.Write(players[p].getPlayerName());
            // if playerID is 0, you're white, if its 1, you're black
            if (players[p].getId() == myID)
            {
                Console.Write(" (ME)");

                // update timeRemaining
                timeRemaining = players[p].getTime();
            }
            Console.WriteLine(" time remaining: " + players[p].getTime());
        }

        // if there has been a move, print the most recent move
        if (moves.Length > 0)
        {
            Console.Write("Last Move Was: ");
            Console.WriteLine(files[moves[0].getFromFile() - 1] + "" + moves[0].getFromRank() + "-" + files[moves[0].getToFile() - 1] + "" + moves[0].getToRank());
        }

        /////////////////////////////////////
        // <-- END OF STOCK AI.cs CODE --> //
        /////////////////////////////////////

        // print current move number
        Console.WriteLine("\nMove " + turnNumber().ToString("D3") + "\n========\n");

        // add to GameState List and update ChessBoard
        if (moves.Length <= 1)
        {
            board = new ChessBoard(ref pieces, myID);
            states.Add(new GameState(null, null));
        }
        else
        {
            ChessMove lastMove = ChessMove.GetChessMove(moves[0].getFromFile(), moves[0].getToFile(), moves[0].getFromRank(), moves[0].getToRank(),
                                                        moves[0].getPromoteType(), states[states.Count - 1].enPassant);
            board = new ChessBoard(ref pieces, myID);
            states.Add(new GameState(states[states.Count - 1], lastMove));
        }

        // display current score information for player
        Console.Write("Score for ");
        if (myID == ChessBoard.WHITE)
        {
            Console.WriteLine("WHITE:\n");
        }
        else if (myID == ChessBoard.BLACK)
        {
            Console.WriteLine("BLACK:\n");
        }
        int material = Score.GetMaterialScore(myID);
        int position = Score.GetPositionScore(myID);
        // int mobility = Score.GetPositionScore(myID);
        int pawn_structure = Score.GetPawnStructureScore(myID);
        int king_safety    = Score.GetKingSafetyScore(myID);

        Console.WriteLine("Net Material = " + material);
        Console.WriteLine("Net Position = " + position);
        //Console.WriteLine("Net Mobility = " + mobility);
        Console.WriteLine("Net Pawn Structure = " + pawn_structure);
        Console.WriteLine("Net King Safety = " + king_safety + "\n");
        Console.WriteLine("Overall Score = " + (material + position + /*mobility +*/ pawn_structure + king_safety) + "\n");

        // if playing as human, get move from console prompt
        while (HUMAN_PLAYER)
        {
            // get legal moves for this position
            List <ChessMove> legalMoves = MoveGen.GenerateMoves(myID, false);

            // prompt user for move
            Console.Write("Enter a move ([from] [to] <promotion type>): ");
            string[] humanMove = Console.ReadLine().Split(' ');

            // get origin square
            int humanFromFile = 0, humanFromRank = 0;
            for (int i = 0; i < 8; i++)
            {
                if (humanMove[0][0] == files[i])
                {
                    humanFromFile = i + 1;
                    break;
                }
            }
            humanFromRank = (int)Char.GetNumericValue(humanMove[0][1]);

            // get destination square
            int humanToFile = 0, humanToRank = 0;
            for (int i = 0; i < 8; i++)
            {
                if (humanMove[1][0] == files[i])
                {
                    humanToFile = i + 1;
                    break;
                }
            }
            humanToRank = (int)Char.GetNumericValue(humanMove[1][1]);

            // if promotion type is specified, get the promotion piece from move
            int humanPromote = 0;
            if (humanMove.Length > 2)
            {
                humanPromote = (int)humanMove[2][0];
            }

            // check for legality of human move
            bool isLegal = false;
            for (int i = 0; i < legalMoves.Count; i++)
            {
                ChessMove m = legalMoves[i];
                if ((ChessMove.GetFile(m.GetFromSq()) + 1) == (uint)humanFromFile &&
                    (ChessMove.GetRank(m.GetFromSq()) + 1) == (uint)humanFromRank &&
                    (ChessMove.GetFile(m.GetToSq()) + 1) == (uint)humanToFile &&
                    (ChessMove.GetRank(m.GetToSq()) + 1) == (uint)humanToRank)
                {
                    isLegal = true;
                    break;
                }
            }

            // if move is legal, make move
            if (isLegal)
            {
                // get Piece associated with move
                Piece humanPiece = pieces[FindPiece(humanFromFile, humanFromRank)];

                // make move
                humanPiece.move(humanToFile, humanToRank, humanPromote);
                return(true);
            }
            else if (!isLegal)
            {
                Console.WriteLine("ILLEGAL MOVE. Please input a legal move.\n");
            }
        }

        // reset TIME_EXPIRED and timer
        TIME_EXPIRED = false;
        timer.Reset();

        // reset history table
        history = new HistoryTable();

        // run ABMiniMax
        int  moveScore = 0, n = 0, toFile = -1, toRank = -1;
        uint fromSq = 0, toSq = 0, thePiece = 0;

        depth = 0;
        List <ChessMove> completeBestMoves = new List <ChessMove>(0);

        Search.UpdateTimePerMove(moves.Length);
        timer.Start();
        while (!TIME_EXPIRED)
        {
            depth                  += 1;
            nodes                   = 0;
            Search.MAX_DEPTH        = depth;
            Search.NULLMOVE_ALLOWED = true;
            Search.FOLLOW_PV        = true;
            Search.PV               = new List <ChessMove>(0);
            int score = Search.PVABMiniMax(0, Search.SMALL_NUM, Search.LARGE_NUM);
            if (score != Score.TIME_EXPIRED_SCORE)
            {
                moveScore         = score;
                completeBestMoves = new List <ChessMove>(Search.PV);
            }

            // select random move from bestMoves List
            if (completeBestMoves.Count > 0)
            {
                n = generator.Next(0, completeBestMoves.Count - 1);

                // get bestMove info
                fromSq   = completeBestMoves[n].GetFromSq();
                thePiece = completeBestMoves[n].GetPiece();
                toSq     = completeBestMoves[n].GetToSq();
                toFile   = (int)((toSq % 8) + 1);
                toRank   = (int)((toSq / 8) + 1);

                // print bestMove info
                Console.WriteLine("Best Move: " + completeBestMoves[n].GetMoveString() + ", Score: " + moveScore + ", Depth: " + depth + " (t = " +
                                  (timer.ElapsedMilliseconds / 1000.0).ToString("F3") + "s, nodes = " + nodes + ")");
            }

            // if checkmate is found, stop searching
            if (score == Score.CHECKMATE_WIN_SCORE)
            {
                break;
            }
        }
        timer.Stop();

        // output number of best moves
        Console.WriteLine("completeBestMoves = " + completeBestMoves.Count);

        // make bestMove
        pieces[FindPiece(fromSq, thePiece)].move(toFile, toRank, completeBestMoves[n].GetPromoteType());

        // update ChessBoard and GameState List
        completeBestMoves[n].DoMove(Search.MAKE);

        return(true);
    }
Example #14
0
        /// <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);
        }
Example #15
0
    // returns the position score for the specified color
    public static int GetPositionScore(int player)
    {
        // initialize variables
        int  white_position = 0, black_position = 0, net_position = 0;
        uint white_king_sq = MoveGen.GetNextSquare(AI.board.white_king);
        uint black_king_sq = MoveGen.GetNextSquare(AI.board.black_king);

        // loop through game AI.board squares and calculate position/distance scores for each piece
        for (int i = 0; i < 64; i++)
        {
            if (AI.board.theBoard[i] == ChessBoard.EMPTY)
            {
                continue;                                     // square is empty
            }
            if (ChessBoard.GetPieceColor(AI.board.theBoard[i]) == ChessBoard.WHITE)
            {
                switch (AI.board.theBoard[i])
                {
                case ChessBoard.W_PAWN:
                    white_position += PAWN_POSITION[i];
                    white_position += PAWN_OPPONENT_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(black_king_sq)),
                                                                      Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(black_king_sq)))];
                    white_position += PAWN_OWN_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(white_king_sq)),
                                                                 Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(white_king_sq)))];
                    break;

                case ChessBoard.W_ROOK:
                    white_position += ROOK_POSITION[i];
                    white_position += ROOK_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(black_king_sq)),
                                                             Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(black_king_sq)))];
                    break;

                case ChessBoard.W_KNIGHT:
                    white_position += KNIGHT_POSITION[i];
                    white_position += KNIGHT_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(black_king_sq)),
                                                               Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(black_king_sq)))];
                    break;

                case ChessBoard.W_BISHOP:
                    white_position += BISHOP_POSITION[i];
                    white_position += BISHOP_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(black_king_sq)),
                                                               Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(black_king_sq)))];
                    break;

                case ChessBoard.W_QUEEN:
                    white_position += QUEEN_POSITION[i];
                    white_position += QUEEN_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(black_king_sq)),
                                                              Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(black_king_sq)))];
                    break;

                case ChessBoard.W_KING:
                    if (IsEndGame(GetMaterialScore(ChessBoard.WHITE), GetMaterialScore(ChessBoard.BLACK)))
                    {
                        white_position += KING_ENDGAME_POSITION[i];
                    }
                    else
                    {
                        white_position += KING_POSITION[i];
                    }
                    break;
                }
            }
            else if (ChessBoard.GetPieceColor(AI.board.theBoard[i]) == ChessBoard.BLACK)
            {
                switch (AI.board.theBoard[i])
                {
                case ChessBoard.B_PAWN:
                    black_position += PAWN_POSITION[MIRROR[i]];
                    black_position += PAWN_OPPONENT_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(white_king_sq)),
                                                                      Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(white_king_sq)))];
                    black_position += PAWN_OWN_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(black_king_sq)),
                                                                 Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(black_king_sq)))];
                    break;

                case ChessBoard.B_ROOK:
                    black_position += ROOK_POSITION[MIRROR[i]];
                    black_position += ROOK_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(white_king_sq)),
                                                             Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(white_king_sq)))];
                    break;

                case ChessBoard.B_KNIGHT:
                    black_position += KNIGHT_POSITION[MIRROR[i]];
                    black_position += KNIGHT_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(white_king_sq)),
                                                               Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(white_king_sq)))];
                    break;

                case ChessBoard.B_BISHOP:
                    black_position += BISHOP_POSITION[MIRROR[i]];
                    black_position += BISHOP_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(white_king_sq)),
                                                               Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(white_king_sq)))];
                    break;

                case ChessBoard.B_QUEEN:
                    black_position += QUEEN_POSITION[MIRROR[i]];
                    black_position += QUEEN_DISTANCE[Math.Min(Math.Abs((int)ChessMove.GetFile((uint)i) - (int)ChessMove.GetFile(white_king_sq)),
                                                              Math.Abs((int)ChessMove.GetRank((uint)i) - (int)ChessMove.GetRank(white_king_sq)))];
                    break;

                case ChessBoard.B_KING:
                    if (IsEndGame(GetMaterialScore(ChessBoard.WHITE), GetMaterialScore(ChessBoard.BLACK)))
                    {
                        black_position += KING_ENDGAME_POSITION[MIRROR[i]];
                    }
                    else
                    {
                        black_position += KING_POSITION[MIRROR[i]];
                    }
                    break;
                }
            }
        }

        // calculate net position score
        if (player == ChessBoard.WHITE)
        {
            net_position += white_position - black_position;
        }
        else if (player == ChessBoard.BLACK)
        {
            net_position += black_position - white_position;
        }

        // return position score
        return(net_position);
    }
Example #16
0
    /// <summary>
    /// Searches only capturing moves.
    /// </summary>
    public int Quiescence(int alpha, int beta, int depth)
    {
        int Score = (Evaluation.Evaluate(board) * ((board.SideToPlay * 2) - 1));

        QNodes++;

        CheckTime();

        if (RunOutOfTime)
        {
            return(0);
        }

        if (Score >= beta)
        {
            return(beta);
        }

        if (Score > alpha)
        {
            alpha = Score;
        }

        if (depth <= 21)   //Should not happen, but it's here anyway
        {
            return(Score);
        }


        int MadeALegalMove = 0;

        Score = -5000000;

        int add = depth * Defs.MaxMoves;
        int num = MoveGen.GenerateCapturingMoves(board, Moves, add) + add; //Generates only capturing moves
        int move;

        for (int i = add; i < num; i++)
        {
            PickBestMove(i, num);
            move = Moves[i].move;

            board.MakeMove(move);
            if (!board.MoveWasIllegal())
            {
                MadeALegalMove++;
                Score = -Quiescence(-beta, -alpha, depth - 1);

                if (Score > alpha)
                {
                    if (Score >= beta)
                    {
                        if (MadeALegalMove == 1)
                        {
                            FailHighFirst++;
                        }
                        FailHigh++;

                        board.UndoMove();
                        return(beta);
                    }

                    alpha = Score;
                }
            }
            board.UndoMove();
        }


        return(alpha);
    }
Example #17
0
    // returns the pawn structure score for the specified color
    public static int GetPawnStructureScore(int player)
    {
        // initialize variables
        int    white_pawn_structure = 0, black_pawn_structure = 0, net_pawn_structure = 0;
        UInt64 white_pawns = AI.board.white_pawn, black_pawns = AI.board.black_pawn;

        // calculate white pawn structure score
        while (white_pawns != ChessBoard.EMPTY_BOARD)
        {
            // get square of next pawn
            uint square = MoveGen.GetNextSquare(white_pawns);

            // check to see if pawn is a passed pawn
            if ((W_PASSED_PAWN[square] & AI.board.black_pawn) == ChessBoard.EMPTY_BOARD)
            {
                white_pawn_structure += BONUS_PASSED_PAWN;

                // check to see if rook is behind a passed pawn
                if ((MoveGen.GetRookMoves(square, AI.board.occupied_squares, AI.board.occupied_squares) ^ AI.board.white_rook) != ChessBoard.EMPTY_BOARD)
                {
                    white_pawn_structure += BONUS_ROOK_BEHIND_PASSED_PAWN;
                }
            }

            // check to see if pawn is a doubled pawn
            if (((ChessBoard.UP_MOVES[square] | ChessBoard.DOWN_MOVES[square]) ^ ChessBoard.SQUARES[square]) != 0)
            {
                white_pawn_structure += PENALTY_DOUBLED_PAWN;
            }

            // check to see if pawn is an isolated pawn (if not isolated, check to see if pawn is a backward pawn)
            if ((W_ISOLATED_PAWN[square] & AI.board.white_pawn) == ChessBoard.EMPTY_BOARD)
            {
                white_pawn_structure += PENALTY_ISOLATED_PAWN;
            }
            else
            {
                if (((ChessBoard.PAWN_CAPTURES[square + 8] & AI.board.black_pawn) != ChessBoard.EMPTY_BOARD) &&
                    (W_BACKWARD_PAWN[square] & AI.board.white_pawn) == ChessBoard.EMPTY_BOARD)
                {
                    white_pawn_structure += PENALTY_BACKWARD_PAWN;
                }
            }

            // remove current pawn from white pawns BitBoard
            white_pawns ^= ChessBoard.SQUARES[square];
        }

        // calculate black pawn structure score
        while (black_pawns != ChessBoard.EMPTY_BOARD)
        {
            // get square of next pawn
            uint square = MoveGen.GetNextSquare(black_pawns);

            // check to see if pawn is a passed pawn
            if ((B_PASSED_PAWN[square] & AI.board.white_pawn) == ChessBoard.EMPTY_BOARD)
            {
                black_pawn_structure += BONUS_PASSED_PAWN;

                // check to see if rook is behind a passed pawn
                if ((MoveGen.GetRookMoves(square, AI.board.occupied_squares, AI.board.occupied_squares) ^ AI.board.black_rook) != ChessBoard.EMPTY_BOARD)
                {
                    black_pawn_structure += BONUS_ROOK_BEHIND_PASSED_PAWN;
                }
            }

            // check to see if pawn is a doubled pawn
            if (((ChessBoard.UP_MOVES[square] | ChessBoard.DOWN_MOVES[square]) ^ ChessBoard.SQUARES[square]) != 0)
            {
                black_pawn_structure += PENALTY_DOUBLED_PAWN;
            }

            // check to see if pawn is an isolated pawn (if not isolated, check to see if pawn is a backward pawn)
            if ((B_ISOLATED_PAWN[square] & AI.board.black_pawn) == ChessBoard.EMPTY_BOARD)
            {
                black_pawn_structure += PENALTY_ISOLATED_PAWN;
            }
            else
            {
                if (((ChessBoard.PAWN_CAPTURES[square - 8] & AI.board.white_pawn) != ChessBoard.EMPTY_BOARD) &&
                    (B_BACKWARD_PAWN[square] & AI.board.black_pawn) == ChessBoard.EMPTY_BOARD)
                {
                    black_pawn_structure += PENALTY_BACKWARD_PAWN;
                }
            }

            // remove current pawn from black pawns BitBoard
            black_pawns ^= ChessBoard.SQUARES[square];
        }

        // calculate net pawn structure score
        if (player == ChessBoard.WHITE)
        {
            net_pawn_structure += white_pawn_structure - black_pawn_structure;
        }
        else if (player == ChessBoard.BLACK)
        {
            net_pawn_structure += black_pawn_structure - white_pawn_structure;
        }

        // return pawn structure score
        return(net_pawn_structure);
    }
Example #18
0
        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.println("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);
        }
Example #19
0
        public int AlphaBeta(int alpha, int beta, int depth, ref S_SearchInfo info, bool DoNull)
        {
            Debug.Assert(BoardOperations.CheckBoard(board));

            if (depth == 0)
            {
                return(Quiescence(alpha, beta, ref info));
            }

            if ((info.Nodes & 2047) == 0)
            {
                CheckUp(ref info);
            }

            info.Nodes++;

            // If position is a draw.
            if ((IsRepetition() || board.FiftyMoves >= 100) && board.Ply != 0)
            {
                return(0);
            }

            if (board.Ply > Variables.MAX_DEPTH - 1)
            {
                return(Evaluate.Position(board));
            }

            bool kingInCheck = Attack.IsSqAttacked(board.KingSq[board.Side], board.Side ^ 1, board);

            // If king is in check, search deeper to get out of check.
            if (kingInCheck)
            {
                depth++;
                // The two following lines are possibly ERROR.
                long timeInc = (info.StopTime - info.StartTime) * (1 / 2);
                info.StopTime += timeInc;
            }

            MoveList list = new MoveList();

            MoveGen.GenerateAllMoves(board, list, false);
            int oldAlpha = alpha;
            int score    = -infinite;
            int legal    = 0; // Will increment when we find a legal move.
            int bestMove = Variables.NO_MOVE;
            int PvMove   = PvTable.Probe(board);

            // Prioritize Principle Variation move if it's found.
            if (PvMove != Variables.NO_MOVE)
            {
                for (int i = 0; i < list.Count; ++i)
                {
                    var move = list.Moves[i].Move;
                    if (move == PvMove)
                    {
                        list.Moves[i].Score = 2000000;
                        break;
                    }
                }
            }

            for (int i = 0; i < list.Count; ++i)
            {
                PickNextMove(i, list);

                var move = list.Moves[i].Move;
                if (!MakeMove.Make_Move(board, move))
                {
                    continue;
                }

                legal++;
                score = -AlphaBeta(-beta, -alpha, depth - 1, ref info, true);
                MakeMove.TakeMove(board); // Take back the made move.

                if (info.Stopped)
                {
                    return(0); // Back up to the root if times up.
                }

                // We have a new alpha or beta cutoff.
                if (score > alpha)
                {
                    bool isCaptureMove = (move & MoveOperations.MoveFlagCapture) != 0;
                    // beta cutoff?
                    if (score >= beta)
                    {
                        if (legal == 1)
                        {
                            info.Fhf++; // We searched the best move first.
                        }

                        info.Fh++;

                        // If beta cutoff, but no capture move.
                        if (!isCaptureMove)
                        {
                            board.SearchKillers[1, board.Ply] = board.SearchKillers[0, board.Ply];
                            board.SearchKillers[0, board.Ply] = move;
                        }
                        return(beta);
                    }

                    // Alpha cutoff
                    alpha    = score;
                    bestMove = move;

                    if (!isCaptureMove)
                    {
                        int from = MoveOperations.FromSq(move);
                        int to   = MoveOperations.ToSq(move);
                        board.SearchHistory[board[from], to] += depth; // Prioritizes move near the root of the tree.
                    }
                }
            }

            // If we haven't had any legal moves.
            if (legal == 0)
            {
                // If in check with no legal moves checkmate.
                if (kingInCheck)
                {
                    return(-mate + board.Ply); // Return the amount of moves it takes to mate.
                    // Returning in this way, allows the method to "prefer" the fastest checkmate combination.
                }
                else
                {
                    return(0); // Stalemate.
                }
            }

            if (alpha != oldAlpha)
            {
                PvTable.StoreMove(board, bestMove);
            }

            return(alpha);
        }
Example #20
0
        /// <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);
        }
Example #21
0
    // executes time-limited alpha/beta pruning depth-limited MiniMax search
    public static int PVABMiniMax(int depth, int alpha, int beta)
    {
        // initialize principal variant flag
        bool pvfound = false;

        // update evaluated node count
        AI.nodes++;

        // check to see if we have time left
        if (AI.timer.ElapsedMilliseconds > TIME_PER_MOVE)
        {
            AI.TIME_EXPIRED = true;
            return(Score.TIME_EXPIRED_SCORE);
        }

        // initialize variables
        List <ChessMove> moves = new List <ChessMove>(0);
        ChessMove        bestAction = new ChessMove();
        int value = SMALL_NUM, bestValue = SMALL_NUM, color = -1;

        if (depth % 2 != 0)
        {
            bestValue = LARGE_NUM;
        }

        // check for draws
        if (Score.IsDrawByHundredMoves()) // 100 move draw; update history table
        {
            return(Score.DRAW_SCORE);
        }
        if (Score.IsDrawByRepetition()) // repitition draw
        {
            return(Score.DRAW_SCORE);
        }
        if (Score.IsDrawByInsufficientMaterial()) // insufficient material draw
        {
            return(Score.DRAW_SCORE);
        }

        // set color of current player
        if (depth % 2 == 0)
        {
            color = AI.board.myColor;
        }
        else
        {
            color = AI.board.oppColor;
        }

        // if depth limit has been reached, return quiescence search value for this node
        if (depth >= MAX_DEPTH)
        {
            // set follow pv flag
            FOLLOW_PV = false;

            // go one node deeper if player to move is currently in check
            if (MoveGen.IsKingAttacked(color))
            {
                MAX_DEPTH++;
                value = PVABMiniMax(depth, alpha, beta);
                MAX_DEPTH--;
                return(value);
            }

            // return quiescence search value
            return(QSearch(alpha, beta, color));
        }

        // if allowed, try a null move to get an early prune
        if (NULLMOVE_ALLOWED && !FOLLOW_PV)
        {
            // if game could be in zugzwang for player to move or player to move is in check, do not attempt null move
            if (((color == ChessBoard.WHITE && Score.GetMaterialScore(color) > Score.NULLMOVE_LIMIT_SCORE) ||
                 (color == ChessBoard.BLACK && Score.GetMaterialScore(color) > Score.NULLMOVE_LIMIT_SCORE)) &&
                !MoveGen.IsKingAttacked(color))
            {
                // set allow null move flag
                NULLMOVE_ALLOWED = false;

                // if we are next player to move, run zero-window search for alpha; else use beta
                if (color == AI.board.oppColor)
                {
                    value = PVABMiniMax(depth + NULLMOVE_DEPTH_GAP, alpha, alpha + 1);
                }
                else if (color == AI.board.myColor)
                {
                    value = PVABMiniMax(depth + NULLMOVE_DEPTH_GAP, beta, beta + 1);
                }

                // reset allow null move flag
                NULLMOVE_ALLOWED = true;

                // if alpha/beta was not improved, prune
                if (color == AI.board.myColor && value >= beta)
                {
                    return(value);
                }
                else if (color == AI.board.oppColor && value <= alpha)
                {
                    return(value);
                }
            }
        }
        NULLMOVE_ALLOWED = true;

        // generate moves for player based on depth
        moves = MoveGen.GenerateMoves(color, false);

        // iterate through generated moves
        for (int i = 0; i < moves.Count; i++)
        {
            // order remaining moves according to history table
            AI.history.OrderMoves(ref moves, color, i);

            // make current move
            moves[i].DoMove(MAKE);

            // if move is illegal, unmake move; continue otherwise
            if (!MoveGen.IsKingAttacked(color))
            {
                // if principal variant flag is set, run zero-window search; else, run normal search
                if (pvfound)
                {
                    // if we are next player to move, use alpha for zero-window search; else, use beta
                    if (depth % 2 != 0)
                    {
                        value = PVABMiniMax(depth + 1, alpha, alpha + 1);
                    }
                    else if (depth % 2 == 0)
                    {
                        value = PVABMiniMax(depth + 1, beta, beta + 1);
                    }

                    // if value returned falls within alpha/beta window, run normal search with normal alpha/beta window
                    if (value > alpha && value < beta)
                    {
                        value = PVABMiniMax(depth + 1, alpha, beta);
                    }
                }
                else
                {
                    value = PVABMiniMax(depth + 1, alpha, beta);
                }

                // unmake current move
                moves[i].DoMove(UNMAKE);

                // check to see if search found checkmate
                if (value == Score.CHECKMATE_WIN_SCORE && depth == 0)
                {
                    // update PV
                    PV.Clear();
                    PV.Add(moves[i]);

                    // return checkmate score
                    return(Score.CHECKMATE_WIN_SCORE);
                }

                // check to see if time has expired
                if (value == Score.TIME_EXPIRED_SCORE)
                {
                    return(Score.TIME_EXPIRED_SCORE);
                }

                // evaluate minimax search value
                if (depth % 2 == 0)    // maximize
                {
                    if (value >= beta) // fail-high, prune; update history table
                    {
                        if (color == ChessBoard.WHITE)
                        {
                            AI.history.whiteValue[moves[i].GetFromSq()][moves[i].GetToSq()] += (MAX_DEPTH - depth) * (MAX_DEPTH - depth);
                        }
                        else if (color == ChessBoard.BLACK)
                        {
                            AI.history.blackValue[moves[i].GetFromSq()][moves[i].GetToSq()] += (MAX_DEPTH - depth) * (MAX_DEPTH - depth);
                        }
                        return(value + 1);
                    }
                    if (value > alpha) // set new alpha, set principal variant flag
                    {
                        alpha   = value;
                        pvfound = true;
                    }
                    if (value >= bestValue)             // set new best action, best value
                    {
                        // if alpha improves at root, update PV
                        if (depth == 0 && value > bestValue)
                        {
                            PV.Clear();
                            PV.Add(moves[i]);
                        }
                        else if (depth == 0 && value == bestValue)
                        {
                            PV.Add(moves[i]);
                        }

                        bestAction = moves[i];
                        bestValue  = value;
                    }
                }
                else if (depth % 2 == 1) // minimize
                {
                    if (value <= alpha)  // fail-low, prune; update history table
                    {
                        if (color == ChessBoard.WHITE)
                        {
                            AI.history.whiteValue[moves[i].GetFromSq()][moves[i].GetToSq()] += (MAX_DEPTH - depth) * (MAX_DEPTH - depth);
                        }
                        else if (color == ChessBoard.BLACK)
                        {
                            AI.history.blackValue[moves[i].GetFromSq()][moves[i].GetToSq()] += (MAX_DEPTH - depth) * (MAX_DEPTH - depth);
                        }
                        return(value - 1);
                    }
                    if (value < beta) // set new beta, set principal variant flag
                    {
                        beta    = value;
                        pvfound = true;
                    }
                    if (value < bestValue) // set new best action, best value
                    {
                        bestAction = moves[i];
                        bestValue  = value;
                    }
                }
            }
            else
            {
                moves[i].DoMove(UNMAKE);
            }
        }

        // no legal moves for this state
        if (value == SMALL_NUM)
        {
            // if in check, checkmate; else stalemate
            if (MoveGen.IsKingAttacked(color))
            {
                if (color == AI.board.myColor) // we are in checkmate
                {
                    return(Score.CHECKMATE_LOSE_SCORE);
                }
                else if (color == AI.board.oppColor) // opp is in checkmate
                {
                    return(Score.CHECKMATE_WIN_SCORE);
                }
            }
            else
            {
                return(Score.DRAW_SCORE);
            }
        }

        // return best value from current depth; update history table
        if (color == ChessBoard.WHITE)
        {
            AI.history.whiteValue[bestAction.GetFromSq()][bestAction.GetToSq()] += ((MAX_DEPTH - depth) * (MAX_DEPTH - depth) + 1);
        }
        else if (color == ChessBoard.BLACK)
        {
            AI.history.blackValue[bestAction.GetFromSq()][bestAction.GetToSq()] += ((MAX_DEPTH - depth) * (MAX_DEPTH - depth) + 1);
        }
        return(bestValue);
    }
Example #22
0
File: Io.cs Project: Woldbye/LINKcs
        /// <summary>
        ///     Translates a move to an integer
        /// </summary>
        /// <param name="board"></param>
        /// <param name="ptrChar"></param>
        /// <returns></returns>
        public static int ParseMove(Board board, char[] ptrChar)
        {
            if (ptrChar[1] > '8' || ptrChar[1] < '1')
            {
                return(Variables.NO_MOVE);
            }

            if (ptrChar[3] > '8' || ptrChar[3] < '1')
            {
                return(Variables.NO_MOVE);
            }

            if (ptrChar[0] > 'h' || ptrChar[0] < 'a')
            {
                return(Variables.NO_MOVE);
            }

            if (ptrChar[2] > 'h' || ptrChar[2] < 'a')
            {
                return(Variables.NO_MOVE);
            }

            // Use ASCII values as integers.
            int from = Conversion.FR2SQ(ptrChar[0] - 'a', ptrChar[1] - '1');
            int to   = Conversion.FR2SQ(ptrChar[2] - 'a', ptrChar[3] - '1');

            Debug.Assert(Validators.SqOnBoard(from), String.Format("The from {0} sq is invalid", Io.SqToString(from)));
            Debug.Assert(Validators.SqOnBoard(to),
                         String.Format("The to {0} sq is invalid", Io.SqToString(to)));

            MoveList moveList = new MoveList();

            MoveGen.GenerateAllMoves(board, moveList, false);

            for (int i = 0; i < moveList.Count; ++i)
            {
                int move = moveList.Moves[i].Move;

                // If the move has been located in the move list, it means it's a valid move.
                if (MoveOperations.FromSq(move) == from && MoveOperations.ToSq(move) == to)
                {
                    int promotedPce = MoveOperations.Promoted(move);
                    if (promotedPce != (int)Piece.EMPTY)
                    {
                        if (Data.IsPieceRookQueen(promotedPce) &&
                            !Data.IsPieceBishopQueen(promotedPce) && ptrChar[4] == 'r')
                        {
                            return(move);
                        }
                        else if (!Data.IsPieceRookQueen(promotedPce) &&
                                 Data.IsPieceBishopQueen(promotedPce) && ptrChar[4] == 'b')
                        {
                            return(move);
                        }
                        else if (Data.IsPieceKnight(promotedPce) && ptrChar[4] == 'k')
                        {
                            return(move);
                        }
                        else if (Data.IsPieceBishopQueen(promotedPce) &&
                                 Data.IsPieceRookQueen(promotedPce) && ptrChar[4] == 'q')
                        {
                            return(move);
                        }
                        continue;
                    }

                    return(move);
                }
            }

            return(Variables.NO_MOVE);
        }
Example #23
0
        /// <summary>
        /// sqの駒を掴む
        /// sqの駒が自駒であることは確定している。
        /// 行き先の候補の升情報を更新する。
        /// </summary>
        /// <param name="sq"></param>
        public void pick_up(SquareHand sq)
        {
            if (!(gameServer.CanUserMove && !gameServer.EngineInitializing))
            {
                return;
            }

            var pos = gameServer.Position;

            // この駒をユーザーが掴んで動かそうとしていることを示す
            viewState.picked_from = sq;
            viewState.picked_to   = SquareHand.NB;
            viewState.state       = GameScreenControlViewStateEnum.PiecePickedUp;

            // デバッグ用に出力する。
            //Console.WriteLine("pick up : " + sq.Pretty() );

            // 簡単に利きを表示する。
            // ここで連続王手による千日手などを除外すると
            // 「ユーザーが駒が動かせない、バグだ」をみたいなことを言い出しかねない。
            // 移動後に連続王手の千日手を回避していないという警告を出すようにしなくてはならない。

            // 合法手を生成して、そこに含まれるものだけにする。
            // この生成、局面が変わったときに1回でいいような気はするが..
            // 何回もクリックしまくらないはずなのでまあいいや。

            int n = MoveGen.LegalAll(pos, moves_buf, 0);

            var      is_drop = sq.IsHandPiece();
            var      pt      = pos.PieceOn(sq).PieceType();
            Bitboard bb      = Bitboard.ZeroBB();

            // 生成されたすべての合法手に対して移動元の升が合致する指し手の移動先の升を
            // Bitboardに反映させていく。
            for (int i = 0; i < n; ++i)
            {
                var m = moves_buf[i];
                if (is_drop)
                {
                    // 駒の打てる先。これは合法手でなければならない。
                    // 二歩とか打ち歩詰めなどがあるので合法手のみにしておく。
                    // (打ち歩詰めなので打てませんの警告ダイアログ、用意してないので…)

                    // 合法手には自分の手番の駒しか含まれないのでこれでうまくいくはず
                    if (m.IsDrop() && m.DroppedPiece() == pt)
                    {
                        bb |= m.To();
                    }
                }
                else
                {
                    // 駒の移動できる先
                    if (!m.IsDrop() && m.From() == (Square)sq)
                    {
                        bb |= m.To();
                    }
                }
            }

            viewState.picked_piece_legalmovesto = bb;
            viewState.state = GameScreenControlViewStateEnum.PiecePickedUp;

            // この値が変わったことで画面の状態が変わるので、次回、OnDraw()が呼び出されなくてはならない。
            Dirty = true;
        }
Example #24
0
        /// <summary>
        /// Parse a FEN string and return a chess Position object.
        /// </summary>
        /// <param name="fen"></param>
        /// <returns></returns>
        public static Position readFEN(string fen)
        {
            Position pos = new Position();

            string[] words = fen.Split(' ');

            if (words.Length < 2)
            {
                throw new ChessParseError("Too few pieces");
            }

            // Piece placement
            int row = 7;
            int col = 0;

            for (int i = 0; i < words[0].Length; i++)
            {
                char c = words[0][i];

                switch (c)
                {
                case '1':
                    col += 1;
                    break;

                case '2':
                    col += 2;
                    break;

                case '3':
                    col += 3;
                    break;

                case '4':
                    col += 4;
                    break;

                case '5':
                    col += 5;
                    break;

                case '6':
                    col += 6;
                    break;

                case '7':
                    col += 7;
                    break;

                case '8':
                    col += 8;
                    break;

                case '/':
                    row--; col = 0;
                    break;

                case 'P':
                    safeSetPiece(pos, col, row, Piece.WPAWN); col++;
                    break;

                case 'N':
                    safeSetPiece(pos, col, row, Piece.WKNIGHT); col++;
                    break;

                case 'B':
                    safeSetPiece(pos, col, row, Piece.WBISHOP); col++;
                    break;

                case 'R':
                    safeSetPiece(pos, col, row, Piece.WROOK); col++;
                    break;

                case 'Q':
                    safeSetPiece(pos, col, row, Piece.WQUEEN); col++;
                    break;

                case 'K':
                    safeSetPiece(pos, col, row, Piece.WKING); col++;
                    break;

                case 'p':
                    safeSetPiece(pos, col, row, Piece.BPAWN); col++;
                    break;

                case 'n':
                    safeSetPiece(pos, col, row, Piece.BKNIGHT); col++;
                    break;

                case 'b':
                    safeSetPiece(pos, col, row, Piece.BBISHOP); col++;
                    break;

                case 'r':
                    safeSetPiece(pos, col, row, Piece.BROOK); col++;
                    break;

                case 'q':
                    safeSetPiece(pos, col, row, Piece.BQUEEN); col++;
                    break;

                case 'k':
                    safeSetPiece(pos, col, row, Piece.BKING); col++;
                    break;

                default: throw new ChessParseError("Invalid piece");
                }
            }

            if (words[1].Length == 0)
            {
                throw new ChessParseError("Invalid side");
            }

            pos.setWhiteMove(words[1][0] == 'w');

            // Castling rights
            int castleMask = 0;

            if (words.Length > 2)
            {
                for (int i = 0; i < words[2].Length; i++)
                {
                    char c = words[2][i];
                    switch (c)
                    {
                    case 'K':
                        castleMask |= (1 << Position.H1_CASTLE);
                        break;

                    case 'Q':
                        castleMask |= (1 << Position.A1_CASTLE);
                        break;

                    case 'k':
                        castleMask |= (1 << Position.H8_CASTLE);
                        break;

                    case 'q':
                        castleMask |= (1 << Position.A8_CASTLE);
                        break;

                    case '-':
                        break;

                    default:
                        throw new ChessParseError("Invalid castling flags");
                    }
                }
            }
            pos.setCastleMask(castleMask);

            if (words.Length > 3)
            {
                // En passant target square
                string epstring = words[3];
                if (epstring != "-")
                {
                    if (epstring.Length < 2)
                    {
                        throw new ChessParseError("Invalid en passant square");
                    }
                    pos.setEpSquare(getSquare(epstring));
                }
            }

            try
            {
                if (words.Length > 4)
                {
                    pos.halfMoveClock = int.Parse(words[4]);
                }
                if (words.Length > 5)
                {
                    pos.fullMoveCounter = int.Parse(words[5]);
                }
            }
            catch
            {
                // Ignore errors here, since the fields are optional
            }

            // Each side must have exactly one king
            int wKings = 0;
            int bKings = 0;

            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                {
                    int p = pos.getPiece(Position.getSquare(x, y));
                    if (p == Piece.WKING)
                    {
                        wKings++;
                    }
                    else if (p == Piece.BKING)
                    {
                        bKings++;
                    }
                }
            }

            if (wKings != 1)
            {
                throw new ChessParseError("White must have exactly one king");
            }

            if (bKings != 1)
            {
                throw new ChessParseError("Black must have exactly one king");
            }

            // Make sure king can not be captured
            Position pos2 = new Position(pos);

            pos2.setWhiteMove(!pos.whiteMove);

            if (MoveGen.inCheck(pos2))
            {
                throw new ChessParseError("King capture possible");
            }

            fixupEPSquare(pos);

            return(pos);
        }