Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Цель и тематика курсовой работы

Поиск

ОБЩИЕ МЕТОДИЧЕСКИЕ УКАЗАНИЯ

Цель и тематика курсовой работы

Цель выполнения данной курсовой работы - формирование представления о взаимосвязи различных стадий единого процесса проектирования сложных программных систем. В результате выполнения работы студенты должны получить практические навыки реализации основных стадий разработки: системного анализа, проектирования, программирования и тестирования. Варианты курсовой работы выбираются из различных предметных областей таким образом, чтобы разрабатываемое программное обеспечение имело признаки сложной системы.

Системный анализ

Объектно-ориентированный анализ предметной области заключается в идентификации и моделировании основных классов и объектов, логических отношений и взаимодействий между ними. В процессе анализа (внешнего проектирования) выполняются следующие действия:

1. Определение границ предметной области посредством формирования словаря предметной области.

2. Анализ предметной области:

- формализация реального состояния задачи;

- определение внешних событий;

- моделирование частей будущей системы.

3. Создание прототипа, если это необходимо.

При объектно-ориентированном анализе большинство понятий, которые являются кандидатами в классы, могут быть отнесены к одной из категорий: абстракция существования предмета в физическом мире (реальный объект); абстракция цели или назначения (роль); абстракция чего-либо произошедшего или случившегося (событие); класс объектов, получаемых из отношений между другими объектами (взаимодействие).

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

- описание выполняемых системой функций;

- совокупность условий, при которых предполагается эксплуатировать будущую систему (аппаратные и программные ресурсы, предоставляемые системе; внешние условия ее функционирования; состав людей и работ, имеющих к ней отношение, и другие условия);

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

Проектирование

Программирование

На этапе программирования составляются синтаксически и семантически правильные программы в соответствии с проектными спецификациями, описываются глобальные данные, выполняется тестирование программных модулей и отладка. Этап программирования при объектно-ориентированном подходе называют эволюцией разрабатываемой системы. В процессе эволюции совмещаются такие виды деятельности, как составление программ, их тестирование и интеграция. Поэтому процесс разработки превращается в постепенное составление ряда развивающихся прототипов, которые затем переходят в конечную реализацию.

Тестирование

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

Порядок тестирования модуля рассмотрим подробнее. На первом шаге тестирования программный модуль рассматривается как "черный ящик" и тест подготавливается по спецификациям. На последующих шагах тесты составляются по тексту программы.

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

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

На третьем шаге составляется матрица тестирования циклов. Ситуациями в данном случае являются факты прохождения тела каждого цикла 0 раз, 1 раз, максимальное число раз.

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

ПРИМЕР РАЗРАБОТКИ ПРОГРАММНОЙ СИСТЕМЫ

Формулировка задачи

Предлагаемый пример является несколько измененным вариантом задачи из [3]. Требуется выполнить моделирование передвижения шаров при игре в бильярд. Бильярдный стол состоит из поля, ограниченного четырьмя стенками, в которых расположены четыре лузы. По полю двигаются шары. Один из шаров имеет белый цвет, остальные - черный. При столкновении шаров энергия в равных долях перераспределяется между ними. При столкновении шара со стенкой отражение происходит без потери энергии. Во время движения шары теряют энергию из-за трения о стол. При попадании в лузу черный шар остается в ней, теряя всю энергию, на белый шар луза не оказывает влияния. Первоначально шары имеют традиционную расстановку: белый шар в центре, черные - треугольником. Началом моделирования является придание белому шару начальной энергии и произвольного направления движения. Шары могут быть приведены в начальное состояние в любой момент времени.

Системный анализ

Составление словаря предметной области и идентификация классов и объектов могут быть выполнены в соответствии со следующей формальной процедурой:

1. Перечислить факты, которые характеризуют предметную область, выделяя их из постановки задачи.

2. Перечислить все объекты (существительные) и приписать им те факты, в которых они упоминаются.

3. Разделить факты для каждого объекта на три группы: первая - "атрибуты", вторая - "поведение", третья - “сообщения другим объектам”. Группа “атрибуты” - это перечень абстракций сущности данного объекта. В группу “поведение” добавляются действия, которые можно сформулировать как "сделать что-то" с данным объектом, при этом указывается, какие атрибуты изменяются. При формировании группы "поведение" может возникнуть необходимость пополнения группы "атрибуты". В группу “сообщения другим объектам” включаются те действия, которые описывают взаимодействие данного объекта с другими объектами.

В результате выполнения указанной процедуры получаем следующий словарь предметной области:

· Бильярдный стол (TTable)

¨ Атрибуты:
Четыре стенки
Четыре лузы
Черные шары
Белый шар

¨ Действия:
Начать игру (Start)
Выполнить начальную расстановку (Initiate)

· Стенка (TWall)

¨ Атрибуты:
Длина (theLength)
Угол (theAngle)

