public override Move move(IField field, int teamId, int turn)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();
            mMyTeamId = teamId;
            MaxMinBitField f         = new MaxMinBitField(field, teamId, turn);
            MaxNode        root      = new MaxNode(f);
            Move           bestMove  = null;
            double         bestScore = -1;
            int            d         = 1;
            Dictionary <ulong, MaxNode> maxNodesCache = new Dictionary <ulong, MaxNode>(100000);
            Dictionary <ulong, MinNode> minNodesCache = new Dictionary <ulong, MinNode>(100000);

            for (;; d++)
            {
                maxNodesCache.Clear();
                minNodesCache.Clear();
                double s = root.search(d, Double.NegativeInfinity, Double.PositiveInfinity, sw, maxNodesCache, minNodesCache);
                if (s < 0)
                {
                    break;
                }
                bestMove  = root.getBestChild().getLastMove();
                bestScore = root.getScore();
                if (s < 0.0001 || s >= 0.9999)
                {
                    break;
                }
            }
            Debug.WriteLine("s:" + bestScore + "(d=" + d);
            mTotalDepth += d;
            return(bestMove);
        }
        public double search(int depth, double alpha, double beta, Stopwatch sw, Dictionary <ulong, MaxNode> maxNodsCache, Dictionary <ulong, MinNode> minNodesCache)
        {
            if (mField == null)
            {
                if (sw.ElapsedMilliseconds > 200)
                {
                    return(-1.0);
                }

                mField = new MaxMinBitField(mParent.getField());
                var result = mField.updateByEnemyMove(mLastMove);
                mValue = result[0];
                mProb  = result[1];
            }

            if (depth >= 4)
            {
                ulong   hash = mField.TransPositionHash();
                MaxNode node = null;
                if (maxNodsCache.TryGetValue(hash, out node))
                {
                    mScore = node.getScore();
                    return(mScore);
                }
                else
                {
                    maxNodsCache.Add(hash, this);
                }
            }

            if (mProb == 1.0)
            {
                mScore = mValue;
                return(mValue);
            }

            if (depth <= 0)
            {
                mScore = mProb * mValue + (1.0 - mProb) * MaxMinVotingPlayer.Score(mField);
                return(mScore);
            }

            if (mChildList == null)
            {
                var moveList = MaxMinBitField.CreateMoves(mField, mField.getNextPlayerId());
                mChildList = new List <MinNode>(moveList.Count);
                foreach (Move m in moveList)
                {
                    mChildList.Add(new MinNode(m, this));
                }
            }
            else
            {
                // 降順
                mChildList.Sort((MinNode n0, MinNode n1) =>
                {
                    return(n0.getScore() > n1.getScore() ? -1 :
                           n0.getScore() < n1.getScore() ? 1 : 0);
                });
            }
            mScore = Double.NegativeInfinity;
            foreach (MinNode node in mChildList)
            {
                double s = mProb * mValue;
                if (s + (1.0 - mProb) <= mScore)
                {
                    continue;
                }
                double childValue = node.search(depth - 1, alpha, beta, sw, maxNodsCache, minNodesCache);
                if (childValue < 0)
                {
                    //打ち切り
                    return(childValue);
                }

                s += (1.0 - mProb) * childValue;
                if (s > mScore)
                {
                    mScore     = s;
                    mBestChild = node;
                    if (s > alpha)
                    {
                        alpha = s;
                        if (s >= beta)
                        {
                            break;
                        }
                    }
                }
            }
            return(mScore);
        }