Beispiel #1
0
        static Cell FindNearestCell(ACircularUnit my)
        {
            double ds = Const.MapSize / GridSize;

            var    I = (int)(my.X / ds + Const.Eps);
            var    J = (int)(my.Y / ds + Const.Eps);
            int    seldI = int.MaxValue, seldJ = int.MaxValue;
            double minDist   = int.MaxValue;
            var    obstacles = _obstacles
                               .Concat(BuildingsObserver.Buildings)
                               .Concat(TreesObserver.Trees)
                               .ToArray();

            for (var di = 0; di < 2; di++)
            {
                for (var dj = 0; dj < 2; dj++)
                {
                    var dst = WizardPath.GetSegmentWeight(_points[I + di, J + dj], my, true);
                    if (dst < minDist &&
                        obstacles.All(ob =>
                                      !Geom.SegmentCircleIntersects(my, _points[I + di, J + dj], ob, ob.Radius + my.Radius + MagicConst.RadiusAdditionalEpsilon))
                        )
                    {
                        minDist = dst;
                        seldI   = di;
                        seldJ   = dj;
                    }
                }
            }
            if (seldI == int.MaxValue)
            {
                return(null);
            }
            return(new Cell(I + seldI, J + seldJ));
        }
Beispiel #2
0
        public static void DijkstraStart(Cell start, DijkstraCellStopFunc stopCondition, DijkstraPointCostFunc costFunc)
        {
            var q = new PriorityQueue <Pair <double, Cell> >();

            q.Push(new Pair <double, Cell>(0.0, start));
            for (var i = 0; i <= GridSize; i++)
            {
                for (var j = 0; j <= GridSize; j++)
                {
                    _distMap[i, j]  = Const.Infinity;
                    _distPrev[i, j] = null;
                }
            }

            _distMap[start.I, start.J] = 0;
            while (q.Count > 0)
            {
                var cur     = q.Top().Second;
                var minDist = -q.Top().First;
                q.Pop();

                if (minDist > _distMap[cur.I, cur.J])
                {
                    continue;
                }

                if (stopCondition(cur))
                {
                    break;
                }

                for (var k = 0; k < _dx.Length; k++)
                {
                    var I = cur.I + _dx[k];
                    var J = cur.J + _dy[k];
                    if (I < 0 || J < 0 || I > GridSize || J > GridSize)
                    {
                        continue;
                    }

                    var distTo = _distMap[cur.I, cur.J] + WizardPath.GetSegmentWeight(_points[cur.I, cur.J], _points[I, J], false);
                    if (costFunc != null)
                    {
                        distTo += costFunc(_points[I, J]);
                    }

                    if (distTo < _distMap[I, J] && CanPass(_points[cur.I, cur.J], _points[I, J]))
                    {
                        _distMap[I, J]  = distTo;
                        _distPrev[I, J] = cur;
                        q.Push(new Pair <double, Cell>(-distTo, new Cell(I, J)));
                    }
                }
                ;
            }
        }
Beispiel #3
0
        public static WizardPath[] DijkstraFindPath(AWizard start, DijkstraPointStopFunc stopFunc, DijkstraPointCostFunc costFunc)
        {
            start       = new AWizard(start);
            _startState = start;

            _obstacles = Combats
                         .Where(x => !x.IsOpponent && x.Id != start.Id && x.GetDistanceTo2(start) < Geom.Sqr(start.VisionRange)) // (нейтральные включительно)
                         .ToArray();

            var startCell = FindNearestCell(start);

            if (startCell == null)
            {
                return new WizardPath[] {}
            }
            ;

            var endCells = new List <Cell>();

            DijkstraStart(startCell, cell =>
            {
                var point  = _points[cell.I, cell.J];
                var status = stopFunc(point);

                if (status == DijkstraStopStatus.Take || status == DijkstraStopStatus.TakeAndStop)
                {
                    endCells.Add(cell);
                }

                if (status == DijkstraStopStatus.Stop || status == DijkstraStopStatus.TakeAndStop)
                {
                    return(true);
                }
                return(false);
            }, costFunc);

            return(endCells.Select(endCell =>
            {
                var cellsPath = DijkstraGeneratePath(startCell, endCell);

                var res = new WizardPath {
                    start
                };
                res.AddRange(cellsPath.Select(cell => _points[cell.I, cell.J]));
                return res;
            }).ToArray());
        }
    }
