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); }
public static void Draw() { if (_form.InvokeRequired) { _form.BeginInvoke(new DrawDelegate(Draw), new object[] { }); return; } _renderTick++; if ((_renderTick - 1) % _myCarsCount != _myCarsCount - 1) { return; } var panel = _form.panel; _form.tickLabel.Text = MyStrategy.world.Tick + ""; var drawArea = new Bitmap(panel.Size.Width, panel.Size.Height); panel.Image = drawArea; _graphics = Graphics.FromImage(drawArea); if (_myCarsCount == 1) { _form.jeepRadioButton.Enabled = false; _form.buggyRadioButton.Enabled = false; LookUp(new Point(MyStrategy.world.Cars.FirstOrDefault(x => x.IsTeammate))); } else { LookUp( new Point( MyStrategy.world.Cars.FirstOrDefault( x => x.IsTeammate && (x.Type == CarType.Jeep && _form.jeepRadioButton.Checked || x.Type == CarType.Buggy && _form.buggyRadioButton.Checked)))); } //var myNextWp = MyStrategy.GetNextWayPoint(self); //FillRect(Brushes.Aqua, myNextWp.J * Const.TileSize, myNextWp.I * Const.TileSize, Const.TileSize, Const.TileSize); // tiles foreach (var tile in MyStrategy.MyTiles) { var margin = Const.TileMargin; var tsize = Const.TileSize; var dx = Const.TileSize * tile.J; var dy = Const.TileSize * tile.I; if (tile.Type == TileType.Unknown) { FillRect(Brushes.DarkGray, dx, dy, tsize, tsize); } if (tile.Type == TileType.Empty) { FillRect(Brushes.Black, dx, dy, tsize, tsize); } if (!tile.IsFreeLeft) { FillRect(Brushes.Black, dx, dy, margin, tsize); } if (!tile.IsFreeTop) { FillRect(Brushes.Black, dx, dy, tsize, margin); } if (!tile.IsFreeRight) { FillRect(Brushes.Black, dx + tsize - margin, dy, margin, tsize); } if (!tile.IsFreeBottom) { FillRect(Brushes.Black, dx, dy + tsize - margin, tsize, margin); } foreach (var part in tile.Parts) { switch (part.Type) { case TilePartType.Circle: FillCircle(Brushes.Black, part.Circle.X, part.Circle.Y, part.Circle.Radius); break; case TilePartType.Segment: DrawLine(Brushes.DarkRed, part.Start.X, part.Start.Y, part.End.X, part.End.Y, 1); break; default: throw new Exception("Unknown TilePartType"); } } } // Bonuses foreach (var bonus in MyStrategy.world.Bonuses) { var rect = new ABonus(bonus).GetRect(); for (var i = 0; i < 4; i++) { Brush brush; if (bonus.Type == BonusType.PureScore) { brush = Brushes.OrangeRed; } else if (bonus.Type == BonusType.RepairKit) { brush = Brushes.LimeGreen; } else if (bonus.Type == BonusType.OilCanister) { brush = Brushes.DarkSlateGray; } else if (bonus.Type == BonusType.NitroBoost) { brush = Brushes.Blue; } else if (bonus.Type == BonusType.AmmoCrate) { brush = Brushes.DarkGoldenrod; } else { throw new Exception("Unknown BonusType"); } DrawLine(brush, rect[i].X, rect[i].Y, rect[(i + 1) % 4].X, rect[(i + 1) % 4].Y, 2); } } // Cars foreach (var car in MyStrategy.world.Cars) { var isAvtive = DurabilityObserver.IsActive(car); var rect = new ACar(car).GetRectEx(isAvtive ? 0 : 1); for (var i = 0; i < 4; i++) { DrawLine(car.IsTeammate ? Brushes.Green : Brushes.Red, rect[i].X, rect[i].Y, rect[(i + 1) % 4].X, rect[(i + 1) % 4].Y, isAvtive ? 2 : 1); } var to = Point.ByAngle(car.Angle) * 100 + new Point(car); DrawLine(Brushes.Black, car.X, car.Y, to.X, to.Y, car.Type == CarType.Buggy ? 2 : 6); DrawText("~" + car.ProjectileCount, 50, Brushes.Black, car.X, car.Y); } // Oil foreach (var stick in MyStrategy.world.OilSlicks) { FillCircle(Brushes.Black, stick.X, stick.Y, stick.Radius); } // Nitro foreach (var car in MyStrategy.world.Cars) { if (car.RemainingNitroTicks > 0) { FillCircle(Brushes.Blue, car.X, car.Y, 40); } } // Canisters foreach (var car in MyStrategy.world.Cars) { if (car.OilCanisterCount == 0) { continue; } var canisterPen = car.RemainingOilCooldownTicks == 0 ? Pens.DarkSlateGray : Pens.Lavender; var slick = new AOilSlick(new ACar(car)); DrawCircle(canisterPen, slick.X, slick.Y, slick.Radius); if (car.RemainingOiledTicks > 0) { FillCircle(Brushes.Black, car.X, car.Y, 30); } } // Projectiles foreach (var pr in MyStrategy.world.Projectiles) { FillCircle(Brushes.OrangeRed, pr.X, pr.Y, pr.Radius); } // Segments try { foreach (var _el in SegmentsDrawQueue) { var el = _el as object[]; var brush = el[0] as Brush; var line = el[1] as Points; var width = Convert.ToDouble(el[2]); for (var i = 1; i < line.Count; i++) { DrawLine(brush, line[i - 1].X, line[i - 1].Y, line[i].X, line[i].Y, (float)width); } } } catch (Exception) { } // Circles foreach (var el in CircleFillQueue) { var brush = el.Item1; var circle = el.Item2; FillCircle(brush, circle.X, circle.Y, circle.Radius); } CircleFillQueue.Clear(); SegmentsDrawQueue.Clear(); }
public bool CheckUseProjectile() { if (world.Tick < Const.Game.InitialFreezeDurationTicks) { return(false); } if (self.ProjectileCount == 0) { return(false); } if (self.RemainingProjectileCooldownTicks > 0) { return(false); } var projectiles = AProjectile.GetProjectiles(new ACar(self)); var shot = new bool[projectiles.Length]; var shotSpeed = 0.0; var checkTicks = MagicConst.OpponentsTicksPrediction * (self.Type == CarType.Buggy ? 0.5 : 0.4); for (var t = 1; t < checkTicks; t++) { for (var prId = 0; prId < projectiles.Length; prId++) { var pr = projectiles[prId]; if (!pr.Exists) { continue; } pr.Move(); for (var i = 0; i < All.Length; i++) { if (t >= All[i].Length) { continue; } var car = All[i][t]; /* * Чужие машинки считать меньшими по размеру * Свои - большими */ if (pr.Intersect(car, car.Original.IsTeammate ? 5 : -(pr.Type == ProjectileType.Tire ? 40 : 5))) { if (pr.Type == ProjectileType.Tire) { // если это я только что выпустил шину if (car.Original.Id == self.Id && Math.Abs(pr.Speed.Length - Const.Game.TireInitialSpeed) < Eps) { continue; } } else { // если это я выпустил шайбу if (car.Original.Id == self.Id) { continue; } } if (car.Original.IsTeammate) // попал в своего { return(false); } if (DurabilityObserver.ReactivationTime(car.Original) + 2 < world.Tick + t || DurabilityObserver.IsActive(car.Original)) { // если он не мертв shot[prId] = true; if (pr.Type == ProjectileType.Tire) { shotSpeed = pr.Speed.Length; } } pr.Exists = false; } } } } var shotCount = shot.Count(val => val); if (self.Type == CarType.Buggy) { return(shotCount >= 3 || shotCount == 2 && self.ProjectileCount > 2); } return(shotCount == 1 && (shotSpeed >= Const.Game.TireInitialSpeed - Eps || shotSpeed >= Const.Game.TireInitialSpeed / 2.5 && self.ProjectileCount > 2)); }
private void _move() { var pts = GetWaySegments(self); if (world.Tick > Const.Game.InitialFreezeDurationTicks) { PositionsHistory.Add(new Point(self)); } if (!DurabilityObserver.IsActive(self)) { return; } if (CheckBackMove(pts[1])) { return; } InitBrutes(); if (world.Tick < Const.Game.InitialFreezeDurationTicks) { var nextCell = DijkstraNextCell(GetCell(self), GetNextWayPoint(self), new Cell[] {}); var nextCenter = GetCenter(nextCell); move.EnginePower = self.GetAngleTo(nextCenter.X, nextCenter.Y) < Math.PI / 2 ? 1 : -1; return; } if (BAD_TESTING_STRATEGY) { AlternativeMove(pts); return; } // если еду назад, то запускать только первый перебор // если маленькая скорость, то 1-й и 2-й var bruteRes = _doAndSelectBrute( self.EnginePower < 0 ? new[] { Brutes[0] } : (GetSpeed(self) < 5 ? new[] { Brutes[0], Brutes[1] } : Brutes), pts); var sel = bruteRes.Item1; var bestMoveStacks = bruteRes.Item2; if (sel != -1 && bestMoveStacks[sel].Count > 0) { Brutes[sel].SelectThis(); bestMoveStacks[sel][0].Apply(move, new ACar(self)); ComputedPath[self.Id] = GetCarPath(self, bestMoveStacks[sel]); #if DEBUG Visualizer.DrawWays(self, bestMoveStacks, sel); #endif } else { TimerStart(); AlternativeMove(pts); TimerEndLog("AlternativeMove", 30); } }