public Satellite(Satellite s) : this(s.Pos.Lat, s.Pos.Lon, s.Speed, s.RotSpeed, s.MaxRot, s.Id) { CurrentRot = new Coords(s.CurrentRot); CurrentTurn = s.CurrentTurn; Range = new Range(s.Range); }
public PartialSolution(float val, Range range, List<Snapshot> snaps, BitArray taken) { EstimatedValue = val; CurrentRange = range; Snapshots = snaps; PicturesTaken = taken; }
/// <summary> /// assumes satellite is already at the right position /// </summary> public Snapshot TakePicture(Coords pict) { CurrentRot.Lat = pict.Lat - Pos.Lat; CurrentRot.Lon = pict.Lon - Pos.Lon; Range = new Range {DeltaLatMin = CurrentRot.Lat, DeltaLatMax = CurrentRot.Lat, DeltaLonMin = CurrentRot.Lon, DeltaLonMax = CurrentRot.Lon}; //reset range to zero around current direction return new Snapshot(pict.Lat, pict.Lon, CurrentTurn, Id); }
public static Solution Solve(Input input) { var tree = BuildTree(input); var satellites = input.Satellites.OrderBy(s => s.MaxRot).ToArray(); var totalNbPic = tree.Count; var solution = new List<Snapshot>(); var picturesConfirmed = new BitArray(totalNbPic); for (int s = 0; s < satellites.Length; s++) { var satellite = satellites[s]; Console.WriteLine($"satellite {s+1}/{satellites.Length} (#{satellite.Id})"); var state = new List<PartialSolution> {new PartialSolution(picturesConfirmed)}; for (int t = 1; t < input.NbTurns; t++) { if (t % 20000 == 0) Console.WriteLine(t); Step(state, satellite); SimplifyRanges(state); //look for pictures to take var candidates = tree.RadialSearch(new float[] {satellite.Pos.Lat, satellite.Pos.Lon}, satellite.MaxRot*SQRT2, 150); //TOO SLOW ! Helper.Assert(() => candidates.Length < 145, candidates.Length); candidates = candidates.Where(node => !picturesConfirmed.Get(node.Value.Item1 + node.Value.Item2.BasePicId) && node.Value.Item2.PictureCanBeTaken(t)).ToArray(); var stopIdx = state.Count; //we're gonna add more, but we don't want to browse'em for (int st = 0; st < stopIdx; st++) { var sol = state[st]; var range = sol.CurrentRange; foreach (var candidate in candidates) { var collec = candidate.Value.Item2; var picIdx = candidate.Value.Item1; if(sol.PicturesTaken.Get(collec.BasePicId + picIdx)) continue; var picLoc = collec.Locations[picIdx]; if (picLoc.IsInRange(range, satellite.Pos)) { var newScore = sol.EstimatedValue + Score(collec, sol); var newRange = new Range(satellite.Pos, picLoc); if (!WorthTaking(newScore, newRange, state)) continue; var newCommands = new List<Snapshot>(sol.Snapshots); newCommands.Add(new Snapshot(picLoc.Lat, picLoc.Lon, t, satellite.Id)); var taken = new BitArray(sol.PicturesTaken); taken.Set(collec.BasePicId + picIdx, true); state.Add(new PartialSolution (newScore, newRange, newCommands, taken)); } } } } PartialSolution best = null; foreach (var partialSolution in state) { if (best == null || partialSolution.EstimatedValue > best.EstimatedValue) best = partialSolution; } solution.AddRange(best.Snapshots); picturesConfirmed.Or(best.PicturesTaken); //union } int score = 0; foreach (var picCollection in input.Collections) { bool complete = true; var stop = picCollection.BasePicId + picCollection.Locations.Count; for (int i = picCollection.BasePicId; i < stop; i++) { if (!picturesConfirmed.Get(i)) { complete = false; break; } } if (complete) score += picCollection.Value; } return new Solution(solution, score); }
public PartialSolution(BitArray taken) { CurrentRange = new Range(); Snapshots = new List<Snapshot>(); PicturesTaken = taken; }
static bool WorthTaking(float newScore, Range newRange, List<PartialSolution> state) { bool take = true; Parallel.ForEach(state, (sol, loop) => { if (newScore <= sol.EstimatedValue && sol.CurrentRange.Contains(newRange)) { take = false; loop.Stop(); } }); return take; }
public Range(Range range) { DeltaLatMin = range.DeltaLatMin; DeltaLatMax = range.DeltaLatMax; DeltaLonMin = range.DeltaLonMin; DeltaLonMax = range.DeltaLonMax; }
public bool Contains(Range other) { return other.DeltaLatMin >= DeltaLatMin && other.DeltaLatMax <= DeltaLatMax && other.DeltaLonMin >= DeltaLonMin && other.DeltaLonMax <= DeltaLonMax; }