コード例 #1
0
ファイル: MateFinder.cs プロジェクト: maksimbulva/chesshive
        public static List<List<MoveDesc>> Run(AnalysisNode starting_node,
            INodeGenerator node_generator, uint fullmove_depth)
        {
            Debug.Assert(starting_node != null && starting_node.Position != null);
            Debug.Assert(node_generator != null);
            Debug.Assert(fullmove_depth > 0);

            List<List<MoveDesc>> result = null;

            // Run recursive function, which finds all forced mates
            // This call erases all nodes (except root), which do not
            // lead to a forced checkmate. So, if there is (are) forced mate(s)
            // then the remaining tree nodes give us an answer
            if (FindMateRecursive(starting_node, node_generator, fullmove_depth)
                && !starting_node.IsLeaf)
            {
                result = new List<List<MoveDesc>>();
                foreach (var child in starting_node.Children)
                {
                    CollectAllVariations(child, new List<MoveDesc>(), result);
                }
                Debug.Assert(result.Count > 0);
            }

            return result;
        }
コード例 #2
0
        public float Evaluate(AnalysisNode node, IPersonality personality)
        {
            m_white_data.Init(node.Position);
            m_black_data.Init(node.Position);

            ulong white_good_cells = 0;
            ulong black_good_cells = 0;

            float white_value = m_white_data.m_material;
            float black_value = m_black_data.m_material;

            // TODO - if not endgame..
            white_good_cells = CentralSquares;
            black_good_cells = CentralSquares;

            // TODO - create arrays for pawns, we need them anyway
            var white_pieces = node.Position.GetPieces(Players.White);
            var black_pieces = node.Position.GetPieces(Players.Black);

            var white_good_cells_count = CountGoodCells(white_good_cells,
                Players.White, white_pieces);
            var black_good_cells_count = CountGoodCells(black_good_cells,
                Players.Black, black_pieces);

            // TODO - consider here optimistic and pessimistic players
            white_value += 0.05f * white_good_cells_count;
            black_value += 0.05f * black_good_cells_count;

            // TODO - do more
            return white_value - black_value;
        }
コード例 #3
0
ファイル: AnalysisNode.cs プロジェクト: maksimbulva/chesshive
 // TODO - consider removing
 //public Fingerprint Fingerprint { get; set; }
 public AnalysisNode(AnalysisNode parent, Position.Position p, Move m)
 {
     Debug.Assert(p != null);
     Parent = parent;
     // Must init ParentMove before Position
     m_parent_move = m;
     Position = p;
     Children = null;
     IsWhiteToMove = p.IsWhiteToMove;
 }
コード例 #4
0
ファイル: MateFinder.cs プロジェクト: maksimbulva/chesshive
        private static bool FindMateRecursive(AnalysisNode starting_node,
            INodeGenerator nodes_generator, uint fullmove_depth)
        {
            Debug.Assert(fullmove_depth > 0);

            if (fullmove_depth == 1)
            {
                nodes_generator.GenerateAllChildren(starting_node, 1);
                // Release all children nodes except checkmate nodes
                nodes_generator.ReleaseChildren(x =>
                {
                    if (x.Position.IsInCheck)
                    {
                        nodes_generator.GenerateAllChildren(x, 1);
                        return !x.Position.IsCheckmate;
                    }
                    return true;
                },
                starting_node);
            }
            else
            {
                nodes_generator.GenerateAllChildren(starting_node, 2);
                foreach (var my_move in starting_node.Children)
                {
                    bool is_skip = false;
                    foreach (var her_move in my_move.Children)
                    {
                        if (!FindMateRecursive(her_move, nodes_generator,
                            fullmove_depth - 1))
                        {
                            // My opponent can avoid being checkmated
                            is_skip = true;
                            break;
                        }
                    }

                    if (is_skip)
                    {
                        nodes_generator.ReleaseChildren(my_move);
                    }
                }

                // Erase all children except checkmate nodes or move sequences
                // that lead to a force mate
                nodes_generator.ReleaseChildren(x =>
                {
                    return !x.Position.IsCheckmate && x.Children == null;
                },
                starting_node);
            }

            return starting_node.Children != null;
        }
コード例 #5
0
ファイル: MinMax.cs プロジェクト: maksimbulva/chesshive
        public static void Evaluate(AnalysisNode root)
        {
            for (int i = 0; i < root.Children.Count; ++i)
            {
                var child = root.Children[i];
                if (child.Children != null)
                    Evaluate(child);
            }

            var best_child = GetBestChild(root);
            if (best_child != null)
            {
                root.MinmaxEvaluation = best_child.MinmaxEvaluation;
            }
        }
コード例 #6
0
ファイル: MateFinder.cs プロジェクト: maksimbulva/chesshive
 private static void CollectAllVariations(AnalysisNode current_node,
     List<MoveDesc> current_parents, List<List<MoveDesc>> variations)
 {
     var new_parents = new List<MoveDesc>(current_parents.Count + 1);
     new_parents.AddRange(current_parents);
     new_parents.Add(current_node.ParentMove.ToMoveDesc(current_node.Position));
     if (current_node.Children == null || current_node.Children.Count == 0)
     {
         // Leaf node
         variations.Add(new List<MoveDesc>(new_parents));
     }
     else
     {
         foreach (var child in current_node.Children)
         {
             CollectAllVariations(child, new_parents, variations);
         }
     }
 }
コード例 #7
0
ファイル: MinMax.cs プロジェクト: maksimbulva/chesshive
 public static AnalysisNode GetBestChild(AnalysisNode root)
 {
     int best_index = -1;
     if (root.IsWhiteToMove)
     {
         float best_evaluation = float.MinValue;
         // Return the child with the greatest evaluation
         for (int i = 0; i < root.Children.Count; ++i)
         {
             var child = root.Children[i];
             if (child.IsLeaf && child.HasStaticEvaluation)
             {
                 child.MinmaxEvaluation = child.StaticEvaluation;
             }
             if (child.HasMinmaxEvaluation
                 && child.MinmaxEvaluation > best_evaluation)
             {
                 best_index = i;
                 best_evaluation = child.MinmaxEvaluation;
             }
         }
     }
     else
     {
         // Return the child with the lowest evaluation
         float best_evaluation = float.MaxValue;
         for (int i = 0; i < root.Children.Count; ++i)
         {
             var child = root.Children[i];
             if (child.IsLeaf && child.HasStaticEvaluation)
             {
                 child.MinmaxEvaluation = child.StaticEvaluation;
             }
             if (child.HasMinmaxEvaluation
                 && child.MinmaxEvaluation < best_evaluation)
             {
                 best_index = i;
                 best_evaluation = child.MinmaxEvaluation;
             }
         }
     }
     return best_index == -1 ? null : root.Children[best_index];
 }
コード例 #8
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
        /// <summary>
        /// Erases all children nodes which satisfy the specified condition
        /// WARNING: this method is not thread-safe, run it in parallel only
        /// for nodes in non-overlapping subtrees
        /// </summary>
        public void ReleaseChildren(Predicate<AnalysisNode> condition,
            AnalysisNode subtree_root)
        {
            if (subtree_root.Children == null)
            {
                return;
            }

            List<AnalysisNode> new_children = null;
            foreach (var child in subtree_root.Children)
            {
                if (condition(child))
                {
                    ReleaseNode(child);
                }
                else
                {
                    if (new_children == null)
                    {
                        new_children = new List<AnalysisNode>(
                            subtree_root.Children.Count);
                    }
                    new_children.Add(child);
                }
            }

            if (new_children == null
                || (new_children.Count != subtree_root.Children.Count))
            {
                subtree_root.IsSomeChildrenErased = true;
                subtree_root.SetChildrenList(new_children);
            }
        }
コード例 #9
0
        public void UpdateBestLine(AnalysisNode root_node, bool report)
        {
            if (root_node == null || root_node.Children == null
                || root_node.Children.Count == 0)
            {
                m_best_line = null;
                Evaluation = 0;
            }
            else
            {
                m_best_line = new List<MoveDesc>(64);
                Evaluation = root_node.HasMinmaxEvaluation ?
                    root_node.MinmaxEvaluation : 0f;
                var cur_node = MinMax.GetBestChild(root_node);
                while (cur_node != null)
                {
                    m_best_line.Add(cur_node.GetParentMoveDesc());

                    cur_node = cur_node.Children != null
                        && cur_node.Children.Count > 0
                        ? MinMax.GetBestChild(cur_node) : null;
                }

                // Just in case there are no evaluated nodes
                if (m_best_line.Count == 0)
                {
                    m_best_line.Add(root_node.Children[0].GetParentMoveDesc());
                }
            }

            UpdateTime();

            if (report)
            {
                Factory.Instance.AnalysisStatsReporter?.Report(this);
            }
        }
コード例 #10
0
ファイル: Analyzer.cs プロジェクト: maksimbulva/chesshive
        private void AnalyzeChildren(AnalysisNode root, int depth_to_go)
        {
            // If this is not true, then we must continue recursively after
            // we have statically evaluated a grandchild node
            Debug.Assert(depth_to_go <= 2);

            m_tree.GenerateAllChildren(root, 1);
            for (int i = 0; i < root.Children.Count; ++i)
            {
                var child = root.Children[i];
                var move = child.ParentMove;

                // For some kind of moves we can't say if they are so
                // good or not without seeing possible replies
                if (move.IsCapture || move.IsPromotion
                    || child.Position.IsInCheck)
                {
                    m_tree.GenerateAllChildren(child, 1);
                    for (int j = 0; j < child.Children.Count; ++j)
                    {
                        var grandchild = child.Children[j];
                        MakeStaticEvaluation(grandchild);
                        // Continue recursively here if depth_to_go > 2
                    }
                }
                else
                {
                    MakeStaticEvaluation(child);
                    if (depth_to_go > 1)
                    {
                        AnalyzeChildren(child, depth_to_go - 1);
                    }
                }
            }
        }
