Загрузка данных
Вы очень внимательно проанализировали поведение алгоритма, но в данном случае предложенное «исправление» (сохранение чистого физического состояния и использование его для новых подвесок) не устраняет дефект, а создаёт новый.
Давайте разберёмся почему.
Что делает блок последовательной симуляции активных подвесок
После переноса накопления планов в SelectAndMove мы добились того, что:
Каждая активная подвеска моделируется последовательно, начиная с чисто физического состояния (localVatBusyUntil содержит только фактические времена окончания процессов в ваннах).
Когда подвеска A просчитана, её будущие интервалы занятости добавляются в localVatBusyUntil.
Подвеска B, симулируемая следующей, видит уже планы A и корректно вписывает свои шаги в оставшиеся свободные окна.
Никакого «склеивания» не происходит, потому что каждая подвеска учитывает только уже зафиксированные планы предыдущих, а не все сразу.
Результат этого блока — массив localVatBusyUntil, содержащий точный прогноз занятости ванн с учётом всех уже движущихся подвесок. Это та самая «фоновая занятость», которую обязаны видеть новые кандидаты (с загрузки или из буфера), чтобы не начать движение в момент, когда нужная ванна будет занята.
Почему использование «чистого физического состояния» для новых подвесок ошибочно
Предположим, мы последовали вашему совету и для подвески, стартующей с позиции 0, передаём в EvaluatePodveska массивы physicsVatBusyUntil (только физическое состояние, без планов активных подвесок). Тогда:
Симуляция новой подвески не увидит будущих занятостей, созданных уже едущими подвесками.
Она может выбрать такое время входа в ванну, которое уже зарезервировано активной подвеской.
Когда обе подвески доедут до этой ванны, возникнет реальный конфликт (физически ванна не сможет принять две подвески одновременно), что гораздо хуже, чем временная задержка на старте.
Таким образом, «ложная блокировка», которую вы описали, на самом деле является правильным предотвращением конфликта. Если CheckConstraints возвращает FALSE при взгляде на полную фоновую занятость, это означает, что нет допустимого окна для запуска подвески без нарушения ограничений. Это не ошибка, а штатная работа планировщика.
Возможный источник вашего беспокойства
Действительно, может сложиться ситуация, когда активные подвески «забивают» окна так, что новая подвеска не может стартовать, хотя интуитивно кажется, что место есть. Однако это происходит не из-за «мусорных» планов, а потому, что последовательная симуляция активных подвесок в фиксированном порядке (a=1..4) может дать неоптимальное распределение ресурсов.
Пример:
Подвеска №1 (олово) и подвеска №2 (серебро) конкурируют за ванну №3.
Если мы всегда симулируем №1 раньше, она займёт удобный слот, а №2 будет вынуждена ждать дольше, возможно, нарушив maxWait.
Если бы мы поменяли порядок, то, возможно, обе уложились бы в допустимые окна.
Это не «мусор», а неоптимальность, вызванная отсутствием глобальной оптимизации. Но заметьте: эта неоптимальность существовала и в исходном алгоритме (в CyclicCall), только там она усугублялась склеиванием интервалов. Теперь склеивания нет, но порядок симуляции по-прежнему фиксирован. Это плата за простоту реализации. В реальной системе линии с жёсткими временными требованиями может потребоваться более сложный алгоритм поиска оптимального расписания, но для базовой работоспособности текущее решение корректно и безопасно.
Рекомендация
Не заменяйте полную фоновую занятость на физическую для новых подвесок. Оставьте текущую логику, при которой все кандидаты оценивают свои маршруты относительно единого прогноза, построенного последовательным наложением планов активных подвесок. Это гарантирует отсутствие физических столкновений.
Если вы наблюдаете конкретный сценарий, в котором новая подвеска не стартует, хотя «окна должны быть», пришлите лог переменных (времена, планы) — я помогу найти, действительно ли окно существует, или оно перекрыто другими планами.
Текущий код SelectAndMove с блоком последовательной симуляции активных подвесок является правильным и не содержит указанного вами дефекта. Дополнительные «слепки» физического состояния могут использоваться разве что для диагностики, но не для принятия решений о запуске.