Создание диаграммы действий. Учебное пособие

Это учебное пособие научит вас создавать диаграммы действий - структурированные блок-схемы, позволяющие задавать алгоритмы графически в стиле структурированного программирования. Диаграммы действий облегчают задание алгоритмов, делая необязательным знание синтаксиса Java операторов. Использование диаграмм действий дает еще одно преимущество: с их помощью вы можете визуализировать алгоритмы, делая их более понятными для других пользователей модели.

Чтобы облегчить процесс обучения, мы используем уже имеющуюся модель столкновения бильярдных шаров: Billiard Balls. В этой модели несколько шаров двигаются в двумерной прямогольной области. Шары эластично отскакивают друг от друга и от границ области.

Мы создадим диаграмму действий, задающую алгоритм, реализованный в текущей модели с помощью функции checkHit(). Этот алгоритм проверяет, не произошло ли в текущий момент времени столкновения данного шара с каким-либо другим шаром.

Алгоритм последовательно проходит по всем шарам (они представлены в модели как популяция агентов типа Ball) и проверяет, выполняются ли для шаров условия, свидетельствующие о том, что эти два шара столкнулись. Должны быть выполнены два условия: расстояние между этими шарами должно быть меньше, чем диаметр шара, и кроме того шары должны двигаться навстречу друг другу. Если столкновение будет обнаружено, то диаграмма действий вернет тот шар, который столкнулся с шаром, переданным ей в качестве аргумента.

 Подготовьте модель для учебного пособия

  1. Выберите Справка > Примеры моделей из главного меню AnyLogic.
  2. Будет открыта страница Примеры моделей Начальной страницы.
  3. Откройте модель Billiard Balls, щелкнув мышью по ссылке с ее названием.
  4. В панели Проекты разверните ветвь модели Billiard Balls, затем подветвь типа Main и наконец подветвь Функции.
  5. Щелкните правой кнопкой мыши по функции checkHit и выберите Удалить из контекстного меню.

  1. Сохраните модель на диске под другим именем с помощью команды Сохранить как.... Это нужно для того, чтобы быть уверенными в том, что внесенные нами изменения не повлияют на исходный пример модели.

Шаг 1. Создание новой диаграммы действий

 Создайте новую диаграмму действий
  1. Перетащите элемент Диаграмма действий  с палитры Диаграмма действий на диаграмму типа агента Main. Будет нарисована простейшая диаграмма действий, состоящая из начальной точки (задаваемой блоком "диаграмма действий") и блока "вернуть значение".

  2. Измените имя диаграммы действий: введите checkHit и нажмите Enter

  1. Задайте свойства диаграммы действий в панели Свойства.
  2. Укажите тип возвращаемого диаграммой действий значения. В нашем случае мы хотим вернуть шар, который столкнулся с данным. Мы будем возвращать значение отличного от предлагаемых Java класса. Поэтому выберите из группы кнопок Тип возвращаемого значения опцию Другой и введите имя типа в расположенном справа поле. Поскольку в этой модели шары заданы как агенты типа Ball, введите здесь Ball.
  3. Теперь нам нужно задать аргумент диаграммы действий, поскольку он нам нужен для того, чтобы передавать реализуемому нами алгоритму шар, столкновения которого мы будем искать. Аргументы диаграммы действий задаются в таблице Аргументы. Введите в ячейке Имя имя аргумента: b. В ячейке Тип укажите тип элемента: щелкните мышью внутри ячейки и выберите Ball из выпадающего списка. 

Вы закончили создание простейшей диаграммы действий. Теперь вам будет нужно добавить в созданную структуру другие блоки диаграммы действий согласно задаваемому вами алгоритму.

Шаг 2. Добавление цикла, производящего итерацию по коллекции шаров

Чтобы обнаружить столкновение одного шара с каким-то другим, мы должны поочередно проверить все присутствующие в нашей модели шары на предмет столкновения с данным. Поэтому сейчас мы добавим в наш алгоритм цикл, который будет проверять для всех шаров выполнение условий столкновения.

Лучшим способом последовательно выполнить какое-либо действие над всеми элементами коллекции (с помощью которой мы задали бильярдные шары в нашей модели) является использование блока диаграммы действий Цикл For. Есть две разновидности этого цикла: Цикл со счетчиком и Итератор по коллекции. Как следует из названия, Итератор по коллекции итеративно проходит по всем элементам указанной коллекции. На каждой итерации выполняется заданное действие циклв, в котором доступен очередной элемент коллекции.

 Добавьте цикл "for" в диаграмму действий

  1. Перетащите элемент Цикл For из палитры Диаграмма действий в нашу диаграмму действий. 
    Перетаскивая блок над областью графического редактора, вы увидите, что определенные точки диаграммы действий будут выделяться с помощью маленьких кружков. Эти точки являются так называемыми точками вставки диаграммы действий. Если при перетаскиваниии блока вы отпустите кнопку мыши, когда курсор мыши будет находиться над одной из этих точек, то блок будет добавлен в соответствующее место диаграммы. 
    В первое время выбор необходимой вам точки вставки может быть не совсем интуитивен, поэтому в этом учебном пособии мы будем указывать нужные точки вставки на рисунках с помощью специальных красных стрелок:

  1. Перетащив блок в указанную нами точку диаграммы действий, вы увидите, что в диаграмму будет добавлен новый блок "цикл for": 

  1. Перейдите в панель Свойства и задайте тип цикла. Поскольку мы хотим, чтобы этот цикл выполнял действия над элементами коллекции, выберите опцию Итератор по коллекции.
  2. В поле Коллекция введите имя переменной-коллекции, по элементам которой будет последовательно проходить данный цикл. Введите имя нашей поуляции агентов: balls (вы можете пользоваться помощью мастера подстановки кода).
  3. В поле Элемент укажите имя типа агентов и имя, которое вы будете использовать для доступа к очередному элементу коллекции при выполнении действий итерации цикла. Введите здесь Ball b1

  1. Вы увидите, что изменение свойств цикла будет тут же отражено и в графическом редакторе:

Шаг 3. Добавление блока "решение"

При последовательном прохождении всех шаров очевидно, что мы столкнемся с ситуацией, когда будем сравнивать столкновение шара с самим собой (поскольку все шары хранятся в одной и той же коллекции balls). Мы хотим предотвратить этот случай путем проверки того, является ли шар, переданный диаграмме действий в качестве аргумента, тем же шаром, что проверяется сейчас в ходе текущей итерации цикла. Мы реализуем эту проверку с помощью блока Решение

Блок Решение (If.. Else) является простейшим способом управления выполнением алгоритма. Он обеспечивает выполнение фрагментов кода в соответствии с условием. У блока есть две исходящие ветви - true и false. С помощью других блоков диаграммы действий вы можете задать последовательность действий для каждой из этих ветвей. Когда управление дойдет до данного блока, будет приниматься решение о том, по какой ветви блока управление пойдет дальше. Если заданное для блока условие будет выполнено (т.е. результат его выполнения будет равен true), то будет выбрана ветвь true. В противном случае - ветвь false.

 Добавьте блок "решение"
  1. Перетащите элемент Решение (If .. Else)  из палитры Диаграмма действий в диаграмму действий (а именно - в точку вставки, расположенную внутри цикла "for"):  

  1. Новый блок "решение" будет добавлен в эту точку диаграммы.

  1. Перейдите в панель Свойства и введите условие в поле УсловиеУсловие может быть любым выражением Java, возвращающим значение типа boolean. Введите здесь b==b1. Вы увидите, что это условие будет отображено внутри блока в графическом редакторе. 


Шаг 4. Добавление блока кода

Теперь мы хотим реализовать пропуск проверки столкновения в том случае, если мы сравниваем шар с самим собой. Нам нужно поместить только одну строку кода в ту ветвь диаграммы действий, которая будет выбрана в том случае, если результат выполнения нашего условия будет истинным (true). Вы можете добавить фрагменты кода в диаграмму действий с помощью соответствующих блоков Код. Код может быть как простым выражением Java, так и набором выражений, отделенных точками с запятой. Этот код будет выполняться тогда, когда управление дойдет до соответствующего блока "код".

 Добавьте блок кода
  1. Перетащите элемент Код  из палитры Диаграмма действий в точку вставки, расположенную в ветви true блока "решение". 

  1. Новый блок "код" будет добавлен в эту точку диаграммы.

  1. Перейдите в панель Свойства. В поле Код введите Java код, который вы хотите выполнить в тот момент, когда управление диаграммы дойдет до этого блока. Введите здесь
    continue;
    Этот код будет отображен внутри блока в графическом редакторе. 
  2. Теперь добавим комментарий к этому коду, чтобы сделать алгоритм более понятным для других пользователей этой модели. Введите skip checking в поле Метка
  3. При желании вы можете изменить цвет заливки блока с помощью элемента управления Цвет заливки.

  1. Все эти изменения будут отражены на диаграмме в графическом редакторе, так что в результате диаграмма действий должна будет выглядеть так:

Теперь наша диаграмма действий не будет выполнять проверку столкновения шара с самим собой, пропустив этот случай и продолжив итерирование по другим элементам коллекции.

Шаг 5. Добавление локальных переменных

Теперь мы хотим проверить первое условие столкновения, а именно - проверить, находятся ли шары на расстоянии столкновения (т.е. расстояние между шарами меньше диаметра шара).