コード例 #11
0
ファイル: Analyzer.cs プロジェクト: maksimbulva/chesshive
        // Returns best children
        private AnalysisNode AnalyzeFourBestChildren(AnalysisNode root,
            int depth_to_go)
        {
            AnalysisNode best_1 = null;
            AnalysisNode best_2 = null;
            AnalysisNode best_3 = null;
            AnalysisNode best_4 = null;

            bool is_white_to_move = root.IsWhiteToMove;

            for (int i = 0; i < root.Children.Count; ++i)
            {
                var child = root.Children[i];
                if (depth_to_go > 1)
                {
                    var best_grandchild = AnalyzeFourBestChildren(child,
                        depth_to_go - 1);

                    if (best_grandchild != null)
                        child.MinmaxEvaluation = best_grandchild.MinmaxEvaluation;
                }
                else
                {
                    AnalyzeChildren(child, 2);
                    MinMax.Evaluate(child);
                }

                bool is_release_grandchildren = true;

                if (child.HasMinmaxEvaluation)
                {
                    if (best_4 == null || MinMax.IsBetter(child.MinmaxEvaluation,
                        best_4.MinmaxEvaluation, is_white_to_move))
                    {
                        is_release_grandchildren = false;
                        if (best_4 != null)
                            m_tree.ReleaseChildren(best_4);

                        best_4 = child;
                        if (best_3 == null || MinMax.IsBetter(
                            child.MinmaxEvaluation, best_3.MinmaxEvaluation,
                            is_white_to_move))
                        {
                            best_4 = best_3;
                            best_3 = child;
                            if (best_2 == null || MinMax.IsBetter(
                                child.MinmaxEvaluation, best_2.MinmaxEvaluation,
                                is_white_to_move))
                            {
                                best_3 = best_2;
                                best_2 = child;
                                if (best_1 == null || MinMax.IsBetter(
                                    child.MinmaxEvaluation, best_1.MinmaxEvaluation,
                                    is_white_to_move))
                                {
                                    best_2 = best_1;
                                    best_1 = child;
                                }
                            }
                        }
                    }
                }

                if (is_release_grandchildren)
                    m_tree.ReleaseChildren(child);
            }  // loop over root's children

            m_tree.ReleaseChildren(x => !(ReferenceEquals(x, best_1)
                || ReferenceEquals(x, best_2) || ReferenceEquals(x, best_3)
                || ReferenceEquals(x, best_4)), root);

            return best_1;
        }
コード例 #12
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
        /// <summary>
        /// Generates all immediate children of the specified node
        /// WARNING: this method is not thread-safe, run it in parallel only
        /// for nodes in non-overlapping subtrees
        /// </summary>
        public void GenerateAllChildren(AnalysisNode parent, uint depth,
            bool is_restore_missing_positions = true)
        {
            Debug.Assert(parent != null && parent.Position != null);
            Debug.Assert(depth > 0);

            // Check if all moves were generated for the parent node
            // If not, clear the list of children and re-generate them all
            if (parent.IsSomeChildrenErased)
            {
                parent.SetChildrenList(null);
            }

            if (parent.Children == null)
            {
                parent.InitChildrenList();
                // TODO - conside memory pooling for the list of moves
                var moves = new List<Move>(64);
                MovesGenerator.GenerateMoves(parent.Position, moves);
                var player_to_move = parent.Position.PlayerToMove;
                bool is_parent_in_check = parent.Position.IsInCheck;
                foreach (var m in moves)
                {
                    var child_position = parent.Position.PlayMove(m);
                    // Last check if the move is a legal move
                    // Didn't do it earlier, as we need resulting position
                    // for this
                    if (!PositionValidator.IsMyMovePutsMyKingInCheck(
                        player_to_move, m, child_position, is_parent_in_check))
                    {
                        parent.Children.Add(new AnalysisNode(parent, child_position,
                            m));
                        Interlocked.Increment(ref m_node_count);
                    }
                }
                // Let the position to know whether there are legal moves
                parent.Position.HasLegalMoves = !parent.IsLeaf;
            }
            else if (is_restore_missing_positions)
            {
                foreach (var node in parent.Children)
                {
                    if (node.Position == null)
                    {
                        // Position object was destroyed to free the memory
                        // Re-create it now
                        node.RecreatePosition();
                    }
                }
            }

            // Indicate that all children are generated and present in the collection
            // Unless we have generated the moves having some restrictions imposed
            parent.IsSomeChildrenErased = false;

            // Generate next levels of child nodes recursively
            if (depth > 1)
            {
                foreach (var node in parent.Children)
                {
                    GenerateAllChildren(node, depth - 1, is_restore_missing_positions);
                }
            }

            if (ReferenceEquals(parent, Root))
            {
                m_listener.RootChildrenGenerated(Root.Children);
            }
        }
コード例 #13
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
 // Assumes the tree is locked
 private void ReleaseNode(AnalysisNode subtree_root)
 {
     if (subtree_root.Children != null)
     {
         foreach (var child in subtree_root.Children)
         {
             ReleaseNode(child);
         }
         subtree_root.SetChildrenList(null);
     }
     Interlocked.Decrement(ref m_node_count);
 }
コード例 #14
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
 // Assumes that the tree is locked
 private void Clean()
 {
     if (Root != null)
     {
         ReleaseNode(Root);
         Debug.Assert(NodeCount == 0);
         Root = null;
         m_listener.RootChildrenGenerated(null);
     }
 }
コード例 #15
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
 public void SetRoot(Position.Position p, Move parent_move)
 {
     Clean();
     if (p != null)
     {
         Root = new AnalysisNode(null, p, parent_move);
         m_node_count = 1;
         // Probably this position was not analyzed yet, and IsInCheck
         // is not initialized yet. Evaluate and set IsInCheck flag
         p.IsInCheck = PositionHelper.IsCellAttacked(
             new ChessboardCell(p.GetPieces(p.PlayerToMove).KingsCell),
             Helper.GetOtherPlayer(p.PlayerToMove), p);
         // For root we want to create children and grandchildren
         // To detect stalemate or checkmate
         GenerateAllChildren(Root, 2);
     }
     m_listener.RootPositionChanged(p);
 }
コード例 #16
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
 /// <summary>
 /// Erases all children nodes
 /// WARNING: this method is not thread-safe, run it in parallel only
 /// for nodes in non-overlapping subtrees
 /// </summary>
 public void ReleaseChildren(AnalysisNode subtree_root)
 {
     if (subtree_root.Children != null)
     {
         foreach (var child in subtree_root.Children)
         {
             ReleaseNode(child);
         }
     }
     subtree_root.IsSomeChildrenErased = true;
     subtree_root.SetChildrenList(null);
 }
コード例 #17
0
ファイル: AnalysisTree.cs プロジェクト: maksimbulva/chesshive
        public bool MakeChildNewRoot(ChessboardCell from, ChessboardCell to,
            Exports.Pieces promote_to = Exports.Pieces.NoPiece)
        {
            if (Root == null)
            {
                return false;
            }

            // Discard all root children and their subtrees, except the child
            // specified by the method parameters
            ReleaseChildren(child =>
            {
                return child.ParentMove.FromCell != from.Value
                    || child.ParentMove.ToCell != to.Value
                    || child.ParentMove.PromoteToPiece != promote_to;
            }, Root);

            if (Root.Children.Count != 1)
            {
                Clean();
                m_listener.RootPositionChanged(null);
                return false;
            }

            // Discard current root
            Interlocked.Decrement(ref m_node_count);

            // Set a new root
            Root = Root.Children[0];
            m_listener.RootPositionChanged(Root.Position);
            GenerateAllChildren(Root, 2);
            return true;
        }
コード例 #18
0
ファイル: Analyzer.cs プロジェクト: maksimbulva/chesshive
        private void Run(AnalysisNode root, int depth_to_go, ulong max_node_count)
        {
            if (depth_to_go == 1)
            {
                AnalyzeFourBestChildren(root, 2);

                // TODO - remove
                Console.WriteLine("Node count: " + m_tree.NodeCount);

                // Update stats for the whole tree
                MinMax.Evaluate(m_tree.Root);
                m_stats.UpdateBestLine(m_tree.Root, true);
            }
            else
            {
                root?.Children.ForEach(x =>
                    {
                        if (m_stats.NodesEvaluated < max_node_count)
                            Run(x, depth_to_go - 1, max_node_count);
                    });
            }
        }
コード例 #19
0
ファイル: Analyzer.cs プロジェクト: maksimbulva/chesshive
        private void MakeStaticEvaluation(AnalysisNode node)
        {
            if (node.Position == null)
            {
                node.RecreatePosition();
            }

            node.StaticEvaluation = m_data_buffer.Evaluate(node, m_stats.Personality);
            //node.Fingerprint = data_buffer.MakeFingerprint();
            m_stats.IncNodesEvaluatedCounter();
        }