Как написать морской бой

Как написать морской бой

Здраствуйте. Я, Иван. Хотел бы сделать игру, WoW-killer суть такова.

Думаю, рано или поздно любого заядлого геймера при задрачивании очередной игрушки посещает примерно мысль "Черт, почему разработчики не могли добавить %фичанейм?". При определенном стечении обстоятельств мысль трансформируется в "Я же могу сделать лучше!". Ну из нее берет начало неудержимый поток: "Ох, а как было бы здорово сделать свою игру"; "Круто было бы сделать Доту, только с лазерами"; "А ведь на этом можно еще и кучу денег заработать!"; "Все, с завтрашнего дня начинаю". И, как правило, не начинают. По крайней мере, так было до сих пор у меня.

Постановке этой цели предшествовало много креативных идей, грез о золотых горах и изрисованных клочков бумаги. Начиналось все с пристрастия к играм меня и моего тогдашнего начальника. Постепенно обсуждения игр в курилке перерастали в обсуждение того, как круто будет сделать свою игру. И конечно же, это должна была быть убийца WoW, EVE и Lineage вместе взятых. После были попытки хоть немного структурировать идеи на бумаге. У меня до сих пор валяется где-то стопка листиков с набросками идей, корявыми концепт-артами и списками киллер-фич в духе "опупенная графика; живой мир; реалистичная экономика" и подобными. Естественно, так они на бумаге и остались — вряд ли два хеллоуворлдщика в обозримые сроки могут сделать игру, напичканную функционалом пяти лучших игр, сделанных топовыми профессиональными студиями. Однако кое-что я все-таки сделал: прошел туториал по разработке игр на allegro под C++, написал 216 строчек кошмарного кода на python, воплощая менее масштабную идею зомби-шутера (если кому интересно, тут ). А еще мы перелопатили огромное количество книг, статей и howto из области геймдева. Постепенно пришло понимание того, что глобальную игрушку мы не потянем даже если наймем программистов и художников. Так что WoW-killer трансформировался сначала в Dota-killer, потом в "простенькую игрушку с корованами и корабликами", а теперь — в "морской бой для мобилок с небольшими фичами. Надо же с чего-то начинать".

Работа над морским боем началась недели две назад с выбора инструментов. Выбор остановили на unity — хотелось выпустить игру побыстрее и начать снова ломать зубы о старые идеи. Первая неделя прошла за изучением обучалок и попытками не заспамить мегафичами обучающий проект. Вторая неделя ознаменовалась попытками написания мегадвижка для сетки — яркий пример overengineering. По замыслу, центральным объектом игры становилась сетка, которая должна была отвечать и за размещениемасштабирование кораблей, и за обработку событий, и за игровую логику. В итоге получилось нечто забашованное, но играбельное. Однако дальнейшая разработка сулила сплошную головную боль и страдания, поэтому сегодняшний день будет посвящен переосмыслению картины мира и рефакторингу кода. Нужно сильно постараться снова не накодить лишнего функционала "на потом". Ну а до 31-го декабря нужно уже доделать это чудо ламерской мысли и приступить к навешиванию фич.

Критерий завершения

Игра доступна для скачивания

Личные ресурсы

Личное время 247, появившееся после сокращения с работы

Экологичность цели

Эта цель необходима мне для начального погружения в gamedev, повышения скилла "программирование" и первого опыта доведения проекта до финала.

Разработка стандартной версии "морского боя"

Этот этап нужен больше для того, чтобы хоть немного набить руку на программировании и unity.

Игра на конец этапа должна выглядеть просто: два поля на экране, вместо кораблей — стандартные кубы unity соответствующей длины. Игроку противостоит противник, который действует случайным образом. Игра делится на 3 стадии: расстановка, бой, конец игры.

Расстановка: из меню выбирается корабль длиной l, расположенный горизонтально (вдоль x) по умолчанию. Ориентацию корабля можно менять на вертикальную. Далее выбирается клетка на поле игрока, в которую корабль будет помещен, и если клетки на площади размещения корабля свободны, то корабль размещается на поле. Этап заканчивается после нажатия на кнопку "начать игру" в случае если все корабли игрока были расставлены на поле. В начале этого этапа ИИ также расставляет свои корабли.

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

