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()));
            }
        }
Exemple #2
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, new Player(MyAgent1, MyAgent2), new Player(EnemyAgent1, EnemyAgent2), WaysPool);

            for (; deepness <= 1; deepness++)
            {
                NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator);
                if (CancellationToken.IsCancellationRequested == false)
                {
                    SolverResult = new Decided(dp[0].Agent1Way, dp[0].Agent2Way);
                }
                else
                {
                    break;
                }
                Log("[SOLVER] deepness = {0}", deepness);
            }
        }
Exemple #3
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);
            }
        }
        //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);
        }
Exemple #5
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, new Player(MyAgent1, MyAgent2), new Player(EnemyAgent1, EnemyAgent2), WaysPool);
            int score = PointEvaluator_Normal.Calculate(ScoreBoard, state.MeBoard, 0) - PointEvaluator_Normal.Calculate(ScoreBoard, state.EnemyBoard, 0);

            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) && IsAgent1Moved == false && IsAgent2Moved == false && score > 0)    //勝っている状態で競合していたら
            {
                SolverResultList.Add(lastTurnDecided);
                return;
            }

            for (; deepness <= maxDepth; deepness++)
            {
                DecidedEx resultList = new DecidedEx();

                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);
                Decided best1 = new Decided(dp1[0].Agent1Way, dp1[0].Agent2Way);
                resultList.Add(best1);

                //競合手.Agent1 == 最善手.Agent1 && 競合手.Agent2 == 最善手.Agent2になった場合、競合手をngMoveとして探索をおこない、最善手を探す
                if ((IsAgent1Moved == false && lastTurnDecided.MeAgent1.Equals(best1.MeAgent1)) && (IsAgent2Moved == false && lastTurnDecided.MeAgent2.Equals(best1.MeAgent2)))
                {
                    NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator, best1, greedyDepth);
                    Decided best2 = new Decided(dp2[0].Agent1Way, dp2[0].Agent2Way);
                    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.MeAgent1, SolverResult.MeAgent2);
                    }
                    Log("[SOLVER] SolverResultList.Count = {0}, score = {1}", SolverResultList.Count, score);
                }
                else
                {
                    return;
                }
                Log("[SOLVER] deepness = {0}", deepness);
            }
        }
Exemple #6
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        private int NegaMax(int deepness, SearchState state, int alpha, int beta, int count, PointEvaluator.Base evaluator, Decided ngMove, int greedyDepth)
        {
            if (deepness == 0)
            {
                for (int j = 0; j < greedyDepth; j++)
                {
                    Way move = state.MakeGreedyMove(ScoreBoard, WayEnumerator);
                    state.Move(move.Agent1Way, move.Agent2Way);
                    //Ways moves = state.MakeMoves(WayEnumerator);
                    //SortMoves(ScoreBoard, state, moves, 49, null);
                    //state.Move(moves[0].Agent1Way, moves[1].Agent2Way);
                }
                int score = evaluator.Calculate(ScoreBoard, state.MeBoard, 0) - evaluator.Calculate(ScoreBoard, state.EnemyBoard, 0);
                if (greedyDepth % 2 == 1)
                {
                    return(-score);
                }
                return(score);
            }

            Ways ways = state.MakeMoves(WayEnumerator);

            SortMoves(ScoreBoard, state, ways, count, ngMove);

            for (int i = 0; i < ways.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) && (ways[i].Agent1Way.Equals(ngMove.MeAgent1) || ways[i].Agent2Way.Equals(ngMove.MeAgent2)))
                {
                    continue;
                }                                                                                                                                                 //2人とも競合手とは違う手を指す

                SearchState nextState = state;
                nextState.Move(ways[i].Agent1Way, ways[i].Agent2Way);
                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, ways[i].Agent1Way, ways[i].Agent2Way);
                    }
                    else
                    {
                        dp2[count].UpdateScore(alpha, ways[i].Agent1Way, ways[i].Agent2Way);
                    }
                    if (alpha >= beta)
                    {
                        return(beta);               //βcut
                    }
                }
            }
            ways.Erase();
            WaysPool.Return(ways);
            return(alpha);
        }
        //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);
            }
        }
        //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);
        }