· Луза (THole)

¨ Атрибуты:
Радиус (theRadius)

· Шар (TBall)

¨ Атрибуты:
Направление движения шара (theDirection)
Энергия шара (theEnergy)
Радиус (theRadius)

¨ Действия:
Двигать шар (Move)
Установить значение энергии (SetEnergy)
Установить направление (SetDirection)

¨ Сообщения другим объектам:
Ударить шар в другой шар (HitOnBall)
Ударить шар в стенку (HitOnWall)
Попасть в лузу (HitOnHole)

· Черный шар (TBlackBall)

· Белый шар (TWhiteBall)

· Моделируемая действительность (TReality)

¨ Атрибуты:
Бильярдный стол

¨ Действия:
Выполнить моделирование (Run)

К полученному словарю предметной области следует сделать следующие замечания. Все шары имеют одноименные характеристики поведения, поэтому классы TWhiteBall и TBlackBall являются подклассами одного класса TBall. Строго говоря, моделируемый бильярдный стол не является замкнутой системой, он входит в состав более широкого понятия - моделируемая действительность. Это проявляется в том, что по условиям задачи на моделируемый стол оказывается воздействие в форме сообщений Initiate и Start от внешнего источника. Поэтому вводится понятие "моделируемая действительность" как объект theReality класса TReality. Об этом объекте известно лишь то, что он генерирует внешние события и воздействует на моделируемый бильярдный стол в процессе моделирования (Run).

Понятие "начальная энергия шара" является некоторой физической величиной, которую следовало бы предварительной определить из натурного эксперимента, но, упрощая задачу, примем ее как константу cMaxEnergy = 200.0 условных единиц. При изучении движения шара следовало бы рассмотреть физику трения качения и привести соответствующие формулы. Учитывая учебный характер примера, примем грубое допущение, что за единичный интервал времени энергия шара уменьшается на cDeltaEnergy=0.05 условных единиц не зависимо от скорости. Если в некоторый момент времени энергия оказывается меньше порогового значения cThresholdEnergy = 0.5, то шар далее двигаться не может. В реальном мире скорость движения шара зависит от его кинетической энергии, но в рассматриваемом примере будем считать, что шар движется с постоянной скоростью cVelocity = 2.0 условных единиц в единицу времени, если его энергия превышает cThresholdEnergy.

Будем определять направление движения как угол между некоторым базовым направлением и прямой, по которой движется шар. При столкновении шара, имеющего направление Alpha, со стенкой, имеющей угол theAngle, угол отражения Beta определяется формулой Beta=2*TheAngle-Alpha. Это означает, что необходимым атрибутом класса TWall является угол стенки theAngle к базовому направлению.

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

Абстракция поведения "выполнить начальную расстановку" предполагает размещение шаров на поле по следующему алгоритму. Белый шар располагается недалеко от центра поля, а остальные шары располагаются рядами, образуя треугольник. Абстракция поведения "начать моделирование" означает, что белому шару сообщаются начальная энергия и случайное направление. Из этого взаимодействия следует, что для класса TBall определены операции: "установить значение энергии" (SetEnergy) и "установить направление" (SetDirection).

Для решаемой задачи важным является отображение формы моделируемых объектов, при этом соотношение размеров следовало бы получить экспериментальным путем. Примем следующие константы в условных единицах измерения: радиус шаров cBallRadius = 5, диаметр лузы cHoleRadius = 6, длина длинных стенок cLongWallLength = 290, длина коротких стенок cShortWallLength = 190, стенки расположены под прямым углом друг к другу.

Необходимость графического отображения влечет расширение словаря предметной области. В класс TBall вводим атрибут "радиус" (theRadius), в класс THole - атрибут "радиус" (theRadius), в класс TWall - “длина” (theLength).

Результатом системного анализа является техническое задание на проектирование, составленное с использованием словаря предметной области и сопровождаемое диаграммой классов (рис. 11), диаграммой объектов (рис. 12), обобщенными алгоритмами абстракций поведения. Техническое задание содержит следующие требования.

Функции системы (здесь приводятся кратко, чтобы не повторять вышеизложенные рассуждения, но в курсовой работе они должны быть приведены полностью):

- управление моделированием осуществляется при помощи команд, подаваемых с клавиатуры: начать моделирование (клавиша “S”), выполнить начальную расстановку (клавиша “I”), завершить работу программы (клавиша “Q”);

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

Эксплуатационные требования:

- технические средства - ПЭВМ IBM PC;

- операционная система - MSDOS;

- процесс моделирования управляется одним оператором.

Ограничения на процесс разработки:

- сроки выполнения проекта определены в разделе “порядок выполнения работы” данных методических указаний;

- порядок сдачи системы определен в разделе “порядок выполнения работы” данных методических указаний.

Проектирование

Программирование

Программирование выполняется на языке С++, что определено общими требованиями к курсовой работе, но в реальном проекте выбор языка программирования должен быть обоснован. Основу для программирования составляют диаграммы и спецификации этапа проектирования. Подробнее останавливаться на данном этапе не будем, считая, что он не должен вызвать затруднений. Необходимые детали разъясняются комментариями в тексте программы в приложении 1.

Тестирование

Тестирование программного модуля (подпрограммы) рассмотрим на примере метода HitOnBall класса TBall. При восходящем тестировании сначала тестируются модули нижнего уровня. Модули последующих уровней тестируются в предположении, что используемые модули абсолютно надежны. В рассматриваемом случае программными модулями нижнего уровня являются методы GetDistance, GetCenter, GetDirection, SetDirection, GetEnergy, SetEnergy класса TBall. При тестировании метода класса следует иметь в виду, что кроме явно объявляемых параметров соответствующей процедуре передается указатель на объект, и поэтому поля объекта являются одновременно входными и выходными данными.

Спецификация тестируемого метода:

· Имя: HitOnBall;

· Назначение: изменить параметры движения двух шаров при их столкновении;

· Аргумент: TBall *aBall (указатель на пассивный шар);

· Квалификация: управление;

· Расширение: добавление;

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

Тесты допустимых границ входных данных (тесты 1¸4) и функциональных границ (тесты 5¸7) сведем в таблицу.

 

 

N Входные данные Выходные данные
  Шары имеют нулевую энергию: this‑>theRadius==5; this‑>theCenter=={11,25}; this‑>theState==stOnField; this‑>theEnergy==0; this‑>theDirection==3*Pi/4; aBall‑>theRadius==5; aBall‑>theCenter=={15,25}; aBall‑>theState==stOnField; aBall‑>theEnergy==0; aBall‑>theDirection==-3*Pi/4. Направление и энергия не изменяются: this‑>theEnergy==0; this‑>theDirection==3*Pi/4; aBall‑>theEnergy==0; aBall‑>theDirection==-3*Pi/4.
  Шары имеют максимальную энергию: this‑>theRadius==5; this‑>theCenter=={11,25}; this‑>theState==stOnField; this‑>theEnergy==cMaxEnergy; this‑>theDirection==3*Pi/4; aBall‑>theRadius==5; aBall‑>theCenter=={15,25}; aBall‑>theState==stOnField; aBall‑>theEnergy==cMaxEnergy; aBall‑>theDirection==-3*Pi/4. Направление и энергия изменяются: this‑>theEnergy==cMaxEnergy; this‑>theDirection==Pi/4; aBall‑>theEnergy==cMaxEnergy; aBall‑>theDirection==-Pi/4.

 


 

    Продолжение
  Первый шар находится в лузе: this‑>theRadius==5; this‑>theCenter==cLongWallCenter1; this‑>theState==stOnHole; this‑>theEnergy==cMaxEnergy/3; this‑>theDirection==3*Pi/4; aBall‑>theRadius==5; aBall‑>theCenter=={cLongWallCenter1.X, cLongWallCenter1.Y-4}; aBall‑>theState==stOnField; aBall‑>theEnergy==cMaxEnergy/5; aBall‑>theDirection==-3*Pi/4. Направление и энергия не изменяются: this‑>theEnergy==cMaxEnergy/3; this‑>theDirection==3*Pi/4; aBall‑>theEnergy==cMaxEnergy/5; aBall‑>theDirection==-3*Pi/4.
  Второй шар находится в лузе: this‑>theRadius==5; this‑>theCenter=={cLongWallCenter1.X, cLongWallCenter1.Y-4}; this‑>theState==stOnField; this‑>theEnergy==cMaxEnergy/5; this‑>theDirection==-3*Pi/4; aBall‑>theRadius==5; aBall‑>theCenter==cLongWallCenter1; aBall‑>theState==stOnHole; aBall‑>theEnergy==cMaxEnergy/3; aBall ‑>theDirection==3*Pi/4. Направление и энергия не изменяются: this‑>theEnergy==cMaxEnergy/5; this‑>theDirection==-3*Pi/4; aBall‑>theEnergy==cMaxEnergy/3; aBall‑>theDirection==3*Pi/4.
  Оба шара находятся в поле и движутся навстречу: this‑>theRadius==5; this‑>theCenter=={5,10}; this‑>theState==stOnField; this‑>theEnergy==0.1*cMaxEnergy; this‑>theDirection==Pi/4+Pi/2; aBall‑>theRadius==5; aBall‑>theCenter=={10,10}; aBall‑>theState==stOnField; aBall‑>theEnergy==0.3*cMaxEnergy; aBall‑>theDirection==Pi/4. Направление и энергия изменяются в соответствии со спецификацией: this‑>theEnergy==0.2*cMaxEnergy; this‑>theDirection==Pi/4; aBall‑>theEnergy==0.2*cMaxEnergy; aBall‑>theDirection==Pi/4+Pi/2.
  Оба шара находятся в поле и движутся в разные стороны: this‑>theRadius==5; this‑>theCenter=={5,10}; this‑>theState==stOnField; this‑>theEnergy==0.7*cMaxEnergy; this‑>theDirection==Pi/4; Направление не изменяется: this‑>theDirection==Pi/4; this‑>theEnergy==0.5*cMaxEnergy; aBall‑>theDirection==Pi/4+Pi/2; aBall‑>theEnergy==0.5*cMaxEnergy.
    Окончание
  aBall‑>theRadius==5; aBall‑>theCenter=={10,10}; aBall‑>theState==stOnField; aBall‑>theEnergy==0.3*cMaxEnergy; aBall‑>theDirection==Pi/4+Pi/2.  

 

