                     Решения задач
                     -------------

6.2.1. Задача 1 (5 баллов)
Средний бал решений: 3.7 (73%)

 Введем следующее определение:
Определение
-----------
<число> ::= <целое> | <дробь>
<целое> ::= <цифра> | <целое><цифра>
<дробь> ::= <простая> | <десятичная>
<простая> ::= <целое>/<целое>
<десятичная> ::= .<целое> | <целое>. | <целое>.<целое>
<цифра> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

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

   Примеры работы программы:

Начальное состояние                 После работы программы
┬─┬─╦═╦─┬─┬─┬─┬─┬─┬─┐               ┬─┬─┬─┬─┬─┬─╦═╦─┬─┬─┐
│░│░║░║1│2│7│░│░│░│░│    ─────>     │░│░│░│1│2│7║░║ц│л│░│
┴─┴─╩═╩─┴─┴─┴─┴─┴─┴─┘               ┴─┴─┴─┴─┴─┴─╩═╩─┴─┴─┘

Начальное состояние                 После работы программы
┬─┬─╦═╦─┬─┬─┬─┬─┬─┬─┐               ┬─┬─┬─┬─╦═╦─┬─┬─┬─┬─┐
│░│░║░║1│!│9│░│░│░│░│    ─────>     │░│░│░│1║!║9│░│о│ш│░│
┴─┴─╩═╩─┴─┴─┴─┴─┴─┴─┘               ┴─┴─┴─┴─╩═╩─┴─┴─┴─┴─┘

Решение

   Диаграмма переходов  изображена  на рисунке. Слова в круглых
скобках обозначают состояния алгоритма.
   Схема читается следующим образом.  Исходным  является состо-
яние (вход).  На  каждом  шаге просматривается следующий символ
записи, и, в зависимости от  его  типа,  движение происходит по
соответствующей стрелке.
   Пусть, например, алгоритм обрабатывает запись "12.7".
   В состоянии (вход) смотрим на символ "1". Это цифра, перехо-
дим в состояние (целое).
   В состоянии (целое)  смотрим на символ "2". Это цифра, оста-
емся в прежнем состоянии. Следующий  символ  ".".  Переходим  в
состояние (десятичная).
   В состоянии (десятичная)  смотрим  на символ "7". Это цифра,
остаемся в прежнем состоянии. Следующий символ ПУСТО. Переходим
в состояние (ответ_десятичная).
   В состоянии  (ответ_десятичная)  формируем запись "дс" и за-
канчиваем работу.

      (ответ_целое)    (ошибка)
          ^             ^ ^
          │  остальное  │ │
    пусто │ ┌───────────┘ │ остальное
          │ │             │
          │ │     цифра   │      .                   остальное
  ┌──── (целое) <───────(вход)───────>(десятичная?) ───────────>(ошибка)
  │      ^ │  │                            │
  │      │ │  │ .                 цифра    │
  │цифра │ │  └──────┐          ┌──────┐   │цифра
  └──────┘ │         │          │      │   │
           │ /       │          │      V   V          остальное
           │         │          └──── (десятичная) ─────────────>(ошибка)
           │         │                  ^     │
           │         └──────────────────┘     │
           V       остальное                  │пусто
       (простая?)────────────>(ошибка)        │
           │                                  V
 цифра     │                          (ответ_десятичная)
┌───────┐  │цифра
│       │  │
│       V  V      остальное
└──── (простая)  ───────────>(ошибка)
           │
           │ пусто
           │
           V
     (ответ_простая)


  Описание состояний.

   В каждом  состоянии анализируется следующий символ записи и,
в зависимости от его значения, принимается решение о переходе в
новое состояние.

   (вход)
   Это состояние входное для алгоритма.
   Алгоритм анализирует первый символ записи.
   Если символ - цифра, алгоритм переходит в состояние (целое).
   Если точка - в состояние (десятичное?).
   Любой другой символ - переход в состояние (ошибка).

   (целое)
   Алгоритм анализирует очередной символ записи.
   Если символ - цифра, алгоритм остается в состоянии (целое)
   Если символ - "/", алгоритм переходит в состояние (простая?)
   Если символ - ".", алгоритм переходит в состояние (десятичная)
   Если символ - пусто, алгоритм переходит в состояние (ответ_целое)
   Любой другой символ - переход в состояние (ошибка).

   (простая?)
   Алгоритм анализирует следующий за "/" символ записи.
   Если символ - цифра, алгоритм переходит в состоянии (простая)
   При любом другом символе - в состояние (ошибка)

   (простая)
   Алгоритм анализирует очередной символ записи.
   Если символ - цифра, алгоритм остается в состоянии (простая)
   Если символ - пусто, алгоритм переходит в состояние (ответ_простая)
   Любой другой символ - переход в состояние (ошибка).

   (десятичная?)
   Алгоритм анализирует второй символ записи, следующий за ".".
   Если символ - цифра, алгоритм переходит в состоянии (десятичная)
   При любом другом символе - в состояние (ошибка)

   (десятичная)
   Алгоритм анализирует очередной символ записи.
   Если символ - цифра, алгоритм остается в состоянии (десятичная)
   Если символ - пусто, алгоритм переходит в состояние (ответ_десятичная)
   Любой другой символ - переход в состояние (ошибка).

Программа

ЭТО вход
 ВПРАВО
 ЕСЛИ       ЦИФРА ТО целое
 ИНАЧЕ ЕСЛИ .     ТО десятичная?
 ИНАЧЕ ошибка
КОНЕЦ

ЭТО целое
  ВПРАВО
  ЕСЛИ       ПУСТО  ТО ответ_целое
  ИНАЧЕ ЕСЛИ ЦИФРА  ТО целое
  ИНАЧЕ ЕСЛИ .      ТО десятичная
  ИНАЧЕ ЕСЛИ /      ТО простая?
  ИНАЧЕ ошибка
КОНЕЦ

ЭТО десятичная?
  ВПРАВО
  ЕСЛИ ЦИФРА ТО десятичная
  ИНАЧЕ ошибка
КОНЕЦ

ЭТО десятичная
  ВПРАВО
  ЕСЛИ ПУСТО       ТО ответ_десятичная
  ИНАЧЕ ЕСЛИ ЦИФРА ТО десятичная
  ИНАЧЕ ошибка
КОНЕЦ


ЭТО простая?
  ВПРАВО
  ЕСЛИ ЦИФРА ТО простая
  ИНАЧЕ ошибка
КОНЕЦ

ЭТО простая
  ВПРАВО
  ЕСЛИ       ПУСТО ТО ответ_простая
  ИНАЧЕ ЕСЛИ ЦИФРА ТО простая
  ИНАЧЕ ошибка
КОНЕЦ

// Запишем ответ "ош" и
// вернемся к месту ошибки
ЭТО ошибка
 ВПРАВО
 ЕСЛИ ПУСТО ТО ответ_ошибка
 ИНАЧЕ ошибка
 ВЛЕВО
КОНЕЦ

ЭТО ответ_ошибка
 ВПРАВО ПИШИ о
 ВПРАВО ПИШИ ш
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ

ЭТО ответ_целое
 ВПРАВО ПИШИ ц
 ВПРАВО ПИШИ л
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ

ЭТО ответ_десятичная
 ВПРАВО ПИШИ д
 ВПРАВО ПИШИ с
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ

ЭТО ответ_простая
 ВПРАВО ПИШИ п
 ВПРАВО ПИШИ р
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ

Типичные ошибки в конкурсных решениях
-------------------------------------

   1) В записи программы не всегда удачно записаны переключате-
ли:

Авторская запись               │Так нагляднее
───────────────────────────────┼─────────────────────────
ЭТО Задача1                    │ЭТО Задача1
 ВПРАВО                        │ ВПРАВО
 ЕСЛИ ПРОБЕЛ                   │ ЕСЛИ       ПРОБЕЛ ТО Ошибка
  ТО Ошибка                    │ ИНАЧЕ ЕСЛИ ПУСТО  ТО Целое
  ИНАЧЕ                        │ ИНАЧЕ ЕСЛИ .      ТО Дробь
   ЕСЛИ ПУСТО                  │ ИНАЧЕ                Символы
    ТО Целое                   │КОНЕЦ // Задача1
    ИНАЧЕ                      │
     ЕСЛИ .                    │
      ТО Дробь                 │
      ИНАЧЕ Символы            │
КОНЕЦ // Задача1               │


   2) Конструкции вида:

 ЕСЛИ 0 ТО { ПИШИ о ВПРАВО ПИШИ ш }
 ЕСЛИ 1 ТО { ПИШИ ц ВПРАВО ПИШИ л }
 ЕСЛИ 2 ТО { ПИШИ д ВПРАВО ПИШИ с }
 ЕСЛИ 3 ТО { ПИШИ п ВПРАВО ПИШИ р }

потенциально опасны и не оптимальны (об этом говорилось в  ана-
лизе решений задач Кукарачи).
   Не  оптимальны  они потому, что вся цепочка условных  команд
работает всегда.  Опасны потому, что может выполниться "лишняя"
команда, а это приведет к неверному результату.
 Пример:
 ЕСЛИ 0 ТО  ПИШИ 1
 ЕСЛИ 1 ТО  ПИШИ 2
 ЕСЛИ 2 ТО  ПИШИ 3
 ЕСЛИ 3 ТО  ПИШИ 4
   После выполнения этой  группы  команд на ленту будет записано
