问题
I am working on a random dungeon generator just for fun / as a side project to learn some new things. I have written a function that returns an integer hash value for any given cell, which gives you information about what type of gameobject it should be. i.e. if it is a wall, what direction to face, is it a corner, etc. Here is what the function currently looks like.
private int CellHashValue(int xIndex, int yIndex, char centerTile)
{
int hashValue = 0;
if (dungeon2DArray[xIndex - 1, yIndex + 1] == centerTile)
{
hashValue += 1;
}
if (dungeon2DArray[xIndex, yIndex + 1] == centerTile)
{
hashValue += 2;
}
if (dungeon2DArray[xIndex + 1, yIndex + 1] == centerTile)
{
hashValue += 4;
}
if (dungeon2DArray[xIndex - 1, yIndex] == centerTile)
{
hashValue += 8;
}
if (dungeon2DArray[xIndex + 1, yIndex] == centerTile)
{
hashValue += 16;
}
if (dungeon2DArray[xIndex - 1, yIndex - 1] == centerTile)
{
hashValue += 32;
}
if (dungeon2DArray[xIndex, yIndex - 1] == centerTile)
{
hashValue += 64;
}
if (dungeon2DArray[xIndex + 1, yIndex - 1] == centerTile)
{
hashValue += 128;
}
return hashValue;
}
My question is, is there a more efficient and faster way to do these checks that perhaps I am not thinking of? The dungeon array ranges in size from 100x100 to 1000x1000, though the function is not called on each cell. I have a separate List that contains rooms and there start and end indexes for each direction that I iterate over to instantiate objects.
回答1:
What you're doing is essentially applying a form of convolution. Without more context as to how your method is being called or how you're using the returned hash value, what you're doing seems to be close to the most efficient way to iterate a 3x3 grid. Assuming your dungeon2dArray is a char[][] and is global, this is what I believe to be a bit clearer and more concise (you'll have to adjust how to interpret the resulting sum based on the order of iteration).
private int CellHashValue(int x, int y) {
int hashSum = 0; // Hash sum to return
int hashValue = 1; // Increases as power of 2 (1,2,4,8,...128)
char centerTile = dungeon2DArray[x, y]; // Cache center tile
for (int r = -1; r <= 1; r++) {
for (int c = -1; c <= 1; c++) {
if (r == 0 && c == 0) continue; // Skip center tile
if (dungeon2DArray[x + c, y + r] == centerTile) {
hashSum += hashValue;
}
hashValue *= 2; // Next power of two
//could also bit shift here instead
// hashValue <<= 1
}
}
return hashSum;
}
Note: This method doesn't do any boundary checking, so if x or y index is along edge, indices will fail.
Each of the array accesses is O(1) and iterating over your entire dungeon array is O(n^2), so the only way to get better efficiency would be to combine per cell methods calls, but this is still only a constant factor, so not really more efficient, but depending on the calculation could boost performance a little bit.
回答2:
Since you are using an array to build the map then the access time is constant due to direct access. Thus, the process of checking each array index is fast.
There are several minor things to speed up the function.
- Return the hashValue within the corresponding
if
statement. This will remove a few lines of code. - By removing the
hashValue
variable and returning a hard-coded value, a variable initialization will be removed from the process. This is more significant than it may seem. To create and remove an object takes time, lots of time when at scale. xIndex
andyIndex
can be made global to the object. Be careful implementing this idea. Since xIndex and yIndex are not changing while checking for specific conditions then they can be made global within the object. This reduces the number of parameters passed in. Since Java does not pass by reference then an object of equal size is created and passed into the function. A simpleint
won't impact the speed much but if you have an object that contains many variables then more time is needed to build another object of equal value.- Each check can be moved to a separate function. This primarily helps with readability and debugging later on. There are some speed advantages but they're project dependent. By observing how objects are initialized/manipulated then certain conditions can typically be forced to be true. When logic doesn't need to be checked and conclusions can be reached without checks, then less time is needed.
Just a few ideas. If you have some time to research, the 2nd and 3rd points use concepts from low latency/high frequency
. Also, be aware that some of these concepts are not thought of as best practice.
来源:https://stackoverflow.com/questions/48872167/fastest-way-to-check-each-neighbor-in-2d-array