Введем обозначения для ветвлений:

A: (theState==stOnField);

B: (aBall->GetDistance(GetCenter()) <= theRadius + cSmallSpace);

C: (aBall->theState==stOnField).

Построим диаграмму управления (рис.18) и, руководствуясь ею, составим матрицу учета ветвей.

 

  Условия              
A (theState==stOnField) T X X   X X X
    F     X      
B (aBall->GetDistance(GetCenter()) <= T X X   X X X
  TheRadius+ cSmallSpace) F            
C (aBall->theState==stOnField) T X X     X X
    F       X    

 

Из матрицы учета ветвей видно, что предусмотренные тесты не охватывают ситуацию B=F, поэтому дополнительно вводим еще тест:

 

  Оба шара находятся в поле и движутся в разные стороны: this‑>theRadius==5; this‑>theCenter=={5,10}; this‑>theState==stOnField; this‑>theEnergy==cMaxEnergy/2; this‑>theDirection==Pi/4+Pi/2; aBall‑>theRadius==5; aBall‑>theCenter=={100,20}; aBall‑>theState==stOnField; aBall‑>theEnergy==cMaxEnergy/3; aBall‑>theDirection==Pi/4. Направление и энергия не изменяются: this‑>theEnergy==cMaxEnergy/2; this‑>theDirection==Pi/4+Pi/2; aBall‑>theEnergy==cMaxEnergy/3; aBall‑>theDirection==Pi/4.

 

Циклы и сложные логические условия в тестируемой процедуре отсутствуют, поэтому нет необходимости составлять соответствующие тесты. Драйвер для выполнения тестов с номерами 5, 6, 7 и результаты тестирования приводятся в приложениях 2 и 3. Отметим, что в тесте 5 несоответствие результата и ожидаемого значения обусловлено ошибкой округления. Тест 6 выявляет ошибку, вызванную тем, что в тестируемой подпрограмме направление шаров изменяется, если они расходятся. Исправление ошибки требует возврата к этапу проектирования. Аналогичная ошибка выявляется при тестировании TBall::HitOnWall.

 

ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

Преподавателем выдаются задания на курсовую работу и указываются конкретные даты выполнения этапов. Примерный график выполнения курсовой работы:

· 1-я неделя. Получение задания.

· 2-я - 3-я недели. Системный анализ.

· 4-я - 7-я недели. Проектирование программной системы.

· 8-я - 10-я недели. Программирование.

· 11-я - 12-я недели. Тестирование.

· 13-я - 14-я недели. Отладка.

· 15-я - 16-я недели. Оформление пояснительной записки.

· 17-я неделя. Защита курсовой работы.

Отчет о выполнении курсовой работы оформляется на листах писчей бумаги формата 11 (A4). Текст следует размещать на листах, оставляя свободное поле сверху и снизу 20 мм, слева - 25 мм, справа - 15 мм. Разделы, подразделы, таблицы, рисунки и страницы отчета нумеруются. Заголовки разделов пишутся прописными буквами (симметрично тексту), заголовки подразделов - строчными, кроме первой прописной (с абзаца).

Состав пояснительной записки по курсовой работе:

- титульный лист;

- аннотация, включающая в себя сведения об объеме курсовой работы, количество рисунков, таблиц, краткое описание задачи, оценку результатов и т.д.;

- лист задания;

- содержание, в котором дается перечисление наименований разделов и подразделов, а также приложений с указанием номеров страниц (титульный лист не нумеруется);

- основная часть записки (введение, разделы, заключение);

- список литературы;

- приложения.

Основная часть записки должна включать следующие обязательные разделы: системный анализ, проектирование программной системы, программирование, тестирование. Тексты программ вынести в приложение. Пояснительная записка должна содержать необходимый и достаточный набор диаграмм и спецификаций. В заключение указать пути возможного усовершенствования разработанной программной системы.

Защита курсовой работы проводится перед комиссией, состав которой утвержден кафедрой, и в присутствии студентов данной группы. При защите курсовой работы студент должен сделать краткое сообщение, в котором обоснованно изложить:

- назначение и технические возможности программной системы;

- основные результаты системного анализа, проектирования, программирования и тестирования;

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

ПРИЛОЖЕНИЕ 1.
Тексты программы учебного примера “Бильярд”

 

// figures.h - Интерфейс модуля графических фигур

#ifndef figures_h

#define figures_h­

#include<math.h>

// Класс точка на экране

class TPoint

{ public:

float X,Y;

float DistanceTo(TPoint& aPoint)

{float X2 = X-aPoint.X;

float Y2 = Y-aPoint.Y;

return (sqrt(X2*X2+Y2*Y2));

};

};

// Базовый класс фигура

class TFigure

{

TPoint theCenter; // геометрический центр фигуры

public:

TFigure(TPoint& aPoint); // инициализировать новыми

//координатами

virtual void Show()=0; // отобразить

void Hide(); // спрятать

virtual float GetDistance(TPoint aPoint)=0; // расстояние

// до фигуры

TPoint GetCenter(); // дать координаты центра

void SetCenter(TPoint aPoint); // установить
//новые коорд.центра

};

#endif

 

// figures.cpp - Реализация модуля графических фигур

#include"figures.h"

#include<graphics.h>

TFigure::TFigure(TPoint& aPoint)

// инициализировать новыми координатами

{ theCenter = aPoint; };

void TFigure::Hide()

{int prev_col = getcolor(); // запомнить предыд.цвет

//рисования

setcolor(BLACK); // установить цвет фона

Show(); // отобразить в "черном цвете"

setcolor(prev_col); // восстановить цвет

};

TPoint TFigure::GetCenter() // дать координаты центра

{return theCenter;};

void TFigure::SetCenter(TPoint aPoint)

// установить новые координаты центра

{theCenter = aPoint;};

 

// billiard.h - Заголовок модуля элементов бильярда

#ifndef billiard_h

#define billiard_h

#include "figures.h"

// Константы предметной области

float const Pi=3.14159265359;

const cWallsNumber=4; // Количество стенок

//у бильярдного стола

const cHolesNumber=4; // Количество луз стола

const cBallsNumber=11; // Количество шаров

//на бильярдном столе

const cBallRadius=5; // Радиус шара

const cHoleRadius=6; // Радиус лузы

const cLongWallLength=290; // Длина длиной стенки стола

const cShortWallLength=190; // Длина короткой стенки стола

float const cMaxEnergy=200.0; // максимальная энергия шара

float const cDeltaEnergy=0.05;

// уменьшение энергии в единицу времени

float const cThresholdEnergy=0.5;

// предел энергии подвижности

float const cVelocity=2.0; // скорость перемещения шара

// Константы проектирования

TPoint const cLongWallCenter1={155,10};

// Положение центра длинной стенки

TPoint const cLongWallCenter2={155,200};

// Положение центра длинной стенки

float const cLongWallAngle = 0.0; // Наклон длинной стенки

TPoint const cShortWallCenter1={10,105};

// Положение центра короткой стенки

TPoint const cShortWallCenter2={300,105};

// Положение центра короткой стенки

float const cShortWallAngle=Pi/2.0;

// Наклон короткой стенки

int const cTimerInterval = 2;

// период генерации событий времени

float const cSmallDistance = 1.0;

// зазор между шарами при расстановке

// константы событий

enum TEvConstant {EvNothing, EvStart, EvInitiate, EvQuit, EvTick};

// Интерфейсы классов

class TEvent

{

// Класс Событие

public:

TEvConstant What;

};

class TTimer

{

private:

int theCounter; // счетчик обращений

int theInterval; // период генерации события

public:

TTimer(int anInterval){theInterval = anInterval; theCounter = 0;};

void HandleEvent(TEvent* anEvent)

{if(theCounter<theInterval){theCounter++;}

// нет события

else{theCounter=0; anEvent->What=EvTick;};

// есть событие

};

~Ttimer(){;}; // Деструктор

};

class TWall: public TFigure

{

// Стенка

float theLength;

float theAngle;

public:

TWall(TPoint aCenter, int aLength, float anAngle);

// параметры

virtual float GetDistance(TPoint aPoint);

// расстояние до точки

float GetAngle(); // угол наклона

virtual void Show();

};

class THole: public TFigure

{

// Луза

int theRadius;

public:

THole(TPoint aCenter, int aRadius);

virtual float GetDistance(TPoint aPoint);

// расстояние до точки

virtual void Show();

};

class TBall: public TFigure

