/** * A class representing coordinates in a hexagonal grid with 2 dimensions. * Offset system is "odd-r". */ export class Hex { x: number; y: number; constructor(x: number | { x: number, y: number }, y?: number) { if (typeof x === "number") { this.x = x as number; this.y = y || 0; } else { this.x = x.x; this.y = x.y; } } toCube() { const q = this.x - (this.y - (this.y&1)) / 2; const r = this.y; return new Cube(q, r, -q - r); } } /** * A class representing coordinates in a hexagonal grid with 3 dimensions. * Mostly used as a transient value for easier algorithms. */ class Cube { q: number; r: number; s: number; constructor(q: number, r: number, s: number) { this.q = q; this.r = r; this.s = s; } toHex() { return new Hex( this.q + (this.r - (this.r&1)) / 2, this.r ); } add(cube: Cube) { return new Cube(this.q + cube.q, this.r + cube.r, this.s + cube.s); } subtract(cube: Cube) { return new Cube(this.q - cube.q, this.r - cube.r, this.s - cube.s); } } export function getCornersAtDistance(distance: number) { const results: Hex[] = []; for (let q = -distance; q <= distance; q++) { for (let r = Math.max(-distance, -q - distance); r <= Math.min(distance, -q + distance); r++) { const s = -q - r; if ( (q === 0 || r === 0 || s === 0) && Math.max(Math.abs(q), Math.abs(r), Math.abs(s)) === distance ) { const cube = new Cube(q, r, s); results.push(cube.toHex()); } } } return results; } export function getTilesAtDistance(distance: number) { const results: Hex[] = []; for (let q = -distance; q <= distance; q++) { for (let r = Math.max(-distance, -q - distance); r <= Math.min(distance, -q + distance); r++) { const s = -q - r; if (Math.max(Math.abs(q), Math.abs(r), Math.abs(s)) === distance) { const cube = new Cube(q, r, s); results.push(cube.toHex()); } } } return results; } const adjacentVectors = [ new Cube(+1, 0, -1), new Cube(+1, -1, 0), new Cube(0, -1, +1), new Cube(-1, 0, +1), new Cube(-1, +1, 0), new Cube(0, +1, -1), ]; /** * Return all coordinates adjacent to a given one. * @param tile Hex - 2D coordinates in a hexagonal grid. * @returns Array of 6 2D coordinates. */ export function getAdjacentCoords(tile: Hex): Hex[] { const origin = tile.toCube(); return adjacentVectors.map(vec => origin.add(vec).toHex()); } /** * Return a position on the 3D board based on coordinates of a tile on our grid. * @param x The x coordinate in the grid. * @param y The y coordinate in the grid. * @returns An array containing the 3 coordinates (x, y, z) of that tile on a 3D board. */ export function getPositionOnBoard(x: number, y: number): [number, number, number] { const posX = x * 2 + (y % 2 ? 1 : 0); const posY = 0; const posZ = y * 1.72; return [ posX, posY, posZ ]; } /** * Return the distance between two cells. * @param a Hex - 2D coordinates in a hexagonal grid. * @param b Hex - 2D coordinates in a hexagonal grid. * @returns Distance between the two coordinates. */ export function distanceBetween(a: Hex, b: Hex): number { const aCube = a.toCube(); const bCube = b.toCube(); const vector = aCube.subtract(bCube); return (Math.abs(vector.q) + Math.abs(vector.r) + Math.abs(vector.s)) / 2; }