Конец игры: Вывод статистики игры и предложение сыграть еще одну партию. После принятия предложения поля игрока и противника приводятся в изначальный вид, и игра возвращается в режим "Расстановка".

Читайте также:  Найти автомобиль по номеру телефона владельца

Здравствуйте, я вообще верстальщик, учусь в магистратуре.

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

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

1) Как сделать перетаскивание + разворачивание кораблей разного размера на площадке?
2) Каким образом сохранять все в noSQL и какую использовать?

Полный текст задания:

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

Цель игры — первым поразить корабли противника.
Игровое поле — квадрат 10х10 у каждого игрока, на котором игрок размещает свои корабли

В состав эскадры каждого игрока входят:
* 1 корабль — ряд из 4 клеток (четырёхпалубный)
* 2 корабля — ряд из 3 клеток (трёхпалубный)
* 3 корабля — ряд из 2 клеток (двухпалубный)
* 4 корабля — ряд из 1 клетки (однопалубный)
При размещении корабли не могут касаться друг друга даже углами.

Необходимо создать приложение для игры в морской бой. Программа должна допускать два режима игры:
* Человек-компьютер (бот)
* Человек-человек

Функциональные требования:
1. Программа должна состоять из RESTful-сервиса (API) и клиентской части (html5/Javascript).
2. В качестве хранилища данных использовать nosql.
3. Клиентская часть не должна использовать polling запросы (возможно использование async, web socket, SignalR).
4. Программа должна позволять регистрацию пользователя, создание новой игры, выбор режима (с ботом или с человеком), просмотр статистики игр и текущего рейтинга среди всех пользователей.
5. Клиентская часть должна позволять визуально разместить корабли вручную либо по желанию пользователя разместить рандомно с возможность ручного изменения.
6. Сервис должен поддерживать одновременно несколько игровых сессий.
7. Программа должна позволять сохранение и возобновление игр.
8. В игре устанавливается таймаут (лимит по времени на ход), по истечении которого выставляется поражение (нет необходимости в функционале пауз).

Предисловие

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

Общая концепция текущей реализации

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

Стратегия расстановки кораблей следующая: 2-3-4 палубные размещаются по краям карты (2 клетки), 1-палубный в центре (квадрат 6х6).

Стратегия ходов, как в игре между людьми: первый ход наобум, если попал, то прорабатываем 4 клетки вокруг и далее, если попал повторно, то прорабатываем по две клетки уже на линии (две, т.к. макс. длинна корабля 4 клетки, в 2 уже попал, значит макс. есть ещё 2 клетки).

В статье на Википедии всё достаточно подробно описано, поэтому не буду здесь сильно касаться игровой логики, тем более, что и так все примерно понимают, о чём идёт речь. У меня отличия только такие: начисление очков за каждый ход, нумерация клеток от 0 до 9.

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

Game отвечает за общую игровую логику, Player — за стратегию ходов, Ship — хранит текущее состояние кораблей и их координаты.

Ссылка проект в GitHub.

Основные сложности, которые возникли входе разработки

1. Проектирование. Писать с использованием классов или функций? Какой набор классов использовать?
Основной проблемой при проектировании оказалось отслеживание различных состояний в игре. Например, кто сейчас ходит, в каком состоянии корабль (подбит, убит), не закончилась ли игра, кто выиграл и т.п.

2. Логика/алгоритмы. Как расставить корабли в соответствии со стратегией, как выбрать координаты для хода?

Обзор наиболее интересных частей кода

return_shoot_state — определяет дальнейшую стратегию в зависимости от результатов текущего хода.

Важные переменные: recomendation_pool — список координат для будущих выстрелов, succ_shoots — последний успешный выстрел.

Если мы попали в корабль, то, во-первых, нужно начислить себе очки за успешный выстрел (scores += 1), а во-вторых, понять, что делать дальше. Мы проверяем recomendation_pool, есть ли там что-то, если нет, то записываем туда 4 близлежащих координаты (предварительно отфильтровав их по границам поля и списку координат, по которым мы уже стреляли).

