Прогулка по лунолётам. 1 - Пролог

| рубрика «Программы» | автор st
Метки:

Все прогулки: первая, вторая, третья и четвёртая.

Хорошей программы должно быть много. Математика, вложенная более 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 регистров код ста с лишним строк программы на паскале.