Я пишу 2D-платформерную игру, где мне нужны комнаты с (максимум 4) дверями. Я пишу это на Java, но язык не имеет значения.Является ли Хешинг подходящим решением? Я слишком усложняю это?
В каждом номере есть 4 двери, сверху, снизу и боковые стороны. Я называю их NORTH
, SOUTH
, EAST
и WEST
. Когда я строю комнату, я даю ей целое число, где каждый бит целого числа представляет собой дверь.
Например, если я хочу номер с 3-мя дверями (один на севере, один на Востоке, и на на западе) я дать комнату номер: 11 (1011 в двоичной системе).
По этой причине каждая дверь имеет целое число, идентифицирующее ее.
NORTH = 8;//1000
SOUTH = 4;//0100
EAST = 2;//0010
WEST = 1;//0001
Если я создаю комнату, я даю ей комбинацию этих идентификаторов.
Например: ранее упомянутый номер будет получить идентификатор
doorStock = NORTH | EAST | WEST;
хранить эти двери в простом массиве:
Door doors[] = new Door[4];
Моей проблема: Мне нужна функция, которая может отображать идентификаторы к правильному индексу в массиве. Мне не всегда нужно 4 двери.
То, что я делал сначала, кажется самым простым: в массиве дверей всегда будет 4 элемента, а индексы, которые я бы не использовал, просто оставались бы нулями.
public Door getDoor(int doorID){
switch(doorID){
case NORTH:{
return doors[0];
}
case SOUTH:{
return doors[1];
}
case EAST:{
return doors[2];
}
case WEST:{
return doors[3];
}
}
return null;
}
Для того, чтобы быть в безопасности, мне нужно было определить, существует ли дверь, которую я запрашиваю, в комнате.
private boolean doorExists(int doorID){
return (doorID & doorStock) != 0
}
Так с этим, функция запроса выглядит следующим образом:
public Door getDoor(int doorID){
switch(doorID){
case NORTH:{
if(doorExists(NORTH))return doors[0];
else return null;
}
case SOUTH:{
if(doorExists(NORTH))return doors[1];
else return null;
}
case EAST:{
if(doorExists(NORTH))return doors[2];
else return null;
}
case WEST:{
if(doorExists(NORTH))return doors[3];
else return null;
}
}
return null;
}
Который работал. НО! Таким образом, массив может потерять пространство с неиспользуемыми элементами. Плюс класс Door
потенциально может быть любого размера, увеличивая объем памяти.
Не говоря уже о том, что мне может понадобиться больше «слотов» для дверей (например, если я попытаюсь реализовать это в 3D), поэтому я решил попробовать размер массива дверей в зависимости от идентификатора дверей:
Door doors = new Door[Integer.bitCount(doorStock)];
Который дал ошибку IndexOutOfBounds
действительно быстро. Я не был удивлен, потому что массив дверей мог быть любого размера от 0 до 4, поэтому мне нужен новый метод хэширования.
То, что я придумал два хэш-таблицы, один для индексов массива:
private final int[][] doorhash = {
/* NORTH SOUTH EAST WEST doorStock*/
{ -1, -1, -1, -1} /*0000*/,
{ -1, -1, -1, 0} /*0001*/,
{ -1, -1, 0, -1} /*0010*/,
{ -1, -1, 0, 1} /*0011*/,
{ -1, 0, -1, -1} /*0100*/,
{ -1, 0, -1, 1} /*0101*/,
{ -1, 0, 1, -1} /*0110*/,
{ -1, 0, 1, 2} /*0111*/,
{ 0, -1, -1, -1} /*1000*/,
{ 0, -1, -1, 1} /*1001*/,
{ 0, -1, 1, -1} /*1010*/,
{ 0, -1, 1, 2} /*1011*/,
{ 0, 1, -1, -1} /*1100*/,
{ 0, 1, -1, 2} /*1101*/,
{ 0, 1, 2, -1} /*1110*/,
{ 0, 1, 2, 3} /*1111*/
};
и один, который помогает помогает в отображении предыдущей таблицы:
private final int[] directionHash = {
-1, /*0000*/
3, /*0001 - WEST*/
2, /*0010 - EAST*/
-1, /*0011*/
1, /*0100 - SOUTH*/
-1, /*0101*/
-1, /*0110*/
-1, /*0111*/
0, /*1000 - NORTH*/
};
так мой текущая функция отображения выглядит так:
public Door getDoor(int doorID){
switch(doorID){
case NORTH:{
if(doorExists(NORTH))return doors[doorhash[doorStock][directionHash[NORTH]]];
else return null;
}
case SOUTH:{
if(doorExists(NORTH))return doors[doorhash[doorStock][directionHash[SOUTH]]];
else return null;
}
case EAST:{
if(doorExists(NORTH))return doors[doorhash[doorStock][directionHash[EAST]]];
else return null;
}
case WEST:{
if(doorExists(NORTH))return doors[doorhash[doorStock][directionHash[WEST]]];
else return null;
}
}
return null;
}
Который также работает нормально, но я чувствую, что есть простое er решение этой проблемы, или один с менее расточительными хеш-таблицами. Я чувствую, что это не так асимптотически гибко, как должно быть, или я слишком усложняю вещи. Что было бы лучшим методом?
Благодарим вас за внимание!
Комната без дверей не помещение, так '0000' является незаконным значение. –
«Таким образом, массив может потерять пространство с неиспользуемыми элементами» - если у вас нет миллионов комнат, о которых не стоит беспокоиться. В вашем массиве будут храниться ссылки на объекты «Дверь», а не сами объекты (т. Е. Указатель в терминах С ++), поэтому размер класса «Дверь» не имеет значения для нулевого нуля. – Rup
Почему вы так делаете, у него есть чувство безумия. Что не так с 4 булевыми? –