コード例 #1
0
ファイル: PVSearch.cs プロジェクト: Royar13/artemis-chess
        public PVList Calculate(int depth, PVList prevPV, CancellationToken ct, SearchStats searchStats)
        {
            searchDepth      = depth;
            this.searchStats = searchStats;
            this.ct          = ct;
            if (searchDepth > 1 && prevPV != null)
            {
                currentPVNode = prevPV.First;
            }
            PVList pvList = new PVList();
            int    score  = Search(depth, 0, ArtemisEngine.INITIAL_ALPHA, ArtemisEngine.INITIAL_BETA, pvList, false);

            pvList.Score = score;
            pvList.Depth = depth;
            return(pvList);
        }
コード例 #2
0
ファイル: SearchThread.cs プロジェクト: Royar13/artemis-chess
        public PVList Search(int startDepth, CancellationToken ct)
        {
            SearchStats = new SearchStats();
            killerMoves.Prepare(gameState.IrrevStates);
            PVList pv = null;
            bool   con;
            int    depth = startDepth;

            do
            {
                PVList newPV = pvSearch.Calculate(depth, pv, ct, SearchStats);
                if (!ct.IsCancellationRequested)
                {
                    pv = newPV;
                }
                depth++;
                con = !ct.IsCancellationRequested && (!config.ConstantDepth || depth <= config.Depth);
            } while (con);

            return(pv);
        }
コード例 #3
0
ファイル: ThreadMaster.cs プロジェクト: Royar13/artemis-chess
        public async Task <PVList> Search(CancellationToken ct)
        {
            Stopwatch watch = new Stopwatch();

            watch.Start();
            List <Task <PVList> > tasks = new List <Task <PVList> >();
            int currentThreadsNum       = config.Multithreading ? threadsNum : 1;

            for (int t = 0; t < currentThreadsNum; t++)
            {
                SearchThread thread = searchThreads[t];
                thread.LoadState(gameState);
                Task <PVList> engineTask = Task.Run(() => thread.Search(1, ct));
                tasks.Add(engineTask);
            }

            PVList[] foundPV = await Task.WhenAll(tasks);

            PVList       bestPV     = new PVList();
            SearchThread bestThread = null;

            for (int i = 0; i < foundPV.Length; i++)
            {
                if (foundPV[i] != null && foundPV[i].First != null && foundPV[i] > bestPV)
                {
                    bestPV     = foundPV[i];
                    bestThread = searchThreads[i];
                }
            }
            watch.Stop();

            bestThread.SearchStats.Time = watch.ElapsedMilliseconds;
            string statsJson = JsonConvert.SerializeObject(bestThread.SearchStats);

            Console.WriteLine(statsJson);
            Console.WriteLine(bestPV);

            searchedNodes.Clear();
            return(bestPV);
        }
