html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Игра «морской бой»: расстановка кораблей

Доброго времени суток, уважаемые! К сожалению, из-за больничного режима, я не мог последний месяц опубликовать своё очередное изыскание на тему игры «Морской бой». Надеюсь, моя заметка окажется для кого-то полезной, и, даже если и будет частичным повторением, то в новой интерпретации.
Итак, сегодня я хотел бы обсудить вопрос расстановки (не оптимальной, а произвольной) кораблей перед боем. Слева вы видите пример результата работы рассматриваемого далее алгоритма: корабли в форме букв «R», «A», «H», «B» расставлены на игровом поле размером 5х15 с несколькими запрещёнными к использованию клетками (помечены зелёным цветом). Заинтересовавшихся прошу под кат.

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

Количество вариантов


Если рассматривать не классическую эскадру, то общее количество вариантов расстановки кораблей вычисляется по формуле:

Эта формула учитывает все возможные варианты: даже априорно тупиковые. Необходимость в этой формуле вызвана желанием пронумеровать каждый вариант, чтобы уже потом проверять конкретный номер на приемлемость. Нетрудно заметить, что для 10 кораблей и поля 10х10 мы получаем число порядка 10^26, а это значит, что для индексации нам понадобится переменная размером в 87 бит, с учётом выравнивания – итого больше. Причём увеличение поля, или, что ещё хуже, количества кораблей, усугубляет ситуацию. Так добавление всего одного корабля увеличивает число вариантов до порядка 10^28. Ни один встроенный (аппаратно поддерживаемый) тип данных не подходит для работы с такими числами. Конечно, можно эмулировать арифметику с большими числами, но это обернется потерей производительности и излишне большим вспомогательным инструментарием для одной задачи движка логики игры. Кроме того, использование индексации подразумевает сопоставление каждому индексу уникальной расстановки, то есть индекс всё равно будет «распадаться» на некоторый набор чисел, характеризующий координаты и углы вращения кораблей. Если ещё подумать, то можно обойти проблему больших чисел, используя характер последующего применения индекса.

Перебор вариантов для одного корабля


По сути, мы говорим: тройка чисел характеризует корабль, а набор таких «троек» — эскадру. Упорядочив характеристики, мы можем уточнить: первое число характеризует ординату и изменяется от 0 до (Ymax-1), второе – абсциссу и принадлежит [0; Xmax-1], последнее – угол вращения, принимающий четыре разрешённых состояния. Немного подумав, можно представить себе ключи, характеризующие позицию и вращение корабля в виде дерева Ордината-Абсцисса-Угол (одна палуба помечена для упрощения восприятия; рабочая область – поле 2х2):


Поиск в глубину по такому дереву будет возвращать значения {000}, {001}, {002}, {003}, {010}, {011}, {012} … {113}. Нетрудно заметить, что перечисление ключей напоминает перечисление чисел позиционной системы счисления, в которой каждый разряд имеет свой диапазон значений. Так как каждый разряд нашей системы независим и характеризует одну из степеней свободы корабля, то алгоритм генерации ключей можно представить в виде следующей виртуальной машины:

Двигая нижнюю рейку, мы последовательно получим ключи: {000}, {001}, {002} и {003}, после чего рейка «закончится». После исчерпания младшего разряда, возвращаем его рейку в начальное состояние и сдвигаем среднюю на одну позицию. Генератор возвращает {010}, {011}, {012} и {013} – младший и средний разряд исчерпываются. «Сбрасываем» состояние всех исчерпавшихся разрядов, и сдвигаем верхнюю рейку на одну позицию: {100}, {101}, {102} и {103}.
Таким образом, алгоритм запроса очередного ключа следующий:



Перебор вариантов для эскадры


Разобравшись с одним кораблём, мы можем чуть абстрагироваться, и решить задачу для эскадры. Принцип генерации ключей тот же самый, только вместо реек теперь уже выступают генераторы, рассмотренные выше. Мы последовательно перебираем все значения младшего разряда (т.е. здесь – младшего генератора) до его переполнения, затем «увеличиваем следующий за ним разряд на единицу» (то есть запрашиваем новое значение с соответствующего генератора) и вновь прокручиваем младший:
{{000},{000}}
{{000},{001}}
{{000},{002}}
{{000},{003}}
{{000},{010}}

{{000},{113}}
{{001},{000}}

{{113},{113}}

Генерация расстановки


Итак, наконец-то мы решили первую задачу: мы можем последовательно перебрать все возможные расстановки. Теперь рассмотрим вопрос валидации варианта.
Алгоритм прост: получаем ключ для первого корабля, если поместить корабль возможно – устанавливаем его на поле и переходим к следующему судну, в противном случае – генерируем следующий ключ для данного корабля. Если ключи закончились, подаём сигнал «выше»: для предыдущего корабля подбираем новый валидный ключ, переустанавливаем судно и «возвращаемся». Всё в точности как с цифрами в позиционной системе, только появился ещё ряд ограничивающих правил, запрещающий некоторые сочетания.
Правила можно для удобства разбить по логическим категориям, ускорив, таким образом, проверку за счёт введения обязательных критериев. Например: корабль обязательно должен весь умещаться на игровом поле. Этот простой критерий, применительно к рассмотренному выше случаю, позволит сразу срезать 75% расстановок. Дальнейшие проверки зависят от организации данных в вашей реализации.

Случайности


Всё это хорошо, но детерминированная последовательность действий будет всегда порождать одну и ту же комбинацию, даже если их доступно несколько. Решение просто до безобразия: надо перемешать числа на рейках в генераторах. Просто, считывая i с рейки, возвращайте в точку вызова значение i-ого элемента некоторого массива random_num[i].
В перемешивании элементов массива можно порекомендовать следующее.
Во-первых, формула гарантированно генерирующая индекс второго элемента для обмена, отличный от первого. Вы, конечно, можете не запрещать фиктивный обмен random_num[j]<->random_num[j], но зачем тратить на это итерацию?
//N – количество элементов в массиве
//% - остаток целочисленного деления
unsigned a_indx=rand()%N;
unsigned b_indx=(a_indx+1+rand()%(N-1))%N;
//если вы опасаетесь за просадку производительности
//из-за дополнительного ‘%’ – его вполне можно
//заменить условием

Во-вторых, минимальное достаточное количество для полного перемешивания (беспорядка) выражается как
ceil(N*0.5);

Пример перемешивания чисел на «младшей» рейке и «хороший» генератор приведены далее:

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

В предыдущих сериях



(прошу прощения, если кого-то забыл упомянуть; сообщите в ЛС)

Заключение


Спасибо всем, кто осилил эту статью, выделив на её прочтение своё время. Постараюсь ответить на возникшие вопросы и прокомментировать критику. Просьба: замечания и советы по корректуре писать в личку, чтобы не уводить обсуждение от предмета статьи.
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

5

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции