Какой самый эффективный способ определить, попал ли корабль в игру в линейный корабль? - PullRequest
0 голосов
/ 11 февраля 2019

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

Случай 1 - Все корабли имеют 1xN и вертикальные или горизонтальные

  • Корабельный объект содержит координаты начальной точки (верх
    слева), направления и размера
    • Каждый раз, когда производится выстрел, мы перебираем все корабли, для каждого корабля мы вычисляем ихкоординаты и определить, совпадает ли одна из координат с координатами выстрела

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

Случай 2 - Все корабли имеют произвольный размер, размер доски составляет 1 миллиард на 1 миллиард квадратов, а количество кораблей составляет 1 миллион.

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

Какой самый эффективный способ отслеживания местоположения кораблей/ координаты, такие, что решение масштабируется изящно?

Ответы [ 3 ]

0 голосов
/ 12 февраля 2019

Я должен не согласиться с решением на основе четырех деревьев - хотя оно все еще быстрое и выполнит работу, оно полностью игнорирует любую врожденную структуру сохраняемых точек данных.Если вам нужно быстрое, готовое решение, то, вероятно, так оно и будет, поскольку многие языки будут поддерживать квад-деревья или, по крайней мере, kd-деревья (k = 2).Если вы хотите что-то немного более быстрое и использующее немного меньше памяти, то подумайте о следующем:

Итерируйте по вертикально ориентированным кораблям и складывайте их по их координатам x в массивы, сохраняя кортежи их yкоордината, размер и идентификатор (сортировка по координате y).Затем создайте другой массив, который содержит кортежи этих массивов и соответствующие им x-координаты, отсортированные по x-координатам.Чтобы определить, попадает ли метка в вертикальный корабль, вы затем выполняете двоичный поиск по первому массиву, чтобы найти все корабли в этом столбце, а затем выполняете второй двоичный поиск, чтобы найти корабль с наибольшей координатой y, равной или меньшей чемзнак.Проверьте, если mark_y < ship_y + ship_size, если так, метка попала в этот корабль, иначе он ничего не попалПовторите этот процесс для горизонтальных кораблей и, при необходимости, определите приоритеты проверки ориентации с большим количеством кораблей для первого удара.

Хотя это звучит очень похоже на квад-дерево, есть важное отличие - мы делим сетку вдольодна ось полностью перед началом другой оси.Мы делаем это так, чтобы не хранить все точки, через которые проходят корабли;мы только храним их якорь в верхнем левом углу.Мы не можем сделать это с квад-деревом, потому что нам нужно запросить этот столбец специально (или строку для горизонтальных кораблей), чтобы определить, находится ли корабль «над», знак проходит через марку.Если корабли масштабируются по размеру доски, это приведет к небольшому асимптотическому ускорению над наивным четырехугольным деревом.Если они остаются на фиксированном N, то это все равно уменьшает количество запросов на log2(N) и уменьшает потребление памяти на N.

0 голосов
/ 12 февраля 2019

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

Ваша доска имеет размер N x M, и есть S кораблей произвольного размера.Я собираюсь сделать некоторые предположения:

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

Вы представляете свой корабль как:

Ship
    Id
    Top
    Left
    Width
    Height
    Hits // array of [Height x Width] Booleans that indicates which positions have been hit.
    HitCount // number of positions that have been hit. When HitCount == (Width x Height), the ship is sunk.

А ваша доска представляет собой массив ссылок N x M насудов.Таким образом, доска 5 х 4 с двумя кораблями может выглядеть так:

     0     1     2     3     4
0  ship1 ship1 ship1 NULL  NULL
1  ship1 ship1 ship1 NULL  ship2
2  NULL  NULL  NULL  NULL  ship2
3  NULL  NULL  NULL  NULL  ship2

Теперь кто-то делает снимок в строке 1, столбец 3. Вы смотрите в массив и видите, что в этом квадрате нет корабля.,Чистая мисс.Следующий снимок идет в (2, 4).Вы индексируете в массив и видите, что это корабль 2. Вы ищите корабль 2, переводите позицию доски (2, 4) в массив корабля Hits (в данном случае это будет (0, 1), и записываетеУдар. Увеличивайте HitCount, если эта позиция не была ранее поражена. Когда HitCount == (Width x Height), корабль потоплен.

Это представление позволяет осуществлять прямой поиск при каждом выстреле: поиск не требуется.асимптотические термины, это требует O ((N x M) + S) памяти, а обработка выстрела O (1). На самом деле, наихудший случай памяти составляет 2*(N x M), потому что для каждого корабля требуется Height*Width памяти, а вв худшем случае корабли могут заполнить всю доску.

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

Вы можете уменьшить объем памяти структуры выше, используя несколько простых приемов. Используя массив битов или что-то подобное, вместо массива логических значений для Hits, например, может сэкономить вам место.А хранение кораблей в массиве и использование индекса, а не ссылки на доске, может сократить пространство, используемое для доски, вдвое.Но даже с оптимизацией памяти эта структура может зайти так далеко.При 16 гигабайтах оперативной памяти максимальный размер платы, вероятно, будет порядка 100 000 x 100 000.

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

0 голосов
/ 11 февраля 2019

Я думаю, что это естественно для квадродерева (https://en.wikipedia.org/wiki/Quadtree).

. Они работают путем рекурсивного деления 2-й области на 4 субрегиона. Она использует тот факт, что многие субрегионы будут идентичны. Iпроцитирую википедию:

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

Подразделяемые области могут быть квадратными илипрямоугольные или могут иметь произвольные формы. Эта структура данных была названа quadtree Рафаэлем Финкелем и Дж. Л. Бентли в 1974 году. Подобное разбиение также известно как Q-дерево. Все формы четырех деревьев имеют некоторые общие черты:

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

Это должно позволить вам эффективно хранить и запрашивать ваше пространство.

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