Логическая игра Морской бой

Федеральное агентство по образованию







Государственное образовательное учреждение высшего профессионального образования

«Н А Ц И О Н А Л Ь Н Ы Й   И С С Л Е Д О В А Т Е Л Ь С К И Й   Т О М С К И Й                  П О Л И Т Е Х Н И Ч Е С К И Й   У Н И В Е Р С И Т Е Т»



Факультет Автоматики и вычислительной техники

Кафедра Автоматики и компьютерных систем

Специальность  «Информационные системы и технологии»







Пояснительная записка к курсовой работе по дисциплине

«Технология программирования»

на тему

«Логическая игра «Морской бой»»



















Выполнил                                    		           

студент группы 8880                  	                 _________________   Погребной В.Ю.	

								

						Проверил                                                             

						преподаватель кафедры АиКС                          _________________   Лунева Е.Е.

						

						

						

							                      

							                      Томск 2010
Содержание

Техническое задание	3

Введение	6

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

1.1	Функциональная спецификация	7

1.2	Диаграмма вариантов использования	12

1.3	Диаграмма классов	13

1.4	Диаграмма состояния	14

1.5	Диаграмма последовательности	15

1.6	Диаграмма компонентов	16

2.	Руководство пользователя	17

3.	Руководство программиста	21

4.	Тестирование и отладка	26

5.	Заключение	27

5.1	Достоинства и недостатки программы	27

5.2	Развитие программы	27

5.3	Итоги работы	27

6.	Список литературы	28

7.	Приложение	29

Текст программы (основные моменты)	29

	











	Техническое задание

1. Общие сведения

		Программный продукт «Логическая игра «Морской бой»», используемый пользователем персонального компьютера. 

	Разработчиком программы является студент Томского Политехнического Университета группы 8880 специальности «Информационные системы и технологии в бизнесе» Погребной Вадим Юрьевич.

	Программный продукт создается на основании выданного задания от преподавателя кафедры АИКС Луневой Е.Е.

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

Назначение и цели создания системы

Основное назначение логической игры «Морской бой» - развитие логического мышления и параллельное развлечение; в связи с потенциальной возможностью сохранения результатов игр, возможен также соревновательный игровой процесс; построение стратегий. Целью данной работы является ознакомление и углубление в технологию объектно-ориентированного программирования, изучение среды визуального программирования Borland C++ Builder 2006.

Характеристики объекта автоматизации

Объектом автоматизации служит Windows приложение в виде нескольких окон (основного и вспомогательных), на которых располагаются клеточные поля, поверх которых необходимо поместить изображения кораблей. Положение каждого объекта-корабля подлежит изменению, а при готовности игроков, эти положения сохраняются в памяти. Необходимо предусмотреть выполнение всех правил игры, сохранение результатов в файл, реализацию удобного и понятного интерфейса. Данное приложение будет работать на персональном компьютере, и создано в среде разработки Borland C++ Builder 2006.

Требования к системе

		Требования к функциональным характеристикам.

Приложение должно обеспечивать следующие функции:

		начало новой игры на поле, соответствующем выбранному режиму игры;

		перетаскивание кораблей и проверка на правильность их расположения;

		переход в режим боя при готовности всех участников игры;

		осуществление самого процесса боя с фиксацией окончания боя и победы одного из игроков;

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

		Требования к составу и параметрам технических средств:

Программное обеспечение должно функционировать на IBM-совместимых персональных компьютерах.

		Требования к информационной и программной совместимости:

Программное обеспечение должно работать под управлением операционных систем  семейства Windows. Среда  разработки Borland C++ Builder 2006. Требований к защите информации не предъявляются.

Состав и содержание работ по созданию системы

		Разработка должна быть проведена в три стадии:

	разработка технического задания; 

	создание рабочего проекта; 

	внедрение.

		На стадии разработки технического задания должен быть выполнен этап разработки, согласования и утверждения настоящего технического задания, а также:

	постановка задачи;

	определение и уточнение требований к техническим средствам; 

	определение требований к программе;

	определение стадий, этапов и сроков разработки программы и документации на неё; 

	согласование и утверждение технического задания.

		На стадии рабочего проектирования должны быть выполнены перечисленные ниже этапы работ:

	разработка программы;

	разработка программной документации;

	испытания программы.

		На стадии внедрения должен быть выполнен этап разработки «подготовка и передача программы».

		На этапе разработки программной документации должна быть выполнена разработка программных документов в соответствии с требованиями к составу документации.

		На этапе испытаний программы должны быть выполнены перечисленные ниже виды работ:

	разработка, согласование и утверждение и методики испытаний;

	проведение приемо-сдаточных испытаний;

	корректировка программы и программной документации по результатам испытаний.

		На этапе подготовки и передачи программы должна быть выполнена работа по подготовке и передаче программы и программной документации в эксплуатацию на объектах Заказчика.

Порядок контроля и приемки системы

Контроль выполнения осуществляется руководителем согласно срокам выполнения работ. Срок сдачи определяется в соответствии с учебным планом кафедры «Автоматики и компьютерных систем» ТПУ. Также будет осуществляться отдельная приемка исходного кода и скомпилированной программы.

Требования к документированию

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

		В состав сопровождающей документации должны входить:

	техническое задание;

	руководство пользователя;

	программа и методики испытаний.

	
Введение

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

Созданное приложение представляет все этапы по созданию программного продукта и программную реализацию «Логическая игра «Морской бой»». Оно носит развлекательный характер, тренирует логическое мышление, способность выстраивать стратегии в определенных условиях. Многие в детстве играли в данную игру с помощью листочка и тратили время  и бумагу на прорисовку кораблей, теперь есть возможность вспомнить про эту интересную игру, но уже используя компьютер с его искусственным интеллектом.























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

		Функциональная спецификация

1.1.1 Общие сведения

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

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

1.1.2 Блок-схема программы «Логическая игра «Морской бой»»

Чтобы представить, как работает данная программа, взглянем на блок-схему программы (рис.1). Данная блок-схема не полная, но правильно показывает, как мы собираемся использовать данное приложение.



Рис. 1. Блок-схема программы «Логическая игра «Морской бой»» 

Начало программы

Конец

программы

Игра против

компьютера

Игра против

 человека

Конец игры, сохранение

Выход

Меню

Результаты

Расстановка кораблей



1.1.3 Спецификации для каждого экрана

«Логическая игра «Морской бой»» содержит несколько окон: основное окно, которое содержит игровые поля и корабли, главное меню, также место для отображения результатов игры. Меню содержит все основные функции программы, ссылка на функцию начала боя, а также его возобновления вынесена  в окно основной формы. Игровое поле состоит из 100 клеток 10x10, на котором необходимо для начала боя разместить 10 кораблей в соответствии с правилами игры, т.е. так, чтобы корабли не соприкасались, хотя система не позволит этого сделать как бы этого не хотел игрок. При изменении режима боя меняется и интерфейс программы. При возникновении накладок от старых кораблей необходимо обратиться к функции новой игры, которая находится в главном меню. Непосредственно во время боя управление осуществляется кликом мыши по выбранной клетке поля, что подтверждается графически.

Также в программе присутствует окно с данными о программе и ее создателе. Результаты игр просматриваются в самой программе посредством вызова специального окна в оригинальном стиле.

1.1.4 Главная форма игры

Форма игрового поля появляется при запуске приложения.  Исходная форма является основной, на которой выполняется режим боя.

Начальный вид окна изображен на рисунке 2.





Рис. 2. Главное окно приложения «Морской бой», режим игры с компьютером



Обратившись к главному меню (Файл или Помощь), происходит управление программой. Меню игры должно обеспечивать выбор варианта игры (против компьютера, или игра между двумя игроками), выход, новая игра, просмотр результатов, переход в режим боя. Корабли в виде желтых клеток необходимо установить в нужное положение. В поле ввода текстовой информации возможен ввод имени игрока. Мерцание надписи «FIGHT» говорит о том, что необходимо расставить корабли и начать бой.





Рис. 3. Главное окно приложения «Морской бой», режим игры с человеком



Форма в режиме игры с человеком изображена на рисунке 3. В данном случае есть возможность изменять имя обоих игроков, также появляется изображение кораблей второго игрока. При нажатии надписи «ГОТОВ» игрок подтверждает свою готовность.

1.1.5 Форма данных о программе

Содержит данные о создателе, версию и название программы.

Форма имеет вид, изображенный на рисунке 4.



Рис. 4. Данные о программе 



1.1.6 Форма результатов игр

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

Форма имеет вид, изображенный на рисунке 5.



Рис. 5. Результаты игр



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















		Диаграмма вариантов использования



	Диаграмма классов





	Диаграмма состояния

          

	
Диаграмма последовательности

  

	Диаграмма компонентов

 



























		Руководство пользователя

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

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

		Выбор противника – человек или компьютер. Пункт недоступен в режиме боя.

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

		Результаты – происходит загрузка результатов прошлых игр из файла и игроку показываются результаты в специальном окне (рис. 5). Пункт доступен в любой момент времени.

		Выход – функция завершения работы приложения.

		Помощь – предоставляются данные о программе и о создателе приложения.

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

Также на форме приложения сразу можно заметить поля для ввода имен игроков, в режиме игры с компьютером можно изменять только первое поле ввода, при игре с человеком изменяются оба поля. В той же области окна находятся поля, предназначенные для ведения статистики боя, они будут изменяться в течение боя. Заметим, что изменение имен станет невозможным при переключении в режим боя. Мерцающая надпись указывает на то, игра находится в режиме расстановки кораблей, сама надпись является ссылкой на пункт меню – начать бой. Если игра находится в режиме игры с человеком, то метка начнет мерцать только после готовности обоих игроков начать бой. Для подтверждения готовности необходимо кликнуть на соответствующую надпись. Но для начала нужно будет расставить корабли, сначала расставляет первый игрок (второй должен будет отвернуться), затем он нажимает на «Готово» и  аналогичным образом второй игрок проводит те же операции. Только после этого можно будет начать бой, на что укажет мерцающий текст. При игре с компьютером все намного проще, нужно просто расставить корабли и можно приступить к бою.

Важной частью программы является расстановка кораблей. Для ее реализации нужно просто зажать левую кнопку мыши на корабле и перетащить в задуманное положение. Для поворота корабля на 90 градусов нужно нажать на нем правой кнопкой мыши. При наведении курсора на каждый объект возможность его перетаскивания показывается графически в виде специального курсора. Если корабли будут соприкасаться между собой, то начать бой будет невозможным, система вам не позволит этого сделать, поэтому расставляйте корабли правильно. Также хотелось бы отметить, что расставлять корабли необходимо внимательно и с умом, так как от этого зависит весь ход боя. Компьютер расставляет корабли автоматически, если вы кликнули пункт начать бой или «FIGHT» на самом окне, что намного удобнее.  

Изначальный вид окон вы можете посмотреть на рисунках 2 и 3. Окна результатов и данных о программе показаны на рисунках 4 и 5. Все функции приложения до начала боя изображены на следующем рисунке (рис.6).



Рис. 6. Функции приложения до начала боя



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

 









































Рис. 7. Режим боя

	Цель игры – убить все корабли противника быстрее, чем это сделает сам противник. Также есть возможность соревноваться с результатами прошлых игроков, их можно увидеть, по-прежнему кликнув на пункт результаты в меню программы. 

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





Рис. 8. Победа одного из игроков



Заметим, что в этом случае корабли невозможно перетащить, они показаны только для визуализации. Надпись начинает вновь мерцать, но в данном случае она ссылается на функцию меню «Новая игра».

		
Руководство программиста

Программа состоит из четырех модулей: 

	«TFlashingLabel.cpp», в котором содержится класс «TFlashingLabel», потомок класса «TLabel», носит вспомогательную роль для мерцания текста.

Содержит следующие переменные:

bool FFlashEnabled;   //Включение мерцания

int  FFlashRate;          //Скорость мерцания

TTimer *Timer;         //Таймер

А также следующие функции:

void SetFlashEnabled (bool AFlashEnabled);  	

Включение мерцания, параметр регулирует его включение

void SetFlashRate (int AFlashRate);            

Установление скорости; параметр содержит число, соответствующее скорости мерцания

void OnTimer (TObject *Sender);                

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



	«AboutProgFrm.cpp», в нем содержится следующий класс «TAboutProg», а также форма, на которой расположена информация о программе.

Содержит функцию:

void OKClick(TObject *Sender);

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



	«ResultsFrm.cpp» состоит из класса «TResultsForm» и формы для размещения текстовой информации в метках Label, загружаемой из файла.

Содержит следующие функции:

void __fastcall OKClick(TObject *Sender);

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

void LoadRes ();

Функция загружает данные из файла «SeaButResults.txt» и размещает их на форме.



	«SeaButFrm.cpp» - главный модуль приложения, посредством которого осуществляются все основные функции игры. В том числе визуализация на форме данного модуля.

Содержит следующие переменные (все переменные в разделе private):

TDrawGrid **Ships1;  		//Корабли на 1-ом поле

TDrawGrid **Ships2;            	//Корабли на 2-ом поле

int **field1;                           	//Массив 1-го поля

int **field2;                         	 //Массив 2-го поля

int linex;                        	//Координата x графической линии

int liney;                        	//Координата y графической линии

Shoot Cpu;                        	//Переменная для хранения информации стрельбы компьютера, является переменной типа Shoot, определенного следующей структурой:

struct Shoot   			//Структура для хранения данных выстрелов компьютера

{

 int Choice; 			//Выбор

 bool Target; 			//Попадание

 bool TarDir; 			//Правильно ли выбрана горизонталь

 bool TarDirect; 		//Правильно ли выбрано направление

 bool TarDestr;			//Корабль убит

 int Direction; 			//Направление

 int RowNum[100]; 		//Неопознанные точки поля

 int RowDir[4]; 			//Неопознанные направления

};

  int Choice;                       		//Выбор при попадании компьютера

  int Ships1Destr[10];			//Подбитые корабли 1-го поля

  int Ships2Destr[10];             		 //Подбитые корабли 2-го поля

  int Count1Destr;                  		//Кол-во подбитых кораблей 1-го поля

  int Count2Destr;                  		//Кол-во подбитых кораблей 2-го поля

  Graphics::TBitmap *Bitmap1;       	//Для хранения изображения канвы

  Graphics::TBitmap *Bitmap2;

  TFlashingLabel *FIGHT;            	//Динамическая мерцающая метка



А также содержит следующие функции:

		Связанные с формой приложения и являющиеся методами компонентов

  void __fastcall ExitClick(TObject *Sender);   	

Выход из приложения.

	void __fastcall GridField1DragOver(TObject *Sender, TObject *Source, int X,

		  int Y, TDragState State, bool &Accept);    

Перетаскивание объекта над полем.

	void __fastcall ShipsDragOver(TObject *Sender, TObject *Source, int X,

		  int Y, TDragState State, bool &Accept);

Функция для обеспечения возможности перетаскивания корабля.

	void __fastcall ShipsMouseDown(TObject *Sender, TMouseButton Button,

		  TShiftState Shift, int X, int Y);

Необходима для поворота корабля на 90 градусов.

	void __fastcall AboutClick(TObject *Sender); 	

Вызов окна «о программе».

	void __fastcall CompClick(TObject *Sender);  	

Переход в режим игры с компьютером.

	void __fastcall HumanClick(TObject *Sender);      

С человеком.

	void __fastcall FightClick(TObject *Sender);       	

Начать бой.

	void __fastcall NewGameClick(TObject *Sender);  

Новая игра.

	void __fastcall Ready1Click(TObject *Sender);   	

Готовность 1-го игрока.

	void __fastcall Ready2Click(TObject *Sender);   	

Готовность 2-го игрока.

	void __fastcall GridField1MouseDown(TObject *Sender, TMouseButton Button,

		  TShiftState Shift, int X, int Y);         	

Выстрел.

	void __fastcall Timer1Timer(TObject *Sender);   	

Работа таймера 1, необходим для прорисовки линий и стрельбы компьютера.

	void __fastcall Timer2Timer(TObject *Sender);

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

	void __fastcall Timer3Timer(TObject *Sender);

Работа таймера 1, необходим для показа победы игрока.

	void __fastcall FormDestroy(TObject *Sender);   	

При уничтожении формы, очистка памяти.

	void __fastcall FormPaint(TObject *Sender);    	 

Прорисовка формы, в случае перекрывания другими окнами.

	void __fastcall ResultsClick(TObject *Sender);  	

Показать результаты.

	void __fastcall FormDragOver(TObject *Sender, TObject *Source, int X, int Y,

		  TDragState State, bool &Accept);

Для запрета перемещения кораблей вне поля.



		Созданные программистом (все в разделе private)

  void SaveRes (int);               

Сохранение результатов игры в файл, параметр определяет победителя.

  void SaveBM (int);                

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

  void DelBM (int);                 

Удаление изображения, параметр вводится для соответствия указателю на изображение, необходимого для удаления. 

  void SetWindow (bool);            

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

  void SeaDraw (int, int, int, bool);

Рисование на канве, номер которой указан первым параметром. Ее координаты указываются следующими двумя параметрами типа int, ложное значение последнего параметра указывает на промах игрока, правдивое – на попадание.

  void NullCpu (); 					

Обнуление Cpu.

  void NewShips (int);              

Создание объектов – кораблей, задание им необходимых свойств. Объекты располагаются на панели под номером, указанным параметром.

  void Newfield (int);              

Создание динамического массива для поля боя игрока под номером, указанным параметром.

  void DelShips (int);              

Удаление кораблей на панели под номером параметра типа int.

  void Delfield (int);              

Удаление массивов.

  bool CheckShips (int);            

Проверка правильной расстановки кораблей, проверяются корабли указанные параметром.

  void CheckDestr ();               

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

  void CreateShips ();              

Случайная расстановка кораблей компьютером.

  void CompShot ();                 

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

  void ChangeCur (char *, int);     

Смена курсоров производится в соответствии с указанным файлом в первом параметре. Курсор запоминается с помощью константы, имя которой указано во втором параметре.

		
Тестирование и отладка

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

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

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

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

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

		
Заключение

		Достоинства и недостатки программы 

В любом программном продукте есть свои достоинства и недостатки. Рассмотрим достоинства и недостатки «Логической игры «Морской бой»».

Достоинства:

Удобный и простой интерфейс;

Возможность соревноваться с предыдущими результатами игр;

Минимальная загруженность оперативной памяти;

Возможность игры с человеком, что редко встречается в компьютерных реализациях этой игры;

Богатое графическое оформление игры.

Недостатки:

	Отсутствие справки к программе;

	Довольно примитивный интеллект компьютера;

	Отсутствие дополнительных функций игры, увеличивающих интерес к ней;

	Возможность испортить графику игры перекрыванием другими приложениями или меню Пуск.

		Развитие программы

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

		Итоги работы

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



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

		Страуструп Б. «Язык программирования С++.» – М: Бином, 1999. -  990с.

		Уолнем К. «Объектно-ориентированное программирование на языке BORLAND C++» - Мн.: ООО «Попурри», 1997. – 640 с.:ил.

		«Программирование в C++ Builder 6» [Электронный ресурс], формат pdf, 1150 с.

		«Borland С++ Builder. Освой самостоятельно» [Электронный ресурс], формат pdf, 705 с.




		Приложение

Текст программы (основные моменты)



ResultsFrm.cpp



//Загрузка результатов

void TResultsForm::LoadRes ()

{

ifstream infile ("SeaButResults.txt");

if (!infile) return;



//Обнуление всех меток

Name1->Caption = '\0';

Name2->Caption = '\0';

Name3->Caption = '\0';

Name4->Caption = '\0';

Name5->Caption = '\0';

Name6->Caption = '\0';

Name7->Caption = '\0';

Name8->Caption = '\0';

Name9->Caption = '\0';

Name10->Caption = '\0';

S1->Caption = '\0';

S2->Caption = '\0';

S3->Caption = '\0';

S4->Caption = '\0';

S5->Caption = '\0';

S6->Caption = '\0';

S7->Caption = '\0';

S8->Caption = '\0';

S9->Caption = '\0';

S10->Caption = '\0';



char *temp;

temp = new char [20];

//Загружаем в temp строки из файла и показываем их

//пока не конец файла

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name1->Caption = temp;

  infile >> temp;

  S1->Caption = temp;

  infile.seekg(infile.tellg()+2);    //перемещаемся на 2 позиции вперед

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name2->Caption = temp;

  infile >> temp;

  S2->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name3->Caption = temp;

  infile >> temp;

  S3->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name4->Caption = temp;

  infile >> temp;

  S4->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name5->Caption = temp;

  infile >> temp;

  S5->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name6->Caption = temp;

  infile >> temp;

  S6->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name7->Caption = temp;

  infile >> temp;

  S7->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name8->Caption = temp;

  infile >> temp;

  S8->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name9->Caption = temp;

  infile >> temp;

  S9->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;

if (!infile.eof())

  {

  infile.getline(temp, 20, '\n');

  Name10->Caption = temp;

  infile >> temp;

  S10->Caption = temp;

  infile.seekg(infile.tellg()+2);

  }

else return;



delete [] temp;

infile.close();



}





SeaButFrm.cpp



//Создание новых кораблей

void TSeaButForm::NewShips (int number)

{

if (number == 1) //Проверка номера поля (1 или 2), если 1ое поле

  {

  DelShips (1);  //Удалить корабли



  Ships1 = new TDrawGrid * [10];    //Создать динамические корабли

  for (int i = 0; i < 10; i++)      //Придаем им необходимый внешний вид

	{

	Ships1[i] = new TDrawGrid (SeaButForm);

	Ships1[i]->Left = 0;

	Ships1[i]->Top = 29*i;

	Ships1[i]->DragMode = dmAutomatic;

	Ships1[i]->Height = 29;

	Ships1[i]->DefaultColWidth = 27;

	Ships1[i]->DefaultDrawing = false;

	Ships1[i]->DefaultRowHeight = 27;

	Ships1[i]->FixedCols = 0;

	Ships1[i]->FixedRows = 0;

	Ships1[i]->GridLineWidth = 2;

	Ships1[i]->RowCount = 1;

	Ships1[i]->ScrollBars = ssNone;

	Ships1[i]->BevelInner = bvNone;

	Ships1[i]->BevelOuter = bvNone;

	Ships1[i]->BorderStyle = bsSingle;

	Ships1[i]->Color = clYellow;

	Ships1[i]->FixedColor = clYellow;

	Ships1[i]->OnDragOver = ShipsDragOver;

	Ships1[i]->OnMouseDown = ShipsMouseDown;

	Ships1[i]->Parent = Field1;

	Ships1[i]->Cursor = (Controls::TCursor)4;

	Ships1[i]->DragCursor = (Controls::TCursor)5;

	}

  Ships1[0]->Tag = 410 + number;

  Ships1[1]->Tag = 310 + number;

  Ships1[2]->Tag = 320 + number;

  Ships1[3]->Tag = 210 + number;

  Ships1[4]->Tag = 220 + number;

  Ships1[5]->Tag = 230 + number;

  Ships1[6]->Tag = 110 + number;

  Ships1[7]->Tag = 120 + number;

  Ships1[8]->Tag = 130 + number;

  Ships1[9]->Tag = 140 + number;

  for (int i = 0; i < 10; i++)

	{

	Ships1[i]->Width = 29*(int)(Ships1[i]->Tag/100);

	Ships1[i]->ColCount = (int)(Ships1[i]->Tag/100);

	}

  }

else    //Если 2ое поле, делать для него то же самое

  {………

  }

}



//Проверка правильной расстановки кораблей

bool TSeaButForm::CheckShips (int number)

{

if (number == 1)      		//Если для 1го поля

  {

  Newfield (1);             //Создаем массив 1го поля



  int x = 0, y = 0;

  for (int i = 0; i < 10; i++)

	{

	x = Ships1[i]->Left/29;      	//Определяем координаты кораблей

	y = Ships1[i]->Top/29;



	//Переменные для перехода вокруг корабля, длины сторон

	//площадей вокруг кораблей. Как по x, так и по y

	int y_temp = 0, x_temp = 0, x_len, y_len;



	//Проверка на расположение корабля у границ

	x == 9 ? x_len = 2 : x_len = 3;

	y == 9 ? y_len = 2 : y_len = 3;

	if (y)

	  y_temp = y - 1;

	else

	  y_len = 2;

	if (x)

	  x_temp = x - 1;

	else

	  x_len = 2;



	//Проверка расстояний между кораблями и 1 полем проверяемого корабля

	for (int ky = 0; ky < y_len; ky++)

	  {

	  for (int kx = 0; kx < x_len; kx++)

		{

		//Если есть рядом

		if (field1[y_temp][x_temp])

		  {

		  //звук

		  PlaySound("Sounds\\SOUNMETA.WAV", 0, SND_ASYNC);

		  //показать сообщение

		  MessageDlgPos("Корабли не должны соприкасаться!!!", mtWarning,

			TMsgDlgButtons() << mbRetry, 0, SeaButForm->Left + SeaButForm->Width/2 - 120,

			SeaButForm->Top + SeaButForm->Height - 130);

		  return false;

		  }

		x_temp += 1;

		}

	  y_temp += 1;

	  x_temp -= x_len;

	  }

	field1[y][x] = 1;    			//Если все в порядке, то занимаем поле



	//Проверка ширины корабля, если больше 1 поля в ширину

	if (Ships1[i]->Width > 30)

	  {

	  x++;     //Переходим правее и проводим проверку для остальных полей корабля

	  for (int j = 0; j < Ships1[i]->ColCount - 1; j++)

		{

		y_temp = 0, x_temp = 0;

		x == 9 ? x_len = 2 : x_len = 3;

		if (y)

		  y_temp = y - 1;

		x_temp = x - 1;



		for (int ky = 0; ky < y_len; ky++)

		  {

		  for (int kx = 0; kx < x_len; kx++)

			{

			//Проверка на расположение корабля у границ

			if (!kx && y_temp == y)

			  {

			  kx++;

			  x_temp++;

			  }

			if (field1[y_temp][x_temp])

			  {

			  PlaySound("Sounds\\SOUNMETA.WAV", 0, SND_ASYNC);

			  MessageDlgPos("Корабли не должны соприкасаться!!!", mtWarning,

				TMsgDlgButtons() << mbRetry, 0, SeaButForm->Left + SeaButForm->Width/2 - 120,

				SeaButForm->Top + SeaButForm->Height - 130);

			  return false;

			  }

			x_temp += 1;

			}

		  y_temp += 1;

		  x_temp -= x_len;

		  }

		field1[y][x++] = 1;  //Отмечаем поле и переходим правее

		}

	  }

	//Иначе больше 1го поля в высоту

	else

	  {

	  y++;   //Проводим аналогичные операции, только в высоту

	  for (int j = 0; j < Ships1[i]->RowCount - 1; j++)

		{

		y_temp = 0, x_temp = 0;

		y == 9 ? y_len = 2 : y_len = 3;



		y_temp = y - 1;

		if (x)

		  x_temp = x - 1;



		for (int ky = 0; ky < y_len; ky++)

		  {

		  for (int kx = 0; kx < x_len; kx++)

			{

			if (x_temp == x && !ky)

			  {

			  x_temp++;

			  continue;

			  }

			if (field1[y_temp][x_temp])

			  {

			  PlaySound("Sounds\\SOUNMETA.WAV", 0, SND_ASYNC);

			  MessageDlgPos("Корабли не должны соприкасаться!!!", mtWarning,

				TMsgDlgButtons() << mbRetry, 0, SeaButForm->Left + SeaButForm->Width/2 - 120,

				SeaButForm->Top + SeaButForm->Height - 130);

			  return false;

			  }

			x_temp += 1;

			}

		  y_temp += 1;

		  x_temp -= x_len;

		  }

		field1[y++][x] = 1;

		}

	  }

	}

  }

else       //Иначе для 2го поля боя, повторяем аналогичные процессы

  {………..

  }

return true;

}



//Случайное создание кораблей компьютером

void TSeaButForm::CreateShips ()

{

  NewShips (2);

  //Скрытие кораблей 2 поля

  for (int i = 0; i < 10; i++)

	Ships2[i]->Visible = false;

  Newfield (2);             			//Создание массива 2го поля боя



  int xc = -1, dir = -1, xx = -1;   	//Выбранная координата, направление

  bool cl = false;                      //Переменная для проверки условий

  int arr[100], arrdir[4] = {0,1,2,3};  //Для сверки с недоступными полями и направлениями

  for (int i = 0; i < 100; i++)         //Заполнение массива доступных полей

	arr[i] = i;



  //Процесс создания 10 кораблей

  for (int sh = 0; sh < 10; sh++)

	{

	int count;      //Вид корабля

	switch (sh)

	  {

	  case 0: count = 3; break;

	  case 1: count = 2; break;

	  case 2: count = 2; break;

	  case 3: count = 1; break;

	  case 4: count = 1; break;

	  case 5: count = 1; break;

	  default: count = 0;

	  }

	cl = false;

	//Заполнение массива доступных направлений

	for (int k = 0; k < 4; k++)

	  arrdir[k] = k;

	//Выбор случайного поля

M2:	do

	  {

	  Randomize();

	  xc = Random(100);

	  //Сверить, доступно ли оно

	  if (xc == arr[xc])

		{

		cl = true;

		xx = xc;

		}

	  }

	while (!cl);



	//Выбор направления корабля

M1:	do

	  {

	  cl = false;

	  xx = xc;            //Запомнить выбранное поле

	  //Проверка на существование невыбранных направлений

	  for (int m = 0; m < 4; m++)

		if (arrdir[m] != -1) { cl = true; break; }

	  if (!cl)

		{

		//Заполнение массива направлений

		for (int k = 0; k < 4; k++)

		  arrdir[k] = k;

		goto M2;    //Переход к выбору нового поля

		}

	  //Выбор направления

	  do

		{

		cl = false;

		Randomize();

		dir = Random(4);

		//Проверка на доступность направления

		if (dir == arrdir[dir])

		  {

		  arrdir[dir] = -1;

		  cl = true;

		  }

		}

	  while (!cl);



	 //Проверка на то, впишется ли корабль

	 cl = false;

	  switch (dir)

		{

		case 0: if (xx%10 >= count) cl = true; break;

		case 1: if (xx - 10*count >= 0) cl = true; break;

		case 2: if (xx%10 <= 9 - count) cl = true; break;

		case 3: if (99 - xx >= 10*count) cl = true; break;

		}

	  }

	while (!cl);



	//Проверка расположения других кораблей относительно полей данного

	for (int j = 0; j < count + 1; j++)

	  {

	  cl = false;

	  //Переход в зависимости от направления

	  switch (dir)

		{

		case 0: if (xx%10) xx -= 1; break;

		case 1: if ((int)(xx/10)) xx -= 10; break;

		case 2: if ((xx%10) != 9) xx += 1; break;

		case 3: if ((int)(xx/10) != 9 )xx += 10; break;

		}

	  //Проверка на доступность

	  if (xx == arr[xx])

		cl = true;

	  //Иначе переход к выбору другого направления

	  if (!cl) goto M1;

	  }



	//Заполнение массива в соответствии с положением корабля

	//и прорисовка кораблей

	int coor_x = xc%10, coor_y = (int)(xc/10);



	switch (dir)

		{

		case 0: Ships2[sh]->Width = (count+1)*29;

				Ships2[sh]->Height = 29;

				Ships2[sh]->Left = (coor_x-count)*29;

				Ships2[sh]->Top = coor_y*29;

				Ships2[sh]->ColCount = count+1;

				Ships2[sh]->RowCount = 1; break;

		case 1: Ships2[sh]->Width = 29;

				Ships2[sh]->Height = (count+1)*29;

				Ships2[sh]->Left = coor_x*29;

				Ships2[sh]->Top = (coor_y-count)*29;

				Ships2[sh]->ColCount = 1;

				Ships2[sh]->RowCount = count+1; break;

		case 2: Ships2[sh]->Width = (count+1)*29;

				Ships2[sh]->Height = 29;

				Ships2[sh]->Left = coor_x*29;

				Ships2[sh]->Top = coor_y*29;

				Ships2[sh]->ColCount = count+1;

				Ships2[sh]->RowCount = 1; break;

		case 3: Ships2[sh]->Width = 29;

				Ships2[sh]->Height = (count+1)*29;

				Ships2[sh]->Left = coor_x*29;

				Ships2[sh]->Top = coor_y*29;

				Ships2[sh]->ColCount = 1;

				Ships2[sh]->RowCount = count+1; break;

		}



	for (int i = 0; i < count + 1; i++)

	  {

	  field2[coor_y][coor_x] = 1;

	  switch (dir)

		{

		case 0: coor_x--; break;

		case 1: coor_y--; break;

		case 2: coor_x++; break;

		case 3: coor_y++; break;

		}

	  }



	//Заполнение границ вокруг корабля недоступными значениями

	//с учетом границ поля боя и выбранного направления

	int bord1 = 0, bord2 = 0, bord3 = 0, bord4 = 0;

	switch (dir)

	  {

	  case 0: if (!(coor_x + 1))

				bord1 = 1;

			  else

				if (coor_x + count + 1 == 9)

				  bord3 = 1;

			  if (!coor_y)

				bord2 = 1;

			  else

				if (coor_y == 9)

				  bord4 = 1;

			  for (int u = -1 + bord2; u < 2 - bord4; u++)

				for (int v = -1*(count + 1) + bord1; v < 2 - bord3; v++)

					arr[xc+u*10+v] = -1;

			  break;

	  case 1: if (!coor_x)

				bord1 = 1;

			  else

				if (coor_x == 9)

				  bord3 = 1;

			  if (!(coor_y + 1))

				bord2 = 1;

			  else

				if (coor_y + count + 1 == 9)

				  bord4 = 1;

			  for (int u = -1*(count + 1) + bord2; u < 2 - bord4; u++)

				for (int v = -1 + bord1; v < 2 - bord3; v++)

					arr[xc+u*10+v] = -1;

			  break;

	  case 2: if (!(coor_x - count - 1))

				bord1 = 1;

			  else

				if (coor_x - 1 == 9)

				  bord3 = 1;

			  if (!coor_y)

				bord2 = 1;

			  else

				if (coor_y == 9)

				  bord4 = 1;

			  for (int u = -1 + bord2; u < 2 - bord4; u++)

				for (int v = -1 + bord1; v < count + 2 - bord3; v++)

					arr[xc+u*10+v] = -1;

			  break;

	  case 3: if (!coor_x)

				bord1 = 1;

			  else

				if (coor_x == 9)

				  bord3 = 1;

			  if (!(coor_y - count - 1))

				bord2 = 1;

			  else

				if (coor_y - 1 == 9)

				  bord4 = 1;

			  for (int u = -1 + bord2; u < count + 2 - bord4; u++)

				for (int v = -1 + bord1; v < 2 - bord3; v++)

					arr[xc+u*10+v] = -1;

			  break;

	  }



	}

}



//Перетаскивание кораблей над полем

void __fastcall TSeaButForm::GridField1DragOver(TObject *Sender,

	  TObject *Source, int X, int Y, TDragState State, bool &Accept)

{

Accept = Source->ClassNameIs("TDrawGrid");

TDrawGrid *S = (TDrawGrid *) Source;

S->DragCursor = (Controls::TCursor)5;   //Изменение курсора

//Изменение координат корабля в соответствии с положением указателя мыши

S->Top = Y - Y%29;

S->Left = X - X%29;

//Проверка границ поля

if (S->Left + S->Width > 300)

  switch ((int)S->Tag/100)

   {

   case 4: S->Left = 174; break;

   case 3: S->Left = 203; break;

   case 2: S->Left = 232; break;

   case 1: S->Left = 261; break;

   }

if (S->Top + S->Height > 300)

  switch ((int)S->Tag/100)

   {

   case 4: S->Top = 174; break;

   case 3: S->Top = 203; break;

   case 2: S->Top = 232; break;

   case 1: S->Top = 261; break;

   }

}



//Возможность перетаскивания при положении курсора над кораблем

void __fastcall TSeaButForm::ShipsDragOver(TObject *Sender, TObject *Source,

	  int X, int Y, TDragState State, bool &Accept)

{

TDrawGrid *S = (TDrawGrid *) Source;

Accept = Source->ClassNameIs("TDrawGrid");

S->DragCursor = (Controls::TCursor)5;     //Изменение курсора

}



//При перетаскивании корабля над формой

void __fastcall TSeaButForm::FormDragOver(TObject *Sender, TObject *Source,

	  int X, int Y, TDragState State, bool &Accept)

{

TDrawGrid *S = (TDrawGrid *)Source;

S->DragCursor = (Controls::TCursor)7;      //Изменение курсора

}



//Изменение положения корабля при нажатии правой кнопки мыши

void __fastcall TSeaButForm::ShipsMouseDown(TObject *Sender,

	  TMouseButton Button, TShiftState Shift, int X, int Y)

{

TDrawGrid *S = (TDrawGrid *) Sender;

//Проверка нажатой кнопки

if (Button == mbRight)

  {

  PlaySound("Sounds\\SOUNPLAS.WAV", 0, SND_ASYNC);

  //Определение положения и замена на противоположное

  if (S->Width > 29)

	{

	S->Height = S->Width;

	S->Width = 29;

	S->RowCount = S->ColCount;

	S->ColCount = 1;

	}

  else

	{

	S->Width = S->Height;

	S->Height = 29;

	S->ColCount = S->RowCount;

	S->RowCount = 1;

	}

  }

//Проверка границ поля

if (S->Left + S->Width > 300)

  switch ((int)S->Tag/100)

   {

   case 4: S->Left = 174; break;

   case 3: S->Left = 203; break;

   case 2: S->Left = 232; break;

   case 1: S->Left = 261; break;

   }

if (S->Top + S->Height > 300)

  switch ((int)S->Tag/100)

   {

   case 4: S->Top = 174; break;

   case 3: S->Top = 203; break;

   case 2: S->Top = 232; break;

   case 1: S->Top = 261; break;

   }



}



//О программе

void __fastcall TSeaButForm::AboutClick(TObject *Sender)

{

//Запоминание изображения канвы

SaveBM (1);

SaveBM (2);

//Показать окно

AboutProg->Position = poMainFormCenter;

AboutProg->Visible = Enabled;

}



//Интерфейс игры с компьютером

void __fastcall TSeaButForm::CompClick(TObject *Sender)

{

//Если выбран интерфейс игры с человеком

if (Human->Checked)

  {

  PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

  //Активизация элементов интерфейса и удаление кораблей

  Field2->Enabled = false;

  DelShips (2);

  Comp->Checked = !Comp->Checked;

  Human->Checked = !Human->Checked;

  Fight->Enabled = true;

  FrameReady1->Visible = false;

  FrameReady2->Visible = false;

  FIGHT->FlashEnabled = true;

  FrameAgain->Enabled = true;

  RichEdit2->ReadOnly = true;

  RichEdit2->Lines->Strings[0] = "Machine";

  }

}



//Интерфейс игры с человеком

void __fastcall TSeaButForm::HumanClick(TObject *Sender)

{

//Если выбран интерфейс игры с компьютером

if (Comp->Checked)

  {

  PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

  //Активизация элементов интерфейса и создание кораблей

  Field2->Enabled = true;

  NewShips (2);

  Human->Checked = !Human->Checked;

  Comp->Checked = !Comp->Checked;

  Fight->Enabled = false;

  FrameReady1->Visible = true;

  FrameReady2->Visible = true;

  Ready1->Enabled = true;

  Ready2->Enabled = false;

  FrameReady1->Enabled = true;

  FrameReady2->Enabled = false;

  Field2->Enabled = false;

  FIGHT->FlashEnabled = false;

  FrameAgain->Enabled = false;

  RichEdit2->ReadOnly = false;

  RichEdit2->Lines->Strings[0] = "Player 2";

  }

}





//Выбор начала боя

void __fastcall TSeaButForm::FightClick(TObject *Sender)

{

//Определение интерфейса

if (Comp->Checked)

  {

  bool AllRight = CheckShips (1);  //Проверить расположение кораблей



  //Если все в порядке

  if (AllRight)

	{

	//Звук и смена курсоров на боевые

	PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

	GridField1->Cursor = (Controls::TCursor)6;

	GridField2->Cursor = (Controls::TCursor)6;



	//Активизация элементов

	Field2->Enabled = true;

	Field1->Enabled = false;



	CreateShips ();                //Случайное создание кораблей

	//Скрытие кораблей 1 поля

	for (int i = 0; i < 10; i++)

	  Ships1[i]->Visible = false;



	//Сохранение изображения канв

	SaveBM (1);

	SaveBM (2);



	Choise->Enabled = false;

	Fight->Enabled = false;

	//Переход к режиму боя

	GridField2->OnMouseDown = GridField1MouseDown;

	FIGHT->FlashEnabled = false;

	FrameAgain->Enabled = false;

	RichEdit1->ReadOnly = true;

	RichEdit1->Color = clRed;

	}

  }

else

  {

  //Звук и смена курсоров на боевые

  PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

  GridField1->Cursor = (Controls::TCursor)6;

  GridField2->Cursor = (Controls::TCursor)6;

  //Сохранение изображения канв

  SaveBM (1);

  SaveBM (2);



  //Активизация элементов

  FrameReady1->Visible = false;

  FrameReady2->Visible = false;

  Fight->Enabled = false;

  //Переход к режиму боя

  GridField1->OnMouseDown = GridField1MouseDown;

  GridField2->OnMouseDown = GridField1MouseDown;

  FIGHT->FlashEnabled = false;

  FrameAgain->Enabled = false;

  RichEdit1->Color = clRed;

  }

}



//Создать новую игру

void __fastcall TSeaButForm::NewGameClick(TObject *Sender)

{

//Звук и смена курсоров на начальные

PlaySound("Sounds\\SOUNOPEN.WAV", 0, SND_ASYNC);

GridField1->Cursor = (Controls::TCursor)1;

GridField2->Cursor = (Controls::TCursor)1;

//Обнуление данных

Count1Destr = 0;

Count2Destr = 0;

Shoots1->Caption = "0";

Shoots2->Caption = "0";

for (int i = 0; i < 10; i++)

  {

  Ships1Destr[i] = 0;

  Ships2Destr[i] = 0;

  }

GridField1->OnMouseDown = NULL;

GridField2->OnMouseDown = NULL;

//Активизация элементов

Choise->Enabled = true;

Field1->Enabled = true;

Field2->Enabled = false;

RichEdit1->Color = clNavy;

RichEdit2->Color = clNavy;

NewShips (1);

Delfield (1);

Delfield (2);

//Удаление изображений канвы

DelBM (1);

DelBM (2);



if (Comp->Checked)     //Режим игры с компьютером

  {

  NullCpu ();

  DelShips (2);

  FIGHT->FlashEnabled = true;

  FIGHT->OnClick = FightClick;

  FrameAgain->OnClick = FightClick;

  FrameAgain->Enabled = true;

  Fight->Enabled = true;

  RichEdit1->ReadOnly = false;

  //Очистка канвы 2 поля

  for (int i = 0; i < 10; i++)

	for (int j = 0; j < 10; j++)

	  GridField2->Canvas->FillRect(GridField2->CellRect(i,j));

  }

else                  //Режим игры с человеком

  {

  //Активизация элементов

  FIGHT->OnClick = FightClick;

  FrameAgain->OnClick = FightClick;

  FIGHT->FlashEnabled = false;

  FrameAgain->Enabled = false;

  Ready1->Enabled = true;

  Ready2->Enabled = false;

  FrameReady1->Enabled = true;

  FrameReady2->Enabled = false;

  FrameReady1->Visible = true;

  FrameReady2->Visible = true;

  RichEdit1->ReadOnly = false;

  RichEdit2->ReadOnly = false;

  NewShips (2);

  }

}



//Готовность 1го игрока

void __fastcall TSeaButForm::Ready1Click(TObject *Sender)

{

bool AllRight = CheckShips (1);     //Проверка кораблей 1го поля



if (AllRight)                       //Если все в порядке

  {

  PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

  //Активизация 2 поля

  //Скрытие кораблей 1 поля

  for (int i = 0; i < 10; i++)

	Ships1[i]->Visible = false;

  Field1->Enabled = false;

  Field2->Enabled = true;

  Ready1->Enabled = false;

  Ready2->Enabled = true;

  FrameReady1->Enabled = false;

  FrameReady2->Enabled = true;

  Choise->Enabled = false;

  RichEdit1->ReadOnly = true;

  }

}



//Готовность 2го игрока

void __fastcall TSeaButForm::Ready2Click(TObject *Sender)

{

bool AllRight = CheckShips (2);      //Проверка кораблей 2го поля



if (AllRight)                        //Если все в порядке

  {

  PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

  //Скрытие кораблей 1 поля

  for (int i = 0; i < 10; i++)

	Ships2[i]->Visible = false;

  Ready2->Enabled = false;

  FrameReady2->Enabled = false;

  Fight->Enabled = true;

  FIGHT->FlashEnabled = true;

  FrameAgain->Enabled = true;

  RichEdit2->ReadOnly = true;

  }

}



//Метод выстрела

void __fastcall TSeaButForm::GridField1MouseDown(TObject *Sender,

	  TMouseButton Button, TShiftState Shift, int X, int Y)

{

//Переменная для дальнейшего опредления поля

TDrawGrid *Field = (TDrawGrid *) Sender;

//Координаты выстрела

int xp = (int)(X/29), yp = (int)(Y/29);

//Производить при нажатии левой кнопки

if (Button == mbLeft)

  {

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

  //для сохранения изображения

  SetWindow (0);

  //Проверка поля

  if (Field->Tag == 1)

  {

  //Если произошло попадание

  if (field1[yp][xp] == 1)

	{

	//Звук и увеличение количества выстрелов

	PlaySound("Sounds\\SOUNBROK.WAV", 0, SND_ASYNC);

	Shoots2->Caption = IntToStr(StrToInt(Shoots2->Caption)+1);



	field1[yp][xp] = 3;   //На месте выстрела поставить метку 3

	//Графически показать попадание

	SeaDraw (1,xp,yp,true);

	linex = xp*29 + 24;

	liney = yp*29 + 3;

	Timer1->Enabled = true;



	//Переменные для определения границ, направления и необходимые для

	//определения убитого корабля и выставления "мимо" вокруг него

	int dir = 0, temp = 0, count = 0;

	bool bord1 = !xp, bord2 = !yp, bord3 = !(9-xp), bord4 = !(9-yp);



	//Определение вспомогательных переменных

	if (!bord1)

	  if ((field1[yp][xp-1] == 3))

		{

		dir = 1;

		temp = xp;

		goto M1;

		}

	if (!bord2)

	  if ((field1[yp-1][xp] == 3))

		{

		dir = 2;

		temp = yp;

		goto M1;

		}

	if (!bord3)

	  if ((field1[yp][xp+1] == 3))

		{

		dir = 1;

		temp = xp;

		goto M1;

		}

	if (!bord4)

	  if ((field1[yp+1][xp] == 3))

		{

		dir = 2;

		temp = yp;

		goto M1;

		}



	//Логическая переменная для обозначения, убит ли корабль

M1:	bool emp = false;

	//Условие на направление корабля, если влево

	if (dir == 1)

	  {

	  //Условие на приграничность корабля

	  if (!bord1)

		//Переходим к самому левому раненому полю

		while (field1[yp][temp]==3)

		  {

		  //Если дошли до границы

		  if (!temp)

			{

			bord1;

			break;

			}

		  //Если дошли до нераненного поля

		  if (field1[yp][temp--]==1)

			{

			emp = true;

			break;

			}

		  };

	  //В случае, если ушли от корабля влево, увеличиваем temp

	  if ((field1[yp][temp]==0)||(field1[yp][temp]==2)) temp++;



	  //Если не было нераненных полей

	  if (!emp)

		//Теперь идем до конца корабля вправо

		for (int i = 0; i < 5; i++)

		  {

		  //Определение границы справа

		  if (temp+i == 10)

			{

			bord3 = true;

			break;

			}

		  //Если ранен, то идем дальше, увеличиваем

		  //количество палуб корабля

		  if (field1[yp][temp+i]==3)  count++;

		  else  //Если есть нераненое поле, то закончить проверку

				//И показать, что корабль не убит

			if (field1[yp][temp+i]==1)

			  {

			  emp = true;

			  break;

			  }

			//Иначе, он убит, проверка закончена

			else break;

		  }



	  if (!emp)

		{

		PlaySound("Sounds\\SOUNDESTR.WAV", 0, SND_ASYNC);

		Count1Destr++;    //Увеличиваем количество убитых кораблей

		//Заполняем массив убитых кораблей

		switch (count)

		  {

		  case 2: for (int dsh = 4; dsh < 7; dsh++)

					if (!Ships1Destr[dsh])

					  {

					  Ships1Destr[dsh] = 1;

					  break;

					  } break;

		  case 3: for (int dsh = 7; dsh < 9; dsh++)

					if (!Ships1Destr[dsh])

					  {

					  Ships1Destr[dsh] = 1;

					  break;

					  } break;

		  default: Ships1Destr[9] = 1;

		  }

		//В случае игры с компьютером

		if (Comp->Checked)

		  {

		  //Указываем, что корабль убит

		  Cpu.TarDir = false;

		  Cpu.Target = false;

		  Cpu.TarDirect = false;

		  Cpu.TarDestr = true;

		  }

		//Заполняем поля вокруг корабля

		for (int u = yp-1+bord2; u < yp+2-bord4; u++)

		  for (int v = temp - 1 + bord1; v < temp + count + 1 - bord3; v++)

			if (field1[u][v] == 0)

			  {

			  field1[u][v] = 2;

			  SeaDraw (1,v,u,false);

			  }

		}

	  }



	//В случае вертикального расположения корабля

	//повторяем аналогичные процессы

	if (dir == 2)

	  {

	  if (!bord2)

		while (field1[temp][xp]==3)

		  {

		  if (!temp)

			{

			bord2 = true;

			break;

			}

		  if (field1[temp--][xp]==1)

			{

			emp = true;

			break;

			}

		  };

	  if ((field1[temp][xp]==0)||(field1[temp][xp]==2)) temp++;



	  if (!emp)

		for (int i = 0; i < 5; i++)

		  {

		  if (temp+i == 10)

			{

			bord4 = true;

			break;

			}

		  if (field1[temp+i][xp]==3)  count++;

		  else

			if (field1[temp+i][xp]==1)

			  {

			  emp = true;

			  break;

			  }

			else break;

		  }



	  if (!emp)

		{

		PlaySound("Sounds\\SOUNDESTR.WAV", 0, SND_ASYNC);

		Count1Destr++;

		switch (count)

		  {

		  case 2: for (int dsh = 4; dsh < 7; dsh++)

					if (!Ships1Destr[dsh])

					  {

					  Ships1Destr[dsh] = 1;

					  break;

					  } break;

		  case 3: for (int dsh = 7; dsh < 9; dsh++)

					if (!Ships1Destr[dsh])

					  {

					  Ships1Destr[dsh] = 1;

					  break;

					  } break;

		  default: Ships1Destr[9] = 1;

		  }

		if (Comp->Checked)

		  {

		  Cpu.TarDir = false;

		  Cpu.Target = false;

		  Cpu.TarDirect = false;

		  Cpu.TarDestr = true;

		  }

		for (int u = temp - 1 + bord2; u < temp + count + 1 - bord4; u++)

		  for (int v = xp-1+bord1; v < xp+2-bord3; v++)

			if (field1[u][v] == 0)

			  {

			  field1[u][v] = 2;

			  SeaDraw (1,v,u,false);

			  }

		}

	  }



	//Если убит однопалубный корабль

	//повторяем те же процессы

	if ((dir == 0) && (field1[yp][xp-1+bord1]!=1) && (field1[yp-1+bord2][xp]!=1)

		&& (field1[yp][xp+1-bord3]!=1) && (field1[yp+1-bord4][xp]!=1))

	  {

	  PlaySound("Sounds\\SOUNDESTR.WAV", 0, SND_ASYNC);

	  Count1Destr++;

	  for (int dsh = 0; dsh < 4; dsh++)

		if (!Ships1Destr[dsh])

		  {

		  Ships1Destr[dsh] = 1;

		  break;

		  }

	  if (Comp->Checked)

		{

		Cpu.TarDir = false;

		Cpu.Target = false;

		Cpu.TarDirect = false;

		Cpu.TarDestr = true;

		}

	  for (int u = yp - 1 + bord2; u < yp + 2 - bord4; u++)

		  for (int v = xp - 1 + bord1; v < xp + 2 - bord3; v++)

			if (field1[u][v] == 0)

			  {

			  field1[u][v] = 2;

			  SeaDraw (1,v,u,false);

			  }

	  }

	}



  //Если произошло попадание в "молоко"

  if (field1[yp][xp] == 0)

	{

	PlaySound("Sounds\\SOUNMILK.WAV", 0, SND_ASYNC);

	Shoots2->Caption = IntToStr(StrToInt(Shoots2->Caption)+1);

	//Указываем компьютеру, что выбрано неправильное направление

	if (Comp->Checked)

	  Cpu.TarDirect = false;

	//Ставим метку стреленого места

	field1[yp][xp] = 2;

	//Указываем графически

	SeaDraw (1,xp,yp,false);

	//Позволяем стрелять другому игроку

	Field1->Enabled = false;

	Field2->Enabled = true;

	RichEdit2->Color = clNavy;

	RichEdit1->Color = clRed;

	}

  }

  //Если стрельба проводится по 2му полю

  //то делать то же самое для него

  else

  {……………

  }

  //Сохранить изображение канв

  SaveBM (1);

  SaveBM (2);

  //Если стрельбу не производит компьютер

  if (!Timer2->Enabled && !Timer1->Enabled)

	SetWindow (1);  //Восстановить первоначальные свойства окна

  }

}



//Таймер для прорисовки линий и стрельбы компьютера

void __fastcall TSeaButForm::Timer1Timer(TObject *Sender)

{

//Проверка активного поля

if (Field1->Enabled)

  {

  //Дорисовать линию через время

  GridField1->Canvas->LineTo(linex,liney);

  //Выключить таймер

  Timer1->Enabled = false;

  //Если убиты не все корабли

  if (Count1Destr != 10)

	{

	//Если компьютер стреляет, то указать необходимые

	//ему атрибуты

	if (Comp->Checked)

	  {

	  if (Cpu.Target)

		{

		if (Cpu.TarDir)

		  Cpu.TarDirect = true;

		else

		  {

		  Cpu.TarDir = true;

		  switch (Cpu.Direction)

			{

			case 0: Cpu.RowDir[1] = -1; Cpu.RowDir[3] = -1; break;

			case 1: Cpu.RowDir[0] = -1; Cpu.RowDir[2] = -1; break;

			case 2: Cpu.RowDir[1] = -1; Cpu.RowDir[3] = -1; break;

			case 3: Cpu.RowDir[0] = -1; Cpu.RowDir[2] = -1; break;

			}

		  Cpu.TarDirect = true;

		  }

		}

	  else

		if (!Cpu.TarDestr)

		  Cpu.Target = true;

	  //Включить 2ой таймер

	  Timer2->Enabled = true;

	  }

	else  SetWindow (1);  //Если стреляет игрок восстановить окно

	}

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

  else

	{

	//Воспроизвести разные звуки в зависимости от того

	//человек или компьютер играл

	if (Comp->Checked)

	  PlaySound("Sounds\\Sounholi.wav", 0, SND_ASYNC);

	else

	  PlaySound("Sounds\\Sounhihi.wav", 0, SND_ASYNC);

	//Активизация элементов

	for (int i = 0; i < 10; i++)

	  Ships2[i]->Visible = true;

	Field1->Enabled = false;

	SetWindow(1);

	FrameAgain->Enabled = true;

	FIGHT->OnClick = NewGameClick;

	FrameAgain->OnClick = NewGameClick;

	SaveRes (2);

	Timer3->Enabled = true;

	}

  //Сохранить изображение канвы1

  SaveBM (1);

  }

//При стрельбе по 2му полю

else

  {

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

  GridField2->Canvas->LineTo(linex,liney);

  Timer1->Enabled = false;



  //Сохранить изображение

  SaveBM (2);

  //восстановить окно

  SetWindow (1);

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

  if (Count2Destr == 10)

	{

	PlaySound("Sounds\\Sounhihi.wav", 0, SND_ASYNC);  //звук победы

	//Активизация элементов

	for (int i = 0; i < 10; i++)

	  Ships1[i]->Visible = true;

	Field2->Enabled = false;

	FrameAgain->Enabled = true;    	//Для быстрого начала новой игры

	FIGHT->OnClick = NewGameClick;

	FrameAgain->OnClick = NewGameClick;

	SaveRes (1);              		//Сохранить результаты

	Timer3->Enabled = true;

	}

  }



}



//Функция выстрелов компьютера

void TSeaButForm::CompShot ()

{

bool cl = false;       //Логическая переменная

int x = 0, y = 0;      //Координаты выстрела



//Определение ненужных координат

for (int i = 0; i < 10; i++)

  for (int j = 0; j < 10; j++)

	if ((field1[i][j]!=1) && (field1[i][j]!=0))

	  Cpu.RowNum[10*i + j] = -1;



//Если не было попадания

if (!Cpu.Target)

  {

  CheckDestr ();    //Проверка на необходимость стрельбы по всем полям

  //Заполнение массива направлений стрельбы

  for (int i = 0; i < 4; i++)

	  Cpu.RowDir[i] = i;

  //Обнуление переменных, показывающих попадания по кораблю

  Cpu.Direction = -1;

  Cpu.TarDestr = false;

  //Выбор случайного поля

  do

	{

	Randomize();

	Cpu.Choice = Random(100);

	Choice = Cpu.Choice;

	//Проверка на доступность

	if (Choice == Cpu.RowNum[Choice])

	  {

	  cl = true;

	  Cpu.RowNum[Choice] = -1;

	  }

	}

  while (!cl);

  }

//Если же было попадание

else

  {

  //Если неизвестно положение корабля

  if (!Cpu.TarDir)

  //Выбираем его случайно

  do

	{

	Choice = Cpu.Choice;

	Randomize();

	Cpu.Direction = Random(4);

	//Сверяем на его доступность

	if (Cpu.Direction == Cpu.RowDir[Cpu.Direction])

	  {

	  cl = true;

	  Cpu.RowDir[Cpu.Direction] = -1;   //Запоминаем его

	  //Проверка на границы и на доступность этого поля

	  //Если недоступно, то повторить выбор

	  switch (Cpu.Direction)

		{

		case 0: if (!(Choice%10))

				  {

				  cl = false; break;

				  }

				else

				  if (Cpu.RowNum[Choice-1] == -1)

					{

					cl = false; break;

					}

				break;

		case 1: if (!(int)(Choice/10))

				  {

				  cl = false; break;

				  }

				else

				  if (Cpu.RowNum[Choice-10] == -1)

					{

					cl = false; break;

					}

				break;

		case 2: if (Choice%10 == 9)

				  {

				  cl = false; break;

				  }

				else

				  if (Cpu.RowNum[Choice+1] == -1)

					{

					cl = false; break;

					}

				break;

		case 3: if ((int)(Choice/10) == 9)

				  {

				  cl = false; break;

				  }

				else

				  if (Cpu.RowNum[Choice+10] == -1)

					{

					cl = false; break;

					}

				break;

		}

	  }

	}

  while (!cl);

  //Если же известно положение корабля

  else

	//Проверяем, верно ли выбрано было направление его

	if (!Cpu.TarDirect)

	  {

	  //Если нет, тогда меняем на противоположное

M3:	  switch (Cpu.Direction)

		  {

		  case 0: Cpu.Direction = 2; Choice = Cpu.Choice; break;

		  case 1: Cpu.Direction = 3; Choice = Cpu.Choice; break;

		  case 2: Cpu.Direction = 0; Choice = Cpu.Choice; break;

		  case 3: Cpu.Direction = 1; Choice = Cpu.Choice; break;

		  }

	  Cpu.TarDirect = true;

	  }

  }



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

if (Cpu.Direction == -1)        //Если производится первый выстрел

  {

  x = Choice%10;

  y = (int)(Choice/10);

  }

else

  {

  //Когда уже выбрано направление, проверяем на граничность

  //и на доступность поля, если все в порядке, то выстрел можно выполнять

  //И тогда можно подтвердить выбор

  switch (Cpu.Direction)

	  {

	  case 0: if (!(Choice%10))

					goto M3;

				  else

					if (Cpu.RowNum[Choice-1] == -1)

					  goto M3;

			  Choice--; Cpu.RowNum[Choice] = -1; break;

	  case 1: if (!(int)(Choice/10))

					goto M3;

				  else

					if (Cpu.RowNum[Choice-10] == -1)

					  goto M3;

			  Choice-=10; Cpu.RowNum[Choice] = -1; break;

	  case 2: if (Choice%10 == 9)

					goto M3;

				  else

					if (Cpu.RowNum[Choice+1] == -1)

					  goto M3;

			  Choice++; Cpu.RowNum[Choice] = -1; break;

	  case 3: if ((int)(Choice/10) == 9)

					goto M3;

				  else

					if (Cpu.RowNum[Choice+10] == -1)

					  goto M3;

			  Choice+=10; Cpu.RowNum[Choice] = -1; break;

	  }

  //И определяем координаты

  x = Choice%10;

  y = (int)(Choice/10);

  }



TShiftState Shift;    //Пустая переменная для передачи в функцию выстрела



//Производим выстрел

GridField1MouseDown (GridField1, mbLeft, Shift, 29*x + 1, 29*y + 1);

}



//Проверка на необходимость выстрела по каждому полю

void TSeaButForm::CheckDestr ()

{

int len = 0;       //Переменная указывает для какого вида корабля проверяем

//Определяем все ли 1палубные убиты

for (int i = 0; i < 4; i++)

  if (Ships1Destr[i])

	if (i == 3)

	  len++;

	else continue;

  else break;

if (!len) return;   //Если нет, то выйти из функции



//Проверяем для 1палубных

for (int d1 = 0; d1 < 100; d1++)

  //Если нашли доступное поле

  if (Cpu.RowNum[d1] != -1)

	{

	//Проверяем на то, есть ли вокруг него доступные поля

	if (d1%10)

	  if (Cpu.RowNum[d1-1] != -1) continue;

	if (d1>9)

	  if (Cpu.RowNum[d1-10] != -1) continue;

	if (d1%10 < 9)

	  if (Cpu.RowNum[d1+1] != -1) continue;

	if (d1<90)

	  if (Cpu.RowNum[d1+10] != -1) continue;

	  else  Cpu.RowNum[d1] = -1;     //Если нету, то делаем поле недоступным

	else Cpu.RowNum[d1] = -1;

	}



//Если 1палубные убиты, то определяем все ли 2палубные убиты

if (len)

  for (int i = 4; i < 7; i++)

	if (Ships1Destr[i])

	  if (i == 6)

		len++;

	  else continue;

	else break;

if (len == 1) return;



//Делаем аналогичную проверку, как и 1 палубных

//Только смотрим на ближайшие 2 поля вокруг выбранного

for (int d1 = 0; d1 < 100; d1++)

  if (Cpu.RowNum[d1] != -1)

	{

	if (d1%10)

	  if (Cpu.RowNum[d1-1] != -1)

		if (d1%10>1)

		  {

		  if (Cpu.RowNum[d1-2] != -1) continue;

		  else

			if (d1%10<9)

			  if (Cpu.RowNum[d1+1] != -1) continue;

		  }

		else

		  if (Cpu.RowNum[d1+1] != -1) continue;

	if (d1>9)

	  if (Cpu.RowNum[d1-10] != -1)

		if (d1>19)

		  {

		  if (Cpu.RowNum[d1-20] != -1) continue;

		  else

			if (d1<90)

			  if (Cpu.RowNum[d1+10] != -1) continue;

		  }

		else

		  if (Cpu.RowNum[d1+10] != -1) continue;



	if (d1%10<9)

	  if (Cpu.RowNum[d1+1] != -1)

		if (d1%10<8)

		  if (Cpu.RowNum[d1+2] != -1) continue;



	if (d1<90)

	  if (Cpu.RowNum[d1+10] != -1)

		if (d1<80)

		  if (Cpu.RowNum[d1+20] != -1) continue;

		  else  Cpu.RowNum[d1] = -1;

		else  Cpu.RowNum[d1] = -1;

	  else  Cpu.RowNum[d1] = -1;

	else  Cpu.RowNum[d1] = -1;

	}



//Аналогично для 3 палубных

if (len == 2)

  for (int i = 7; i < 9; i++)

	if (Ships1Destr[i])

	  if (i == 8)

		len++;

	  else continue;

	else break;

if (len == 2) return;



for (int d1 = 0; d1 < 100; d1++)

  if (Cpu.RowNum[d1] != -1)

	{

	if (d1%10)

	  if (Cpu.RowNum[d1-1] != -1)

		{

		if (d1%10>1)

		  {

		  if (Cpu.RowNum[d1-2] != -1)

			{

			if (d1%10>2)

			  {

			  if (Cpu.RowNum[d1-3] != -1) continue;

			  else

				if (d1%10<9)

				  if (Cpu.RowNum[d1+1] != -1) continue;

			  }

			else

			  if (Cpu.RowNum[d1+1] != -1) continue;

			}

		  else

			if (d1%10<9)

			  if (Cpu.RowNum[d1+1] != -1)

				if (d1%10<8)

				  if (Cpu.RowNum[d1+2] != -1) continue;

		  }

		else

		  if (Cpu.RowNum[d1+1] != -1)

			if (Cpu.RowNum[d1+2] != -1) continue;

		}



	if (d1>9)

	  if (Cpu.RowNum[d1-10] != -1)

		{

		if (d1>19)

		  {

		  if (Cpu.RowNum[d1-20] != -1)

			{

			if (d1>29)

			  {

			  if (Cpu.RowNum[d1-30] != -1) continue;

			  else

				if (d1<90)

				  if (Cpu.RowNum[d1+10] != -1) continue;

			  }

			else

			  if (Cpu.RowNum[d1+10] != -1) continue;

			}

		  else

			if (d1<90)

			  if (Cpu.RowNum[d1+10] != -1)

				if (d1<80)

				  if (Cpu.RowNum[d1+20] != -1) continue;

		  }

		else

		  if (Cpu.RowNum[d1+10] != -1)

			if (Cpu.RowNum[d1+20] != -1) continue;

		}



	if (d1%10<9)

	  if (Cpu.RowNum[d1+1] != -1)

		if (d1%10<8)

		  if (Cpu.RowNum[d1+2] != -1)

			if (d1%10<7)

			  if (Cpu.RowNum[d1+3] != -1) continue;



	if (d1<90)

	  if (Cpu.RowNum[d1+10] != -1)

		if (d1%10<80)

		  if (Cpu.RowNum[d1+20] != -1)

			if (d1%10<70)

			  if (Cpu.RowNum[d1+30] != -1) continue;

			  else  Cpu.RowNum[d1] = -1;

			else  Cpu.RowNum[d1] = -1;

		  else  Cpu.RowNum[d1] = -1;

		else  Cpu.RowNum[d1] = -1;

	  else  Cpu.RowNum[d1] = -1;

	else  Cpu.RowNum[d1] = -1;

	}



}



//Таймер для замедления выстрелов компьютера

void __fastcall TSeaButForm::Timer2Timer(TObject *Sender)

{

Timer2->Enabled = false;

CompShot ();

}



//Прорисовка канвы на форме из сохраненного изображения

void __fastcall TSeaButForm::FormPaint(TObject *Sender)

{

if (Bitmap1)

  {

  GridField1->Canvas->CopyRect(Rect(0,0,300,300),Bitmap1->Canvas,Rect(0,0,300,300));

  GridField2->Canvas->CopyRect(Rect(0,0,300,300),Bitmap2->Canvas,Rect(0,0,300,300));

  }

}



//Сохранение изображения канв

void TSeaButForm::SaveBM (int number)

{

//Для какого поля необходимо сохранить изображение

if (number == 1)

  {

  if (!Bitmap1)

	{

	Bitmap1 = new Graphics::TBitmap ();

	Bitmap1->Height = 300;

	Bitmap1->Width = 300;

	}

  Bitmap1->Canvas->CopyRect(Rect(0,0,300,300),GridField1->Canvas,Rect(0,0,300,300));

  }

else

  {

  if (!Bitmap2)

	{

	Bitmap2 = new Graphics::TBitmap ();

	Bitmap2->Height = 300;

	Bitmap2->Width = 300;

	}

  Bitmap2->Canvas->CopyRect(Rect(0,0,300,300),GridField2->Canvas,Rect(0,0,300,300));

  }

}



//Установка свойств окна в нужный режим

void TSeaButForm::SetWindow (bool kind)

{

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

//0 - деактивация элементов

//1 - активация

if (!kind)

  {

  SeaButForm->FormStyle = fsStayOnTop;   //Сделать окно поверх

  TBorderIcons tempBI = BorderIcons;     //Убрать кнопки изменения размера окна

  tempBI >> biMinimize;

  BorderIcons = tempBI;

  File->Enabled = false;                 //деактивировать меню

  Help->Enabled = false;

  }

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

else

  {

  SeaButForm->FormStyle = fsNormal;

  TBorderIcons tempBI = BorderIcons;

  tempBI << biMinimize;

  BorderIcons = tempBI;

  File->Enabled = true;

  Help->Enabled = true;

  }

}



//Рисование на канве под номером number в поле с координатами

//xp b yp в случая попадания или непопадания. aim определяет попадание

void TSeaButForm::SeaDraw (int number, int xp, int yp, bool aim)

{

if (number == 1)

  if (aim)

	{

	GridField1->Canvas->MoveTo(xp*29+3,yp*29+3);

	GridField1->Canvas->LineTo(xp*29+24,yp*29+24);

	GridField1->Canvas->MoveTo(xp*29+3,yp*29+24);

	}

  else

	{

	GridField1->Canvas->Brush->Color = clBlack;

	GridField1->Canvas->Ellipse(xp*29+10,yp*29+10,xp*29+18,yp*29+18);

	GridField1->Canvas->FloodFill(xp*29+14,yp*29+14,clBlack,fsSurface);

	}

else

  if (aim)

	{

	GridField2->Canvas->MoveTo(xp*29+3,yp*29+3);

	GridField2->Canvas->LineTo(xp*29+24,yp*29+24);

	GridField2->Canvas->MoveTo(xp*29+3,yp*29+24);

	}

  else

	{

	GridField2->Canvas->Brush->Color = clBlack;

	GridField2->Canvas->Ellipse(xp*29+10,yp*29+10,xp*29+18,yp*29+18);

	GridField2->Canvas->FloodFill(xp*29+14,yp*29+14,clBlack,fsSurface);

	}

}



//Сохранение результатов. number - определяет того, кто выиграл

void TSeaButForm::SaveRes (int number)

{

ifstream infile ("SeaButResults.txt");

if (!infile) return;



int i = 0;

char temp1[300];

char *temp2 = NULL;

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

while (!infile.eof())

  {

  infile.get(temp1[i]);

  i++;

  }

temp1[i-1] = '\0';



int j = 0;

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

for (int i = 0; i < 10; i++)

  {

  //Если конец строки, то добавить результат

  //и все перенести в temp2

  if (!temp1[j])

	if (number == 1)

	  {

	  temp2 = new char [300];

	  for (int z = 0; z <= j; z++)

		temp2[z] = temp1[z];

	  strcat(temp2, RichEdit1->Lines->Strings[0].c_str());

	  strcat(temp2, "\n");

	  strcat(temp2, Shoots1->Caption.c_str());

	  int len = strlen(temp2);

	  temp2[len] = '\n';

	  temp2[len+1] = '\0';

	  break;

	  }

	else

	  {

	  temp2 = new char [300];

	  for (int z = 0; z <= j; z++)

		temp2[z] = temp1[z];

	  strcat(temp2, RichEdit2->Lines->Strings[0].c_str());

	  strcat(temp2, "\n");

	  strcat(temp2, Shoots2->Caption.c_str());

	  int len = strlen(temp2);

	  temp2[len] = '\n';

	  temp2[len+1] = '\0';

	  break;

	  }

  int pos = j;       					//запомнить позицию курсора

  while (temp1[j] != '\n') j++;    	 	//перейти к кол-ву выстрелов

  int count = 0;

  while (temp1[++j] != '\n') count++;   //определить кол-во знаков в числе

  int k, tempnumb = 0;

  for (count == 3 ? k = 100: k = 10; k >= 1; k/=10)

	tempnumb += ((int)temp1[j-count--]-48)*k;  //определяем кол-во выстрелов

  j++;

  //Сравниваем с выстрелами текущего результата

  //если больше, то вставляем перед проверяемым результатом

  if (number == 1)

	if (tempnumb > StrToInt(Shoots1->Caption))

	  {

	  temp2 = new char [300];

	  for (int z = 0; z < pos; z++)

		temp2[z] = temp1[z];

	  temp2[pos] = '\0';

	  strcat(temp2, RichEdit1->Lines->Strings[0].c_str());

	  strcat(temp2, "\n");

	  strcat(temp2, Shoots1->Caption.c_str());

	  int len = strlen(temp2);

	  temp2[len] = '\n';

	  while (temp1[pos])

		temp2[++len] = temp1[pos++];

	  temp2[len+1] = '\0';

	  break;

	  }

  if (number == 2)

	if (tempnumb > StrToInt(Shoots2->Caption))

	  {

	  temp2 = new char [300];

	  for (int z = 0; z < pos; z++)

		temp2[z] = temp1[z];

	  temp2[pos] = '\0';

	  strcat(temp2, RichEdit2->Lines->Strings[0].c_str());

	  strcat(temp2, "\n");

	  strcat(temp2, Shoots2->Caption.c_str());

	  int len = strlen(temp2);

	  temp2[len] = '\n';

	  while (temp1[pos])

		temp2[++len] = temp1[pos++];

	  temp2[len+1] = '\0';

	  break;

	  }

  }



//Если результат попал в 10ку

//то отбрасываем 11 результат

if (temp2)

  {

  i = 0;

  int count = 0;

  while (temp2[i++])

	{

	if (temp2[i] == '\n') count++;

	if (count == 20)

	  {

	  temp2[i+1] = '\0';

	  break;

	  }

	}

  }

infile.close();



//Заносим temp2 в файл

if (temp2)

  {

  ofstream outfile ("SeaButResults.txt");

  if (!outfile) return;



  i = 0;



  while (temp2[i])

	outfile.put(temp2[i++]);

  delete [] temp2;

  outfile.close();

  }



}



//Таймер для показа победы

void __fastcall TSeaButForm::Timer3Timer(TObject *Sender)

{

static int k = 0;    //Количество обращений к таймеру

//Если дошло до 8

if (k == 8)

  {

  //Увеличить кол-во побед

  if (Count1Destr == 10)

	Wins2->Caption = IntToStr(StrToInt(Wins2->Caption)+1);

  else

	Wins1->Caption = IntToStr(StrToInt(Wins1->Caption)+1);

  k = 0;

  Timer3->Enabled = false;

  FIGHT->FlashEnabled = true;

  }

//Иначе изменить цвета метки

else

 {

  if (Count1Destr == 10)

	if (Win2->Font->Color == clBlack)

	  Win2->Font->Color = clSilver;

	else

	  Win2->Font->Color = clBlack;

  else

	if (Win1->Font->Color == clBlack)

	  Win1->Font->Color = clSilver;

	else

	  Win1->Font->Color = clBlack;

 k++;

 }



}



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

void __fastcall TSeaButForm::ResultsClick(TObject *Sender)

{

PlaySound("Sounds\\SOUNREST.WAV", 0, SND_ASYNC);

ResultsForm->Position = poMainFormCenter;

ResultsForm->Visible = true;

SeaButForm->Enabled = false;

ResultsForm->LoadRes();

}



//Изменение курсоров

//NameCur - имя файла

//Num - константа для запоминания курсора

void TSeaButForm::ChangeCur (char *NameCur, int Num)

{

HCURSOR cursor;

cursor = LoadCursorFromFile(NameCur);    //Загрузить из файла

if (cursor)

  Screen->Cursors[Num] = cursor;         //Занести в список 

}





2