diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 5c1ae6a..e93ff45 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -6208,13 +6208,64 @@ UHyperTwistCoachDashboardWidget::BuildMethodDrillFollowUpWeighting() const } } - if (Weighting.MatchingHistoryCount <= 0) + Weighting.UpstreamNarrowPacketStructureHistoryCount = + CachedCoachPanelState.NarrowMethodDrillFollowUpPacketStructureHistoryCount; + Weighting.UpstreamBroadPacketStructureHistoryCount = + CachedCoachPanelState.BroadMethodDrillFollowUpPacketStructureHistoryCount; + Weighting.UpstreamPacketStructureHistoryCount = + Weighting.UpstreamNarrowPacketStructureHistoryCount + + Weighting.UpstreamBroadPacketStructureHistoryCount; + Weighting.UpstreamNarrowPacketStructureAverageOutcomeScore = + CachedCoachPanelState.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore; + Weighting.UpstreamBroadPacketStructureAverageOutcomeScore = + CachedCoachPanelState.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore; + Weighting.bHasUpstreamStructureSignal = Weighting.UpstreamPacketStructureHistoryCount > 0; + if (Weighting.bHasUpstreamStructureSignal) + { + const bool bPreferNarrowStructure = + Weighting.UpstreamNarrowPacketStructureHistoryCount > 0 + && (Weighting.UpstreamBroadPacketStructureHistoryCount <= 0 + || Weighting.UpstreamNarrowPacketStructureAverageOutcomeScore + >= Weighting.UpstreamBroadPacketStructureAverageOutcomeScore); + const bool bPreferBroadStructure = + Weighting.UpstreamBroadPacketStructureHistoryCount > 0 + && (Weighting.UpstreamNarrowPacketStructureHistoryCount <= 0 + || Weighting.UpstreamBroadPacketStructureAverageOutcomeScore + > Weighting.UpstreamNarrowPacketStructureAverageOutcomeScore); + if (bPreferNarrowStructure) + { + Weighting.bUsedUpstreamNarrowStructureSignal = true; + Weighting.ContinueNarrowBias += FMath::Clamp( + Weighting.UpstreamNarrowPacketStructureHistoryCount + - Weighting.UpstreamBroadPacketStructureHistoryCount + + (Weighting.UpstreamNarrowPacketStructureAverageOutcomeScore >= 72.0f ? 1 : 0), + 1, + 3 + ); + } + else if (bPreferBroadStructure) + { + Weighting.bUsedUpstreamBroadStructureSignal = true; + Weighting.RedirectCoachBias += FMath::Clamp( + Weighting.UpstreamBroadPacketStructureHistoryCount + - Weighting.UpstreamNarrowPacketStructureHistoryCount + + (Weighting.UpstreamBroadPacketStructureAverageOutcomeScore >= 70.0f ? 1 : 0), + 1, + 3 + ); + } + } + + if (Weighting.MatchingHistoryCount <= 0 && Weighting.UpstreamPacketStructureHistoryCount <= 0) { return Weighting; } - Weighting.AverageSuccessRate /= static_cast(Weighting.MatchingHistoryCount); - Weighting.AverageMistakes /= static_cast(Weighting.MatchingHistoryCount); + if (Weighting.MatchingHistoryCount > 0) + { + Weighting.AverageSuccessRate /= static_cast(Weighting.MatchingHistoryCount); + Weighting.AverageMistakes /= static_cast(Weighting.MatchingHistoryCount); + } Weighting.bPreferDrillFollowUp = Weighting.ContinueNarrowBias >= Weighting.RedirectCoachBias + 2; Weighting.bPreferCoachHandoff = @@ -7346,9 +7397,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() const FString MethodDrillOutcomePreferenceLine = !MethodDrillFollowUpWeighting.IsStructurallyValid() ? TEXT("no retained drill follow-up history yet") : (MethodDrillFollowUpWeighting.bPreferDrillFollowUp - ? TEXT("retained drill history favors staying narrow with drill follow-up") + ? (MethodDrillFollowUpWeighting.bUsedUpstreamNarrowStructureSignal + ? TEXT("retained drill-follow-up packet structure history favors staying narrow with drill follow-up") + : TEXT("retained drill history favors staying narrow with drill follow-up")) : (MethodDrillFollowUpWeighting.bPreferCoachHandoff - ? TEXT("retained drill history favors handing control back to broader coach guidance") + ? (MethodDrillFollowUpWeighting.bUsedUpstreamBroadStructureSignal + ? TEXT("retained drill-follow-up packet structure history favors handing control back to broader coach guidance") + : TEXT("retained drill history favors handing control back to broader coach guidance")) : TEXT("retained drill history is balanced"))); const FString MethodDrillFollowUpHistoryStatusLine = SelectedMethodDrillFollowUpHistoryEntry != nullptr @@ -7402,7 +7457,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() *MethodDrillOutcomePreferenceLine ); MethodDrillDiagnosticsDetailLine = FString::Printf( - TEXT("%s || History match %d | strong %d | weak %d | avg success %.2f | avg mistakes %.2f | strong packet cont %d | weak packet redirect %d | queue/follow-up/recommended-first %d/%d/%d | redirect packets %d"), + TEXT("%s || History match %d | strong %d | weak %d | avg success %.2f | avg mistakes %.2f | strong packet cont %d | weak packet redirect %d | queue/follow-up/recommended-first %d/%d/%d | redirect packets %d | upstream narrow/broad packet structure %d/%d avg %.1f/%.1f"), *MethodDrillDiagnosticsDetailLine, MethodDrillFollowUpWeighting.MatchingHistoryCount, MethodDrillFollowUpWeighting.StrongOutcomeCount, @@ -7414,7 +7469,11 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() MethodDrillFollowUpWeighting.QueueEntryFirstStructureCount, MethodDrillFollowUpWeighting.FollowUpPacketFirstStructureCount, MethodDrillFollowUpWeighting.RecommendedBriefFirstStructureCount, - MethodDrillFollowUpWeighting.RecommendedRedirectStructureCount + MethodDrillFollowUpWeighting.RecommendedRedirectStructureCount, + MethodDrillFollowUpWeighting.UpstreamNarrowPacketStructureHistoryCount, + MethodDrillFollowUpWeighting.UpstreamBroadPacketStructureHistoryCount, + MethodDrillFollowUpWeighting.UpstreamNarrowPacketStructureAverageOutcomeScore, + MethodDrillFollowUpWeighting.UpstreamBroadPacketStructureAverageOutcomeScore ); } if (bCanLaunchMethodDrillFollowUp && MethodDrillFollowUpWeighting.bPreferDrillFollowUp) @@ -8351,10 +8410,21 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() if (bCanLaunchMethodDrillFollowUp && MethodDrillFollowUpWeighting.IsStructurallyValid()) { CoachHandoffRecommendationDetailLine += MethodDrillFollowUpWeighting.bPreferDrillFollowUp - ? TEXT(" | Drill history says stay narrow with drill-derived follow-up before broader coach handoff.") + ? (MethodDrillFollowUpWeighting.bUsedUpstreamNarrowStructureSignal + ? TEXT(" | Upstream narrow drill-follow-up packet structure history directly tipped this branch toward tighter drill continuation.") + : TEXT(" | Drill history says stay narrow with drill-derived follow-up before broader coach handoff.")) : (MethodDrillFollowUpWeighting.bPreferCoachHandoff - ? TEXT(" | Drill history says broader coach handoff is now stronger than another narrow drill follow-up.") + ? (MethodDrillFollowUpWeighting.bUsedUpstreamBroadStructureSignal + ? TEXT(" | Upstream broad drill-follow-up packet structure history directly tipped this branch back toward broader coach guidance.") + : TEXT(" | Drill history says broader coach handoff is now stronger than another narrow drill follow-up.")) : TEXT(" | Drill history is balanced against broader coach handoff.")); + CoachHandoffRecommendationDetailLine += FString::Printf( + TEXT(" | upstream packet structure narrow/broad %d/%d avg %.1f/%.1f"), + MethodDrillFollowUpWeighting.UpstreamNarrowPacketStructureHistoryCount, + MethodDrillFollowUpWeighting.UpstreamBroadPacketStructureHistoryCount, + MethodDrillFollowUpWeighting.UpstreamNarrowPacketStructureAverageOutcomeScore, + MethodDrillFollowUpWeighting.UpstreamBroadPacketStructureAverageOutcomeScore + ); } if (MethodDrillRecoveryPacketHandoffBias.bHasSignal) { diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index c516e33..f887001 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -370,6 +370,9 @@ struct FHyperTwistCoachDashboardMethodDrillRecoveryMemoryHistoryEntry struct FHyperTwistCoachDashboardMethodDrillFollowUpWeighting { int32 MatchingHistoryCount = 0; + int32 UpstreamPacketStructureHistoryCount = 0; + int32 UpstreamNarrowPacketStructureHistoryCount = 0; + int32 UpstreamBroadPacketStructureHistoryCount = 0; int32 StrongOutcomeCount = 0; int32 WeakOutcomeCount = 0; int32 ContinueNarrowBias = 0; @@ -382,12 +385,17 @@ struct FHyperTwistCoachDashboardMethodDrillFollowUpWeighting int32 RecommendedRedirectStructureCount = 0; float AverageSuccessRate = 0.0f; float AverageMistakes = 0.0f; + float UpstreamNarrowPacketStructureAverageOutcomeScore = 0.0f; + float UpstreamBroadPacketStructureAverageOutcomeScore = 0.0f; bool bPreferDrillFollowUp = false; bool bPreferCoachHandoff = false; + bool bHasUpstreamStructureSignal = false; + bool bUsedUpstreamNarrowStructureSignal = false; + bool bUsedUpstreamBroadStructureSignal = false; bool IsStructurallyValid() const { - return MatchingHistoryCount > 0; + return MatchingHistoryCount > 0 || UpstreamPacketStructureHistoryCount > 0; } };