{

// Просто шар

protected:

int theRadius; // радиус

enum TState {stOnField, stOnHole} theState;

// состояние (в поле; в лузе)

float theEnergy; // энергия

float theDirection; // направление движения

public:

TBall(TPoint& aCenter, int aRadius);

void HitOnWall(TWall* aWall);

virtual void HitOnHole(THole* aHole)=0;

void HitOnBall(TBall* aBall);

void SetOnTable(TPoint& aCenter);

virtual void Move();

virtual float GetDistance(TPoint aPoint);

float GetEnergy();

float GetDirection();

void SetEnergy(float anEnergy);

void SetDirection(float aDirection);

};

class TBlackBall: public TBall

{

// Черный шар

public:

TBlackBall(TPoint& aCenter, int aRadius);

virtual void HitOnHole(THole* aHole);

virtual void Show();

};

class TWhiteBall: public TBall

{

// Белый шар

public:

TWhiteBall(TPoint& aCenter, int aRadius);

virtual void HitOnHole(THole* aHole);

virtual void Show();

};

class TTable

{

// Бильярдный стол

TWall* PWalls[cWallsNumber];

//массив указателей на элементы стола

THole* PHoles[cHolesNumber];

TBall* PBalls[cBallsNumber];

TWhiteBall* PTheWhiteBall; // указатель на белый шар

public:

TTable();

void HandleEvent(TEvent* anEvent); // обработка событий

void Initiate(); // Первоначальная расстановка

void Start(); // Удар кием

void Update(); // Изменить состояние

~TTable();

};

class TReality

{

// Моделируемая действительность

TTable* PTheTable; // указатель на стол

TTimer* PTheTimer; // указатель на таймер

public:

TReality();

void Run();

~TReality();

};

#endif

 

// billiard.cpp - Реализация модуля элементов бильярда

#include"figures.h"

#include"billiard.h"

#include<graphics.h>

#include<conio.h>

#include<stdlib.h>

#include <string.h>

// Реализация класса Стенка

TWall::TWall(TPoint aCenter, int aLength, float anAngle)

: TFigure(aCenter)

{ theLength = aLength; theAngle = anAngle;};

float TWall::GetDistance(TPoint aPoint)

// расстояние до точки

{

// Площадь треугольника - по формуле Герона

TPoint A,B; // концы стенки

float L1, L2; //длины боковых сторон

float S, D;

// Определить координаты концов стенки

A.X = theLength*cos(theAngle)/2.0+GetCenter().X;

A.Y = theLength*sin(theAngle)/2.0+GetCenter().Y;

B.X = 2*GetCenter().X-A.X;

B.Y = 2*GetCenter().Y-A.Y;

// Найти длины сторон треугольника между точкой

// и концами стенки

L1 = aPoint.DistanceTo(A);

L2 = aPoint.DistanceTo(B);

// Полупериметр треугольника

S = (L1+L2+theLength)/2.0;

// Искомое расстояние

D = 2.0*sqrt(S*(S-theLength)*(S-L1)*(S-L2))/theLength;

return(D);

};

float TWall::GetAngle() // угол наклона

{ return(theAngle); };

void TWall::Show()

{

// Найти координаты концов стенки

TPoint A,B; // концы стенки

// Определить координаты концов стенки

A.X = theLength*cos(theAngle)/2.0+GetCenter().X;

A.Y = theLength*sin(theAngle)/2.0+GetCenter().Y;

B.X = 2.0*GetCenter().X-A.X;

B.Y = 2.0*GetCenter().Y-A.Y;

line(A.X, A.Y, B.X, B.Y); // и нарисовать ее

};

// Реализация класса Луза

THole::THole(TPoint aCenter, int aRadius): TFigure(aCenter)

{ theRadius = aRadius;};

float THole::GetDistance(TPoint aPoint)

// расстояние до точки

{

// Исключить из расстояния радиус лузы

TPoint A;

A = GetCenter();

return(aPoint.DistanceTo(A)-theRadius);

};

void THole::Show()

{ circle(GetCenter().X, GetCenter().Y, theRadius);};

// Реализация класса Шар

TBall::TBall(TPoint& aCenter, int aRadius): TFigure(aCenter)

{

theRadius = aRadius; // Константа

theState = stOnField; // в поле

theEnergy = 0.0;

theDirection = 0.0;

};

void TBall::HitOnWall(TWall* aWall)

{

if(theState==stOnField) // действия - если в поле

{

// Отражение - если близко

if(aWall->GetDistance(GetCenter()) <= theRadius)

{

// Зеркальное отражение

if(theState==stOnField)

theDirection = 2.0*aWall->GetAngle() - theDirection;

}; // -если близко

}; // -если в поле

};

void TBall::HitOnBall(TBall* aBall)

