Игра Морской бой на JavaScript. Выстрел компьютера.

Вступление.

Заключительная статья из цикла «Игра Морской бой на чистом JavaScript». В этой статье мы рассмотрим:

  1. Выбор координат для выстрела компьютера.
  2. Обработка результата выстрела.
  3. Определение гарантированно пустых клеток, в которых не может быть кораблей противника.
  4. Вычисление координат следующего выстрела после попадания.
  5. Анализ количества оставшихся кораблей противника (игрока) и их тип.

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

Внимание.
Перед изучением JavaScript, реализующего выстрел компьютера, необходимо ознакомится со статьёй «Игра Морской бой на JavaScript. Выстрел игрока.». Ряд функций используется как для выстрела игрока, так и для выстрела компьютера и в данной статье повторно рассматриваться не будут.

Игра «Морской бой». Оптимальная тактика ведения морского боя компьютера.

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

Игра Морской бой. Выбор координат для выстрела компьютера.

Заштрихованные клетки отображают координаты выстрелов компьютера. При такой тактике, компьютер максимум за 24 выстрела попадёт в четырёхпалубный корабль, и это в худшем варианте. В реальности, будут попадания и в другие корабли. Конечно, если игрок знает про такую тактику, то он может расположить все корабли, за исключением четырёх палубного, в клетках, которые не подвергнутся обстрелу.
Давайте усложним задачу и изменим наклон диагоналей, по которым будет вестись стрельба, и сведём полученные координаты в единый массив.

Игра Морской бой. Оптимальные координаты выстрела компьютера.

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

Игра «Морской бой». Инициализация ведения морского боя компьютером.

Для формирования и хранения координат выстрела компьютера нам понадобится несколько массивов и объектов, являющимися свойствами класса Controller. Рассмотрим подробно их название и назначение:

coordsFixedHit
Массив с заранее вычисленными координатами выстрелов для реализации оптимальной тактики игры по алгоритму представленному выше.
coordsRandomHit
Массив координат будет использован для рандомного обстрела, после того, как будут использованы все координаты из массива coordsFixedHit. Изначально в данном массиве содержаться координаты всех клеток игрового поля. При каждом выстреле компьютера, координата выстрела будет удаляться из данного массива. Так же будут удаляться и координаты гарантированно пустых клеток. В результате, после того, как будут использованы все значения массива coordsFixedHit, останутся лишь те координаты, где реально может быть расположен корабль игрока. Вот эти оставшиеся координаты и будут использоваться для следующего выстрела.
coordsAroundHit
Массив координат клеток, расположенных вокруг попадания. Эти координаты используются для дальнейшего обстрела корабля при попадании. После использования координаты, она удаляется из массивов coordsFixedHit и coordsRandomHit.
START_POINTS
Массив базовых координат для формирования массива coordsFixedHit.
tempShip
Объект, в котором хранятся:
— координаты первого попадания;
— коэффициенты kx и ky, определяющие направление расположения корабля, вычисляются после второго попадания;
— количество попаданий в обстреливаемый корабль.

Игра «Морской бой». Формирование массивов с координатами выстрела компьютера.

Для заполнения массивов coordsFixedHit и coordsRandomHit координатами выстрелов запускается функция setCoordsShot, являющаяся методом класса Controller.

Функция setCoordsShot использует в своей работе данные массива START_POINTS. Прежде чем рассматривать работу данной функции, давайте сначала более подробно разберём содержание массива START_POINTS.

Массив START_POINTS содержит в себе всего лишь два элемента, каждый из которых, в свою очередь, так же является массивом. Первый массив содержит координаты начальных точек четырёх диагоналей направленных вправо-вниз. На приведённом ранее рисунке они изображены красным цветом. Второй — координаты начальных точек четырёх диагоналей направленных вправо-вверх. На рисунке они отображены синим цветом.

Добавим в класс Controller функцию setCoordsShot:

Игра «Морской бой». Получение координат для выстрела компьютера.

Выстрел компьютера в игре «Морской бой» представляет из себя извлечение значения двумерного массива игрового поля human.matrix по координатам, взятым из одного из трёх массивов: coordsAroundHit, coordsFixedHit или coordsRandomHit.

Выстрел компьютера начинается с вызова функции makeShot из функции init класса Controller.

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

Подробно функция makeShot была рассмотрена в статье «Игра Морской бой на JavaScript. Выстрел игрока.» Добавим в эту функцию несколько строк, касающихся выстрела компьютера:

Как видно из кода, координаты очередного выстрела компьютера будем получать с помощью функции getCoordsForShot. В зависимости от игровой обстановки, координаты берутся в одном из трёх массивов: coordsAroundHit, coordsFixedHit или coordsRandomHit.

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

После того, как координаты выстрела были получены, они удаляются из всех массивов, чтобы исключить повторный обстрел. Для этого используется функция removeCoordsFromArrays.

Как видно из приведённого кода, у нас появилась ещё одна новая функция — removeElementArray, с помощью которой можно удалить элемент массива содержащий определённые координаты. Данная функции имеет два аргумента:
— массив, из которого нужно удалить элемент;
— массив с координатами выстрела (первый элемент массива — координата по оси X, второй — по оси Y.

Для свой работы функция использует встроенный метод filter(), который возвращает новый массив координат из которого исключены координаты, переданные в качестве аргумента.

Рассмотрим подробно код функции:

Итак, координаты для выстрела получены. Теперь рассмотрим сам выстрел и оценку его результатов.

Игра «Морской бой». Выстрел компьютера. Попадание.

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

Игра «Морской бой». Алгоритм обработки попадания при выстреле компьютера.

Алгоритм обработки попадания, как я писал в предыдущей статье, реализован в функции hit. JS-код во многом совпадает с JS-кодом обработки попадания в корабль игрока, но есть существенные дополнения, касающиеся ИИ компьютера.

Алгоритм обработка результата попадания в корабль игрока:

  • 1

    Визуально отображаем попадание и записываем в массив игрового поля игрока human.matrix по этим координатам значение 4. Выводим сообщение о попадании.

  • 2

    Перебираем массив эскадры игрока human.squadron, в котором храниться информация о каждом корабле. По координатам выстрела определяем корабль в который произошло попадание.

  • 3

    Увеличиваем счётчик попадания hits по данному кораблю на 1.

  • 4

    Отмечаем гарантированно пустые клетки и формируем координаты обстрела вокруг попадания.

  • 5

    Если количество попаданий равно количеству палуб у корабля, то удаляем корабль из объекта эскадры, но перед этим сохраняем координаты первой палубы удаляемого корабля в объект tempShip. Эти координаты понадобятся для отметки заведомо пустых клеток по краям корабля.

  • 6

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

  • 7

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

    1. считаем, что обстреливаемый корабль потоплен;
    2. помечаем клетки вокруг корабля, как гарантированно пустые;
    3. сбрасываем значения свойств объекта tempShip в исходное состояние;
    4. переходим к следующему выстрелу по игровому полю игрока.
  • 8

    Если найдены корабли, у которых количество палуб больше, чем количество попаданий, то:

    1. увеличиваем счётчик попадания hits, являющийся свойством объекта tempShip на 1;
    2. продолжаем уничтожение текущего корабля путём обстрела вокруг палубы, в которую было сделано попадание.

Алгоритм достаточно сложный и вы, возможно, заметили некоторые противоречия между пунктами 5, 6, 7 и 8. Постараюсь объяснить возможную ситуацию на примере.
Допустим, компьютер обстрелял трехпалубный корабль и попал во все палубы. Мы удаляем этот корабль из эскадры, но компьютер этого не знает. Он предполагает, что это может быть четырёхпалубник и проводит проверку — уничтожен четырёхпалубный корабль ранее или нет. Если не уничтожен, то продолжает обстрел. В противном случае, обстрел трёхпалубника прекращается и производится выстрел по новым координатам.

На первом, втором и третьем пунктах приведённого алгоритма я останавливаться не буду, т. к. JS-код используется тот же самый, что и при выстреле игрока. А вот остальные пункты рассмотрим подробно.

Внимание.
Для облегчения восприятия нового JS-кода, я буду объяснять и показывать отдельные блоки кода, относящиеся к тому или иному пункту алгоритма. В конце будет представлен полный код функции hit.

Игра «Морской бой». Отмечаем гарантированно пустые клетки вокруг попадания.

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

Игра Морской бой. Гарантированно пустые клетки.

Полученные координаты клеток передаются в качестве аргумента в функцию markUselessCell, которая выполняет следующие задачи:

  1. Перебирает полученный объект с координатами и удаляет из него координаты по которым уже установлены ранее отметки пустых клеток, попаданий или промахов, а так же, если эти координаты оказываются за пределами игрового поля игрока.
  2. Записывает по этим координатам в двумерный массив игрового поля игрока значение ‘2’, что соответствует отметке пустой клетки.
  3. Вызывает функцию showIcons, для визуального отображения гарантированно пустых клеток на игровом поле игрока.
  4. Используя функцию removeCoordsFromArrays, удаляет эти координаты из массивов coordsAroundHit, coordsFixedHit и coordsRandomHit, чтобы исключить в дальнейшем стрельбу по этим координатам.

Ниже представлен полный JS-код функции markUselessCell:

Обратите внимание на строку:

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

Игра «Морской бой». Обстрел игрового поля вокруг попадания.

После попадания в корабль игрока, компьютеру необходимо продолжить его обстрел до полного уничтожения. Логично предположить, что следующая палуба будет находиться в соседней клетке. После первого попадания ещё не понятно, как расположен корабль — горизонтально или вертикально. Поэтому необходимо обстрелять клетку с попаданием со всех сторон. Количество координат обстрела может варьироваться от двух до четырёх, в зависимости от координат попадания.

Игра Морской бой. Обстрел клетки с попаданием.

В данном случае, точками обозначены возможные координаты выстрелов.

После второго попадания компьютер опять устанавливает маркеры гарантированно пустых клеток по диагонали от попадания. При этом удаляется часть координат возможного обстрела вокруг предыдущего попадания.
Кроме этого, мы можем определить направление расположения корабля и установить значения коэффициентов kx и ky. Данная информация понадобится при установке маркеров пустых клеток после полного уничтожения корабля игрока.

Игра Морской бой. Координаты обстрела корабля.

В данном случае, точками обозначены возможные координаты выстрелов.

Для вычисления направления расположения корабля и координат обстрела вокруг попадания используем функцию setCoordsAroundHit. Аргументами этой функции будут координаты попадания и объект с координатами выстрелов вокруг попадания.

В своей работе функция setCoordsAroundHit использует данные, хранящиеся в объекте tempShip: массив с координатами первого попадания firstHit и коэффициенты kx и ky. В исходном состоянии массив пустой, а kx и ky имеют значение 0.

Ещё раз напомню значение комбинаций коэффициентов:

  1. tempShip.kx == 1 && tempShip.ky == 0 — корабль расположен вертикально;
  2. tempShip.kx == 0 && tempShip.ky == 1 — корабль расположен горизонтально.

Функция setCoordsAroundHit выполняет следующие задачи:

  1. Запоминает координаты первого попадания.
  2. После второго попадания определяет направление расположения корабля.
  3. Перебирает объект с координатами обстрела, при этом:
    — удаляет координаты находящиеся за пределами игрового поля;
    — проверяет значение матрицы по оставшимся координатам, значение должно быть равно 0 (пустое место) или 1 (палуба корабля).
  4. Оставшиеся валидные координаты добавляет в массив coordsAroundHit.

Игра «Морской бой». Сохранение координаты первого попадания и определение направления расположения корабля.

Теперь можно приступить к написанию функции setCoordsAroundHit и первое, что мы сделаем — напишем условия, при которых определяется первое и второе попадание. Для этого обратимся к свойствам объекта tempShip.
Если массив tempShip.firstHit пустой, в нём нет никаких координат, значит это первое попадание в корабль. Если в массив записаны координаты, но коэффициенты kx и ky равны 0, значит это второе попадание и можно вычислить направление расположения корабля. Данная информация понадобится при установке маркеров пустых клеток после полного уничтожения корабля игрока.

Очень важно.
В условии коэффициенты kx и ky сравниваются с 0, а не с 1. Это сделано для универсальности вычислений как для первого попадания, так и для последующих, т. к. при первом попадании оба коэффициента равны 0.

Игра «Морской бой». Валидация координат обстрела вокруг попадания.

Валидация координат обстрела проводится в два этапа. Первоначально проверяем, что координата не выходит за пределы игрового поля. Далее, проверяем значение матрицы по оставшимся координатам обстрела. Значения должны быть равны 0 (пустое место) или 1 (палуба корабля).
Оставшиеся после проверки координаты помещаем в массив coordsAroundHit.

Добавим в функцию setCoordsAroundHit JS-код, проверяющий полученные координаты обстрела вокруг попадания:

Игра «Морской бой». Проверяем, потоплен ли корабль.

На первый взгляд, реализация этой проверки не должна вызвать трудностей. Достаточно сравнить в массиве human.squadron значения свойств decks (количество палуб) и hits (количество попаданий) обстреливаемого корабля. Если эти значения равны, то корабль считается потопленным. К сожалению, при таком подходе мы поставим игрока в заведомо неравное положение, ведь он обстреливает корабль до тех пор, пока явно не будет видно, что корабль потоплен. Откажемся от этого способа и научим компьютер самостоятельно определять необходимость дальнейшего обстрела раненого корабля — потоплен корабль или нет.

Определить, потоплен корабль или нет достаточно просто. Для этого необходимо проверить длину массива coordsAroundHit. Если массив пустой, т. е. обстреляны все возможные координаты вокруг попаданий, значит корабль уничтожен.
В противном случае, необходимо в эскадре игрока найти среди оставшихся кораблей, корабль с максимальным количеством палуб и сравнить это количество с количеством попаданий tempShip.hits. Если максимальное количество палуб меньше или равно количеству попаданий, то считаем, что корабль потоплен.
В зависимости от результата, после некоторой задержки, компьютер производит новый выстрел, продолжая обстреливать корабль или открывает стрельбу по новым координатам.
Данный алгоритм реализован в функции isShipSunk.

Код функции isShipSunk с комментариями:

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

  1. установить вокруг корабля недостающие маркеры заведомо пустых клеток;
  2. очистить массив coordsAroundHit;
  3. сбросить в исходное состояние объект tempShip.

Для реализации выше перечисленного, будем использовать две функции markUselessCellAroundShip() и resetTempShip().
Функция resetTempShip() рассматривалась в статье Редактирование положения корабля и начало игры..

Игра «Морской бой». Устанавливаем маркеры после уничтожения корабля.

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

Игра Морской бой. Гарантированно пустые клетки вокруг потопленного корабля.

Варианты расположения гарантированно пустых клеток
в зависимости от положения потопленного корабля.

Как видно из приведённого рисунка, для однопалубного корабля, помечаются максимум четыре клетки, расположенные с четырёх сторон.
Рассчитать координаты пустых клеток вокруг такого корабля не сложно:

Для многопалубных кораблей требуются максимум две клетки, расположенные с торцов.
Для расчёта координат потребуются данные объекта tempShip:

количество попаданий hits
в данном случае это значение равно количеству палуб потопленного корабля.
коэффициенты kx и ky
определяют, с какой стороны корабля устанавливать маркеры пустых клеток.

Рассчёт координат пустых клеток для многопалубного корабля будет выглядеть так:

После получения объекта coords, вызываем функцию markUselessCell, которая устанавливает маркеры пустых клеток на игровом поле на основе полученных координат.
Полный код функции markUselessCellAroundShip:

Игра «Морской бой». Уничтожение эскадры противника и окончание игры.

Эскадра противника считается уничтоженной, если длина массива Object.keys(this.opponent.squadron) равна 0. При этом, если победил игрок, то ему выводится поздравление с победой. В противном случае, выводится сообщение о проигрыше, а на игровом поле компьютера показываются оставшиеся корабли его эскадры.
Для вывода оставшихся кораблей, необходимо перебрать объект эскадры компьютера, получить данные по каждому оставшемуся кораблю и вызвать функцию showShip(), относящуюся к классу Ships. В качестве аргументов функции необходимо передать полученные данные.

На данный момент мы рассмотрели весь алгоритм работы программы при попадании в корабль игрока. Теперь можно представить полный код функции hit:

Игра «Морской бой». Выстрел компьютера. Промах.

Напомню, что промахом считается выстрел, по координатам которого в матрице игрового поля противника прописано значение 0, т. е. пустая клетка:

JS-код для обработки промаха является практически общим, как для игрока, так и для компьютера. Единственное, что я сделаю — добавлю в функцию miss несколько строчек кода, которые ниже рассмотрим подробнее:

Проверяется следующее условие: массив с координатами клеток вокруг попадания пустой, при этом в свойстве hits объекта tempShip содержится некое значение отличное от нуля (количество попаданий). Это значит, что компьютер обстреливал раненый корабль и все координаты, по которым могли находиться палубы корабля обстреляны. Другими словами — корабль игрока потоплен. Теперь необходимо сделать следующее:

  1. отметить маркерами все клетки вокруг корабля, как заведомо пустые исходя из правил игры;
  2. обнулить свойства объекта tempShip — они нам больше не нужны, т. к. корабль противника уничтожен.

Игра «Морской бой». Запуск новой игры.

Перезапуск игры начинается с нажатия на кнопку «Продолжить», которая становится доступной после полного уничтожения эскадры кого-либо из игроков.

При этом, игру необходимо вернуть в исходное состояние, как при первоначальной загрузке:

  1. Скрываем кнопку перезапуска игры и игровое поле компьютера.
  2. Показываем управляющие элементы выбора способа расстановки кораблей.
  3. Очищаем поле игрока от иконок попаданий, промахов и маркеров пустых клеток.
  4. Устанавливаем флаги начала игры и выстрела компьютера в исходное состояние.
  5. Очистить объекты эскадры от всех значений.
  6. Обнуляем массивы с координатами выстрела.
  7. Сбрасываем значения временного объекта корабля.

К кнопке перезапуска игры привязан обработчик события, который содержит функционал, реализующий перечисленный выше алгоритм. Рассмотрим его JS-код:

Заключение.

В пяти статьях, посвящённых игре «Морской бой», я постарался подробно и доступно рассказать, как написать эту популярную игру на чистом JavaScript. Я не претендую на то, что написанный мною код идеален и полностью оптимизирован. Возможно вы сможете предложить свои варианты каких-либо участков кода, другие пути решения. С удовольствием обсудим их в комментариях.

Комментарии

Всего: 18 комментариев
Требования при посте комментариев:
  1. Комментарии должны содержать вопросы и дополнения по статье, ответы на вопросы других пользователей.
    Комментарии содержащие обсуждение политики, будут безжалостно удаляться.
  2. Для удобства чтения Вашего кода, не забываейте его форматировать. Вы его можете подсветить код с помощью тега <pre>:
    <pre class="lang:xhtml"> - HTML;
    <pre class="lang:css"> - CSS;
    <pre class="lang:javascript"> - JavaScript.
  3. Если что-то не понятно в статье, постарайтесь указать более конкретно, что именно не понятно.
  • В статье присутствует ошибка синтаксиса в коде, в функции getCoordinatesShot (восьмая строка в вашем блоке кода). Поправьте

  • В это игре есть один существенный баг. Если в расположить коробли близко друг к други и попытаться повернуть один корабль так, чтобы он попал в зону нахождения второго корабля, то корабль изчезает. Можно начать игру и затащить на изи. Но корабли перед использование этой уязвимости должны ВСЕ находиться на поле.

    • Ошибку исправил. Это не баг логики, а косяк при работе с редактором. В скрипте примера, в функции Instance.prototype.rotationShip, случайно были поменяны местами несколько строк кода.
      Код приведённый в статье в разделе «Поворот корабля на 90°» — верный, там править ничего не надо.
      Спасибо за указанную ошибку.

  • Статьи пока не читал, добавил в закладки, почитаю на свежую голову.
    Поиграл немного, нашел много разных багов:
    1. Корабли можно перетаскивать даже во время боя.
    2. Хотелось бы, чтобы убитые корабли автоматически окружались промахами по периметру.
    3. Отсюда вытекает следующий пункт: никогда не знаешь точно убит ли корабль полностью. Соперник добивает корабль и следующий выстрел всегда делает в следующую клетку, как если бы там была еще одна палуба.

    • По первому пункту, действительно, баг присутствует — разберусь. А по п.п. 2 и 3 — так и задумывалось.

      • Так это же идёт вразрез с правилами игры. Когда корабль убит полностью сопернику сообщают об этом, и он не должен делать бессмысленный выстрел рядом с полностью убитым кораблём

  • Еще бывает так, что в ячейке стоит промах, а на самом деле там палуба корабля

  • Вы не правы на счет того, что компьютер с рандомным вариантом стрельбы без тактики не соперник для человека, поиграйте в мою версию игры, там 5 уровней сложности компьютера и на всех пяти уровнях компьютер стреляет рандомно, но я вас уверяю, победить там задача не из легких. Вот скриншот ( https://drive.google.com/file/d/1q12eQyAXhttDgoJa5LWuDx6sSmYW00jY/view?usp=sharing ), счет в его пользу 25:71.
    Плюс, по Вашей игре есть замечания, убитый корабль должен как-то обозначаться, и компьютер не должен обстреливать уже потопленный корабль, это противоречит правилам игры.
    Добавьте больше интерактива в игру, звуки, кнопки, возможность начать игру заново после раунда.
    Вот ссылка на мою версию игры (не работает на Internet Explorer и Microsoft Eagle):
    https://eugene-kul.github.io/seaBattle/index.html

    • Вальдемар Евгений Ответить 18 июня 2020 в 11:28

      Процитируйте, плиз, где написано «компьютер с рандомным вариантом стрельбы без тактики не соперник для человека». А вообще, по тактике игры в Морской бой есть множество статей с математическими вкладками по теории вероятности, картинками и т.д., где доказывается преимущество тактики перед рандомом.
      Уничтоженный корабль видно по попаданиям, а повторных обстрелов быть не может, т.к. из массива возможных выстрелов удаляются координаты, по которым стреляли. Хотя может есть какие-то не выявленные баги, на 100% не буду утверждать.
      В игру можно добавить много чего, но тогда статья удлинится в несколько раз и, вряд ли кто-то будет читать её до конца. Я не ставлю перед собой целью распространить (навязать) готовый плагин, скрипт, программу и т.д. Смысл этого блога показать направления и пути решения часто возникающих задач. А окончательное «вылизование» — это на усмотрение читателей. Возможно мои решения не всегда оптимальны и реализованы не лучшим способом, для этого есть блок комментариев — давайте это обсуждать.
      А так ваш коммент больше похож на пиар вашей программы.

      • Цитата из пункта Введение:
        «Для того, чтобы компьютер мог, как минимум, играть на равных с человеком, он (компьютер) должен иметь некую тактику игры. Причём, данная тактика должна быть оптимальна применительно к игре «Морской бой» и обеспечивать высокие шансы на победу над человеком.
        Исходя из этого, сразу же откажемся от рандомного обстрела поля игрока в начальной стадии игры. В рандомном формировании координат выстрела компьютера в полной мере присутствует элемент случайности, а нам, для победы компьютера над человеком, нужно свести этот элемент к минимуму.»
        Поэтому я Вам показал свой вариант игры, где реализована тактика игры компьютера на уровне человека с рандомным обстрелом поля. Я свое приложение не пиарю, это первое что я сделал на javaScript, и я знаю, что там в коде миллион ошибок. Я только учусь.
        По поводу обстрела убитых кораблей компьютером, ссылка на запись: ( https://drive.google.com/file/d/1UPLGqovxXbvAswLvOuAjMnqPBlD6A_Ei/view?usp=sharing ). И я не вижу никаких выделений уничтоженных кораблей и я не могу понять, убил я корабль или нет, и начинаю бессмысленно простреливать вокруг потопленного корабля. Чисто мое мнение, если ты начал что-то делать, то это что-то должно быть похоже на законченную вещь. Я не критикую Вашу игру, Вы молодец, что все это делаете, я просто опровергаю слова сказанные в статье, вот и все, не стоит на меня обижаться)

        • Вальдемар Евгений 18 июня 2020 в 13:49

          Обид никаких нет, для того комменты и прикручены, чтобы можно было обсуждать, указывать на ошибки и предлагать свои варианты реализации.
          По поводу обстрела корабля вокруг — именно так я планировал, так сложнее код в выстреле компьютера. Кстати, компьютер тоже обстреливает все возможные клетки рядом с кораблём, так что игрок и комп в этом случае находятся в равном положении.
          А с косяком буду разбираться, всё-равно хотел переписать на ES6

  • Только учусь фронтэнд разработке, в 28 лет пришло понимание, что занимаюсь не тем! Сейчас прохожу курсы, верстку осилил, приступил к изучению java-scripta. Отличный у Вас сайт!!! Приятно здесь находиться, очень много полезного! Создать игру такую как морской бой для меня сейчас просто фантастическая задача но статейки читаю!) Исключительно с точки зрения юзера по нраву больше игра Вальдемара, оформление такое тетрадное как в детстве. Я все детство играл в эту игру в таком варианте, что не нужно было говорить — тебя ранили или убили. Просто попал! Ваш вариант очень близок! Конечно не хватает, аудио. В игре Евгения большой минус как по мне это невозможность расставить корабли самостоятельно! А вообще вы виртуозы, это очень круто!!!! Надеюсь доросту до такого…

  • Было бы неплохо если бы не только код в архиве был переписан по новым стандартам, но и само обучение)Нет в планах пункта улучшить сам текст обучалки?)

    • Вальдемар KingJulian Ответить 4 декабря 2020 в 18:50

      Статьи с описанием создания игры в стандарте ES6+ практически готовы. Осталось дописать последнюю — «Выстрел компьютера». Если есть острая необходимость, то могу выложить первые четыре статьи и новый архив. В процессе переписывания статей в код вносились изменения связанные с оптимизацией.

      • KingJulian Вальдемар Ответить 10 декабря 2020 в 17:50

        Спасибо за ответ и за труды,очень жду обновление этой интереснейшей статьи.Если не затруднит,то можете выкладывать первые части.Я думаю,что это разумно)
        Пока люди проработают первые пару частей у Вас будет время дописать оставшуюся.

  • Еще раз доброго времени суток)
    Все ждемс обновленную игру детства.Как там успехи?Скоро ли увидим обновление?)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *