Из задач для Microsoft Visual C++

Если вы такие умные, то почему строем не ходите?!
Из армейского юмора.

После публикации статьи «Батарея, огонь!»[1] преподаватель из Рыбинска В.Н. Пинаев (pinaev@rgata. adm.yar.ru) прислал мне письмо с критическими замечаниями, а в ходе завязавшейся вслед за этим переписки поделился со мной еще одной задачей, которая перекликается с разбираемой в статье задачей Майхилла о синхронной стрельбе. Мне показалось интересным продемонстрировать на ее примере возможности сочетания объектного подхода и автоматной модели, прояснить роль автоматов в формировании «жизни» объектов в ООП и рассказать о том, как решается проблема доступа к общему ресурсу в рамках автоматной модели и библиотеки FSA.

В.Н. Пинаев предпочитает формулировать задачу Майхилла в «демилитаризованном» варианте: построенные в шеренгу роботы по команде должны одновременно поливать цветы. А вот новая задача — назовем ее условно «новобранцы» — сохранила армейский антураж. Впрочем, она совсем не воинственная, скорее наоборот:

Новобранцы по команде «Нале-во!» повернулись кто куда: одни - налево, другие - направо. В следующую секунду те из них, кто столкнулся с соседом нос к носу, поняли, что ошиблись, развернулись на 180o, и т.д. Вопрос: закончится ли когда-нибудь это безобразие, а если да, то через сколько шагов и как именно расположатся новобранцы?

Эту задачу можно решить и аналитически, как математическую, но я не буду приводить здесь решения, чтобы не лишать читателя удовольствия найти его самостоятельно. Цель статьи — построить модель действий новобранцев на базе поведения стрелков из задачи Майхилла. Замечу, что анализ модели и наблюдение за ее работой могут стать довольно серьезной подсказкой, и сообщу ту часть ответа на вопрос задачи, которая нам понадобится: да, строй новобранцев сравнительно скоро придет в устойчивое состояние.

Поведение новобранца

Создавая алгоритм для новобранца, мы не затронем действий стрелка, основной целью которых остается подготовка к выполнению команды (раньше это был выстрел, сейчас — поворот). А вот вид и поведение пули должны измениться значительно, поэтому целесообразно, используя механизм наследования, породить от нее класс лица новобранца CHead. Нам потребуется:

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

Рассмотрим теперь изменения уже имеющихся классов TBounce и CBullet, а также новый класс CHead.

Класс TBounce

Итак, лицо (порожденное пулей) должно вертеться туда-сюда. Чтобы это обеспечить, введем в описание базового класса пули TBounce свойство cstrFace. Этот класс содержит метод MakeNewBall, который ранее рисовал на экране эллипс, символизирующий пулю, а теперь будет отображать лицо.

Рисование эллипса в методе MakeNewBall заменим на вывод символа, отражающего положение лица новобранца. Кроме того, свяжем TBounce с породившим его автоматным классом: введем указатель pFsaShot для хранения ссылки и метод SetAddrMan для установки pFsaShot (см. листинг 1).

Добавим в конструктор класса еще параметр, определяющий приоритет автоматного объекта (nPri). Приоритеты служат для управления порядком исполнения процессов в параллельной среде, и данный случай не является исключением (для чего конкретно они нам пригодятся, будет рассказано ниже). Приоритет передается методу Fload базового автоматного класса LfsaAppl,...

Это не вся статья. Полная версия доступна только подписчикам журнала. Пожалуйста, авторизуйтесь либо оформите подписку.