{

float MidAngle, MidEnergy;

// Все действия, если в поле

if(theState==stOnField)

{

// Столкновение, если близко

if(aBall->GetDistance(GetCenter()) <= theRadius)

{

if(aBall->theState==stOnField)

// если ударяемый шар в поле

{

// Вычиcлить средний угол между направлениями шаров

MidAngle = (theDirection + aBall->GetDirection())/2.0;

// Вычислить новые углы для активного и пассивного шаров

theDirection = 2.0*MidAngle - theDirection;

aBall->SetDirection(2.0*MidAngle - aBall->GetDirection());

// Найти половину суммарной энергии

MidEnergy = (theEnergy + aBall->GetEnergy())/2.0;

aBall->SetEnergy(MidEnergy);

theEnergy = MidEnergy;

}; // -если другой шар в поле

}; // -если близко

}; // -если в поле

};

void TBall::SetOnTable(TPoint& aCenter)

{

theState = stOnField;// в любом случае состояние - в поле

Hide(); // убрать изображение

SetCenter(aCenter); // указать новые координаты

Show(); // отобразить

};

void TBall::Move()

{

TPoint TargetPoint; // Целевая точка перемещения

if(theState==stOnField) // изменения - если в поле

{

// Перемещение, если не достигнут предел подвижности

if(theEnergy > cThresholdEnergy)

{

Hide(); // спрятать

// Переместить центр в направлении движения

TargetPoint.X = GetCenter().X+cVelocity*1.0*cos(theDirection);

TargetPoint.Y = GetCenter().Y+cVelocity*1.0*sin(theDirection);

SetCenter(TargetPoint);

// Уменьшить энергию

SetEnergy(GetEnergy()-cDeltaEnergy);

Show(); // опять отобразить

}; // -если подвижный

}; // -если в поле

};

float TBall::GetDistance(TPoint aPoint)

{

return(GetCenter().DistanceTo(aPoint)-theRadius);

};

float TBall::GetEnergy()

{ return(theEnergy);};

float TBall::GetDirection()

{ return(theDirection);};

void TBall::SetEnergy(float anEnergy)

{ theEnergy = anEnergy;};

void TBall::SetDirection(float aDirection)

{ theDirection = aDirection;};

// Реализация класса Черный шар

TBlackBall::TBlackBall(TPoint& aCenter, int aRadius)

:TBall(aCenter, aRadius) {;};

void TBlackBall::HitOnHole(THole* aHole)

{

// В соответствии с диаграммой преходов

if(theState==stOnField)

{

// Если близко с лузой

if(aHole->GetDistance(GetCenter()) <= theRadius)

{

Hide(); // спрятать изображение

SetCenter(aHole->GetCenter()); // переместить в лузу

theEnergy = 0.0; // лишить энергии

theState = stOnHole; // изменить состояние

}; // -если близко

}; // -если в поле

};

// Реализация класса Белый шар

TWhiteBall::TWhiteBall(TPoint& aCenter, int aRadius)

:TBall(aCenter, aRadius) {;};

void TWhiteBall::HitOnHole(THole* aHole)

{;}; // Белый шар игнорирует столкновение с лузой

void TWhiteBall::Show()

{

// Нарисовать закрашенный круг

if(theState==stOnField)

{

char pattern[8];

getfillpattern(pattern);

setfillpattern(pattern, getcolor());

pieslice(GetCenter().X, GetCenter().Y, 0, 360, theRadius);

};

};

void TBlackBall::Show()

{

// Нарисовать закрашенный круг

if(theState==stOnField) circle(GetCenter().X, GetCenter().Y, theRadius);

};

// Реализация класса Бильярдный стол

TTable::TTable()

{

int i; // Индекс для массивов

TPoint StartPoint;

// Создать стенки

PWalls[0] =

new TWall(cLongWallCenter1, cLongWallLength, cLongWallAngle);

PWalls[1] =

new TWall(cLongWallCenter2, cLongWallLength, cLongWallAngle);

PWalls[2] =

new TWall(cShortWallCenter1, cShortWallLength, cShortWallAngle);

PWalls[3] =

new TWall(cShortWallCenter2, cShortWallLength, cShortWallAngle);

// Создать лузы

PHoles[0] = new THole(cLongWallCenter1, cHoleRadius);

PHoles[1] = new THole(cLongWallCenter2, cHoleRadius);

PHoles[2] = new THole(cShortWallCenter1, cHoleRadius);

PHoles[3] = new THole(cShortWallCenter2, cHoleRadius);

// Создать шары (черные и один белый) между стенками

StartPoint.X = (cLongWallCenter1.X+cLongWallCenter2.X)/2;

StartPoint.Y = (cLongWallCenter1.Y+cLongWallCenter2.Y)/2;

PTheWhiteBall = new TWhiteBall(StartPoint, cBallRadius);

PBalls[0] = PTheWhiteBall;

// запомнить указатель на белый шар

for(i=1; i<cBallsNumber;i++) PBalls[i] =

new TBlackBall(StartPoint, cBallRadius);

Initiate();

// установить первоначальную расстановку шаров

};

void TTable::HandleEvent(TEvent* anEvent)

