- Saved searches
- Use saved searches to filter your results more quickly
- DmT14/SeaBattle
- Name already in use
- Sign In Required
- Launching GitHub Desktop
- Launching GitHub Desktop
- Launching Xcode
- Launching Visual Studio Code
- Latest commit
- Git stats
- Files
- README.md
- About
- Морской бой на С++: как создать игру с нуля
- Основы игры
- Особенности создания Морского боя на С++
- Шаги по созданию игры
- Заключение
- морской бой на с++
- 2 ответа 2
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
Консольное приложение на C++ для игры в морской бой
DmT14/SeaBattle
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
SeaBattle — консольное приложение для игры в морской бой
Проект выполнялся в рамках курсовой работы. Цель проекта — разработка консольного приложения для игры в морской бой. Разработка велась на языке C++ с использованием IDE Visual Studio 2017. Оценка по результатам защиты — «отлично».
Данный репозиторий содержит файл с исходным кодом SeaBattle.cpp и исполняемый файл SeaBattle.exe . Для тестирования приложения Вы можете скачать исполняемый exe -файл и запустить его на своём компьютере (может появиться предупреждение от защитника Windows, но его нужно проигнорировать и всё равно запустить файл).
Скриншоты работы приложения
Далее приведены скриншоты работы приложения.
Начальное окно содержит информацию о правилах игры «Морской бой», особенностях данного приложения и авторе приложения. После прочтения пользователю необходимо нажать любую клавишу, после чего происходит переход к следующему окну.
В окне расстановки кораблей пользователю предлагается поочерёдно расставить корабли на своём поле посредством ввода координат начала и конца корабля.
После успешной расстановки кораблей пользователем происходит переход к следующему окну, в котором осуществляется игровой процесс.
По завершении игры появляется окно, в котором пользователь видит свое поле, а также поле компьютера. Если пользователь проиграл, он может посмотреть, где стояли не потопленные корабли компьютера. В этом же окне пользователь может сделать выбор: выйти из приложения или же начать новую игру.
About
Консольное приложение на C++ для игры в морской бой
Источник
Морской бой на С++: как создать игру с нуля
Морской бой – классическая настольная игра, которая может быть легендарной, если вы перенесете ее в мир программирования. В этой статье мы расскажем, как создать игру Морской бой на С++ с нуля.
Основы игры
Первым шагом в создании игры Морской бой является понимание правил игры настольного варианта. В игре есть два поля: поле игрока и поле компьютера. На каждом поле сетка 10х10 клеток. Игроки размещают свои корабли только по горизонтали и вертикали. Каждый корабль занимает одну или несколько клеток. Перед началом игры игроки размещают свои корабли на своем поле. Игроки по очереди совершают выстрелы в поле противника. Если выстрел попадает в клетку, которая занята частью корабля, то этот корабль получает повреждение. Если все клетки корабля поражены, то корабль уничтожается. Цель игры – уничтожить все корабли на поле противника.
Особенности создания Морского боя на С++
Создание игры на C++ может включать в себя некоторые сложности. Если вы хотите создать игру Морской бой на С++, вам потребуется некоторое знание языка программирования и его ключевых особенностей.
Шаги по созданию игры
- Начните с создания разметки полей игроков. Поле состоит из сетки клеток 10х10. С помощью C++ вы можете отслеживать состояние поля и кораблей на нем. Для этого вы можете использовать массив, который будет хранить состояние каждой клетки, а также массивы, которые будут отображать состояние каждого корабля на поле.
- Разработайте функции, которые будут отвечать за размещение кораблей на поле игрока и компьютера. Функция должна принимать в качестве аргумента поле, которое мы создали в первом шаге, номер корабля, которые требуется разместить, и координаты, где следует разместить корабль.
- Разработайте функцию, которая будет отвечать за игровой процесс. Функция должна принимать поле игрока и компьютера, а затем инструктировать игрока на совершение выстрела и следить за тем, как изменяется состояние игры.
- Разработайте систему, которая будет отслеживать количество оставшихся на поле кораблей и определять, кто победил.
Заключение
Создание игры Морской бой на С++ – это увлекательный процесс. Вы можете создать свою собственную версию классической настольной игры, которая будет захватывать дух игроков. Игра Морской бой на С++ может стать интересным проектом для начинающих программистов, которые хотят найти применение своим знаниям в практике.
Источник
морской бой на с++
Недавно написал морской бой, хоть код и рабочий ,но мне кажется ,что он плохой и в нём куча ошибок. Так как я только недавно стал изучать с++ , то сам эти ошибки не увижу. Если вам не трудно , то можете дать несколько советов по этому коду. Заранее огромное спасибо.
#include #include #include #include #include #include using namespace std; void field(string(&a2)[10][10], string(&b2)[10][10]) < cout cout cout cout cout > > void help(short& l, short& s, string(&a2)[10][10], string(&b2)[10][10]) < cout " > l; cout > s; int tu = 10; while (tu != 0) < tu = 0; if (s >9 || l > 9) < tu = 1; cout else if (s < 0 || l < 0) < tu = 1; cout > > int game(string a[10][10], string b[10][10]) < char t; short s, l; string a2[10][10]; string b2[10][10]; // заполнение масивов for (char i = 0; i < size(a2); i++) < for (char j = 0; j < size(a2); j++) < a2[i][j] = "?"; b2[i][j] = "?"; a[i][j] = "0"; b[i][j] = "0"; >> field(a2, b2); help(l, s, a2, b2); //расстановка корабля a[s][l] = "1"; a2[s][l] = '^'; system("cls"); field(a2, b2); help(l, s, a2, b2); cout > t; //расстановка корабля switch (t)< case '^' : if (s - 1 >= 0) < a[s][l] = "1"; a2[s][l] = "O"; a[s - 1][l] = "1"; a2[s - 1][l] = "^"; >break; case '>': if (l + 1 "; > break; case '= 0) < a[s][l] = "1"; a2[s][l] = "O"; a[s][l - 1] = "1"; a2[s][l - 1] = "break; case '!': if (s + 1 > system("cls"); field(a2, b2); help(l, s, a2, b2); cout > t; switch (t)< case '^': if (s - 2 >= 0) < a[s][l] = "1"; a2[s][l] = "O"; a[s - 1][l] = "1"; a2[s - 1][l] = "O"; a[s - 2][l] = "1"; a2[s - 2][l] = "^"; >break; case '>': if (l + 2 "; > break; case '= 0) < a[s][l] = "1"; a2[s][l] = "O"; a[s][l - 1] = "1"; a2[s][l - 1] = "O"; a[s][l - 2] = "1"; a2[s][l - 2] = "break; case '!': if (s + 2 > system("cls"); field(a2, b2); //бот расставляет корабли srand(time(NULL)); int TAB_BOT, LINE_BOT; TAB_BOT = rand() % 10; LINE_BOT = rand() % 10; b[TAB_BOT][LINE_BOT] = "1"; Sleep(200); int u = 0; l = 0; while (u != 1) < TAB_BOT = rand() % 10; LINE_BOT = rand() % 10; if (TAB_BOT - 1 > > Sleep(200); l = 0; while (l != 1) < TAB_BOT = rand() % 10; LINE_BOT = rand() % 10; if (TAB_BOT + 1 > > //бот закончил short bot_heat = 0, person_heat = 0; system("cls"); while (bot_heat < 6 && person_heat < 6) < field(a2, b2); cout > l; cout > s; if (b[s][l] == "1") < person_heat++; b2[s][l] = "*"; cout else < b2[s][l] = "x"; cout system("cls"); field(a2, b2); cout else < a2[TAB_BOT][LINE_BOT] = "x"; l = 0; >> > system("cls"); > if (bot_heat > person_heat) < cout else < cout return 0; > int main()
Ваш код очень сложно понять. Именование переменных явно «хромает». Называйте переменные согласно их предназначению.
2 ответа 2
- Названия переменных плохие, надо переименовать
- Для массивов лучше использовать std::array
- Лучше не использовать using namespace std;
- Лучше не использовать неявные преобразования типов (в индексах, например)
- Вместо endl лучше использовать \n
- Вместо односимвольных строк лучше использовать символы
- Вместо множества явных пробелов для форматирования лучше использовать манипуляторы
- Стоит добавить обработку ошибок, а то непонятно, что вводить игроку
добро пожаловать на Stack Overflow на русском! пожалуйста, постарайтесь оставлять чуть более развёрнутые ответы. дополнить ответ можно, нажав править
обработка ошибок это если введены неправильные координаты и ты выводишь «неверные координаты, впишите заново» ?
В коде кроме всяких мелочей (типа endl\n) есть более глобальные проблемы. Начнем с мелкого, постепенно пофиксим немного.
Первое, что бросается в глаза, это вот это
после того, как присмотришься, стает понятно, что это игровое поле и a и b — это свое и противника, но абсолютно не очевидно, где чье. Сделаем первый шаг — заведем отдельный тип для этого и добавим туда пару функций.
class Field < std::string m_field[10][10]; public: const std::string& get(int x, int y) < return m_field[x][y]; >void set(int x, int y, const std::string& v) < m_field[x][y] = x; >>;
этот класс просто заворачивает массив в себя. Многие на этом моменте скажут, мол, нужно уже на char поменять или использовать вектор векторов. Не нужно спешить, такое делается мелкими шагами.
Теперь в коде заиспользуем этот класс и посмотрим как оно будет.
И сразу видим в функции game вот такое
хм, так это же 4 массива заполняются символами. Более того, просто повезло, что размеры совпали удачно. Но это кандидат на отдельную функцию в Field.
a2.fill("?"); b2.fill("?"); a.fill("0"); b.fill("0");
void fill(const std::string& el) < for (int i = 0; i < width; i++) < for (int j = 0; j < height; j++) < m_field[i][j] = el; >> >
да, ещё не очевидно, что значат знаки вопроса, но уже понятна суть. Двигаемся дальше по функции game.
идем в сигнатуры этих функций и меняем типы.
функция help похоже ошибок не содержит из за замены типа, а вот field не повезло. Первое — там куча size(a2) . Если вдруг поле станет не квадратным — все пойдет кувырком. Но и кода там намешано куча, попробуем понять, что оно делает.
Для начала нам понадобится две функции в наш класс Field
int get_width() const < return width; >int get_height() const
и все эти size(a2) можно поменять. правда я делал это немного наугад.
теперь настало время поменять все a[i][j] на a.get(i,j) или a.set(i,j. ) .
После всех замен выясняется, что да, в массиве m_field могут хранится только символы. И не просто символы, а только определенные символы. Заведем перечисление для этого
enum class CellType < None, Type0, // 0 Type1, // 1 TypeQ, // ? TypeS, // * TypeO, // O Typeo, // o TypeU, // ^ TypeL, // < TypeR, // >TypeX, // x >;
и функцию для вывода. Она нам ещё пригодится.
std::ostream& operator<<(std::ostream& os, const CellType& c) < switch (c) < case CellType::None: os << ' '; break; case CellType::Type0: os << '0'; break; case CellType::Type1: os << '1'; break; case CellType::TypeQ: os << '?'; break; case CellType::TypeS: os << '*'; break; case CellType::TypeO: os << 'O'; break; case CellType::Typeo: os << 'o'; break; case CellType::TypeU: os << '^'; break; case CellType::TypeL: os << '<'; break; case CellType::TypeR: os << '>'; break; case CellType::TypeX: os return os; >
возникает вопрос — а почему такие странные имена? а я делал полуавтоматическую замену. я не до конца понимал суть каждого символа. Это следующий этап.
Теперь смотрим по коду и пытаемся приписать этим элементам перечисления «разумные имена».
enum class CellType < None, Type0, // 0 Ship, // 1 TypeQ, // ? Hit, // * TypeO, // O BowBottom, // o BowUp, // ^ BowLeft, // < BowRight, // >Miss, // x >;
Не все получилось, но это такое.
Теперь, если посмотреть в код, там есть ещё system(«cls») и Sleep, который немного напрягает. Давайте сделаем для этого маленький класс
class Platform < public: static void Init() < setlocale(LC_ALL, "rus"); >static void CleanScreen() < system("cls"); >static void Sleep(int s) < ::Sleep(s); >>;
На первый взгляд он выглядит странно, но на самом деле он инкапсулировал в себе все платформенно зависимое. И теперь вместе с #include можно унести в отдельный файл. Потом, позже, чуточку переделав, можно сделать этот код рабочим и под Linux/Mac или ncurce. Мелочь, а приятно.
Попутно выясняется, что функция field скорее всего должна называться show_field . Функция help на самом деле не только показывает подсказу, а и спрашивает координаты удара. get_user_input ? ask_user_about_coord ?. А по хорошему ее нужно ещё и разделить на несколько меньших.
Да, мы подобрались к самому вкусному. Функция game — она на самом деле огромная. Она должна быть порезана на куски. Более того, комментарии внутри намекают на это.
get_user_input(l, s, a2, b2); cout > t;
ой ой. мы получили координаты, а потом ещё прямо запрашиваем направление и чуть ниже заполняем наши поля. И посмотрев на это по новому, я понял, что это просто запрос одного однопалубного, одного двух палубного и одного трехпалубного. Неочевиденько.
В процессе выделения выясняется, что там есть прям готовая функция
void generate_bot_ships(Field& b)
о, значит b — это все таки от бот, а a — это игрок.
Я также заметил, что очень часто одни и теже переменные используются для разных целей. Не нужно боятся делать разные переменные для разных целей. одной такой есть переменная с именем l , которая и для пользовательского ввода используется, и для флажков.
#include #include #include #include #include #include using namespace std; class Platform < public: static void Init() < setlocale(LC_ALL, "rus"); >static void CleanScreen() < system("cls"); >static void Sleep(int s) < ::Sleep(s); >>; enum class CellType < None, Type0, // 0 Ship, // 1 TypeQ, // ? Hit, // * TypeO, // O BowBottom, // o BowUp, // ^ BowLeft, // < BowRight, // >Miss, // x >; std::ostream& operator<<(std::ostream& os, const CellType& c) < switch (c) < case CellType::None: os << ' '; break; case CellType::Type0: os << '0'; break; case CellType::Ship: os << '1'; break; case CellType::TypeQ: os << '?'; break; case CellType::Hit: os << '*'; break; case CellType::TypeO: os << 'O'; break; case CellType::BowBottom: os << 'o'; break; case CellType::BowUp: os << '^'; break; case CellType::BowLeft: os << '<'; break; case CellType::BowRight: os << '>'; break; case CellType::Miss: os return os; > class Field < static const int width = 10; static const int height = 10; CellType m_field[width][height]; public: const CellType get(int x, int y) < return m_field[x][y]; >void set(int x, int y, const CellType v) < m_field[x][y] = v; >void fill(const CellType el) < for (int i = 0; i < width; i++) < for (int j = 0; j < height; j++) < m_field[i][j] = el; >> > int get_width() const < return width; >int get_height() const < return height; >>; void show_field(Field& a2, Field& b2) < cout cout cout cout cout > > void get_user_input(short& l, short& s, Field& a2, Field& b2) < cout > l; cout > s; int tu = 10; while (tu != 0) < tu = 0; if (s >9 || l > 9) < tu = 1; cout else if (s < 0 || l < 0) < tu = 1; cout > > void ask_user_about_initial_ships(Field& a2, Field& b2, Field& a) < char t; short s, l; show_field(a2, b2); get_user_input(l, s, a2, b2); //расстановка корабля a.set(s, l, CellType::Ship); a2.set(s, l, CellType::BowUp); Platform::CleanScreen(); show_field(a2, b2); get_user_input(l, s, a2, b2); cout > t; //расстановка корабля switch (t) < case '^': if (s - 1 >= 0) < a.set(s, l, CellType::Ship); a2.set(s, l, CellType::TypeO); a.set(s - 1, l, CellType::Ship); a2.set(s - 1, l, CellType::BowUp); >break; case '>': if (l + 1 break; case '= 0) < a.set(s, l, CellType::Ship); a2.set(s, l, CellType::TypeO); a.set(s, l - 1, CellType::Ship); a2.set(s, l - 1, CellType::BowLeft); >break; case '!': if (s + 1 > Platform::CleanScreen(); show_field(a2, b2); get_user_input(l, s, a2, b2); cout > t; switch (t) < case '^': if (s - 2 >= 0) < a.set(s, l, CellType::Ship); a2.set(s, l, CellType::TypeO); a.set(s - 1, l, CellType::Ship); a2.set(s - 1, l, CellType::TypeO); a.set(s - 2, l, CellType::Ship); a2.set(s - 2, l, CellType::BowUp); >break; case '>': if (l + 2 break; case '= 0) < a.set(s, l, CellType::Ship); a2.set(s, l, CellType::TypeO); a.set(s, l - 1, CellType::Ship); a2.set(s, l - 1, CellType::TypeO); a.set(s, l - 2, CellType::Ship); a2.set(s, l - 2, CellType::BowLeft); >break; case '!': if (s + 2 > > void generate_bot_ships(Field& b) < short l; //бот расставляет корабли srand(time(NULL)); int TAB_BOT = rand() % 10; int LINE_BOT = rand() % 10; b.set(TAB_BOT, LINE_BOT, CellType::Ship); Platform::Sleep(200); int u = 0; l = 0; while (u != 1) < TAB_BOT = rand() % 10; LINE_BOT = rand() % 10; if (TAB_BOT - 1 > > Platform::Sleep(200); l = 0; while (l != 1) < TAB_BOT = rand() % 10; LINE_BOT = rand() % 10; if (TAB_BOT + 1 > > //бот закончил > int game(Field a, Field b) < //char t; short s, l; Field a2<>; Field b2<>; // заполнение масивов a2.fill(CellType::TypeQ); b2.fill(CellType::TypeQ); a.fill(CellType::Type0); b.fill(CellType::Type0); ask_user_about_initial_ships(a2, b2, a); Platform::CleanScreen(); show_field(a2, b2); generate_bot_ships(b); short bot_heat = 0, person_heat = 0; Platform::CleanScreen(); while (bot_heat < 6 && person_heat < 6) < show_field(a2, b2); cout > l; cout > s; if (b.get(s,l) == CellType::Ship) < person_heat++; b2.set(s,l, CellType::Hit); cout else < b2.set(s,l, CellType::Miss); cout Platform::CleanScreen(); show_field(a2, b2); cout else < a2.set(TAB_BOT,LINE_BOT, CellType::Miss); >need_to_continue = true; > > Platform::CleanScreen(); > if (bot_heat > person_heat) < cout else < cout return 0; > int main() < Platform::Init(); Field a<>; Field b<>; game(a, b); >
Но тут ещё работать и работать, а у меня есть и своя работа.
Источник