Читайте также:  Сколько воды берет стиральная машинка

Если recomendation_pool не пустой — это значит, что мы попали второй раз и речь уже идёт не о 4 координатах вокруг, а о двух с каждого края.

Если текущим выстрелом корабль был потоплен, мы считаем свою задачу выполненной и зачищаем пул рекомендаций и проч. Следующий выстрел будет выполнен случайным образом.

service.gen_cord — генерирует все возможные координаты для каждого типа кораблей. Результатом работы функции будет словарь со следующей структурой: <«S0»:[[[x0,y0],[x1,y2],[xN0,yN1]], [[x3,y3],[x4,y4],[xN2,yN3]], . ], «S1»: . >, где S — тип корабля, [[x0,y0],[x1,y2],[xN0,yN1]] — набор координат для корабля.

Важные переменные: all_comb — хранит координаты поля в формате [[x0,y0], [x1,y1], . ]. for_1_ship — тот самый квадрат 6х6 для однопалубных, for_other_ship — набор координат для всех остальных кораблей. cord_comb — словарь, который хранит все комбинации координат.

Расстановка кораблей

В момент инициализации экземпляра класса Player также расставляются и корабли. В классе за это отвечает метод create_ships, где происходит следующее:

1. Для каждого корабля (ships) из доступной последовательности комбинаций координат (combinations) псевдослучайным образом (random.choice) выбирается набор координат.
2. Далее для набора координат генерируется ореол (service.set_halo). Ореол — это набор координат в которые нельзя будет поставить потом корабль (правило: не размещать корабли рядом).

3. После чего зачищаем список комбинаций (data_cleaner) из списка который состоит из координат корабля и ореола.

Модуль Logging

Под конец разработки открыл для себя модуль logging из стандартной библиотеки. Поля для вывода настраиваются (logging.basicConfig), а работать с выводом не сложнее, чем с print.

Прочее

sevice.rdn_usr_name — генерирует случайные имена игроков из набора букв и цифр от 0 до 999.

Игра заканчивается, если у противника Player.ships_defeat = 10, т.е. потоплены все 10 кораблей. Счётчик обновляется, если корабль отвечает «Убил!».

Список улучшений (TO DO)

1. Сделать турнир между игроками, скажем, где будет 1000 игроков. По идее, с учётом текущего времени выполнения весь турнир должен занять примерно 30 сек.

2. Добавить «базовый алгоритм» хода, например, ходить крест на крест, т.е. пробивать все клетки по диагонали и потом далее. Реализовать несколько таких алгоритмов и далее присваивать случайным образом работу по ним игроку. После чего сравнивать эффективность (например, что даёт больше результата случайные ходы или алгоритм «крест на крест»?)

3. Оптимизировать механизм поиска комбинаций (service.gen_cord), т.к. очевидно, что он избыточен и отнимает много ресурсов.

4. Реализовать различные стратегии размещения кораблей и потом сравнить какая из них наиболее успешна.

P.S. Буду признателен за любые интересные идеи.

Турнир реализован + сделан небольшой сбор статистики и вот что получается:

В турнире идёт игра на вылет, т.е. если проиграл на след. ступень уже не попадаешь.

Чтобы турнир был без косяков количество игроков должно быть, чтобы при делении остаток от деления всегда делился на 2 и так до того как число игроков в турнире не будет 1 (т.е. победитель). К таким числам относятся 1024 (512, 256, 128, 64, 32, 16, 8, 4, 2).

Ранее я предполагал, что турнир будет длиться порядка 30 секунд, т.е. время вырастает линейно в зависимости от количества игроков, однако каково же было моё удивление, когда весь турнир для 1024 игроков всего 17 секунд. Почему получается 17 секунд мне не ведомо, возможно начинают работать какие-то механизмы оптимизации. Мои расчеты таковы: 1022 партии длится весь турнир* 25 мс одна партия = 25.55 секунд.

Статистика турнира держится в пределах следующих значений:

1. Среднее количество ходов (всех игроков): 85.06,
2. Среднее количество ходов выигравших игроков: 85.95,
3. Среднее количество ходов проигравших игроков: 84.17,
4. Среднее количество очков, которое набрали проигравшие: 17.75

Выводы можем сделать следующие:

1. Количество ходов, что выигравшие, что проигравшие делают примерно одинаковое.

2. Количество очков почти 18 (для победы нужно 20).

Итог: оба игрока играют примерно одинаково и одинаково неэффективно 🙂 Разница в 2 очка показывает, что победа буквально вырывается из лап соперника на последних ходах.

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

Следите за обновлениями статьи.

UPDATE2(16.01.2015)
Реализовал добавление ореола к списку пробитых координат после потопления корабля (в принципе всё честно). Статистика по количеству ходов существенно улучшилась:
1. Среднее количесво ходов (всех игроков): 58.91,
2. Среднее количество ходов выйгравших игроков: 60.98,
3. Среднее количество ходов проигравших игроков: 56.83,
4. Среднее количество очков, которое набрали проигравшие: 15.37

Читайте также:  Пакет приложений общение ростелеком

Спасибо Meklon за идею.

Реализовал новые стратегии размещения кораблей (там где 60 клеток под однопалубные). В итоге получилось следующее, если каждый из игроков использует одну и туже стратегию, то разницы между проигравшими и победителями нет, а вот если кажому игроку стратегия расстановки присваивается случайно, то явно видно, что прогиравших с моей стратегией больше (квадрат 6х6 в центре), т.е. если мою стратегию выбросить, то все будут играть примерно одинаково. Это тоже не интересно. Теперь буду реализывать различные стратегии ходов (может найдётся, что-то сверхоптимальное).

left,right, top,bottom и т.п. — это всё вариации размещения 60 координат на поле.
[2015-01-17 19:14:07,780] Статистика:
1. Среднее количесво ходов (всех игроков): 63.18,
2. Среднее количество ходов выйгравших игроков: 64.82,
3. Среднее количество ходов проигравших игроков: 61.54,
4. Среднее количество очков, которое набрали проигравшие: 16.24
[2015-01-17 19:14:07,783] Стратегия: for_1_ship_left loosers: 508
[2015-01-17 19:14:07,783] Стратегия: for_1_ship_left winners: 515

[2015-01-17 19:20:27,526] Статистика:
1. Среднее количесво ходов (всех игроков): 62.58,
2. Среднее количество ходов выйгравших игроков: 64.23,
3. Среднее количество ходов проигравших игроков: 60.93,
4. Среднее количество очков, которое набрали проигравшие: 16.23
[2015-01-17 19:20:27,529] Стратегия: for_1_ship_right loosers: 498
[2015-01-17 19:20:27,529] Стратегия: for_1_ship_right winners: 525

[2015-01-17 19:21:40,153] Статистика:
1. Среднее количесво ходов (всех игроков): 58.94,
2. Среднее количество ходов выйгравших игроков: 61.02,
3. Среднее количество ходов проигравших игроков: 56.87,
4. Среднее количество очков, которое набрали проигравшие: 15.35
[2015-01-17 19:21:40,155] Стратегия: for_1_ship_36 loosers: 518
[2015-01-17 19:21:40,157] Стратегия: for_1_ship_36 winners: 505

[2015-01-17 19:23:37,322] Статистика:
1. Среднее количесво ходов (всех игроков): 62.85,
2. Среднее количество ходов выйгравших игроков: 64.55,
3. Среднее количество ходов проигравших игроков: 61.16,
4. Среднее количество очков, которое набрали проигравшие: 16.15
[2015-01-17 19:23:37,323] Стратегия: for_1_ship_bottom loosers: 526
[2015-01-17 19:23:37,325] Стратегия: for_1_ship_bottom winners: 497

[2015-01-17 19:33:07,933] Статистика:
1. Среднее количесво ходов (всех игроков): 61.59,
2. Среднее количество ходов выйгравших игроков: 63.37,
3. Среднее количество ходов проигравших игроков: 59.81,
4. Среднее количество очков, которое набрали проигравшие: 15.95
[2015-01-17 19:33:07,934] Стратегия: for_1_ship_center_vertical loosers: 512
[2015-01-17 19:33:07,934] Стратегия: for_1_ship_center_vertical winners: 511

