Дисковод щелкнул шаговым двигателем, протяжно загудел, считывая дорожку, и затих. На темном экране появилось приглашение программы.
Шрамов подвинул к себе растрепанную общую тетрадь. На разворотах синели густые столбцы рукописного кода — его часть работы: ввод с клавиатуры, справочник причин задержек, проверка ошибок и вывод на печать. На дисплее ровно горело: «МАРШРУТ-82В. ОЖИДАНИЕ ВВОДА».
— Значит, твой расчётный блок я прицепил, — пробормотал Шрамов, водя колпачком ручки по строкам. — Сошлось без ошибок. Теперь давай еще раз по формату твоих данных. А то я в них завязну, пока ты с цветом, локальной сетью и системными задачами возишься.
Громов подошел ближе, положил рядом с дисплеем распечатку и развернул склейку листов с густой паутиной кружков и линий.
— Я буду рядом, пока ты об эту структуру спотыкаться не перестанешь, — пообещал он. — Смотри. Мы храним только реальные пути. Забивать память отсутствующими перегонами бессмысленно. Выходит около двухсот сорока пунктов и порядка восьмисот перегонов.
Шрамов прищурился на чертеж, быстро прикидывая:
— Двести сорок узлов… Если отдашь под номер восьмибитную ячейку, запаса не останется. Построят новый цех, кинут пару тупиков, и адресация рухнет.
— Поэтому на внутренний номер пункта закладываем два байта, — Громов чиркнул карандашом по полям распечатки, вырисовывая цепочку блоков. — Чуть тяжелее, зато места хватит на любые временные площадки и пути отстоя. Для каждой станции держим список только прямых соседей. Описание одной связи — это двухбайтный код смежного пункта, базовое время хода и номер группы для динамических ограничений.
Липатов, разбиравший в углу кипу документации, поднял голову от бланков.
— В память-то влезет вся эта география?
— Килобайт на десять потянет, — отозвался Громов. — Плюс таблицы текущих запретов на проезд. На шестидесяти четырех килобайтах ОЗУ места хватит и для программы, и для расчетов.
Шрамов кивнул и начал переносить набросок Громова в свою рабочую тетрадь. Структура получалась логичной и ложилась в его код как влитая.
— Ладно, теоретики, — позвал от двери Морозов. Он вошел в комнату, придерживая тяжелую створку и пропуская Ширяева.
Ширяев подошел к столу и опустил рядом с клавиатурой пухлую картонную папку.
— Принимайте смену, — сказал он, развязывая тесемки. — Расклад месячной давности, но самый что ни на есть боевой. Я эти выписки из журналов и ведомости механизмов еще перед командировкой собрал. Как чуял, что пригодятся. Специально взял день, от которого у наших диспетчеров обычно изжога начинается. Ничего не выдумывал, чистая историческая правда.
Он раскрыл обложку и вытряхнул на столешницу стопку карточек. Настоящие рабочие наряды на перемещение — с замятыми углами, размашистыми карандашными пометками и мазутными пятнами.
— Так, — Ширяев начал раскладывать карточки, как пасьянс. — Дано. Три партии проката со склада нужно перетащить в механосборочный цех. Груз тяжелый, негабаритный. Снимать только стотонным краном.
— Заложили стотонный кран в таблицу ресурсов, — отозвался Громов, сверяясь с листами. — Узел семнадцать.
— Дальше слушайте, — Ширяев поднял палец. — На перегоне между седьмым и восьмым цехом — плановая замена шпал. Путь закрыт наглухо с двух часов дня до восьми вечера. А в шестнадцать ноль-ноль через главную горловину Северной станции проходит литерный состав. Секретный груз, без остановок, зеленая улица. За час до его прохода и час после — Северная станция закрыта для любых маневров. Никого не впускать, никого не выпускать.
Морозов подошел к столу, скрестив руки на груди:
— Классический конфликт ресурсов. И как ваши диспетчеры выкручиваются, Павел Андреевич?
— Как-как, — хмыкнул Ширяев. — Матерятся и решают. Обычно диспетчер видит короткий путь: через Северную, прямо к стотонному крану. Он прямой, на схеме красиво смотрится, и диспетчер сразу загоняет туда прокат. А потом выясняется, что кран занят разгрузкой станков, а тут литерный на подходе. Прокат остается в тупике, горловина забита, режимники орут, завод стоит.
— Главное, не подсказывайте машине ответ, — предупредил Морозов. — Юрий Павлович, вводите исходные данные. Посмотрим, как наша топология справится с литерным составом.
Шрамов придвинулся к клавиатуре и быстро вбил первую команду. На экране высветились короткие строки:
ГРУЗ: ПРОКАТ_НЕГАБАР
МАССА: 80
ОТПРАВЛЕНИЕ: СКЛАД_4
НАЗНАЧЕНИЕ: МЕХСБОРКА_1
— Это только наша болванка, — проговорил Шрамов. — Если нажать пуск сейчас, программа проложит путь по пустому заводу. Давайте вашу обстановку, Павел Андреевич. Что еще катается по узлу?
Ширяев пододвинул стопку нарядов.
— Пишем. Перегон цехов семь-восемь — закрыт. Литерное окно на Северной — с пятнадцати до семнадцати ноль-ноль. По ведомости механизмов… так, стотонный кран занят с шестнадцати до девятнадцати.
Шрамов методично заносил информацию в машину. Ниже параметров груза выстраивался плотный столбец сменного расклада: с десяток транзитных сцепок, подача мазута на котельную, маневры у пакгаузов.
— Вы ей сейчас прямо отсекаете короткую дорогу, — с сомнением произнес Морозов, глядя на растущий список занятых путей.
— Я ей даю реальный завод, Алексей Николаевич, — парировал Ширяев. — Это не подсказка. У меня кран занят по графику, горловина заперта режимом. Без этих вводных машина решит игрушечную задачку, а не сменный наряд.
— Стой, — вмешался Горелов. Он поднялся из-за соседнего стола, где до этого молча слушал их спор, и шагнул к дисплею. — Время начала маневра сейчас вводить будешь? Маску зашили? Вы мне обещали железобетонную защиту от усталого оператора в ночную смену.
Шрамов отнял руки от клавиатуры и чуть отодвинулся, уступая место.
— А вы сами попробуйте, Андрей Витальевич. Прямо сейчас. Вбейте в графу часов цифру «25».
Горелов недоверчиво хмыкнул, склонился над клавиатурой и уверенно нажал двойку, а затем пятерку.
Из зуммера за передней панелью опытной машины раздался резкий писк. Желтый бордюр экрана мгновенно залило красным. Символ «5» так и не появился — курсор застыл на месте, а в нижней строке ярко высветилось: «ОШИБКА ВВОДА: ЧАСЫ (00–23)».
Ширяев вздрогнул от неожиданного звука и довольно крякнул.
— Вот это дело! — оживился он. — Такой сигнал и спящего диспетчера разбудит. Вслепую ошибку не пропустишь.
— Стоит намертво, — с гордостью подтвердил Шрамов. — Часы только до двадцати трех, минуты до пятидесяти девяти. Наберешь чушь — программа выдает ошибку, меняет цвет бордюра и блокирует ввод до нажатия забоя. В расчетный модуль мусор теперь не проскочит.
Горелов нажал клавишу возврата. Красный бордюр послушно сменился привычным черным.
— А текстовое сообщение по несуществующим станциям? То, что с Егоровой обсуждали?
— Зашито, — Шрамов снова придвинул к себе клавиатуру и быстро вбил правильное время. — Чужой шифр не пройдет, программа сразу выдаст предупреждение.
— Отлично, — Липатов чиркнул ручкой в блокноте, отмечая пункт о контроле ввода. — Требование выполнено.
— Так, данные в маске, — подытожил Шрамов, заполняя последнее поле. — Готовы? Запускаю расчет.
Он нажал клавишу ввода. Дисплей на мгновение мигнул, строки данных исчезли, уступив место мигающей надписи: РАСЧЕТ МАРШРУТА. ПОДОЖДИТЕ.
Дисковод снова ожил, зашуршал, подгружая в память расчетные подпрограммы Громова. Процессор начал обсчитывать граф.
Секунда. Вторая. Пятая.
— Что-то долго, — заметил Ширяев, глядя на экран.
— Нормально. — Громов не отрывал взгляда от мигающей надписи. — Это вам не два числа сложить. Алгоритм перебирает сотни ветвей. Натыкается на наши заградительные штрафы, откатывается назад, ищет обход, проверяет динамические ограничения по времени на каждом перегоне…
— Окно литерного — с пятнадцати до семнадцати, — вслух прикинул Ширяев. — А груз готов в четырнадцать тридцать. По идее, главную горловину должен успеть проскочить.
На десятой секунде дисковод замолк. Экран очистился, и на нем загорелось: РАСЧЕТ ЗАВЕРШЕН. ВЫВОД ГОТОВ.
Шрамов нажал клавишу, разворачивая результат на экране. Под мерцающим курсором появились строки ответа. Программист вчитался в текст, недоверчиво покачал головой и нажал комбинацию клавиш для вывода на печать.
Алфавитно-цифровое печатающее устройство, занимавшее отдельную усиленную тумбу в углу комнаты, ожило. Массивный вал с шипением провернулся, затягивая широкую перфорированную бумагу. Стальная печатная цепь завертелась на шкивах, и десятки электромагнитных молоточков с пулеметным лязгом ударили по широкой красящей ленте, впечатывая символы в бумагу. Запахло свежей мастикой, машинным маслом и разогретым металлом электромагнитов.
Через пять секунд лязг оборвался. Шрамов привычным жестом оторвал лист по линии перфорации, положил его на зеленое сукно стола и разгладил ладонью.
Все склонились над распечаткой.
Фиолетовые буквы дублировали ответ с дисплея:
МАРШРУТ-82В. СМЕННОЕ ЗАДАНИЕ 14.
ГРУЗ: ПРОКАТ_НЕГАБАР. МАССА: 80.
ПУТЬ СЛЕДОВАНИЯ:
СКЛАД_4 — ВЕТКА_12 — ЮЖНЫЙ_ОБХОД — ТУПИК_3 — ПАКГАУЗ_2 — ОЖИДАНИЕ (45 МИН) — МЕХСБОРКА_1.
РЕСУРС: КРАН_50Т (СПАРЕННЫЙ РЕЖИМ).
РАСЧЕТНОЕ ВРЕМЯ В ПУТИ: 185 МИНУТ.
Шрамов провел пальцем по напечатанной строке и поднял глаза на Громова.
— Евгений Александрович, — тихо сказал Шрамов. — Ваша математика рехнулась.
Ширяев оперся кулаками о край стола и хохотнул.
— Сто восемьдесят пять минут? Три часа на доставку? Да вы смеетесь. От четвертого склада до мехсборки через Северную горловину ехать двадцать минут! Сорок, если маневровый ползет еле-еле. Какой Южный обход? Какой третий тупик? Это же крюк в пятнадцать километров вокруг всего завода!
— И посмотрите на ресурс, — добавил Липатов, указывая колпачком ручки на строчку. — У вас в задании требовался стотонный кран. А машина предлагает спаренный режим для двух пятидесятитонных. Зачем городить огород с синхронным подъемом, если есть нормальный тяжелый кран?
Громов подхватил распечатку со стола, быстро просмотрел строки и потянулся к листам с графами.
— Ошибка в таблице перегонов? — пробормотал он, водя пальцем по кружкам на бумаге. — Нет, Южный обход соединен с третьим тупиком, тут все верно. Но откуда такой вес? Сто восемьдесят пять минут… Это огромная стоимость маршрута. Он должен был найти вариант подешевле.
— Может, вы знак перепутали при начислении штрафа? — предположил Горелов.
— Ничего я не перепутал! — огрызнулся Громов. — Математика не ошибается, алгоритм ищет минимум функции. Если он выдал сто восемьдесят пять, значит, все остальные варианты стоили еще дороже!
Морозов, до этого молча слушавший перепалку, подался вперед.
— Павел Андреевич, — обратился он к Ширяеву. — Отложите распечатку. Возьмите ваши карточки. Разложите их на столе так, как будто это заводская территория.
Ширяев хмыкнул, но спорить не стал. Он отодвинул в сторону тетрадь и листы с графами, пододвинул к себе кипу карточек и начал выкладывать их на свободном пространстве стола.
— Вот здесь у нас Склад номер четыре, — он положил карточку с жирной цифрой 4. — Вот здесь Мехсборка, — вторая карточка легла в полуметре правее. — Вот прямой путь. Ветка номер шесть, потом Северная станция, горловина, и мы на месте. Тут же, у мехсборки, стоит стотонный кран. Вот его карточка.
— Идеально, — согласился Морозов. — А теперь давайте пройдем этот идеальный путь по минутам, учитывая ваши же ограничения. Груз готов в четырнадцать тридцать. Поехали.
Ширяев поставил палец на карточку Склада.
— Погрузка негабарита займет минут сорок. То есть выедем мы в пятнадцать десять.
— Стоп, — Громов вскинул голову от расчетов. — Пятнадцать десять? Выезд?
— Ну да, — Ширяев пожал плечами. — Ехать до Северной станции пятнадцать минут. В пятнадцать двадцать пять будем на узле.
— А окно литерного состава? — тихо спросил Шрамов.
Ширяев осекся, его палец замер на карточке Северной станции.
— Окно литерного с пятнадцати до семнадцати, — медленно проговорил он. — За час до прохода горловина закрывается, так что в пятнадцать ноль-ноль Северная уже не принимает.
— Именно! — Громов хлопнул ладонью по столу. — Машина это посчитала! Если вы выезжаете в пятнадцать десять, то к моменту прибытия на Северную она уже закрыта наглухо. Что произойдет в реальности?
Ширяев задумчиво потер подбородок.
— В реальности диспетчер отправит состав, не подумав про литерный. Состав упрется в закрытый семафор перед Северной и встанет на шестой ветке.
— И будет стоять там до семнадцати часов, пока литерный не проскочит, — закончил Морозов. — То есть почти два часа.
— Допустим, — неохотно согласился Ширяев. — Но в семнадцать ноль-ноль горловина откроется, состав проедет, и к половине шестого будет под стотонным краном. Это все равно быстрее, чем предложенные машиной три часа по буеракам!
— Вы уверены? — Морозов указал на карточку стотонного крана. — Вы принесли сменный журнал. Что делал стотонный кран в семнадцать тридцать той смены?
Ширяев полез в картонную папку, достал ведомость работы механизмов и быстро просмотрел колонки цифр.
— Разгрузка статоров для турбинного цеха, — неохотно прочитал он. — С шестнадцати до девятнадцати ноль-ноль.
— Вот вам и ответ, — Громов скрестил руки на груди. — Узел «Северная станция» имеет абсолютный запрет в окне 15:00–17:00. Узел «Стотонный кран» получает штраф занятости с 16:00 до 19:00. Если отправить прокат коротким путем, состав простоит два часа перед литерным, а потом еще полтора будет ждать кран. Двести пятьдесят минут против ста восьмидесяти пяти.
Шрамов присвистнул, заново перечитывая распечатанные строки.
— То есть Южный обход…
— Южный обход длиннее по километрам, — подтвердил Громов, показывая расчеты. — Машина пускает состав в объезд всего завода. Да, это долго, скорость там низкая. Состав плетется по третьему тупику, приезжает к пакгаузу и ждет там сорок пять минут в отстойнике, чтобы не забивать главный ход. А потом заходит к Мехсборке с другой стороны!
— И поскольку стотонный кран занят статорами, — подхватил Липатов, глядя в распечатку, — машина находит свободные ресурсы. Два старых пятидесятитонных крана — они медленные, требуют спаренного режима, но зато свободны именно в это время!
Ширяев долго молчал. Затем он взял карандаш и провел линию в воздухе, повторяя маршрут, предложенный «Сферой». Длинная, изломанная кривая огибала все узкие места.
— Знаете, что самое страшное? — наконец сказал Ширяев. — Диспетчер в ту смену сделал именно так, как я говорил. Отправил прямым путем, и состав застрял перед Северной. Когда литерный прошел, прокат потащили дальше, но уперлись в занятый кран и бросили платформы на путях. Из-за них турбинный цех не смог вывезти стружку, и к восьми вечера вся горловина встала намертво. Я полночи с начальником смены этот затор разгребал.
Ширяев со стуком бросил карандаш поверх разложенных карточек.
— Длиннее, но вернее, — резюмировал Морозов и похлопал ладонью по папке Ширяева. — Машина не просто считает километры. Она бережет ваши редкие ресурсы и не забивает узкие места.
— Подождите радоваться, — Липатов постучал ручкой по столу. — Мы все равно сначала решили, что машина выдала бред. Хотя Женя сам эту математику писал, а Павел Андреевич смену наизусть помнит.
Липатов поднял распечатку.
— А теперь представьте диспетчера Петю. Три часа ночи. Запах мазута. Петя вводит данные, и машина выплевывает ему вот этот лист. Ехать в обход, стоять сорок пять минут, брать спаренные краны вместо одного мощного. Что сделает Петя? Он порвет эту распечатку, назовет инженеров КБ «Сфера» идиотами и отправит состав прямым путем.
— Вот для этого Егорова вчера и требовала текстовых обоснований, — поддержал Горелов. — Если маршрут неоптимален по расстоянию, машина обязана доложить понятным человеческим языком, почему она так решила.
— Код причины обхода из расчетного модуля Евгения Александровича я получаю, — отозвался Шрамов. — Он у меня в буфере лежит как «штраф типа три на узле Северная». Но в моем справочнике к этому привязана общая фраза «Узел занят». Я ее пока в печать не вывел, потому что диспетчеру она ничего не объяснит.
— Значит, дорабатываем справочник под живое предприятие, — потребовал Липатов, открывая блокнот. — Женя выдает код, а мы переводим его на заводской язык. Если расчетное расстояние превышает кратчайшее больше чем на двадцать процентов, программа обязана напечатать блок «ОБОСНОВАНИЕ». Давайте формулировать. Что мы напишем про Северную станцию вместо «Узел занят»?
— Пишите: «Узел закрыт по временному окну», — предложил Ширяев.
— Слишком размыто, — возразил Липатов. — Какому окну? Чьему? Диспетчер должен сразу понять, с кем конфликт. Нужно конкретно. «ОБХОД: ЗАНЯТОСТЬ УЗЛА СЕВЕРНАЯ (ЛИТЕР)». Понятно?
— Понятно, — согласился Ширяев.
— А по крану? «Ресурс стотонный кран имеет высокий весовой коэффициент занятости»? — Липатов оторвал взгляд от блокнота и посмотрел на Громова. — За такую формулировку на заводе тебя не поймут. Пишем протокольно и четко: «ЗАМЕНА РЕСУРСА: КРАН 100Т ЗАНЯТ (16:00–19:00)».
Шрамов делал пометки в общей тетради, затем замер и постучал колпачком ручки по столешнице.
— Подождите. Фразы отличные, но куда мы их денем? ОЗУ не резиновое. Если я сейчас забью в оперативную память сотню таких развернутых строк под каждый перегон и каждый кран, память кончится раньше, чем Евгений Александрович запустит расчет.
Громов переглянулся с Морозовым. Алексей едва заметно кивнул.
— В оперативку мы их грузить не будем, — произнес Громов. — Зашьем весь словарь причин прямо в ПЗУ.
— Массив текстовых констант? — Шрамов подался вперед, уловив идею.
— Именно. Алгоритм выдает вам, например, код 1А. Вы берете этот номер, вычисляете смещение в ПЗУ и читаете готовый текст напрямую из микросхемы, байт за байтом. Сначала выводите на экран вместе с результатом. А когда диспетчеру понадобится документ — эта же готовая строка уходит на АЦПУ. Никаких гигантских текстовых буферов. Надежно, и не съест ни байта свободной памяти.
— Идеально, — Шрамов просиял. — Привяжу конкретные фразы к кодам. На экране выделю причину цветом, чтобы привлекала внимание, а на распечатке пущу отдельным блоком перед итоговым временем.
— А давайте проверим, не перестраховывается ли она вообще всегда, — предложил Ширяев, протягивая руку к клавиатуре. — Юрий Павлович, пустите-ка.
Ширяев оттеснил Шрамова от клавиатуры.
— Что вы делаете? — удивился Морозов.
— Меняю оперативную обстановку, — ответил Ширяев, нажимая клавишу «СБРОС ФОРМЫ». — Юрий Павлович мне вчера показывал, как работает второй режим. Экран диспетчерских ограничений.
На дисплее привычная маска маршрута сменилась таблицей активных запретов. Ширяев, щурясь на экран, тяжело застучал по клавишам, подводя курсор к строке «УЗЕЛ 17 (КРАН 100Т)».
— Допустим, стотонный кран в ту смену не разгружал статоры. Допустим, он сломался, и мужики из рембригады починили его досрочно, к четырем часам. Значит, с шестнадцати часов для нас он абсолютно свободен.
Ширяев нажал клавишу забоя, стирая временной интервал штрафа, и подтвердил ввод. Динамическая таблица весов в оперативной памяти мгновенно обновилась.
Затем он нажал клавишу возврата в главное меню и изменил время готовности груза на складе с 14:30 на 15:50.
— Смотрите. Прокат готов без десяти четыре. Запрет на движение из-за литерного состава снимают в семнадцать ноль-ноль. Пока мы сорок минут грузимся на платформу и пятнадцать минут едем до узла, на часах будет шестнадцать сорок пять. Окно запрета как раз заканчивается. И тяжелый кран уже свободен. Ну, умная машина? Считай!
Он с силой ударил по клавише ввода.
Снова замигала надпись ожидания, сухо щелкнул дисковод. На этот раз расчет занял меньше пяти секунд, и строки на экране дрогнули, сменившись новым результатом.
Ширяев приблизился к самому стеклу дисплея, вчитываясь в светящиеся символы.
— Склад номер четыре, шестая ветка, Северная станция… ожидание пятнадцать минут. И Мехсборка-1, — прочитал он вслух. — Ресурс — стотонный кран. Расчетное время в пути — семьдесят пять минут.
Он выпрямился.
— Вот это дело. Увидела, что литерный ушел, подождала четверть часа на ветке, пока семафор откроют, и рванула по прямой к мощному крану. Время сократилось в два с лишним раза. Юрий Павлович, дайте-ка мне бумажную копию.
Шрамов набрал команду печати. АЦПУ в углу комнаты загрохотало, выбивая строки на свежей бумаге.
Громов потер руки.
— Я же говорил! Функция ищет оптимум. Изменились условия, пересчитались веса графа — изменился и маршрут.
Морозов потянулся и взял со стола первую распечатку — длинную, с обходом.
— Работает, — негромко констатировал он. — На чистой математике мы бы заперли всю горловину, а с учетом ограничений выкрутились.
Он повернулся к Ширяеву:
— Павел Андреевич, копию длинного маршрута забирайте себе. Пусть ваше руководство посмотрит, как можно было избежать затора.
Ширяев бережно сложил распечатку и убрал ее в картонную папку к карточкам.
— Покажу. Обязательно покажу. Если ваша «Сфера» будет такие подсказки давать диспетчеру, мы план по внутризаводским перевозкам на двадцать процентов поднимем.
— Это пока не готовая машина, — осадил его Морозов. — У нас на руках только алгоритм на дискете. Юрий Павлович, — он посмотрел на Шрамова, — сможете встроить буфер причин в программу в ближайшие дни?
Шрамов молча записал задачу в тетрадь.
— Андрей Витальевич, — Морозов повернулся к Горелову. — Математика сошлась, можно фиксировать ядро. Готовьте ТЗ под ПЗУ-82В.
— Давно пора, — отозвался Горелов, уже прикидывая в уме объем необходимой памяти. — Вы мне тогда актуальную карту адресов напишите. Загрузчик, математика Громова, интерфейс Шрамова и этот ваш словарь причин. Если Громов свой модуль уплотнил до семи килобайт, мы гарантированно влезем в стандартный блок микросхем К573РФ2.
Морозов подошел к окну. Черное стекло отражало комнату 82В и мерцающий экран «Сферы».
— Юрий Павлович, — Морозов посмотрел на Шрамова через плечо. — Алгоритм работает. Теперь вам предстоит самая нудная часть. Завтра напишите, пожалуйста, все возможные варианты заводских отказов. Станция закрыта, кран занят, пути разобраны, состав не сформирован. Формулируете их коротким, сухим текстом. Чтобы к моменту сборки мастер-ПЗУ у нас лежал готовый словарь.
Шрамов придвинулся ближе к моноблоку и вывел на экран редактор кода.