Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kursach.docx
Скачиваний:
108
Добавлен:
13.04.2015
Размер:
298.35 Кб
Скачать

3. Комп’ютерна модель гри «морський бій»

3.1 Обґрунтування вибору середовища програмної реалізації

Програма реалізована в середовищі розробки Microsoft Visual Studio 2008 на мові об'єктно-орієнтованого програмування С++.

Microsoft Visual Studio 2008 допомагає індивідуальним програмістам і невеликим групам, що створюють будь-які види ПО, прискорити розробку додатків і створення призначених для користувача інтерфейсів з принципово новим рівнем зручності, підвищити ефективність колективної роботи.

Visual Studio 2008 допомагає писати код швидше, підтримуючи безліч засобів і можливостей, які підвищують продуктивність праці.

Технологія Intellisense є різновидом авто завершення: як тільки ви вводите ім'я класу або об'єкту і ставите крапку, показується список доступних членів даного класу або об'єкту. Це прискорює кодування, оскільки зменшується кількість тексту, що набирає на клавіатурі.

Візуальні конструктори Visual Studio 2008 дозволяють створювати потужні і привабливі застосування, засновані на Windows Presentation Foundation, — графічній підсистемі

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

З метою зручнішого проектування, налаштування, і розділення окремих виконуваних операцій, програма побудована на класах, які взаємодіють між собою. Використання класів дає покращуваною розуміння коди, а значить налаштування і подальшу модифікацію вихідної коди програми. У даній програмі чітко просліджуються групи функцій, які із-за виконуваних ними операцій варто об'єднати в класи. Проаналізувавши наочну область програми можна виділити наступні класи:

-Game

-Main

-Computer

-Shell

Клас Main – клас, який забезпечує початок гри, містить в собі вісім функцій, а саме:

WinMain - точка входу в програму, аналог main в консольних додатках. У ній відбувається ініціалізація головного вікна.

WndProc - обробник подій. У цій функції перевіряється чи натискує кнопка.

InitializeShipButtonSelect - відбувається ініціалізація кнопок - кораблів, за допомогою яких відбувається розставляння їх на полі.

ActionsForAllButtons - обробник натиснення всіх кнопок, який залежно від типа кнопки перенаправляє подію в інший метод.

ActionsForCompFieldButton - обробник натиснення кнопок-поля комп'ютера, застосовується при грі.

ActionsForFieldButtons - обробник натиснення кнопок-поля користувача, застосовується при розставлянні.

CheckeNabledButton - перевіряє на кількість кораблів, що залишилися, на кожній палубі, якщо таких вже ні переводить кнопку в неактивований стан.

ActionsForPlaceButtons - обробник кнопок-кораблів розставляння.

Клас Game – забезпечую сам процес гри, містить в собі шість функцій:

Game - конструктор, ініціалізація всіх змінних.

InitializeFields - розставляє кнопки на формі(поля гравця і комп'ютера).

PlaceCompShip - розміщення кораблів комп'ютера.

NextCompStep - здійснюємо хід комп'ютера.

MakeUserShot - перевіряємо хід гравця і повертаємо стан.

~Game – деструктор.

Клас Computer – відповідає за гру комп’ютера. Містить в собі шість функцій:

ShotAlgorythm - алгоритм стрілянини комп'ютера.

PlaceShips - алгоритм розставляння кораблів комп'ютера

CheckShot - перевірка пострілу, занесення результатів в матрицю комп'ютера

ship_is_good - перевірка на можливість розташування корабля

set_ship_with_size - завдання корабля з певним розміром

set_ships - завдання всіх кораблів.

Клас Shell – відповідає а реалізацію пострілу.

3.3Інструкція користувача

Перед початком гри необхідно:

  1. Запустити гру «Морський бій».

  2. Розташувати всі свої кораблі.

  3. Почати гру, користувач завжди стріляє першим.

  4. Гра продовжується до тих пір, доки хтось не уб’є всі кораблі супротивника.

ВИСНОВКИ

У рамках даної курсової роботи була розроблена і реалізована гра «Морський бій». Було проведено дослідження компонентів програмного середовища Visual Studio 2008, які використовувалися при створенні гри. В результаті дослідження були виявлені наступні недоліки отриманого програмного продукту:

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

2. При повному потопленні корабля це ніяк не відбивається;

3. Неможливість повернення ходів назад;

4. Працездатність додатка лише в середовищі Windows;

Проте, окрім недоліків, є і достоїнства в цього програмного продукту:

  1. Можливість ручного розставляння кораблів гравця.

  2. Програмний продукт маловимогливий до системних ресурсів комп'ютера.

В результаті обліку всіх зроблених вище зауважень можливе поліпшення створеного програмного продукту, на яке буде потрібно мінімум змін вихідної коди програми.

перелік посилань

  1. Страуструп, Б. Язык программирования С++. Часть 1 [Текст] / Б. Страуструп; перевод с англ. – К.: ДиаСофт, 1993. – 264 с.

  2. Страуструп, Б. Язык программирования С++. Часть 2 [Текст] / Б. Страуструп; перевод с англ. – К.: ДиаСофт, 1993. – 296 с.

  3. Павловська, Т. А. C/С++. Програмування на мові високого рівня / Т. А. Павлівська. – СПб.: Пітер, 2010. – 461 с.

  4. Прата, С. Мова програмування С++. Лекції і вправи / С. Прата. М.: Вільямс, 2006. – 1184 с.

Додаток А

Вихідний текст програми

Constants.h

const int Empty = 0;

const int EmptyAndShooted = 1;

const int DeadZone = 2;

const int Hited = 3;

const int Ship = 4;

const int Killed = 5;

const int MaxCells = 20;

const int ColSize = 10;

const int FormLeft = 20;

const int FormTop = 20;

const int ButtonWidth = 20;

const int ButtonHeight = 20;

const int WidthBetweenFields = 100;

Shell.h

#pragma once

class Shell

{

private:

int _x;

int _y;

bool _isUser;

public:

int X(){return _x;}

int Y(){return _y;}

bool IsUser(){return _isUser;}

Shell(int x,int y, bool isUser){

_x = x;

_y = y;

_isUser = isUser;

}

bool IsNull(){return _x==0 && _y==0;}

~Shell(void);

};

Computer.h

#include "Shell.h"

#include <iostream>

class Computer

{

private:

int** _compField;

int** _possibleUserField;

Shell* _lastRightCell;

Shell* direction;

public:

Computer(int** userField);

Shell* ShotAlgorythm();

bool PlaceShips();

void CheckShot(Shell* shell, int state);

~Computer(void);

private:

bool ship_is_good(int size, bool is_horiz, int row_top, int col_left, int** field);

void set_ship_with_size(int size, int** field);

void set_ships();

};

Game.h

#pragma once

#include "Computer.h"

#include "Constants.h"

#include <Windows.h>

class Game

{

private:

int** _userField;

int** _compField;

int _lostUserCells;

int _lostCompCells;

Computer* _computer;

public:

int** GetUserField(){return _userField;}

Game(void);

void InitializeFields(HWND hwnd);

void PlaceCompShip(void);

Shell* NextCompStep(void);

int MakeUserShot(int x,int y);

~Game(void);

};

Shell.cpp

#include "Shell.h"

Computer.cpp

#pragma once

#include "Computer.h"

#include "Constants.h"

using namespace std;

Computer::Computer(int** compField)

{

_compField = compField;

direction=new Shell(0,0,false);

_possibleUserField = new int*[12];

for (int i=0;i<12;i++)

{

_possibleUserField[i]=new int[12];

for (int j=0;j<12;j++)

_possibleUserField[i][j]=Empty;

}

_lastRightCell = new Shell(0,0,false);

}

void Computer::CheckShot(Shell* shell, int state)

{

if (state==Ship)

{

if (!_lastRightCell->IsNull())

direction = new Shell(shell->X()-_lastRightCell->X(),shell->Y()-_lastRightCell->Y(),false);

_possibleUserField[shell->X()+1][shell->Y()+1]=Hited;

_lastRightCell=shell;

}

else

{

if (state==Killed)

{

_possibleUserField[shell->X()+1][shell->Y()+1]=Hited;

_lastRightCell = new Shell(0,0,false);

direction = new Shell(0,0,false);

}

else

{

_possibleUserField[shell->X()+1][shell->Y()+1]=EmptyAndShooted;

}

}

}

Shell* Computer::ShotAlgorythm()

{

int x;

int y;

if (_lastRightCell->IsNull())//Если мы не нашли ни одного корабля или все убиты

{

do

{

x = rand()%ColSize;

y = rand()%ColSize;

}

while (_possibleUserField[x+1][y+1]!=Empty);

}

else

{

if (direction->IsNull())

{

do

{

int dir = rand()%2;

if (dir==0)//по горизонтали

{

int dir2 = rand()%2;

y = _lastRightCell->Y();

if (dir2==0) //влево

x = _lastRightCell->X()-1;

else//вправо

x = _lastRightCell->X()+1;

}

else//по вертикали

{

int dir2 = rand()%2;

x = _lastRightCell->X();

if (dir2==0) //вверх

y = _lastRightCell->Y()-1;

else//вниз

y = _lastRightCell->Y()+1;

}

}

while (_possibleUserField[x+1][y+1]==EmptyAndShooted);

}

else

{

x=_lastRightCell->X()+direction->X();

y=_lastRightCell->Y()+direction->Y();

}

}

return new Shell(x,y,false);

}

bool Computer::PlaceShips()

{

try

{

set_ships();

}

catch(char *err_str)

{

return false;

}

return true;

}

Computer::~Computer(void)

{

}

//Private methods for setting ships

bool Computer::ship_is_good(int size, bool is_horiz, int row_top, int col_left, int** field)

{

if(is_horiz)

{

for(int i = row_top-1; i <= row_top + 1;++i)

{

for(int j = col_left - 1;j <= col_left + size; ++j)

{

if(field[i][j] == Ship) return false;

}

}

return true;

}

else//вертикальный

{

for(int i = row_top - 1; i <= row_top + size; ++i)

{

for(int j = col_left - 1; j <= col_left + 1; ++j)

{

if(field[i][j] == Ship) return false;

}

}

return true;

}

}

void Computer::set_ship_with_size(int size, int** field)

{

bool is_horiz = rand() % 2 == 0;

int row_top = 0;

int col_left = 0;

do

{

do

{

row_top = rand() % ColSize+1;

}while( !is_horiz

&& row_top > ColSize - size);

do

{

col_left = rand() % ColSize+1;

}while( is_horiz

&& col_left > ColSize - size);

}while(!ship_is_good(size, is_horiz, row_top, col_left, field));

if(is_horiz)

{

for(int j = col_left; j < col_left + size; ++j)

{

field[row_top][j] = Ship;

}

}

else//вертикальный

{

for(int i = row_top; i < row_top + size; ++i)

{

field[i][col_left] = Ship;

}

}

}

void Computer::set_ships()

{

for(int i = 0; i < 1; ++i)

{

set_ship_with_size(4, _compField);

}

for(int i = 0; i < 2; ++i)

{

set_ship_with_size(3, _compField);

}

for(int i = 0; i < 3; ++i)

{

set_ship_with_size(2, _compField);

}

for(int i = 0; i < 4; ++i)

{

set_ship_with_size(1, _compField);

}

}

Game.cpp

#include "Game.h"

Game::Game(void)

{

//Инициализируем поля игрока и компьютера пустыми клетками

_userField = new int*[12];

_compField = new int*[12];

for (int i=0;i<12;i++)

{

_userField[i]=new int[12];

_compField[i]=new int[12];

for (int j=0;j<12;j++)

{

_userField[i][j] = Empty;

_compField[i][j] = Empty;

}

}

_lostCompCells=20;

_lostUserCells=20;

_computer = new Computer(_compField);

}

int Game::MakeUserShot(int x,int y)

{

if (_compField[x][y]==EmptyAndShooted||_compField[x][y]==Hited)

return -1;

if (_compField[x][y]==Ship)

{

_lostCompCells--;

_compField[x][y]=Hited;

for (int i=x-1;i<=x+1;i++)

for (int j=y-1;j<=y+1;j++)

if (_compField[i][j]==Ship)

return Ship;

return Killed;

}

else

{

_compField[x][y]=EmptyAndShooted;

return _compField[x][y];

}

}

void Game::InitializeFields(HWND hwnd)

{

for (int pl = 0;pl<2;pl++) //поля для игрока и компьютера

{

for (int i=0;i<10;i++)

{

for (int j=0;j<10;j++)

{

int x = pl*(10*ButtonWidth + WidthBetweenFields) + FormLeft + i*ButtonWidth; //pl*(10*ButtonWidth + 50 int y = FormTop + j*ButtonHeight;

HWND button = CreateWindowEx(WS_EX_CLIENTEDGE,L"Button",L"",WS_CHILD|WS_VISIBLE,

x,y,ButtonWidth,ButtonHeight,hwnd,(HMENU)(pl*100+i*10+j),NULL,NULL);

}

}

}

}

void Game::PlaceCompShip(void)

{

while (!_computer->PlaceShips()){}

}

Shell* Game::NextCompStep(void)

{

if (_lostCompCells==0)

{

return new Shell(-10,-10,true);

}

Shell* shell = _computer->ShotAlgorythm();

int x = shell->X()+1, y = shell->Y()+1;

int state = Empty;

if (_userField[x][y]==Ship)

{

_lostUserCells--;

_userField[x][y]=Hited;

state = Killed;

for (int i=x-1;i<=x+1&&state!=Ship;i++)

{

for (int j=y-1;j<=y+1&&state!=Ship;j++)

{

if (_userField[i][j]==Ship)

{

state = Ship;

}

}

}

}

else

{

_userField[x][y]=EmptyAndShooted;

}

_computer->CheckShot(shell,state);

if (_lostUserCells==0)

return new Shell(-20,-20,false);

return shell;

}

Game::~Game(void)

{

}

Main.cpp

#pragma once

#include <iostream>

#include <Windows.h>

#include "Game.h"

#include <time.h>

using namespace std;

//constants

const char g_szClassName[] = "myWindowClass";

const int Width = 750;

const int Height = 400;

//variables

Game* game;

int** userField;

int selectedShip;

int Ships[4] = {4,3,2,1};

int lostShips = 10;

void Initialize()

{

game = new Game();

userField = game->GetUserField();

}

void ActionsForPlaceButtons(HWND hwnd,WPARAM wParam, LPARAM lParam)

{

selectedShip = wParam;

}

void ShowCompShips(HWND hwnd,int** compfield)

{

int **field = game->GetCompField();

for (int i=0;i<10;i++)

{

for (int j=0;j<10;j++)

{

if (field[i+1][j+1]!=Empty)

{

int BtnID = 100+i*10+j;

SetDlgItemText(hwnd,BtnID,L"X");

}

}

}

}

void CheckEnabledButton(HWND hwnd, WPARAM wParam, LPARAM lParam)

{

int shipID = selectedShip%1000-1;

Ships[shipID]--;

lostShips--;

if (Ships[shipID]==0)

{

HWND horizontalButton = GetDlgItem(hwnd,1001+shipID);

HWND verticalButton = GetDlgItem(hwnd,2001+shipID);

EnableWindow(horizontalButton,false);

EnableWindow(verticalButton,false);

}

if (lostShips==0)

{

game->PlaceCompShip();

ShowCompShips(hwnd,game->GetCompField());

}

}

void ActionsForFieldButtons(HWND hwnd, WPARAM wParam, LPARAM lParam)//расстановка кораблей

{

if (lostShips==0) return;

int x = wParam/10;

int y = wParam%10;

if (userField[x][y]!=Empty)

{

MessageBox(hwnd,L"Cell is reserved!",L"Atention",MB_ICONINFORMATION);

return;

}

if (selectedShip==0)

{

MessageBox(hwnd,L"Ship wasn't selected",L"Atention",MB_ICONINFORMATION);

return;

}

int horizonalCheck;

int verticalCheck;

if (selectedShip/1000==1)

{

horizonalCheck = selectedShip%1000+2;

verticalCheck = 3;

}

else

{

horizonalCheck = 3;

verticalCheck = selectedShip%1000+2;

}

for (int i=0;i<horizonalCheck;i++)

{

if (x+i>11)//Ограничение поля

{

MessageBox(hwnd,L"Can't place ship here!",L"Atention",MB_ICONINFORMATION);

selectedShip=0;

return;

}

for (int j=0;j<verticalCheck;j++)

{

if (userField[x+i][y+j]!=Empty)

{

MessageBox(hwnd,L"Cell is reserved!",L"Atention",MB_ICONINFORMATION);

selectedShip=0;

return;

}

}

}

for (int i=0;i<selectedShip%1000;i++)

{

int btnID;

if (selectedShip/1000==1)

{

userField[x+i+1][y+1] = Ship;

btnID = (x+i)*10+y;

}

else

{

userField[x+1][y+i+1] = Ship;

btnID = x*10+y+i;

}

wchar_t ch[2];

_itow_s(selectedShip%1000,ch,10);

SetDlgItemText(hwnd,btnID,ch);

}

CheckEnabledButton(hwnd,wParam,lParam);

selectedShip=0;

}

void ActionsForCompFieldButton(HWND hwnd, WPARAM wParam, LPARAM lParam)

{

if (lostShips!=0) return;

wParam-=100;

int x = wParam/10;

int y = wParam%10;

int state = game->MakeUserShot(x+1,y+1);

if (state==-1)

{

MessageBox(hwnd,L"This cell was used",L"Attention",MB_ICONINFORMATION);

return;

}

LPCTSTR str;

switch (state)

{

case Ship: str=L"Hit"; break;

case Killed: str=L"kill"; break;

default: str=L"Empty";break;

}

SetDlgItemText(hwnd,12345,str);

int btnID = 100+x*10+y;

switch (state)

{

case Ship: SetDlgItemText(hwnd,btnID,L"X"); break;

case Killed:SetDlgItemText(hwnd,btnID,L"X"); break;

default: SetDlgItemText(hwnd,btnID,L"*"); break;

}

Shell* sh = game->NextCompStep();

if (sh->X()==-10)//user win

{

MessageBox(hwnd,L"You win!",L"We have winner!",MB_ICONINFORMATION);

exit(0);

}

else if (sh->X()==-20)//comp win

{

MessageBox(hwnd,L"Computer win!",L"We have winner!",MB_ICONINFORMATION);

exit(0);

}

int ux = sh->X(), uy = sh->Y();

int ustate = userField[ux+1][uy+1];

switch (ustate)

{

case Hited:SetDlgItemText(hwnd,ux*10+uy,L"X");

break;

case Ship:SetDlgItemText(hwnd,ux*10+uy,L"S"); break;

default:SetDlgItemText(hwnd,ux*10+uy,L"*");

break;

}

}

void ActionsForAllButtons(HWND hwnd,WPARAM wParam, LPARAM lParam)

{

if (hwnd == INVALID_HANDLE_VALUE) return;

try

{

if (wParam/1000>0)

{

ActionsForPlaceButtons(hwnd,wParam,lParam);

}

else

{

if (wParam/100==0)

ActionsForFieldButtons(hwnd,wParam,lParam);

else if (wParam/100==1)

ActionsForCompFieldButton(hwnd,wParam,lParam);

}

}

catch(char *err_str)

{

MessageBox(hwnd,LPCWSTR(err_str),L"",MB_ICONERROR);

exit(0);

}

}

void InitializeShipButtonSelect(HWND hwnd)

{

int yPos=4;

for (int i=4;i>0;i--)

{

wchar_t chr[2];

_itow_s(i,chr,10);

int x = FormLeft+10*(ButtonWidth+1);

int y = FormTop+(ButtonHeight+10)*(yPos-i);

HWND button = CreateWindowEx(WS_EX_CLIENTEDGE,L"Button",chr,WS_CHILD|WS_VISIBLE,

x,y,ButtonWidth*i,ButtonHeight,hwnd,(HMENU)(1000+i),NULL,NULL);//корабли по горизонтали

HWND button1 = CreateWindowEx(WS_EX_CLIENTEDGE,L"Button",chr,WS_CHILD|WS_VISIBLE,

y,x,ButtonWidth,ButtonHeight*i,hwnd,(HMENU)(2000+i),NULL,NULL);//корабли по вертикали

}

CreateWindowEx(WS_EX_NOACTIVATE,L"STATIC",L"",WS_CHILD|WS_VISIBLE,240,150,60,15,hwnd,(HMENU)(12345),NULL,NULL);

}

// Step 4: the Window Procedure

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) //Обработка событий

