comment pass
This commit is contained in:
@@ -9,6 +9,9 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is the main way to interact with measurements.
|
||||
/// </summary>
|
||||
public static class Measure
|
||||
{
|
||||
/// <summary>
|
||||
@@ -19,20 +22,46 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
private static Dictionary<int, PuzzleMeasurement> _runningMeasurements;
|
||||
private static Session _currentSession;
|
||||
|
||||
/// <summary>
|
||||
/// The average time to solve a specific puzzle.
|
||||
/// </summary>
|
||||
public static float AverageTime(PuzzleModuleDescription puzzle) =>
|
||||
PuzzleStorage.Instance.Load(puzzle).AverageTimeToSolve;
|
||||
/// <summary>
|
||||
/// The average time to solve a group of puzzles.
|
||||
/// </summary>
|
||||
public static float AverageTime(IEnumerable<PuzzleModuleDescription> puzzles) => puzzles.Sum(AverageTime);
|
||||
/// <summary>
|
||||
/// The average time to solve a specific room.
|
||||
/// </summary>
|
||||
/// <remarks>This only counts puzzles already placed in a room.</remarks>
|
||||
public static float AverageTime(Room room) =>
|
||||
room.puzzles.Sum(puzzle => AverageTime((PuzzleModuleDescription)puzzle.description));
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the time a specific puzzle will take to be solved by the current player.
|
||||
/// </summary>
|
||||
public static float EstimateTime(PuzzleModuleDescription puzzle) =>
|
||||
PuzzleStorage.Instance.Load(puzzle).EstimateTimeToSolve(SessionPercentile());
|
||||
/// <summary>
|
||||
/// Estimate the time a group of puzzles will take to be solved by the current player.
|
||||
/// </summary>
|
||||
public static float EstimateTime(IEnumerable<PuzzleModuleDescription> puzzles) => puzzles.Sum(EstimateTime);
|
||||
/// <summary>
|
||||
/// Estimate the time a room will take to be solved by the current player.
|
||||
/// </summary>
|
||||
/// <remarks>This only counts puzzles already placed in a room.</remarks>
|
||||
public static float EstimateTime(Room room) =>
|
||||
room.puzzles.Sum(puzzle => EstimateTime((PuzzleModuleDescription)puzzle.description));
|
||||
|
||||
/// <summary>
|
||||
/// The estimated percentile the current player is placed in.
|
||||
/// </summary>
|
||||
public static float SessionPercentile() => _currentSession?.MeanPercentile ?? 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Start counting the time to solve a specific puzzle.
|
||||
/// </summary>
|
||||
public static void StartMeasuring(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
_runningMeasurements[puzzle.Id] = new PuzzleMeasurement
|
||||
@@ -44,6 +73,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
Logger.Log($"Started measuring {puzzle}", LogType.Measuring);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A puzzle has been solved and the measurement should be stopped. This will also store the finished measurement in the database.
|
||||
/// </summary>
|
||||
public static void Solve(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
if (_currentSession == null)
|
||||
@@ -62,6 +94,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
Logger.Log($"Solved {puzzle} with measurement {measurement}", LogType.Measuring);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new session and place the current player at the 50th percentile.
|
||||
/// </summary>
|
||||
public static void StartSession()
|
||||
{
|
||||
_currentSession = new Session();
|
||||
@@ -75,6 +110,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
Logger.Log($"Started {_currentSession}", LogType.Measuring);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End a session and store it in the database.
|
||||
/// </summary>
|
||||
public static void EndSession(float time)
|
||||
{
|
||||
if (Store)
|
||||
|
||||
@@ -3,10 +3,22 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The target and estimated time, along with the percentile since the last section, that will be stored in the database.
|
||||
/// </summary>
|
||||
public class PlanResult : EmbeddedObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The target time set by the game master when this section ended.
|
||||
/// </summary>
|
||||
public float TargetTime { get; set; }
|
||||
/// <summary>
|
||||
/// The percentile of the current player during this section.
|
||||
/// </summary>
|
||||
public float SectionPercentile { get; set; }
|
||||
/// <summary>
|
||||
/// The estimated time to complete the whole puzzle plan when this section ended.
|
||||
/// </summary>
|
||||
public float TimeEstimation { get; set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -8,15 +8,30 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The representation of a specific puzzle in the database. This includes all measurements for this puzzle.
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
|
||||
public class Puzzle : RealmObject
|
||||
{
|
||||
[PrimaryKey]
|
||||
public int ID { get; set; }
|
||||
/// <summary>
|
||||
/// All puzzle measurements recorded for this puzzle.
|
||||
/// </summary>
|
||||
public IList<PuzzleMeasurement> Measurements { get; }
|
||||
|
||||
/// <summary>
|
||||
/// How much time has been spent on this puzzle in total. This is used to calculate the average time to solve this puzzle.
|
||||
/// </summary>
|
||||
public float TotalTimeSpentOnPuzzle => Measurements.Sum(measurement => measurement.Time);
|
||||
/// <summary>
|
||||
/// The average time to solve this puzzle using all measurements recorded for it.
|
||||
/// </summary>
|
||||
public float AverageTimeToSolve => Measurements.Count > 0 ? TotalTimeSpentOnPuzzle / Measurements.Count : 0f;
|
||||
/// <summary>
|
||||
/// The normal distribution of all recorded measurements.
|
||||
/// </summary>
|
||||
public NormalDistribution Distribution => new(TimesAsSamples());
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -3,11 +3,23 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// A single measurement, consisting of when a puzzle was started and solved, stored in the database.
|
||||
/// </summary>
|
||||
public class PuzzleMeasurement : EmbeddedObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The relative time since the engine was initialised of when this puzzle was started.
|
||||
/// </summary>
|
||||
public float TimeStarted { get; set; }
|
||||
/// <summary>
|
||||
/// The relative time since the engine was initialised of when this puzzle was solved.
|
||||
/// </summary>
|
||||
public float TimeSolved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total time taken to solve this puzzle during this measurement.
|
||||
/// </summary>
|
||||
public float Time => TimeSolved - TimeStarted;
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -7,12 +7,22 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The storage engine that manages the data in a realm database.
|
||||
/// </summary>
|
||||
public class PuzzleStorage : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The schema version must be updated whenever the schema in the database changed.
|
||||
/// </summary>
|
||||
private const int SchemaVersion = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The active instance of the storage engine.
|
||||
/// </summary>
|
||||
public static PuzzleStorage Instance { get; private set; }
|
||||
|
||||
[Tooltip("The path of the database relative to where the engine stores persistent data.")]
|
||||
[SerializeField]
|
||||
private string databasePath = "measurements.realm";
|
||||
|
||||
@@ -20,6 +30,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// configure special actions during specific migrations of the database
|
||||
var config = new RealmConfiguration
|
||||
{
|
||||
SchemaVersion = SchemaVersion,
|
||||
@@ -59,6 +70,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
#region Session
|
||||
|
||||
/// <summary>
|
||||
/// End a session and store it to the database.
|
||||
/// </summary>
|
||||
public void EndSession(Session session, float time)
|
||||
{
|
||||
session.Time = time;
|
||||
@@ -70,6 +84,10 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
#region Puzzles
|
||||
|
||||
/// <summary>
|
||||
/// Create a new puzzle for a specific description and store it in the database.
|
||||
/// </summary>
|
||||
/// <remarks>This requires that the puzzle does not yet exist in the database.</remarks>
|
||||
private Puzzle New(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
Puzzle created = null;
|
||||
@@ -79,10 +97,20 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
return created;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a specific puzzle from the database or create it if it wasn't found.
|
||||
/// </summary>
|
||||
private Puzzle LoadOrNew(PuzzleModuleDescription puzzle) => _realm.Find<Puzzle>(puzzle.Id) ?? New(puzzle);
|
||||
|
||||
/// <summary>
|
||||
/// Load a specific puzzle from the database.
|
||||
/// </summary>
|
||||
/// <returns>The puzzle or null if it wasn't found in the database.</returns>
|
||||
public Puzzle Load(PuzzleModuleDescription puzzle) => _realm.Find<Puzzle>(puzzle.Id);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all records concerning a specific puzzle from the database irreversibly.
|
||||
/// </summary>
|
||||
public void Delete(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
var found = Load(puzzle);
|
||||
@@ -92,6 +120,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the measurement for a specific puzzle and store it in the database. Also stores the results of the current puzzle plan.
|
||||
/// </summary>
|
||||
public void EndMeasurement(Session session, PuzzleModuleDescription puzzle, PuzzleMeasurement measurement)
|
||||
{
|
||||
var found = LoadOrNew(puzzle);
|
||||
|
||||
@@ -8,16 +8,33 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The representation of a session in the database. This stores all plan results during this session and what puzzles were solved.
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
|
||||
public class Session : RealmObject
|
||||
{
|
||||
[PrimaryKey]
|
||||
public ObjectId ID { get; set; }
|
||||
public float Time { get; set; }
|
||||
/// <summary>
|
||||
/// The plan results for each section during this section.
|
||||
/// </summary>
|
||||
/// <remarks>The order of the plan results corresponds with the order of the solved puzzles.</remarks>
|
||||
public IList<PlanResult> PlanResults { get; }
|
||||
/// <summary>
|
||||
/// The puzzles solved during this session.
|
||||
/// </summary>
|
||||
/// <remarks>The order of the solved puzzles corresponds with the order of the plan results.</remarks>
|
||||
public IList<Puzzle> PuzzlesSolved { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The section percentiles the current player has been placed in.
|
||||
/// </summary>
|
||||
public IEnumerable<float> Percentiles => PlanResults.Select(result => result.SectionPercentile);
|
||||
/// <summary>
|
||||
/// The average of all section percentiles.
|
||||
/// </summary>
|
||||
public float MeanPercentile => PlanResults.Count == 0 ? .5f : Probability.Mean(Percentiles.ToArray());
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
Reference in New Issue
Block a user