public double GetDistanceTo(Point point) { if (A.Equals(B)) { return(A.GetDistanceTo(point)); } var a = A - point; var b = B - point; double aa, bb, cc; Geom.GetABC(a, b, out aa, out bb, out cc); if (Geom.Sign((a.Y + bb) * aa - (a.X + aa) * bb) * Geom.Sign((b.Y + bb) * aa - (b.X + aa) * bb) <= 0) { return(Math.Abs(cc / Math.Sqrt(aa * aa + bb * bb))); } return(Math.Min(a.Length, b.Length)); }
private void _updateVehicleCoordinates(AVehicle veh, double prevX, double prevY) { var unitTree = _trees[veh.IsMy ? 1 : 0, veh.IsAerial ? 1 : 0]; if (unitTree == null) { return; // Дерево ещё не создано. Когда будет создаваться - тогда и наполнится обновленными данными. } var moveX = veh.X; var moveY = veh.Y; if (!Geom.PointsEquals(prevX, prevY, moveX, moveY)) { veh.X = prevX; veh.Y = prevY; if (!unitTree.ChangeXY(veh, moveX, moveY)) { throw new Exception("Can't change unit coordinates, id=" + veh.Id); } } }
static double GetSumMaxAlmostAttacks(Sandbox env, IEnumerable <AVehicle> myVehicles) { Logger.CumulativeOperationStart("Danger0"); var result = myVehicles.Sum(m => { var additionalRadius = m.ActualSpeed; const int radiusFactor = 5; return(env.GetOpponentNeighbours(m.X, m.Y, G.MaxAttackRange + additionalRadius * radiusFactor).DefaultIfEmpty(null) .Max(opp => { if (opp == null) { return 0; } var dmg = opp.GetAttackDamage(m, additionalRadius * radiusFactor); if (dmg == 0) { return -(m.GetAttackDamage(opp, additionalRadius) + m.GetAttackDamage(opp, additionalRadius * radiusFactor) / 2.0); } return (opp.GetAttackDamage(m, additionalRadius) + opp.GetAttackDamage(m, additionalRadius * 2) / 2.0 + opp.GetAttackDamage(m, additionalRadius * 3) / 4.0 + opp.GetAttackDamage(m, additionalRadius * 4) / 8.0 + dmg / 16.0 ) * (G.AttackDamage[(int)m.Type, (int)opp.Type] > 0 ? Geom.Sqr(1.0 * opp.Durability / G.MaxDurability) : 1) * (m.Type == opp.Type ? 0.6 : 1) * (G.IsAerialButerDetected && opp.Type == VehicleType.Fighter ? 3 : 1); })); }); Logger.CumulativeOperationEnd("Danger0"); return(result); }
private static AVehicle _doFacilityProd(Sandbox env, AFacility facility) { var vehicleType = facility.VehicleType.Value; var isMy = facility.IsMy; var pt = new ACircularUnit(); pt.Radius = G.VehicleRadius; for (var j = 0; j < 11; j++) { for (var i = 0; i < 11; i++) { if (facility.IsMy) { pt.X = facility.X + i * 6 + G.VehicleRadius; pt.Y = facility.Y + j * 6 + G.VehicleRadius; } else { pt.X = facility.X2 - i * 6 - G.VehicleRadius; pt.Y = facility.Y2 - j * 6 - G.VehicleRadius; } var nearby = env.GetFirstIntersector(pt, Utility.IsAerial(vehicleType)); if (nearby == null && !facility.IsMy) { nearby = OppUncheckedVehicles.Values .Where(x => Utility.IsAerial(x.Type) == Utility.IsAerial(vehicleType)) .ArgMin(x => x.GetDistanceTo2(pt)); } if (nearby == null || !nearby.IntersectsWith(pt) || nearby.Id == _nextFreeId && Geom.PointsEquals(nearby, pt)) { return(new AVehicle(pt, _nextFreeId++, vehicleType, isMy)); } } } return(null); }
Tuple <AMove[], MyGroup, DangerResult> MainLoopStrategy(bool opt) { VisualSegments.Clear(); var visualVectorsStart = new List <Point>(); var visualVectorsDir = new List <Point>(); var visualVectorsScore = new List <double>(); _isSlowMode = _isSlowMode && Environment.OppVehicles.Count == 0; var baseTicksCount = Const.ActionsBruteforceDepth; if (Environment.Nuclears.Length > 0) { baseTicksCount *= 2; } var selMoves = new[] { new AMove() }; MyGroup selGroup = null; DangerResult selDanger = null; var targetFacilities = GetDanger(Environment, Environment, GroupsManager.MyGroups, MyUngroupedClusters).TargetFacility; for (var s = 0; s < GroupsManager.MyGroups.Count + MyUngroupedClusters.Count; s++) { var availableActions = MoveObserver.AvailableActions; if (Opp.RemainingNuclearStrikeCooldownTicks < 60 && Environment.Nuclears.Length == 0) { availableActions -= 2; } MyGroup group; List <AVehicle> newGroupVehicles = null; if (s < GroupsManager.MyGroups.Count) { group = GroupsManager.MyGroups[s]; } else { newGroupVehicles = MyUngroupedClusters[s - GroupsManager.MyGroups.Count]; if (newGroupVehicles.Count < NewGroupMinSize) { continue; } if (availableActions < 3) // required: clear, move, assign { continue; } group = new MyGroup(GroupsManager.NextGroupId, newGroupVehicles[0].Type); } if (opt && !( Environment.Nuclears.Length > 0 || Environment.Facilities.Length <= 4 || World.TickIndex < 2500 || MoveObserver.MaxAvailableActions <= 12 || _doMainLastGroup != null && _doMainLastGroup.Group == group.Group || // ходил предыдущий раз (newGroupVehicles == null && group.Group % 2 == _doMainsCount % 2 || newGroupVehicles != null && group.Group % 3 == _doMainsCount % 3) // через раз/два )) { continue; } if (_isSlowMode && World.TickIndex < 300 && group.VehicleType == VehicleType.Helicopter) { continue; } Logger.CumulativeOperationStart("First env actions"); var startEnv = Environment.Clone(); var ticksCount = baseTicksCount; if (newGroupVehicles != null) { foreach (var newVeh in newGroupVehicles) { startEnv.AddVehicleGroup(startEnv.VehicleById[newVeh.Id], group.Group); } } var selectedIds = Utility.UnitsHash(startEnv.MyVehicles.Where(x => x.IsSelected)); var needToSelectIds = Utility.UnitsHash(startEnv.GetVehicles(true, group)); List <AMove> selectionMoves = new List <AMove>(); if (selectedIds != needToSelectIds) { if (availableActions < 2) // required: select, move { Logger.CumulativeOperationEnd("First env actions"); continue; } if (newGroupVehicles == null) { selectionMoves.Add(AMovePresets.ClearAndSelectGroup(group.Group)); } else { var selectionMove = AMovePresets.ClearAndSelectType(group.VehicleType, Utility.BoundingRect(newGroupVehicles)); startEnv.ApplyMove(selectionMove); // ниже выполнится лишний раз, но не страшно selectionMoves.Add(selectionMove); foreach (var mg in GroupsManager.MyGroups) { if (mg.VehicleType == group.VehicleType && startEnv.MyVehicles.Where(x => x.IsSelected).Any(x => x.IsGroup(mg))) { selectionMoves.Add(new AMove { Action = ActionType.Deselect, Group = mg.Group }); } } } if (availableActions < selectionMoves.Count + 1) // required: select, move, deselect all { Logger.CumulativeOperationEnd("First env actions"); continue; } foreach (var mv in selectionMoves) { startEnv.ApplyMove(mv); availableActions--; } } availableActions--; Logger.CumulativeOperationEnd("First env actions"); // availableActions теперь - это сколько действий останется после выполнения текущего тика // должно остаться хотябы 2, или 0, если обладатель ядерки selected var myNuclear = startEnv.Nuclears.FirstOrDefault(n => n.IsMy); if (myNuclear != null && availableActions < 2 - (startEnv.VehicleById.ContainsKey(myNuclear.VehicleId) && startEnv.VehicleById[myNuclear.VehicleId].IsSelected ? 2 : 0)) { continue; } var typeRect = Utility.BoundingRect(startEnv.GetVehicles(true, group)); Sandbox partialEnv = null; var sumMaxAlmostAttacksCache = -1.0; if (Environment.Nuclears.Length == 0) { Logger.CumulativeOperationStart("Partial env actions"); partialEnv = new Sandbox( startEnv.Vehicles.Where(x => !x.IsSelected), new ANuclear[] { }, startEnv.Facilities, clone: true ); partialEnv.CheckCollisionsWithOpponent = false; var grps = GroupsManager.MyGroups.Select(g => partialEnv.GetVehicles(true, g).ToArray()).ToArray(); try { for (var i = 0; i < ticksCount; i++) { for (var j = 0; j < grps.Length; j++) { var pgr = grps[j]; if (pgr.Length > 0) { partialEnv.DoMoveApprox(pgr, pgr[0].Action != AVehicle.MoveType.Scale); } } partialEnv.DoFacilities(); partialEnv.DoNuclears(); } partialEnv.DoFight(); sumMaxAlmostAttacksCache = GetSumMaxAlmostAttacks(partialEnv, partialEnv.MyVehicles); } catch (QuadTree <AVehicle> .PointAlreadyExistsException e) { Logger.Log(e.Message); continue; } finally { Logger.CumulativeOperationEnd("Partial env actions"); } } Logger.CumulativeOperationStart("Pre last env actions"); Sandbox preLastEnv = null; AVehicle[] nearInteractors = null; List <AVehicle> currentVehicles = null; AVehicle[] preLastEnvVehiclesCopy = null; if (partialEnv != null) { currentVehicles = startEnv.GetVehicles(true, group); var currentVehiclesCenter = Utility.BoundingRect(currentVehicles).Center; nearInteractors = partialEnv.Vehicles .Where(x => !x.IsMy && x.GetDistanceTo2(currentVehiclesCenter) < Geom.Sqr(2 * G.TacticalNuclearStrikeRadius) || x.IsMy && x.IsAerial == Utility.IsAerial(group.VehicleType) && x.GetDistanceTo2(currentVehiclesCenter) < Geom.Sqr(G.TacticalNuclearStrikeRadius)) .ToArray(); preLastEnv = new Sandbox( partialEnv.Vehicles.Concat(currentVehicles), new ANuclear[] { }, new AFacility[] { }, clone: true ); preLastEnvVehiclesCopy = preLastEnv.Vehicles.Select(x => new AVehicle(x)).ToArray(); } Logger.CumulativeOperationEnd("Pre last env actions"); Func <AMove, double> checkAction = move => { Logger.CumulativeOperationStart("Building nearby environment"); Sandbox env; if (partialEnv == null) { env = startEnv.Clone(); } else { env = new Sandbox(nearInteractors.Concat(currentVehicles), startEnv.Nuclears, partialEnv.Facilities, clone: true); } env.CheckCollisionsWithOpponent = false; env.UseFightOptimization = false; if (partialEnv != null) { foreach (var veh in env.Vehicles) { if (veh.IsGroup(group)) { continue; } veh.ForgotTarget(); // чтобы не шли повторно veh.CanChargeFacility = false; // чтобы не захватывали повторно // TODO: лечение if (veh.RemainingAttackCooldownTicks > 0) // у тех, кто стрелял давно, откатываем кд { veh.RemainingAttackCooldownTicks += ticksCount; } // TODO: если кд только восстановилось } } Logger.CumulativeOperationEnd("Building nearby environment"); Logger.CumulativeOperationStart("End of simulation"); env.ApplyMove(move); try { env.DoTicksApprox(ticksCount, moveApprox: move.Action == ActionType.Move || move.Action == ActionType.Rotate, fightApprox: true); } catch (QuadTree <AVehicle> .PointAlreadyExistsException e) { Logger.Log(e.Message); return(double.PositiveInfinity); } finally { Logger.CumulativeOperationEnd("End of simulation"); } Logger.CumulativeOperationStart("Building last environment"); var cache = sumMaxAlmostAttacksCache; if (partialEnv != null) { var tmp = env; env = preLastEnv; for (var i = 0; i < env.Vehicles.Length; i++) { var veh = env.Vehicles[i]; if (tmp.VehicleById.ContainsKey(veh.Id)) { env.UpdateVehicle(veh, tmp.VehicleById[veh.Id]); } else { env.UpdateVehicle(veh, preLastEnvVehiclesCopy[i]); } } env.Nuclears = tmp.Nuclears; env.Facilities = tmp.Facilities; cache += GetSumMaxAlmostAttacks(env, env.GetVehicles(true, group)); } var myGroups = GroupsManager.MyGroups.AsEnumerable(); var myUngroups = MyUngroupedClusters.AsEnumerable(); if (newGroupVehicles != null) { myGroups = myGroups.ConcatSingle(group); myUngroups = myUngroups.Where(cl => !cl.Equals(newGroupVehicles)); } if (env.Vehicles.Length != Environment.Vehicles.Length) { throw new Exception("Final sandbox size mismatch"); } Logger.CumulativeOperationEnd("Building last environment"); var danger = GetDanger(Environment, env, myGroups.ToList(), myUngroups.ToList(), cache); if (move.Action == ActionType.Move) { visualVectorsStart.Add(typeRect.Center); visualVectorsDir.Add(new Point(move.X, move.Y).Normalized()); visualVectorsScore.Add(danger.Score); } if (selDanger == null || danger.Score < selDanger.Score) { selDanger = danger; selMoves = selectionMoves.Concat(new[] { move, newGroupVehicles == null ? null : AMovePresets.AssignGroup(group.Group) }) .Where(x => x != null) .ToArray(); selGroup = group; } return(danger.Score); }; var typeRectCenter = typeRect.Center; var simpleMode = Environment.Nuclears.Length == 0 && ( Environment.OppVehicles.Count == 0 || Environment.OppVehicles.Min(x => x.GetDistanceTo2(typeRectCenter)) > Geom.Sqr(120)); var moveMaxSpeed = _isSlowMode && Utility.IsAerial(group.VehicleType) ? G.MaxSpeed[(int)group.VehicleType] * 0.6 : 0; Func <int, AMove> idxToMove = idx => AMovePresets.Move( Point.ByAngle(2 * Math.PI / 12 * idx) * startEnv.MyVehicles.Where(x => x.IsSelected).Max(x => x.ActualSpeed) * ticksCount * 40, group.Group == GroupsManager.StartingTanksGroupId && Const.MixArrvsWithGrounds ? Math.Min(G.MaxSpeed[(int)VehicleType.Tank], G.MaxSpeed[(int)VehicleType.Arrv]) : group.Group == GroupsManager.StartingIfvsGroupId && Const.MixArrvsWithGrounds ? Math.Min(G.MaxSpeed[(int)VehicleType.Ifv], G.MaxSpeed[(int)VehicleType.Arrv]) : moveMaxSpeed ); double[] dangers; if (simpleMode) { // проверка на каждые 3 часа dangers = Enumerable.Range(0, 4).Select(i => checkAction(idxToMove(i * 3))).ToArray(); } else { // проверка на каждые 2 часа dangers = Enumerable.Range(0, 6).Select(i => checkAction(idxToMove(i * 2))).ToArray(); // проверка на середины лучших промежутков var dangers2 = dangers.Select((x, i) => new Tuple <double, int>(x, i)).OrderBy(x => x.Item1).Select(x => x.Item2).Take(2).ToArray(); foreach (var i in dangers2.Select(i => i * 2 + 1).Concat(dangers2.Select(i => i * 2 - 1)).Distinct()) { checkAction(idxToMove(i)); } } foreach (var move in Environment.Nuclears .Where(n => n.GetDistanceTo(Utility.Average(startEnv.MyVehicles.Where(x => x.IsSelected))) < G.TacticalNuclearStrikeRadius * 2) .SelectMany(nuclear => new[] { AMovePresets.Scale(nuclear, 1.5), AMovePresets.Scale(nuclear, 3.0), Environment.VehicleById.ContainsKey(nuclear.VehicleId) ? AMovePresets.Scale((Environment.VehicleById[nuclear.VehicleId] + nuclear) / 2, 2.0) : null, })) { if (move != null) { checkAction(move); } } checkAction(AMovePresets.Scale(typeRect.Center, 0.1)); if (_doMainLastUnscale.ContainsKey(group.Group)) { var prevScaleMove = _doMainLastUnscale[group.Group].Item2; checkAction(AMovePresets.Scale(prevScaleMove.Point, 1 / prevScaleMove.Factor)); } checkAction(AMovePresets.Rotate(typeRect.Center, Math.PI / 4)); checkAction(AMovePresets.Rotate(typeRect.Center, -Math.PI / 4)); List <Point> positiveInteractors = new List <Point>(), negativeInteractors = new List <Point>(); foreach (var cluster in OppClusters) { foreach (var oppType in Const.AllTypes) { if (cluster.CountByType[(int)oppType] > 0) { var avg = Utility.Average(cluster.VehicleType(oppType)); if (G.AttackDamage[(int)group.VehicleType, (int)oppType] > 0) { positiveInteractors.Add(avg); } else if (G.AttackDamage[(int)oppType, (int)group.VehicleType] > 0) { negativeInteractors.Add(avg); } } } } foreach (var move in positiveInteractors.OrderBy(cen => cen.GetDistanceTo2(typeRect.Center)) .Take(2) .Select(cen => AMovePresets.MoveTo(typeRect.Center, cen, moveMaxSpeed))) { checkAction(move); } foreach (var move in negativeInteractors.OrderBy(cen => cen.GetDistanceTo2(typeRect.Center)) .Take(1) .Select(cen => AMovePresets.Move((typeRect.Center - cen).Take(150), moveMaxSpeed))) { checkAction(move); } if (targetFacilities.ContainsKey(group.Group)) { checkAction(AMovePresets.MoveTo(typeRect.Center, targetFacilities[group.Group], moveMaxSpeed)); } // проверка действия "ничего не делать" if (selectionMoves.Count == 0) { checkAction(new AMove()); } // полет к ближайшему Arrv if (group.VehicleType == VehicleType.Helicopter || group.VehicleType == VehicleType.Fighter) { var arrvGroupsCenters = GroupsManager.MyGroups .Where(g => g.VehicleType == VehicleType.Arrv) .Select(g => Utility.BoundingRect(Environment.GetVehicles(true, g)).Center) .ToArray(); if (arrvGroupsCenters.Length > 0) { checkAction(AMovePresets.MoveTo(typeRect.Center, arrvGroupsCenters.ArgMin(p => p.GetDistanceTo2(typeRect.Center)), moveMaxSpeed)); } } } #if DEBUG //if (selDanger != null) //{ // var maxScore = visualVectorsScore.Max(); // var minScore = visualVectorsScore.Min(); // if (maxScore > minScore) // { // for (var i = 0; i < visualVectorsStart.Count; i++) // { // VisualSegments.Add(new object[] // { // new List<Point> // { // visualVectorsStart[i], // visualVectorsStart[i] + visualVectorsDir[i]*((visualVectorsScore[i]-minScore)/(minScore-maxScore)*40) // }, // new System.Drawing.Pen(System.Drawing.Color.Green), // 5 // }); // } // } //} #endif return(new Tuple <AMove[], MyGroup, DangerResult>(selMoves, selGroup, selDanger)); }
public static void Update() { _disappearedIds.Clear(); foreach (Vehicle vehicle in MyStrategy.World.NewVehicles) { _vehicleById[vehicle.Id] = vehicle; VehicleById[vehicle.Id] = new AVehicle(vehicle); if (G.IsFogOfWarEnabled && vehicle.PlayerId != MyStrategy.Me.Id) { if (vehicle.Id <= 1000 && !_visibleOnce.Contains(vehicle.Id)) { var fakeId = _idsPool[(int)vehicle.Type].Last(); _idsPool[(int)vehicle.Type].Pop(); OppUncheckedVehicles.Remove(fakeId); OppCheckedVehicles.Remove(fakeId); } OppCheckedVehicles.Remove(vehicle.Id); OppUncheckedVehicles.Remove(vehicle.Id); _visibleOnce.Add(vehicle.Id); } } foreach (VehicleUpdate vehicleUpdate in MyStrategy.World.VehicleUpdates) { var vehicleId = vehicleUpdate.Id; if (vehicleUpdate.Durability == 0) { _vehicleById.Remove(vehicleId); VehicleById.Remove(vehicleId); _disappearedIds.Add(vehicleId); } else { var veh = new Vehicle(_vehicleById[vehicleId], vehicleUpdate); _vehicleById[vehicleId] = veh; if (veh.PlayerId != MyStrategy.Me.Id) { OppCheckedVehicles.Remove(veh.Id); OppUncheckedVehicles.Remove(veh.Id); } } } var errorsCount = 0; foreach (var veh in _vehicleById.Values) { var prev = MoveObserver.BeforeMoveUnits.ContainsKey(veh.Id) ? MoveObserver.BeforeMoveUnits[veh.Id] : null; var cur = VehicleById.ContainsKey(veh.Id) ? VehicleById[veh.Id] : null; var updatedVehicle = new AVehicle(veh); if (updatedVehicle.IsMy) { if (prev != null) { AVehicle aveh = new AVehicle(prev); if (!Geom.PointsEquals(prev, updatedVehicle)) // в local runner сдвинулся { aveh.Move(); } if (!Geom.PointsEquals(aveh, updatedVehicle)) { Console.WriteLine("Looks vehicle updated wrong (X, Y)"); } if ((aveh.Action == AVehicle.MoveType.Move || aveh.Action == AVehicle.MoveType.Scale) && Geom.DoublesEquals(aveh.MoveLengthOrRotationAngle, 0) || aveh.Action == AVehicle.MoveType.Rotate && Geom.DoublesEquals(aveh.MoveLengthOrRotationAngle, 0)) { aveh.ForgotTarget(); } updatedVehicle.Action = aveh.Action; updatedVehicle.MoveVectorOrRotationCenter = aveh.MoveVectorOrRotationCenter; updatedVehicle.MoveSpeedOrAngularSpeed = aveh.MoveSpeedOrAngularSpeed; updatedVehicle.MoveLengthOrRotationAngle = aveh.MoveLengthOrRotationAngle; updatedVehicle.DurabilityPool = cur.DurabilityPool; //TODO: поддерживать DurabilityPool if (!updatedVehicle.IsMy) } // дополнительные проверки if (prev != null && !Geom.PointsEquals(prev, updatedVehicle)) // в local runner сдвинулся { var tmp = new AVehicle(cur); if (Geom.PointsEquals(prev, cur)) { tmp = new AVehicle(prev); tmp.Move(); errorsCount++; } if (!Geom.PointsEquals(tmp, updatedVehicle)) { Console.WriteLine("Looks vehicle updated wrong (X, Y)"); } } else if (!Geom.PointsEquals(cur, updatedVehicle)) // мой сдвинулся, а в local runner нет { errorsCount++; var tmp = new AVehicle(updatedVehicle); tmp.Move(); if (!Geom.PointsEquals(cur, tmp)) { Console.WriteLine("Looks vehicle updated wrong (X, Y)"); } } } VehicleById[veh.Id] = updatedVehicle; if (cur != null && updatedVehicle.IsSelected != cur.IsSelected) { Console.WriteLine("Looks vehicle updated wrong (IsSelected)"); } } if (errorsCount > 0) { Logger.Log("Move errors count: " + errorsCount); } }
private static double _getSquaredDistanceTo(T value, double x, double y, double defaultValue = double.PositiveInfinity) { return(value == null ? defaultValue : Geom.SumSqr(value.X - x, value.Y - y)); }
private Tuple <double, AMove> _nuclearFindMove(Sandbox env, double selTotalDamage, bool checkOnly) { AMove selMove = null; for (var s = 0; s < GroupsManager.MyGroups.Count + MyUngroupedClusters.Count; s++) { var vehicles = s < GroupsManager.MyGroups.Count ? env.GetVehicles(true, GroupsManager.MyGroups[s]) : MyUngroupedClusters[s - GroupsManager.MyGroups.Count]; var myAvg = Utility.Average(vehicles); var vrg = G.VisionRange[(int)VehicleType.Fighter] + G.MaxTacticalNuclearStrikeDamage; var oppGroups = OppClusters .Where(cl => cl.Avg.GetDistanceTo(myAvg) < vrg && cl.Any(x => env.VehicleById.ContainsKey(x.Id)))// пропускать полностью фантомные группы .OrderBy(cl => cl.Avg.GetDistanceTo(myAvg)) .Take(3) .ToArray(); foreach (var veh in vehicles) { if (!veh.IsSelected && MoveObserver.AvailableActions < 3) { continue; } if (veh.IsSelected && MoveObserver.AvailableActions < 2) { continue; } var vr = veh.ActualVisionRange * 0.9; foreach ( var oppGroup in new[] { env.GetOpponentNeighbours(veh.X, veh.Y, vr + G.TacticalNuclearStrikeRadius) }.Concat(oppGroups)) { ANuclear nuclear; var totalDamage = _nuclearGetDamage(veh, env, selTotalDamage, oppGroup, out nuclear); if (totalDamage <= selTotalDamage) { continue; } var vehNextMove = new AVehicle(veh); for (var t = 0; t < 3; t++) { vehNextMove.Move(); } if (vehNextMove.GetDistanceTo2(nuclear) + Const.Eps >= Geom.Sqr(vehNextMove.ActualVisionRange)) { continue; } const int n = 10; if (vehicles.Count > n) { var myDist2 = veh.GetDistanceTo2(nuclear); var myNearestCount = vehicles.Count(x => x.GetDistanceTo2(nuclear) <= myDist2); if (myNearestCount < n) { continue; } } selTotalDamage = totalDamage; selMove = new AMove { Action = ActionType.TacticalNuclearStrike, VehicleId = veh.Id, Point = nuclear, }; if (checkOnly) { return(new Tuple <double, AMove>(selTotalDamage, selMove)); } } } } if (selMove == null) { return(null); } return(new Tuple <double, AMove>(selTotalDamage, selMove)); }
public static bool IsInRange2(this AbsolutePosition position, Range2 range) => Geom.Between(range.XMin, range.XMax, position.X) && Geom.Between(range.YMin, range.YMax, position.Y);
private double _getSquaredDistanceTo(T value, double defaultValue = double.PositiveInfinity) { return(value == null || value.Id == _id ? defaultValue : Geom.SumSqr(value.X - _x, value.Y - _y)); }
public bool IntersectsWith(Rect rect) { return(Geom.Intersect1D(X, X2, rect.X, rect.X2) && Geom.Intersect1D(Y, Y2, rect.Y, rect.Y2)); }
private T _findNearest(Node node, double left, double top, double right, double bottom) { if (node.Value != null) { if (_getSquaredDistanceTo(node.Value, _squaredDistance) <= _squaredDistanceE) { return(node.Value); } return(null); } if (!node.HasValueBelow) { return(null); } var centerX = (left + right) / 2.0D; var centerY = (top + bottom) / 2.0D; if (_x < centerX) { if (_y < centerY) { var nearestValue = _findNearest(node.LeftTop, left, top, centerX, centerY); var nearestSquaredDistance = _getSquaredDistanceTo(nearestValue, _squaredDistance); if (nearestSquaredDistance + _epsilon >= Geom.Sqr(centerX - _x)) { var otherValue = _findNearest(node.RightTop, centerX, top, right, centerY); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon >= Geom.Sqr(centerY - _y)) { var otherValue = _findNearest(node.LeftBottom, left, centerY, centerX, bottom); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon >= Geom.SumSqr(centerX - _x, centerY - _y)) { var otherValue = _findNearest(node.RightBottom, centerX, centerY, right, bottom); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; } } return(nearestValue); } else { var nearestValue = _findNearest(node.LeftBottom, left, centerY, centerX, bottom); var nearestSquaredDistance = _getSquaredDistanceTo(nearestValue, _squaredDistance); if (nearestSquaredDistance + _epsilon >= Geom.Sqr(centerX - _x)) { var otherValue = _findNearest(node.RightBottom, centerX, centerY, right, bottom); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _x, _y, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon > Geom.Sqr(_y - centerY)) { var otherValue = _findNearest(node.LeftTop, left, top, centerX, centerY); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon >= Geom.SumSqr(centerX - _x, _y - centerY)) { var otherValue = _findNearest(node.RightTop, centerX, top, right, centerY); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; } } return(nearestValue); } } else { if (_y < centerY) { var nearestValue = _findNearest(node.RightTop, centerX, top, right, centerY); var nearestSquaredDistance = _getSquaredDistanceTo(nearestValue, _squaredDistance); if (nearestSquaredDistance + _epsilon > Geom.Sqr(_x - centerX)) { var otherValue = _findNearest(node.LeftTop, left, top, centerX, centerY); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon >= Geom.Sqr(centerY - _y)) { var otherValue = _findNearest(node.RightBottom, centerX, centerY, right, bottom); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon >= Geom.SumSqr(_x - centerX, centerY - _y)) { var otherValue = _findNearest(node.LeftBottom, left, centerY, centerX, bottom); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; } } return(nearestValue); } else { var nearestValue = _findNearest(node.RightBottom, centerX, centerY, right, bottom); var nearestSquaredDistance = _getSquaredDistanceTo(nearestValue, _squaredDistance); if (nearestSquaredDistance + _epsilon > Geom.Sqr(_x - centerX)) { var otherValue = _findNearest(node.LeftBottom, left, centerY, centerX, bottom); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon > Geom.Sqr(_y - centerY)) { var otherValue = _findNearest(node.RightTop, centerX, top, right, centerY); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; nearestSquaredDistance = otherSquaredDistance; } } if (nearestSquaredDistance + _epsilon > Geom.SumSqr(_x - centerX, _y - centerY)) { var otherValue = _findNearest(node.LeftTop, left, top, centerX, centerY); var otherSquaredDistance = _getSquaredDistanceTo(otherValue, _squaredDistance); if (otherSquaredDistance < nearestSquaredDistance) { nearestValue = otherValue; } } return(nearestValue); } } }
public void DoNuclears() { var needRemove = false; foreach (var nuclear in Nuclears) { if (VehicleById.ContainsKey(nuclear.VehicleId)) // если нет информации о владельце, то оставлять бомбу { var owner = VehicleById[nuclear.VehicleId]; if (!owner.IsAlive || owner.GetDistanceTo2(nuclear) + Const.Eps > Geom.Sqr(owner.ActualVisionRange)) { needRemove = true; nuclear.RemainingTicks = 0; continue; } } nuclear.RemainingTicks--; if (nuclear.RemainingTicks == 0) { needRemove = true; foreach (var target in GetAllNeighbours(nuclear.X, nuclear.Y, nuclear.Radius)) { target.Durability -= target.GetNuclearDamage(nuclear); } } } if (needRemove) { Nuclears = Nuclears.Where(x => x.RemainingTicks > 0).ToArray(); } }
public static bool IsInRange(this double value, double minLimit, double maxLimit) => Geom.Between(minLimit, maxLimit, value);
private void _doMove1(AVehicle[] vehicles) { var unblockedLength = 0; for (var i = 0; i < vehicles.Length; i++) { var veh = vehicles[i]; if (veh.Action == AVehicle.MoveType.None) { veh.Move(); _complete[i] = true; continue; } if (_movedState[i] == null) { _movedState[i] = new AVehicle(veh); } else { _movedState[i].CopyFrom(veh); } if (!_movedState[i].Move()) { veh.CopyFrom(_movedState[i]); _complete[i] = true; continue; } _unblocked[unblockedLength++] = i; _complete[i] = false; veh.Index = i; if (_deps[i] == null) { _deps[i] = new int[MagicMaxDependenciesCount]; } _depsLen[i] = 0; } while (unblockedLength > 0) { var unblockedNewLength = 0; for (var i = 0; i < unblockedLength; i++) { var idx = _unblocked[i]; var movedUnit = _movedState[idx]; var unitTree = _tree(movedUnit.IsMy, movedUnit.IsAerial); var oppTree = _tree(!movedUnit.IsMy, movedUnit.IsAerial); var intersectsWith = -1; do { { var nearest = unitTree.FindFirstNearby(movedUnit, Geom.Sqr(2 * movedUnit.Radius)); if (nearest != null) { if (nearest.IntersectsWith(movedUnit)) { intersectsWith = nearest.Index; break; } } } if (!movedUnit.IsAerial && CheckCollisionsWithOpponent) { var nearest = oppTree.FindFirstNearby(movedUnit, Geom.Sqr(2 * movedUnit.Radius)); if (nearest != null) { if (nearest.IntersectsWith(movedUnit)) { intersectsWith = nearest.Index; break; } } } } while (false); if (intersectsWith != -1) { if (!_complete[intersectsWith]) { _deps[intersectsWith][_depsLen[intersectsWith]++] = idx; } } else { var unit = vehicles[idx]; var prevX = unit.X; var prevY = unit.Y; unit.CopyFrom(movedUnit); if (!Geom.PointsEquals(prevX, prevY, movedUnit.X, movedUnit.Y)) { unit.X = prevX; unit.Y = prevY; if (!unitTree.ChangeXY(unit, movedUnit.X, movedUnit.Y)) { throw new Exception("Can't change unit coordinates, id=" + unit.Id); } if (_nearestFightersCacheTick != null && _nearestFightersCacheTick[idx] != -1) { _nearestFightersCacheDist[idx] -= unit.GetDistanceTo(prevX, prevY); } } } if (intersectsWith == -1 || _complete[intersectsWith]) { // resolve dependencies _complete[idx] = true; for (var k = 0; k < _depsLen[idx]; k++) { _unblocked2[unblockedNewLength++] = _deps[idx][k]; } } } unblockedLength = unblockedNewLength; Utility.Swap(ref _unblocked, ref _unblocked2); } }
public AVehicle GetFirstIntersector(ACircularUnit circle, bool isAerial) { for (var isMy = 0; isMy < 2; isMy++) { var nearby = _tree(isMy == 1, isAerial).FindFirstNearby(circle.X, circle.Y, Geom.Sqr(circle.Radius + G.VehicleRadius), -1); if (nearby != null && nearby.IntersectsWith(circle)) { return(nearby); } } return(null); }
public void ApplyMove(Move move) { // TODO: проверки на валидность var movePt = new Point(move.X, move.Y); var moveVecNorm = movePt.Normalized(); var moveVecLength = movePt.Length; switch (move.Action) { case ActionType.ClearAndSelect: foreach (var unit in MyVehicles) { if (move.Group != 0) { unit.IsSelected = unit.HasGroup(move.Group); } else { unit.IsSelected = Geom.Between(move.Left, move.Right, unit.X) && Geom.Between(move.Top, move.Bottom, unit.Y) && (move.VehicleType == null || move.VehicleType == unit.Type); } } break; case ActionType.AddToSelection: foreach (var unit in MyVehicles) { if (move.Group != 0) { unit.IsSelected = unit.HasGroup(move.Group); } else { unit.IsSelected |= Geom.Between(move.Left, move.Right, unit.X) && Geom.Between(move.Top, move.Bottom, unit.Y) && (move.VehicleType == null || move.VehicleType == unit.Type); } } break; case ActionType.Deselect: foreach (var unit in MyVehicles) { if (!unit.IsSelected) { continue; } if (move.Group != 0) { if (unit.HasGroup(move.Group)) { unit.IsSelected = false; } } else { if (Geom.Between(move.Left, move.Right, unit.X) && Geom.Between(move.Top, move.Bottom, unit.Y) && (move.VehicleType == null || move.VehicleType == unit.Type)) { unit.IsSelected = false; } } } break; case ActionType.Assign: foreach (var unit in Vehicles) { if (!unit.IsMy) { continue; } unit.AddGroup(move.Group); } break; case ActionType.Move: foreach (var unit in Vehicles) { if (!unit.IsSelected) { continue; } unit.Action = AVehicle.MoveType.Move; unit.MoveSpeedOrAngularSpeed = move.MaxSpeed; unit.MoveVectorOrRotationCenter = moveVecNorm; unit.MoveLengthOrRotationAngle = moveVecLength; } break; case ActionType.Rotate: foreach (var unit in Vehicles) { if (!unit.IsSelected) { continue; } unit.Action = AVehicle.MoveType.Rotate; unit.MoveSpeedOrAngularSpeed = move.MaxAngularSpeed; unit.MoveLengthOrRotationAngle = move.Angle; unit.MoveVectorOrRotationCenter = movePt; } break; case ActionType.Scale: foreach (var unit in Vehicles) { if (!unit.IsSelected) { continue; } unit.Action = AVehicle.MoveType.Scale; unit.MoveSpeedOrAngularSpeed = move.MaxSpeed; var vec = (unit - movePt) * move.Factor + movePt - unit; unit.MoveVectorOrRotationCenter = vec.Normalized(); unit.MoveLengthOrRotationAngle = vec.Length; } break; } }
public static double AreaCoeff(double area, int count) { var r = Geom.Sqr(2 * G.VehicleRadius) * count / area; return(Math.Pow(r, 0.25)); }
private void _findAllNearby(Node node, double left, double top, double right, double bottom) { if (node.Value != null) { if (_getSquaredDistanceTo(node.Value) <= _squaredDistanceE) { _values.Add(node.Value); } return; } if (!node.HasValueBelow) { return; } var centerX = (left + right) / 2.0D; var centerY = (top + bottom) / 2.0D; if (_x < centerX) { if (_y < centerY) { _findAllNearby(node.LeftTop, left, top, centerX, centerY); if (_squaredDistanceE >= Geom.Sqr(centerX - _x)) { _findAllNearby(node.RightTop, centerX, top, right, centerY); } if (_squaredDistanceE >= Geom.Sqr(centerY - _y)) { _findAllNearby(node.LeftBottom, left, centerY, centerX, bottom); } if (_squaredDistanceE >= Geom.SumSqr(centerX - _x, centerY - _y)) { _findAllNearby(node.RightBottom, centerX, centerY, right, bottom); } } else { _findAllNearby(node.LeftBottom, left, centerY, centerX, bottom); if (_squaredDistanceE >= Geom.Sqr(centerX - _x)) { _findAllNearby(node.RightBottom, centerX, centerY, right, bottom); } if (_squaredDistanceE > Geom.Sqr(_y - centerY)) { _findAllNearby(node.LeftTop, left, top, centerX, centerY); } if (_squaredDistanceE >= Geom.SumSqr(centerX - _x, _y - centerY)) { _findAllNearby(node.RightTop, centerX, top, right, centerY); } } } else { if (_y < centerY) { _findAllNearby(node.RightTop, centerX, top, right, centerY); if (_squaredDistanceE > Geom.Sqr(_x - centerX)) { _findAllNearby(node.LeftTop, left, top, centerX, centerY); } if (_squaredDistanceE >= Geom.Sqr(centerY - _y)) { _findAllNearby(node.RightBottom, centerX, centerY, right, bottom); } if (_squaredDistanceE >= Geom.SumSqr(_x - centerX, centerY - _y)) { _findAllNearby(node.LeftBottom, left, centerY, centerX, bottom); } } else { _findAllNearby(node.RightBottom, centerX, centerY, right, bottom); if (_squaredDistanceE > Geom.Sqr(_x - centerX)) { _findAllNearby(node.LeftBottom, left, centerY, centerX, bottom); } if (_squaredDistanceE > Geom.Sqr(_y - centerY)) { _findAllNearby(node.RightTop, centerX, top, right, centerY); } if (_squaredDistanceE > Geom.SumSqr(_x - centerX, _y - centerY)) { _findAllNearby(node.LeftTop, left, top, centerX, centerY); } } } }
public virtual bool IntersectsWith(ACircularUnit unit) { // если касаются, то false return(GetDistanceTo2(unit) < Geom.Sqr(Radius + unit.Radius)); }
public static bool IsInRange(this double value, Range range) => Geom.Between(range.MinLimit, range.MaxLimit, value);