Alt-F4 #37 — Ускоренный курс по комбинаторах 2

опубликовали  pocarski, stringweasel, Nanogamer7, Conor_, Therenas, Firerazer

На 37-й неделе, когда выходит выпуск Alt-F4, мы представляем: Выпуск №37! Какой сюрприз! В нем pocarski, вернулся с еще более доступными объяснениями того, как можно оживить и оптимизировать свою базу с помощью всего лишь нескольких комбинаторов!

Комбинаторы 2: Расширенная логистика pocarski

Несколько недель назад я написал статью об использовании комбинаторов для улучшения конкретных решений . На этот раз мы рассмотрим способы применения логической сети в более общем плане, чтобы сделать всю вашу фабрику более эффективной. Мы рассмотрим подводные камни традиционного проектирования, найдем способы их решения и реализуем эти решения с использованием логической сети. Такие улучшения можно делать как с ботами, так и с поездами, а схема настолько проста, что почти не требует сравнивающих комбинаторов. Поехали!

Боты: межсетевой интерфейс

У всех нас была такая проблема: вы увеличиваете спрос на ботов, и внезапно все боты с дальнего конца вашей базы решают, что это хорошая идея — пройти тысячи плиток по зонам без робопортов. В лучшем случае это вызовет легкое разочарование поразительным сходством с реальными службами доставки, а в худшем случае боты будут продолжать уничтожаться кусаками или разворачиваться на полпути, чтобы заряжаться, которые они только что покинули. оставляя вас вообще без пропускной способности. Это происходит, когда ваша логистическая сеть имеет угол, обращенный внутрь, создавая огромную лишенную логистики зону, через которую боты, двигающиеся по прямой линии, немедленно начнут прорезать ее.

A majority of a network’s bots being stuck in battery range limbo

Итак, чтобы этого не произошло, было написано правило: «Не создавайте вогнутых логистических сетей». Звучит просто, правда? Просто сделайте своей базой массивный прямоугольник робопортов, и там просто не будет углов, которые нужно будет вырезать. Это правильное решение, но оно накладывает очень серьезные ограничения на ваше расширение, поскольку вам придется расширять прямоугольник, чтобы охватить всю вашу недавно приобретенную недвижимость. Это вызывает ситуации, когда ваша фактическая база занимает лишь крошечную часть площади, покрываемой вашей логистической сетью.

A base with awkward “stalk” that would inflate the logistic rectangle

Гораздо лучший способ решить эту проблему — разделить сети. По сути, вместо того, чтобы создавать один огромный прямоугольник, вы создаете кучу несвязанных меньших прямоугольников, которые затем можно расположить так, чтобы покрыть любую форму, которую вы хотите. Таким образом, любая отдельная сеть по-прежнему будет выпуклой, а это значит, что боты никогда не покинут зону покрытия робопорта. Это хорошее решение, но как заставить предметы перемещаться через промежутки между сетями? Здесь на помощь приходит логика.

Давайте построим две сети с промежутком в один тайл между ними и назовем их сетью A и сетью B. Элементы будут пересекать этот промежуток с помощью манипулятора, расположенного между ящиком запроса и активного снабжения. Для любых элементов, которые мы хотим переместить из A в B, мы должны установить запрос для запрашивающих A как количество элементов, которые мы хотим передать. Аналогичным образом мы можем передавать предметы из B в A.

Хотя мы можем разработать сложные способы точно определить, сколько из того, что нужно куда-то направить, мы будем придерживаться простого решения, которое достаточно хорошо работает для большинства целей: хранить в обеих сетях одинаковое количество элементов. Для этого мы определим половину разницы между сетевым содержимым каждого элемента и заставим сеть с большим количеством этого элемента отправить это количество в сеть с меньшим количеством этого элемента. Вот примерная диаграмма, описывающая эту идею:

Diagram of the idea

