Сервер игры “Морской бой”

Автор работы: Пользователь скрыл имя, 24 Ноября 2013 в 15:02, курсовая работа

Краткое описание

Целью данной работы является разработка сервера для одной из самых известных и популярных в России и мире игр – Морской бой. «Морской бой» — игра для двух участников, в которой игроки по очереди называют координаты на неизвестной им карте соперника. Если у соперника по этим координатам имеется корабль (координаты заняты), то корабль или его часть «топится», а попавший получает право сделать ещё один ход. Цель игрока — первым поразить все корабли противника. Игра впервые была выпущена в виде настольной игры компанией Milton Bradley Company в 1931-ом году.

Содержание

Введение 3
Теоретический анализ и проектирование 4
Архитектура системы. 4
Протокол прикладного уровня. 4
Команды протокола прикладного уровня 5
Протокол транспортного уровня. 6
Сетевой алгоритм работы: 6
Программная реализация 7
Исходный код 7
Внешний вид приложения и порядок работы 12
Тестирование 13
Выводы 14
Список литературы 15

Прикрепленные файлы: 69 файлов

Введение.doc

— 163.50 Кб (Скачать документ)


Министерство образования  и науки Российской Федерации

ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ

ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО  ОБРАЗОВАНИЯ

«СИБИРСКИЙ ГОСУДАРСТВЕННЫЙ  ИНДУСТРИАЛЬНЫЙ УНИВЕРСИТЕТ»

Кафедра информационных технологий в металлургии

 

 

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

по дисциплине: «Информационные  сети» 

тема: «Сервер игры “Морской бой”»

 

 

 

 

 

 

Выполнил:

ст. группы ИВТ-10

Серафиновский М.Ю.

 

 

 

 

Научный руководитель:

ст. преподаватель 

Малинов М.Б.

 

 

 

 

 

 

 

 

 

 

 

 

Новокузнецк

2013

 

Содержание

 

Введение

Компьютерные игры –  одна из самых бурно развивающихся  областей ПО. Если (еще полвека назад) первые компьютерные игры были штучным продуктом из-за, того что компьютеры тогда были редкостью и позволить их себе могли лишь крупные организации и научные центры, а во вторых написание игр было очень сложным занятием и сделать это могли лишь опытные программисты, то сейчас рынок компьютерных игр заполнен и играми написанными профессиональными разработчиками и начинающими программистами. Это возможно во многом благодаря специальным программам-конструкторам, это позволяет создавать игры максимально быстро, правда вследсвии этого значительно страдает производительность, но быстродействие современных компьютеров постоянно растет, и возможно за этими программами бедующее, ведь когда-то также никто не верил в успех языков программирования высокого уровня.

Целью данной работы является разработка сервера для одной из самых известных и популярных в России и мире игр – Морской бой.

«Морской бой» — игра для двух участников, в которой игроки по очереди называют координаты на неизвестной им карте соперника. Если у соперника по этим координатам имеется корабль (координаты заняты), то корабль или его часть «топится», а попавший получает право сделать ещё один ход. Цель игрока — первым поразить все корабли противника.

Игра впервые была выпущена в виде настольной игры компанией Milton Bradley Company в 1931-ом году.

 

 

Теоретический анализ и проектирование

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

Архитектура системы.

Была выбрана клиент-серверная  архитектура, т.к. данная архитектура обладает следующими преимуществами:

  • позволяет организовать простейшее сетевое взаимодействие («клиент» посылает запрос – «сервер» присылает ответ);
  • простота подключения – потребуется вводить только адрес «сервера»;
  • доступные компоненты для реализации данной архитектуры;
  • существование программной реализации примеров данной архитектуры;
  • позволит чётко разделить сетевую часть программы.

Для функционирования игры необходимо чтобы были запущенны, и  верно настроены 3 приложения: сервер и два клиента

Будет создан простой сервер, предоставляющий лишь услуги лишь двум первым присоединившимся игрокам, но возможно дальнейшее  развитие, и добавление дополнительных режимов, таких как режим ожидания, режим приглашения, режим сохранения, режим результатов (рейтинга), и т.д. которые более полно раскрывают необходимость создания клиент-серверного приложения, а не однорангового.

Протокол прикладного уровня.

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

    1. И клиент и сервер будет работать на одной платформе, и будут скомпилированы в одной среде программирования - Delphi, из-за чего не должно возникнуть проблем с разногласием типов.
    2. Клиент и сервер будут разрабатываться согласованно, т.е. при изменении протокола клиента будет откорректирован и протокол сервера и наоборот.
    3. Бинарные протоколы значительно более быстродейственны, чем текстовые, т.к. данные просто переправляются с памяти одной машины в память другой, без необходимости парсинга команд в отдельной функции, и если соблюдаются два вышеизложенных принципа, то не возникнет расхождений. 

