- •1. Общие методические указания
- •1.1. Цель и тематика курсовой работы
- •1.2. Системный анализ
- •1.3. Проектирование
- •1.3.1. Порядок применения объектно-ориентированного подхода
- •1.3.2. Система графических обозначений
- •1.4. Программирование
- •1.5. Тестирование
- •2. Пример разработки программной системы
- •2.1. Формулировка задачи
- •2.2. Системный анализ
- •2.3. Проектирование
- •2.3.1. Идентификация классов и объектов
- •2.3.2. Идентификация содержания классов
- •2.3.3. Идентификация связей между классами и объектами
- •2.3.4. Реализация классов и объектов
- •2.4. Программирование
- •2.5. Тестирование
- •3. Порядок выполнения работы
- •Приложение 1. Тексты программы учебного примера “Бильярд”
- •Приложение 2. Текст программы-драйвера
- •Приложение 3. Листинг тестирования
- •Список рекомендуемой литературы
3. Порядок выполнения работы
Преподавателем выдаются задания на курсовую работу и указываются конкретные даты выполнения этапов. Примерный график выполнения курсовой работы:
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(&theEvent);
} while(theEvent.What != EvQuit);
}; // -TReality::Run()
TReality::~TReality()
{
delete PTheTable; // убрать стол
delete PTheTimer; // убрать таймер
closegraph(); // отменить графический режим для дисплея
};
// main.cpp - Головная программа системы Бильярд
#include"billiard.h"
int main()
{ TReality theReality; // Инициализация всего
theReality.Run(); // Имитация процесса
return(0);
};