Exemple #9
0
        //1ターン = 深さ2
        protected override void Solve()
        {
            int i;

            for (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_AreaCount;
            SearchState         state     = new SearchState(MyBoard, EnemyBoard, new Player(MyAgent1, MyAgent2), new Player(EnemyAgent1, EnemyAgent2), WaysPool);

            //競合判定
            int K = KyogoTurn;              //Kは1以上の整数

            ngMove = null;
            for (i = 0; i < K; i++)
            {
                if (historyStates.Count < K)
                {
                    break;
                }
                int id = historyStates.Count - 1 - i;
                if (id < 0 || state.Equals(historyStates[id]) == false)
                {
                    break;
                }
                if (i + 1 < K && id > 0 && historyDecides[id].Equals(historyDecides[id - 1]) == false)
                {
                    break;
                }
            }
            if (i == K)
            {
                int score = PointEvaluator_Normal.Calculate(ScoreBoard, state.MeBoard, 0) - PointEvaluator_Normal.Calculate(ScoreBoard, state.EnemyBoard, 0);
                if (score <= 0)
                {
                    ngMove = historyDecides[historyDecides.Count - 1];
                    Log("[SOLVER] conclusion!, you cannot move to ", ngMove);
                }
            }

            //反復深化
            for (; deepness <= maxDepth; deepness++)
            {
                NegaMax(deepness, state, int.MinValue + 1, int.MaxValue, 0, evaluator, Math.Min(maxDepth - deepness, GreedyMaxDepth));
                if (CancellationToken.IsCancellationRequested == false)
                {
                    SolverResult = new Decided(dp[0].Agent1Way, dp[0].Agent2Way);
                }
                else
                {
                    break;
                }
                Log("[SOLVER] deepness = {0}", deepness);
            }

            //履歴の更新
            historyStates.Add(state);
            historyDecides.Add(SolverResult);
        }
Exemple #10
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        private int NegaMax(int deepness, SearchState state, int alpha, int beta, int count, PointEvaluator.Base evaluator, int greedyDepth)
        {
            if (deepness == 0)
            {
                //深さgreedyDepth分だけ貪欲をしてから、評価関数を呼び出す
                for (int i = 0; i < greedyDepth; i++)
                {
                    Ways moves = state.MakeMoves(WayEnumerator);
                    SortMoves(ScoreBoard, state, moves, dp.Length - 1);
                    state.Move(moves[0].Agent1Way, moves[0].Agent2Way);
                }
                int eval = evaluator.Calculate(ScoreBoard, state.MeBoard, 0) - evaluator.Calculate(ScoreBoard, state.EnemyBoard, 0);
                if (greedyDepth % 2 == 1)
                {
                    return(-eval);
                }
                return(eval);
            }

            Ways ways = state.MakeMoves(WayEnumerator);

            SortMoves(ScoreBoard, state, ways, count);

            for (int i = 0; i < ways.Count; i++)
            {
                if (CancellationToken.IsCancellationRequested == true)
                {
                    return(alpha);
                }                                                                           //何を返しても良いのでとにかく返す
                if (count == 0 && ngMove != null && new Decided(ways[i].Agent1Way, ways[i].Agent2Way).Equals(ngMove) == true)
                {
                    continue;
                }                                                                                                                                               //競合手は指さない

                SearchState backup = state;
                state.Move(ways[i].Agent1Way, ways[i].Agent2Way);
                int res = -NegaMax(deepness - 1, state, -beta, -alpha, count + 1, evaluator, greedyDepth);
                if (alpha < res)
                {
                    alpha = res;
                    dp[count].UpdateScore(alpha, ways[i].Agent1Way, ways[i].Agent2Way);
                    if (alpha >= beta)
                    {
                        return(beta);               //βcut
                    }
                }
                state = backup;
            }
            ways.Erase();
            WaysPool.Return(ways);
            return(alpha);
        }
Exemple #11
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);
            }
        }