Для этого мы вначале объявим пару локальных переменных для хранения промежуточных результатов вычисления. Переменные в диаграммах действия задаются с помощью блоков Локальная переменная. Пожалуйста, обратите внимание, что локальная переменная видна не во всей диаграмме действий, а только в той ее части, которая следует за точкой объявления переменной.

 Объявите локальную переменную
  1. Перетащите элемент Локальная переменная с палитры Диаграмма действий в точку вставки внизу области цикла "for": 

  1. Вы увидите, что в диаграмму действий будет добавлен новый блок, задающий локальную переменную. 
  1. Перейдите в панель Свойства.
  2. В поле Имя введите имя локальной переменной: dx. Имя переменной будет отображено внутри блока в графическом редакторе. 
  3. Задайте тип локальной переменной. Выберите опцию double из группы кнопок Тип
  4. Введите начальное значение переменной в поле Начальное значение: b1.x - b.x

 Объявите еще одну локальную переменную

  1. Добавьте ниже еще одну локальную переменную. Мы создадим ее путем копирования уже созданной переменной. 
  2. Щелкните правой кнопкой мыши по блоку переменной dx и выберите Копировать из контекстного меню. 
  3. Затем щелкните правой кнопкой мыши по пустому месту диаграммы и выберите Вставить. На диаграмме появится новый блок - копия ранее добавленного блока "локальная переменная".
  4. Перетащите этот блок в диаграмму действий под блок переменной dx. Перетаскивая блок, отпустите кнопку мыши тогда, когда курсор мыши будет находиться над зеленой точкой, находящейся в ветви, идущей из блока переменной dx:
  1. Измените свойства созданной переменной. Назовите ее dy и задайте ее Начальное значение: b1.y - b.y.

Шаг 6. Проверка того, находятся ли шары на расстоянии столкновения

Добавьте еще один блок "решение"

  1. Поместите под переменными еще один блок "решение". 
  1. Введите условие в поле Условие: dx*dx+dy*dy < 4*b.r*b.r
  2. Введите комментарий к блоку в поле Метка:
    check the distance between balls
    Этот комментарий будет виден внутри блока (ранее там отображалось условие).


  1. Измените размер блока в графическом редакторе так, чтобы комментарий поместился внутрь блока:

Шаг 7. Проверка того, движутся ли шары навстречу друг другу

Теперь мы должны проверить второе условие столкновения  - двигались ли шары в момент потенциального столкновения навстречу друг другу или нет. Мы реализуем эту проверку так же, как и предыдущую - вначале создадим локальные переменные, а затем добавим блок "решение", который собственно и будет производить проверку.

 Объявите две локальные переменные 
  1. Добавьте две локальные переменные в ветвь true только что созданного блока "решение", как показано на приведенном ниже рисунке:
 
  1. Сделайте обе переменные вещественными (типа double). 
  2. Назовите первую переменную vrx и задайте Начальное значение: b1.vx - b.vx

  3. Назовите вторую переменную vry и задайте Начальное значение: b1.vy - b.vy

 Добавьте еще один блок "решение"

  1. Поместите еще один блок "решение" ниже блока переменной vry
  1. Введите условие в поле Условиеdx*vrx+dy*vry <= 0
  2. Введите комментарий к блоку в поле Метка:
    check the balls are moving towards
  3. Измените размер блока в графическом редакторе так, чтобы комментарий поместился внутрь блока:

Шаг 8. Возвращение результатов выполнения алгоритма

Теперь нам нужно определить, какие значения будет возвращать наша диаграмма действий. Это может быть сделано с помощью блоков Вернуть значение (Return). Блок Вернуть значение (Return) играет две роли: во-первых, он определяет, какое значение будет возвращать диаграмма действия (если ее тип возвращаемого значения не void), и во-вторых, немедленно возвращает это значение, завершая тем самым процесс.

Если мы обнаружим столкновение шаров, то наша диаграмма действий должна будет вернуть в качестве возвращаемого значения тот шар, который столкнулся с шаром, переданным этой диаграмме в качестве аргумента.

 Вставьте блок "вернуть значение"
  1. Перетащите элемент Вернуть значение (Return)  из палитры Диаграмма действий в ветвь true только что созданного блока "решение". Эта ветвь будет нарисована пунктиром, обозначая тем самым, что управление никогда не дойдет до тех блоков, которые будут следовать в данной ветви за блоком "вернуть значение". 
  2. В панели Свойства, введите b1 в поле Возвращаемое значение

Каждая ветвь диаграммы действий должна заканчиваться блоком Вернуть значение (Return). По этой причине в конец каждой новой диаграммы действий, один блок "вернуть значение" был автоматически добавлен в ее конец, сделав таким образом уже эту начальную конструкцию логически завершенной. Управление будет передано этому блоку, когда алгоритм закончит свою работу и не найдет ни одного столкновения, поэтому здесь мы должны вернуть значение null.

 Задайте значение, возвращаемое диаграммой действий
  1. Выберите блок "вернуть значение", расположенный внизу нашей диаграммы действий.
  2. В панели Свойства, введите null в поле Возвращаемое значение
Мы закончили создание диаграммы действий. В итоге она должна выглядеть так, как показано на приведенном ниже рисунке:

Диаграмма действий вызывается так же, как и функция - вы пишете имя диаграммы действий, после которого ставите круглые скобки, в которых через запятую приводите значения аргументов диаграммы действий. Поэтому все вызовы функции checkHit() в этой модели теперь будут вызывать нашу диаграмму действий. Вы можете запустить модель и проверить, что она работает так же, как и до того, как мы заменили функцию checkHit() на аналогичную диаграмму действий. Но теперь ваш алгоритм представлен визуально и стал более понятным для других пользователей этой модели, которые захотят понять суть и алгоритмистику этой модели.


См. также

     Визуальное задание алгоритмов с помощью диаграмм действий