Команды протокола прикладного уровня

В протокол будут включены следующие команды:

  • START – команда от клиента, сообщающая что он расставил корабли и готов начать игру.
  • FIRST – ответ на команду START сообщающий что игрок расставил корабли первым, и что первый ход его.
  • SECOND -  ответ на команду START сообщающий что игрок расставил корабли вторым, и что ходит противник
  • GO – сигнал начала игры, который возникает в случае когда оба игрока расставили корабли и готовы играть.
  • SHOT x, y – команда от клиента, которая сообщает, что игрок выстрелил по координатам x, y.
  • SLIP x, y – ответ клиента на команду SHOT, сообщающий, об отсутствии корабля по координатам x, y.
  • HIT - ответ клиента на команду SHOT, сообщающий, о попадании в корабль по координатам x, y.
  • WIN – команда сообщающая серверу, что клиент пославший ее выиграл партию
  • LOSE – команда сообщающая серверу, что клиент пославший ее проиграл партию.

Протокол транспортного уровня.

В качестве протокола транспортного уровня был выбран протокол TCP, т.к.:

  • Морской бой не динамическая игра, в которой потеря одного пакета не повлияет на игровой процесс, напротив если пользователь отправил сообщение о выстреле, а оно не дошло до назначения, то это может ввести пользователя в замешательство. Так же в ней не требуется моментального сообщения о реакции противника, поэтому задержки возможные при использовании TCP вполне уместны.
  • Используется двоичный протокол, и в случае если команда не войдет в один пакет (что маловероятно, но возможно), и один из пакетов не дойдет до адресата, то возможна неверная интерпретация команды, или что еще более фатально, ошибка приложения, что в случае с сервером приведет к ошибкам на стороне клиента.

Сетевой алгоритм работы:

Алгоритм подключения  следующий:

    1. Клиент, расставив корабли, отправляет команду START, сервер, если клиент нажал кнопку готовности первым, отправляет ему ответ FIRST иначе SECOND.
    2. Когда оба клиента заявили о готовности сервер посылает обоим команду GO, сообщая клиентам, что все игроки готовы и игра может быть начата.
    3. Игрок, получавший ответ FIRST, т.е. делающий первый ход, отправляет команду SHOT с аргументами x и y, сообщая серверу что был произведен выстрел по координатам.
    4. Получив команду SHOT x, y, сервер пересылает ее клиенту – “противнику”.
    5. В случае попадания, клиент отправляет на сервер команду HIT x,y, а тот в свою очередь стрелявшему, в случае промаха выполняется аналогичные действия, но с командой SLIP x,y.
    6. Когда один из игроков выбил все корабли противника, он отправляет серверу команду WIN, сообщая о победе в партии, проигравший в свою очередь отправляет команду LOSE, сообщая о проигрыше.

Программная реализация

Компонентами для реализации сервера игры морской бой, был  выбран компонент IdTCPServer – этот компонент инкапсулирует полный многопоточный TCP сервер, и избавляет от необходимости низкоуровнего программирования с использованием API функций. Еще одним несомненным преимуществом данного компонента является простота программирования, она осуществляется так же просто как запись и чтение обычного файла, это достигается за счет использования режима блокирующих сокетов, но платой за это становится “замораживание” программы. Но в данной работе с этим не возникнет проблем, т.к. каждого подключения создается свой поток, слушающий и пишущий независимо от основного потока.

Остановимся более подробно на исходном коде отвечающем за сетевое взаимодействие.

Исходный код

Процедура вызываемая при подключении нового клиента

procedure TServerFrmMain.ServerConnect(AThread: TIdPeerThread);

var

  NewClient: PClient;

begin

    new(NewClient);

    NewClient.DNS := AThread.Connection.Socket.Binding.PeerIP;

    NewClient.Connected :=  Now;

    NewClient.LastAction := NewClient.Connected;

    NewClient.Thread := AThread;

    AThread.Data := TObject(NewClient);

    try

         Clients.LockList.Add(NewClient);

    finally

         Clients.UnlockList;

    end;

    Protocol.Lines.Add(TimeToStr(Time) + ' Присоединился "' + NewClient.DNS + '"');

end;

 

Это процедура возникающая  при присоединении нового клиента, она сохраняет в структуре типа PClient, который следующую информацию:

    NewClient.DNS := AThread.Connection.Socket.Binding.PeerIP;

{Сохраняет IP подключившегося клиента.}

    NewClient.Connected :=  Now;

{Сохраняет дату подключения.}

    NewClient.LastAction := NewClient.Connected;

