В кабинете 82В рабочее место уже обросло бумагами. На сдвинутых столах лежали методичка по системным вызовам, несколько чистых бланков для будущей ведомости и закрытая серая папка.
Переданная группе машина стояла у края стола: широкий серый моноблок «Сферы-82» с массивным дисководом ИЗОТ, занявшим добрую треть свободного пространства. Рядом громоздился дисплей. На его темном экране мигало светлым курсором системное приглашение МикроДОС.
Шрамов сидел у клавиатуры, чуть подавшись вперед. Рядом лежал открытый блокнот с набросками строк ввода и пометками для печати.
— Машина свободна, — сказал он, придвигая к себе старую декабрьскую распечатку форматов, испещренную карандашными правками. — Давайте новую версию расчетного модуля, Евгений Александрович. Порядок входной строки поменялся? Моя программа чтения не споткнется?
Громов щелкнул замком портфеля. Достал несколько свежих листов, положил их на стол, а поверх аккуратно опустил дискету.
— Основные поля остались на прежних местах, — ответил Громов. — Код станции, тоннаж, тип вагона читаются как раньше. Но сама строка стала длиннее. После обычных данных я добавил позиции под занятые ресурсы и выделил байты для кодов причин — почему маршрут забракован или получил штраф.
Шрамов пробежал глазами по верхнему листу.
— Адреса сдвинулись на двенадцать байт, — констатировал он, прикидывая разметку. — Незанятые позиции забиты пробелами или нулями?
— Пробелами, по формату, — ответил Громов. — Расчетный модуль отдает только короткие числовые коды причин и штрафов. Превращать их в понятные строки для ведомости предстоит вам.
Шрамов кивнул, делая пометку на полях своей распечатки.
— Справочник причин я в структуру заложил, — произнес Шрамов. — Расчетный кусок остается изолированным, печать на мне. Порядок контрольных прогонов не меняем?
— Идем по нашему плану, — подтвердил Морозов. — Один набор данных гоняем тремя способами: по кратчайшему пути, первым подходящим вариантом и динамическим расчетом с отсечением ветвей. К каждому отклонению привязываем код причины. Тамаре Николаевне понадобится сравнительная ведомость, чтобы наглядно видеть разницу подходов на бумаге.
Шрамов взял у Громова дискету с модулем и вставил ее в щель накопителя ИЗОТ, опустив пластиковый рычаг. Механизм коротко загудел, раскручивая шпиндель. Шрамов запустил чтение в оперативную память, дождался остановки дисковода, вынул чужую дискету и вставил свою рабочую, чтобы сбросить порцию данных из буфера на магнитную дорожку.
Громов наблюдал за этой поочередной сменой с легким раздражением.
— С одним накопителем работать — сплошная морока, — проворчал он. — Нам нужна хотя бы одна машина с двумя дисководами. Элементарно чтобы программы копировать.
— Наладим сеть, — спокойно отозвался Морозов, — сможем перекидывать такие модули по кабелю между машинами. А пока придется потерпеть.
Завершив перенос, Шрамов вызвал на экран обновленную структуру программы.
— Откровенную бессмыслицу вроде несуществующих станций или отрицательного тоннажа я уже отсекаю, — сказал он, проверяя адреса. — Человек промахнулся мимо клавиши — ЭВМ вернула карточку на исправление. Нам сейчас важнее проверить те случаи, когда формально код правильный, математика сходится, а маршрут в итоге вредит предприятию.
Горелов согласно кивнул и достал карандаш.
— Точная граница, — сказал он. — Ошибка ввода — это вина оператора. А вот если расчет пройден, но состав запер маневровую бригаду — это дефицит правил. Техника отработала честно, подвела бедность модели. Эти ситуации должны оформляться совершенно разными сообщениями.
Ширяев придвинулся ближе и развязал тесемки серой картонной папки. Выложил на стол стопку карточек.
Громов взял карандаш Горелова и набросал на верхнем листе несколько кружков.
— Юрий Павлович, логика простая. Станция — это вершина. Перегон — ребро. Каждый переход получает цену. Гоним пустой состав — копим штраф за лишний километраж. Платформа не подходит под груз — оценка ухудшается. В память весь квадрат переходов мы не грузим, ОЗУ не вытянет.
Шрамов с сомнением посмотрел на схему.
— Как тогда модуль ищет маршрут?
— Входной массив формируется только из оперативной сводки: станция отправления, назначение, тип вагона, вес и срок. Код накладывает эти переменные на постоянную таблицу перегонов. Если накопленный штраф на текущей ветви превысил лучший найденный итог, ветвь отсекается сразу.
Ширяев отделил от пачки небольшую стопку и придвинул Шрамову.
— Проверим теорию на земле. Чистый набор. Пять станций, обычный уголь, стандартные платформы. Ремонт на одном перегоне учтен в правилах.
Шрамов быстро набрал цифровые индексы станций и параметры груза. Нажал клавишу ввода. Дисковод зашуршал, обращаясь к модулю Громова, и через секунду экран выдал плотную алфавитно-цифровую строку.
Громов пробежал глазами по символам.
— Ремонтный участок обошли, пробег минимальный. Расчет сошелся.
Ширяев выждал, пока строка на экране застынет, и достал из папки карточку с красной диагональной полосой.
— На гладком наборе и математика работает гладко, — сказал он. — А теперь добавим хозяйство. Введите вот это.
Шрамов взял картонку.
— Трансформатор тяжелый, прибытие через сорок минут на Б-12. Требует кран большой грузоподъемности.
Он набил новые параметры груза. Дисковод коротко щелкнул, подтягивая модуль Громова. Экран мигнул, выдавая обновленный расчет.
Ширяев подвел острие карандаша к мерцающим символам «КРАН_Б12_УГОЛЬ».
— Математически ваш маршрут безупречен, — констатировал он. — Вы экономите пробег. Но расчет только что отдал единственный тяжелый подъемный механизм под обычный уголь. А трансформатор оставил ждать. Обычный кран мы заменим. Этот — нет. Плюс резервный путь вы заняли под ожидание, а следом по графику идет литерный состав. На земле за такое снимают с дежурства.
Громов перестал улыбаться. Быстро прикинул в уме таблицу штрафов.
— Цена перегона была минимальной. Граф взвешен, программа честно отсекла длинные ветви.
Горелов сделал пометку в журнале.
— Это не отказ техники. Программа отработала заданные правила. У вас просто все механизмы равноценны.
— Баланс перекошен, — Громов с силой потер переносицу. — Ладно. Зададим тяжелому крану и запасному пути весовой коэффициент в сто раз выше обычного.
— Одними весами не отделаетесь, — возразил Морозов. — Однажды математическая выгода от короткого маршрута перекроет любой штраф. Машина выставит уголь перед литерным составом, просто потому что так сойдутся цифры.
Горелов поддержал:
— Занять кран — это хозяйственный спор. А чужой состав перед литерным — аварийная ситуация.
— Разделяем логику, — решил Морозов. — Для редких механизмов держим высокие штрафы. Для литерных вводим абсолютный запрет. Таблица переходов вообще не должна давать такой ход. Отсекаем ветвь до расчета, бережем такты процессора.
Шрамов постучал пальцем по пластиковому корпусу клавиатуры.
— Выходной массив Громова я заберу в свою программу, — деловито сообщил он. — Разобью табуляцией, выстрою колонки и подставлю маску путевого бланка. Но мне нужны понятные коды причин. Диспетчеру требуется печатный документ.
— Забирайте, Юрий Павлович, — спокойно согласился Громов. — Моя часть — выдать верные значения. Оформление за вами. А теперь прогоним для Тамары Николаевны три контрольных расчета на одних данных. Первый способ — кратчайший путь.
Он шагнул ближе и набрал директиву запуска.
Строка обновилась. Шрамов пробежал глазами по индексам.
— Пробег минимальный.
Ширяев наклонился к экрану.
— Идеальный. Только без учета ремонтов этот расчет гонит состав прямиком на снятые рельсы.
Пальцы Шрамова снова легли на клавиши.
— Второй способ. Берем первый подходящий путь.
Символы на дисплее дернулись и сменились новым набором. Ширяев покачал головой.
— Сначала выглядит здраво. А на третьем шаге забивает резервную ветку, и весь узел встает.
— Теперь динамический расчет с отсечением плохих ветвей, — скомандовал Громов.
Очередной прогон вывел на экран третий вариант маршрута.
— Этот тупики обходит, — произнес Ширяев. — Но, как мы уже видели, забирает тяжелый кран под уголь. Хозяйственная бессмыслица.
Громов крепко сжал подбородок.
— Значит, я могу поднять штраф на тяжелый механизм, но тогда расчет потащит уголь в обход всего узла.
Ширяев выложил поверх распечаток еще три картонные карточки и карандашную схему.
— Веса вас не спасут. Смотрите на живую работу. Введите вот этот короткий и экономный обход.
Шрамов молча набил шифры станций. Машина выдала время прибытия.
— Половина восьмого утра, — прочитал Громов. — Перегон свободен.
— Он свободный для ночного транзита, — парировал Ширяев. — А в половине восьмого там пересменка и массовая подача вагонов в цеха. Горловина забита намертво. Ваш экономный состав встанет поперек путей и сломает сменный ритм.
Он придвинул следующую карточку.
— Теперь лес. Четыре состава через второстепенную ветку. С интервалом в час. Вводите.
Шрамов запустил расчет серии. Программа выдала аккуратный столбец одинаковых маршрутов.
— Ветка же пустая, — сверил данные Громов.
— На ней всего два приемо-отправочных пути, — сухо ответил Ширяев. — Машина берет задачи поштучно. Первый состав встал под разгрузку, второй ждет, третий застревает на стрелке, четвертый блокирует выход с соседней станции. Программа не видит накопления вагонов за смену.
Он нарисовал на полях схемы длинный зигзаг.
— И третья ситуация. Обход закрытого на ремонт участка. Запускайте.
Результат на экране показал сложную цепочку станций.
— Формально допустимо, — сказал Ширяев, разглядывая вывод. — Но чтобы состав так прошел, маневровой бригаде придется четыре раза отцеплять вагоны, перетягивать их вытяжным локомотивом и менять направление. Люди физически не сделают столько перестановок за смену. Выдохнутся на втором маневре.
Горелов аккуратно прочертил в своем блокноте новую колонку.
— Вот это уже можно разложить по полочкам. Аппаратура исправна. Ввод верный. А маршрут ведет к затору. Модель неполна.
Морозов оперся руками о край столешницы.
— Придется вводить искусственные узлы графа для режимов работы. Временные окна для горловин. Горизонт смены. И штраф за излишнюю дробность — ограничение числа маневров.
Громов покачал головой.
Полный квадрат станций с учетом времени мгновенно убьет память, Алексей Николаевич. Процессор-то восьмиразрядный. Значительную долю ОЗУ уже держит МикроДОС, буферы дисковода, программа ввода и проверка кодов. Загрузите туда матрицу с временными окнами, где половина перегонов не существует в природе — не останется места для расчетов. И никакой дробной арифметики. Только целые числа.
— Храним сеть не квадратом, а плоским списком реальных перегонов, — напомнил Морозов. — Не раздувай граф. Добавь отдельную таблицу строгих запретов. Наступило утро — перегон закрыт запретом, а не весовым коэффициентом.
Шрамов подался вперед.
— Если маршрут строится, но требует невыполнимых маневров или лезет в пересменку, я не выведу оператору голый шифр. Мне нужны текстовые пояснения. Превышение маневров, конфликт расписания, очередь на второстепенной ветке.
— Именно так, — согласился Горелов. — Программа печатает предупреждение, а окончательное решение принимает человек.
Шрамов проверил отступы в своей части кода, убедился, что текстовые колонки встанут ровно, и отправил сформированную ведомость на АЦПУ. Устройство с громким треском выбило итоговые строки на широкой бумаге.
Громов оторвал перфорированный лист и провел ногтем по напечатанным столбцам.
— Тамаре Николаевне отнесем именно это. Три способа рядом, и сразу видно, где каждый ломается. Кратчайший путь устроил аварию и влез в утреннюю пересменку, первый подходящий заблокировал перегон и собрал очередь, а расчет с отсечением забрал нужный механизм и потребовал невыполнимых маневров. Это уже не разговор на словах, а проверочный пример: один набор данных, три ответа и причины отказа на бумаге.
Ширяев положил рядом с клавиатурой плотную стопку перевязанных суровой ниткой карточек.
— А теперь сменный объем, — сказал он. — Здесь полсотни маршрутов. Ночная смена, половина третьего. Диспетчер набивает данные не по одной штуке, а сплошным потоком.
Он вытянул из середины карточку с потекшими от влаги синими чернилами и положил поверх стопки.
— Уголь ждут на разгрузку на Б-12. Но человек устал, освещение тусклое. Он читает эту кляксу и вбивает В-12.
Шрамов внимательно посмотрел на расплывшиеся буквы.
— Если кода нет в справочнике узла, программа забракует ввод и вернет строку на исправление. Несуществующие шифры я отлавливаю сразу.
— Станция В-12 существует, — уточнил Ширяев. — Небольшая сортировочная горловина севернее кольца. Шифр рабочий. Программа его пропустит.
Горелов перестал крутить в руках карандаш и постучал тупым концом по столешнице.
— Получается скверная картина. Вычислительный блок получает формально допустимые координаты. Расчетный модуль строит математически идеальный маршрут для ошибочного пункта назначения.
Шрамов перевел взгляд со стопки картона на мерцающий экран. Построчный контроль здесь не спасал. Если отдавать массив в расчет сразу после ввода, искаженная координата уйдет в работу.
— Значит, рвем прямую передачу массива, — Шрамов придвинул к себе чистый лист и быстро набросал сетку колонок. — Делаем накопительную таблицу. Диспетчер набивает шифр, а программа вытаскивает из словаря полное русское название и ставит рядом.
Он вписал несколько слов в нарисованные ячейки.
— Человек ввел В-12 — на экране загорелось «Воронцово». Ввел Б-12 — появилось «Быково». Строки собираются в общий список.
Морозов посмотрел на карандашную схему.
— Визуальная сверка всего пакета перед расчетом.
— Да, — подтвердил Шрамов. — В модуль Евгения Александровича данные уходят только после явного подтверждения. Оператор просматривает колонку с русскими названиями, сверяет со своими бумагами и нажимает клавишу подтверждения. До этого момента математика ждет.
Горелов забрал у Шрамова лист и провел жирную вертикальную черту, отделяя набросок от свободного пространства.
— Раз мы заговорили об ответственности, давайте разделим виды производственного брака, — сказал Горелов и поставил на бумаге единицу. — Первое — отказ аппаратуры. Сбой памяти, остановка дисковода, скачок напряжения. Тут картина простая: техника встала, процесс прерван. Второе — человеческая ошибка. Оператор вбил несуществующий код или промахнулся по клавишам. Программа на это должна отвечать понятной строкой на экране. Никаких служебных кодов и адресов памяти, в которых разбираются только программисты. Просто и по-русски: «Проверь станцию назначения».
Шрамов сделал пометку на полях своей схемы.
— Текстовые подсказки съедят некоторое место на дискете, но оперативную память мы не перегрузим. Будем подгружать их с диска только в момент ошибки.
— И третье, — Горелов аккуратно подчеркнул последнее словосочетание. — Опасная неполнота правил. Расчет выполнен, маршрут найден, но он цепляет границу дозволенного. Занят тяжелый механизм, перекрыт резервный путь перед прохождением особого состава. Здесь программа выводит предупреждение, и человек решает — пускать эшелон или искать обходной вариант.
Громов подался вперед, опираясь локтями о стол.
— Чтобы человек взял на себя такую ответственность, ему нужно видеть цену обходного варианта, — произнес Громов.
— Значит, выводим на бумагу, — подытожил Шрамов. — Прогоняем одну пачку карточек тремя способами. Сначала смотрим на экран, убеждаемся, что сообщения читаются нормально, а потом бьем ведомость на АЦПУ. Нам все равно нужен контрольный пример для сравнения.
Они потратили около часа на подготовку сводного прогона. Малая машина мерно гудела, перебирая переходы для пяти тестовых станций. Шрамов сидел у клавиатуры, старательно высчитывая отступы, чтобы длинные названия перегонов ложились в ровную колонку.
— Строки не плывут, все уместилось, — доложил он, отрываясь от экрана. — Пускаю на печать.
Широкая каретка АЦПУ ожила с тяжелым металлическим лязгом. Молоточки ударили по красящей ленте, наполняя комнату ритмичным треском. Свести три подхода в единый документ оказалось непросто. Слева ложились цифры кратчайшего пути, по центру шел метод простого захвата ближайших свободных ресурсов, а справа печатался сложный расчет с отсечением тупиковых ветвей.
Громов оторвал бумажную ведомость по линии перфорации, стряхнул пыль и расстелил лист поверх карандашных схем.
— Смотрите, — он провел ногтем по правой колонке. — Расчет математически безупречен, но рядом вывелась текстовая приписка: «Тяжелый подъемный механизм занят».
Ширяев склонился над соседними столбцами.
— А простой путь вообще загнал вагоны прямо в зону ремонта. Зато доложил, что вышло очень быстро.
Громов хмыкнул, рассматривая ровные ряды символов.
— Забавно. В декабре эта сложная математика вытащила нас на комиссии. А сегодня красивый алгоритм споткнулся о подъемник на скромной станции Б-12.
— Дело совершенно не в подъемнике, Евгений Александрович, — Ширяев аккуратно собрал картонные карточки и стянул их бечевкой. — Вы вплотную столкнулись с реальностью живого предприятия.
В дальнем углу кабинета скрипнул стул. Тамара Николаевна, до этого молча работавшая с документами, поднялась и подошла к рабочему столу. Здесь, в режимном помещении, она находилась на своей территории, где инженеры-разработчики были лишь гостями с допуском. Ее взгляд, привыкший мгновенно выхватывать производственную суть из любых бумаг, сразу остановился на свежей распечатке.
Егорова уверенно протянула руку и взяла край перфорированного листа.
— Это мне?
Громов неуловимо подобрался, спина стала заметно прямее.
— Черновик, — ответил он, убирая руку от края широкой ведомости. — Три способа расчета на одном наборе данных. Завтра подготовлю чистовой вариант со своими пояснениями по каждой спорной позиции.
Егорова пробежала глазами выровненные колонки. Она читала распечатку молча, быстро пробираясь сквозь сплетение цифр и сокращений. На секунду ее взгляд задержался на строке с кодировкой занятого механизма.
— Отдельные пояснения к делу не подошьешь, Евгений Александрович, — произнесла она без малейшего нажима, но с абсолютной профессиональной непреклонностью. — В таком виде я документ не пропущу. Причина каждого отказа или предупреждения должна быть напечатана прямо здесь, русскими буквами. И эта строка обязана дословно совпадать с тем, что оператор видел на экране перед запуском эшелона. Никаких устных оправданий постфактум. Если маршрут отвергнут, проверяемое основание остается в распечатке навсегда, чтобы любой контролер мог поднять бумагу из архива через год.
Громов выдержал этот спокойный, внимательный взгляд.
— Понял. Значит, текстовая причина станет обязательной частью ведомости.
Егорова коротко кивнула, забрала черновик и вернулась к своему столу.
В комнате 82В повисла короткая тишина, нарушаемая только тихим шелестом бумаги на столе.
Шрамов откинулся на спинку стула и криво усмехнулся.
— Все-таки робеешь перед ней?
Громов взял оставленный лист, тщательно выровнял его по краю столешницы, собирая бумаги в аккуратную стопку.
— Учусь выживать в естественной производственной среде, Юрий Павлович, — отозвался он, не поднимая глаз от текста. — Она просматривает бумагу внимательнее, чем самый строгий транслятор ищет синтаксис в коде. С ней нельзя договориться обаянием или ссылками на передовой алгоритм.
Морозов перевел взгляд с вороха бумаг на представителя заказчика.
— Павел Андреевич, нам потребуются еще реальные карточки. Желательно парочку типовых сменных раскладов. И обязательно один узел с острым дефицитом путей.
Ширяев сунул свою потертую картонную папку глубоко под мышку.
— Сделаем. Я подготовлю вам такую задачу, где программе придется предложить обход в три раза длиннее, чтобы намертво не заблокировать узловую горловину маневровым составом. Путь выйдет долгим, но хозяйственно самым верным.
Громов тихо фыркнул, пододвигая к себе исписанный лист со сложными формулами.
— Длиннее, но вернее. Звучит как прямое издевательство над математикой. Придется заново переписывать все весовые коэффициенты.