public static Solution Solve(Input input) { var takenPictures = new List<Snapshot>(); var tree = new KdTree<float, PicCollection>(2, new FloatMath()); foreach (var picCollection in input.Collections) { foreach (var pict in picCollection.Locations) { tree.Add(new float[] { pict.Lat, pict.Lon }, picCollection); } } tree.Balance(); var orderedSatellelites = input.Satellites.OrderByDescending(sat => sat.MaxRot).ToList(); for (int s = 0; s < orderedSatellelites.Count; ++s) { var satellite = orderedSatellelites[s]; for (int turn = 0; turn < input.NbTurns; ++turn) { var node = tree.RadialSearch(new float[] { satellite.Pos.Lat, satellite.Pos.Lon }, satellite.MaxRot*SQRT2, 150).ToArray(); if (node.Length > 0) { var valids = node.Where(n => n.Value.PictureCanBeTaken(turn)) .Where(k => satellite.CanTakePicture((int)k.Point[0], (int)k.Point[1])) .OrderByDescending(k => Math.Pow(k.Point[0] - satellite.Pos.Lat, 2) + Math.Pow(k.Point[1] - satellite.Pos.Lon, 2)) //.OrderByDescending(k => k.Value.TakenPictures.Count) .ToList(); if (valids.Count > 0) { Console.WriteLine("Found {0} valid new positions", valids.Count); var pict = valids[0]; var pictCoord = new Coords((int)pict.Point[0], (int)pict.Point[1]); var snap = satellite.TakePicture(pictCoord); takenPictures.Add(snap); pict.Value.TakePicture(pictCoord); pict.Value.Locations.Remove(pictCoord); tree.RemoveAt(pict.Point); Console.WriteLine("Satellite {1} Found {0} pict - Turn {2}", node.Length, satellite.Id, turn); ////Console.WriteLine("Satellite Lat {0} Lon {1} Pict {2} {3} Rot {4} {5}", satellite.Pos.Lat, //satellite.Pos.Lon, pict.Point[0], pict.Point[1], satellite.CurrentRot.Lat, satellite.CurrentRot.Lon); } } satellite.NextTurn(); } } var score = input.Collections.Where(c => c.Locations.Count == 0 && c.TakenPictures.Count > 0).Sum(p => p.Value); var solution = new Solution(takenPictures, score); return solution; }
public int TestScoreForTurn(int turn) { var s = new Solution(new Input {NbTurns = 160}); return s.GetScoreForDeliveryOn(turn); }
public static Solution Solve(Input input) { _multidroneMalus = 1.0 + Helper.Rand.NextDouble(); //choose a random malus between 1 and 2 for this run var solution = new Solution(input); var drones = new Drone[input.NbDrones]; for (int d = 0; d < input.NbDrones; d++) { drones[d] = new Drone(input, d); } var iteration = 0; //to ease debuging a particular step while (true) { iteration++; //chooseDrone furthest in the past Drone chosen = drones[0]; for (int d = 1; d < drones.Length; d++) { if (drones[d].turn < chosen.turn) chosen = drones[d]; } if (chosen.turn > input.NbTurns) { Console.WriteLine("end of times reached"); return solution; //can't do shit anymore } //choose order WareHouse wh; var order = GetBestOrder(chosen, input, out wh); if (order == null) { return solution; //no more order to deliver } if (wh != null) { //go to warehouse and load everything for (int i = 0; i < order.ItemsWanted.Length; i++) { var itemType = order.ItemsWanted[i]; if(itemType < 0) continue; wh.Stock[itemType]--; Helper.Assert(() => wh.Stock[itemType] >= 0); chosen.Load(wh, itemType); solution.LoadForDelivery(chosen, wh, order, itemType); } //everything is loaded for (int dd = 0; dd < order.NbItemsRemaining; dd++) { chosen.Deliver(order); } solution.DoDeliver(chosen, order, orderComplete: true); order.ItemsWanted = null; } else //we'll have to go to several warehouses to load stuff OR we'll need several drones { var loadedToDeliver = new List<int>(); var itemsToDeliver = (int[]) order.ItemsWanted.Clone(); while(itemsToDeliver.Any(it => it >= 0)) { //best warehouse with item in stock double bestScore = Double.PositiveInfinity; WareHouse bestwh = null; List<int> availableItems = null; for (int w = 0; w < input.NbWareHouses; w++) { var currentwh = input.WareHouses[w]; var items = currentwh.GetFulfillable(itemsToDeliver); if (items.Count > 0) { var score = (double) Helper.Distance(chosen.X, chosen.Y, currentwh.X, currentwh.Y)/items.Count; //time per item if (score < bestScore) { bestScore = score; bestwh = currentwh; availableItems = items; } } } wh = bestwh; for (int i = 0; i < availableItems.Count; i++) { var itemType = order.ItemsWanted[availableItems[i]]; if (itemType < 0) //already delivered continue; if (!chosen.CheckLoad(wh, itemType)) { //drone passed end of turns or is full goto deliver; //maybe we could stash one or two more small items, but whatever } wh.Stock[itemType]--; itemsToDeliver[availableItems[i]] = -1; chosen.Load(wh, itemType); solution.LoadForDelivery(chosen, wh, order, itemType); loadedToDeliver.Add(availableItems[i]); } } deliver: for (int dd = 0; dd < loadedToDeliver.Count; dd++) { chosen.Deliver(order); } for (int i = 0; i < loadedToDeliver.Count; i++) { Helper.Assert(() => order.ItemsWanted[loadedToDeliver[i]] >= 0); order.TotalWeight -= input.ProductTypes[order.ItemsWanted[loadedToDeliver[i]]]; order.ItemsWanted[loadedToDeliver[i]] = -1; //mark as delivered order.NbItemsRemaining--; } var orderComplete = order.NbItemsRemaining == 0; if (orderComplete) { Helper.Assert(() => order.ItemsWanted.All(it => it < 0)); order.ItemsWanted = null; } else { Helper.Assert(() => order.ItemsWanted.Any(it => it >= 0)); } solution.DoDeliver(chosen, order, orderComplete); } } }