{Сохраняет дату последнего действия}

    NewClient.Thread := AThread;

{Сохраняет указатель на вызвавший поток.}

   AThread.Data := TObject(NewClient);

{Сохраняет заполненную структуру с информацией о вызвавшем потоке, в свойстве Data этого же потока, для дальнеишего доступа к полям струтуры NewClient по мере надобности.}

 

Событие OnExecute возникает после подключения клиента к серверу.

procedure TServerFrmMain.ServerExecute(AThread:TIdPeerThread);

var

ActClient, RecClient: PClient;

 

CommBlock, NewCommBlock: TCommBlock;

{струтура  содержащая информацию о считанной  и записываемой команде соответвтвенно}

 

RecThread: TIdPeerThread;

{поток в  который будет производится запись}

 

i: Integer;

begin

     if not AThread.Terminated and AThread.Connection.Connected then

{проверка  активности потока и подключения}

 

     begin

          AThread.Connection.ReadBuffer(CommBlock, SizeOf (CommBlock));

ActClient := PClient(AThread.Data);

{информация о потоке с которого произошло чтение}

 

 if ((CommBlock.Command = 'START') and (not Player1)) then

{если  считана команда START и это первый присоединившийся игрок}

 begin

      Player1 := True;

      Protocol.Lines.Add(TimeToStr(Time) + ' Игрок ' + ActClient.DNS + ' готов начать игру');

      NewCommBlock.Command := 'FIRST';

      AThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

{отправка  ответа игроку делающему 1 ход}

 end

 else

 if ((CommBlock.Command = 'START') and (not Player2)) then

{если считана  команда START и это второй присоединившийся игрок}

 begin

      Player2 := True;

      Protocol.Lines.Add(TimeToStr(Time) + ' Игрок ' + ActClient.DNS + ' готов начать игру');

      NewCommBlock.Command := 'SECOND';

      AThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

{отправка  ответа игроку делающему ожидающему  хода противника}

      with Clients.LockList do

           try

                for i := 0 to Count-1 do

                begin

                     RecClient := Items[i];

                     RecThread := RecClient.Thread;

                     NewCommBlock.Command := 'GO';

                     RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

{отправка  команды игрокам о начале игры}

                 end;

           finally

                Clients.UnlockList;

           end;

  end

  else

  if (CommBlock.Command = 'SHOT') then

{если считана  команда SHOT - вычтрел }

  begin

      NewCommBlock := CommBlock;

      Protocol.Lines.Add(TimeToStr(Time)+ ' Игрок ' + ActClient.DNS + ' стреляет по координатам : x: '+ IntToStr(CommBlock.Coord.x) + ' y: ' + IntToStr(CommBlock.Coord.y));

      with Clients.LockList do

      try

          RecClient:=Items[0];

          if RecClient.Thread <> AThread then

          begin

                RecThread:=RecClient.Thread;

                RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

         end

         else

         begin

              RecClient:=Items[1];

              RecThread:=RecClient.Thread;

              RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

         end;

    finally

          Clients.UnlockList;

   end;

  end

  else

       if (CommBlock.Command = 'SLIP') then

{если считана команда SLIP - промах }

 

       begin

            NewCommBlock := CommBlock;

  Protocol.Lines.Add(TimeToStr(Time)+ ' Игрок ' + ActClient.DNS + ' не попал в корабль по координатам : x'+ IntToStr(CommBlock.Coord.x) + ' y: ' + IntToStr(CommBlock.Coord.y));

  with Clients.LockList do

        try

               RecClient:=Items[0];

               if RecClient.Thread <> AThread then

               begin

                    RecThread:=RecClient.Thread;

                    RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

               end

               else

               begin

                    RecClient:=Items[1];

             RecThread:=RecClient.Thread;

             RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

      end;

      finally

       Clients.UnlockList;

      end;

  end

  else

   if (CommBlock.Command = 'HIT') then

{если считана  команда HIT - попадание }

   begin

        NewCommBlock := CommBlock;

        Protocol.Lines.Add(TimeToStr(Time)+ ' Игрок ' + ActClient.DNS + ' попал в корабль по координатам : x'+ IntToStr(CommBlock.Coord.x) + ' y: ' + IntToStr(CommBlock.Coord.y));

      with Clients.LockList do

       try

        RecClient:=Items[0];

          if RecClient.Thread <> AThread then

          begin

                RecThread:=RecClient.Thread;

                RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

          end

          else

          begin

                RecClient:=Items[1];

                RecThread:=RecClient.Thread;

                RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);

          end;

       finally

            Clients.UnlockList;

       end;

            end

GlobalUnit.dcu