[2015-01-17 19:36:03,585] Статистика:
1. Среднее количесво ходов (всех игроков): 61.03,
2. Среднее количество ходов выйгравших игроков: 62.89,
3. Среднее количество ходов проигравших игроков: 59.18,
4. Среднее количество очков, которое набрали проигравшие: 15.78
[2015-01-17 19:36:03,589] Стратегия: for_1_ship_36 loosers: 148
[2015-01-17 19:36:03,589] Стратегия: for_1_ship_36 winners: 109
[2015-01-17 19:36:03,591] Стратегия: for_1_ship_bottom loosers: 34
[2015-01-17 19:36:03,591] Стратегия: for_1_ship_bottom winners: 50
[2015-01-17 19:36:03,591] Стратегия: for_1_ship_center_horisontal loosers: 129
[2015-01-17 19:36:03,591] Стратегия: for_1_ship_center_horisontal winners: 120
[2015-01-17 19:36:03,592] Стратегия: for_1_ship_center_vertical loosers: 96
[2015-01-17 19:36:03,592] Стратегия: for_1_ship_center_vertical winners: 94
[2015-01-17 19:36:03,592] Стратегия: for_1_ship_left loosers: 28
[2015-01-17 19:36:03,592] Стратегия: for_1_ship_left winners: 44
[2015-01-17 19:36:03,592] Стратегия: for_1_ship_right loosers: 40
[2015-01-17 19:36:03,594] Стратегия: for_1_ship_right winners: 48
[2015-01-17 19:36:03,594] Стратегия: for_1_ship_top loosers: 35
[2015-01-17 19:36:03,594] Стратегия: for_1_ship_top winners: 48

Добавил различные варианты совершения ходов: random — случайно из свободных клеток, cross — крест на крест, linear — линейно в 4 ряда через одну (как в хвалёных статьях). Важный момент: стратегия расстановки кораблей выдаётся на весь турнир, а вот стратегия ходов выдаётся на каждую игру.

Собрал статистку (напомню речь идёт о турните, где 1024 игрока играют между собой на вылет).

Основные выводы:
Стратегии расстановки однопалубных кораблей random_12 (выбирается 12 случайных клеток и в них расставляем корабли) и for_1_ship_36 (поле 6х6 в центре) явно наименее эффективные.

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

Количество ходов с реализацией дополнительных стратегий ходов не уменьшилось, а вот время турнира увеличилось с 25 до 50 секунд:
1. Среднее количесво ходов (всех игроков): 61.43,
2. Среднее количество ходов выйгравших игроков: 63.23,
3. Среднее количество ходов проигравших игроков: 59.63,
4. Среднее количество очков, которое набрали проигравшие: 15.93

Буду признателен, если кто-то посмотрит мой код на GitHub и даст свои рекомендации по его улучшению.

Осталась одна намеченная задача по оптимизации, но, как известно, оптимизировать можно бесконечно долго, так что статья без особой надобности в ближайшее время обновляться не будет.

Спасибо за внимание и да прибудет с вами сила Python!

Ссылка на основную публикацию
Как использовать термопасту для компьютера
Если вы собираете компьютер и требуется установить систему охлаждения на процессор или же во время чистки компьютера, когда снимается кулер,...
Как достать парашют в гта 5
Достаточно многие пользователи сталкивались с культовой серией игр «ГТА», в которой мы пользуемся моментом полной безнаказанности и свободы – об...
Как добавить текст в формулу excel
Объединение текста и чисел ​Смотрите также​​ (формула) ".​чтобы на февраль.​ за которую продали​С уважением.​Stormy Day​ формуле нужно указать​: Использую функцию...
Как использовать шрифты в ворде
Для творческих людей всегда недостаточно стандартных инструментов в программах для работы с текстами. Но всегда можно установить шрифт в ворд...
Adblock detector