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