число 4 при любом начальном символе  из диапазона 0, 1, 2, 3. То
есть, совсем не то, что предполагал программист.
   Лучше сразу приучить себя писать безопасные переключатели ви-
да:
 ЕСЛИ       0 ТО { ПИШИ о ВПРАВО ПИШИ ш }
 ИНАЧЕ ЕСЛИ 1 ТО { ПИШИ ц ВПРАВО ПИШИ л }
 ИНАЧЕ ЕСЛИ 2 ТО { ПИШИ д ВПРАВО ПИШИ с }
 ИНАЧЕ ЕСЛИ 3 ТО { ПИШИ п ВПРАВО ПИШИ р }
   Привычка в программировании  (как и по жизни) - моторная шту-
ка. В данном конкретном случае небрежная  запись переключателя к
ошибке не привела (неоптимальность остается), но привыкнув к та-
кой записи, очень легко незаметно совершить промах.

   3) Не всегда верно указывается положение ошибки в записи.

Где показано │Где находится│
место ошибки │ошибка       │  Комментарий
─────────────┼─────────────┼────────────────────────────────────────
   5/        │ 5/          │Символ "/" не является ошибочным. Ошибка
    ^        │   ^         │расположена за ним в пустой клетке (по опре-
             │             │делению в этой клетке обязана быть цифра).
             │             │
   1/1.2     │ 1/1.2       │
     ^       │    ^        │
   1/1/2     │ 1/1/2       │
     ^       │    ^        │

  ^

4) Замечания по стилю записи текста программы

Авторская запись                  │ Вот так гораздо лучше
──────────────────────────────────┼─────────────────────────────
                                  │
ЭТО Проход                        │// Проверка наличия дробной черты
// Проверка наличия дробной черты │ЭТО Проход
Черта                             │  Черта
Поиск                             │  Поиск
КОНЕЦ                             │КОНЕЦ
//                                │
ЭТО Черта                         │// Помещает дробную черту в ящик
// Помещает дробную черту в ящик. │ЭТО Черта
 ПИШИ / ЯЩИК+ ПИШИ ПУСТО ВПРАВО   │  ПИШИ / ЯЩИК+
КОНЕЦ                             │  ПИШИ ПУСТО ВПРАВО
//                                │КОНЕЦ
....                              │
ЕСЛИ НЕ ЦИФРА ТО Возврат          │ЕСЛИ НЕ ЦИФРА ТО Возврат
ИНАЧЕ                             │ИНАЧЕ
{                                 │{
ПОКА ЦИФРА ВПРАВО                 │  ПОКА ЦИФРА ВПРАВО
ЕСЛИ ПУСТО ТО Целое               │  ЕСЛИ       ПУСТО ТО Целое
ИНАЧЕ ЕСЛИ Я=Л ТО Далее           │  ИНАЧЕ ЕСЛИ Я=Л   ТО Далее
ИНАЧЕ Возврат                     │  ИНАЧЕ Возврат
}                                 │}
КОНЕЦ                             │КОНЕЦ
//                                │
....                              │....
и т.д.                            │и т.д.

Авторская запись                      │Так понятнее
──────────────────────────────────────┼─────────────────────────────
ЭТО Символ                            │ЭТО Символ
 Цифра                                │ Цифра  // идем до первой нецифры
 ЕСЛИ ПУСТО ТО { ВПРАВО ПИШИ ц ВПРАВО │ ЕСЛИ ПУСТО ТО
 ПИШИ л }                             │ { // все цифры
// Будет выполняться, если все цифры  │   ВПРАВО ПИШИ ц
// подряд до ПУСТО                    │   ВПРАВО ПИШИ л
 ИНАЧЕ Дробный_знак                   │ }
// выполнится, когда появится Нецифра │ ИНАЧЕ Дробный_знак // когда нецифра
КОНЕЦ                                 │КОНЕЦ
                                      │

   Идея использовать максимальный размер строки для плотной за-
писи программного кода не кажется слишком удачной.
   Комментарии, которые "отщепляют" ИНАЧЕ от ТО и ЕСЛИ - просто
вредны, тем более, что они не очень содержательны. Ведь то, что
в записи были все цифры, следует  уже из того, что в этом месте
программного кода на ленту  записывается  текст "цл". А вот со-
держательный комментарий, сопровождающий  процедуру Цифра, опу-
щен.
   Теперь самое ужасное: комментарии записаны не  до, не рядом,
а после(!) кода, который комментируется. Это  совершенно не до-
пустимо и здорово сбивает с толку.
