Пример #1
0
        protected override ScoringEfficiency EvaluateGame()
        {
            //移動によるスコアを計算
            if (BetterRoute != null)
            {
                int    nowIndex = BetterRoute.ToList().FindIndex((n) => n.Point == Agent.Position);
                int    beforeTeam, beforeEnemy, nextTeam, nextEnemy;
                int    needTurn = 0;
                double delta    = 0.0;
                //移動させて推定得点を出すために、フィールドを複製
                Field field = Game.Field.Clone(true, true, true);
                //敵の存在する確率を求めるクラスを保持
                var calculateExistenceProbability = new CalculateExistenceProbability(1);

                //初期値を設定
                beforeTeam  = field.EvaluateMap(TeamEnum);
                beforeEnemy = field.EvaluateMap(EnemyEnum);


                //一つづつ移動してみて、推定能率を計算
                foreach (var node1 in BetterRoute.ToList().Skip(nowIndex))
                {
                    //ターン追加
                    needTurn++;
                    //自チームにタイルを置く
                    field.Map[node1.Point.Y, node1.Point.X].SetState(TeamEnum, CellState.Occupied);
                    //相手に占有されていたらその分ターンが必要なので
                    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);

                    //値の変化を見る
                    nextTeam  = field.GetScore(TeamEnum);
                    nextEnemy = field.GetScore(EnemyEnum);
                    delta    += ((nextTeam - beforeTeam) - (nextEnemy - beforeEnemy))
                                * (1 - calculateExistenceProbability.MapPossibilities(Enemy.Agent1.Position, Enemy.Agent2.Position, field.Width, field.Height, needTurn)[node1.Point.Y, node1.Point.X]);

                    beforeTeam  = nextTeam;
                    beforeEnemy = nextEnemy;
                }

                //得点を計算
                return(new ScoringEfficiency(delta, needTurn));
            }

            //経路がない場合
            return(new ScoringEfficiency(0, 0));
        }
        public override Intent Search(params Point[] prohibitedPoints)
        {
            //探索内最高点差を保持
            double bestScoreDifference = double.MinValue;
            //一時的な差を保持
            double delta;


            //エージェントの経路を保持
            Direction[] route;
            Direction[] bestDirections = new Direction[Depth];

            /*探索した部分をもとに戻すためのリスト*/
            List <Point> points = new List <Point>();

            //nターンで取れる行動を列挙するクラスEnumerateRoutesのインスタンスを作成
            EnumerateRoutes enumerateRoutes = new EnumerateRoutes
            {
                Turn = Depth
            };

            //作業用変数
            int   i;
            Agent agent = new Agent(); /*探索用*/
            Point agentNextPos;

            ICell[,] map = Game.Field.Map.Clones();

            int startTeam = EvaluateMap(map, TeamEnum), startEnemy = EvaluateMap(map, EnemyEnum), beforeTeam, beforeEnemy, nextTeam, nextEnemy;



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

            i = 1;
            //敵エージェント存在確率保持
            while (Depth >= i)
            {
                agentsProbabilities.Add(
                    CalculateExistenceProbability.MapPossibilities(
                        Enemy.Agent1.Position,
                        Enemy.Agent2.Position,
                        Game.Field.Width,
                        Game.Field.Height,
                        i)
                    );
                i++;
            }


            //最善手を探す
            while (enumerateRoutes.HasNext)
            {
                //経路の取得
                route = enumerateRoutes.Next();

                //初手 移動 or タイル除去 ができる場合のみを考える
                if (Game.CanMove(Agent, route[0]) || Game.CanRemove(Agent, route[0]))
                {
                    //エージェント情報のコピー
                    agent.Position = Agent.Position;
                    //マップをコピー
                    foreach (var p in points)
                    {
                        map[p.Y, p.X].State1 = Map[p.Y, p.X].State1;
                        map[p.Y, p.X].State2 = Map[p.Y, p.X].State2;
                    }

                    //書き換えた経路をリセット
                    points.Clear();

                    delta = 0.0;

                    beforeTeam  = startTeam;
                    beforeEnemy = startEnemy;

                    //取り出した経路にしたがってエージェントを動かす
                    for (i = 0; i < Depth; i++)
                    {
                        //移動した場合の場所を検索
                        agentNextPos = agent.Position.FastMove(route[i]);
                        //移動した先がちゃんとマップ内であり、禁止領域でなければ移動
                        if (!(agentNextPos.X < 0 || agentNextPos.Y < 0 || agentNextPos.X >= Width || agentNextPos.Y >= Height) && prohibitedPoints.All(p => p != agentNextPos))
                        {
                            points.Add(agentNextPos);
                            AgentMove(map, TeamEnum, agent, route[i]);

                            nextTeam    = EvaluateMap(map, TeamEnum);
                            nextEnemy   = EvaluateMap(map, EnemyEnum);
                            delta      += ((nextTeam - beforeTeam) - (nextEnemy - beforeEnemy)) * (1.0 - agentsProbabilities[i][agentNextPos.Y, agentNextPos.X]);
                            beforeTeam  = nextTeam;
                            beforeEnemy = nextEnemy;
                        }
                        else
                        {
                            //マップ外にでてしまった場合
                            goto NextRoutes;  //マップ外に出るような移動は考えない
                        }
                    }

                    //より高い得点を得られる経路であれば
                    if (delta > bestScoreDifference)
                    {   //方向の更新
                        route.CopyTo(bestDirections, 0);
                        //最高得点の更新
                        bestScoreDifference = delta;
                    }
                }
                NextRoutes :;
            }
            BestDeltaScore = bestScoreDifference;

            //最善経路の保持
            Way = new Way(Agent, bestDirections);
            Way.Next(out agentNextPos, out Direction direction);


            Intent Intent = new Intent()
            {
                Intention = Intentions.Stay,
                Direction = direction
            };

            //移動先に移動できれば移動する意志に、敵タイルがあれば除去
            if (Game.CanMove(Agent, direction))
            {
                Intent.Intention = Intentions.Move;
            }
            else if (Game.CanRemove(Agent, direction))
            {
                Intent.Intention = Intentions.Remove;
            }


            return(Intent);
        }
Пример #3
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));
        }