Разработать программу, моделирующую игру “Морской бой”. 2



Основные данные о работе

Филиал

Красноярский, Нижнеингашский СГБ

Вид работы

Курсовая работа

Название дисциплины

ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ

ВЫСОКОГО УРОВНЯ

Тема

Разработать программу, моделирующую игру “Морской бой”.

Фамилия студента

Тимченко

Имя студента

Михаил

Отчество студента

Васильевич

№ контракта

05606100609001


Содержание

Введение………………………………………………………………………………….3

1          Структурные операторы языка программирования ……………..………………..7

1.1   Оператор if…then…(else)ю……………………………………………………….7

1.2   Оператор case…of…end ………….……………………………………...…….…7

1.3   Оператор цикла while…do………………………………………………….….....8

1.4   Операторы цикла repeat…until…...........................................................................8

1.5   Операторы цикла for…to…do… и for…downto…do…........................................9

2          Разработка программы……………………………………………………..….……10

2.1   Постановка задачи………………………………………………………….……10

2.2   Алгоритм реализации работы...............................................................................10

2.3   Стратегия игры компьютера………………………………………….…..……..12

2.4   Прострел…………………………………………………………………......……14

2.5   Обстрел……………………………………………………………………..……..15

2.6   Расстрел……………………………………………………………………..…….16

Заключение……………………………………………………………….…..………….19

Глоссарий………………………………………………………………………..….…....20

Список использованных источников…………………………………………..………22

Приложение А

 

 

 

 

 

 

 

 

 

 

 

Введение

 

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

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

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

Компьютерные игры берут свое начало в 50-ые года двадцатого века. Сегодня игровая общественность до конца не определилась, кто является их первоначальным создателем. История знает трех человек, которые в 1950-ые годы начинали работать над данным вопросом. Первым из этих людей является Ральф Баэр. Будучи инженером в 1951 году он предложил общественности идею интерактивного телевиденья. Вторым человеком является А.С. Дуглас. В 1952 году им была написана игра, получившая название «ОХО». Данная игра представляла собой программную реализацию всем известных «крестиков-ноликов». И третьим человеком, которого можно назвать отцом компьютерных игр, является Уильям Хигинботем. В 1958 году он создал компьютерную игру «Теннис». В нее могли играть два человека.

Видеоигры в 60-е годы XX века

В 1960 году компанией Digital Equipment Corporation был выпущен первый компьютер серии PDP. Он получил название PDP-1. Спустя 2 года, в 1962 году для него была разработана первая компьютерная игра, которую разработчик назвал Space War.

Компьютерные игры в 70-е годы XX века.                                                                                                                   В 1970 году выдается патент на компьютерный манипулятор, без которого сейчас не может обойтись не один игрок. Речь идет о компьютерной мышке. Человека, получившего патент, звали Дуглас Энгельбарт.

1975 год стало годом проявления интереса к компьютерным играм со стороны общественности. Уильям Кроутер создает игру, которая является прообразом приключенческого жанра и называет ее Colossal Cave Adventure. Данная игра распространяется моментально через сеть ArpaNET.

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

Видеоигры в 80-е годы XX века

В 80-е годы в связи с заметным удешевлением домашних компьютеров (спасибо IBM), ранок компьютерных игр стал быстро расти. Сейчас можно сказать, что именно в 1980-х наступила эпоха компьютерных игр. Появилось множество компаний занимающихся исключительно разработкой игр. Компания Namco выпускает игру Pac-Man, суть которой сводилась к управлению непонятным существом, которое должно было собирать разбросанные по лабиринту точки, уклоняясь от врагов. Идея данной игры жива до сих пор и часто находит свое выражение на мобильных платформах.

В 1987 году появился видеоадаптер VGA, а следом SVGA. Эти события отправили в прошлое 16 цветное царство. Теперь на мониторах 256 цветов, что естественно сделало игры более красочными и относительно похожими на современные.

Компьютерные игры в 90-е годы XX века

Начинания с 90-х бум компьютерных игр стал только набирать обороты, а индустрия расти и расти. В 1993 году 10 декабря компанией Id Software, был выпущен великий Doom. Игра которая заложила основы жанра шутер. Подробнее об этом и других жанрах pc-игр можно узнать из статьи о жанрах компьютерных игр. Именно там будут представлены типичные их представители.

В 1994 году появилась первая игра с мультиплеером - Rise of the Triad. А на следующий год появляется The Terminator: Future Shock, первый шутер с элементами трехмерности мира и врагов, а так же свободным обзором при помощи мышки.

В 1996 году на свет появилась Voodoo I – первая видео карта с поддержкой полноценного 3D. Это позволило выпустить Duke Nukem 3D и Quake – первые полностью трехмерные игры. Так же в этом году появились такие игры, как Super Mario, Command & Conquer: Red Alert, Tomb Raider, Resident Evil, Diablo и многие другие.