コード例 #4
0
ファイル: PVSearch.cs プロジェクト: Royar13/artemis-chess
        private int Search(int depth, int ply, int alpha, int beta, PVList pvList, bool nullMoveReduction)
        {
            if (ct.IsCancellationRequested)
            {
                return(0);
            }

            searchStats.Nodes++;

            if (gameState.IsDraw())
            {
                int score = evaluator.GetDrawScore(engine.EngineColor);
                if (score > alpha)
                {
                    pvList.Replace(new PVList());
                }
                return(score);
            }

            if (gameState.IsCheck() && depth < ArtemisEngine.MAX_DEPTH)
            {
                //check extension
                depth += 1;
            }

            int   originalAlpha = alpha;
            ulong hash          = gameState.GetIrrevState().ZobristHash;
            TTHit ttHit         = transpositionTable.TryGetValue(hash, depth, alpha, beta, pvList);

            if (ttHit.HitType == HitType.Hit)
            {
                searchStats.TTHits++;
                return(ttHit.Score);
            }
            TranspositionNode ttNode = ttHit.TTNode;

            if (depth <= 0 || ply == ArtemisEngine.MAX_DEPTH)
            {
                int score = quietSearch.Search(alpha, beta);
                if (score > alpha)
                {
                    pvList.Replace(new PVList());
                }
                return(score);
            }


            Move   bestMove = null;
            bool   cutoff   = false;
            PVList newPV    = new PVList();
            bool   PVNode   = alpha != beta - 1;

            if (!PVNode && ttHit.HitType != HitType.AvoidNullMove &&
                !nullMoveReduction && engine.GameStage != GameStage.Endgame && !gameState.IsCheck())
            {
                //null move pruning
                gameState.MakeNullMove();
                int nextDepth = depth - 1 - config.NullMoveDepthReduction;
                int score     = -Search(nextDepth, ply + 1, -beta, -beta + 1, newPV, true);
                gameState.UnmakeNullMove();
                if (score >= beta)
                {
                    searchStats.NullMoveCutoffs++;
                    searchStats.AlphaBetaCutoffs++;
                    TranspositionNode newNode = new TranspositionNode(NodeType.CutNode, score, nextDepth + 1, null, null);
                    SaveNode(hash, ttNode, newNode);
                    //alpha-beta cutoff
                    return(beta);
                }
            }

            List <Move> moves  = gameState.GetMoves();
            Move        pvMove = null;

            if (PVNode)
            {
                if (currentPVNode != null)
                {
                    pvMove        = currentPVNode.Move;
                    currentPVNode = currentPVNode.Next;
                }
                else
                {
                    PVNode = false;
                }
            }
            Move hashMove = null;

            if (ttNode != null)
            {
                hashMove = ttNode.BestMove;
            }
            Move[] killers = killerMoves.GetKillerMoves(ply);
            moves = moves.OrderByDescending(m => moveEvaluator.EvaluateMove(m, pvMove, hashMove, killers).Score).ToList();

            int  originalLen          = moves.Count;
            int  moveCount            = 0;
            bool lmrCandidatePosition = depth >= 3 && !PVNode && !gameState.IsCheck();

            for (int i = 0; i < moves.Count && !cutoff; i++)
            {
                Move move = moves[i];
                gameState.MakeMove(move);
                if (move.IsLegal())
                {
                    int  nextDepth    = depth - 1;
                    bool lmrReduction = false;
                    if (lmrCandidatePosition && moveCount >= 4 && move.IsQuiet() && !gameState.IsCheck())
                    {
                        lmrReduction = true;
                        nextDepth--;
                        searchStats.LMRReductions++;
                    }

                    int score;
                    if (moveCount == 0 || searchDepth == 1)
                    {
                        score = -Search(nextDepth, ply + 1, -beta, -alpha, newPV, false);
                    }
                    else
                    {
                        ulong moveHash = gameState.GetIrrevState().ZobristHash;
                        if (!config.Multithreading || i >= originalLen || searchedNodes.TryAdd(moveHash, true))
                        {
                            score = -Search(nextDepth, ply + 1, -alpha - 1, -alpha, newPV, false);
                            searchedNodes.TryRemove(moveHash, out _);

                            if (score > alpha)
                            {
                                if (lmrReduction)
                                {
                                    nextDepth++;
                                }
                                score = -Search(nextDepth, ply + 1, -beta, -alpha, newPV, false);
                            }
                        }
                        else
                        {
                            moves.Add(move);
                            gameState.UnmakeMove(move);
                            continue;
                        }
                    }

                    if (score >= beta)
                    {
                        //alpha-beta cutoff
                        searchStats.AlphaBetaCutoffs++;
                        alpha    = beta;
                        bestMove = move;
                        cutoff   = true;
                        killerMoves.AddMove(move, ply);
                    }
                    else if (score > alpha)
                    {
                        alpha    = score;
                        bestMove = move;
                    }

                    moveCount++;
                }
                gameState.UnmakeMove(move);
            }

            if (moveCount == 0)
            {
                //player has no legal moves
                if (gameState.IsCheck())
                {
                    return(-PositionEvaluator.CHECKMATE_SCORE - depth);
                }
                else
                {
                    return(0);
                }
            }

            NodeType nodeType = GetNodeType(originalAlpha, beta, alpha);
            PVList   nodePV   = null;

            if (nodeType == NodeType.PVNode)
            {
                searchStats.PVNodes++;
                PVNode node = new PVNode(bestMove);
                newPV.AddFirst(node);
                nodePV = newPV;
                pvList.Replace(newPV);
            }
            TranspositionNode updatedNode = new TranspositionNode(nodeType, alpha, depth, bestMove, nodePV);

            SaveNode(hash, ttNode, updatedNode);

            return(alpha);
        }
コード例 #5
0
 public void Replace(PVList lst)
 {
     First = lst.First;
 }