Skip to content

Commit

Permalink
feat(hex): normalize and assert all required hex prototype properties…
Browse files Browse the repository at this point in the history
… in createHexPrototype()
  • Loading branch information
flauwekeul committed Apr 22, 2021
1 parent 4c08684 commit 9cf0511
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 32 deletions.
75 changes: 71 additions & 4 deletions src/hex/functions/createHexPrototype.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,83 @@
import { normalizeDimensions } from '../../utils'
import { HexPrototype, Orientation } from '../types'
import { isCartesian, isObject } from '../../utils'
import { CartesianCoordinates, Ellipse, HexPrototype, Orientation, Rectangle } from '../types'

export interface HexPrototypeOptions {
dimensions: Ellipse | Rectangle | number
orientation: Orientation | 'pointy' | 'flat'
origin: CartesianCoordinates | number
offset: number
}

export const defaultPrototype: HexPrototype = {
dimensions: { xRadius: 1, yRadius: 1 },
orientation: Orientation.POINTY,
origin: 0,
// todo: why isn't this the center of the hex:
origin: { x: 0, y: 0 },
offset: -1,
}

export const createHexPrototype = <T>(prototype: T & Partial<HexPrototype>) => {
const normalizeDimensions = ({ dimensions, orientation }: HexPrototypeOptions) => {
if (isObject(dimensions)) {
if (Number.isFinite((dimensions as Ellipse).xRadius) && Number.isFinite((dimensions as Ellipse).yRadius)) {
return { ...(dimensions as Ellipse) }
}

const { width, height } = dimensions as Rectangle
if (Number.isFinite(width) && Number.isFinite(height)) {
return orientation === Orientation.POINTY
? { xRadius: width / Math.sqrt(3), yRadius: height / 2 }
: { xRadius: width / 2, yRadius: height / Math.sqrt(3) }
}
}

if (Number.isFinite(dimensions as number)) {
return { xRadius: dimensions, yRadius: dimensions } as Ellipse
}

throw new TypeError(
`Invalid dimensions: ${dimensions}. Dimensions must be expressed as an Ellipse ({ xRadius: number, yRadius: number }), a Rectangle ({ width: number, height: number }) or a number.`,
)
}

const normalizeOrientation = ({ orientation }: HexPrototypeOptions) => {
orientation = orientation.toUpperCase() as Orientation

if (orientation === Orientation.POINTY || orientation === Orientation.FLAT) {
return orientation
}

throw new TypeError(`Invalid orientation: ${orientation}. Orientation must be either 'POINTY' or 'FLAT'.`)
}

const normalizeOrigin = ({ origin }: HexPrototypeOptions) => {
if (isCartesian(origin)) {
return { ...origin } as CartesianCoordinates
}

if (Number.isFinite(origin)) {
return { x: origin, y: origin } as CartesianCoordinates
}

throw new TypeError(
`Invalid origin: ${origin}. Origin must be expressed as CartesianCoordinates ({ x: number, y: number }), or a number.`,
)
}

const assertOffset = ({ offset }: HexPrototypeOptions) => {
if (!Number.isFinite(offset)) {
throw new TypeError(`Invalid offset: ${offset}. Offset must be a number.`)
}

return offset
}

export const createHexPrototype = <T>(prototype: T & Partial<HexPrototypeOptions>) => {
const finalPrototype = { ...defaultPrototype, ...prototype } as T & HexPrototype

finalPrototype.dimensions = normalizeDimensions(finalPrototype)
finalPrototype.orientation = normalizeOrientation(finalPrototype)
finalPrototype.origin = normalizeOrigin(finalPrototype)
finalPrototype.offset = assertOffset(finalPrototype)

return finalPrototype
}
9 changes: 7 additions & 2 deletions src/hex/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ export interface CubeCoordinates {
s: number
}

export interface CartesianCoordinates {
x: number
y: number
}

export interface Ellipse {
xRadius: number
yRadius: number
Expand All @@ -22,9 +27,9 @@ export interface Rectangle {
export type hexDimensions = Ellipse | Rectangle | number

export interface HexPrototype {
dimensions: hexDimensions
dimensions: Ellipse
orientation: Orientation
origin: number
origin: CartesianCoordinates
offset: number
}

Expand Down
3 changes: 2 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './isCartesian'
export * from './isCube'
export * from './isObject'
export * from './normalizeDimensions'
export * from './offsetFromZero'
export * from './signedModulo'
5 changes: 5 additions & 0 deletions src/utils/isCartesian.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CartesianCoordinates } from '../hex'
import { isObject } from './isObject'

export const isCartesian = (value: unknown): value is CartesianCoordinates =>
isObject<CartesianCoordinates>(value) && Number.isFinite(value.x) && Number.isFinite(value.y)
10 changes: 10 additions & 0 deletions src/utils/isCube.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CubeCoordinates } from '../hex'
import { isObject } from './isObject'

export const isCube = (value: unknown): value is CubeCoordinates =>
isObject<CubeCoordinates>(value) &&
Number.isFinite(value.q) &&
Number.isFinite(value.r) &&
Number.isFinite(value.s) &&
// todo: not sure if this is necessary
value.q + value.r + value.s === 0
25 changes: 0 additions & 25 deletions src/utils/normalizeDimensions.ts

This file was deleted.

0 comments on commit 9cf0511

Please sign in to comment.