Implement Phase 6R-A hyper puzzle catalog contract
This commit is contained in:
parent
9a75f0103e
commit
30b553b792
12 changed files with 601 additions and 23 deletions
|
|
@ -114,6 +114,14 @@ FHyperTwistPuzzleDefinitionRef UHyperTwistContractLibrary::MakeSampleClassicPuzz
|
|||
FHyperTwistPuzzleDefinitionRef UHyperTwistContractLibrary::MakeSampleHyperPuzzleDefinition()
|
||||
{
|
||||
FHyperTwistPuzzleDefinitionRef Definition;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
TEXT("hypercube/2x2x2x2"),
|
||||
Definition
|
||||
))
|
||||
{
|
||||
return Definition;
|
||||
}
|
||||
|
||||
Definition.PuzzleId = TEXT("hypercube/2x2x2x2");
|
||||
Definition.PuzzleFamily = EHyperTwistPuzzleFamily::Hypercube;
|
||||
Definition.Dimension = 4;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,26 @@
|
|||
|
||||
namespace HyperTwistTrainingCatalogLibraryInternal
|
||||
{
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry MakeRetainedHyperCatalogEntry(
|
||||
const FString& PuzzleId,
|
||||
const FString& DisplayName,
|
||||
const TArray<int32>& SizeVector,
|
||||
const FString& Variant,
|
||||
const TArray<FString>& Tags,
|
||||
const TArray<FString>& AliasPuzzleIds
|
||||
)
|
||||
{
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry Entry;
|
||||
Entry.PuzzleId = PuzzleId;
|
||||
Entry.DisplayName = DisplayName;
|
||||
Entry.Dimension = SizeVector.Num();
|
||||
Entry.SizeVector = SizeVector;
|
||||
Entry.Variant = Variant;
|
||||
Entry.Tags = Tags;
|
||||
Entry.AliasPuzzleIds = AliasPuzzleIds;
|
||||
return Entry;
|
||||
}
|
||||
|
||||
template <typename TStruct>
|
||||
bool LoadStructFromJsonFile(
|
||||
const FString& JsonPath,
|
||||
|
|
@ -680,6 +700,93 @@ namespace HyperTwistTrainingCatalogLibraryInternal
|
|||
}
|
||||
}
|
||||
|
||||
FHyperTwistRetainedHyperPuzzleCatalog UHyperTwistTrainingCatalogLibrary::MakeRetainedHyperPuzzleCatalog()
|
||||
{
|
||||
FHyperTwistRetainedHyperPuzzleCatalog Catalog;
|
||||
Catalog.Entries =
|
||||
{
|
||||
HyperTwistTrainingCatalogLibraryInternal::MakeRetainedHyperCatalogEntry(
|
||||
TEXT("hypercube/3x3x3x3"),
|
||||
TEXT("3x3x3x3"),
|
||||
{3, 3, 3, 3},
|
||||
FString(),
|
||||
{TEXT("hypercube"), TEXT("virtual"), TEXT("entry"), TEXT("retained/hyperspeedcube")},
|
||||
{TEXT("3x3x3x3")}
|
||||
),
|
||||
HyperTwistTrainingCatalogLibraryInternal::MakeRetainedHyperCatalogEntry(
|
||||
TEXT("hypercube/2x2x2x2"),
|
||||
TEXT("2x2x2x2"),
|
||||
{2, 2, 2, 2},
|
||||
FString(),
|
||||
{TEXT("hypercube"), TEXT("virtual"), TEXT("compact"), TEXT("retained/hyperspeedcube")},
|
||||
{TEXT("2x2x2x2")}
|
||||
),
|
||||
HyperTwistTrainingCatalogLibraryInternal::MakeRetainedHyperCatalogEntry(
|
||||
TEXT("hypercube/4x4x4x4"),
|
||||
TEXT("4x4x4x4"),
|
||||
{4, 4, 4, 4},
|
||||
FString(),
|
||||
{TEXT("hypercube"), TEXT("virtual"), TEXT("extended"), TEXT("retained/hyperspeedcube")},
|
||||
{TEXT("4x4x4x4")}
|
||||
),
|
||||
HyperTwistTrainingCatalogLibraryInternal::MakeRetainedHyperCatalogEntry(
|
||||
TEXT("hypercube/3x3x3x3x3"),
|
||||
TEXT("3x3x3x3x3"),
|
||||
{3, 3, 3, 3, 3},
|
||||
FString(),
|
||||
{TEXT("hypercube"), TEXT("virtual"), TEXT("higher-dimensional"), TEXT("retained/hyperspeedcube")},
|
||||
{TEXT("3x3x3x3x3")}
|
||||
),
|
||||
HyperTwistTrainingCatalogLibraryInternal::MakeRetainedHyperCatalogEntry(
|
||||
TEXT("hypercube/2x2x2x2/physical"),
|
||||
TEXT("Physical 2x2x2x2"),
|
||||
{2, 2, 2, 2},
|
||||
TEXT("physical"),
|
||||
{TEXT("hypercube"), TEXT("physical"), TEXT("retained/hyperspeedcube")},
|
||||
{TEXT("phys_2x2x2x2")}
|
||||
)
|
||||
};
|
||||
return Catalog;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingCatalogLibrary::TryGetRetainedHyperPuzzleCatalogEntry(
|
||||
const FString& PuzzleId,
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry& OutEntry
|
||||
)
|
||||
{
|
||||
if (PuzzleId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FHyperTwistRetainedHyperPuzzleCatalog Catalog = MakeRetainedHyperPuzzleCatalog();
|
||||
for (const FHyperTwistRetainedHyperPuzzleCatalogEntry& Entry : Catalog.Entries)
|
||||
{
|
||||
if (Entry.MatchesPuzzleId(PuzzleId))
|
||||
{
|
||||
OutEntry = Entry;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
const FString& PuzzleId,
|
||||
FHyperTwistPuzzleDefinitionRef& OutDefinition
|
||||
)
|
||||
{
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry Entry;
|
||||
if (!TryGetRetainedHyperPuzzleCatalogEntry(PuzzleId, Entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutDefinition = Entry.ToDefinitionRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
FHyperTwistContentPack UHyperTwistTrainingCatalogLibrary::MakeAlgTrainerStarterContentPack()
|
||||
{
|
||||
const FHyperTwistTrainingCase OLLT01 = HyperTwistTrainingCatalogLibraryInternal::MakeAlgTrainerCase(
|
||||
|
|
|
|||
|
|
@ -20583,7 +20583,15 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionOwnedExec
|
|||
|
||||
const auto IncrementPuzzleFamilyCounts = [&Surface](const FString& PuzzleId)
|
||||
{
|
||||
if (PuzzleId.StartsWith(TEXT("cube/")))
|
||||
FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
PuzzleId,
|
||||
RetainedHyperDefinition
|
||||
))
|
||||
{
|
||||
++Surface.HypercubePuzzleOptionCount;
|
||||
}
|
||||
else if (PuzzleId.StartsWith(TEXT("cube/")))
|
||||
{
|
||||
++Surface.CubePuzzleOptionCount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -340,6 +340,15 @@ namespace HyperTwistTrainingLibraryInternal
|
|||
|
||||
FHyperTwistPuzzleDefinitionRef MakeDefinitionForCase(const FHyperTwistTrainingCase& TrainingCase)
|
||||
{
|
||||
FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
TrainingCase.PuzzleId,
|
||||
RetainedHyperDefinition
|
||||
))
|
||||
{
|
||||
return RetainedHyperDefinition;
|
||||
}
|
||||
|
||||
FHyperTwistPuzzleDefinitionRef Definition;
|
||||
Definition.PuzzleId = TrainingCase.PuzzleId;
|
||||
Definition.DefinitionVersion = TEXT("2026.04");
|
||||
|
|
@ -454,6 +463,15 @@ namespace HyperTwistTrainingLibraryInternal
|
|||
|
||||
bool MatchesPuzzleFamily(const FString& PuzzleId, EHyperTwistPuzzleFamily PuzzleFamily)
|
||||
{
|
||||
FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
PuzzleId,
|
||||
RetainedHyperDefinition
|
||||
))
|
||||
{
|
||||
return RetainedHyperDefinition.PuzzleFamily == PuzzleFamily;
|
||||
}
|
||||
|
||||
switch (PuzzleFamily)
|
||||
{
|
||||
case EHyperTwistPuzzleFamily::ClassicCube:
|
||||
|
|
|
|||
|
|
@ -1868,6 +1868,15 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
|
||||
EHyperTwistPuzzleFamily ResolvePuzzleFamilyFromPuzzleId(const FString& PuzzleId)
|
||||
{
|
||||
FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
PuzzleId,
|
||||
RetainedHyperDefinition
|
||||
))
|
||||
{
|
||||
return RetainedHyperDefinition.PuzzleFamily;
|
||||
}
|
||||
|
||||
if (PuzzleId.StartsWith(TEXT("hypercube/")))
|
||||
{
|
||||
return EHyperTwistPuzzleFamily::Hypercube;
|
||||
|
|
@ -1881,6 +1890,15 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
|
||||
FString ResolveNotationProfileFromPuzzleId(const FString& PuzzleId)
|
||||
{
|
||||
FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
|
||||
PuzzleId,
|
||||
RetainedHyperDefinition
|
||||
))
|
||||
{
|
||||
return RetainedHyperDefinition.NotationProfile;
|
||||
}
|
||||
|
||||
if (PuzzleId.StartsWith(TEXT("hypercube/")))
|
||||
{
|
||||
return TEXT("hyper-4d");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "HyperTwistCore/HyperTwistCoreTypes.h"
|
||||
#include "HyperTwistTrainingCatalogImportTypes.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
|
|
@ -682,3 +683,108 @@ struct FHyperTwistTrainingCatalogImportLoadReport
|
|||
&& bLoadedReferenceTargets;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistRetainedHyperPuzzleCatalogEntry
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PuzzleId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DisplayName;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistPuzzleFamily PuzzleFamily = EHyperTwistPuzzleFamily::Hypercube;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 Dimension = 4;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DefinitionVersion = TEXT("2026.04");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString NotationProfile = TEXT("hyper-4d");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<int32> SizeVector;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Variant;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> Tags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> AliasPuzzleIds;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !PuzzleId.IsEmpty()
|
||||
&& !DisplayName.IsEmpty()
|
||||
&& Dimension > 0
|
||||
&& !DefinitionVersion.IsEmpty()
|
||||
&& !NotationProfile.IsEmpty()
|
||||
&& SizeVector.Num() == Dimension;
|
||||
}
|
||||
|
||||
bool MatchesPuzzleId(const FString& CandidatePuzzleId) const
|
||||
{
|
||||
if (CandidatePuzzleId.Equals(PuzzleId, ESearchCase::IgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return AliasPuzzleIds.ContainsByPredicate([&CandidatePuzzleId](const FString& AliasPuzzleId)
|
||||
{
|
||||
return CandidatePuzzleId.Equals(AliasPuzzleId, ESearchCase::IgnoreCase);
|
||||
});
|
||||
}
|
||||
|
||||
FHyperTwistPuzzleDefinitionRef ToDefinitionRef() const
|
||||
{
|
||||
FHyperTwistPuzzleDefinitionRef Definition;
|
||||
Definition.PuzzleId = PuzzleId;
|
||||
Definition.PuzzleFamily = PuzzleFamily;
|
||||
Definition.Dimension = Dimension;
|
||||
Definition.DefinitionVersion = DefinitionVersion;
|
||||
Definition.NotationProfile = NotationProfile;
|
||||
Definition.SizeVector = SizeVector;
|
||||
Definition.Variant = Variant;
|
||||
return Definition;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistRetainedHyperPuzzleCatalog
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CatalogId = TEXT("retained/hyperspeedcube/hyper-puzzles");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CatalogVersion = TEXT("2026.05");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistRetainedHyperPuzzleCatalogEntry> Entries;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (CatalogId.IsEmpty() || CatalogVersion.IsEmpty() || Entries.Num() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FHyperTwistRetainedHyperPuzzleCatalogEntry& Entry : Entries)
|
||||
{
|
||||
if (!Entry.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,21 @@ class UNREALHYPERTWIST_API UHyperTwistTrainingCatalogLibrary : public UBlueprint
|
|||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Catalog")
|
||||
static FHyperTwistRetainedHyperPuzzleCatalog MakeRetainedHyperPuzzleCatalog();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Catalog")
|
||||
static bool TryGetRetainedHyperPuzzleCatalogEntry(
|
||||
const FString& PuzzleId,
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry& OutEntry
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Catalog")
|
||||
static bool TryResolveRetainedHyperPuzzleDefinition(
|
||||
const FString& PuzzleId,
|
||||
FHyperTwistPuzzleDefinitionRef& OutDefinition
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Catalog")
|
||||
static FHyperTwistContentPack MakeAlgTrainerStarterContentPack();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright HyperTwist, Inc. All Rights Reserved.
|
||||
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
#include "HyperTwistBootstrap/HyperTwistContractLibrary.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingLibrary.h"
|
||||
|
||||
#if WITH_AUTOMATION_TESTS
|
||||
|
||||
namespace HyperTwistHyperspeedcubePhase6RATestInternal
|
||||
{
|
||||
FHyperTwistTrainingDeck MakeHypercubeDeck(const FString& PuzzleId)
|
||||
{
|
||||
FHyperTwistTrainingDeck Deck;
|
||||
Deck.DeckId = TEXT("phase6r-a/hypercube-catalog");
|
||||
Deck.Title = TEXT("Phase 6R-A Hyper Puzzle Catalog");
|
||||
Deck.DeliveryModes = {EHyperTwistTrainingDeliveryMode::Timer};
|
||||
|
||||
FHyperTwistTrainingCase TrainingCase;
|
||||
TrainingCase.CaseId = TEXT("phase6r-a-case");
|
||||
TrainingCase.PuzzleId = PuzzleId;
|
||||
TrainingCase.PromptLabel = TEXT("Phase 6R-A Hyper Puzzle");
|
||||
TrainingCase.AllowedDeliveryModes = {EHyperTwistTrainingDeliveryMode::Timer};
|
||||
Deck.Cases = {TrainingCase};
|
||||
return Deck;
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistHyperspeedcubePhase6RACatalogLookupTest,
|
||||
"HyperTwist.Permissive.Hyperspeedcube.Phase6R.A.CatalogLookup",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistHyperspeedcubePhase6RACatalogLookupTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistRetainedHyperPuzzleCatalog Catalog =
|
||||
UHyperTwistTrainingCatalogLibrary::MakeRetainedHyperPuzzleCatalog();
|
||||
|
||||
TestTrue(TEXT("The retained hyper puzzle catalog must be structurally valid."), Catalog.IsStructurallyValid());
|
||||
TestTrue(TEXT("The retained hyper puzzle catalog must register multiple retained entries."), Catalog.Entries.Num() >= 5);
|
||||
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry VirtualEntry;
|
||||
TestTrue(
|
||||
TEXT("The catalog must resolve the virtual 3x3x3x3 alias."),
|
||||
UHyperTwistTrainingCatalogLibrary::TryGetRetainedHyperPuzzleCatalogEntry(TEXT("3x3x3x3"), VirtualEntry)
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The virtual 3x3x3x3 alias must map to the canonical retained puzzle id."),
|
||||
VirtualEntry.PuzzleId,
|
||||
TEXT("hypercube/3x3x3x3")
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The virtual 3x3x3x3 alias must resolve as a 4D hypercube."),
|
||||
VirtualEntry.Dimension,
|
||||
4
|
||||
);
|
||||
|
||||
FHyperTwistRetainedHyperPuzzleCatalogEntry PhysicalEntry;
|
||||
TestTrue(
|
||||
TEXT("The catalog must resolve the physical 2x2x2x2 alias."),
|
||||
UHyperTwistTrainingCatalogLibrary::TryGetRetainedHyperPuzzleCatalogEntry(TEXT("phys_2x2x2x2"), PhysicalEntry)
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The physical 2x2x2x2 alias must map to the canonical retained puzzle id."),
|
||||
PhysicalEntry.PuzzleId,
|
||||
TEXT("hypercube/2x2x2x2/physical")
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The physical 2x2x2x2 entry must preserve the physical variant label."),
|
||||
PhysicalEntry.Variant,
|
||||
TEXT("physical")
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistHyperspeedcubePhase6RATrainingRunDefinitionTest,
|
||||
"HyperTwist.Permissive.Hyperspeedcube.Phase6R.A.TrainingRunDefinition",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistHyperspeedcubePhase6RATrainingRunDefinitionTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistTrainingRunState RunState = UHyperTwistTrainingLibrary::StartTrainingRun(
|
||||
HyperTwistHyperspeedcubePhase6RATestInternal::MakeHypercubeDeck(TEXT("3x3x3x3")),
|
||||
TEXT("phase6r-a-user"),
|
||||
TEXT("phase6r-a-session"),
|
||||
EHyperTwistTrainingDeliveryMode::Timer
|
||||
);
|
||||
|
||||
TestTrue(TEXT("The bounded 6R-A deck must start a structurally valid run."), RunState.IsStructurallyValid());
|
||||
TestEqual(
|
||||
TEXT("The replay packet must promote the virtual 3x3x3x3 alias to the canonical retained puzzle id."),
|
||||
RunState.ReplayPacket.PuzzleDefinition.PuzzleId,
|
||||
TEXT("hypercube/3x3x3x3")
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The replay packet must retain the retained hyper notation profile."),
|
||||
RunState.ReplayPacket.PuzzleDefinition.NotationProfile,
|
||||
TEXT("hyper-4d")
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The replay packet must retain the 4D hypercube family."),
|
||||
RunState.ReplayPacket.PuzzleDefinition.PuzzleFamily,
|
||||
EHyperTwistPuzzleFamily::Hypercube
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The replay packet must retain the 4D hypercube dimension."),
|
||||
RunState.ReplayPacket.PuzzleDefinition.Dimension,
|
||||
4
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistHyperspeedcubePhase6RASampleDefinitionTest,
|
||||
"HyperTwist.Permissive.Hyperspeedcube.Phase6R.A.SampleDefinition",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistHyperspeedcubePhase6RASampleDefinitionTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistPuzzleDefinitionRef Definition =
|
||||
UHyperTwistContractLibrary::MakeSampleHyperPuzzleDefinition();
|
||||
|
||||
TestEqual(
|
||||
TEXT("The sample hyper definition must resolve through the retained hyper puzzle catalog."),
|
||||
Definition.PuzzleId,
|
||||
TEXT("hypercube/2x2x2x2")
|
||||
);
|
||||
TestEqual(TEXT("The sample hyper definition must remain 4D."), Definition.Dimension, 4);
|
||||
TestEqual(TEXT("The sample hyper definition must retain the hyper notation profile."), Definition.NotationProfile, TEXT("hyper-4d"));
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -94,33 +94,39 @@ Status update on `2026-05-20`:
|
|||
|
||||
- the current canonical repo-row portfolio count is `75`
|
||||
- all `75` current portfolio rows now have explicit root-tracker coverage
|
||||
- the current implemented-row count is `24`
|
||||
- the current implemented-row count is `25`
|
||||
- the four later restrictive clean-room rows now implemented after the original `2026-05-13` truth
|
||||
block are:
|
||||
- `cubing/alg.js`
|
||||
- `cubing/twisty.js`
|
||||
- `HactarCE/2x2x2x2-Scrambler`
|
||||
- `kash/cubedesk`
|
||||
- the fifth additional implemented row is the same-day bounded permissive partial row:
|
||||
- `HactarCE/Hyperspeedcube`
|
||||
- the earlier first-party packet block is now confirmed landed in current code through:
|
||||
- `d4f4ad3` `Add primary coach orchestration entry lane`
|
||||
- `1860f14` `Add provider-backed recognition sidecar client`
|
||||
- `2473665` `Overlay imported training catalog packs and finite bundles`
|
||||
- the current next bounded move is the source-backed `Phase 6R-A` `HactarCE/Hyperspeedcube`
|
||||
runtime-anchor widening packet, not a new restrictive packet by default
|
||||
- the bounded permissive `Phase 6R-A` `HactarCE/Hyperspeedcube` puzzle-catalog contract widening
|
||||
packet is now landed in current code
|
||||
- `HactarCE/Hyperspeedcube` remains partially incorporated; the current next bounded move is a
|
||||
source-backed `Phase 6R-B` `kkoomen/qbr` preparation/control pass, not a new restrictive packet
|
||||
by default
|
||||
- use the repo-row README census, the portfolio standing refresh backfill, and the `2R-A`
|
||||
ownership contract for the current queue after that correction
|
||||
|
||||
This file now also preserves the current truth that future models must not lose:
|
||||
|
||||
- current curated HyperTwist shallow-eval set: `75` repos
|
||||
- currently verified live/implemented in checked `UnrealHyperTwist` surfaces: `24`
|
||||
- permissive live lanes: `13`
|
||||
- currently verified live/implemented in checked `UnrealHyperTwist` surfaces: `25`
|
||||
- permissive live lanes: `14`
|
||||
- boundary-sensitive live lanes: `6`
|
||||
- restrictive live lanes: `5`
|
||||
|
||||
The thirteen permissive live lanes are:
|
||||
The fourteen permissive live lanes are:
|
||||
|
||||
- `Aarav2709/KubeTimr`
|
||||
- `HactarCE/Hyperspeedcube`
|
||||
- `apache/echarts`
|
||||
- `abunickabhi/5style-Trainer`
|
||||
- `google/model-viewer`
|
||||
|
|
@ -203,8 +209,7 @@ Current practical interpretation:
|
|||
- the landed `PostHog/posthog` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_D_POSTHOG_CONTROL_PLANE_IMPLEMENTATION_2026-05-13.md`
|
||||
- the landed `screenpipe/screenpipe` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_E_SCREENPIPE_CAPTURE_HISTORY_IMPLEMENTATION_2026-05-13.md`
|
||||
- the landed `remotion-dev/remotion` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_F_REMOTION_MEDIA_EXPORT_IMPLEMENTATION_2026-05-13.md`
|
||||
- the next bounded move is the bounded `Phase 6R-A` `HactarCE/Hyperspeedcube` runtime-anchor
|
||||
widening packet
|
||||
- the next bounded move is a source-backed `Phase 6R-B` `kkoomen/qbr` preparation/control pass
|
||||
|
||||
Companion docs:
|
||||
|
||||
|
|
@ -219,6 +224,7 @@ Companion docs:
|
|||
- `docs/HYPERTWIST_PHASE_3R_PACKET_3R_A_KUBETIMR_IMPLEMENTATION_2026-05-13.md`
|
||||
- `docs/HYPERTWIST_PHASE_3R_PACKET_3R_B_HYPERCUBING_XYZ_IMPLEMENTATION_2026-05-13.md`
|
||||
- `docs/HYPERTWIST_PHASE_3R_PACKET_3R_F_BROWSER_SPATIAL_SUPPORT_IMPLEMENTATION_2026-05-13.md`
|
||||
- `docs/arch/HYPERTWIST_PHASE6R_A_HYPERSPEEDCUBE_PUZZLE_CATALOG_IMPLEMENTATION_PACKET_2026-05-20.md`
|
||||
- `docs/HYPERTWIST_REPO_STATE_BOARD_2026-05-11.md`
|
||||
|
||||
## Landed live-lane legal records
|
||||
|
|
@ -1196,6 +1202,10 @@ Current licensing judgment:
|
|||
- not a clean-room case
|
||||
- treat as a bounded permissive donor candidate whose technical widening is still constrained by the
|
||||
retained `Phase 6R-A` ownership contract
|
||||
- the first narrower bounded implementation slice is now landed in current code:
|
||||
- hyper puzzle catalog contract
|
||||
- the row remains only partially incorporated; DSL, notation, replay verification, and stats-shape
|
||||
widening remain deferred
|
||||
|
||||
Source basis:
|
||||
|
||||
|
|
@ -1231,6 +1241,9 @@ Approved working posture:
|
|||
permission to transplant the whole Rust application shell
|
||||
- do not let this row absorb non-Euclidean topology ownership that remains queued for
|
||||
`roice3/MagicTile`
|
||||
- after the landed puzzle-catalog slice, the next queue head should move to a source-backed
|
||||
`Phase 6R-B` `kkoomen/qbr` preparation/control pass rather than pretending the entire
|
||||
`Hyperspeedcube` family is already closed
|
||||
|
||||
### `coqui-ai/TTS`
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
# HyperTwist Phase 6R-A Hyperspeedcube puzzle catalog implementation packet
|
||||
|
||||
Created on `2026-05-20`
|
||||
|
||||
## Status
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- bounded permissive `Phase 6R-A` implementation slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet lands the first narrower bounded slice from the retained `HactarCE/Hyperspeedcube`
|
||||
runtime-anchor row.
|
||||
|
||||
The landed slice is:
|
||||
|
||||
- first-party hyper puzzle catalog contract
|
||||
|
||||
It is not:
|
||||
|
||||
- a full `Hyperspeedcube` row transplant
|
||||
- a puzzle-definition DSL packet
|
||||
- a notation parser or serializer packet
|
||||
- a replay verification packet
|
||||
- a stats-shape packet
|
||||
- a `qbr`, `rubix-cube-solver`, or `MagicTile` packet
|
||||
|
||||
## Current authority basis
|
||||
|
||||
This implementation packet stands on:
|
||||
|
||||
- `docs/HYPERTWIST_PHASE_0R_PACKET_0R_A_EVALUATION_2026-05-12.md`
|
||||
- `docs/HYPERTWIST_PHASE_2R_PACKET_2R_A_OWNERSHIP_AND_ACCEPTANCE_CONTRACT_2026-05-13.md`
|
||||
- `docs/REPO_LICENSE_TRACKING.md`
|
||||
- `docs/arch/HYPERTWIST_PHASE6R_A_HYPERSPEEDCUBE_RUNTIME_ANCHOR_PREPARATION_PACKET_2026-05-20.md`
|
||||
|
||||
The retained owner remains:
|
||||
|
||||
- `HactarCE/Hyperspeedcube`
|
||||
|
||||
The granted family remains bounded to:
|
||||
|
||||
- puzzle catalog contract
|
||||
- puzzle-definition DSL boundary
|
||||
- notation grammar and serialization boundary
|
||||
- replay-event taxonomy and verification boundary
|
||||
- stats-shape and solve-record contract
|
||||
|
||||
This packet lands only the first family in that granted set.
|
||||
|
||||
## Landed scope
|
||||
|
||||
The current code now owns a retained hyper puzzle catalog contract through:
|
||||
|
||||
- retained catalog contract types for canonical hyper puzzle entries and the catalog wrapper
|
||||
- `UHyperTwistTrainingCatalogLibrary` catalog construction and lookup helpers
|
||||
- canonical hyper-definition resolution for:
|
||||
- `3x3x3x3`
|
||||
- `2x2x2x2`
|
||||
- `4x4x4x4`
|
||||
- `3x3x3x3x3`
|
||||
- `phys_2x2x2x2`
|
||||
- replay-packet definition shaping in `UHyperTwistTrainingLibrary`
|
||||
- session/runtime family and notation resolution in `UHyperTwistTrainingSubsystem`
|
||||
- coach option family counting in `UHyperTwistTrainingCoachLibrary`
|
||||
- sample hyper definition routing in `UHyperTwistContractLibrary`
|
||||
|
||||
## Why this is still intentionally bounded
|
||||
|
||||
This packet replaces sample / heuristic hyper puzzle identity with a catalog-owned contract, but it
|
||||
does not widen into the neighboring retained families.
|
||||
|
||||
Still deferred:
|
||||
|
||||
- puzzle-definition DSL parsing and authoring
|
||||
- notation parsing and serialization
|
||||
- replay-event taxonomy widening and replay verification
|
||||
- stats-shape / solve-record widening
|
||||
- broad view / simulation UX
|
||||
- non-Euclidean topology ownership
|
||||
- `qbr` calibration / perception ownership
|
||||
- `rubix-cube-solver` correction / explanation ownership
|
||||
|
||||
## Validation
|
||||
|
||||
Build validation:
|
||||
|
||||
- `Build.bat UnrealHyperTwistEditor Win64 Development -Project='C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.uproject' -WaitMutex -NoHotReloadFromIDE`
|
||||
|
||||
Focused automation validation:
|
||||
|
||||
- `Automation RunTests HyperTwist.Permissive.Hyperspeedcube.Phase6R.A`
|
||||
|
||||
Regression automation validation:
|
||||
|
||||
- `Automation RunTests HyperTwist.CleanRoom.CubeDesk`
|
||||
- `Automation RunTests HyperTwist.CleanRoom.HactarCE`
|
||||
|
||||
Expected covered tests:
|
||||
|
||||
- `CatalogLookup`
|
||||
- `SampleDefinition`
|
||||
- `TrainingRunDefinition`
|
||||
- existing `CubeDesk` clean-room regression suite
|
||||
- existing `HactarCE` clean-room regression suite
|
||||
|
||||
## Queue effect
|
||||
|
||||
This packet consumes the current `Phase 6R-A` implementation slice.
|
||||
|
||||
`HactarCE/Hyperspeedcube` remains only partially incorporated:
|
||||
|
||||
- landed now:
|
||||
- puzzle catalog contract
|
||||
- still deferred:
|
||||
- DSL
|
||||
- notation
|
||||
- replay verification
|
||||
- stats-shape
|
||||
|
||||
The next clean move is not another immediate `Hyperspeedcube` widening by default.
|
||||
|
||||
The next queue head should be:
|
||||
|
||||
- a source-backed `Phase 6R-B` `kkoomen/qbr` preparation/control pass
|
||||
|
||||
Keep the legal sequencing guard visible there:
|
||||
|
||||
- do not copy or redistribute `src/assets/arial-unicode-ms.ttf` without separate confirmation or
|
||||
replacement
|
||||
|
|
@ -4,8 +4,10 @@ Created on `2026-05-20`
|
|||
|
||||
## Status
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- historical same-day preparation authority
|
||||
- bounded post-Phase-`5R` preparation slice
|
||||
- the first bounded implementation slice now lands separately under:
|
||||
- `docs/arch/HYPERTWIST_PHASE6R_A_HYPERSPEEDCUBE_PUZZLE_CATALOG_IMPLEMENTATION_PACKET_2026-05-20.md`
|
||||
|
||||
## Purpose
|
||||
|
||||
|
|
@ -183,7 +185,7 @@ Before widening starts, that packet should:
|
|||
|
||||
## Suggested next packet
|
||||
|
||||
The next explicit implementation-facing packet after this preparation slice should be:
|
||||
The next explicit implementation-facing packet after this preparation slice is now:
|
||||
|
||||
- a bounded permissive `Phase 6R-A` `HactarCE/Hyperspeedcube` puzzle-catalog contract widening
|
||||
packet
|
||||
|
|
|
|||
|
|
@ -3,20 +3,26 @@
|
|||
Status update on `2026-05-20`:
|
||||
|
||||
- the canonical HyperTwist repo-row portfolio is now treated as `75` rows, not `71`
|
||||
- currently implemented rows are now `24`, not `20`
|
||||
- the additional current implemented rows are the later-landed restrictive clean-room lanes:
|
||||
- currently implemented rows are now `25`, not `20`
|
||||
- four of the additional current implemented rows are the later-landed restrictive clean-room lanes:
|
||||
- `cubing/alg.js`
|
||||
- `cubing/twisty.js`
|
||||
- `HactarCE/2x2x2x2-Scrambler`
|
||||
- `kash/cubedesk`
|
||||
- the fifth additional current implemented row is the same-day bounded permissive partial row:
|
||||
- `HactarCE/Hyperspeedcube`
|
||||
- the current next bounded move is **not** another restrictive packet by default
|
||||
- the earlier first-party packet block that was still being treated as next is now confirmed landed:
|
||||
- `d4f4ad3` `Add primary coach orchestration entry lane`
|
||||
- `1860f14` `Add provider-backed recognition sidecar client`
|
||||
- `2473665` `Overlay imported training catalog packs and finite bundles`
|
||||
- the generic source-backed `Phase 6R-A` `HactarCE/Hyperspeedcube` control pass is now consumed
|
||||
- the current next bounded move is the bounded permissive `Phase 6R-A`
|
||||
`HactarCE/Hyperspeedcube` puzzle-catalog contract widening packet
|
||||
- the bounded permissive `Phase 6R-A` `HactarCE/Hyperspeedcube` puzzle-catalog contract widening
|
||||
packet is now landed in current code
|
||||
- `HactarCE/Hyperspeedcube` remains partially incorporated; DSL, notation, replay verification,
|
||||
and stats-shape families stay deferred
|
||||
- the current next bounded move is a source-backed `Phase 6R-B` `kkoomen/qbr` preparation/control
|
||||
pass
|
||||
- the repo-row implementation queue is now live from that `Phase 6R-A` entry point rather than
|
||||
waiting on another first-party packet
|
||||
|
||||
|
|
@ -44,8 +50,8 @@ Donor-strength rule:
|
|||
- route difficulty changes how retained value may enter the product, not whether it may win technically
|
||||
|
||||
- current shallow-eval set: `75` repos
|
||||
- currently verified live/implemented in checked Unreal surfaces: `24`
|
||||
- permissive live lanes: `13`
|
||||
- currently verified live/implemented in checked Unreal surfaces: `25`
|
||||
- permissive live lanes: `14`
|
||||
- boundary-sensitive live lanes: `6`
|
||||
- restrictive live lanes: `5`
|
||||
- the restrictive landed lanes are:
|
||||
|
|
@ -55,7 +61,7 @@ Donor-strength rule:
|
|||
- `HactarCE/2x2x2x2-Scrambler`
|
||||
- `kash/cubedesk`
|
||||
- each restrictive landed lane is to be treated as properly clean-roomed and implemented afterward
|
||||
- `Phase 0R` is now closed for the remaining `51` non-live rows
|
||||
- `Phase 0R` is now closed for the remaining `50` non-live rows
|
||||
- `Phase 1R` is now closed as the retained-set contract and handoff overhaul
|
||||
- `Phase 2R` is now closed as the retained-set ownership and acceptance packet sequence
|
||||
- `Phase 3R-A` is now closed as the landed `Aarav2709/KubeTimr` timer subsystem widening packet
|
||||
|
|
@ -75,11 +81,10 @@ Current routing truth:
|
|||
|
||||
- retained rows total: `68`
|
||||
- discarded from the active retained set: `3`
|
||||
- active non-live implementation-board rows: `39`
|
||||
- active non-live implementation-board rows: `38`
|
||||
- retained benchmark, oracle, or clean-room-later rows outside the active implementation board: `9`
|
||||
|
||||
The next bounded move is the bounded `Phase 6R-A` `HactarCE/Hyperspeedcube` puzzle-catalog
|
||||
contract widening packet.
|
||||
The next bounded move is a source-backed `Phase 6R-B` `kkoomen/qbr` preparation/control pass.
|
||||
|
||||
Queue interpretation after that packet:
|
||||
|
||||
|
|
@ -87,14 +92,23 @@ Queue interpretation after that packet:
|
|||
- highest current repo-row queue pressure sits in:
|
||||
- `kkoomen/qbr`
|
||||
- `vivaansinghvi07/rubix-cube-solver`
|
||||
- the bounded speech-input / voice sidecar set
|
||||
- keep the adjacent legal sequencing guards visible when those rows come up:
|
||||
- `roice3/MagicTile`
|
||||
- `HactarCE/Hyperspeedcube` remains a partially landed row rather than a closed row:
|
||||
- landed:
|
||||
- puzzle catalog contract
|
||||
- still deferred:
|
||||
- DSL
|
||||
- notation / serialization
|
||||
- replay verification
|
||||
- stats-shape
|
||||
- after the `Phase 6R-B` control pass, keep the adjacent legal sequencing guards visible:
|
||||
- `kkoomen/qbr`
|
||||
- do not copy or redistribute `src/assets/arial-unicode-ms.ttf` without separate confirmation
|
||||
or replacement
|
||||
- `vivaansinghvi07/rubix-cube-solver`
|
||||
- do not copy or redistribute `frontend/lib/twistysim.min.js` without preserving or replacing
|
||||
its upstream provenance/license
|
||||
- the bounded speech-input / voice sidecar set
|
||||
- keep the optional `Phase 3R-G` browser comparison lane deferred unless the landed primary browser
|
||||
spatial stack exposes a real gap
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue