public LocationEvent(Skier skier, DateTimeOffset time) { SkierId = skier.Id; Latitude = skier.Location.Latitude; Longitude = skier.Location.Longitude; EventTime = time; }
private void LoadUnloadSkiers(SimulatedChairlift lift, long currentTime) { for (int i = 0; i < lift.ChairLift.PassengerCount && lift.SkiersWaiting.Count > 0; i++) { Skier skier = lift.SkiersWaiting.Dequeue(); skier.StartTimeForCurrentStage = currentTime; skier.Location = lift.ChairLift.Top; // TODO: interpolate location between bottom and top Debug.Assert(!lift.SkiersRiding.Contains(skier)); lift.SkiersRiding.Enqueue(skier); } for (int i = 0; i < lift.ChairLift.PassengerCount && lift.SkiersRiding.Count > 0; i++) { Skier skier = lift.SkiersRiding.Peek(); if (currentTime - skier.StartTimeForCurrentStage >= lift.ChairLift.TimeToTop) { skier = lift.SkiersRiding.Dequeue(); skier.StartTimeForCurrentStage = currentTime; skier.Location = lift.ChairLift.Top; // TODO: randomize new chairlift target Debug.Assert(!lift.SkiersSkiingToThisLift.Contains(skier)); lift.SkiersSkiingToThisLift.Add(skier); } Debug.Assert(lift.SkiersRiding.Contains(skier) ^ lift.SkiersSkiingToThisLift.Contains(skier)); } lift.LastLoadTime = currentTime; }
private void ReportOut(long currentTime, List <SimulatedChairlift> simulatedLifts, Skier reference, Stopwatch watch) { Console.WriteLine($"------------{currentTime}"); string ridingLift = simulatedLifts.SingleOrDefault(l => l.SkiersRiding.Contains(reference))?.ChairLift.Name ?? "<none>"; string waitingLift = simulatedLifts.SingleOrDefault(l => l.SkiersWaiting.Contains(reference))?.ChairLift.Name ?? "<none>"; string skiiingToLift = simulatedLifts.SingleOrDefault(l => l.SkiersSkiingToThisLift.Contains(reference))?.ChairLift.Name ?? "<none>"; if (ridingLift != "<none>" && waitingLift != "<none>" || ridingLift != "<none>" && skiiingToLift != "<none>" || waitingLift != "<none>" && skiiingToLift != "<none>") { Debug.Assert(false); } Console.WriteLine($"{reference.Id}\t{reference.Location.Latitude}\t{waitingLift}\t{ridingLift}\t{skiiingToLift}\t{watch.ElapsedMilliseconds}"); string line = "waiting"; foreach (var lift in simulatedLifts) { line += $"\t{lift.SkiersWaiting.Count}"; } Console.WriteLine(line); line = "riding"; foreach (var lift in simulatedLifts) { line += $"\t{lift.SkiersRiding.Count}"; } Console.WriteLine(line); }
public void Start() { Random random = new Random(); List <SimulatedChairlift> simulatedLifts = Lifts.Select(l => new SimulatedChairlift(l)).ToList(); // TODO: add new skiers gradually List <Skier> skiers = new List <Skier>(_skierCount); for (int i = 0; i < _skierCount; i++) { // TODO: skew towards easier runs int lift = random.Next(0, Lifts.Length); Skier skier = new Skier { Location = simulatedLifts[lift].ChairLift.Bottom }; simulatedLifts[lift].SkiersWaiting.Enqueue(skier); skiers.Add(skier); } Skier reference = simulatedLifts[0].SkiersWaiting.Peek(); long currentTime = 0; Stopwatch watch = new Stopwatch(); while (true) { watch.Restart(); foreach (SimulatedChairlift lift in simulatedLifts) { if (currentTime - lift.LastLoadTime >= lift.ChairLift.TimeBetweenLoads) { LoadUnloadSkiers(lift, currentTime); } // TODO: variability in time-to-bottom Func <Skier, bool> doneWithRunPredicate = s => currentTime - s.StartTimeForCurrentStage >= lift.ChairLift.AverageTimeDown; MoveSkiersToWaiting(currentTime, lift, doneWithRunPredicate); } currentTime++; watch.Stop(); if (watch.Elapsed < _oneSecond) { Thread.Sleep(_oneSecond - watch.Elapsed); } if (currentTime % _reportPeriod == 0) { // Create a real timeline for events by assuming the simulation starts at 8 AM and goes on in real time DateTimeOffset now = DateTimeOffset.Now; DateTimeOffset eventTime = new DateTimeOffset(now.Year, now.Month, now.Day, 8, 0, 0, now.Offset); eventTime = eventTime.Add(TimeSpan.FromSeconds(currentTime)); // Create a copy of the list and of the data since we'll send this in the background and want // a stable view of the state of the simulation SendLocationEvents(skiers.Select(s => new LocationEvent(s, eventTime)).ToList()); } if (currentTime % 4 == 0) { ReportOut(currentTime, simulatedLifts, reference, watch); } CheckInput(currentTime, simulatedLifts); } }