Создание игровой программы "Морской бой"
Курсовой проект - Компьютеры, программирование
Другие курсовые по предмету Компьютеры, программирование
?ь саму эту ячейку и все соседние (их 8 штук). И только если все они не заняты можно дать положительный ответ (True), в противном случае - отрицательный (False):
function Freedom (x, y: Integer; Pole: TPole): Boolean; const d: array[1..8,1..2] of Integer = ((0,1),(1,0),(0,-1),(-1,0),(1,1),(-1,1),(1,-1),(-1,-1)); var i: Integer; dx, dy: Integer; begin if (x > 0) and (x -1) then begin Result := False; Exit; end; {if} end; {for} Result := True; end else Result := False; end; {func Freedom}
Как известно из правил игры, на поле должны находиться следующие корабли: один четырех палубный, два трехпалубных, три двухпалубных и четыре однопалубных. Процедура, расставляющая эти корабли должна выполнять следующие действия: взять случайную свободную ячейку и проверить, можно ли поставить текущий корабль горизонтально или вертикально. Если да, то корабль размещается на игровом поле и обработка переходит к следующему. Понятно, что если нет, то возвращаемся к выбору координат. Порядок действий должен быть от большего корабля к меньшему, что бы не возникла ситуация невозможности размещения ни в одну позицию поля. Вот код этой процедуры:
procedure Ships (var Pole: TPole); var N, M, i: Integer; x, y, kx, ky: Integer; B: Boolean; begin Init (Pole); for N := 3 downto 0 do for M := 0 to 3 - N do repeat x := Random (10) + 1; y := Random (10) + 1; kx := Random (2); if kx = 0 then ky := 1 else ky := 0; B := True; for i := 0 to N do if not Freedom (x + kx * i, y + ky * i, Pole) then B := False; if B then for i := 0 to N do Pole[x+kx*i,y+ky*i] := 0; until B; end; {proc Ships}
Это, собственно, и все, что касается размещения кораблей компьютера. Теперь достаточно сделать вызов: Ship (Pole); и корабли будут случайным образом расставлены по своим местам. Подобным образом можно помочь пользователю, что бы он каждый раз не тратил время на эту операцию, вызвав Ship (Play); где Play - поле игрока (тип TPole).
Стратегия игры компьютера
Задача заключается в разработке алгоритма, по которому компьютер сможет играть в "Морской бой" с максимальным качеством и при этом не подглядывая расположение флота игрока. Дополнительное и очевидное условие: при каждой новой игре вне зависимости от размещения сил противника компьютер должен играть по-разному, т.е. его ходы должны быть не предсказуемы. Необходимо вспомнить правила игры: участники поединка делают ходы поочередно, причем, если один из игроков попадает по кораблю соперника, то он получает право следующего хода. Если реализовать поиск цели компьютером в виде отдельной процедуры, то надо как-то научить его запоминать исходы прошлых выстрелов, чтобы адекватно произвести следующий. Из этого факта вытекает, что самое простое и рациональное решение данной проблемы можно оформить в виде конечного автомата, наиболее точно описывающего последовательность действий. Можно выделить три состояния:
- прострел игрового поля по случайным координатам до попадания по кораблю, после чего переход во второе состояние;
- обстрел вокруг подбитой ячейки поля для определения направления корабля (вертикальное или горизонтальное), после очередного попадания - переход в третье состояние;
- расстрел корабля в полученном направлении до полного его уничтожения, после чего переход в первое состояние.
Итак, вся игра зациклена на трех основных действиях: прострел, обстрел и расстрел. Все эти действия должны продолжаться до тех пор, пока у одной из сторон не будут уничтожены все корабли. Компьютеру потребуется еще одно поле, на котором он будет вести игру. Назовем его Play. Помимо этого нужно помнить, какие корабли остались у игрока, а какие уже разбиты. Объявим все необходимые переменные:
var Play: TPole; Kor: array[1..4] of Integer; State: Integer;// состояние автомата Len: Integer;// кол-во подбитых палуб текущего корабля Pkx, Pky: Integer;// направление удара Px, Py: Integer;// позиция попадания
Перед началом игры надо настроить все значения. Это удобно сделать в отдельной процедуре:
procedure Start; var I: Integer; begin Init (Play); Ships (Pole); State := 1; for I := 1 to 4 do Kor[I] := 5 - I; end; {proc Start}
Предположим, что у нас есть функция, которая выдает истину, если в ячейки (x,y) игрока стоит корабль и ложь в противном случае: function Killed (x, y: Integer): Boolean;. Еще потребуется функция, определяющая длину самого большого корабля игрока:
function MaxShip: Integer; var i: Integer; begin for i := 1 to 4 do if Kor[i] > 0 then Result := i; end; {func MaxShip}
И функция, определяющая проигрыш юзера:
function GameOver: Boolean; var I: Integer; begin for I := 1 to 4 do if Kor[I] > 0 then begin Result := False; Exit; end; {if} Result := True; end; {func GameOver}
Все вспомогательные подпрограммы готовы и можно приступить к реализации самого автомата. Для большей наглядности каждое состояние оформим в виде отдельной процедуры. Итак, все по порядку.
Прострел
На этом этапе компьютер должен поймать какой-либо из кораблей противника. Для этого он будет стрелять по произвольным незанятым клеткам поля игрока. Гораздо эффективнее сначала разделаться с большими кораблями, поэтому выбирая координаты для выстрела надо проверять, что бы в этой позиции мог разместиться самый большой из оставшихся кораблей. Процесс прекращается, как только произойдет попадание. Обозначим подбитую часть корабля значением 1, а промах -2 соответствующей ячейки поля. Если у игрока остались только однопалубные корабли, то этим попаданием корабль уничтожен полностью и обстреливать его нет смысла. В противном случае надо перейти ко второму состоянию. Приведем код описанной функции:
function State1 (var x, y: Integer): Boolean; var k, i, n, m: Integer; B: Boolean; tmp: Integer; begin repeat repeat x := Random (10) + 1; y := Random (10) + 1; until Freedom (x, y, Play); Pkx := Random (2); Pky := Pkx - 1; for m := 1 to 2 do begin i := 0; k := 0; for n := 1 to 2 do begin while Freedom (x + Pkx * i,