Exemple #12
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        private int NegaMax(int deepness, SearchState state, int alpha, int beta, int count, PointEvaluator.Base evaluator)
        {
            if (deepness == 0)
            {
                return(evaluator.Calculate(ScoreBoard, state.MeBoard, 0) - evaluator.Calculate(ScoreBoard, state.EnemyBoard, 0));
            }

            Ways ways = state.MakeMoves(WayEnumerator);

            SortMoves(ScoreBoard, state, ways, count);

            for (int i = 0; i < ways.Count; i++)
            {
                if (CancellationToken.IsCancellationRequested == true)
                {
                    return(alpha);
                }                                                                                           //何を返しても良いのでとにかく返す
                SearchState backup = state;
                state.Move(ways[i].Agent1Way, ways[i].Agent2Way);
                int res = -NegaMax(deepness - 1, state, -beta, -alpha, count + 1, evaluator);
                if (alpha < res)
                {
                    alpha = res;
                    dp[count].UpdateScore(alpha, ways[i].Agent1Way, ways[i].Agent2Way);
                    if (alpha >= beta)
                    {
                        return(beta);                                   //βcut
                    }
                }
                state = backup;
            }
            ways.Erase();
            WaysPool.Return(ways);
            return(alpha);
        }
Exemple #13
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        //NegaMaxではない
        private int NegaMax(int deepness, SearchState state, int alpha, int count, PointEvaluator.Base evaluator, Decision ngMove, int nowAgent)
        {
            if (deepness == 0)
            {
                return(evaluator.Calculate(ScoreBoard, state, 0));
            }
            if (CancellationToken.IsCancellationRequested == true)
            {
                return(alpha);
            }                                                                           //何を返しても良いのでとにかく返す
            SingleAgentWays ways = state.MakeMovesSingle(AgentsCount, nowAgent, ScoreBoard);

            for (int i = 0; i < ways.Count; ++i)
            {
                var way = ways.Data[i];
                if (count == 0 && !(ngMove is null))    //競合手とは違う手を指す
                {
                    if (way == ngMove.Agents[nowAgent])
                    {
                        continue;
                    }
                }

                SearchState newState = state.GetNextStateSingle(nowAgent, way, ScoreBoard, deepness);

                //自エージェントとの衝突を防ぐ
                if (count == 0)
                {
                    int j = 0;
                    for (j = 0; j < AgentsCount; ++j)
                    {
                        if (j == nowAgent)
                        {
                            continue;
                        }
                        if (ngMove is null && dp1[count][j] == way)
                        {
                            break;
                        }
                        if (!(ngMove is null) && dp2[count][j] == way)
                        {
                            break;
                        }
                    }
                    if (j != AgentsCount)
                    {
                        continue;
                    }
                }
                int res = NegaMax(deepness - 1, newState, alpha, count + 1, evaluator, ngMove, nowAgent);
                if (alpha < res)
                {
                    alpha = res;
                    if (ngMove is null)
                    {
                        dp1[count][nowAgent] = way;
                    }
                    else
                    {
                        dp2[count][nowAgent] = way;
                    }
                }
            }

            //Log("NODES : {0} nodes, elasped {1} ", i, sw.Elapsed);
            ways.End();
            return(alpha);
        }
