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, y + Pky * i,
Play) do begin Inc (k); Inc (i); end; {while}
Pkx := -Pkx; Pky := -Pky; i := 1; end; {for}
B := k >= MaxShip; if B then Break; tmp := Pkx;
Pkx := Pky; Pky := tmp; end; {for} until B;
Result := Killed (x, y); if Result then begin Px :=
x; Py := y; Len := 1; if MaxShip > 1 then
State := 2 else Dec (Kor[Len]); end; {if} end; {func State1} |
|
Ее
результатом служат координаты выстрела
и показатель попадания.
Обстрел
На
этом шаге задача заключается в определении
направления пойманного корабля. Для
этого надо обстрелять четыре ячейки
(если они свободны), которые могут
служить продолжением. В случае,
когда все четыре клетки обстреляны,
а попадания не произошло (однопалубный
корабль), надо перейти к первому
состоянию. Если в какой-то момент удалось
подбить еще одну палубу противника,
то можно переходит к расстрелу
данного корабля, т.к. его направление
стало известно. Аналогично первому
состоянию, если у игрока остались корабли
не более двух палуб, то этим попаданием
корабль уничтожен полностью
и надо вернуться к прострелу.
Посмотрим, как все это выглядит:
function
State2 (var x, y: Integer): Boolean; var Old: ShortInt; tmp: Integer;
k: Integer; begin Old := Play[Px,Py]; Play[Px,Py] := -1;
repeat if not Freedom (Px + Pkx, Py + Pky, Play) and not Freedom
(Px - Pkx, Py - Pky, Play) then begin tmp := Pkx;
Pkx := Pky; Pky := tmp; end; {if} if Random (2) =
0 then begin x := Px + Pkx; y := Py + Pky; end
else begin x := Px - Pkx; y := Py - Pky; end;
{if} until Freedom (x, y, Play); Result := Killed (x, y);
if Result then begin Len := 2; State := 1; if
MaxShip > 2 then State := 3 else Dec (Kor[Len]);
end else begin k := 4; if not Freedom (Px + 1, Py,
Play) then Dec (k); if not Freedom (Px - 1, Py, Play) then Dec
(k); if not Freedom (Px, Py + 1, Play) then Dec (k); if
not Freedom (Px, Py - 1, Play) then Dec (k); if k < 2 then
State := 1; end; {if} Play[Px,Py] := Old; end; {func State2} |
|
Расстрел
На
предыдущем шаге удалось установить
в каком направлении размещен
пойманный корабль. Теперь задача заключается
в его полном уничтожении. Для
этого надо стрелять справа или слева
(сверху или снизу) подбитых палуб, пока
не добьем его целиком, после чего
вернемся в состояние прострела.
При этом следует учитывать максимально
возможный корабль и стараться
попасть по четвертой палубе, когда
четырех палубный корабль уничтожен,
нет никакого смысла. Все достаточно
просто:
function
State3 (var x, y: Integer): Boolean; var Old: ShortInt; i: Integer;
B: Boolean; begin for i := 1 to 2 do begin x := Px;
y := Py; while Play[x,y] = 1 do begin Inc (x, Pkx);
Inc (y, Pky); end; {while} Old := Play[x-Pkx,y-Pky];
Play[x-Pkx,y-Pky] := -1; B := Freedom (x, y, Play); Play[x-Pkx,y-Pky]
:= Old; if B then Break; Pkx := -Pkx; Pky := -Pky;
end; {for} if B then begin Result := Killed (x, y);
if Result then begin Inc (Len); if Len = MaxShip then
begin Dec (Kor[Len]); State := 1; end; {if}
end; end else begin Dec (Kor[Len]); State :=
1; Result := State1 (x, y); end; {if} end; {func State3} |
|
Осталось
собрать все это в одной
процедуре, которая будет контролировать
результат выстрела и обеспечивать
повторный ход при попадании:
procedure
Comput; var x, y: Integer; Kill: Boolean; begin repeat
case State of 1: Kill := State1 (x, y); 2: Kill := State2
(x, y); 3: Kill := State3 (x, y); end; {case} if Kill
then Play[x,y] := 1 else Play[x,y] := -2; until not Kill
or GameOver; end; {proc Comput} |
|
Можно
заметить, что функция Killed вызывается
ровно один раз при каждом ходе
компьютера. От сюда следует, что компьютер
не подглядывает расположение кораблей
игрока, т.к. другой возможности узнать
о состоянии какой-либо ячейки поля
юзера у него нет. В этом можно
убедиться на практике, собрав все
эти части кода вместе и сделав
консольное приложение, в котором
функция Killed спрашивала бы у игрока,
попал компьютер или промазал.
Все это легко с минимальными
изменениями реализовать на Turbo Pascal
7.0
3.
БЛОК - СХЕМА
ЗАКЛЮЧЕНИЕ
В
результате выполнения данной курсовой
работы был получен игровой программный
продукт, названный «Морской бой». Было
проведено исследование компонентов
программной среды Turbo Pascal 7.0, которые
использовались при создании игры.
В
результате исследования были выявлены
следующие недостатки полученного
программного продукта:
- Низкий исскуственный
интеллект, т.е. ход компьютера осуществляется
случайным образом, что делает маловероятным
победу компьютера;
- При полном
потоплении корабля это никак не отражается;
- Невозможность
возврата на несколько ходов назад;
- Работоспособность
приложения только в среде Windows;
Однако,
помимо недостатков, есть и достоинства
у этого программного продукта:
- Автоматическая
расстановка кораблей ;
- Программный
продукт малотребователен к системным
ресурсам компьютера. Минимальная конфигурация:
процессор – не ниже Pentium, оперативная
память – не ниже 16 Mb, операционная система
– Windows 95 / 98/ Me / NT / 2000 / XP.
В
результате учета всех сделанных
выше замечаний возможно улучшение
созданного программного продукта, на
которое потребуется минимум
изменений исходного кода программы.
СПИСОК
ИСПОЛЬЗУЕМОЙ ЛИТЕРАТУРЫ
- Немнюгин
С. Turbo Pascal / Учебный курс.– СПб: Питер, 2001.
- Сухарев М.
Turbo Pascal 7.0. Теория и практика программирования.-
СПб.: Наука и техника. 2004.
- Фаронов В.В.
Турбо Паскаль 7.0. Начальный курс. Учебное
пособие – М.: Издательство ООО ОМД «Групп»,
2002.
- Федоренко
Ю. Алгоритмы и программы на Turbo Pascal / Учебный
курс.– СПб: Питер, 2001.