(最大 4 つの) ドアのある部屋が必要な 2D プラットフォーマー ゲームを作成しています。Javaで書いていますが、言語は問いません。
各部屋には、上、下、側面の 4 つのドアがあります。私はそれらNORTH
を 、SOUTH
、EAST
および と呼びますWEST
。部屋を作るときは、整数のみを与えます。整数の各ビットはドアを表します。
たとえば、ドアが 3 つある部屋 (北に 1 つ、東に 1 つ、西に 1 つ) が必要な場合、部屋に 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 つの要素があり、使用しないインデックスは単純に null のままです。
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 までの任意のサイズにすることができたので、私は驚きませんでした。そのため、新しいハッシュ メソッドが必要でした。
私が思いついたのは、配列インデックス用の 2 つのハッシュ テーブルです。
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*/
};
1 つ目は、前のテーブルのマッピングに役立ちます。
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;
}
これもうまくいくようですが、この問題にはもっと簡単な解決策、またはハッシュテーブルの無駄が少ない解決策があると思います。これはあるべきほど漸近的に柔軟ではないと感じているか、物事を過度に複雑にしています。より良い方法は何でしょうか?
お時間をいただきありがとうございます!