예제 #1
0
        public override Intent Search(params Point[] prohibitedPoints)
        {
            //問題は、二回目以降の探索を行うときに起こる

            //Agent agent = new Agent();
            Field field = Game.Field.Clone(true, true, true);

            int    startTeam, startEnemy, beforeTeam, beforeEnemy, nextTeam, nextEnemy;
            int    needTurn;
            double delta;

            startTeam  = field.EvaluateMap(TeamEnum);
            startEnemy = field.EvaluateMap(EnemyEnum);

            //良いとされるルートを保持
            Node[] betterRoute = new Node[1];

            //敵の存在する確率を求めるクラスを保持
            var calculateExistenceProbability = new CalculateExistenceProbability(1);
            //Listで敵エージェントがそこに存在する確率を保持することで、オーバーヘッドを軽減
            List <double[, ]> agentsProbabilities = new List <double[, ]>();


            BetterRoute    = new Node[1];
            BetterRoute[0] = new Node();

            BetterEfficiency = double.MinValue;

            AStarSearch.Nodes.ForEach((r, n) =>
            {
                //エージェントの位置以外探索
                //おもすぎるので、相対位置が--の場合に変えるかも?

                if (n.Point != Agent.Position)
                {
                    AStarSearch.ResetResult();
                    AStarSearch.StartNode = AStarSearch.Nodes[Agent.Position.Y, Agent.Position.X];
                    AStarSearch.EndNodes  = new Node[] { n };

                    //禁止領域は予めクローズすることで対応
                    foreach (var p in prohibitedPoints)
                    {
                        AStarSearch.Nodes[p.Y, p.X].Status = NodeStatus.Closed;
                    }


                    //探索開始
                    AStarSearch.Search((c) =>
                    {
                        Point p = c.Point;
                        //まだ敵エージェントが存在する確率を計算していない
                        if (c.Turn >= agentsProbabilities.Count)
                        {
                            agentsProbabilities.Add(
                                calculateExistenceProbability.MapPossibilities(Enemy.Agent1.Position, Enemy.Agent2.Position, Game.Field.Width, Game.Field.Height, c.Turn)
                                );
                        }

                        //Score計算
                        ICell cell = Game.Field.GetCell(p);

                        //移動成功確率をセルに保持。移動成功確率は前の成功確率とこの移動ができる確率の積
                        c.SuccessProbability = (1.0 - agentsProbabilities[c.Turn - 1][p.Y, p.X]) * c.Parent.SuccessProbability;


                        //移動に伴うコストは、盤面の平均値とする
                        //要改善、失敗確率の累積を考えていない
                        //敵のタイル情報で場合分け
                        switch (cell.GetState(EnemyEnum))
                        {
                        case CellState.Occupied:
                            c.Turn++;     //敵のセルがある場合は、ターンが余計にかかるので、その分
                            agentsProbabilities.Add(
                                calculateExistenceProbability.MapPossibilities(Enemy.Agent1.Position, Enemy.Agent2.Position, Game.Field.Width, Game.Field.Height, c.Turn)
                                );
                            //2ターン必要ということで、成功確率も減る
                            c.SuccessProbability *= (1.0 - agentsProbabilities[c.Turn - 1][p.Y, p.X]);

                            return(16 - cell.Score * c.SuccessProbability + 2 * averageScore);

                        case CellState.InRegion:
                            return(16 - cell.Score * c.SuccessProbability + 1 * averageScore);
                        }
                        //自チームのタイル状況で場合分け
                        switch (cell.GetState(TeamEnum))
                        {
                        case CellState.None:
                            return(16 - cell.Score * c.SuccessProbability + 1 * averageScore);

                        case CellState.Occupied:
                            return(16 + 0 * c.SuccessProbability + 1 * averageScore);

                        case CellState.InRegion:
                            //取るとかえって損なセルがある
                            if (cell.Score >= 0)
                            {
                                return(16 + 0 * c.SuccessProbability + 1 * averageScore);
                            }
                            else
                            {
                                return(16 - cell.Score * c.SuccessProbability + 1 * averageScore);
                            }

                        default:
                            //ここに来ることはありえない
                            return(16 - cell.Score * c.SuccessProbability + 1 * averageScore);
                        }
                    }, (c) =>
                    {
                        //HeuristicScore計算
                        Point pos       = c.Point - Agent.Position;
                        double minSteps = Math.Max(Math.Abs(pos.X), Math.Abs(pos.Y));
                        return((int)((16 - averageScore + 1) * minSteps));
                    });

                    //実際に移動させてみて得点がどうなるかを見る
                    field = Game.Field.Clone(true, true, true);

                    field.AutoEvaluate = false;

                    nextTeam  = beforeTeam = startTeam;
                    nextEnemy = beforeEnemy = startEnemy;

                    needTurn = 0;
                    delta    = 0;

                    //一つづつチェック
                    foreach (var node1 in AStarSearch.BestWayNodes)
                    {
                        if (field.Map[node1.Point.Y, node1.Point.X].GetState(TeamEnum) != CellState.Occupied)
                        {
                            field.Map[node1.Point.Y, node1.Point.X].SetState(TeamEnum, CellState.Occupied);
                            //値の変化を見る
                            nextTeam = field.EvaluateMap(TeamEnum);
                        }
                        //相手に占有されていたらその分ターンが必要なので
                        if (field.Map[node1.Point.Y, node1.Point.X].GetState(EnemyEnum) == CellState.Occupied)
                        {
                            needTurn++;
                            field.Map[node1.Point.Y, node1.Point.X].SetState(EnemyEnum, CellState.None);
                            nextEnemy = field.EvaluateMap(EnemyEnum);
                        }



                        delta += ((nextTeam - beforeTeam) - (nextEnemy - beforeEnemy)) * node1.SuccessProbability;

                        beforeTeam  = nextTeam;
                        beforeEnemy = nextEnemy;

                        needTurn++;//必要ターン加算
                    }

                    //よりよい経路が見つかったら
                    if (BetterEfficiency < delta / needTurn)
                    {
                        betterRoute = AStarSearch.BestWayNodes.ToArray();
                        //最後のノードに推定能率を保持
                        BetterEfficiency = delta / needTurn;
                        NeedTurn         = needTurn;
                    }
                }
            });
            //結果を保存
            BetterRoute = betterRoute;

            //得られた結果をWayクラスに変換
            Way = new Way(Agent, BetterRoute.Select(node2 => node2.Point).ToArray());
            Point agentNextPos;

            //次を取り出す
            Way.Peep(out agentNextPos, out Direction direction);


            return(Game.GetIntent(Agent, direction));
        }