Exemple #14
0
        protected override void Solve()
        {
            var myAgents = SearchFirstPlace();

            Array.Clear(dp1, 0, dp1.Length);
            Array.Clear(dp2, 0, dp2.Length);

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

            PointEvaluator.Base evaluator = (TurnCount / 3 * 2) < CurrentTurn ? PointEvaluator_Normal : PointEvaluator_Dispersion;
            SearchState         state     = new SearchState(MyBoard, EnemyBoard, myAgents, EnemyAgents, MySurroundedBoard, EnemySurroundedBoard);
            int score = 0;

            for (uint x = 0; x < ScoreBoard.GetLength(0); ++x)
            {
                for (uint y = 0; y < ScoreBoard.GetLength(1); ++y)
                {
                    if (MyBoard[x, y])
                    {
                        score += ScoreBoard[x, y];
                    }
                    else if (MySurroundedBoard[x, y])
                    {
                        score += Math.Abs(ScoreBoard[x, y]);
                    }
                    else if (EnemyBoard[x, y])
                    {
                        score -= ScoreBoard[x, y];
                    }
                    else if (EnemySurroundedBoard[x, y])
                    {
                        score -= Math.Abs(ScoreBoard[x, y]);
                    }
                }
            }

            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();

                //普通にNegaMaxをして、最善手を探す
                for (int agent = 0; agent < AgentsCount; ++agent)
                {
                    if (MyAgentsState[agent] == AgentState.NonPlaced)
                    {
                        continue;
                    }
                    NegaMax(deepness, state, int.MinValue + 1, 0, evaluator, null, agent);
                }
                var res = dp1[0];
                for (int agent = 0; agent < AgentsCount; ++agent)
                {
                    if (MyAgentsState[agent] == AgentState.NonPlaced)
                    {
                        res[agent] = myAgents[agent];
                    }
                }
                Decision best1 = new Decision((byte)AgentsCount, res, agentStateAry);
                resultList.Add(best1);
                //競合手.Agent1 == 最善手.Agent1 && 競合手.Agent2 == 最善手.Agent2になった場合、競合手をngMoveとして探索をおこない、最善手を探す
                for (int i = 0; i < AgentsCount; ++i)
                {
                    if (IsAgentsMoved[i] || (!(lastTurnDecided is null) && lastTurnDecided.Agents[i] != best1.Agents[i]))
                    {
                        break;
                    }
                    if (i < AgentsCount - 1)
                    {
                        continue;
                    }

                    for (int agent = 0; agent < AgentsCount; ++agent)
                    {
                        if (MyAgentsState[agent] == AgentState.NonPlaced)
                        {
                            continue;
                        }
                        NegaMax(deepness, state, int.MinValue + 1, 0, evaluator, best1, agent);
                    }
                    res = dp2[0];
                    for (int agent = 0; agent < AgentsCount; ++agent)
                    {
                        if (MyAgentsState[agent] == AgentState.NonPlaced)
                        {
                            res[agent] = myAgents[agent];
                        }
                    }
                    Decision best2 = new Decision((byte)AgentsCount, res, agentStateAry);
                    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);
            }
        }
Exemple #15
0
        //Meが動くとする。「Meのスコア - Enemyのスコア」の最大値を返す。
        private int NegaMax(int deepness, SearchState state, int alpha, int beta, int count, PointEvaluator.Base evaluator)
        {
            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.GetEnumerator(AgentsCount))
            {
                i++;
                if (CancellationToken.IsCancellationRequested == true)
                {
                    return(alpha);
                }                                                                                           //何を返しても良いのでとにかく返す
                SearchState backup = state;
                state = state.GetNextState(AgentsCount, way);
                state = state.ChangeTurn();
                int res = -NegaMax(deepness - 1, state, -beta, -alpha, count + 1, evaluator);
                if (alpha < res)
                {
                    alpha = res;
                    dp[count].UpdateScore(alpha, way);
                    if (alpha >= beta)
                    {
                        return(beta);                                   //βcut
                    }
                }
                state = backup;
            }
            sw.Stop();
            Log("NODES : {0} nodes, elasped {1} ", i, sw.Elapsed);
            ways.End();
            return(alpha);
        }