Томский государственный университет систем управления и радиоэлектроники (тусур)
Кафедра компьютерных систем и
управления в проектировании (КСУП)
по курсовому проекту по дисциплине
«Алгоритмические языки и программирование»
- Тема проекта: Игра « Морской бой »
- Срок сдачи студентом законченной работы
- Исходные данные к проекту: На поле 10 на 10 позиций стоят невидимые вражеские корабли: 4 корабля по одной клетке, три корабля по 2 клетки, 2 корабля по 3 клетки, 1 корабль в 4 клетки. Позиции указываются русскими буквами от А до К (по строкам) и цифрами от 1 до 10 (по столбцам). Конфигурация и положение кораблей на поле выбираются с помощью датчика случайных чисел. Если клетка корабля угадана играющим верно, она отмечается крестиком, в противном случае точкой.
- Дата выдачи задания
Введение
22.06.2014 24.64 Кб 53 1-1 Алгоритмические языки.rtf
22.06.2014 24.27 Кб 46 2- 0_Алгоритмические языки.rtf
Ограничение
Программирование на С++. Урок 36. Морской бой
Для продолжения скачивания необходимо пройти капчу:
Источник: studfile.net
морской бой на с++
Недавно написал морской бой, хоть код и рабочий ,но мне кажется ,что он плохой и в нём куча ошибок. Так как я только недавно стал изучать с++ , то сам эти ошибки не увижу. Если вам не трудно , то можете дать несколько советов по этому коду. Заранее огромное спасибо.
#include #include #include #include #include #include using namespace std; void field(string(b2)[10][10]) < cout cout cout cout cout > > void help(short s, 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()
Отслеживать
1,339 13 13 серебряных знаков 28 28 бронзовых знаков
задан 27 окт 2021 в 9:53
37 5 5 бронзовых знаков
Делаем игру Морской бой на Python / Урок #1
Ваш код очень сложно понять. Именование переменных явно «хромает». Называйте переменные согласно их предназначению.
27 окт 2021 в 10:00
а какие «ошибки» Вы хотите? по работе или по душку кода?
27 окт 2021 в 10:10
koVadim,ну ,ошибки в оптимизации кода, если они там есть
27 окт 2021 в 17:43
ох ох. ошибки оптимизации. какой ещё оптимизации?
28 окт 2021 в 9:43
ну, где то за место одной части кода можно использовать что то другое ,чтобы сократить код
28 окт 2021 в 10:49
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
- Названия переменных плохие, надо переименовать
- Для массивов лучше использовать std::array
- Лучше не использовать using namespace std;
- Лучше не использовать неявные преобразования типов (в индексах, например)
- Вместо endl лучше использовать n
- Вместо односимвольных строк лучше использовать символы
- Вместо множества явных пробелов для форматирования лучше использовать манипуляторы
- Стоит добавить обработку ошибок, а то непонятно, что вводить игроку
Отслеживать
9,507 9 9 золотых знаков 24 24 серебряных знака 35 35 бронзовых знаков
ответ дан 27 окт 2021 в 10:01
21 2 2 бронзовых знака
добро пожаловать на Stack Overflow на русском! пожалуйста, постарайтесь оставлять чуть более развёрнутые ответы. дополнить ответ можно, нажав править
27 окт 2021 в 10:01
27 окт 2021 в 10:05
обработка ошибок это если введены неправильные координаты и ты выводишь «неверные координаты, впишите заново» ?
27 окт 2021 в 10:26
В коде кроме всяких мелочей (типа endln) есть более глобальные проблемы. Начнем с мелкого, постепенно пофиксим немного.
Первое, что бросается в глаза, это вот это
string a[10][10];
после того, как присмотришься, стает понятно, что это игровое поле и a и b — это свое и противника, но абсолютно не очевидно, где чье. Сделаем первый шаг — заведем отдельный тип для этого и добавим туда пару функций.
class Field < std::string m_field[10][10]; public: const std::string return m_field[x][y]; >void set(int x, int y, const std::string m_field[x][y] = x; >>;
этот класс просто заворачивает массив в себя. Многие на этом моменте скажут, мол, нужно уже на char поменять или использовать вектор векторов. Не нужно спешить, такое делается мелкими шагами.
Теперь в коде заиспользуем этот класс и посмотрим как оно будет.
И сразу видим в функции game вот такое
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»; >>
хм, так это же 4 массива заполняются символами. Более того, просто повезло, что размеры совпали удачно. Но это кандидат на отдельную функцию в Field.
А сделаем вот так
a2.fill(«?»); b2.fill(«?»); a.fill(«0»); b.fill(«0»);
void fill(const std::string for (int i = 0; i < width; i++) < for (int j = 0; j < height; j++) < m_field[i][j] = el; >> >
да, ещё не очевидно, что значат знаки вопроса, но уже понятна суть. Двигаемся дальше по функции game.
field(a2, b2); help(l, s, a2, b2);
идем в сигнатуры этих функций и меняем типы.
функция 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<(std::ostream 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 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<(std::ostream 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 b2) < cout cout cout cout cout > > void get_user_input(short s, 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 b2, Field 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 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); >
Но тут ещё работать и работать, а у меня есть и своя работа.
Источник: ru.stackoverflow.com
Игра морской бой на языке программирования PYTHON (ч.1)
Я решил немного отступить от обзора моей игры WORLDSPACE и показать, как можно быстро написать простую и довольно популярную игру «морской бой».
игровой автомат «морской бой» и взгляд сквозь перископ прицела
Моя игра будет немного проще, но анимации побольше)). Пожалуй, начнем!
Любая программа на python начинается с импорта необходимых модулей. Нам понадобятся модули tkinter и из модуля PIL мы загрузим Image, ImageTk:
import tkinter as tk
from tkinter import*
from PIL import Image, ImageTk
tkinter — это графический интерфейс, в котором будет отображаться наша игра, а image и ImageTk из библиотеки PIL — загрузка и обработка картинок.
root.geometry(«1000×546+2+10»)
root.resizable(width=False, height=False)
root = tk.Tk() — создание главного окна нашей игры
root.geometry(«1000×546+2+10») — геометрия главного окна (ширина, высота, координата х верхнего левого угла, координата у верхнего левого угла)
root.resizable(width=False, height=False) — запрет изменения размеров главного окна по ширине и высоте
frames = [PhotoImage(file=’C:\sea\sea_011.gif’, format = ‘gif -index %i’ %(i)) for i in range(20)] — создание списка методом генератора списков и заполнение этого списка кадрами из gif-анимации и присвоение переменной frames этого списка. Число (20) в цикле — это количество кадров, которое содержит gif-анимация.
Небольшое отступление. gif-анимацию можно скачать с интернета, а можно ее сделать самому. Я делал ее сам при помощи программы Sqirlz Water Reflections — наложение спецэффектов на воду.
Создаем холст для размещения будущей графики:
canvas1 = Canvas(root, width = 1000, height = 546) — root — родитель для холста, ширина холста 1000 пикселей, высота 546 пикселей
Упаковываем холст методом place в родительском окне:
canvas1.place(x = 0, y = 0) — упаковка place — абсолютные координаты в родительском окне (root) — указывается верхний левый угол.
Следующий код — загрузка кораблика (будущая мишень) в программу. Здесь загружаем два кораблика — для движения налево и направо.
im = Image.open(«C:\sea\ships_10_001.png»).convert(‘RGBA’)
datas = im.getdata()
opacity_level = 0
for item in datas:
if item[0] == 127 and item[1] == 127 and item[2] == 127:
newData.append((0, 0, 0, opacity_level))
newData.append(item)
im.putdata(newData)
ship1 = ImageTk.PhotoImage(im)
fon = canvas1.create_image(0, 0, anchor = ‘nw’, image = frames[0])
ships = canvas1.create_image(600, 300, anchor = ‘nw’, image = ship1)
im = Image.open(«C:\sea\ships_10_101.png»).convert(‘RGBA’)
datas = im.getdata()
opacity_level = 0
for item in datas:
if item[0] == 127 and item[1] == 127 and item[2] == 127:
newData.append((0, 0, 0, opacity_level))
newData.append(item)
im.putdata(newData)
ship2 = ImageTk.PhotoImage(im)
Изображение кораблика я взял с интернета и предварительно немного обработал в paint — убрал все, что не относится к кораблику окрасил в серый цвет(RGB палитра — 127,127,127). Каждый пиксель с этим цветом будет преобразован в прозрачный вот в этой строчке: newData.append((0, 0, 0, opacity_level)) .
fon = canvas1.create_image(0, 0, anchor = ‘nw’, image = frames[0])
ships = canvas1.create_image(600, 300, anchor = ‘nw’, image = ship1)
Этими строчками размещаем наши картинки на холсте. fon — это первый кадр из gif-анимации (frames[0]), ships — кораблик. Для размещения картинок на холсте используются методы холста create_image . Числа — это координаты х, у места позиционирования картинок. anchor = ‘nw’ — это якорь для картинок — относительно какой стороны картинки будут отсчитываться координаты их размещение.
В моем случае (nw) — северо-запад (верхний левый угол). image — какая картинка будет создана на холсте.
Следующий блок кода — функция анимации в нашей программе:
def update(ind, s, speed, fon, ships):
frame = frames[ind] — переменной передается кадр gif-анимации с индексом ind
ind += 1 — следующий кадр gif-анимации
if ind == 20: — если кадр gif-анимации последний
ind = 0 — обнуление индекса
canvas1.itemconfig(fon, image = frame) — изменение картинки gif-анимации на следующую
x = canvas1.coords(ships)[0] — текущая координата х кораблика
y = canvas1.coords(ships)[1] — текущая координата у кораблика
if s == ‘l’ and x > 10: — «l», «r» направление движение кораблика, если направление l и координата х больше 10 (правая сторона экрана)
x -= speed — изменение х на величину скорости кораблика (движение налево)
canvas1.itemconfig(ships, image = ship1) — если движение налево — картинка кораблика 1
else: — если достигли левой стороны экрана
s = ‘r’ — флаг направления меняется на противоположный
x += speed — движение направо
canvas1.itemconfig(ships, image = ship2) — если движение направо — картинка кораблика 2
if x < 12 or x >908: — если достигнут правый или левый край экрана
speed += 0.02 — увеличение текущей скорости на 0,02
y += 1 — изменение координаты у (кораблик спустился на 1 пиксель вниз)
x += speed — движение направо
canvas1.itemconfig(ships, image = ship2) — картинка — кораблик 2
else: — иначе
s = ‘l’- меняем флаг направления движения на противоположный
x -= speed — движение налево
canvas1.itemconfig(ships, image = ship1)
canvas1.coords(ships, x, y) — изменение текущих координат кораблика
root.after(25, update, ind, s, speed, fon, ships) — следующих «ход» для главного цикла программы: выполнить через 25мс, вызвать функцию update, вместе с этой функцией передаются параметры — текущий кадр gif-анимации (ind), флаг направлениядвижения кораблика (s), текущая скорость кораблика (speed), идентификаторы созданных картинок на холсте (fon, ships).
Вызов функции анимации:
update(0, ‘l’, 2, fon, ships)
Главный цикл, который запускает программу:
root.mainloop()
В следующей статье будет продолжение создания игры — анимация стрельбы по кораблику, анимация взрыва кораблика. А здесь можно посмотреть — что получилось на данном этапе.
Источник: dzen.ru