-
Анализ задачи
Классическая игра «Морской бой» представляет собой два игровых поля (игрока и его соперника) размером 10 на 10 клеток, обозначением буквами от А до К по вертикали и цифрами от 1 до 10 по горизонтали. Поскольку мы пишем программу для игры против компьютера в односторонний «морской бой», нам необходимо только одно игровое поле – поле компьютера. Для этого нам нужно научить его:
- расставлять произвольным образом корабли, проверяя при этом наличие свободного пространства;
- хранить в памяти расположение кораблей;
- перемещать прицел по полю, не выходя за его границы;
- показывать результат выстрела: попадание, промах;
- в любой момент времени показывать расстановку кораблей;
- завершать игру, если все корабли потоплены.
Входные данные:
-
Управление прицелом.
-
Выстрел.
-
Показать расстановку кораблей.
-
Выход из программы.
Выходные данные:
-
Перемещение прицела по полю при нажатии определенных клавиш.
-
Отображение результата выстрела с соответствующим звуковым сопровождением.
-
Показ расстановки кораблей.
-
Соответствующий звуковой сигнал, если указанная клетка уже обстреливалась.
-
Сообщение о завершении игры, если все корабли потоплены.
-
Описание алгоритма программы
Для реализации игры нам необходимы:
Константы
-
s – массив литер от «А» до «К»;
-
s1 – массив строк чисел от «1» до «10»;
-
step – размер стороны клетки в пикселах;
-
v, g - координаты левого верхнего угла игрового поля;
Нужно как-то хранить игровое поле в памяти компьютера. Наиболее подходит для этого матрица размером 10 на 10 клеток (записей). Определим для этого соответствующий тип
Тип.
-
kletka – запись;
-
x, y – координаты клетки поля;
-
stat – информация о клетке (0-свободна, 1- занята кораблем, -1-попали, 2-промахнулись);
-
Sea – двухмерный массив записей;
Переменные
-
drive, mode: переменные инициализации графического режима;
-
cell: тип kletka;
-
Pole: тип Sea;
-
i, j: указатели на запись в массиве;
-
count: счетчик подбитых кораблей;
-
key: код нажатой клавиши;
-
l: счетчик цикла задержки показа расстановки кораблей ;
Процедуры
-
Init - инициализация графического режима;
-
Image – создает картинку игрового поля;
-
Setup – заполняет массив Pole координатами клеток и устанавливает их «свободное» состояние;
-
Setup_Ship – расставляет случайным образом корабли на поле;
-
Pricel – рисует или стирает прицел на поле;
-
Mysound – подает звуковой сигнал при попадании в уже обстрелянную клетку;
Функции
-
Freecell – определяет наличие свободного места вокруг корабля при его установке.
Остановимся на работе программы более подробно.
Работа основного модуля начинается с обновления датчика случайных чисел, чтобы добиться реальной случайности расположения флота компьютера. Далее вызывается
процедура Init
Она автоматически инициирует нужный драйвер и установит наиболее подходящий для дисплея режим. Если обнаружена ошибка инициализации графического режима, то на экран выводится сообщение о ней и происходит выход из программы.
С помощью стандартных процедур рисуем заставку с информацией об авторе работы, названием игры, способом управления и предложением нажать любую клавишу для начала игры. После выполнения этого условия переходим к созданию игрового поля компьютера на экране. Для этого обратимся к процедуре Image.
Процедура Image
Входные данные:
-
v, g - координаты левого верхнего угла игрового поля;
-
s – массив литер от «А» до «К»;
-
s1 – массив строк чисел от «1» до «10»;
Внутренние переменные:
-
x, y – рабочие координаты;
Выходные данные:
-
Готовое к игре изображение игрового поля.
Данная процедура очищает экран от предыдущих изображений, устанавливает для фона цвет «морской волны» и рисует в центре экрана белый квадрат, разбитый на клетки, с буквенным обозначением по вертикали и численным по горизонтали.
Перед началом процесса размещения кораблей, необходимо очистить поле, т.е. все клетки должны быть пустыми. Условимся, что все они будут иметь значение 0. Занятая кораблем: 1, при попадании в корабль: -1, при промахе: 2. Кроме этого нам необходимо указать координаты для каждой клетки. Это нужно для того, чтобы в дальнейшем, в зависимости от ситуации рисовать в клетке либо прицел, либо корабль, либо крестик, либо точку. Поэтому, следующей в программе вызывается процедура Setup.
Процедура Setup
Входные данные:
-
Pole – массив записей;
-
v, g - координаты левого верхнего угла игрового поля и соответственно первой клетки;
-
step – приращение для координат следующей клетки;
Внутренние переменные:
-
i, j – переменные цикла:
-
a,b – координаты следующей клетки;
Выходные данные:
-
Инициализированный массив записей – Pole.
Данная процедура, взяв для первой клетки координаты из констант v, g, переходит к следующей записи. Прибавив константу step к предыдущим координатам, записывает их новые значения для каждой последующей клетки на игровом поле, а так же устанавливает ее «нулевое» состояние.
По правилам игры два корабля не могут соприкасаться друг с другом, т.е. между ними должно быть пустое пространство минимум в одну клетку. Нам понадобится вспомогательная функция Freecell, которая позволит определить, можно ли поставить однопалубный корабль в указанную клетку или нет. Для этого необходимо проверить саму эту клетку и все соседние (их 8 штук). И только если все они не заняты, можно дать положительный ответ (True), в противном случае - отрицательный (False).
Функция Freecell
Входные данные
-
Pole – инициализированный массив записей;
-
x, y – номер случайно выбранной записи в массиве;
Внутренние константы
-
d – двухмерный массив;
Внутренние переменные
-
dx, dy – номер проверяемой клетки;
-
i – счетчик цикла;
Выходные данные
-
ложь или истина (будет ли соприкасаться клетка с другим кораблем или нет, и не выходит ли она за пределы поля).
Функция Freecell получает от процедуры Setup_Ship номер ячейки. Если она свободна и не выходит за пределы поля, тогда с помощью массива d определяются координаты соседних клеток и проверяется их статус. В случае, когда все клетки свободны, функция возвращает в процедуру значение «истина».
На поле должны находиться следующие корабли: один четырехпалубный, два трехпалубных, три двухпалубных и четыре однопалубных. Процедура, расставляющая эти корабли должна выполнять следующие действия: взять случайную свободную ячейку и проверить, можно ли поставить текущий корабль горизонтально или вертикально. Если да, то корабль размещается на игровом поле и обработка переходит к следующему. Если нет, то возвращаемся к выбору координат. Порядок расстановки должен быть от большего корабля к меньшему, что бы не возникла ситуация невозможности размещения ни в одну позицию поля. Все эти действия выполняет процедура Setup_Ships.
Процедура Setup_Ships
Входные данные
-
Pole – массив записей;
Внутренние переменные
-
х, у – случайно выбираемые координаты ячейки;
-
stend – положение 4-х палубного корабля по вертикали или горизонтали;
-
i – счетчик цикла;
-
N, M – какой корабль и в каком количестве располагается на поле;
-
kx, ky – каким образом будет располагаться корабль;
-
В – флаг возможности установки корабля в указанную позицию.
Выходные данные
-
Расставленные случайным образом корабли;
Поскольку 4-х палубный корабль располагается на поле первым, его можно поместить в любое место. С помощью переменной stend определим его направление и, используя цикл for, разместим его на поле, начиная с клетки, указанной переменными х, у.
Теперь можно разместить остальные корабли. С помощью переменных kx, ky определим, как будет располагаться корабль. Зададим для х, у случайные значения и передадим их функции Freecell. Если после проверки всех необходимых ячеек функция сохранит флаг В «истина», то в это место устанавливается корабль. В противном случае процедура выбирает другие значения х, у.
Вернемся в основную программу и с помощью переменных i, j установим запись с информацией о первой клетке, а также обнулим счетчик подбитых кораблей count.
Координаты клетки, по которой производится выстрел, можно вводить буквами и цифрами. Но если ее можно будет указать с помощью прицела, который перемещается по полю, игра станет более наглядной. Опишем процедуру Pricel.
Процедура Pricel
Входные данные
-
n – номер цвета;
-
координаты клетки (в пикселах);
Выходные данные
-
в зависимости от выбранного цвета, нарисованный или «стертый» прицел в клетке.
Процедура Mysound будет подавать определенный звуковой сигнал в случае повторного выстрела по клетке.
Теперь, когда компьютер полностью готов к игре, начнем основной цикл программы, цикл диалога с компьютером. В этом цикле он следит за тем, какие клавиши нажаты и сколько потоплено кораблей.
Нажата клавиша перемещения прицела.
Если прицел не выходит за границу поля; стираем его, переходим к следующей клетке по указанному направлению и снова рисуем прицел.
Нажата клавиша выстрела.
Проверяем информацию о статусе клетки.
Если в ней находится корабль
-
производим звук взрыва;
-
отмечаем клетку крестиком;
-
изменяем статус клетки на «убит»;
-
увеличиваем счетчик подбитых кораблей на единицу.
Если клетка пуста
-
подаем звуковой сигнал промаха;
-
отмечаем клетку точкой;
-
изменяем статус клетки на «стрелял, но не попал».
Если клетка отмечена крестиком
-
подаем звуковой сигнал процедурой Mysound.
Если клетка отмечена точкой
-
подаем звуковой сигнал процедурой Mysound.
Нажата клавиша показа расстановки кораблей
-
последовательно проверяем все клетки игрового поля;
-
если в клетке есть корабль, независимо «живой» или «убитый», закрашиваем ее;
-
показываем корабли в течении 5 секунд;
-
вызываем процедуру Image, которая очищает экран и заново рисует игровое поле;
-
последовательно проверяем все клетки игрового поля;
-
если в клетке «убитый» корабль, рисуем крестик;
-
если в клетке «промах», рисуем точку;
-
в правом нижнем углу поля рисуем прицел.
Цикл закончится, если будет нажата клавиша «Esc» или будут потоплены все корабли. В этом случае программа выведет сообщение о том, что игра закончена и после нажатия любой клавиши, графический режим будет закрыт, и осуществлен выход из программы.