— 561 байт (Скачать документ)

GlobalUnit.pas

— 1.14 Кб (Скачать документ)

Project1.cfg

— 446 байт (Скачать документ)

Project1.dof

— 1.97 Кб (Скачать документ)

Project1.dpr

— 381 байт (Скачать документ)

Project1.dproj

— 6.73 Кб (Скачать документ)

Project1.dproj.local

— 62 байт (Скачать документ)

Project1.exe

— 518.00 Кб (Скачать документ)

Project1.identcache

— 77 байт (Скачать документ)

Project1.res

— 1.99 Кб (Скачать документ)

Project1.~dpr

— 381 байт (Скачать документ)

Project1_Icon.ico

— 766 байт (Скачать документ)

Unit1.dcu

— 15.59 Кб (Скачать документ)

Unit1.ddp

— 51 байт (Скачать документ)

Unit1.dfm

— 3.60 Кб (Скачать документ)

Unit1.pas

— 12.17 Кб (Скачать документ)

Unit1.vlb

— 3 байт (Скачать документ)

Unit1.~ddp

— 51 байт (Скачать документ)

Unit1.~dfm

— 3.60 Кб (Скачать документ)

Unit1.~pas

— 11.72 Кб (Скачать документ)

Unit2.dcu

— 637 байт (Скачать документ)

Unit2.pas

— 174 байт (Скачать документ)

Unit2.~pas

— 6.43 Кб (Скачать документ)

Unit3.dcu

— 3.78 Кб (Скачать документ)

Unit3.ddp

— 51 байт (Скачать документ)

Unit3.dfm

— 857 байт (Скачать документ)

Unit3.pas

— 557 байт (Скачать документ)

Unit3.~ddp

— 51 байт (Скачать документ)

Unit3.~dfm

— 882 байт (Скачать документ)

Unit3.~pas

— 713 байт (Скачать документ)

Unit4.dcu

— 4.28 Кб (Скачать документ)

Unit4.ddp

— 51 байт (Скачать документ)

Unit4.dfm

— 1.11 Кб (Скачать документ)

Unit4.pas

— 883 байт (Скачать документ)

Unit4.~ddp

— 51 байт (Скачать документ)

Unit4.~dfm

— 1.09 Кб (Скачать документ)

Unit4.~pas

— 742 байт (Скачать документ)

Unit1.dfm.~1~

— 1.85 Кб (Скачать документ)

Unit1.dfm.~2~

— 2.69 Кб (Скачать документ)

Unit1.dfm.~3~

— 2.72 Кб (Скачать документ)

Unit1.dfm.~4~

— 2.75 Кб (Скачать документ)

Unit1.dfm.~5~

— 2.61 Кб (Скачать документ)

Unit1.dfm.~6~

— 2.65 Кб (Скачать документ)

Unit1.dfm.~7~

— 2.64 Кб (Скачать документ)

Unit1.pas.~1~

— 1.96 Кб (Скачать документ)

Unit1.pas.~2~

— 2.95 Кб (Скачать документ)

Unit1.pas.~3~

— 2.95 Кб (Скачать документ)

Unit1.pas.~4~

— 3.01 Кб (Скачать документ)

Unit1.pas.~5~

— 2.76 Кб (Скачать документ)

Unit1.pas.~6~

— 2.56 Кб (Скачать документ)

Unit2.pas.~1~

— 4.20 Кб (Скачать документ)

Unit2.pas.~2~

— 4.20 Кб (Скачать документ)

Unit2.pas.~3~

— 4.36 Кб (Скачать документ)

Unit2.pas.~4~

— 4.39 Кб (Скачать документ)

GlobalUnit.~pas

— 1.04 Кб (Скачать документ)

Server.cfg

— 446 байт (Скачать документ)

Server.dof

— 1.97 Кб (Скачать документ)

Server.dpr

— 915 байт (Скачать документ)

Server.exe

— 461.50 Кб (Скачать документ)

Server.res

— 876 байт (Скачать документ)

Server.~dpr

— 915 байт (Скачать документ)

ServerFrmMainUnit.dcu

— 11.19 Кб (Скачать документ)

ServerFrmMainUnit.ddp

— 51 байт (Скачать документ)

ServerFrmMainUnit.dfm

— 2.28 Кб (Скачать документ)

ServerFrmMainUnit.pas

— 9.24 Кб (Скачать документ)

ServerFrmMainUnit.~ddp

— 51 байт (Скачать документ)

ServerFrmMainUnit.~dfm

— 2.28 Кб (Скачать документ)

ServerFrmMainUnit.~pas

— 9.24 Кб (Скачать документ)

Информация о работе Сервер игры “Морской бой”