Reputation: 1248
I can easily traverse the following from left to right, but I'm having a lot of trouble (2 days in, and no progress) getting a formula to traverse it from top right & bottom right.
Basically, I'm looking for a formula which can retrieve the following values:
let topRight = [
[ h[2][4], h[3][3], h[4][2] ],
[ h[1][3], h[2][3], h[3][2], h[4][1] ],
[ h[0][2], h[1][2], h[2][2], h[3][1], h[4][0] ],
[ h[0][1], h[1][1], h[2][1], h[3][0] ],
[ h[0][0], h[1][0], h[2][0] ]
]
let bottomRight = [
[ h[2][4], h[1][3], h[0][2] ],
[ h[3][3], h[2][3], h[1][2], h[0][1] ],
[ h[4][2], h[3][2], h[2][2], h[1][1], h[0][0] ],
[ h[4][1], h[3][1], h[2][1], h[1][0] ],
[ h[4][0], h[3][0], h[2][0] ]
]
The only part that I could get working was the topRight
x value:
function hexagonArraySize(row) {
if (row < this.size) {
return (this.size + row)
} else {
return (this.size * 2 - (row % this.size) - 2)
}
}
for (var i = 0, l = this.size * 2 - 1, j = l % size; i < l; ++i, ++j) {
this.h[j] = new Array(this.hexagonArraySize(i)).fill().map((_, b) => {
let x = (i > Math.floor(this.size / 2)) ? b : b + (this.size - i - 1)
let y = 0 // didn't found the formula for this one...
}, []).join("")
}
I made a fiddle available here: https://jsfiddle.net/0qwf8m1p/12/
There still is topRight
y, bottomRight
x & y to be found.
Upvotes: 10
Views: 889
Reputation: 51977
Here's a possible implementation for the two methods. They work by initializing the x,y
coordinates of the start for each row in the transformed hexagon, then conditionally iterate the x
value based on whether or not the y
value passed the size
of the hexagon, where the indices "bend":
function hexagon (size) {
const height = size * 2 - 1;
return Array.from({ length: height }, (_, y) => {
const width = size + Math.min(y, height - y - 1);
return Array.from({ length: width }, (_, x) => [y, x]);
})
}
const h = hexagon(3);
function topRight (h) {
const height = h.length;
const size = (height + 1) / 2;
const t = [];
for (let i = height; i > 0; i--) {
const width = size + Math.min(i - 1, height - i);
const row = Array.from({ length: width });
let y = Math.max(i - size, 0);
let x = i - 1;
for (let j = 0; j < width; j++) {
row[j] = h[y++][y >= size ? x-- : x];
}
t.push(row);
}
return t;
}
function bottomRight (h) {
const height = h.length;
const size = (height + 1) / 2;
const t = [];
for (let i = 0; i < height; i++) {
const width = size + Math.min(i, height - i - 1);
const row = Array.from({ length: width });
let y = height - Math.max(size - i, 1);
let x = height - i - 1;
for (let j = 0; j < width; j++) {
row[j] = h[y][y-- < size ? x-- : x];
}
t.push(row);
}
return t;
}
console.log('topRight');
topRight(h).forEach(row => console.log(JSON.stringify(row)));
console.log('bottomRight');
bottomRight(h).forEach(row => console.log(JSON.stringify(row)));
If you'd like a more object-oriented approach, here's a possible alternative:
class Hexagon extends Array {
constructor (size, map = (row, column) => [row, column]) {
const length = size * 2 - 1;
super(length);
this.fill();
this.size = size;
this.forEach((_, row, hexagon) => {
const width = size + Math.min(row, length - row - 1);
hexagon[row] = Array.from({ length: width }, (_, column) => map(row, column));
});
}
topRight () {
const { length, size } = this;
return new Hexagon(size, (row, column) => {
const upper = Math.max(row * 2 - length, 0) + 1;
const y = Math.max(size - 1 - row, 0) + column;
const x = Math.max(Math.min(length - 1 - row, length - upper - column), 0);
return this[y][x];
});
}
bottomRight () {
const { length, size } = this;
return new Hexagon(size, (row, column) => {
const upper = Math.max(row * 2 - length, 0) + 1;
const y = Math.min(size + row, length) - 1 - column;
const x = Math.max(Math.min(length - 1 - row, length - upper - column), 0);
return this[y][x];
});
}
}
let h = new Hexagon(3);
console.log('topRight');
h.topRight().forEach(row => console.log(JSON.stringify(row)));
console.log('bottomRight');
h.bottomRight().forEach(row => console.log(JSON.stringify(row)));
Upvotes: 0
Reputation: 6381
Ok, so you worked out topRight
x
coordinate.
Both topRight
and bottomRight
y
coordinates have the same equation:
(size - 1) * 2
(size - 1) * 2 - i)
(where i
is the sequence index)i
times, but at most size
timesThis wraps up to the following formula:
let y = (size - 1) * 2 - i - Math.max(0, b - Math.min(i, size - 1))
| | |
| first value | repeat at most size times |
Next, you have to calculate x
value for bottomRight
. You have two cases here:
i
is less than size / 2
then value equals sequence length - b
(item index)(size - 1) * 2 - b
This wraps up to the following formula:
let x = (i > Math.floor(size / 2)) ? (size - 1) * 2 - b : hexagonArraySize(i) - b - 1
| | |
| check index | second half | first half
Upvotes: 5