示例#1
0
        //1ターン = 深さ2
        protected override void Solve()
        {
            for (int i = 0; i < 50; ++i)
            {
                dp[i].Score = int.MinValue;
            }

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

            PointEvaluator.Base evaluator = (TurnCount / 3 * 2) < CurrentTurn ? PointEvaluator_Normal : PointEvaluator_Dispersion;
            SearchState         state     = new SearchState(MyBoard, EnemyBoard, MyAgents, EnemyAgents);

            for (; deepness <= 1; deepness++)
            {
                NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator);
                if (CancellationToken.IsCancellationRequested == false)
                {
                    SolverResult = new Decision(Unsafe8Array <VelocityPoint> .Create(dp[0].Ways.GetEnumerable(AgentsCount).Select(x => x.Direction).ToArray()));
                }
                else
                {
                    break;
                }
                Log("[SOLVER] deepness = {0}", deepness);
            }
        }
示例#2
0
 public void UpdateScore(int score, Unsafe8Array <Way> ways)
 {
     if (Score < score)
     {
         Ways = ways;
     }
 }
示例#3
0
        protected override void Solve()
        {
            for (int i = 0; i < 50; ++i)
            {
                dp[i].Score = int.MinValue;
                dp[i].Ways  = new Unsafe8Array <Way>();
            }

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

            //PointEvaluator.Base evaluator = (TurnCount / 3 * 2) < CurrentTurn ? PointEvaluator_Normal : PointEvaluator_Dispersion;
            PointEvaluator.Base evaluator = PointEvaluator_Normal;
            SearchState         state     = new SearchState(MyBoard, EnemyBoard, MyAgents, EnemyAgents);

            Log("TurnCount = {0}, CurrentTurn = {1}", TurnCount, CurrentTurn);

            for (int agent = 0; agent < AgentsCount; ++agent)
            {
                Unsafe8Array <Way> nextways = dp[0].Ways;
                NegaMax(deepness, state, int.MinValue + 1, 0, evaluator, null, nextways, agent);
            }

            if (CancellationToken.IsCancellationRequested == false)
            {
                SolverResult = new Decision(Unsafe8Array <VelocityPoint> .Create(dp[0].Ways.GetEnumerable(AgentsCount).Select(x => x.Direction).ToArray()));
            }
        }
示例#4
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        //NegaMaxではない
        private int NegaMax(int deepness, SearchState state, int alpha, int count, PointEvaluator.Base evaluator, Decision ngMove, Unsafe8Array <Way> nextways, int nowAgent)
        {
            var sw = System.Diagnostics.Stopwatch.StartNew();

            if (deepness == 0)
            {
                return(evaluator.Calculate(ScoreBoard, state.MeBoard, 0, state.Me, state.Enemy) - evaluator.Calculate(ScoreBoard, state.EnemyBoard, 0, state.Enemy, state.Me));
            }

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

            int i = 0;

            foreach (var way in ways.Data[nowAgent])
            {
                if (CancellationToken.IsCancellationRequested == true)
                {
                    return(alpha);
                }                                                                           //何を返しても良いのでとにかく返す
                if (way.Direction == new VelocityPoint())
                {
                    continue;
                }
                i++;

                int j = 0;
                for (j = 0; j < nowAgent; ++j)
                {
                    if (dp[0].Ways[j].Locate == way.Locate)
                    {
                        break;
                    }
                }
                if (j != nowAgent)
                {
                    continue;
                }

                Unsafe8Array <Way> newways = new Unsafe8Array <Way>();
                newways[nowAgent] = way;
                SearchState backup = state;
                state = state.GetNextState(AgentsCount, newways);

                int res = NegaMax(deepness - 1, state, alpha, count + 1, evaluator, ngMove, nextways, nowAgent);
                if (alpha < res)
                {
                    nextways[nowAgent] = way;
                    alpha = res;
                    dp[count].UpdateScore(alpha, nextways);
                }

                state = backup;
            }

            sw.Stop();
            //Log("NODES : {0} nodes, elasped {1} ", i, sw.Elapsed);
            ways.End();
            return(alpha);
        }
示例#5
0
        public void EqualPoint3Test()
        {
            Unsafe8Array <Point> x = Unsafe8Array <Point> .Create(new Point[] { new Point(0, 1), new Point(2, 3), new Point(4, 5), new Point(6, 7) });

            Unsafe8Array <Point> y = Unsafe8Array <Point> .Create(new Point[] { new Point(0, 1), new Point(2, 3), new Point(4, 5), new Point(8, 9) });

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

            DP[] dp = ngMove is null ? dp1 : dp2;
            if (dp[deep].Score == int.MinValue)
            {
                Killer = Unsafe8Array <Point> .Create(new Point(114, 191), new Point(114, 191), new Point(114, 191), new Point(114, 191), new Point(114, 191), new Point(114, 191), new Point(114, 191), new Point(114, 191));
            }
            else
            {
                Killer = new Unsafe8Array <Point>();
                for (int i = 0; i < AgentsCount; ++i)
                {
                    Killer[i] = state.Me[i] + dp[deep].AgentsWay[i];
                }
            }

            for (int i = 0; i < way.Count; i++)
            {
                int score = 0;
                Unsafe8Array <Point> nexts = new Unsafe8Array <Point>();
                for (int n = 0; n < AgentsCount; ++i)
                {
                    nexts[n] = state.Me[n] + way[i].AgentWays[n];
                }

                if (Killer.Agent1 == next1 && Killer.Agent2 == next2)
                {
                    score = 100;
                }

                if (state.EnemyBoard[next1])
                {
                    score += ScoreBoard[next1.X, next1.Y];
                }                                                                           //タイル除去によって有利になる
                else if (!state.MeBoard[next1])
                {
                    score += ScoreBoard[next1.X, next1.Y];
                }                                                                           //移動でMeの陣地が増えて有利になる
                if (state.EnemyBoard[next2])
                {
                    score += ScoreBoard[next2.X, next2.Y];
                }
                else if (!state.MeBoard[next2])
                {
                    score += ScoreBoard[next2.X, next2.Y];
                }
                way[i].Point = score;
            }
            way.Sort();
        }
