Java – is hashing a suitable solution? Am I overly complicated?
I wrote a 2D platform game. I need room (up to 4) doors I write it in Java, but the language doesn't matter
Each room can have 4 doors at the top, bottom and side I call them north, South, East and West When I build a room, I only give it an integer. Each bit of the integer represents a door
For example, if I want a room with three doors (one in the north, one in the East and one in the West), I give the room number: 11 (1011 in binary)
Therefore, each gate has an integer to identify it
NORTH = 8;//1000 SOUTH = 4;//0100 EAST = 2;//0010 WEST = 1;//0001
If I generate a room, I give them a combination of these identifiers
For example, the room mentioned above will get an identifier
doorStock = NORTH | EAST | WEST;
I store these doors in a simple array:
Door doors[] = new Door[4];
My problem is: I need a function that maps identifiers to the correct index in the array I don't always need four doors
Everything I did initially seems to be the simplest: the gate array always has four elements, and the index I won't use will simply remain empty
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;
}
To be safe, I need to make sure that the door I asked for really exists in the room
private boolean doorExists(int doorID){
return (doorID & doorStock) != 0
}
Therefore, the query function is as follows:
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;
}
Which job, but! In this way, the array may waste space with unused elements Plus the door may have any size, increasing memory waste
Not to mention, I may need more "slot" doors (for example, if I try to achieve this in 3D), so I decided to try to make the size of the gate array depend on the door identifier:
Door doors = new Door[Integer.bitCount(doorStock)];
This gives an indexoutofbounds error really fast I'm not surprised, because the gate array can be any size from 0 to 4, so I need a new hash method
I came up with two hash tables. One is array index:
private final int[][] doorhash = {
/* NORTH SOUTH EAST WEST doorStock*/
{ -1,-1,-1} /*0000*/,{ -1,0} /*0001*/,-1} /*0010*/,1} /*0011*/,-1} /*0100*/,1} /*0101*/,1,-1} /*0110*/,2} /*0111*/,{ 0,-1} /*1000*/,1} /*1001*/,-1} /*1010*/,2} /*1011*/,-1} /*1100*/,2} /*1101*/,2,-1} /*1110*/,3} /*1111*/
};
One that helps map the previous table:
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*/
};
So my current mapping functions are as follows:
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;
}
This also seems to work, but I think there is a simpler solution to this problem, or a hash table with less waste I don't think it should be asymptotically flexible, or I'm too complicated What would be a better way?
Thank you for your time!
Solution
Enumeration is your friend:
// Each possible direction - with Up/Down added to show extendability.
public enum Dir {
North,South,East,West,Up,Down;
}
class Room {
// The doors.
EnumSet doors = EnumSet.noneOf(Dir.class);
// Many other possible constructors.
public Room ( Dir ... doors) {
this.doors.addAll(Arrays.asList(doors));
}
public boolean doorExists (Dir dir) {
return doors.contains(dir);
}
}
It's only natural that we should do something important for you They also provide a very efficient off the shelf enumset
