using System.Collections.Generic; using System.Linq; using EscapeRoomEngine.Engine.Runtime.Modules; using EscapeRoomEngine.Engine.Runtime.UI; using EscapeRoomEngine.Engine.Runtime.Utilities; using UnityEngine; using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger; using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType; namespace EscapeRoomEngine.Engine.Runtime.Measurements { /// /// This class is the main way to interact with measurements. /// public static class Measure { /// /// Whether to store the taken measurements in the database. Disable for test runs. /// public static bool Store { get; set; } private static Dictionary _runningMeasurements; private static Session _currentSession; /// /// The average time to solve a specific puzzle. /// public static float AverageTime(PuzzleModuleDescription puzzle) => PuzzleStorage.Instance.Load(puzzle).AverageTimeToSolve; /// /// The average time to solve a group of puzzles. /// public static float AverageTime(IEnumerable puzzles) => puzzles.Sum(AverageTime); /// /// The average time to solve a specific room. /// /// This only counts puzzles already placed in a room. public static float AverageTime(Room room) => room.puzzles.Sum(puzzle => AverageTime((PuzzleModuleDescription)puzzle.description)); /// /// Estimate the time a specific puzzle will take to be solved by the current player. /// public static float EstimateTime(PuzzleModuleDescription puzzle) => PuzzleStorage.Instance.Load(puzzle).EstimateTimeToSolve(SessionPercentile()); /// /// Estimate the time a group of puzzles will take to be solved by the current player. /// public static float EstimateTime(IEnumerable puzzles) => puzzles.Sum(EstimateTime); /// /// Estimate the time a room will take to be solved by the current player. /// /// This only counts puzzles already placed in a room. public static float EstimateTime(Room room) => room.puzzles.Sum(puzzle => EstimateTime((PuzzleModuleDescription)puzzle.description)); /// /// The estimated percentile the current player is placed in. /// public static float SessionPercentile() => _currentSession?.MeanPercentile ?? 0.5f; /// /// Start counting the time to solve a specific puzzle. /// public static void StartMeasuring(PuzzleModuleDescription puzzle) { _runningMeasurements[puzzle.Id] = new PuzzleMeasurement { TimeStarted = Time.time, TimeSolved = Time.time }; Logger.Log($"Started measuring {puzzle}", LogType.Measuring); } /// /// A puzzle has been solved and the measurement should be stopped. This will also store the finished measurement in the database. /// public static void Solve(PuzzleModuleDescription puzzle) { if (_currentSession == null) { throw new EngineException("Measuring session must be started before taking measurements."); } var measurement = _runningMeasurements[puzzle.Id]; if (Store) { PuzzleStorage.Instance.EndMeasurement(_currentSession, puzzle, measurement); } _runningMeasurements.Remove(puzzle.Id); Logger.Log($"Solved {puzzle} with measurement {measurement}", LogType.Measuring); } /// /// Start a new session and place the current player at the 50th percentile. /// public static void StartSession() { _currentSession = new Session(); // add a first plan result with the initial target and estimated times _currentSession.PlanResults.Add(new PlanResult( GameControl.Instance.TargetTime, .5f, GameControl.Instance.EstimatedTime)); Logger.Log($"Started {_currentSession}", LogType.Measuring); } /// /// End a session and store it in the database. /// public static void EndSession(float time) { if (Store) { PuzzleStorage.Instance.EndSession(_currentSession, time); } Logger.Log($"Ended {_currentSession}", LogType.Measuring); } public static void Clear() { _runningMeasurements = new Dictionary(); Store = true; } } }