В 1998 году появляются Half-life и StarCraft. Игры не теряющие популярности до сих пор, спустя уже 12 лет! Многие игроки и сейчас играют в первую StarCraft, хотя уже появилась возможность скачать без смс Старкрафт 2. Впрочем данная ситуация характерна для многих хитов прошлого.

Компьютерные игры в XXI веке

В первом десятилетии 21-го века игровая индустрия идет вперед семимильными шагами. Ежегодно выпускаются тысячи игр, расходящиеся по всему миру миллионами копий, а оборот составляет десятки миллиардов долларов. Наиболее успешные игровые проекты собирают сотни миллионов долларов от продаж. Вы можете познакомиться с одним из рекордсменов по кассовым сборам, если скачаете одним файлом игру Call of Duty Modern Warfare 2. Замедление вызванное мировым финансовым кризисом, постепенно уходит и индустрия вновь набирает обороты.

Как видно из этой статьи развитие компьютеров тесно связанно с развитием игр. Именно для них создаются мощные видео карты, процессоры, растет объем доступной оперативной памяти. О значении компьютерных игр можно также почитать в статье о роли видеоигр в общественной жизни - Компьютерные игры. Существует даже мнение, и весьма не безосновательное, что компьютеры стали такими, какими мы их знаем именно благодаря играм.

 

 


1       Структурные операторы языка программирования

 

В практической части данной курсовой работы используются следующие операторы среды программирования Turbo Pascal.

 

1.1 Оператор if…then…(else)

 

Оператор if…then

Оператор if…then… называется условным оператором и имеет вид:

If expression1 then statement1;

где выражение expression1 является логическим. Логическое выражение принимает одно из двух возможных значений – True (истина) или False (ложь). Часто в роли логического выражения выступает какое-то условие, которое может выполнять либо нет. В первом случае его значение – «истина»,а во втором – «ложь». Если логическое выражение expression1 принимает значение «истина», то выполняется оператор statement1. В противном случае выполняется будет оператор, следующий за данным логическим оператором. Оператор “ if…then…else..”  является полной версией условного оператора и имеет вид:

If expression then statement1 else statement2;

Выполняется данный оператор следующим образом: если выражение expression принимает значение «истина», то управление передается на оператор statement1, если же нет, то на оператор statement2.

 

1.2 Оператор case…of…end

 

Оператор case…of…end

Для ситуации, где имеется несколько (три или более) альтернатив, больше подходит оператор case. Этот оператор называется оператором выбора и имеет следующий вид:

case expression of

values_1: statement_1;

values_2: statement_2;

…

values_n: statement_n;

else statement;

end;

Рассмотрим элементы этой конструкции. Во-первых, это три зарезервированных слова: case, of и end. Между case и of находится выражение expression, принимающее значение, которое, возможно, имеется в одном из списков значений, находящихся слева от двоеточий. Данное выражение называется селектором оператора case. Каждый оператор, идущий за двоеточием, отделяется от следующего списка значений точкой запятой. Ветвь else, отвечающая всем не перечисленным значениям выражения expression, необязательна. При выполнении данного оператора вначале вычисляется значение селектора. Затем выбирается тот список значений, которому принадлежит полученное значение, и выполняется соответствующий оператор.

 

1.3 Оператор цикла while…do…

 

Оператор цикла является важнейшим оператором и имеется в большинстве современных языков программирования. Цикл позволяет много кратно выполнить некоторое множество действий, задаваемых операторами, составляющими его тело. В Паскале имеется несколько разновидностей оператора цикла. Начнем с оператора цикла с предусловием. Данный оператор имеет вид: While expression do statement ;

При выполнении этого оператора вначале вычисляется значение логического выражения expression. Если это значение истинно, выполняется оператор statement, затем значение выражения проверяется вновь и т. д., до тех пор, пока выражение не примет значений «ложь». Если выражение принимает значение «ложь» при первой же проверке, то оператор statement не выполняется вообще.

 

1.4 Операторы цикла repeat…until…

 

Оператор цикла с постусловием имеет вид: Repeat statement until expression:

Здесь вначале выполняется оператор statement, а затем вычисляется значение логического выражения expression принимает значение «ложь». Как только это значение станет истинным, выполнение цикла прекращается.

 

1.5 Операторы цикла for…to…do… и for…downto…do…

 

Третий вариант оператора цикла – цикл со счетчиком. Можно считать, что есть две очень похожих друг на друга разновидности цикла со счетчиком. Первый из этих операторов имеет вид:

For j := expression1 to expression2 do statement;

Здесь переменная j, называемая управляющей переменной цикла for, является произвольным идентификатором, который объявляется как переменная любого скалярного типа (к скалярным относится целый, символьный, булев и перечислимые типы).

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

 

 

 

 

 

 

 

 

 

2 Разработка программы

 

2.1 Постановка задачи

 