Мы подключаем робопорт в сети A к паре арифметических комбинаторов, один из которых умножает на 1, а другой — на -1. Это даст нам положительную и отрицательную ценность для элементов в сети. То же самое делаем для сети B.

Negating networks

Затем мы соединяем отрицательное значение одной сети с положительным значением другой. Это даст нам разницу между их содержимым. Затем мы делим это значение на 2 и передаем его на запрос. Важно, чтобы сундуки на стороне с большим количеством предметов получали положительное значение, иначе система будет делать прямо противоположное тому, что мы хотим. Также важно округлить значение до размера груза вашего робота, иначе они могут постоянно летать туда и обратно, пытаясь исправить разницу в два элемента, перемещая четыре элемента за раз.

Calculating half of the difference

Поскольку один манипулятор в каждую сторону немного медленно, мы можем добавить больше. Если мы просто слепо добавим больше сундуков, то запрос каждого из них будет вдвое меньше, а это означает, что фактический запрос будет в несколько раз больше, чем должен быть. Нам нужно разделить полученную разницу на количество сундуков, а также добавить остаток в один из сундуков. Еще раз, округление до размера груза робота имеет первостепенное значение. Это округление действительно означает, что сети не станут строго равными, но это необходимая жертва.

Multiple requesters

Эта логика теперь будет делать все возможное, чтобы поддерживать уровень содержимого сети с ошибкой в несколько пунктов. Боты будут немного двигаться вперед и назад, потому что существует задержка между удалением элементов из одной сети и добавлением их в другую, что означает, что сначала происходит небольшая избыточная коррекция. При наличии более двух сетей не так много изменений. Поскольку каждая пара сетей пытается уравнять количество элементов, все элементы постепенно распределяются более или менее равномерно по всей системе.

Эта схема плавно регулируется и настраивается. Вы можете добавить фактор смещения, чтобы содержимое сети находилось в определенном соотношении, или вы можете добавить условия, когда применять смещение и к каким элементам, и все остальное, что вы можете придумать, как это сделать. На мой взгляд, это даже более важная особенность, чем простота.

Поезда: ванильный аналог  LTN

Тогда переходим от ботов к поездам: поезда очень мощные, но поезда также тупые. В сложной системе со многими станциями с одинаковыми названиями вы в значительной степени вынуждены использовать логику, потому что в противном случае поезда будут продолжать движение к одним и тем же станциям, переполняя их, а остальные голодать. Традиционным способом управления движением поездов было отключение станций, которым не нужны поезда, заставляя поезда двигаться в другом месте. Однако это очень грубый и неэффективный метод с множеством проблем: перестановка поездов внутри перекрестков может вызвать тупиковые ситуации, включение одной станции вызывает лавину поездов, а дополнительные поезда из этой лавины создают ненужное движение. Существуют также существующие системы логики, такие как Haphollas’s Vanilla Train Network, которые решили некоторые из этих проблем, но все же не все из них.

Популярный способ избежать всего этого беспорядка — использовать моды. Одним из самых популярных и влиятельных модов для Factorio является LTN,. По сути, он внедряет мозг логистического бота в ваши поезда и дает вашим станциям функциональность сундуков запроса и снабжения. Вы просто устанавливаете то, что хочет каждая станция, а все остальное поезда разберутся сами. Излишне говорить, что мод позволяет колоссальное повышение эффективности. Можно было бы ожидать, что такое фундаментальное изменение в системе будет практически невозможно воссоздать с помощью комбинаторов, и они были бы правильными. Однако чрезвычайно легко создать гораздо более простую, хотя и несколько менее эффективную версию LTN с использованием логики.

