/// <summary>
        /// 获得外部提交的一步棋步(非主线程)
        /// </summary>
        /// <param name="stepNum"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="isPass"></param>
        /// <param name="isResign"></param>
        public void OutsiderMoveArrived(int stepNum, int x, int y, bool isPass, bool isResign)
        {
            m_History.Add(new Tuple <int, int, bool, bool>(x, y, isPass, isResign));

            if (isPass)
            {
                if (m_History.Count > 1 && m_History[m_History.Count - 2].Item3)//两手pass
                {
                    ClientLog.WriteLog(")");
                    if (m_CurrentGameTimes == m_TotalGameLoopTimes)//全部比赛完成
                    {
                        GameOverCallback?.Invoke(stepNum, x, y, isPass, isResign);
                    }
                    else
                    {
                        m_CurrentGameTimes++;
                        Start();//又重新开始
                    }
                    return;
                }
            }

            if (isResign)
            {
                ClientLog.WriteLog(")");
                if (m_CurrentGameTimes == m_TotalGameLoopTimes)//全部比赛完成
                {
                    GameOverCallback?.Invoke(stepNum, x, y, isPass, isResign);
                }
                else
                {
                    m_CurrentGameTimes++;
                    Start();//又重新开始
                }
                return;
            }


            DllImport.Play(x, y, 2 - stepNum % 2);
            UICallback?.Invoke(stepNum, x, y, isPass, isResign);

            if (TerritoryCallback != null)
            {
                int[] territoryStatictics = new int[m_BoardSize * m_BoardSize];
                DllImport.GetTerritoryStatictics(territoryStatictics);
                TerritoryCallback.Invoke(territoryStatictics);
            }

            ClientLog.WriteLog(";" + (stepNum % 2 == 1 ? "W" : "B") + "[" + (char)('a' + x) + (char)('a' + y) + "]");
            //Console.WriteLine((stepNum % 2 == 0 ? "黑" : "白") + "  WinRate: " + x + " " + y);


            stepNum++;
            int turn = stepNum % 4;

            if (aiSettings[turn].IsZen)
            {
                //如果下一步还是Zen
                GetZenMove(stepNum);
            }
            else
            {
                //如果不是zen,交出控制
                HandTurnCallback?.Invoke(stepNum);
            }
        }
        /// <summary>
        /// 处理Zen结果(非主线程)
        /// </summary>
        /// <param name="stepNum"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="isPass"></param>
        /// <param name="isResign"></param>
        private void DealZenResult(int stepNum, int x, int y, bool isPass, bool isResign, int count, float winRate)
        {
            m_History.Add(new Tuple <int, int, bool, bool>(x, y, isPass, isResign));
            if (isPass)
            {
                if (m_History.Count > 1 && m_History[m_History.Count - 2].Item3)//两手pass
                {
                    ClientLog.WriteLog(")");
                    if (m_CurrentGameTimes == m_TotalGameLoopTimes)//全部比赛完成
                    {
                        GameOverCallback?.Invoke(stepNum, x, y, isPass, isResign);
                    }
                    else
                    {
                        m_CurrentGameTimes++;
                        Start();//又重新开始
                    }
                    return;
                }
            }

            if (isResign)
            {
                ClientLog.WriteLog(")");
                if (m_CurrentGameTimes == m_TotalGameLoopTimes)//全部比赛完成
                {
                    GameOverCallback?.Invoke(stepNum, x, y, isPass, isResign);
                }
                else
                {
                    m_CurrentGameTimes++;
                    Start();//又重新开始
                }
                return;
            }

            DllImport.Play(x, y, 2 - stepNum % 2);

            //因为GetTerritoryStatictics耗时,所以这样处理两次,让UI连续
            int[] territoryStatictics = null;
            if (TerritoryCallback != null)
            {
                territoryStatictics = new int[m_BoardSize * m_BoardSize];
                DllImport.GetTerritoryStatictics(territoryStatictics);
            }

            UICallback?.Invoke(stepNum, x, y, isPass, isResign);

            if (TerritoryCallback != null)
            {
                TerritoryCallback.Invoke(territoryStatictics);
                Console.WriteLine((stepNum % 2 == 0 ? "黑" : "白") + "走棋  黑胜率: " + (stepNum % 2 == 0 ? winRate : 1 - winRate).ToString("F2") + "  黑领先目数:" + (territoryStatictics.Sum() / 1000.0 - 6.5).ToString("F1"));
            }

            ClientLog.WriteLog(";" + (stepNum % 2 == 1 ? "W" : "B") + "[" + (char)('a' + x) + (char)('a' + y) + "]" + "C[胜率:" + winRate.ToString("F2") + "% count=" + count + "]");
            WinRateCallback?.Invoke(stepNum % 2 == 0 ? winRate : 1 - winRate);


            stepNum++;
            int turn = stepNum % 4;

            if (aiSettings[turn].IsZen)
            {
                //如果下一步还是Zen
                GetZenMove(stepNum);
            }
            else
            {
                //如果不是zen,交出控制
                HandTurnCallback?.Invoke(stepNum);
            }
        }