Beispiel #4
0
        WizardPath _goAround(ACombatUnit target, bool goAgainst)
        {
            var my              = new AWizard(ASelf);
            var selLane         = Utility.IsBase(target) ? MessagesObserver.GetLane() : RoadsHelper.GetLane(target);
            var nearestBuilding = OpponentBuildings.ArgMin(b => b.GetDistanceTo2(my));

            var buildings = new List <ABuilding>();

            if (nearestBuilding.GetDistanceTo(my) > nearestBuilding.VisionRange)
            {
                buildings.Add(nearestBuilding);
            }
            if (target.IsOpponent && target.Id != nearestBuilding.Id && target is ABuilding)
            {
                buildings.Add((ABuilding)target);
            }

            var threshold = Self.CastRange - 200;

            if (ASelf.GetDistanceTo(target) < Self.CastRange || !goAgainst)
            {
                threshold = 0;
            }

            var path = DijkstraFindPath(ASelf, pos =>
            {
                // точка ОК, если с неё можно стрелять
                var dist2 = pos.GetDistanceTo2(target);
                if (dist2 < Geom.Sqr(Self.CastRange) && dist2 > Geom.Sqr(threshold))
                {
                    var distToLine = RoadsHelper.Roads.Where(seg => seg.LaneType == selLane).Min(seg => seg.GetDistanceTo(pos));

                    if (distToLine < 200 &&
                        (!goAgainst || BuildingsObserver.MyBase.GetDistanceTo2(pos) < BuildingsObserver.MyBase.GetDistanceTo2(target)) &&
                        TreesObserver.Trees
                        .Where(x => x.GetDistanceTo2(pos) < Geom.Sqr(Self.CastRange))
                        .All(x => !Geom.SegmentCircleIntersects(pos, target, x, x.Radius + Game.MagicMissileRadius))
                        )
                    {
                        return(DijkstraStopStatus.TakeAndStop);
                    }
                }
                return(DijkstraStopStatus.Continue);
            }, MoveCostFunc(buildings, selLane)).FirstOrDefault();

            if (path == null && my.GetDistanceTo(target) - my.Radius - target.Radius <= 1)
            {
                path = new WizardPath {
                    my
                }
            }
            ;                                 // из-за эпсилон, если стою близко у цели, то он как бы с ней пересекается, но это не так
            if (path == null || path.Count == 0)
            {
                return(null);
            }

            if (path.Count == 1)
            {
                FinalMove.Turn = my.GetAngleTo(target);
                return(null);
            }

            var obstacles =
                Combats.Where(x => x.Id != Self.Id).Cast <ACircularUnit>()
                .Where(x => my.GetDistanceTo2(x) < Geom.Sqr(my.VisionRange)) //???
                .ToArray();

            path.Simplify(obstacles, MagicConst.SimplifyMaxLength);

            var nextPoint     = path[1];
            var nextNextPoint = path.Count > 2 ? path[2] : target;

            FinalMove.MoveTo(nextPoint, my.GetDistanceTo(nextNextPoint) < Self.VisionRange * 1.2 ? nextNextPoint : nextPoint);

            var nextTree = path.GetNearestTree();

            CutTreesInPath(nextTree, FinalMove);
#if DEBUG
            Visualizer.Visualizer.SegmentsDrawQueue.Add(new object[] { path, Pens.Blue, 3 });
#endif
            return(path);
        }

        void CutTreesInPath(ATree nextTree, FinalMove move)
        {
            if (nextTree == null)
            {
                return;
            }
            var my = new AWizard(ASelf);

            var angleTo = my.GetAngleTo(nextTree);

            if (my.GetDistanceTo(nextTree) < my.VisionRange && Math.Abs(angleTo) > Game.StaffSector / 2)
            {
                move.MoveTo(null, nextTree);
            }

            if (my.RemainingActionCooldownTicks == 0 && Math.Abs(angleTo) <= Game.StaffSector / 2)
            {
                if (my.GetDistanceTo(nextTree) <= Game.StaffRange + nextTree.Radius && my.RemainingStaffCooldownTicks == 0)
                {
                    move.Action = ActionType.Staff;
                }
                else if (my.GetDistanceTo(nextTree) <= my.CastRange + nextTree.Radius && my.RemainingMagicMissileCooldownTicks == 0)
                {
                    move.Action          = ActionType.MagicMissile;
                    move.CastAngle       = angleTo;
                    move.MinCastDistance = Math.Min(my.CastRange - 1, my.GetDistanceTo(nextTree));
                }
            }
        }

        MovingInfo GoToBonus()
        {
            TimerStart();
            var ret = _goToBonus();

            TimerEndLog("GoToBonus", 1);
            return(ret);
        }

        bool _skipBonusCond(ABonus bonus)
        {
            var oppFirst = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsOpponent && x.Lane == MessagesObserver.GetLane() && x.Order == 0);

            if (oppFirst == null || ASelf.GetDistanceTo(oppFirst) <= oppFirst.CastRange)
            {
                return(true);
            }

            var myFirst = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsTeammate && x.Lane == MessagesObserver.GetLane() && x.Order == 0);

            if (myFirst == null || OpponentWizards.Any(x => x.GetDistanceTo(myFirst) <= myFirst.Radius))
            {
                return(true);
            }

            // TODO
            return(false);
        }

        ABonus SelectBonus(AWizard self)
        {
            var bonus = BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo2(self));

            if (bonus.RemainingAppearanceTicks > MagicConst.GoToBonusMaxTicks + MagicConst.BonusTimeReserve)
            {
                return(null);
            }

            if (self.GetDistanceTo(BuildingsObserver.OpponentBase) < BuildingsObserver.OpponentBase.CastRange * 1.4)
            {
                return(null);
            }

            if (Game.IsSkillsEnabled && _skipBonusCond(bonus))
            {
                return(null);
            }

            return(bonus);
        }

        MovingInfo _goToBonus()
        {
            var bonus         = SelectBonus(ASelf);
            var selMovingInfo = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));

            if (bonus == null)
            {
                return(selMovingInfo);
            }

            if (Const.IsFinal)
            {
                var teammates = MyWizards
                                .Where(x => x.Id != ASelf.Id)
                                .Where(x =>
                {
                    var b = SelectBonus(x);
                    return(b != null && b.Id == bonus.Id);
                })
                                .ToArray();
                if (teammates.Any(x => ASelf.GetDistanceTo(bonus) > x.GetDistanceTo(bonus)))
                {
                    return(selMovingInfo);
                }
            }

            var my = new AWizard(ASelf);
            var nearestBuilding = OpponentBuildings.ArgMin(b => b.GetDistanceTo2(my));

            var path = DijkstraFindPath(ASelf, pos =>
            {
                // точка ОК, если бонус совсем близко
                if (pos.GetDistanceTo2(bonus) < Geom.Sqr(bonus.Radius + Self.Radius + 35))
                {
                    return(DijkstraStopStatus.TakeAndStop);
                }

                return(DijkstraStopStatus.Continue);
            }, MoveCostFunc(new [] { nearestBuilding }, MessagesObserver.GetLane())).FirstOrDefault();

            if (path == null)
            {
                GoDirect(bonus, selMovingInfo.Move);
                selMovingInfo.Target = bonus;
                return(selMovingInfo);
            }

            var obstacles =
                Combats.Where(x => x.Id != Self.Id).Cast <ACircularUnit>()
                .Where(x => my.GetDistanceTo2(x) < Geom.Sqr(my.VisionRange))
                .ToArray();

            path.Add(bonus);
            path.Simplify(obstacles, MagicConst.SimplifyMaxLength);


            var time = (int)(path.GetLength() / my.MaxForwardSpeed);

            if (time < MagicConst.GoToBonusMaxTicks)
            {
                selMovingInfo.Time = time;

                var nextPoint     = path[1];
                var nextNextPoint = path.Count > 2 ? path[2] : nextPoint;
                selMovingInfo.Move = new FinalMove(new Move());
                selMovingInfo.Move.MoveTo(nextPoint, my.GetDistanceTo(nextNextPoint) < my.Radius + 20 ? nextNextPoint : nextPoint);
                selMovingInfo.Target = nextPoint;

                var nextTree = path.GetNearestTree();
                CutTreesInPath(nextTree, selMovingInfo.Move);
            }

            if (selMovingInfo.Time <= bonus.RemainingAppearanceTicks - MagicConst.BonusTimeReserve)
            {
                selMovingInfo.Target = null;
            }
