You are here
Прогулка по лунолётам. 1 - Пролог
Все прогулки: первая, вторая, третья и четвёртая.
Хорошей программы должно быть много. Математика, вложенная более 25 лет назад в маломощные ПМК Михаилом Пуховым, настолько привлекательна своей простотой и реализмом (за это спасибо консультанту журнала, космонавту, Герою СССР Ю.Н. Глазкову), что несомненно может стать основой игр и симуляторов на любых платформах.
Прежде всего, для повторного использования алгоритм надо привести в понятный человеку и максимально наглядный вид. Код программ для ПМК таковым не является. Тем более, оригинальный код "Лунолетов".
Надо отдать авторам должное: степень достигнутого сжатия так высока, что восстановление алгоритма из кода оказывается делом весьма непростым. Даже для владеющего программированием на ПМК, понимающего использованные трюки, а не просто "знакомого с основами". Очень непростым. После трех часов "раскрутки" я пришел к выводу о нерациональности такого подхода ввиду наличия блок-схемы для "Лунолет-2". Для "Лунолет-1" она практически идентична, лишь следует исключить из рассмотрения ввод угла вектора тяги и расчет горизонтальной скорости.
Повторно выражая через десятилетия авторам "Лунолет-1" и "2" свое уважение, но оставаясь верным долгу профессии вынужден сказать, что программы эти являются своего рода "анти-образцом". То есть примером того, как не надо писать программы. Если, конечно, вы хотите их в дальнейшем изменять, переносить, передавать на сопровождение другим людям. Не надо, за исключением крайних случаев. Например, когда нужно втиснуть алгоритм в злосчастные 98 шагов (байтов) программной памяти и 14 регистров.
При этом само собой подразумевается, что "как надо писать" вы знаете хорошо и на исключение идете осознанно, как Коршунов - к перелету на "Кон-тики". Если будете писать программы для МК-152/161 - никогда не следуйте стилю авторов, если на то нет особых причин. У программистов подобный стиль издавна называется "тарелка спагетти". Как правило, затраты на модификацию такой программы выше, чем на её полное переписывание.
Однако, и блок-схема не блещет структурностью. Блоки начала и конца отсутствуют. Цепочка сравнений, из которых две стрелки в итоге попадают в один блок ввода-вывода - тоже "тяжелое наследие доструктурной эпохи". Но всё-равно, это гораздо лучше "тарелки спагетти".
В итоге, текст программы на FreePascal, объединяющей оба лунолёта, может выглядеть как на листинге ниже.
А мы перейдем к реализации модели на ПМК семейства HP 50/49/48.
program lunar_ship_1; {$mode objfpc}{$H+} uses Math; var h_i, // altitude - vertical coordinate, m - current and next x_i, // longitude - horizontal coordinate, m v_i, // horizontal velocity, m/sec u_i, // rate of climb, vertical velocity, m/sec mf_i, // mass (amount) of the fuel, kg ms, // mass of the ship without fuel, kg a_lim, // acceleration limit, m/sec2 // In-flight maneuver: d_mf, // fuel consumption, kg t, // time, sec ac, // angle of climb, degrees; is always 0 for vertical flight mode g, // acceleration of gravity, m/sec2 nf, // nozzle flow, m/sec ls, // life support, sec a, // current acceleration q // fuel consumption by time : real; FlightMode : cardinal = 1; WillReverseOfControl: boolean = false; WillQuitProgram : boolean = false; procedure DoStep; var v_i1, u_i1: real; begin repeat v_i1 := v_i; u_i1 := u_i; v_i := v_i + a * t * sin(ac); x_i := x_i + (v_i1 + v_i) / 2 * t; u_i := u_i + (a * cos(ac) - g) * t; h_i := h_i + (u_i1 + u_i) / 2 * t; mf_i := mf_i - q * t; ls := ls - t; if mf_i < 0 then t := mf_i / q; until mf_i >= 0; end; procedure OutInfo; begin writeln('-------------------------------------------'); writeln('Altitude : ', h_i:10:2, ' m'); if FlightMode = 2 then begin writeln('Longitude : ', x_i:10:2, ' m'); writeln('Velocity (horizontal): ', v_i:10:2, ' m/sec'); end; writeln('Velocity (vertical) : ', u_i:10:2, ' m/sec'); writeln('Fuel : ', mf_i:10:0, ' kg'); writeln('Life support : ', ls:10:0, ' sec'); writeln('-------------------------------------------'); end; procedure EnterManeuver( out WillReverseOfControl: boolean; out WillQuitProgram : boolean); begin repeat writeln('Enter in-flight maneuver'); write('Fuel consumption, kg: '); readln(d_mf); WillQuitProgram := d_mf < 0; if WillQuitProgram then exit; write('Time, sec : '); readln(t); if FlightMode <> 2 then ac := 0 else begin write('Climb angle, ° : '); readln(ac); ac := DegToRad(ac); end; until t <> 0; WillReverseOfControl := t < 0; t := abs(t); end; procedure CalcAcceleration(WillReverseOfControl: boolean); begin q := d_mf / t; a := q * nf / (ms + mf_i); if WillReverseOfControl then begin a := -a; WillReverseOfControl := false; end; end; begin writeln('Lunar ship simple simulator'); writeln('(c) 1985 "Lunolet-1", "Lunilet-2" by Mikhail PUKHOV, USSR'); writeln('(c) 2011 Serguei TARASSOV, pmk.arbinada.com'); writeln; writeln('Enter simulator mode:'); writeln(' 1 - "Lunolet-1" - vertical flight only'); writeln(' 2 - "Lunolet-2" - vertical and horizontal flight (2-dimensional)'); readln(FlightMode); writeln('Enter negative fuel consumption value to quit the program'); g := 1.62; // 1,62 m/sec2 for Lune ms := 2250; nf := 3660; a := 0; a_lim := 3 * 9.81; // "3g" v_i := 0; u_i := 0; h_i := 0; x_i := 0; mf_i := 400; ls := 3600; repeat if h_i < 0 then begin t := 2 * h_i / (sqrt(sqr(u_i) + 2 * h_i * (g - a * cos(ac))) - u_i); end else begin if (h_i = 0) or ((a < a_lim) and (mf_i <> 0)) then begin OutInfo; EnterManeuver(WillReverseOfControl, WillQuitProgram); if WillQuitProgram then break; CalcAcceleration(WillReverseOfControl); writeln('Acceleration: ', a:8:2, ' m/sec2'); end else begin d_mf := 0; if not (a < a_lim) then begin writeln('!!! Acceleration exceeded'); t := a - a_lim; writeln('Waiting ', t:5:1, ' sec'); end; if mf_i <= 0 then begin writeln('!!! Fuel exceeded'); t := nf; end; CalcAcceleration(false); end; end; DoStep; until WillQuitProgram; end.
Теперь протестируем полёт Александра Перепёлкина и убедимся, что симулятор работает.
------------------------------------------- Altitude : 0.00 m Velocity (vertical) : 0.00 m/sec Fuel : 400 kg Life support : 3600 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 65 Time, sec : 3 Acceleration: 29.92 m/sec2 !!! Acceleration exceeded Waiting 0.5 sec ------------------------------------------- Altitude : 169.16 m Velocity (vertical) : 84.11 m/sec Fuel : 335 kg Life support : 3597 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 0 Time, sec : 2 Acceleration: 0.00 m/sec2 ------------------------------------------- Altitude : 334.15 m Velocity (vertical) : 80.87 m/sec Fuel : 335 kg Life support : 3595 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 65 Time, sec : 3 Acceleration: 30.68 m/sec2 !!! Acceleration exceeded Waiting 1.2 sec ------------------------------------------- Altitude : 915.81 m Velocity (vertical) : 166.02 m/sec Fuel : 270 kg Life support : 3590 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 0 Time, sec : 120 Acceleration: 0.00 m/sec2 ------------------------------------------- Altitude : 9174.60 m Velocity (vertical) : -28.38 m/sec Fuel : 270 kg Life support : 3470 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 25 Time, sec : 2 Acceleration: 18.15 m/sec2 ------------------------------------------- Altitude : 9150.92 m Velocity (vertical) : 4.69 m/sec Fuel : 245 kg Life support : 3468 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 10 Time, sec : -10 Acceleration: -1.47 m/sec2 ------------------------------------------- Altitude : 9043.50 m Velocity (vertical) : -26.18 m/sec Fuel : 235 kg Life support : 3458 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 25 Time, sec : 5 Acceleration: 7.36 m/sec2 ------------------------------------------- Altitude : 8984.42 m Velocity (vertical) : 2.54 m/sec Fuel : 210 kg Life support : 3453 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 0 Time, sec : 90 Acceleration: 0.00 m/sec2 ------------------------------------------- Altitude : 2652.42 m Velocity (vertical) : -143.26 m/sec Fuel : 210 kg Life support : 3363 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 100 Time, sec : 3 Acceleration: 49.59 m/sec2 !!! Acceleration exceeded Waiting 20.2 sec ------------------------------------------- Altitude : 2122.62 m Velocity (vertical) : -32.00 m/sec Fuel : 110 kg Life support : 3340 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 10 Time, sec : 20 Acceleration: 0.78 m/sec2 ------------------------------------------- Altitude : 1313.70 m Velocity (vertical) : -48.89 m/sec Fuel : 100 kg Life support : 3320 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 10 Time, sec : 15 Acceleration: 1.04 m/sec2 ------------------------------------------- Altitude : 514.89 m Velocity (vertical) : -57.62 m/sec Fuel : 90 kg Life support : 3305 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 35 Time, sec : 1.5 Acceleration: 36.50 m/sec2 !!! Acceleration exceeded Waiting 7.1 sec ------------------------------------------- Altitude : 389.79 m Velocity (vertical) : -16.75 m/sec Fuel : 55 kg Life support : 3297 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 22 Time, sec : 22 Acceleration: 1.59 m/sec2 ------------------------------------------- Altitude : 13.51 m Velocity (vertical) : -17.46 m/sec Fuel : 33 kg Life support : 3275 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 22 Time, sec : 0.7 Acceleration: 50.38 m/sec2 !!! Acceleration exceeded Waiting 21.0 sec ------------------------------------------- Altitude : 7.05 m Velocity (vertical) : -17.27 m/sec Fuel : 11 kg Life support : 3253 sec ------------------------------------------- Enter in-flight maneuver Fuel consumption, kg: 22 Time, sec : 0.7 Acceleration: 50.88 m/sec2 !!! Acceleration exceeded Waiting 21.4 sec ------------------------------------------- Altitude : 0.00 m Velocity (vertical) : -3.61 m/sec Fuel : 0 kg Life support : 3250 sec -------------------------------------------
Как видно из протокола, Перепёлкину снова удалось на последних каплях керосина посадить лунолёт, собранный спустя 25 лет по той же схеме, но новыми средствами.
Ну, а читателю можно в третий раз напомнить о квалификации авторов, сумевших сжать (хоть и с потерей сервиса) до 98 байтов и 15 регистров код ста с лишним строк программы на паскале.
Комментарии
Лунолёты - это
Лунолёты - это конечно классика, но при наличии более совершенного оборудования можно уточнить и саму математику лунолётов. Например при маневрировании вместо равноускоренного движения использовать движение с постоянной тягой и переменной массой. Скорость рассчитывается по формуле Циолковского, для координаты эту формулу можно проинтегритровать по времени, а для ускорения - продифференцировать. Сложнее с ускорением Кориолиса. В принципе, я это уже делал когда-то под кэсио вот здесь: http://pmk.arbinada.com/node/838
Мои программируемые калькуляторы:
Б3-21, Б3-34, МК-61, МК-52, МК-85
CASIO: cfx-9850GB+, fx-9750G+, fx-9750GII, fx-9860G, Algebra fx-2.0, fx-5800P, fx-7400G+
HP: 50G, 48G, 35s
TI: Nspire-CAS, Voyage-200, 89Titanium
SHARP EL-9600G
Ценное
Ценное замечание, ведь от уточнения алгоритма внешняя простота симулятора не изменится.
Посмотрим теперь, на что способен User RPL в плане наглядности :) После изучения возможностей SysRPL, стало ясно, что без особых причин лучше его не использовать.
Совпало с
Совпало с точностью до сотых с посадкой на мк-161 :) У меня -3.6111959 касание :) http://msvk40.livejournal.com/19580.html
Предлагаю
Предлагаю перейти в динамику, благо там можно и в стиле Перпёлкина вертикальные полёты с посадкой в ту же точку совершать. А то пошаговое прохождение с правом подумать неопределённо долго - неспортивно :)
http://pmk.arbinada.com/node/716
Однако в
Однако в лунолётах система управления тягой была другая (4-я степень толкинутости - "Нет ребята, всё было не так" :) Плавного управления тягой не было, а было именно три рычага: "угол", "топливо", "время" и кнопка "пуск". При этом настройки нового манёвра можно ввести в ходе исполнения текущего, а по окончании только нажать "пуск". Поэтому придуманный автором этой версии интерфейс не соответствует описанию моделируемого объекта.
Мои программируемые калькуляторы:
Б3-21, Б3-34, МК-61, МК-52, МК-85
CASIO: cfx-9850GB+, fx-9750G+, fx-9750GII, fx-9860G, Algebra fx-2.0, fx-5800P, fx-7400G+
HP: 50G, 48G, 35s
TI: Nspire-CAS, Voyage-200, 89Titanium
SHARP EL-9600G
Так-то, конечно,
Так-то, конечно, да. Но вот смог бы реальный пилот на реальном лунолете управляться с таким трехрычажным "пользовательским интерфейсом" в реальном времени?
Вопрос
Вопрос привычки и тренировки. И кроме того - этот интерфейс описан в первоисточнике. В автомобиле ведь на 2 ноги 3 педали приходится, если коробка - не автомат.
Мои программируемые калькуляторы:
Б3-21, Б3-34, МК-61, МК-52, МК-85
CASIO: cfx-9850GB+, fx-9750G+, fx-9750GII, fx-9860G, Algebra fx-2.0, fx-5800P, fx-7400G+
HP: 50G, 48G, 35s
TI: Nspire-CAS, Voyage-200, 89Titanium
SHARP EL-9600G
Модификация
Модификация управления, когда вместо расхода топлива и времени может задаваться тяга, обсуждалась на разборе полётов в КЭИ (см. "Техника молодежи" №5 за 1986). Там прямо говорится, что, цитирую, "такой ввод может оказаться особенно полезным при постановке игры на персональном компьютере в реальном масштабе времени". Такое управление более близко к реальному.
Подумалось, что
Подумалось, что такой замечательный материал можно было выложить в "eReader-friendly" форматах, одним файлом. Например, в .PDF, .FB2, .MOBI(.PRC) и .EPUB
Чтобы можно было бы скачивать и читать в оффлайнах.
А какой конкретно материал
А какой конкретно материал и в какой компоновке имеет смысл выкладывать? Экспорт отдельных страниц в printer-friendly форматах можно прикрутить без проблем.
Ну, хотя-бы
Ну, хотя-бы "Прогулка по лунолётам, части 1 - 4". Я сейчас руками скопипастил себе в один файл и в буклет-книжечку на цветном лазере :)
Хорошо
Хорошо, надо попробовать сделать то же в опенофисном формате и экспортировать в FB2.ZIP
В тексте
В тексте программы на Pascal ошибка.
При работе с программой по варианту "Лунолет-2" значение угла не будет обсчитываться в градусах.
Функция sin(x) в Pascal принимает аргумент в радианах. Т.е. для получения корректных результатов необходимо преобразовывать введенное значение градсной меры угла в радианы.
Правильный фрагмент процедуры EnterManeuver:
write('Climb angle, ° : '); readln(ac);
ac := ac * (3.1415926535 * 180); // <== перевод в радианы !!
Да, нужен
Да, нужен перевод в градусы (в Math есть функция), спасибо за вычитку!
Ошибка в Лунолет-1 36-летней давности?
Доброе время суток!
Недавно захотел поностальгировать, загрузил на свой мк-52 Лунолет-1 и обратил внимание на алгоритм контроля ресурса жизнеобеспечения, которое хранится в регистре С. Как я понял, контроль производится по адресам 75-80 оригинальной программы, опубликованной в ТМ за 06/1985. Выглядит это так:
В стек вызывается регистр ПС, П2 и П0, П2 умножается на П0, результат вычитается из ПС и заносится обратно в ПС. В регистре П2, как я понял, находится время маневра в секундах, а вот что находится в регистре П0, и зачем его умножать на П2 я так и не понял. Я не нашел никакого обращения в программе к этому регистру. Ну и после ввода данных, естественно, что в этом регистре находится 0 который, при умножении на П2, дает тоже 0 и в результате никакого изменения регистра ПС не происходит. Я не очень понял, во-первых, как такая ошибка появилась и до сих пор не была замечена (я нашел, что в варианте для DM42 она тоже присутствует - https://pmk.arbinada.com/ru/node/1322, команды 80-85), или я все-же что то недопонял? В любом случае я бы предложил либо вообще убрать эту часть, либо ее исправить, например так:
Т.е каждый раз из регистра жизнеобеспечения будет вычитаться время маневра и сохраняться его новое значение и если это значение меньше нуля, программа перейдет на индикацию ошибки и останов программы. Что вы думаете по этому поводу?
В описании оригинальной
В описании оригинальной программы назначение регистра 0 было так описано:
https://epizodyspace.ru/bibl/tehnika_-_molodyoji/1985/6/put.html
Ясно
Ясно, вот этот момент я пропустил, спасибо. Но получается что в оригинальной версии превышение этого времени никак не отражалось на игре. Типа превысили и превысили, летим дальше. Как вы это прокомментируете?
Не только это
Вы многое пропустили. Например, в начале следующего заседания Клуба замеченная вами в «Лунолёте-1» последовательность команд используется для новой электронной игры:
https://epizodyspace.ru/bibl/tehnika_-_molodyoji/1985/7/put.html
Пожелаю вам на Новый 2022 год внимательности! :-)
Быть внимательным
Спасибо за пожелание быть внимательным! Думаю очень пригодится не только мне и не только в новом году :)
Ну а на то, что регистр С и регистр 0 стал использоваться уже по другому назначению, а именно для задания расстояния до точки посадки и горизонтальной скорости, я уже знал, если честно :) Мне хотелось обратить внимание именно на реалистичность поведения Лунолет-1. Согласитесь, как-то не очень реалистично, когда ресурс жизнеобеспечения вышел, а в игре ничего не происходит.
Регистр С
RC это простейший таймер на пульте, независимый от основной системы «Лунолёта-1» — как электронные часы на белорусской плите Гефест. В основной игре он тикает вперёд или назад. На него можно посмотреть, чтобы принять решение.
Но если таймер своё оттикал, а пилот всё ещё жив — радоваться надо. :-) Для пассажиров или груза, правда, всё может быть печальным.
Это не
"Это не баг, это фича" (ц) :)