/
GeekNerd
/
ServerModelingProject
Обзор
Документация
Войти
/
GeekNerd
/
ServerModelingProject
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Assets/Scripts/OptimizationLogic/View/OptimizationUI.cs
260 строк
9 KB
Gorney-Alex
Init
30 май 2026, 19:05
30 май 2026, 19:05
3cdcc49
Код
Авторство
О чём код?
using System; using System.Reflection; using DataClasses.Algorithm; using TMPro; using UnityEngine; using UnityEngine.UI; namespace OptimizationLogic.View { public sealed class OptimizationUI : MonoBehaviour { [Header("Buttons")] [SerializeField] private Button optimizeButton; [SerializeField] private Button cancelButton; [Header("Progress")] [SerializeField] private Slider progressBar; [SerializeField] private TMP_Text progressText; [Header("Warnings")] [SerializeField] private TMP_Text weightWarningText; [Header("GA Inputs")] [SerializeField] private TMP_InputField populationSizeInput; [SerializeField] private TMP_InputField generationsInput; [SerializeField] private TMP_InputField mutationRateInput; [SerializeField] private TMP_InputField crossoverRateInput; [Header("Weights (must sum to 1)")] [SerializeField] private Slider w1Slider; [SerializeField] private Slider w2Slider; [SerializeField] private Slider w3Slider; [SerializeField] private Slider w4Slider; public event Action OptimizeClicked; public event Action CancelClicked; private void OnEnable() { if (optimizeButton != null) optimizeButton.onClick.AddListener(OnOptimize); if (cancelButton != null) cancelButton.onClick.AddListener(OnCancel); SubscribeWeight(w1Slider); SubscribeWeight(w2Slider); SubscribeWeight(w3Slider); SubscribeWeight(w4Slider); EnsureInitialWeights(); ValidateWeights(); SetRunning(false); } private void OnDisable() { if (optimizeButton != null) optimizeButton.onClick.RemoveListener(OnOptimize); if (cancelButton != null) cancelButton.onClick.RemoveListener(OnCancel); UnsubscribeWeight(w1Slider); UnsubscribeWeight(w2Slider); UnsubscribeWeight(w3Slider); UnsubscribeWeight(w4Slider); } public void SetRunning(bool running) { if (optimizeButton != null) optimizeButton.interactable = !running && AreWeightsValid(); if (cancelButton != null) cancelButton.interactable = running; SetInteractable(populationSizeInput, !running); SetInteractable(generationsInput, !running); SetInteractable(mutationRateInput, !running); SetInteractable(crossoverRateInput, !running); SetInteractable(w1Slider, !running); SetInteractable(w2Slider, !running); SetInteractable(w3Slider, !running); SetInteractable(w4Slider, !running); } public void SetProgress(int generation, int maxGenerations, float fitness) { if (progressBar != null) { progressBar.minValue = 0; progressBar.maxValue = Mathf.Max(1, maxGenerations); progressBar.value = Mathf.Clamp(generation, 0, maxGenerations); } if (progressText != null) progressText.text = $"Gen {generation} / {maxGenerations}, F = {fitness:0.###}"; } public void SetStatus(string message) { if (progressText != null) progressText.text = message; } public GaSettings BuildSettings(GaSettings baseSettings) { baseSettings ??= new GaSettings(); GaSettings s = new GaSettings { PopulationSize = ParseInt(populationSizeInput, baseSettings.PopulationSize > 0 ? baseSettings.PopulationSize : 100), Generations = ParseInt(generationsInput, baseSettings.Generations > 0 ? baseSettings.Generations : 120), MutationRate = ParseFloat(mutationRateInput, baseSettings.MutationRate > 0f ? baseSettings.MutationRate : 0.15f), CrossoverRate = ParseFloat(crossoverRateInput, baseSettings.CrossoverRate > 0f ? baseSettings.CrossoverRate : 0.8f), EliteCount = baseSettings.EliteCount, EarlyStopGenerations = baseSettings.EarlyStopGenerations, MaxTempDelta = baseSettings.MaxTempDelta, TournamentSize = baseSettings.TournamentSize, InitMutationProb = baseSettings.InitMutationProb, RandomSeed = baseSettings.RandomSeed, WeightPlacement = w1Slider != null ? w1Slider.value : baseSettings.WeightPlacement, WeightThermal = w2Slider != null ? w2Slider.value : baseSettings.WeightThermal, WeightAisle = w3Slider != null ? w3Slider.value : baseSettings.WeightAisle, WeightTopology = w4Slider != null ? w4Slider.value : baseSettings.WeightTopology }; return s; } private void OnOptimize() { if (!AreWeightsValid()) return; OptimizeClicked?.Invoke(); } private void OnCancel() { CancelClicked?.Invoke(); } private void SubscribeWeight(Slider s) { if (s == null) return; s.onValueChanged.AddListener(_ => ValidateWeights()); } private void UnsubscribeWeight(Slider s) { if (s == null) return; s.onValueChanged.RemoveAllListeners(); } private void ValidateWeights() { bool ok = AreWeightsValid(); if (weightWarningText != null) { weightWarningText.text = ok ? string.Empty : $"Weights must sum to 1.0 (now {GetWeightSum():0.###})"; } if (optimizeButton != null) { bool running = cancelButton != null && cancelButton.interactable; optimizeButton.interactable = !running && ok; } } private bool AreWeightsValid() { if (w1Slider == null || w2Slider == null || w3Slider == null || w4Slider == null) return true; // no UI wired return Mathf.Abs(GetWeightSum() - 1f) < 0.001f; } private void EnsureInitialWeights() { if (w1Slider == null || w2Slider == null || w3Slider == null || w4Slider == null) return; // Weights are fractional; wholeNumbers would make sum-to-1 impossible. w1Slider.wholeNumbers = false; w2Slider.wholeNumbers = false; w3Slider.wholeNumbers = false; w4Slider.wholeNumbers = false; float sum = GetWeightSum(); if (sum <= 0.0001f) { SetSliderValueWithoutNotify(w1Slider, 0.30f); SetSliderValueWithoutNotify(w2Slider, 0.25f); SetSliderValueWithoutNotify(w3Slider, 0.15f); SetSliderValueWithoutNotify(w4Slider, 0.30f); return; } if (Mathf.Abs(sum - 1f) < 0.001f) return; // Normalize once so the UI starts in a valid state. SetSliderValueWithoutNotify(w1Slider, w1Slider.value / sum); SetSliderValueWithoutNotify(w2Slider, w2Slider.value / sum); SetSliderValueWithoutNotify(w3Slider, w3Slider.value / sum); SetSliderValueWithoutNotify(w4Slider, w4Slider.value / sum); } private static void SetSliderValueWithoutNotify(Slider slider, float value) { if (slider == null) return; // Some older Unity versions don't have Slider.SetValueWithoutNotify(float). MethodInfo m = typeof(Slider).GetMethod( "SetValueWithoutNotify", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, binder: null, types: new[] { typeof(float) }, modifiers: null); if (m != null) { m.Invoke(slider, new object[] { value }); return; } slider.value = value; } private float GetWeightSum() { float w1 = w1Slider != null ? w1Slider.value : 0f; float w2 = w2Slider != null ? w2Slider.value : 0f; float w3 = w3Slider != null ? w3Slider.value : 0f; float w4 = w4Slider != null ? w4Slider.value : 0f; return w1 + w2 + w3 + w4; } private static void SetInteractable(Selectable s, bool value) { if (s == null) return; s.interactable = value; } private static void SetInteractable(TMP_InputField f, bool value) { if (f == null) return; f.interactable = value; } private static int ParseInt(TMP_InputField f, int fallback) { if (f == null) return fallback; return int.TryParse(f.text, out int v) ? v : fallback; } private static float ParseFloat(TMP_InputField f, float fallback) { if (f == null) return fallback; return float.TryParse(f.text, out float v) ? v : fallback; } } }