Skip to content

Commit

Permalink
utils for working with hexagonal boards (#271)
Browse files Browse the repository at this point in the history
* getAllNeighbors implemented and tested

* hexUtils exported in packages

* getDistance implemented and tested

* getRange implemented and tested

* Storybook example of GetRange

* Resolve getRange import correctly

* fix some naming conventions
  • Loading branch information
Korla authored and nicolodavis committed Sep 1, 2018
1 parent 137dd7c commit 2efdbc1
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 2 deletions.
3 changes: 2 additions & 1 deletion packages/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Card } from '../src/ui/card.js';
import { Deck } from '../src/ui/deck.js';
import { Grid } from '../src/ui/grid.js';
import { HexGrid } from '../src/ui/hex.js';
import { HexUtils } from '../src/ui/hex-utils.js';
import Token from '../src/ui/token.js';

export { Card, Deck, Grid, HexGrid, Token };
export { Card, Deck, Grid, HexGrid, Token, HexUtils };
66 changes: 66 additions & 0 deletions src/ui/hex-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2018 The boardgame.io Authors
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

const addPoint = (a, b) => ({ x: a.x + b.x, y: a.y + b.y, z: a.z + b.z });

/**
* Get neighbors
*
* A utility function which returns all neighbors for a point
* expressed in cube coordinates
*
* Arguments:
* point (Cube coorinates)
*
*/
export const getAllNeighbors = point =>
[[1, -1, 0], [1, 0, -1], [0, 1, -1], [0, -1, 1], [-1, 1, 0], [-1, 0, 1]].map(
([dx, dy, dz]) => addPoint(point, { x: dx, y: dy, z: dz })
);

/**
* Get distance
*
* A utility function which calculates the distance between two
* points expressed in cube coordinates
*
* Arguments:
* Two objects with:
* x - X coordinate (cube coordinates)
* y - Y coordinate (cube coordinates)
* z - Z coordinate (cube coordinates)
*
*/
export const getDistance = (a, b) =>
(Math.abs(a.x - b.x) + Math.abs(a.y - b.y) + Math.abs(a.z - b.z)) / 2;

/**
* Get range
*
* A utility function which returns all points within a range
* from the center
*
* Arguments:
* center (Cube coordinates)
* distance number
*
*/
export const getRange = (center, distance) => {
const results = [];
for (let x = -distance; x <= distance; x++) {
const startY = Math.max(-distance, -x - distance);
const stopY = Math.min(distance, -x + distance);
for (let y = startY; y <= stopY; y++) {
const z = -x - y;
results.push(addPoint(center, { x, y, z }));
}
}
return results;
};

export const HexUtils = { getAllNeighbors, getDistance, getRange };
97 changes: 97 additions & 0 deletions src/ui/hex-utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2018 The boardgame.io Authors
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

import { getAllNeighbors, getDistance, getRange } from './hex-utils';

const createCoordinate = ([x, y, z]) => ({ x, y, z });

test('neighbors of origo', () => {
const coordinate = createCoordinate([0, 0, 0]);
const result = getAllNeighbors(coordinate);
const expectedNeighbors = [
[1, -1, 0],
[1, 0, -1],
[0, 1, -1],
[0, -1, 1],
[-1, 1, 0],
[-1, 0, 1],
].map(createCoordinate);
expect(result).toEqual(expectedNeighbors);
});

test('neighbors of (1, 0, -1)', () => {
const coordinate = createCoordinate([1, 0, -1]);
const result = getAllNeighbors(coordinate);
const expectedNeighbors = [
[2, -1, -1],
[2, 0, -2],
[1, 1, -2],
[1, -1, 0],
[0, 1, -1],
[0, 0, 0],
].map(createCoordinate);
expect(result).toEqual(expectedNeighbors);
});

test('distance between neighbors', () => {
const origo = createCoordinate([0, 0, 0]);
const neighbor = createCoordinate([1, 0, -1]);
const result = getDistance(origo, neighbor);
expect(result).toEqual(1);
});

test('distance between non-neighbors', () => {
const origo = createCoordinate([0, 0, 0]);
const nonNeighbor = createCoordinate([3, 3, -6]);
const result = getDistance(origo, nonNeighbor);
expect(result).toEqual(6);
});

test('range from origo', () => {
const origo = createCoordinate([0, 0, 0]);
const result = getRange(origo, 1);
expect(result).toEqual(
[
[-1, 0, 1],
[-1, 1, 0],
[0, -1, 1],
[0, 0, 0],
[0, 1, -1],
[1, -1, 0],
[1, 0, -1],
].map(createCoordinate)
);
});

test('range not from origo', () => {
const origo = createCoordinate([2, -3, 1]);
const result = getRange(origo, 2);
expect(result).toEqual(
[
[0, -3, 3],
[0, -2, 2],
[0, -1, 1],
[1, -4, 3],
[1, -3, 2],
[1, -2, 1],
[1, -1, 0],
[2, -5, 3],
[2, -4, 2],
[2, -3, 1],
[2, -2, 0],
[2, -1, -1],
[3, -5, 2],
[3, -4, 1],
[3, -3, 0],
[3, -2, -1],
[4, -5, 1],
[4, -4, 0],
[4, -3, -1],
].map(createCoordinate)
);
});
34 changes: 33 additions & 1 deletion storybook/hex.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { withKnobs, boolean, number } from '@storybook/addon-knobs/react';
import { HexGrid, Token } from 'boardgame.io/ui';
import { HexGrid, Token, HexUtils } from 'boardgame.io/ui';

function Basic() {
const levels = number('levels', 5);
Expand Down Expand Up @@ -43,6 +43,37 @@ function Basic() {
);
}

function GetRange() {
const levels = number('levels', 5);
const distance = number('distance', 2);
const outline = boolean('outline', true);

class Runner extends React.Component {
state = { tokens: HexUtils.getRange({ x: 0, y: 0, z: 0 }, distance) };
render = () => (
<HexGrid levels={levels} outline={outline}>
{this.state.tokens.map((t, index) => {
return (
<Token
key={index}
x={t.x}
y={t.y}
z={t.z}
style={{ fill: '#555' }}
/>
);
})}
</HexGrid>
);
}

return (
<div style={{ padding: '50px' }}>
<Runner />
</div>
);
}

function TokenTrail() {
const levels = number('levels', 5);
const outline = boolean('outline', true);
Expand Down Expand Up @@ -86,4 +117,5 @@ function TokenTrail() {
storiesOf('HexGrid', module)
.addDecorator(withKnobs)
.add('basic', Basic)
.add('Get range', GetRange)
.add('Tokens placed on hover', TokenTrail);

0 comments on commit 2efdbc1

Please sign in to comment.