Beispiel #1
0
 public void UpdateScore(int score, Unsafe16Array <Way> ways)
 {
     if (Score < score)
     {
         Ways = ways;
     }
 }
Beispiel #2
0
        //1ターン = 深さ2
        protected override void Solve()
        {
            for (int i = 0; i < 50; ++i)
            {
                dp1[i].Score = int.MinValue;
                dp2[i].Score = int.MinValue;
                dp1[i].Ways  = new Unsafe16Array <Way>();
                dp2[i].Ways  = new Unsafe16Array <Way>();
            }

            int deepness = StartDepth;
            int maxDepth = (TurnCount - CurrentTurn) * 2 + 2;

            PointEvaluator.Base evaluator = (TurnCount / 3 * 2) < CurrentTurn ? PointEvaluator_Normal : PointEvaluator_Dispersion;
            SearchState         state     = new SearchState(MyBoard, EnemyBoard, MyAgents, EnemyAgents);
            int score = PointEvaluator_Normal.Calculate(ScoreBoard, state.MeBoard, 0, state.Me, state.Enemy) - PointEvaluator_Normal.Calculate(ScoreBoard, state.EnemyBoard, 0, state.Enemy, state.Me);

            Log("TurnCount = {0}, CurrentTurn = {1}", TurnCount, CurrentTurn);
            //if (!(lastTurnDecided is null)) Log("IsAgent1Moved = {0}, IsAgent2Moved = {1}, lastTurnDecided = {2}", IsAgent1Moved, IsAgent2Moved, lastTurnDecided);

            if (!(lastTurnDecided is null) && score > 0)    //勝っている状態で競合していたら
            {
                int i;
                for (i = 0; i < AgentsCount; ++i)
                {
                    if (IsAgentsMoved[i])
                    {
                        break;
                    }
                }
                if (i == AgentsCount)
                {
                    SolverResultList.Add(lastTurnDecided);
                    return;
                }
            }
            for (; deepness <= maxDepth; deepness++)
            {
                Decided resultList = new Decided();

                int greedyDepth = Math.Min(greedyMaxDepth, maxDepth - deepness);
                if ((deepness + greedyDepth) % 2 == 1 && greedyDepth > 0)
                {
                    greedyDepth--;
                }
                //普通にNegaMaxをして、最善手を探す
                NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator, null, greedyDepth);
                Decision best1 = new Decision((byte)AgentsCount, Unsafe16Array <VelocityPoint> .Create(dp1[0].Ways.GetEnumerable(AgentsCount).Select(x => x.Direction).ToArray()));
                resultList.Add(best1);
                //競合手.Agent1 == 最善手.Agent1 && 競合手.Agent2 == 最善手.Agent2になった場合、競合手をngMoveとして探索をおこない、最善手を探す
                for (int i = 0; i < AgentsCount; ++i)
                {
                    if (IsAgentsMoved[i] || !lastTurnDecided.Agents[i].Equals(best1.Agents[i]))
                    {
                        break;
                    }
                    if (i < AgentsCount - 1)
                    {
                        continue;
                    }
                    NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator, best1, greedyDepth);
                    Decision best2 = new Decision((byte)AgentsCount, Unsafe16Array <VelocityPoint> .Create(dp2[0].Ways.GetEnumerable(AgentsCount).Select(x => x.Direction).ToArray()));
                    resultList.Add(best2);
                }

                if (CancellationToken.IsCancellationRequested == false)
                {
                    SolverResultList = resultList;
                    if (SolverResultList.Count == 2 && score <= 0)  //現時点で引き分けか負けていたら競合を避けるのを優先してみる(デバッグ用)
                    {
                        var tmp = SolverResultList[0];
                        SolverResultList[0] = SolverResultList[1];
                        SolverResultList[1] = tmp;
                        Log("[SOLVER] Swaped! {0} {1}", SolverResult.Agents[0], SolverResult.Agents[1]);
                    }
                    Log("[SOLVER] SolverResultList.Count = {0}, score = {1}", SolverResultList.Count, score);
                }
                else
                {
                    return;
                }
                Log("[SOLVER] deepness = {0}", deepness);
            }
        }
Beispiel #3
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)
        {
            Unsafe16Array <Point> Killer = new Unsafe16Array <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;
                Unsafe16Array <Point> next = new Unsafe16Array <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();
        }
Beispiel #4
0
        Unsafe16Array <Point> SearchFirstPlace()
        {
            Unsafe16Array <Point> newMyAgents = MyAgents;

            //均等に配置する
            //平方根を用いていろいろする
            uint xn    = (uint)Math.Sqrt(AgentsCount);
            uint yn    = (uint)AgentsCount / xn;
            uint ratio = (uint)(ScoreBoard.GetLength(0) / ScoreBoard.GetLength(1)); //縦横の比率

            if (ScoreBoard.GetLength(0) > ScoreBoard.GetLength(1))
            {
                uint tmp = xn;
                xn = yn;
                yn = tmp;
            }
            uint left   = (uint)(AgentsCount - (xn * yn)); //AgentsCountが7の時など、エージェントが余ってしまうときに
            uint spaceX = (uint)ScoreBoard.GetLength(0) / (xn * ratio);
            uint spaceY = (uint)ScoreBoard.GetLength(1) / yn;

            for (byte i = 0; i < AgentsCount - left;)
            {
                uint baseX = spaceX * (i % xn) + spaceX / 2, baseY = spaceY * (i / xn) + spaceY / 2;
                if (MyAgentsState[i] == AgentState.Move)
                {
                    goto next;
                }
                for (byte j = 0; j < spaceX / 2; j++)
                {
                    if (ScoreBoard[(baseX + j) * ratio, baseY] >= 0 && !EnemyBoard[(baseX + j) * ratio, baseY])
                    {
                        newMyAgents[i] = new Point((byte)((baseX + j) * ratio), (byte)baseY);
                        goto next;
                    }
                }
                for (byte j = 0; j < spaceX / 2; j++)
                {
                    if (ScoreBoard[(baseX - j) * ratio, baseY] >= 0 && !EnemyBoard[(baseX - j) * ratio, baseY])
                    {
                        newMyAgents[i] = new Point((byte)((baseX - j) * ratio), (byte)baseY);
                        goto next;
                    }
                }
                for (byte j = 0; j < spaceY / 2; j++)
                {
                    if (ScoreBoard[baseX * ratio, baseY + j] >= 0 && !EnemyBoard[baseX * ratio, baseY + j])
                    {
                        newMyAgents[i] = new Point((byte)(baseX * ratio), (byte)(baseY + j));
                        goto next;
                    }
                }
                for (byte j = 0; j < spaceX / 2; j++)
                {
                    if (ScoreBoard[baseX * ratio, baseY - j] >= 0 && !EnemyBoard[baseX * ratio, baseY - j])
                    {
                        newMyAgents[i] = new Point((byte)(baseX * ratio), (byte)(baseY - j));
                        goto next;
                    }
                }
                newMyAgents[i] = new Point((byte)(baseX * ratio), (byte)baseY);
next:
                ++i;
            }

            if (left == 0)
            {
                return(newMyAgents);
            }
            int cur = AgentsCount - (int)left - 1;

            for (;; ++cur)
            {
                if (cur >= AgentsCount)
                {
                    return(newMyAgents);
                }
                if (MyAgentsState[cur] == AgentState.Move)
                {
                    continue;
                }
                break;
            }
            Random       rand       = new Random();
            List <Point> recommends = new List <Point>();

            //余ったエージェントの配置
            // 10点より高いところに配置する
            for (byte x = 0; x < ScoreBoard.GetLength(0); ++x)
            {
                for (byte y = 0; y < ScoreBoard.GetLength(1); ++y)
                {
                    if (ScoreBoard[x, y] >= 10 && !EnemyBoard[x, y])
                    {
                        recommends.Add(new Point(x, y));
                    }
                }
            }

            foreach (var p in recommends.OrderBy(i => rand.Next()))
            {
                do
                {
                    cur++;
                    if (cur >= AgentsCount)
                    {
                        return(newMyAgents);
                    }
                } while (MyAgentsState[cur] == AgentState.Move);
                newMyAgents[cur] = p;
            }

            //まだ余っていたら
            for (byte x = 0; x < ScoreBoard.GetLength(0); ++x)
            {
                for (byte y = 0; y < ScoreBoard.GetLength(1); ++y)
                {
                    if (ScoreBoard[x, y] >= -1 && !EnemyBoard[x, y])
                    {
                        recommends.Add(new Point(x, y));
                    }
                }
            }

            foreach (var p in recommends.OrderBy(i => rand.Next()))
            {
                do
                {
                    cur++;
                    if (cur >= AgentsCount)
                    {
                        return(newMyAgents);
                    }
                } while (MyAgentsState[cur] == AgentState.Move);
                newMyAgents[cur] = p;
            }
            return(newMyAgents);
        }