phase 2
This commit is contained in:
File diff suppressed because it is too large
Load Diff
332
Assets/Engine/Assets/Prefabs/UI/Puzzle Plan Entry.prefab
Normal file
332
Assets/Engine/Assets/Prefabs/UI/Puzzle Plan Entry.prefab
Normal file
@@ -0,0 +1,332 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &1023969388561388979
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 2655555272253868329, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Name
|
||||
value: Puzzle Plan Entry
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: -1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 320
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 54
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868335, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Text
|
||||
value: Puzzle name
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects:
|
||||
- targetCorrespondingSourceObject: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
insertIndex: -1
|
||||
addedObject: {fileID: 8821617704014446116}
|
||||
m_AddedComponents:
|
||||
- targetCorrespondingSourceObject: {fileID: 2655555272253868329, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
insertIndex: -1
|
||||
addedObject: {fileID: 286020777690709323}
|
||||
m_SourcePrefab: {fileID: 100100000, guid: fa44f6047bc35a141a84d1b4e0919ff9, type: 3}
|
||||
--- !u!1 &3093889143253032090 stripped
|
||||
GameObject:
|
||||
m_CorrespondingSourceObject: {fileID: 2655555272253868329, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1023969388561388979}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &286020777690709323
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3093889143253032090}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8ef80fc9016c4a46a190769f3b771bfa, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
puzzleName: {fileID: 3093889143253032092}
|
||||
estimatedTime: {fileID: 8821617704014446117}
|
||||
--- !u!114 &3093889143253032092 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 2655555272253868335, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1023969388561388979}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3093889143253032090}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!224 &3093889143253032093 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 1023969388561388979}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1001 &6824857666461398794
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 3093889143253032093}
|
||||
m_Modifications:
|
||||
- target: {fileID: 2655555272253868329, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Name
|
||||
value: Estimated Time
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: -1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 320
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 24
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -30
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868335, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_Text
|
||||
value: 'Time Estimate: '
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868335, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_FontData.m_MinSize
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2655555272253868335, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
propertyPath: m_FontData.m_FontSize
|
||||
value: 16
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: fa44f6047bc35a141a84d1b4e0919ff9, type: 3}
|
||||
--- !u!224 &8821617704014446116 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 2655555272253868334, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 6824857666461398794}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &8821617704014446117 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 2655555272253868335, guid: fa44f6047bc35a141a84d1b4e0919ff9,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 6824857666461398794}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cad05994b2fb37746988912bce5a31f5
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -79,4 +79,4 @@ MonoBehaviour:
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 'Time:'
|
||||
m_Text: Text
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
[InfoBox("If a space was generated without any puzzles in it, the engine will try generating another new space. To prevent infinite loops, the amount of retries is bound.")]
|
||||
public int maxSpaceGenerationTries = 1000;
|
||||
[Tooltip("The engine will try to generate a room that takes approximately this many seconds to complete.")]
|
||||
public float initialTargetTime = 5 * 60;
|
||||
public float initialTargetTime = 10 * 60;
|
||||
public Vector3 roomOffset = new(0, 1000, 0);
|
||||
[Required] public EngineTheme theme;
|
||||
|
||||
@@ -83,7 +83,11 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
var tries = 0;
|
||||
Space space;
|
||||
Passage exit = null;
|
||||
var puzzle = PlanPuzzles();
|
||||
|
||||
// choose the next puzzle
|
||||
// PlanPuzzles();
|
||||
var puzzle = ChoosePuzzle();
|
||||
GameControl.Instance.CurrentPuzzle = puzzle;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -119,21 +123,41 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
room.AddSpace(space, exit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the list of puzzles planned for this run and returns the puzzle to put in the next room.
|
||||
/// </summary>
|
||||
private PuzzleModuleDescription PlanPuzzles()
|
||||
private PuzzleModuleDescription ChoosePuzzle()
|
||||
{
|
||||
|
||||
var nextPuzzle = _plannedPuzzles.PopRandomElement();
|
||||
|
||||
EstimatedTimeRemaining = Measure.AverageTime(_plannedPuzzles);
|
||||
|
||||
return nextPuzzle;
|
||||
// choose a puzzle from the plan and remove it from both the plan and later available puzzles (so it is only chosen once)
|
||||
var puzzle = _plannedPuzzles.PopRandomElement();
|
||||
_availablePuzzles.Remove(puzzle);
|
||||
return puzzle;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Updates the list of puzzles planned for this run.
|
||||
/// </summary>
|
||||
public void PlanPuzzles()
|
||||
{
|
||||
var n = _availablePuzzles.Count;
|
||||
var estimates = new int[n];
|
||||
var indices = new Range(0, n).ToArray();
|
||||
var target = Mathf.RoundToInt(GameControl.Instance.TargetTime - GameControl.Instance.EstimatedTimeRoom);
|
||||
_plannedPuzzles = new List<PuzzleModuleDescription>();
|
||||
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
estimates[i] = Mathf.RoundToInt(Measure.EstimateTime(_availablePuzzles[i]));
|
||||
}
|
||||
var chosen = Backtrack.Closest(indices, estimates, target);
|
||||
foreach (var i in chosen)
|
||||
{
|
||||
_plannedPuzzles.Add(_availablePuzzles[i]);
|
||||
}
|
||||
|
||||
EstimatedTimeRemaining = Measure.EstimateTime(_plannedPuzzles);
|
||||
GameControl.Instance.PlannedPuzzles = _plannedPuzzles;
|
||||
}
|
||||
|
||||
public void HidePreviousRoom(bool destroy = true)
|
||||
{
|
||||
if (NumberOfRooms > 2)
|
||||
|
||||
@@ -18,13 +18,20 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
private static Dictionary<int, PuzzleMeasurement> _runningMeasurements;
|
||||
private static Session _currentSession;
|
||||
|
||||
public static float AverageTime(IEnumerable<PuzzleModuleDescription> puzzles) =>
|
||||
puzzles.Sum(puzzle => PuzzleStorage.Instance.Load(puzzle).AverageTimeToSolve);
|
||||
public static float AverageTime(PuzzleModuleDescription puzzle) =>
|
||||
PuzzleStorage.Instance.Load(puzzle).AverageTimeToSolve;
|
||||
public static float AverageTime(IEnumerable<PuzzleModuleDescription> puzzles) => puzzles.Sum(AverageTime);
|
||||
public static float AverageTime(Room room) =>
|
||||
room.puzzles.Sum(puzzle => AverageTime((PuzzleModuleDescription)puzzle.description));
|
||||
|
||||
public static float EstimateTime(PuzzleModuleDescription puzzle) =>
|
||||
PuzzleStorage.Instance.Load(puzzle).EstimateTimeToSolve(SessionPercentile());
|
||||
public static float EstimateTime(IEnumerable<PuzzleModuleDescription> puzzles) => puzzles.Sum(EstimateTime);
|
||||
public static float EstimateTime(Room room) =>
|
||||
room.puzzles.Sum(puzzle => EstimateTime((PuzzleModuleDescription)puzzle.description));
|
||||
|
||||
public static float SessionPercentile() => _currentSession?.MeanPercentile ?? 0.5f;
|
||||
|
||||
public static void StartMeasuring(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
_runningMeasurements[puzzle.Id] = new PuzzleMeasurement
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
public float TotalTimeSpentOnPuzzle => Measurements.Sum(measurement => measurement.Time);
|
||||
public float AverageTimeToSolve => Measurements.Count > 0 ? TotalTimeSpentOnPuzzle / Measurements.Count : 0f;
|
||||
public NormalDistribution Distribution => new(TimesAsSamples());
|
||||
|
||||
[UsedImplicitly]
|
||||
public Puzzle() {}
|
||||
@@ -25,6 +26,23 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
ID = puzzle.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Estimate how long a player in the given percentile will take to solve this puzzle.
|
||||
/// </summary>
|
||||
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)})";
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
public class PuzzleStorage : MonoBehaviour
|
||||
{
|
||||
private const int SchemaVersion = 1;
|
||||
|
||||
public static PuzzleStorage Instance { get; private set; }
|
||||
|
||||
[SerializeField]
|
||||
@@ -17,7 +19,20 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_realm = Realm.GetInstance(databasePath);
|
||||
var config = new RealmConfiguration
|
||||
{
|
||||
SchemaVersion = SchemaVersion,
|
||||
MigrationCallback = (migration, oldSchemaVersion) =>
|
||||
{
|
||||
if (oldSchemaVersion < 1)
|
||||
{
|
||||
// migration from version 0 to 1
|
||||
}
|
||||
|
||||
Logger.Log($"Migrated database to version {SchemaVersion}", LogType.Measuring);
|
||||
}
|
||||
};
|
||||
_realm = Realm.GetInstance(config.ConfigWithPath(databasePath));
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
@@ -41,10 +56,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
session.Time = time;
|
||||
|
||||
_realm.Write(() =>
|
||||
{
|
||||
_realm.Add(session);
|
||||
});
|
||||
_realm.Write(() => _realm.Add(session));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -84,6 +96,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
// add solved puzzle to session
|
||||
session.PuzzlesSolved.Add(found);
|
||||
|
||||
// add time percentile to session
|
||||
session.Percentiles.Add(found.Distribution.Cumulative(measurement.Time));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
using JetBrains.Annotations;
|
||||
using MongoDB.Bson;
|
||||
@@ -13,8 +14,11 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
[PrimaryKey]
|
||||
public ObjectId ID { get; set; }
|
||||
public float Time { get; set; }
|
||||
public IList<float> Percentiles { get; }
|
||||
public IList<Puzzle> PuzzlesSolved { get; }
|
||||
|
||||
public float MeanPercentile => Percentiles.Count == 0 ? .5f : Probability.Mean(Percentiles.ToArray());
|
||||
|
||||
[UsedImplicitly]
|
||||
public Session()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using EscapeRoomEngine.Engine.Runtime.Measurements;
|
||||
using System.Collections.Generic;
|
||||
using EscapeRoomEngine.Engine.Runtime.Measurements;
|
||||
using EscapeRoomEngine.Engine.Runtime.Modules;
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
@@ -15,20 +17,31 @@ namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
{
|
||||
public static GameControl Instance { get; private set; }
|
||||
|
||||
[SerializeField]
|
||||
private float uiUpdateInterval = 1, planUpdateInterval = 1;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private Button startButton, stopButton, pauseButton, addTimeButton, removeTimeButton;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private Text timeText, roomTimeText, estimateTimeText, targetTimeText;
|
||||
private Text timeText, roomTimeText, estimateTimeText, targetTimeText, percentileText;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private float uiUpdateInterval = 1;
|
||||
private PuzzlePlan puzzlePlan;
|
||||
|
||||
[HideInInspector] public GameState gameState = GameState.Stopped;
|
||||
public PuzzleModuleDescription CurrentPuzzle
|
||||
{
|
||||
set => puzzlePlan.CurrentPuzzle = value;
|
||||
}
|
||||
public List<PuzzleModuleDescription> PlannedPuzzles
|
||||
{
|
||||
set => puzzlePlan.Puzzles = value;
|
||||
}
|
||||
|
||||
public float TimeElapsed { get; private set; }
|
||||
public float TimeInRoom { get; set; }
|
||||
public float TargetTime { get; private set; }
|
||||
public float EstimatedTimeRoom { get; private set; }
|
||||
|
||||
private float _previousUIUpdate;
|
||||
private float _previousUIUpdate, _previousPlanUpdate;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -57,6 +70,15 @@ namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
_previousUIUpdate = Time.time;
|
||||
|
||||
SetTimeText();
|
||||
UpdateStats();
|
||||
}
|
||||
|
||||
// update plan
|
||||
if (Time.time > _previousPlanUpdate + planUpdateInterval)
|
||||
{
|
||||
_previousPlanUpdate = Time.time;
|
||||
|
||||
Engine.Instance.PlanPuzzles();
|
||||
}
|
||||
|
||||
// enable or disable buttons
|
||||
@@ -129,15 +151,21 @@ namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
|
||||
Engine.Instance.CurrentRoom.Match(some: room =>
|
||||
{
|
||||
estimateTimeText.text = TimeToText(
|
||||
TimeElapsed - TimeInRoom
|
||||
+ Mathf.Max(TimeInRoom, Measure.AverageTime(room))
|
||||
+ Engine.Instance.EstimatedTimeRemaining);
|
||||
EstimatedTimeRoom =
|
||||
TimeElapsed - TimeInRoom + Mathf.Max(TimeInRoom, Measure.EstimateTime(room));
|
||||
estimateTimeText.text = TimeToText(EstimatedTimeRoom + Engine.Instance.EstimatedTimeRemaining);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateStats()
|
||||
{
|
||||
percentileText.text = PercentageToText(Measure.SessionPercentile());
|
||||
}
|
||||
|
||||
private static string TimeToText(float time) => $"{time.ToTimeSpan():mm':'ss}";
|
||||
|
||||
private static string PercentageToText(float percentage) => $"{percentage:P1}";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Measurements
|
||||
|
||||
56
Assets/Engine/Runtime/UI/PuzzlePlan.cs
Normal file
56
Assets/Engine/Runtime/UI/PuzzlePlan.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using EscapeRoomEngine.Engine.Runtime.Modules;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
{
|
||||
public class PuzzlePlan : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private Vector2 entryOffset;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private RectTransform plan;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private PuzzlePlanEntry currentPuzzle, entryPrefab;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private GameObject currentPuzzleTitle, planTitle;
|
||||
|
||||
public PuzzleModuleDescription CurrentPuzzle
|
||||
{
|
||||
set
|
||||
{
|
||||
currentPuzzleTitle.SetActive(true);
|
||||
currentPuzzle.gameObject.SetActive(true);
|
||||
|
||||
// set the current puzzle
|
||||
currentPuzzle.Puzzle = value;
|
||||
}
|
||||
}
|
||||
public List<PuzzleModuleDescription> Puzzles
|
||||
{
|
||||
set
|
||||
{
|
||||
planTitle.SetActive(true);
|
||||
plan.gameObject.SetActive(true);
|
||||
|
||||
// remove the old children
|
||||
foreach (RectTransform child in plan)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
// add the new children
|
||||
var offset = Vector2.zero;
|
||||
value.ForEach(puzzle =>
|
||||
{
|
||||
var entry = Instantiate(entryPrefab, plan, false);
|
||||
entry.Position = offset;
|
||||
entry.Puzzle = puzzle;
|
||||
offset += entryOffset;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Engine/Runtime/UI/PuzzlePlan.cs.meta
Normal file
3
Assets/Engine/Runtime/UI/PuzzlePlan.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad95894771b8478591e5f5abbe1d0244
|
||||
timeCreated: 1671133031
|
||||
32
Assets/Engine/Runtime/UI/PuzzlePlanEntry.cs
Normal file
32
Assets/Engine/Runtime/UI/PuzzlePlanEntry.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using EscapeRoomEngine.Engine.Runtime.Measurements;
|
||||
using EscapeRoomEngine.Engine.Runtime.Modules;
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
{
|
||||
public class PuzzlePlanEntry : MonoBehaviour
|
||||
{
|
||||
[BoxGroup("Internal")] [Required] [SerializeField]
|
||||
private Text puzzleName, estimatedTime;
|
||||
|
||||
public Vector2 Position
|
||||
{
|
||||
set
|
||||
{
|
||||
puzzleName.rectTransform.anchoredPosition = value;
|
||||
}
|
||||
}
|
||||
public PuzzleModuleDescription Puzzle
|
||||
{
|
||||
set
|
||||
{
|
||||
puzzleName.text = value.puzzleName;
|
||||
estimatedTime.text = $"Time Estimate: {Measure.EstimateTime(value).ToTimeSpan():mm':'ss}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Engine/Runtime/UI/PuzzlePlanEntry.cs.meta
Normal file
3
Assets/Engine/Runtime/UI/PuzzlePlanEntry.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ef80fc9016c4a46a190769f3b771bfa
|
||||
timeCreated: 1671136597
|
||||
127
Assets/Engine/Runtime/Utilities/Backtrack.cs
Normal file
127
Assets/Engine/Runtime/Utilities/Backtrack.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
|
||||
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||
// ReSharper disable ParameterTypeCanBeEnumerable.Local
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
public struct Backtrack
|
||||
{
|
||||
private int[] indices;
|
||||
private int[] values;
|
||||
private int target;
|
||||
|
||||
public Backtrack(int[] indices, int[] values, int target)
|
||||
{
|
||||
this.indices = indices;
|
||||
this.values = values;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find any number of elements from the given set of indices and values with the maximum sum that doesn't exceed the target sum.
|
||||
/// </summary>
|
||||
/// <remarks>This function uses a backtracking approach to find the sum.</remarks>
|
||||
public int[] BruteForceLower(int[] chosen = null, int pos = 0)
|
||||
{
|
||||
chosen ??= Array.Empty<int>();
|
||||
|
||||
if (Sum(chosen) > target)
|
||||
{
|
||||
// if the sum of the chosen values exceeds the target, return nothing
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
if (pos >= indices.Length)
|
||||
{
|
||||
// if we cannot add any more elements, return all chosen
|
||||
return chosen;
|
||||
}
|
||||
|
||||
// find the best indices when skipping the one at the current position
|
||||
var leave = BruteForceLower(chosen, pos + 1);
|
||||
// find the best indices when including the one at the current position
|
||||
var next = new int[chosen.Length + 1];
|
||||
for (var i = 0; i < chosen.Length; i++)
|
||||
{
|
||||
next[i] = chosen[i];
|
||||
}
|
||||
next[^1] = indices[pos];
|
||||
var pick = BruteForceLower(next, pos + 1);
|
||||
|
||||
// return the best result
|
||||
return Sum(leave) > Sum(pick) ? leave : pick;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find any number of elements from the given set of indices and values with the minimum sum that is higher than the target sum.
|
||||
/// </summary>
|
||||
/// <remarks>This function uses a backtracking approach to find the sum.</remarks>
|
||||
public int[] BruteForceHigher(int[] chosen = null, int pos = int.MaxValue)
|
||||
{
|
||||
chosen ??= indices;
|
||||
if (pos == int.MaxValue)
|
||||
{
|
||||
pos = indices.Length - 1;
|
||||
}
|
||||
|
||||
if (Sum(chosen) < target)
|
||||
{
|
||||
// if the sum of the chosen values is lower than the target, return all indices (the maximum choice)
|
||||
return indices;
|
||||
}
|
||||
if (pos < 0)
|
||||
{
|
||||
// if we cannot remove any more elements, return all chosen
|
||||
return chosen;
|
||||
}
|
||||
|
||||
// find the best indices when not removing the one at the current position
|
||||
var leave = BruteForceHigher(chosen, pos - 1);
|
||||
// find the best indices when removing the one at the current position
|
||||
var next = new int[chosen.Length - 1];
|
||||
for (var i = 0; i < chosen.Length; i++)
|
||||
{
|
||||
if (i < pos)
|
||||
{
|
||||
next[i] = chosen[i];
|
||||
} else if (i > pos)
|
||||
{
|
||||
next[i - 1] = chosen[i];
|
||||
}
|
||||
}
|
||||
var pick = BruteForceHigher(next, pos - 1);
|
||||
|
||||
// return the best result
|
||||
return Sum(leave) < Sum(pick) ? leave : pick;
|
||||
}
|
||||
|
||||
public int[] BruteForce()
|
||||
{
|
||||
var lower = BruteForceLower();
|
||||
var higher = BruteForceHigher();
|
||||
var errLower = Math.Abs(target - Sum(lower));
|
||||
var errHigher = Math.Abs(target - Sum(higher));
|
||||
|
||||
return errLower < errHigher ? lower : higher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a subset of indices where the sum of their corresponding values is closest to a target sum.
|
||||
/// </summary>
|
||||
public static int[] Closest(int[] indices, int[] values, int target) =>
|
||||
new Backtrack(indices, values, target).BruteForce();
|
||||
|
||||
private int Sum(int[] chosen)
|
||||
{
|
||||
var sum = 0;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var i in chosen)
|
||||
{
|
||||
sum += values[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Engine/Runtime/Utilities/Backtrack.cs.meta
Normal file
3
Assets/Engine/Runtime/Utilities/Backtrack.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 313a79a04104480f931206ff7f57d0c5
|
||||
timeCreated: 1671126182
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MathNet.Numerics.Distributions;
|
||||
using UnityEngine;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
@@ -8,19 +9,21 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
[Serializable]
|
||||
public struct NormalDistribution
|
||||
{
|
||||
public double mean, σ;
|
||||
public float μ, σ;
|
||||
|
||||
public static NormalDistribution Standard => new NormalDistribution { mean = 0, σ = 1 };
|
||||
public static NormalDistribution Standard => new NormalDistribution { μ = 0, σ = 1 };
|
||||
|
||||
public NormalDistribution(double[] samples) : this()
|
||||
public NormalDistribution(float[] samples) : this()
|
||||
{
|
||||
mean = Probability.Mean(samples);
|
||||
σ = Probability.StandardDeviation(samples, mean);
|
||||
μ = Probability.Mean(samples);
|
||||
σ = Probability.StandardDeviation(samples, μ);
|
||||
}
|
||||
|
||||
public double Sample() => σ * Probability.Normal() + mean;
|
||||
public float Sample() => σ * Probability.Normal() + μ;
|
||||
|
||||
public double Cumulative(double x) => new Normal(mean, σ).CumulativeDistribution(x);
|
||||
public float Cumulative(float x) => (float)new Normal(μ, σ).CumulativeDistribution(x);
|
||||
|
||||
public float InverseCumulative(float x) => (float)new Normal(μ, σ).InverseCumulativeDistribution(x);
|
||||
}
|
||||
|
||||
public static class Probability
|
||||
@@ -32,22 +35,22 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
/// For simplicity, the result is clamped between -3 and 3. This is accurate for 99.7% of all samples, by the three-σ rule.
|
||||
/// </summary>
|
||||
/// <remarks>The calculation of the random variable is done by a Box-Muller transform.</remarks>
|
||||
public static double Normal()
|
||||
public static float Normal()
|
||||
{
|
||||
double u1, u2, square;
|
||||
float u1, u2, square;
|
||||
|
||||
// get two random points inside the unit circle
|
||||
do
|
||||
{
|
||||
u1 = 2 * _random.NextDouble() - 1;
|
||||
u2 = 2 * _random.NextDouble() - 1;
|
||||
u1 = 2 * (float)_random.NextDouble() - 1;
|
||||
u2 = 2 * (float)_random.NextDouble() - 1;
|
||||
square = u1 * u1 + u2 * u2;
|
||||
} while (square >= 1f);
|
||||
|
||||
return u1 * Math.Sqrt(-2 * Math.Log(square) / square);
|
||||
return u1 * Mathf.Sqrt(-2 * Mathf.Log(square) / square);
|
||||
}
|
||||
|
||||
public static double Mean(double[] samples)
|
||||
public static float Mean(float[] samples)
|
||||
{
|
||||
if (samples.Length == 0)
|
||||
{
|
||||
@@ -57,10 +60,10 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
return samples.Sum() / samples.Length;
|
||||
}
|
||||
|
||||
public static double StandardDeviation(double[] samples) => StandardDeviation(samples, Mean(samples));
|
||||
public static double StandardDeviation(double[] samples, double mean)
|
||||
public static float StandardDeviation(float[] samples) => StandardDeviation(samples, Mean(samples));
|
||||
public static float StandardDeviation(float[] samples, float mean)
|
||||
{
|
||||
var deviations = new double[samples.Length];
|
||||
var deviations = new float[samples.Length];
|
||||
|
||||
for (var i = 0; i < samples.Length; i++)
|
||||
{
|
||||
@@ -68,7 +71,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
deviations[i] = d * d;
|
||||
}
|
||||
|
||||
return Math.Sqrt(Mean(deviations));
|
||||
return Mathf.Sqrt(Mean(deviations));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,19 @@
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public int[] ToArray(bool includeMax = false)
|
||||
{
|
||||
var count = includeMax ? Length + 1 : Length;
|
||||
var array = new int[count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
array[i] = min + i;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public override string ToString() => $"{{{min}, ..., {max}}}";
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,14 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
|
||||
public static int RandomInclusive(int from, int to) => Random.Range(from, to + 1);
|
||||
|
||||
public static T RandomElement<T>(this List<T> list) => list[Random.Range(0, list.Count)];
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class ListExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// remove a random element from a list and return it.
|
||||
/// </summary>
|
||||
public static T PopRandomElement<T>(this List<T> list)
|
||||
{
|
||||
var index = Random.Range(0, list.Count);
|
||||
@@ -35,7 +41,20 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
return element;
|
||||
}
|
||||
|
||||
#endregion
|
||||
public static T RandomElement<T>(this List<T> list) => list[Random.Range(0, list.Count)];
|
||||
|
||||
/// <summary>
|
||||
/// Perform a Fisher-Yates shuffle on a given list, leaving it in a random order.
|
||||
/// </summary>
|
||||
public static void Shuffle<T>(this List<T> list)
|
||||
{
|
||||
for (var n = list.Count - 1; n > 0; n--)
|
||||
{
|
||||
var i = Utilities.RandomInclusive(0, n);
|
||||
var j = Utilities.RandomInclusive(0, n);
|
||||
(list[i], list[j]) = (list[j], list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Vector2IntExtensions
|
||||
|
||||
@@ -25,7 +25,7 @@ PluginImporter:
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 1
|
||||
enabled: 0
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
||||
@@ -547,6 +547,7 @@ GameObject:
|
||||
- component: {fileID: 1568048334}
|
||||
- component: {fileID: 1568048339}
|
||||
- component: {fileID: 1568048336}
|
||||
- component: {fileID: 1568048340}
|
||||
m_Layer: 0
|
||||
m_Name: Engine
|
||||
m_TagString: Untagged
|
||||
@@ -567,7 +568,7 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
maxSpaceGenerationTries: 1000
|
||||
initialTargetTime: 300
|
||||
initialTargetTime: 600
|
||||
roomOffset: {x: 0, y: 1000, z: 0}
|
||||
theme: {fileID: 11400000, guid: 568d9a7d70f3edb4cb6db66a0010f105, type: 2}
|
||||
--- !u!4 &1568048335
|
||||
@@ -598,7 +599,7 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
loggingEnabled: 1
|
||||
typeFilter: 00000000
|
||||
typeFilter: 0000000009000000
|
||||
--- !u!114 &1568048339
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -612,3 +613,17 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
databasePath: measurements.realm
|
||||
--- !u!114 &1568048340
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1568048333}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 599a288d4210437698dc391e5cc84a8a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
values: a3000000110100007c0000002801000029000000
|
||||
target: 600
|
||||
|
||||
47
Assets/Test Assets/BacktrackingTest.cs
Normal file
47
Assets/Test Assets/BacktrackingTest.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
using JetBrains.Annotations;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Test_Assets
|
||||
{
|
||||
public class BacktrackingTest : MonoBehaviour
|
||||
{
|
||||
public int[] values;
|
||||
public int target;
|
||||
|
||||
[Button]
|
||||
[UsedImplicitly]
|
||||
public void Closest()
|
||||
{
|
||||
PrintResult(Backtrack.Closest(new Range(0, values.Length).ToArray(), values, target));
|
||||
}
|
||||
|
||||
[Button]
|
||||
[UsedImplicitly]
|
||||
public void ClosestLower()
|
||||
{
|
||||
var backtrack = new Backtrack(new Range(0, values.Length).ToArray(), values, target);
|
||||
PrintResult(backtrack.BruteForceLower());
|
||||
}
|
||||
|
||||
[Button]
|
||||
[UsedImplicitly]
|
||||
public void ClosestHigher()
|
||||
{
|
||||
var backtrack = new Backtrack(new Range(0, values.Length).ToArray(), values, target);
|
||||
PrintResult(backtrack.BruteForceHigher());
|
||||
}
|
||||
|
||||
private void PrintResult(int[] indices)
|
||||
{
|
||||
var sum = 0;
|
||||
foreach (var i in indices)
|
||||
{
|
||||
Debug.Log(values[i]);
|
||||
sum += values[i];
|
||||
}
|
||||
Debug.Log($"sum: {sum}");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Test Assets/BacktrackingTest.cs.meta
Normal file
3
Assets/Test Assets/BacktrackingTest.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 599a288d4210437698dc391e5cc84a8a
|
||||
timeCreated: 1671127266
|
||||
@@ -1,6 +1,5 @@
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
using JetBrains.Annotations;
|
||||
using MathNet.Numerics.Distributions;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -11,7 +10,8 @@ namespace Test_Assets
|
||||
public NormalDistribution distribution = NormalDistribution.Standard;
|
||||
public int steps = 24;
|
||||
public int n = 1000000;
|
||||
public double sample;
|
||||
public float sample;
|
||||
public float percentile = 0.5f;
|
||||
|
||||
[Button]
|
||||
[UsedImplicitly]
|
||||
@@ -62,9 +62,16 @@ namespace Test_Assets
|
||||
Debug.Log(distribution.Cumulative(sample));
|
||||
}
|
||||
|
||||
private double[] Samples()
|
||||
[Button]
|
||||
[UsedImplicitly]
|
||||
public void InversePercentile()
|
||||
{
|
||||
var samples = new double[n];
|
||||
Debug.Log(distribution.InverseCumulative(percentile));
|
||||
}
|
||||
|
||||
private float[] Samples()
|
||||
{
|
||||
var samples = new float[n];
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
samples[i] = distribution.Sample();
|
||||
|
||||
Reference in New Issue
Block a user