{

switch (anEvent->What)

{

case EvStart: Start(); anEvent->What = EvNothing; break;

case EvInitiate: Initiate(); anEvent->What = EvNothing; break;

case EvTick: Update(); anEvent->What = EvNothing; break;

};

};

void TTable::Initiate()

{

TPoint aPoint, CenterPoint;

int i, NInRow, iBall;

// Отобразить стенки и лузы

for(i=0; i<cWallsNumber;i++) PWalls[i]->Show();

for(i=0; i<cHolesNumber;i++) PHoles[i]->Show();

// Установить белый шар в исходную позицию

// и лишить энергии

CenterPoint.X = (cLongWallCenter1.X+cLongWallCenter2.X)/2 - 4*cBallRadius;

CenterPoint.Y = (cLongWallCenter1.Y+cLongWallCenter2.Y)/2;

PTheWhiteBall->SetOnTable(CenterPoint);

// Установить черные шары треугольником

// Начальная точка в четырех диаметрах от белого шара

CenterPoint.X = CenterPoint.X+4*2*cBallRadius;

NInRow = 1;

iBall = 1;

while(iBall<cBallsNumber)

{

// Установить шары текущего ряда

aPoint.X = CenterPoint.X;

aPoint.Y = CenterPoint.Y + (cBallRadius+cSmallDistance)

*(NInRow-1);

for(i=1; (i<=NInRow)&&(iBall<cBallsNumber); i++)

{

PBalls[iBall]->SetOnTable(aPoint);

iBall = iBall+1;

aPoint.Y = aPoint.Y-2*(cBallRadius+cSmallDistance);

}; // -текущий ряд

NInRow = NInRow + 1;

// в следующем ряду на один шар больше

// Переместить центр

CenterPoint.X = CenterPoint.X+2*(cBallRadius+cSmallDistance);

}; // -while

// Обнулить энергию у всех шаров

// и придать случайное направление

for(iBall=0; iBall<cBallsNumber; iBall++)

{

PBalls[iBall]->SetEnergy(0.0);

PBalls[iBall]->SetDirection(2*Pi*rand()/RAND_MAX);

};

};

void TTable::Start()

{

// Белому шару - случайное направление

// и максимальную энергию

PTheWhiteBall->SetDirection(rand()*2.0*Pi/RAND_MAX);

PTheWhiteBall->SetEnergy(cMaxEnergy);

};

void TTable::Update()

{

int i,j;

// Для каждого шара анализировать взаимодействия

for(i=0;i<cBallsNumber;i++)

{

// Проверить на столкновение с лузами

for(j=0; j<cHolesNumber;j++) PBalls[i]->HitOnHole(PHoles[j]);

// Проверить на столкновение со стенками

for(j=0; j<cWallsNumber;j++) PBalls[i]->HitOnWall(PWalls[j]);

// Проверить на столкновение шаров между собой

for(j=i+1; j<cBallsNumber;j++) PBalls[i]->HitOnBall(PBalls[j]);

};

// Переместить шары

for(i=0;i<cBallsNumber;i++)

{

PBalls[i]->Move();

};

// Перерисовать стенки и лузы

for(i=0; i<cWallsNumber;i++) PWalls[i]->Show();

for(i=0; i<cHolesNumber;i++) PHoles[i]->Show();

};

TTable::~TTable()

{

int i;

// Удалить все динамические массивы

for(i=0; i<cWallsNumber; i++)

{PWalls[i]->Hide(); delete PWalls[i];};

for(i=0; i<cHolesNumber; i++)

{PHoles[i]->Hide(); delete PHoles[i];};

for(i=0; i<cBallsNumber; i++)

{PBalls[i]->Hide(); delete PBalls[i];};

};

TReality::TReality()

{

// установить графический режим для дисплея

int gdriver = DETECT, gmode, errorcode;

initgraph(&gdriver, &gmode,"\\bc\\bin");

// Создать экземпляр Бильярдного стола

PTheTimer = new TTimer(cTimerInterval);

PTheTable = new TTable;

}

void TReality::Run()

{

TEvent theEvent; // создать экземпляр объекта Событие

theEvent.What = EvNothing; // еще ничего не произошло

// Цикл получения и генерации событий

do{

// Событие от таймера

PTheTimer->HandleEvent(&theEvent);

// Событие от клавиатуры

if (kbhit())

{ char ch = getch(); strupr(&ch);

switch(ch)

{

case 'I': theEvent.What = EvInitiate; break;

case 'S': theEvent.What = EvStart; break;

case 'Q': theEvent.What = EvQuit; break;

}; // -case ch

}; // -if

// Переслать сообщение о событии возможному получателю

// и, может быть, получить от него

PTheTable->HandleEvent(&theEven



Поделиться:


Последнее изменение этой страницы: 2016-12-17; просмотров: 145; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.223.172.243 (0.029 с.)