Ejemplo n.º 1
0
        //遷移順を決める.  「この関数においては」MeBoard…手番プレイヤのボード, Me…手番プレイヤ、とします。
        //引数: stateは手番プレイヤが手を打つ前の探索状態、(way1[i], way2[i])はi番目の合法手(移動量)です。
        //以下のルールで優先順を決めます.
        //ルール1. Killer手(優先したい手)があれば、それを優先する
        //ルール2. 次のmoveで得られる「タイルポイント」の合計値が大きい移動(の組み合わせ)を優先する。
        //ルール2では, タイル除去によっても「タイルポイント」が得られるとして計算する。
        private void SortMoves(sbyte[,] ScoreBoard, SearchState state, SmallWays ways, int deep, Decision ngMove)
        {
            Unsafe8Array <Point> Killer = new Unsafe8Array <Point>();

            if (ngMove is null)
            {
                if (dp1[deep].Score == int.MinValue)
                {
                    for (int i = 0; i < AgentsCount; ++i)
                    {
                        Killer[i] = new Point(114, 191);
                    }
                }
                else
                {
                    for (int i = 0; i < AgentsCount; ++i)
                    {
                        Killer[i] = state.Me[i] + dp1[deep].Ways[i].Direction;
                    }
                }
            }
            else
            {
                if (dp2[deep].Score == int.MinValue)
                {
                    for (int i = 0; i < AgentsCount; ++i)
                    {
                        Killer[i] = new Point(114, 191);
                    }
                }
                else
                {
                    for (int i = 0; i < AgentsCount; ++i)
                    {
                        Killer[i] = state.Me[i] + dp2[deep].Ways[i].Direction;
                    }
                }
            }

            for (int i = 0; i < ways.Count; ++i)
            {
                sbyte score = 0;
                Unsafe8Array <Point> next = new Unsafe8Array <Point>();
                for (int j = 0; j < AgentsCount; ++j)
                {
                    next[j] = state.Me[j] + ways[i].AgentsWay[j].Direction;
                }

                for (int j = 0; j < AgentsCount; ++j)
                {
                    if (Killer[j] != next[j])
                    {
                        break;
                    }
                    if (j == AgentsCount - 1)
                    {
                        score = 100;
                    }
                }

                for (int j = 0; j < AgentsCount; ++j)
                {
                    if (state.EnemyBoard[next[j]])
                    {
                        score += ScoreBoard[next[j].X, next[j].Y];                               //タイル除去によって有利になる
                    }
                    else if (!state.MeBoard[next[j]])
                    {
                        score += ScoreBoard[next[j].X, next[j].Y];                               //移動でMeの陣地が増えて有利になる
                    }
                }
            }
            ways.Sort();
        }
Ejemplo n.º 2
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        private int NegaMax(int deepness, SearchState state, int alpha, int beta, int count, PointEvaluator.Base evaluator, Decision ngMove, int greedyDepth)
        {
            if (deepness == 0)
            {
                //for (int j = 0; j < greedyDepth; j++)
                //{
                //Unsafe8Array<VelocityPoint> move = state.MakeGreedyMove(ScoreBoard, WayEnumerator, AgentsCount);
                //state.Move(move, AgentsCount);
                //Ways moves = state.MakeMoves(AgentsCount, ScoreBoard);
                //SortMoves(ScoreBoard, state, moves, 49, null);
                //state.Move(moves[0].Agent1Way, moves[1].Agent2Way);
                //}
                int score = evaluator.Calculate(ScoreBoard, state.MeBoard, 0, state.Me, state.Enemy) - evaluator.Calculate(ScoreBoard, state.EnemyBoard, 0, state.Enemy, state.Me);
                if (greedyDepth % 2 == 1)
                {
                    return(-score);
                }
                return(score);
            }

            Ways      ways  = state.MakeMoves(AgentsCount, ScoreBoard);
            SmallWays sways = new SmallWays(AgentsCount);

            //ways => sways
            foreach (var way in ways.GetEnumerator(AgentsCount))
            {
                sways.Add(new SmallWay(way));
            }
            SortMoves(ScoreBoard, state, sways, count, ngMove);

            for (int i = 0; i < sways.Count; ++i)
            {
                if (CancellationToken.IsCancellationRequested == true)
                {
                    return(alpha);
                }                                       //何を返しても良いのでとにかく返す
                //if (count == 0 && !(ngMove is null) && new Decided(ways[i].Agent1Way, ways[i].Agent2Way).Equals(ngMove)) { continue; }	//競合手を避ける場合
                if (count == 0 && !(ngMove is null))    //2人とも競合手とは違う手を指す
                {
                    int j;
                    for (j = 0; j < AgentsCount; ++j)
                    {
                        if (sways[i].Equals(ngMove.Agents[j]))
                        {
                            break;
                        }
                    }
                    if (j != AgentsCount)
                    {
                        continue;
                    }
                }

                SearchState nextState = state;
                nextState = nextState.GetNextState(AgentsCount, sways[i].AgentsWay);
                nextState = nextState.ChangeTurn();
                int res = -NegaMax(deepness - 1, nextState, -beta, -alpha, count + 1, evaluator, ngMove, greedyDepth);
                if (alpha < res)
                {
                    alpha = res;
                    if (ngMove is null)
                    {
                        dp1[count].UpdateScore(alpha, sways[i].AgentsWay);
                    }
                    else
                    {
                        dp2[count].UpdateScore(alpha, sways[i].AgentsWay);
                    }
                    if (alpha >= beta)
                    {
                        return(beta);               //βcut
                    }
                }
            }
            sways.Erase();
            //WaysPool.Return(ways);
            return(alpha);
        }