{

switch(msg)

{

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_COMMAND:

if (HIWORD(wParam)==BN_CLICKED)//если событие нажатия на кнопку

{

ActionsForAllButtons(hwnd,wParam,lParam);

}

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, msg, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow) //main

{

srand(time(0));

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

//Step 1: Registering the Window Class

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = LPCWSTR(g_szClassName);

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{

MessageBox(NULL, L"Window Registration Failed!", L"Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

// Step 2: Creating the Window

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

LPCWSTR(g_szClassName),

L"Sea Battle",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, Width, Height,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{

MessageBox(NULL, L"Window Creation Failed!", L"Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

//Create controls

Initialize();

InitializeShipButtonSelect(hwnd);

game->InitializeLetters(hwnd);

game->InitializeFields(hwnd);

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

// Step 3: The Message Loop

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{

TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

ДОДАТОК В

Тестування програми

Рис.1 – Початок гри «Морський бій»

Рис.2 – Гравець розташував свої кораблі

Рис.3 – Повідомлення про невірне розташування корабля

Рис.4 – Повідомлення про попадання у корабель супротивника

Рис.5 – Повідомлення про потоплення корабля супротивника

Рис.6 – Повідомлення про отримання перемоги гравцем

Рис.7 – Повідомлення про перемогу комп’ютера

Рис.8 – Перевірка вірності розташування кораблів комп’ютера

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]