public void UpdateZoneEvaluations(ContextInfo context) { }
public IList<Task> DefineTasks(ContextInfo context) { if(_tasks == null) _tasks = context.Zones.Select(z => new Task { AssociatedZone = z }).ToList(); foreach(var task in _tasks.AsParallel()) { var zoneInfo = task.AssociatedZone; var zone = zoneInfo.Zone; task.Type = (zone.OwnerId == context.MyTeamId ? TaskType.Defend : TaskType.Attack); Func<Point, int> nbrTurnsToReachZone = p => (int)Math.Ceiling(Math.Max(0, p.DistanceTo(zone.Center) - Zone.Radius) / GameContext.MaxMoveDistance); var myDrones = context.MyDrones .Select(d => new DroneWithDistance { Drone = d.Drone, NbrTurns = nbrTurnsToReachZone(d.Drone.Position) }) .OrderBy(d => d.NbrTurns) .ToArray(); var enemyDrones = context.EnemyDrones .Select(d => new DroneWithDistance { Drone = d.Drone, NbrTurns = nbrTurnsToReachZone(d.Drone.Position), TaskType = d.TaskType, AssociatedZone = d.AssociatedZone }) .ToArray(); // calculate nbr of required drones & gainable points if(task.Type == TaskType.Attack) { var defendingDrones = enemyDrones .Where(d => d.Drone.TeamId == zone.OwnerId) .Where(d => d.NbrTurns <= surroundingDistance || (d.TaskType == TaskType.Defend && d.AssociatedZone == zone)) .ToArray(); // how much drones do I need to capture this zone? int nbrTurnsToSucceed; int nbrRequiredDrones = this.CalculateRequiredDronesForAttack(zone.Id, myDrones, defendingDrones, out nbrTurnsToSucceed); _log.WriteLine("Req={0}, Turns={1}", nbrRequiredDrones, nbrTurnsToSucceed); // if they are other attacking squads, how much drones do I need to make sure I can recapture the zone if necessary? var otherAttackingDroneSquads = enemyDrones .Where(d => d.Drone.TeamId != zone.OwnerId) .Where(d => d.NbrTurns <= surroundingDistance || (d.TaskType == TaskType.Attack && d.AssociatedZone == zone)) .ToLookup(d => d.Drone.TeamId); foreach(var enemySquad in otherAttackingDroneSquads) { int nbrTurnsToSucceed2; int nbrRequiredDrones2 = this.CalculateRequiredDronesForAttack(zone.Id, myDrones, enemySquad, out nbrTurnsToSucceed2); _log.WriteLine("Req={0}, Turns={1}", nbrRequiredDrones2, nbrTurnsToSucceed2); if(nbrTurnsToSucceed2 == nbrTurnsToSucceed) { if(nbrRequiredDrones2 > nbrRequiredDrones) nbrRequiredDrones = nbrRequiredDrones2; } else if(nbrTurnsToSucceed2 > nbrTurnsToSucceed) { nbrTurnsToSucceed = nbrTurnsToSucceed2; nbrRequiredDrones = nbrRequiredDrones2; } } task.NbrRequiredDrones = nbrRequiredDrones; task.AverageGainablePoints = (nbrTurnsConsidered - nbrTurnsToSucceed) / (double)nbrTurnsConsidered; } else { int? nbrTurnsToFail = null; int? nbrRequiredDrones = null; // how much drones do I need to defend the zone against each attacking squad? var attackingDroneSquads = enemyDrones .Where(d => d.NbrTurns <= surroundingDistance || (d.TaskType == TaskType.Attack && d.AssociatedZone == zone)) .ToLookup(d => d.Drone.TeamId); foreach(var enemySquad in attackingDroneSquads) { int nbrTurnsToFail2; int nbrRequiredDrones2 = this.CalculateRequiredDronesForDefense(zone.Id, myDrones, enemySquad, out nbrTurnsToFail2); _log.WriteLine("Req={0}, Turns={1}", nbrRequiredDrones2, nbrTurnsToFail2); if(!nbrTurnsToFail.HasValue || nbrTurnsToFail2 < nbrTurnsToFail) { nbrTurnsToFail = nbrTurnsToFail2; nbrRequiredDrones = nbrRequiredDrones2; } else if(nbrTurnsToFail2 == nbrTurnsToFail) { if(nbrRequiredDrones2 > nbrRequiredDrones) nbrRequiredDrones = nbrRequiredDrones2; } } task.NbrRequiredDrones = nbrRequiredDrones ?? 0; task.AverageGainablePoints = (nbrTurnsToFail ?? nbrTurnsConsidered) / (double)nbrTurnsConsidered; } } return _tasks; }
public void AllocateDronesToTasks(ContextInfo context, IList<Task> tasks) { // calculate importance of attack vs defense var ownedZonesRatio = context.Context.Zones.Count(z => z.OwnerId == context.MyTeamId) / (double)context.Zones.Length; var necessaryZoneRatio = 1.0 / context.Context.Teams.Count; Level defenseImportance = Level.Medium, attackImportance = Level.Medium; if(ownedZonesRatio > 0.8 * necessaryZoneRatio) { defenseImportance = Level.High; attackImportance = Level.Low; } else if(ownedZonesRatio < 0.4 * necessaryZoneRatio) { defenseImportance = Level.Low; attackImportance = Level.High; } var taskImportances = tasks.ToDictionary(task => task, task => task.Type == TaskType.Attack ? attackImportance : defenseImportance); // calculate tasks priorities var taskPriorities = tasks.ToDictionary(task => task, task => 0 + 4.0 * task.AverageGainablePoints + 2.0 * (int)taskImportances[task] + 0.5 * (int)task.AssociatedZone.StrategicValue - 1.0 * task.NbrRequiredDrones); foreach(var task in tasks) { _log.WriteLine("{0}: {1} Priority={2:0.00} Pts={3:0.00} Req={4} Imp={5} Strat={6}", task.AssociatedZone.Zone.Id, task.Type, taskPriorities[task], task.AverageGainablePoints, task.NbrRequiredDrones, taskImportances[task], task.AssociatedZone.StrategicValue); } // alllocate drones to tasks var availableDrones = context.MyDrones.ToList(); foreach(var drone in availableDrones) drone.CurrentTask = null; var sortedTasks = tasks.OrderByDescending(t => taskPriorities[t]).ToArray(); for(int i = 0; i < sortedTasks.Length && availableDrones.Any(); i++) { var task = sortedTasks[i]; if(availableDrones.Count < task.NbrRequiredDrones) { // there are not enough available drones to handle this task // maybe we should skip it and concentrate on the next task if(i < sortedTasks.Length - 1) { var nextTask = sortedTasks[i + 1]; if(availableDrones.Count >= nextTask.NbrRequiredDrones) continue; } } int nbrAllocatedDrones = 0; while(nbrAllocatedDrones < task.NbrRequiredDrones) { if(!availableDrones.Any()) break; // Pick the drone which is closest to the task target) var candidate = availableDrones.MinBy(d => d.Drone.Position.DistanceTo(task.AssociatedZone.Zone.Center)); availableDrones.Remove(candidate); candidate.CurrentTask = task; nbrAllocatedDrones++; } } if(availableDrones.Any()) // some drones were not assigned => do a second pass { for(int i = 0; i < sortedTasks.Length && availableDrones.Any(); i++) { var task = sortedTasks[i]; // Pick the drone which is closest to the task target) var candidate = availableDrones.MinBy(d => d.Drone.Position.DistanceTo(task.AssociatedZone.Zone.Center)); availableDrones.Remove(candidate); candidate.CurrentTask = task; } } }
public void AllocateDronesToTasks(ContextInfo context, IList<Task> tasks) { // how many zones do I need? var nbrZonesToTarget = (int)Math.Ceiling(1 + context.Zones.Length / (double)context.Context.Teams.Count); nbrZonesToTarget++; // get zones to consider ZoneInfo[] zonesToTarget; var myZones = context.Zones.Where(z => z.Zone.OwnerId == context.MyTeamId).ToArray(); if(myZones.Any()) { var medianPoint = HelperExtensions.GetMedianPoint(myZones.Select(z => z.Zone.Center).ToArray()); zonesToTarget = context.Zones.OrderBy(z => medianPoint.DistanceTo(z.Zone.Center)).Take(nbrZonesToTarget).ToArray(); } else { zonesToTarget = context.Zones; } _log.WriteLine("nbrZonesToTarget={0} | zonesToTarget={1}", nbrZonesToTarget, string.Join(",", zonesToTarget.Select(z => z.Zone.Id))); foreach(var task in tasks.OrderBy(t => t.AssociatedZone.Zone.Id)) _log.WriteLine("{0}: {1} Pts={2:0.00} Req={3}", task.AssociatedZone.Zone.Id, task.Type, task.AverageGainablePoints, task.NbrRequiredDrones); // alllocate drones to tasks var availableDrones = context.MyDrones.ToList(); foreach(var drone in availableDrones) drone.CurrentTask = null; var sortedTasks = tasks .Where(t => zonesToTarget.Contains(t.AssociatedZone)) .OrderByDescending(t => t.NbrRequiredDrones == 0 ? int.MaxValue : t.AverageGainablePoints / t.NbrRequiredDrones) .ToArray(); int nbrAssignedTasks = 0; for(int i = 0; i < sortedTasks.Length && nbrAssignedTasks < nbrZonesToTarget && availableDrones.Any(); i++) { var task = sortedTasks[i]; if(availableDrones.Count() < task.NbrRequiredDrones) continue; for(int nbrAllocatedDrones = 0; nbrAllocatedDrones < task.NbrRequiredDrones; nbrAllocatedDrones++) { // Pick the drone which is closest to the task target) var candidate = availableDrones.MinBy(d => d.Drone.Position.DistanceTo(task.AssociatedZone.Zone.Center)); availableDrones.Remove(candidate); candidate.CurrentTask = task; } nbrAssignedTasks++; } }
public void SetDroneDestinations(ContextInfo context) { var myZones = context.Zones.Where(z => z.Zone.OwnerId == context.MyTeamId).ToArray(); var medianPoint = new Point(GameContext.FieldWidth / 2, GameContext.FieldHeight / 2); if(myZones.Any()) medianPoint = HelperExtensions.GetMedianPoint(myZones.Select(z => z.Zone.Center).ToArray()); foreach(var droneInfo in context.MyDrones) { var task = droneInfo.CurrentTask; if(task != null) { if(task.Type == TaskType.Defend && task.AssociatedZone.Zone.Contains(droneInfo.Drone.Position)) droneInfo.Destination = droneInfo.Drone.Position; // no need to move else droneInfo.Destination = droneInfo.Drone.Position.GetZoneBorderPoint(task.AssociatedZone.Zone); } else { // send the drone on patrol droneInfo.Destination = medianPoint; } } }
public void GuessEnemyDronesActivity(ContextInfo context) { var zones = context.Context.Zones; var zoneCenters = zones.Select(z => z.Center).ToArray(); var zoneDistances = zones.Select(z => new ZoneWithDistance { Zone = z }).ToArray(); foreach(var drone in context.EnemyDrones.AsParallel()) { // based on the drone last movement, try to identify the zone it's trying to reach var position = drone.Drone.Position; var previousPosition = drone.Drone.PreviousPosition; if(position.DistanceTo(previousPosition) < 2) // this drone didn't move. Is it already inside a zone? { drone.AssociatedZone = zones.FirstOrDefault(z => z.Contains(position)); } else { var distances = HelperExtensions.RespectiveDistancesToLine(zoneCenters, previousPosition, position); for(int i = 0; i < zoneCenters.Length; i++) zoneDistances[i].Distance = distances[i]; var possibleTargets = zoneDistances .Where(zd => zd.Distance < 1.5 * Zone.Radius) .Where(zd => MathHelper.DotProduct(previousPosition, position, previousPosition, zd.Zone.Center) > 0) // ignore zones behind the drone .Select(zd => zd.Zone) .ToArray(); if(possibleTargets.Any()) { drone.AssociatedZone = possibleTargets.MinBy(z => z.Center.DistanceTo(position)); } else { drone.AssociatedZone = null; _log.WriteLine("*** no targets found for Drone {0}/{1}", drone.Drone.TeamId, drone.Drone.Id); _log.WriteLine("{0},{1} -> {2},{3}", previousPosition.X, previousPosition.Y, position.X, position.Y); for(int i = 0; i < zoneCenters.Length; i++) _log.WriteLine("{0}: {1:0.00}", i, distances[i]); _log.WriteLine("***"); } } if(drone.AssociatedZone == null) drone.TaskType = TaskType.Unknown; else drone.TaskType = (drone.AssociatedZone.OwnerId == drone.Drone.TeamId ? TaskType.Defend : TaskType.Attack); } foreach(var drone in context.EnemyDrones.OrderBy(d => d.Drone.TeamId).ThenBy(d => d.Drone.Id)) _log.WriteLine("{0}/{1}: {2} {3}", drone.Drone.TeamId, drone.Drone.Id, drone.TaskType, drone.AssociatedZone == null ? "/" : drone.AssociatedZone.Id.ToString()); }
public void Initialize(GameContext context) { var errorlog = Console.Error; var dummyLog = new StreamWriter(Stream.Null); _droneActivityObserver = new BasicDroneActivityObserver(dummyLog); _zoneEvaluator = new BasicZoneEvaluator(dummyLog); _taskOrganizer = new OneTaskPerZoneOrganizer(dummyLog); _droneAllocator = (context.Teams.Count > 2 ? (IDroneAllocator)new FocusedDroneAllocator(dummyLog) : (IDroneAllocator)new PriorityBasedDroneAllocator(dummyLog)); _droneCommander = new BasicDroneCommander(dummyLog); _contextInfo = new ContextInfo(this.TeamId, context); _contextInfo.Zones = context.Zones.Select(z => new ZoneInfo(z)).ToArray(); _contextInfo.MyDrones = context.GetDronesOfTeam(this.TeamId).Select(d => new MyDroneInfo(d)).ToArray(); _contextInfo.EnemyDrones = context.GetDronesOfOtherTeams(this.TeamId).Select(d => new EnemyDroneInfo(d)).ToArray(); _zoneEvaluator.GiveInitialZoneEvaluations(_contextInfo.Zones); }
public void UpdateZoneEvaluations(ContextInfo context) { // do nothing }