Сегодня я представляю «Train Limit Dispatcher and Requester”», или TLDR. Это набор очень простых схем, которые несколько человек изобрели независимо друг от друга, используя ограничения поездов на станциях, которые были введены в 1.1, чтобы действовать как флаги запроса поезда. Основное упрощение состоит в том, что в отличие от собственно LTN, в системе TLDR почти каждый поезд или станция выделены для одного ресурса. Логика проста: для каждой станции поставщика вычислите количество «поездов», которое у вас есть на складе, и установите его в качестве лимита поездов. Для каждого запрашивающего сделайте то же самое с разницей между запросом и содержимым. Затем каждый поезд просто проходит между поставщиком и запрашивающим с условиями «груз полон» и «груз пуст».

An extremely simple provider station

TLDR решает все проблемы, присущие классическому решению по отключению станций. Поезда никогда не вызовут тупиковые ситуации из-за смены маршрутов внутри перекрестков, поскольку, в отличие от отключения станции, изменение лимита движения поездов не приводит к смене маршрута. Избыточное количество поездов никогда не будет допущено на станцию, поскольку только столько поездов, сколько позволяет лимит поездов, сможет уйти. Отсутствие схода лавин означает меньший трафик, более высокую пропускную способность и меньшее количество поездов, что также означает лучшую производительность в игре.

Однако все не так просто, как кажется. Например, если поезд выгружается у запрашивающей стороны, но ни один провайдер не готов, то он просто стоит там. Это означает, что нам нужно центральное депо, поэтому поездам всегда есть куда пойти, чтобы освободить станцию ​​запроса. Депо может быть настолько простым, насколько возможно: просто группа станций с постоянным лимитом поездов, равным 1, и несколько манипуляторов для заправки топливом. Поезда теперь также ходят от отправителя запроса к депо к провайдеру, останавливаясь в депо на короткое время. Некоторые поезда могут останавливаться в депо и после того, как отправляются от поставщика, например, если поставщик действительно далеко.

An example depot
Пример депо вместимостью до 100 поездов в удобном для сети формате.

Но подождите, это еще не все! Пространство для ожидания на станциях не безгранично, и если одновременно запрашивается слишком много поездов, они могут начать стоять в очереди на путях, на которых не должно быть ничего стоящего в очереди. Чтобы исправить это, мы добавляем два решающих комбинатора. Они будут проверять, превышает ли запрошенное количество поездов определенную константу. Если это не так, запрос проходит напрямую. Если это так, вместо этого выводится константа. Их выходы суммируются просто потому, что константа и предел поезда используют разные сигналы, и они должны быть одним и тем же сигналом. Затем эта сумма передается станции в качестве лимита поезда.

Train limit limiter

Эта логика, как и первая схема из этой статьи, настраивается. Например, у вас могут быть заказчики, автоматически определяющие и устанавливающие свои собственные запросы, или у вас может быть что-то полностью независимое, управляющее их запросами, или вы даже можете изменить количество элементов, загружаемых в поезд. По сути, любые константы, которые принимает система, можно превратить в динамические значения, управляемые друг другом, какой-то независимой схемой или даже вручную. Вы также можете испортить расписание и условия поездов, например, заставив станции выгружать поезда, как только их запросы будут выполнены, или заставить поезд обрабатывать более одного ресурса.

Итоги

Приведенные здесь схемы предназначены как для конечных продуктов, так и в качестве основы для ваших собственных логических проектов. Я бы сказал, что они похожи на неокрашенные фигурки: вы все еще можете многое из них получить в той форме, в которой вы их получили, но у вас есть безграничные возможности, как только вы проявите немного творчества и навыков. В этой статье намеренно нет чертежей, потому что ее цель не только дать вам несколько аккуратных схем, но и помочь вам лучше их понять. Удачной проводки!

Содействие

Как всегда, мы ищем людей, которые хотят внести свой вклад в Alt-F4, будь то отправка статьи или помощь с переводом. Если у вас есть что-то интересное, чем вы хотите в изящной форме поделиться с сообществом, то это место для вас. Если вы не совсем уверены в этом, мы с радостью поможем, обсудив идеи содержания и вопросы структуры. Если это похоже на то, что вас интересует, присоединяйтесь к Discord, чтобы начать!

Comments: