- •Томский межвузовский центр дистанционного образования
- •Введение
- •Назначение работы и область ее применения. Постановка задачи
- •3.Используемые методы, описание алгоритма программы с описанием функций составных частей и связи между ними
- •Алгоритм размещения кораблей на игровом поле.
- •Описание входных и выходных данных
- •Руководство пользователя
- •Заключение
- •Список литературы
- •Приложение 1. Листинг программы
- •Приложение 2. Результаты работы
Назначение работы и область ее применения. Постановка задачи
Составить программу, моделирующую игру «Морской бой». Для этого программа должна отобразить на экране два игровых поля, одно из которых должно показывать состояние хода игрока, а другое состояние хода компьютера.
В ходе игры случайным образом для игрока и компьютера на поле (10*10) размещаются корабли в количестве: четыре однопалубных, три двухпалубных, два трехпалубных, один четырехпалубный. В процессе игры фиксируется ход игрока и реакция компьютера в соответствии с размещением кораблей на поле. Компьютер в свою очередь выдает координаты очередного хода с необходимостью подтверждения попадания в координаты размещения корабля игрока.
Результатом игры является попадание компьютером или игроком во все координаты размещения кораблей с выводом на экран координат попадания и промаха игрока.
3.Используемые методы, описание алгоритма программы с описанием функций составных частей и связи между ними
Алгоритм программы можно укрупненно записать следующим образом:
|
Ввод координат хода игрока |
|
Контроль совпадения координат с координатами размещения кораблей игрока на поле. |
|
Запись результатов в массив для последующего их считывания и вывода на экран. |
|
Формирование координат хода компьютера и вывод их на экран для подтверждения их совпадения с координатами размещения кораблей на поле игрока. |
|
Формирование координат хода в случае преведущего совпадения координат размещения кораблей на поле игрока и формирование стратегии обстрела соседних клеток для выяснения направления размещения корабля на поле игрока. |
|
Формирование некоторых переменных для записи состояния хода(количество убитых кораблей, состояние хода) |
|
Вывод на экран состояние хода. |
Алгоритм размещения кораблей на игровом поле.
Игровое поле нужно как-то хранить в памяти компьютера. Наиболее простая реализация - в виде матрицы 10x10 клеток (ячеек).
Обусловимся, что пустая ячейка будет иметь значение -1, а ячейка, в которой находится корабль: 0. Перед началом процесса размещения кораблей необходимо очистить поле. Помимо этого надо еще и обновить счетчик случайных чисел, что бы добиться реальной случайности позиций флота компьютера. Все эти действия лучше оформить в виде отдельной процедуры: procedure Init (var Pole: TPole);.
По правилам игры два корабля не могут соприкасаться друг с другом, т.е. между ними должно быть пустое пространство минимум в одну клетку. Нам понадобится вспомогательная функция, которая позволит определить, можно ли поставить однопалубный корабль в указанную ячейку или нет. Для этого необходимо проверить саму эту ячейку и все соседние (их 8 штук). И только если все они не заняты можно дать положительный ответ (True), в противном случае - отрицательный (False): function Freedom (x, y: Integer; Pole: TPole): Boolean;.
Как известно из правил игры, на поле должны находиться следующие корабли: один четырех палубный, два трехпалубных, три двухпалубных и четыре однопалубных. Процедура, расставляющая эти корабли должна выполнять следующие действия: взять случайную свободную ячейку и проверить, можно ли поставить текущий корабль горизонтально или вертикально. Если да, то корабль размещается на игровом поле и обработка переходит к следующему. Понятно, что если нет, то возвращаемся к выбору координат. Порядок действий должен быть от большего корабля к меньшему, что бы не возникла ситуация невозможности размещения ни в одну позицию поля. Это можно достичь с помощью процедуры: procedure Ships (var Pole: TPole);.
Это, собственно, и все, что касается размещения кораблей компьютера. Теперь достаточно сделать вызов: Ships (Pole); и корабли будут случайным образом расставлены по своим местам. Подобным образом помогаем пользователю, что бы он каждый раз не тратил время на эту операцию, вызвав Ship(Pole) .
Стратегия игры компьютера.
Задача заключается в разработке алгоритма, по которому компьютер сможет играть в "Морской бой" с максимальным качеством и при этом не подглядывая расположение флота игрока. Дополнительное и очевидное условие: при каждой новой игре вне зависимости от размещения сил противника компьютер должен играть по-разному, т.е. его ходы должны быть не предсказуемы. Необходимо вспомнить правила игры: участники поединка делают ходы поочередно, причем, если один из игроков попадает по кораблю соперника, то он получает право следующего хода. Если реализовать поиск цели компьютером в виде отдельной процедуры, то надо как-то научить его запоминать исходы прошлых выстрелов, чтобы адекватно произвести следующий. Из этого факта вытекает, что самое простое и рациональное решение данной проблемы можно оформить в виде конечного автомата, наиболее точно описывающего последовательность действий. Можно выделить три состояния:
1.Прострел игрового поля по случайным координатам до попадания по кораблю, после чего переход во второе состояние;
2.Обстрел вокруг подбитой ячейки поля для определения направления корабля (вертикальное или горизонтальное), после очередного попадания - переход в третье состояние;
3.Расстрел корабля в полученном направлении до полного его уничтожения, после чего переход в первое состояние.
И так, вся игра зациклена на трех основных действиях: прострел, обстрел и расстрел. Все эти действия должны продолжаться до тех пор, пока у одной из сторон не будут уничтожены все корабли.
Компьютеру потребуется еще одно поле, на котором он будет вести игру. Назовем его Play. Помимо этого нужно помнить, какие корабли остались у игрока, а какие уже разбиты.
Перед началом игры надо настроить все значения. Это удобно сделать в отдельной процедуре: procedure Start;.
Предположим, что у нас есть функция, которая выдает истину, если в ячейки (x,y) игрока стоит корабль и ложь в противном случае: function Killed (x, y: Integer): Boolean;. Еще потребуется функция, определяющая длину самого большого корабля игрока: function MaxShip: Integer;.
И функция, определяющая проигрыш игрока: function GameOver: Boolean;.
Для большей наглядности каждое состояние оформим в виде отдельной процедуры.
Прострел. На этом этапе компьютер должен поймать какой-либо из кораблей противника. Для этого он будет стрелять по произвольным незанятым клеткам поля игрока. Гораздо эффективнее сначала разделаться с большими кораблями, поэтому выбирая координаты для выстрела надо проверять, что бы в этой позиции мог разместиться самый большой из оставшихся кораблей. Процесс прекращается, как только произойдет попадание. Обозначим подбитую часть корабля значением 1, а промах -2 соответствующей ячейки поля. Если у игрока остались только однопалубные корабли, то этим попаданием корабль уничтожен полностью и обстреливать его нет смысла. В противном случае надо перейти ко второму состоянию. Это достигается с помощью функции: function State1 (var x, y: Integer): Boolean;.Ее результатом служат координаты выстрела и показатель попадания.
Обстрел. На этом шаге задача заключается в определении направления пойманного корабля. Для этого надо обстрелять четыре ячейки (если они свободны), которые могут служить продолжением. В случае, когда все четыре клетки обстреляны, а попадания не произошло (однопалубный корабль), надо перейти к первому состоянию. Если в какой-то момент удалось подбить еще одну палубу противника, то можно переходит к расстрелу данного корабля, т.к. его направление стало известно. Аналогично первому состоянию, если у игрока остались корабли не более двух палуб, то этим попаданием корабль уничтожен полностью и надо вернуться к прострелу. Вводим отдельную функцию: function State2 (var x, y: Integer): Boolean;.
Расстрел. На предыдущем шаге удалось установить в каком направлении размещен пойманный корабль. Теперь задача заключается в его полном уничтожении. Для этого надо стрелять справа или слева (сверху или снизу) подбитых палуб, пока не добьем его целиком, после чего вернемся в состояние прострела. При этом следует учитывать максимально возможный корабль и стараться попасть по четвертой палубе, когда четырех палубный корабль уничтожен, нет никакого смысла: function State3 (var x, y: Integer): Boolean;.
Процедура, которая будет контролировать результат выстрела и обеспечивать повторный ход при попадании: procedure Comput;.
Можно заметить, что функция Killed вызывается ровно один раз при каждом ходе компьютера. От сюда следует, что компьютер не подглядывает расположение кораблей игрока, т.к. другой возможности узнать о состоянии какой-либо ячейки поля игрока у него нет. В этом можно убедиться на практике, собрав все эти части кода вместе и сделав консольное приложение, в котором функция Killed спрашивала бы у игрока, попал компьютер или промазал. Все это легко с минимальными изменениями реализовать на Turbo Pascal.
