using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using EscapeRoomEngine.Engine.Runtime.Modules; using EscapeRoomEngine.Engine.Runtime.Utilities; using JetBrains.Annotations; using Realms; namespace EscapeRoomEngine.Engine.Runtime.Measurements { /// /// The representation of a specific puzzle in the database. This includes all measurements for this puzzle. /// [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] public class Puzzle : RealmObject { [PrimaryKey] public int ID { get; set; } /// /// All puzzle measurements recorded for this puzzle. /// public IList Measurements { get; } /// /// How much time has been spent on this puzzle in total. This is used to calculate the average time to solve this puzzle. /// public float TotalTimeSpentOnPuzzle => Measurements.Sum(measurement => measurement.Time); /// /// The average time to solve this puzzle using all measurements recorded for it. /// public float AverageTimeToSolve => Measurements.Count > 0 ? TotalTimeSpentOnPuzzle / Measurements.Count : 0f; /// /// The normal distribution of all recorded measurements. /// public NormalDistribution Distribution => new(TimesAsSamples()); [UsedImplicitly] public Puzzle() {} public Puzzle(PuzzleModuleDescription puzzle) { ID = puzzle.Id; } /// /// Estimate how long a player in the given percentile will take to solve this puzzle. /// public float EstimateTimeToSolve(float percentile) => Distribution.InverseCumulative(percentile); private float[] TimesAsSamples() { var samples = new float[Measurements.Count]; for (var i = 0; i < Measurements.Count; i++) { samples[i] = Measurements[i].Time; } return samples; } public override string ToString() { return $"{Engine.Theme.GetPuzzle(ID)}: avg. {AverageTimeToSolve.ToTimeSpan():m':'ss} ({string.Join(", ", Measurements)})"; } } }