flauwekeul / honeycomb

Create hex grids easily, in node or the browser.

Home Page:https://abbekeultjes.nl/honeycomb

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Grid.hexesInRange and Grid.neighborsOf are incredibly slow

ValeTheVioletMote opened this issue · comments

I have a function that effectively does this:

grid.hexesInRange(Hex(x,y), 3)
grid.hexesInRange(Hex(x,y), 2)

Calling this in a loop a mere 42 times required 74 seconds. I'm confused.. are the calculations not based on the provided hex?

More examples... This is for a grid of 250x150, by the way:

var start_time = Date.now();for(let x=0;x<50;x++) grid.neighborsOf(Hex(0,0)); console.log("Time elapsed: "+Math.floor((Date.now()-start_time)/1000)+"s");
// Time elapsed: 8s

I ended up writing my own version of the neighbors function based off the RedBlobGames article, and my only guess about this slowness is that you must be looping through the entire grid to check if the hex exists each time, possibly without doing hashed checks
(e.g.)

const oddq_dir_enum = Object.fromEntries([
  "SE", "NE", "N", "NW", "SW", "S" 
].map((d,i) => [d,i]));
const oddq_directions = [
  [[+1,  0], [+1, -1], [ 0, -1], 
   [-1, -1], [-1,  0], [ 0, +1]],
  [[+1, +1], [+1,  0], [ 0, -1], 
   [-1,  0], [-1, +1], [ 0, +1]],
];
function hex_neighbor(col,row, direction) {
  const parity = col & 1;
  const [coladd, rowadd] = oddq_directions[parity][oddq_dir_enum[direction]];
  return {x: col+coladd, y: row+rowadd};
}

const hash_xy = xy => xy.x+","+xy.y;
const gh = Object.fromEntries(grid.map(xy=>[hash_xy(xy), 0]));

function hex_neighbors_checking(x,y,gridhash) {
  return Object.keys(oddq_dir_enum).map(dir => hex_neighbor(x,y,dir))
         .filter(xy => gridhash[hash_xy(xy)] == 0)
}
var start_time = Date.now();for(let x=0;x<50;x++) hex_neighbors_checking(0,0,gh); console.log("Time elapsed: "+Math.floor((Date.now()-start_time)/1000)+"s");
// Time elapsed: 0s

Since I'd rather let Honeycomb be the authoritative and easy source for my hex-related calculations, is it possible you could at least expose the raw calculation functions separate from the checks against the grid? Let me handle checking if the particular hex exists, etc.

And if you already do that somewhere, please point me in the right direction and forgive me for wasting time....

Hey there, thanks for asking your question.

First of all: since May this year I'm working on a new version of Honeycomb (well, not continuously). I wanted to have released an alpha version already, but unfortunately I haven't managed to yet. The main reason for this new version is an improved way to search hexes and it seems that's exactly what your question's about.

I'm not saying the current version of Honeycomb is as fast (or good in general) as it could be, but I'm unable to reproduce the huge wait times you're experiencing. I've made a Fiddle for your 2nd example (using console.time() and console.timeEnd()`) and on my machine it clocks just under 2 seconds. Again, maybe not as fast as you'd like, but I hope to improve that in the next version. Could you share your code so I can see why it takes so long in your case?

Here's the source of the neighborsOf() function. The meat of the function is on lines 276-277. First the hexes (coordinates) around the target hex are acquired (up to 6), then they're converted from cube to cartesian coordinates and finally retrieved from the grid. As you mention, the final part (getting the hexes from the grid) might be a bit redundant and I maybe should leave that to you. But apart from that, I don't think there's any redundancy...

Just to let you know: I've released an alpha version with a new API! Please check out the next branch.