示例#7
0
        public void PutAndGetVelocityPointTest()
        {
            Unsafe8Array <VelocityPoint> x = new Unsafe8Array <VelocityPoint>();

            x[0] = new VelocityPoint(1, 2);
            x[1] = new VelocityPoint(3, 4);
            x[2] = new VelocityPoint(5, 6);
            x[3] = new VelocityPoint(7, 8);
            x[4] = new VelocityPoint(-1, -2);
            x[5] = new VelocityPoint(-3, -4);
            x[6] = new VelocityPoint(-5, -6);
            x[7] = new VelocityPoint(-7, -8);
            Assert.True(x[0] == new VelocityPoint(1, 2));
            Assert.True(x[1] == new VelocityPoint(3, 4));
            Assert.True(x[2] == new VelocityPoint(5, 6));
            Assert.True(x[3] == new VelocityPoint(7, 8));
            Assert.True(x[4] == new VelocityPoint(-1, -2));
            Assert.True(x[5] == new VelocityPoint(-3, -4));
            Assert.True(x[6] == new VelocityPoint(-5, -6));
            Assert.True(x[7] == new VelocityPoint(-7, -8));
        }
示例#8
0
        public void PutAndGetPointTest()
        {
            Unsafe8Array <Point> x = new Unsafe8Array <Point>();

            x[0] = new Point(1, 2);
            x[1] = new Point(3, 4);
            x[2] = new Point(5, 6);
            x[3] = new Point(7, 8);
            x[4] = new Point(9, 10);
            x[5] = new Point(11, 12);
            x[6] = new Point(13, 14);
            x[7] = new Point(15, 16);
            Assert.True(x[0] == new Point(1, 2));
            Assert.True(x[1] == new Point(3, 4));
            Assert.True(x[2] == new Point(5, 6));
            Assert.True(x[3] == new Point(7, 8));
            Assert.True(x[4] == new Point(9, 10));
            Assert.True(x[5] == new Point(11, 12));
            Assert.True(x[6] == new Point(13, 14));
            Assert.True(x[7] == new Point(15, 16));
        }
示例#9
0
        //1ターン = 深さ2
        protected override void Solve()
        {
            for (int i = 0; i < 50; ++i)
            {
                dp1[i].Score = int.MinValue;
                dp2[i].Score = int.MinValue;
            }

            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(Unsafe8Array <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(Unsafe8Array <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);
            }
        }
示例#10
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();
        }
示例#11
0
 public SmallWay(Unsafe8Array <Way> a)
 {
     AgentsWay = a;
     Point     = 0;
 }
示例#12
0
        //1ターン = 深さ2
        protected override void Solve()
        {
            for (int i = 0; i < 50; ++i)
            {
                dp1[i].Score = int.MinValue;
                dp2[i].Score = int.MinValue;
            }

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

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

            Log("TurnCount = {0}, CurrentTurn = {1}", TurnCount, CurrentTurn);
            if (!(lastTurnDecided is null))
            {
                StringBuilder sb = new StringBuilder("AgentMoved: {");
                for (int i = 0; i < AgentsCount; ++i)
                {
                    sb.Append(IsAgentsMoved[i]);
                    sb.Append(", ");
                }
                string ismoved = sb.ToString();
                Log("{0}}}, lastTurnDecided = {2}", ismoved.Substring(0, ismoved.Length - 2), lastTurnDecided);
            }

            if (!(lastTurnDecided is null) && IsAgentsMoved.GetEnumerable(AgentsCount).All(b => b == false) && score > 0)    //勝っている状態で競合していたら
            {
                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(Unsafe8Array <VelocityPoint> .Create(dp1[0].Ways.GetEnumerable(AgentsCount).Select(x => x.Direction).ToArray()));
                resultList.Add(best1);

                //競合手.Agent == 最善手.Agent の数が半数以上になった場合、競合手をngMoveとして探索をおこない、最善手を探す
                int UnMoveAgentNum = 0;
                for (int i = 0; i < AgentsCount; ++i)
                {
                    if (IsAgentsMoved[i] == false && lastTurnDecided.Agents[i] == best1.Agents[i])
                    {
                        ++UnMoveAgentNum;
                    }
                }
                if (UnMoveAgentNum > AgentsCount / 2)
                {
                    NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator, best1, greedyDepth);
                    Decision best2 = new Decision(Unsafe8Array <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);
            }
        }