Esempio n. 1
0
        public bool Intersect(ACar car, double extendRadius)
        {
            if (Type == ProjectileType.Washer)
            {
                return(Geom.ContainPoint(car.GetRect(-extendRadius), this));
            }

            var r = Radius + extendRadius;

            if (GetDistanceTo2(car) > Geom.Sqr(r + Const.CarDiagonalHalfLength))
            {
                return(false);
            }

            return(car.GetRectEx().Any(p => GetDistanceTo(p) < r));
        }
Esempio n. 2
0
        public bool CheckUseOil()
        {
            if (self.RemainingOilCooldownTicks != 0 || world.Tick < Const.Game.InitialFreezeDurationTicks)
            {
                return(false);
            }
            if (self.EnginePower < 0)
            {
                return(false);
            }

            var slick  = new AOilSlick(new ACar(self));
            var rad    = slick.Radius * 0.8;
            var result = false;

            for (var t = 0; t < MagicConst.OpponentsTicksPrediction; t++)
            {
                for (var i = 0; i < Opponents.Length; i++)
                {
                    if (slick.GetDistanceTo2(OpponentsCars[i][t]) < rad * rad &&
                        (self.OilCanisterCount > 1 || Math.Abs(OpponentsCars[i][t].WheelTurn) > 0.2))
                    {
                        result = true;
                    }
                }
            }
            if (!result)
            {
                return(false);
            }

            foreach (var my in MyTeam)
            {
                if (my == null)
                {
                    continue;
                }
                foreach (var pos in my)
                {
                    if (pos.GetDistanceTo2(slick) < Geom.Sqr(slick.Radius))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Esempio n. 3
0
        public Moves Do(ACar car, Points pts)
        {
            // Проверка что данный путь был выбран
            if (_selectThisTick + 1 != MyStrategy.world.Tick)
            {
                _lastSuccessStack = null;
            }

            Self = car.Clone();

            if (_lastCall == LastSuccess)
            {
                LastSuccess = _lastCall;
            }

            for (var t = 0; t < MyStrategy.world.Tick - _lastCall && _lastSuccessStack != null && _lastSuccessStack.Count > 0; t++)
            {
                _lastSuccessStack[0].Times--;
                _lastSuccessStack.Normalize();
            }
            if (_lastSuccessStack != null && (_lastSuccessStack.Count == 0 || _useDist2 && _lastSuccessStack.ComputeTime() < 30))
            {
                _lastSuccessStack = null;
            }

            _lastCall = MyStrategy.world.Tick;

            /*
             * Количество бонусов на расстоянии 0.5t
             * Если изменилось - пересчитывать сильно
             */
            var bonusesCount05 = MyStrategy.Bonuses
                                 .Count(bonus => Self.GetDistanceTo(bonus) < Const.TileSize / 2);

            /*
             * Количество бонусов на расстоянии 2t
             * Если изменилось - чуть нужно пересчитать
             */
            var bonusesCount2 = MyStrategy.Bonuses
                                .Count(
                bonus =>
                Self.GetDistanceTo(bonus) < Const.TileSize * 2 &&
                MyStrategy.CellDistance(Self, bonus) <= 2);

            // Если был success на прошлом тике, то продолжаем. Или каждые _interval тиков.
            if (Const.Game.InitialFreezeDurationTicks < MyStrategy.world.Tick &&
                bonusesCount05 == _bonusesCount05 &&
                LastSuccess < MyStrategy.world.Tick - 1 &&
                (MyStrategy.world.Tick - (LastSuccess + 1)) % _interval != 0)
            {
                _validateLastSuccessStack();
                return(_lastSuccessStack);
            }

            /*
             * Смотрим на шины, которые на расстоянии не более 6 тайлов
             */
            var prevProj = _projCandidates;

            _projCandidates = MyStrategy.Tires
                              .Where(
                proj =>
                Self.GetDistanceTo(proj[0]) <= Const.TileSize * 6 &&
                MyStrategy.CellDistance(Self, proj[0]) <= 6)
                              .ToArray();

            var extended = MyStrategy.ExtendWaySegments(pts, 50);

            _bruteWayPoints = extended.GetRange(0, Math.Min(_waypointsCount, extended.Count)).ToArray();
            if (LastStageMove.IsUseNitro && _turnsCount(_bruteWayPoints) > 1)
            {
                return(null);
            }
#if DEBUG
            var bruteWayPoints = new Points();
            bruteWayPoints.AddRange(_bruteWayPoints);
            Visualizer.SegmentsDrawQueue.Add(new object[] { Brushes.Brown, bruteWayPoints, 0.0 });
#endif
            _needDist  = Const.TileSize * 0.5 - 3;
            _needDist2 = Const.TileSize - 3;
            _turnTo    = _bruteWayPoints[_bruteWayPoints.Length - 1];
            _turnTo2   = _bruteWayPoints[Math.Min(_bruteWayPoints.Length - 1, (int)(_bruteWayPoints.Length * 0.83))];
#if DEBUG
            Visualizer.CircleFillQueue.Add(new Tuple <Brush, ACircularUnit>(Brushes.OrangeRed, new ACircularUnit {
                X = _turnTo.X, Y = _turnTo.Y, Radius = 20
            }));
            Visualizer.CircleFillQueue.Add(new Tuple <Brush, ACircularUnit>(Brushes.Orange, new ACircularUnit {
                X = _turnTo2.X, Y = _turnTo2.Y, Radius = 20
            }));
#endif

            _patterns = Patterns.Select(pt => new PathPattern
            {
                From = pt.From,
                To   = pt.To,
                Step = pt.Step,
                Move = pt.Move.Clone()
            }).ToArray();
            foreach (var p in _patterns)
            {
                if (p.Move.WheelTurn is TurnPattern)
                {
                    var turnPattern = p.Move.WheelTurn as TurnPattern;
                    if (turnPattern.Pattern == TurnPatternType.ToNext)
                    {
                        p.Move.WheelTurn = Self.GetAngleTo(_turnTo) < 0 ? -1 : 1;
                    }
                    else if (turnPattern.Pattern == TurnPatternType.FromNext)
                    {
                        p.Move.WheelTurn = Self.GetAngleTo(_turnTo) < 0 ? 1 : -1;
                    }
                }
            }

            _movesStack     = new Moves();
            _bestMovesStack = new Moves();
            _bestTime       = MyStrategy.Infinity;
            _bestImportance = 0;

            /*
             * Смотрим на бонусы, которые на расстоянии не более 4t
             * TODO: уменьшить приоритет бонусов, которые может быть возьмет другой (в.т.ч тиммейт)
             */
            _bonusCandidates = MyStrategy.Bonuses
                               .Where(
                bonus =>
                MyStrategy.world.Tick > 270 &&         // Не смотреть на бонусы при старте!!!
                Self.GetDistanceTo(bonus) <= Const.TileSize * 4 &&
                MyStrategy.CellDistance(Self, bonus) <= 4
                )
                               .ToArray();


            /*
             * Смотрим на лужи, которые на расстоянии не более 5 тайлов
             */
            var prevSlicks = _slickCandidates;
            _slickCandidates = MyStrategy.OilSlicks
                               .Where(
                slick =>
                Self.GetDistanceTo(slick) <= Const.TileSize * 5 &&
                MyStrategy.CellDistance(Self, slick) <= 5
                )
                               .ToArray();

            /*
             * Пытаться объехать тех, которые
             * - Крашнулись
             * - Убиты
             * - Двигатель меньше чем на 0.5 мощности
             * - Двигаются по встречной
             *
             * - Если у меня нитро, или будет нитро
             *
             * - Своих
             */
            var prevCars = _carCandidates;
            _carCandidates = MyStrategy.Others
                             .Where(opp => opp[0].GetDistanceTo(Self) < Const.TileSize * 9)
                             .Where(
                opp =>
                opp[0].Original.IsTeammate ||
                MyStrategy.IsCrashed(opp[0].Original) ||
                !DurabilityObserver.IsActive(opp[0].Original) ||
                opp[0].EnginePower < 0.5 ||
                Self.RemainingNitroTicks > 0 ||
                Math.Abs(Geom.GetAngleBetween(Self.Speed, opp[0].Speed)) > Math.PI / 2
                )
                             .Where(opp => MyStrategy.CellDistance(Self, opp[0]) <= 9) // 9 - потому что он может ехать по встречке
                             .ToArray();


            if (_cache != null)
            {
                for (var k = 0; k < _patterns.Length; k++)
                {
                    var range = (prevSlicks == null || prevCars == null || prevProj == null ||
                                 _bonusesCount2 != bonusesCount2 ||
                                 prevSlicks.Length != _slickCandidates.Length ||
                                 prevCars.Length != _carCandidates.Length ||
                                 prevProj.Length != _projCandidates.Length)
                        ? (k == 0 ? 6 : 4)
                        : (k == 0 ? 6 : 2);

                    if (_bonusesCount05 != bonusesCount05 || Special && k == 0)
                    {
                        range = 10;
                    }

                    _patterns[k].From = Math.Max(0, _cache[k].Times - range);
                    _patterns[k].To   = Math.Min(_patterns[k].To * 9 / 7, _cache[k].Times + range);
                    _patterns[k].Step = 2;
                }
            }

            _bonusesCount05 = bonusesCount05;
            _bonusesCount2  = bonusesCount2;

            var wayPointRequired = false;
            for (var i = _bruteWayPoints.Length - 1; i >= 0; i--)
            {
                if (_bruteWayPoints[i].GetDistanceTo2(_turnTo) < _needDist * _needDist)
                {
                    for (var j = 0; j < i; j++)
                    {
                        wayPointRequired |=
                            MyStrategy.GetNextWayPoint(Self.Original).Equals(MyStrategy.GetCell(_bruteWayPoints[j]));
                    }
                    break;
                }
            }

            _doRecursive(Self, 0, new PassedInfo {
                WayPoint = !wayPointRequired
            });
            _cache = null;
            if (_bestTime == MyStrategy.Infinity)
            {
                return(_lastSuccessStack);
            }

            if (_bestMovesStack.ComputeTime() != _bestTime)
            {
                throw new Exception("ComputeTime != BestTime");
            }

            LastSuccess = MyStrategy.world.Tick;
            _cache      = _bestMovesStack.Clone();

            if (_maxTicksInfo == null)
            {
                _maxTicksInfo = new int[_bestMovesStack.Count];
            }
            for (var i = 0; i < _maxTicksInfo.Length; i++)
            {
                _maxTicksInfo[i] = Math.Max(_maxTicksInfo[i], _bestMovesStack[i].Times);
            }

            _bestMovesStack.Normalize();
            _lastSuccessStack = _bestMovesStack.Clone();
            return(_bestMovesStack);
        }
Esempio n. 4
0
        public static bool IntersectTail(Point p, double additionalMargin)
        {
            if (p.X < 0 || p.X >= Const.MapWidth || p.Y < 0 || p.Y >= Const.MapHeight)
            {
                return(true);
            }

            var cell = GetCell(p.X, p.Y);
            var tile = MyTiles[cell.I, cell.J];

            if (tile.Type == TileType.Empty)
            {
                return(true);
            }

            var c      = GetCenter(cell);
            var margin = Const.TileSize / 2 - Const.TileMargin;
            var lx     = c.X - margin;
            var rx     = c.X + margin;
            var ly     = c.Y - margin;
            var ry     = c.Y + margin;

            // внутри квадрата
            if (lx <= p.X && p.X <= rx && ly <= p.Y && p.Y <= ry) // optimization
            {
                return(false);
            }

            var cornerDist2 = Geom.Sqr(Const.TileMargin + Math.Max(-5, additionalMargin));

            // в углу
            foreach (var corner in MyTiles[cell.I, cell.J].Parts)
            {
                if (corner.Type != TilePartType.Circle)
                {
                    continue;
                }
                if (corner.Circle.GetDistanceTo2(p) < cornerDist2)
                {
                    return(true);
                }
            }

            // по бокам
            if (p.X < lx + additionalMargin && !tile.IsFreeLeft)
            {
                return(true);
            }
            if (p.X > rx - additionalMargin && !tile.IsFreeRight)
            {
                return(true);
            }
            if (p.Y < ly + additionalMargin && !tile.IsFreeTop)
            {
                return(true);
            }
            if (p.Y > ry - additionalMargin && !tile.IsFreeBottom)
            {
                return(true);
            }

            return(false);
        }
Esempio n. 5
0
File: ACar.cs Progetto: znsoft/AiCup
        public void Move(double enginePower, double wheelTurn, bool isBreak, bool useNitro, bool simpleMode)
        {
            if (RemainingInactiveTicks > 0 || MyStrategy.IsCrashed(Original))
            {
                isBreak     = false;
                useNitro    = false;
                enginePower = 0;
                wheelTurn   = WheelTurn;
            }

            useNitro = useNitro && Original.NitroChargeCount > 0;
            if (useNitro && RemainingNitroTicks == 0 && RemainingNitroCooldownTicks == 0)
            {
                RemainingNitroTicks         = Const.Game.NitroDurationTicks;
                RemainingNitroCooldownTicks = Const.Game.UseNitroCooldownTicks;
            }

            var updateIterations           = simpleMode ? 2 : 10;
            var frictionMultiplier         = Math.Pow(1.0 - Const.Game.CarMovementAirFrictionFactor, 1.0 / updateIterations);
            var rotationFrictionMultiplier = Math.Pow(1.0 - Const.Game.CarRotationFrictionFactor,
                                                      1.0 / updateIterations);

            if (enginePower > 1 + MyStrategy.Eps || enginePower < -1 - MyStrategy.Eps)
            {
                throw new Exception("invalid enginePower " + enginePower);
            }

            if (wheelTurn > 1 + MyStrategy.Eps || wheelTurn < -1 - MyStrategy.Eps)
            {
                throw new Exception("invalid wheelTurn " + wheelTurn);
            }

            if (RemainingNitroTicks > 0)
            {
                EnginePower = 2.0;
            }
            else
            {
                EnginePower = enginePower > EnginePower
                    ? Math.Min(EnginePower + Const.Game.CarEnginePowerChangePerTick, enginePower)
                    : Math.Max(EnginePower - Const.Game.CarEnginePowerChangePerTick, enginePower);
            }


            WheelTurn = wheelTurn > WheelTurn
                ? Math.Min(WheelTurn + Const.Game.CarWheelTurnChangePerTick, wheelTurn)
                : Math.Max(WheelTurn - Const.Game.CarWheelTurnChangePerTick, wheelTurn);


            if (MyStrategy.world.Tick >= Const.Game.InitialFreezeDurationTicks)
            {
                // http://russianaicup.ru/forum/index.php?topic=394.msg3888#msg3888

                var dir = Point.ByAngle(Angle);

                var baseAngSpd = AngularSpeed; // HACK
                AngularSpeed -= baseAngSpd;
                baseAngSpd    = Const.Game.CarAngularSpeedFactor * WheelTurn * (Speed * dir);
                AngularSpeed += baseAngSpd;

                var carAcceleration = EnginePower >= 0
                    ? _carAccelerationUp
                    : _carAccelerationDown;

                var accelerationDelta = dir * (carAcceleration * EnginePower / updateIterations);

                var lengthwiseMovementFrictionFactor = isBreak
                    ? Const.Game.CarCrosswiseMovementFrictionFactor
                    : Const.Game.CarLengthwiseMovementFrictionFactor;
                lengthwiseMovementFrictionFactor /= updateIterations;
                var crosswiseMovementFrictionFactor = Const.Game.CarCrosswiseMovementFrictionFactor /
                                                      updateIterations;

                for (var i = 0; i < updateIterations; i++)
                {
                    X += Speed.X / updateIterations;
                    Y += Speed.Y / updateIterations;
                    if (!isBreak)
                    {
                        Speed.X += accelerationDelta.X;
                        Speed.Y += accelerationDelta.Y;
                    }
                    Speed.X *= frictionMultiplier;
                    Speed.Y *= frictionMultiplier;

                    var t1 = _limit(Speed.X * dir.X + Speed.Y * dir.Y, lengthwiseMovementFrictionFactor);
                    var t2 = _limit(Speed.X * dir.Y - Speed.Y * dir.X, crosswiseMovementFrictionFactor);

                    Speed.X = dir.X * t1 + dir.Y * t2;
                    Speed.Y = dir.Y * t1 - dir.X * t2;

                    Angle       += AngularSpeed / updateIterations;
                    dir          = Point.ByAngle(Angle);
                    AngularSpeed = baseAngSpd + (AngularSpeed - baseAngSpd) * rotationFrictionMultiplier;
                }

                Geom.AngleNormalize(ref Angle);
                if (RemainingNitroCooldownTicks > 0)
                {
                    RemainingNitroCooldownTicks--;
                }
                if (RemainingNitroTicks > 0)
                {
                    RemainingNitroTicks--;
                }
                if (RemainingInactiveTicks > 0)
                {
                    RemainingInactiveTicks--;
                }
            }

            // clear rectangles cache
            _rect   = null;
            _rectEx = null;
        }
Esempio n. 6
0
        public void Move()
        {
            if (!Exists)
            {
                return;
            }

            if (Type == ProjectileType.Washer)
            {
                X += Speed.X;
                Y += Speed.Y;

                if (X < 0 || Y < 0 || X > Const.MapWidth || Y > Const.MapHeight)
                {
                    Exists = false;
                }
                return;
            }

            var reflected = false;

            for (int it = 0; it < UpdateIterations; it++)
            {
                X += Speed.X / UpdateIterations;
                Y += Speed.Y / UpdateIterations;

                // может выйти за пределы если тайлы unknown
                if (X < 1 || Y < 1 || X >= Const.MapWidth - 1 || Y >= Const.MapHeight - 1)
                {
                    Exists = false;
                    break;
                }

                if (reflected)
                {
                    continue;
                }

                var currentCell = MyStrategy.GetCell(this);
                foreach (var part in MyStrategy.MyTiles[currentCell.I, currentCell.J].Parts)
                {
                    Point e = null, n = null;
                    // e - направление стены
                    // n - нормаль от стены
                    double en = 0, et = 0, d = 0, d1 = 0, d2 = 0;

                    if (part.Type == TilePartType.Segment)
                    {
                        var pts = Geom.LineCircleIntersect(part.Start, part.End, this, this.Radius);
                        if (pts.Length == 0)
                        {
                            continue;
                        }


                        e = (part.End - part.Start).Normalized();
                        n = ~e * -1;
                    }
                    else
                    {
                        if (GetDistanceTo2(part.Circle) <= Geom.Sqr(Radius + part.Circle.Radius))
                        {
                            n = (this - part.Circle).Normalized();
                            e = ~n;
                        }
                    }

                    if (e == null || n == null)
                    {
                        continue;
                    }

                    en = Speed * n; // норм.
                    et = Speed * e; // танг.

                    en *= -0.5;

                    d       = n.X * e.Y - n.Y * e.X;
                    d1      = n.X * et - en * e.X;
                    d2      = en * e.Y - n.Y * et;
                    Speed.X = d2 / d;
                    Speed.Y = d1 / d;

                    reflected = true;
                    break;
                }
            }
            if (Speed.Length <= Const.Game.TireDisappearSpeedFactor * Const.Game.TireInitialSpeed)
            {
                Exists = false;
            }
        }
Esempio n. 7
0
 public bool Intersect(ACar car, double safeMargin)
 {
     return(GetDistanceTo2(car) < Geom.Sqr(Radius + safeMargin));
 }
Esempio n. 8
0
        public ATile(int i, int j, TileType type) : base(i, j)
        {
            Type = type;

            IsFreeLeft   = _tileFreeLeft(type);
            IsFreeRight  = _tileFreeRight(type);
            IsFreeTop    = _tileFreeTop(type);
            IsFreeBottom = _tileFreeBottom(type);

            var margin = Const.TileMargin;

            var sy = new Point(0, margin);
            var sx = new Point(margin, 0);
            var ly = new Point(0, Const.TileSize);
            var lx = new Point(Const.TileSize, 0);

            var res = new List <TilePart>();

            switch (type)
            {
            // Левый верхний угол
            case TileType.LeftHeadedT:
            case TileType.TopHeadedT:
            case TileType.RightBottomCorner:
            case TileType.Crossroads:
            case TileType.Unknown:
                res.Add(TilePart.GetCircle(Point.Zero, margin));
                break;
            }

            switch (type)
            {
            // Правый верхний угол
            case TileType.RightHeadedT:
            case TileType.TopHeadedT:
            case TileType.LeftBottomCorner:
            case TileType.Crossroads:
            case TileType.Unknown:
                res.Add(TilePart.GetCircle(lx, margin));
                break;
            }

            switch (type)
            {
            // Правый нижний угол
            case TileType.BottomHeadedT:
            case TileType.RightHeadedT:
            case TileType.LeftTopCorner:
            case TileType.Crossroads:
            case TileType.Unknown:
                res.Add(TilePart.GetCircle(lx + ly, margin));
                break;
            }

            switch (type)
            {
            // Левый нижний угол
            case TileType.BottomHeadedT:
            case TileType.LeftHeadedT:
            case TileType.RightTopCorner:
            case TileType.Crossroads:
            case TileType.Unknown:
                res.Add(TilePart.GetCircle(ly, margin));
                break;
            }

            switch (type)
            {
            // Верхняя полоса
            case TileType.BottomHeadedT:
            case TileType.Horizontal:
            case TileType.LeftTopCorner:
            case TileType.RightTopCorner:
                res.Add(TilePart.GetSegment(sy, lx + sy));
                break;
            }
            switch (type)
            {
            // Нижняя полоса
            case TileType.TopHeadedT:
            case TileType.Horizontal:
            case TileType.LeftBottomCorner:
            case TileType.RightBottomCorner:
                res.Add(TilePart.GetSegment(ly - sy, lx + ly - sy));
                break;
            }
            switch (type)
            {
            // Левая полоса
            case TileType.RightHeadedT:
            case TileType.Vertical:
            case TileType.LeftBottomCorner:
            case TileType.LeftTopCorner:
                res.Add(TilePart.GetSegment(sx, ly + sx));
                break;
            }
            switch (type)
            {
            // Правая полоса
            case TileType.LeftHeadedT:
            case TileType.Vertical:
            case TileType.RightBottomCorner:
            case TileType.RightTopCorner:
                res.Add(TilePart.GetSegment(lx - sx, lx + ly - sx));
                break;
            }

            var dx = Const.TileSize * j;
            var dy = Const.TileSize * i;

            foreach (var part in res)
            {
                if (part.Type == TilePartType.Circle)
                {
                    part.Circle.X += dx;
                    part.Circle.Y += dy;
                }
                else
                {
                    part.Start.X += dx;
                    part.Start.Y += dy;
                    part.End.X   += dx;
                    part.End.Y   += dy;

                    if (Geom.VectorProduct(part.Start, part.End, MyStrategy.GetCenter(i, j)) > 0)
                    {
                        var tmp = part.Start;
                        part.Start = part.End;
                        part.End   = tmp;
                    }
                }
            }
            Parts = res.ToArray();
        }
Esempio n. 9
0
        void Initialize()
        {
            if (!Const.Initialized)
            {
                Const.Initialized = true;

                Const.TileSize   = Const.Game.TrackTileSize;
                Const.TileMargin = Const.Game.TrackTileMargin;

                Const.CarDiagonalHalfLength   = Geom.Gypot(Const.Game.CarWidth, Const.Game.CarHeight) / 2;
                Const.BonusDiagonalHalfLength = Geom.Gypot(Const.Game.BonusSize / 2 - MagicConst.BonusSafeMargin, Const.Game.BonusSize / 2 - MagicConst.BonusSafeMargin);

                Const.MapWidth  = Const.TileSize * world.Width;
                Const.MapHeight = Const.TileSize * world.Height;
            }

            Teammate = world.Cars.FirstOrDefault(car => car.IsTeammate && car.Id != self.Id);

            ComputedPath.Remove(self.Id);
            if (Teammate != null)
            {
                TeammateCar = ComputedPath.ContainsKey(Teammate.Id) ? ComputedPath[Teammate.Id] : null;
            }

            if (Players == null) // check for first call
            {
                MyTiles = new ATile[world.Height, world.Width];
                for (var i = 0; i < world.Height; i++)
                {
                    for (var j = 0; j < world.Width; j++)
                    {
                        MyTiles[i, j] = new ATile(i, j, TileType.Unknown);
                    }
                }
            }

            // intialize tiles
            var t = world.TilesXY;

            for (var i = 0; i < world.Height; i++)
            {
                for (var j = 0; j < world.Width; j++)
                {
                    if (MyTiles[i, j].Type == TileType.Unknown && t[j][i] != TileType.Unknown)
                    {
                        MyTiles[i, j] = new ATile(i, j, t[j][i]);
                    }

                    MyTiles[i, j].Weight = 0;
                }
            }

            // intialize waypoints
            var wp = world.Waypoints;

            Waypoints = new Cell[wp.Length];
            for (var i = 0; i < Waypoints.Length; i++)
            {
                Waypoints[i] = new Cell(wp[i][1], wp[i][0]);
            }

            Players = new Dictionary <long, Player>();
            foreach (var player in world.Players)
            {
                Players[player.Id] = player;
            }

            foreach (var car in world.Cars)
            {
                DurabilityObserver.Watch(car);
            }

            var tires = world.Projectiles.Where(x => x.Type == ProjectileType.Tire).ToArray();

            Tires = new AProjectile[tires.Length][];
#if DEBUG
            var trajectories = Tires.Select(x => new Points()).ToArray();
#endif
            for (var i = 0; i < tires.Length; i++)
            {
                Tires[i]    = new AProjectile[MagicConst.ProjectilePredictionTicks];
                Tires[i][0] = new AProjectile(tires[i]);
                for (var j = 1; j < MagicConst.ProjectilePredictionTicks; j++)
                {
                    Tires[i][j] = Tires[i][j - 1].Clone();
                    Tires[i][j].Move();
#if DEBUG
                    trajectories[i].Add(new Point(Tires[i][j]));
#endif
                }
            }
#if DEBUG
            foreach (var tr in trajectories)
            {
                Visualizer.SegmentsDrawQueue.Add(new object[] { Brushes.Indigo, tr, 0.0 });
            }
#endif

            Bonuses   = world.Bonuses.Select(b => new ABonus(b)).ToArray();
            OilSlicks = world.OilSlicks.Select(s => new AOilSlick(s)).ToArray();

            EnumerateNeigbours(GetCell(self), to =>
            {
                var center = GetCenter(to);
                MyTiles[to.I, to.J].Weight += Math.Abs(self.GetAngleTo(center.X, center.Y));
            });

            foreach (var bonus in Bonuses)
            {
                var cell = GetCell(bonus);
                MyTiles[cell.I, cell.J].AddBonus(bonus);
            }
            foreach (var slick in OilSlicks)
            {
                var cell = GetCell(slick);
                MyTiles[cell.I, cell.J].AddSlick(slick);
            }

            Opponents = world.Cars.Where(car => !car.IsTeammate && !car.IsFinishedTrack).ToArray();
            PrepareOpponentsPath();
            if (OpponentsCars != null)
            {
                Others = OpponentsCars
                         .Concat(TeammateCar == null ? new ACar[][] { } : new[] { TeammateCar })
                         .ToArray();
            }

            ComputedPath.Clear();
            if (self.TeammateIndex == 1 && OpponentsCars != null)
            {
                foreach (var opp in OpponentsCars)
                {
                    ComputedPath[opp[0].Original.Id] = opp;
                }
            }
        }