#if DEBUG
            if (selMovingInfo.Target != null)
            {
                Visualizer.Visualizer.SegmentsDrawQueue.Add(new object[] { path, Pens.Red, 3 });
            }
#endif
            return(selMovingInfo);
        }
Beispiel #5
0
        private void _move(Wizard self, World world, Game game, Move move)
        {
            World     = world;
            Game      = game;
            Self      = self;
            FinalMove = new FinalMove(move);

            Const.Initialize();
            MagicConst.TreeObstacleWeight = Const.IsFinal ? 25 : 35;

            Wizards = world.Wizards
                      .Select(x => new AWizard(x))
                      .ToArray();

            foreach (var wizard in Wizards)
            {
                foreach (var other in Wizards)
                {
                    if (wizard.Faction != other.Faction)
                    {
                        continue;
                    }
                    if (wizard.GetDistanceTo2(other) > Geom.Sqr(Game.AuraSkillRange))
                    {
                        continue;
                    }

                    for (var i = 0; i < 5; i++)
                    {
                        wizard.AurasFactorsArr[i] = Math.Max(wizard.AurasFactorsArr[i], other.SkillsLearnedArr[i] / 2);
                    }
                }
                var orig   = World.Wizards.FirstOrDefault(w => w.Id == wizard.Id);
                var player = World.Players.FirstOrDefault(p => orig != null && p.Id == orig.OwnerPlayerId);
                if (player != null && player.IsStrategyCrashed)
                {
                    wizard.RemainingFrozen = 100500;
                }
            }

            OpponentWizards = Wizards
                              .Where(x => x.IsOpponent)
                              .ToArray();

            MyWizards = Wizards
                        .Where(x => x.IsTeammate)
                        .ToArray();

            Minions = world.Minions
                      .Select(x => x.Type == MinionType.OrcWoodcutter ? (AMinion) new AOrc(x) : new AFetish(x))
                      .ToArray();

            NeutralMinions = Minions
                             .Where(x => x.Faction == Faction.Neutral)
                             .ToArray();

            Combats =
                Minions.Cast <ACombatUnit>()
                .Concat(Wizards)
                .Concat(BuildingsObserver.Buildings)//TODO перед BuildingsObserver.Update????
                .ToArray();

            MyCombats = Combats
                        .Where(x => x.IsTeammate)
                        .ToArray();

            NeutralMinionsObserver.Update();
            OpponentMinions = Minions
                              .Where(x => x.IsOpponent)
                              .ToArray();

            OpponentCombats = Combats
                              .Where(x => x.IsOpponent)
                              .ToArray();

            RoadsHelper.Initialize();
            BuildingsObserver.Update();

            OpponentBuildings = BuildingsObserver.Buildings
                                .Where(x => x.IsOpponent)
                                .ToArray();

            TreesObserver.Update();
            ProjectilesObserver.Update();
            BonusesObserver.Update();
            MessagesObserver.Update();

            InitializeProjectiles();
            InitializeDijkstra();

            ASelf = Wizards.FirstOrDefault(x => x.Id == Self.Id);
            if (ASelf == null)
            {
                throw new Exception("Self not found in wizards list");
            }

            InitializeDangerEstimation();
            SupportObserver.Update();

            if (Self.IsMaster && World.TickIndex == 0)
            {
                MasterSendMessages();
            }
            if (Self.IsMaster)
            {
                MasterCheckRearrange();
            }

            var nearestBonus         = BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo(ASelf));
            var opponentsAroundBonus = OpponentWizards.Where(w => nearestBonus.GetDistanceTo(w) < ASelf.VisionRange * 1.5).ToArray();
            var teammatesAroundBonus = MyWizards.Where(w => ASelf.GetDistanceTo(w) < ASelf.VisionRange * 1.5).ToArray();



            WizardPath path        = null;
            AUnit      pathTarget  = null;
            var        goAway      = GoAwayDetect();
            var        bonusMoving = goAway ? new MovingInfo(null, int.MaxValue, null) : GoToBonus();
            var        target      = FindTarget(new AWizard(ASelf), bonusMoving.Target);

            if (target == null && bonusMoving.Target == null && !goAway)
            {
                var nearest = OpponentCombats
                              .Where(
                    x =>
                    Utility.IsBase(x) || RoadsHelper.GetLane(x) == MessagesObserver.GetLane() ||
                    RoadsHelper.GetLaneEx(ASelf) == ALaneType.Middle &&
                    RoadsHelper.GetLaneEx(x) == ALaneType.Middle && CanRush(ASelf, x))
                              .Where(x => x.IsAssailable && x.Faction != Faction.Neutral)
                              .OrderBy(
                    x =>
                    x.GetDistanceTo(self) +
                    (x is AWizard ? -40 : (x is ABuilding && !((ABuilding)x).IsBesieded) ? 1500 : 0))
                              .ToArray();

                foreach (var n in nearest)
                {
                    path = GoAgainst(n);
                    if (path != null)
                    {
                        pathTarget = n;
                        break;
                    }
                }
                if (nearest.Length > 0 && path == null)
                {
                    GoDirect(nearest[0], FinalMove);
                }
            }

            TimerStart();
            if (!TryDodgeProjectile())
            {
                if (target == null)
                {
                    TryPreDodgeProjectile();
                }

                if (goAway)
                {
                    GoAway();
                }
                else if (target == null || target.Type == TargetType.Teammate ||
                         (FinalMove.Action == ActionType.Staff ||
                          FinalMove.Action == ActionType.MagicMissile ||
                          FinalMove.Action == ActionType.Fireball ||
                          FinalMove.Action == ActionType.FrostBolt) && target.Type == TargetType.Opponent)
                {
                    if (bonusMoving.Target != null)
                    {
                        NextBonusWaypoint = bonusMoving.Target;
                        FinalMove.Turn    = bonusMoving.Move.Turn;
                        if (bonusMoving.Move.Action != ActionType.None && bonusMoving.Move.Action != null)
                        {
                            FinalMove.Action          = bonusMoving.Move.Action;
                            FinalMove.MinCastDistance = bonusMoving.Move.MinCastDistance;
                            FinalMove.MaxCastDistance = bonusMoving.Move.MaxCastDistance;
                            FinalMove.CastAngle       = bonusMoving.Move.CastAngle;
                        }

                        NextBonusWaypoint = ASelf + (NextBonusWaypoint - ASelf).Normalized() * (Self.Radius + 30);

                        if (nearestBonus.GetDistanceTo(ASelf) < ASelf.VisionRange * 1.5 &&
                            nearestBonus.GetDistanceTo(ASelf) > 100 &&
                            opponentsAroundBonus.Length <= 1 &&
                            ASelf.Life + 10 >= (opponentsAroundBonus.FirstOrDefault() ?? ASelf).Life &&
                            OpponentMinions.Count(x => x.GetDistanceTo(ASelf) < Game.FetishBlowdartAttackRange) == 0
                            )
                        {
                            FinalMove.MoveTo(NextBonusWaypoint, null);
                        }
                        else
                        {
                            TryGoByGradient(x => EstimateDanger(x), null, FinalMove);
                        }
                    }
                    else
                    {
                        var all = Combats.Select(Utility.CloneCombat).ToArray();
                        var my  = all.FirstOrDefault(x => x.Id == ASelf.Id) as AWizard;

                        my?.Move(FinalMove.Speed, FinalMove.StrafeSpeed);
                        var ts = new TargetsSelector(all);

                        var skipBuildings = path == null ||
                                            path.GetLength() < 300 ||
                                            path.GetLength() < 600 && OpponentBuildings.Any(x =>
                        {
                            var tar = ts.Select(x);
                            return(tar != null && tar.Id == ASelf.Id);
                        });


                        if (TryGoByGradient(x => EstimateDanger(x), x => HasAnyTarget(x, skipBuildings), FinalMove))
                        {
                            var cutTreeMovingInfo = FindTreeTarget(ASelf);
                            if (cutTreeMovingInfo.Target != null)
                            {
                                FinalMove.Turn = cutTreeMovingInfo.Move.Turn;
                                if (cutTreeMovingInfo.Move.Action != null && FinalMove.Action == null)
                                {
                                    FinalMove.Action = cutTreeMovingInfo.Move.Action;
                                }
                                // не будет мешать TryPreDodgeProjectile?
                            }
                        }
                    }
                }

                PostDodgeProjectile();
            }
            TimerEndLog("Go", 1);

            if (ASelf.CanLearnSkill)
            {
                move.SkillToLearn = MessagesObserver.GetSkill();
            }
        }