1.              Разработать программу, моделирующую игру “Морской бой”. На поле 10 на 10 позиций стоят невидимые вражеские корабли: 4 корабля по 1 клетке, 3 корабля по 2 клетки, 2 корабля по 3 клетки, 1 корабль в 4 клетки. Необходимо поразить каждую из клеток кораблей. Два игрока вводят позиции кораблей в виде цифр (1, 2, 3, 4) в соответствующие элементы матрицы, тем самым определяя конфигурацию и положение кораблей. Игроки по очереди “наносят удары” по кораблям про-тивника. Если позиция корабля указана верно, то она помечается крестиком на поле. Предусмотреть вариант игры, когда одним из играющих является ЭВМ.

 

2.2 Алгоритм реализации работы

 

Алгоритм размещения кораблей на игровом поле. Игровое поле нужно как-то хранить в памяти компьютера. Наиболее простая реализация - в виде матрицы 10x10 клеток (ячеек). Определим соответствующий тип и переменные, которые нам понадобятся:

type TPole = array[1..10,1..10] of Integer;

var Pole: TPole;

Обусловимся, что пустая ячейка будет иметь значение -1, а ячейка, в которой находится корабль: 0. Перед началом процесса размещения кораблей необходимо очистить поле. Помимо этого надо еще и обновить счетчик случайных чисел, что бы добиться реальной случайности позиций флота компьютера. Все эти действия лучше оформить в виде отдельной процедуры:

procedure Init (var Pole: TPole);

var X, Y: Integer;

begin  Randomize;

for X := 1 to 10 do  for Y := 1 to 10 do  Pole[X,Y] := -1;

end; {proc Init}

По правилам игры два корабля не могут соприкасаться друг с другом, т.е. между ними должно быть пустое пространство минимум в одну клетку. Нам понадобится вспомогательная функция, которая позволит определить, можно ли поставить однопалубный корабль в указанную ячейку или нет. Для этого необходимо проверить саму эту ячейку и все соседние (их 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 < 11) and (y > 0) and (y < 11) and (Pole[x,y] = -1) then  begin  for i := 1 to 8 do  begin  dx := x + d[i,1];  dy := y + d[i,2]; 

if (dx > 0) and (dx < 11) and (dy > 0) and (dy < 11) and (Pole[dx,dy] > -1) then  begin  Result := False;

Exit;

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).

 

2.3 Стратегия игры компьютера

 

Задача заключается в разработке алгоритма, по которому компьютер сможет играть в "Морской бой" с максимальным качеством и при этом не подглядывая расположение флота игрока. Дополнительное и очевидное условие: при каждой новой игре вне зависимости от размещения сил противника компьютер должен играть по-разному, т.е. его ходы должны быть не предсказуемы. Необходимо вспомнить правила игры: участники поединка делают ходы поочередно, причем, если один из игроков попадает по кораблю соперника, то он получает право следующего хода. Если реализовать поиск цели компьютером в виде отдельной процедуры, то надо как-то научить его запоминать исходы прошлых выстрелов, чтобы адекватно произвести следующий. Из этого факта вытекает, что самое простое и рациональное решение данной проблемы можно оформить в виде конечного автомата, наиболее точно описывающего последовательность действий. Можно выделить три состояния:

1.              прострел игрового поля по случайным координатам до попадания по кораблю, после чего переход во второе состояние;

2.              обстрел вокруг подбитой ячейки поля для определения направления корабля (вертикальное или горизонтальное), после очередного попадания - переход в третье состояние;

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

Итак, вся игра зациклена на трех основных действиях: прострел, обстрел и расстрел. Все эти действия должны продолжаться до тех пор, пока у одной из сторон не будут уничтожены все корабли. Компьютеру потребуется еще одно поле, на котором он будет вести игру. Назовем его 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}

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

 

2.4 Прострел

 

На этом этапе компьютер должен поймать какой-либо из кораблей противника. Для этого он будет стрелять по произвольным незанятым клеткам поля игрока. Гораздо эффективнее сначала разделаться с большими кораблями, поэтому выбирая координаты для выстрела надо проверять, что бы в этой позиции мог разместиться самый большой из оставшихся кораблей. Процесс прекращается, как только произойдет попадание. Обозначим подбитую часть корабля значением 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}

Ее результатом служат координаты выстрела и показатель попадания.

 

2.5 Обстрел

 

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

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

 

2.6 Расстрел

 

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

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

 

 

Заключение                                                                                 

 

В результате выполнения данной курсовой работы был получен игровой программный продукт, названный «Морской бой». Было проведено исследование компонентов программной среды Turbo Pascal 7.0, которые использовались при создании игры. В результате исследования были выявлены следующие недостатки полученного программного продукта:

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

2.              При полном потоплении корабля это никак не отражается;

3.              Невозможность возврата на несколько ходов назад;

4.              Работоспособность приложения только в среде Windows;

Однако, помимо недостатков, есть и достоинства у этого программного продукта:

Разработать программу, моделирующую игру “Морской бой”. 2