Created
May 5, 2021 01:23
-
-
Save ftsf/6d0a5eca332bcf2e1513e58bb54af8c0 to your computer and use it in GitHub Desktop.
Simple Grid System for Nico
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import nico | |
import nico/vec | |
type GridLayout* = enum | |
gridSquare | |
gridHexPointyTop | |
type Grid*[T] = ref object | |
layout*: GridLayout | |
wrapX*: bool | |
wrapY*: bool | |
width*: int | |
height*: int | |
data*: seq[T] | |
default*: T | |
proc set*[T](g: Grid[T], x,y: int, t: T) = | |
if x < 0 or y < 0 or x >= g.width or y >= g.height: | |
return | |
g.data[y * g.width + x] = t | |
proc get*[T](g: Grid[T], x,y: int): T = | |
if x < 0 or y < 0 or x >= g.width or y >= g.height: | |
return default(T) | |
return g.data[y * g.width + x] | |
proc get*[T](g: Grid[T], v: Vec2i): T = | |
return g.get(v.x, v.y) | |
proc set*[T](g: Grid[T], v: Vec2i, t: T) = | |
g.set(v.x, v.y, t) | |
proc `[]`*[T](g: Grid[T], v: Vec2i): T = | |
g.get(v) | |
proc `[]`*[T](g: Grid[T], x,y: int): T = | |
g.data[y * g.width + x] | |
proc `[]`*[T](g: var Grid[T], x,y: int): var T = | |
g.data[y * g.width + x] | |
proc `[]`*[T](g: var Grid[T], v: Vec2i): var T = | |
g.data[v.y * g.width + v.x] | |
proc `[]=`*[T](g: Grid[T], v: Vec2i, t: T) = | |
g.set(v,t) | |
proc `[]=`*[T](g: Grid[T], x,y: int, t: T) = | |
g.set(vec2i(x,y),t) | |
const hexNeighbours = [ | |
[ 0,+1,-1], | |
[+1, 0,-1], | |
[+1,-1, 0], | |
[ 0,-1,+1], | |
[-1, 0,+1], | |
[-1,+1, 0], | |
] | |
func toHexCoord*(hex: Vec2i): Vec3i = | |
let x = hex.x - (hex.y - (hex.y and 1)) div 2 | |
let z = hex.y | |
let y = -x-z | |
return vec3i(x,y,z) | |
func toOffset*(cube: Vec3i): Vec2i = | |
let col = cube.x + (cube.z - (cube.z and 1)) div 2 | |
let row = cube.z | |
return vec2i(col, row) | |
proc isAdjacent*(g: Grid, a,b: Vec2i): bool = | |
if g.layout == gridSquare: | |
if a.x == b.x: | |
if abs(a.y - b.y) == 1: | |
return true | |
elif g.wrapY and abs(a.y - b.y) == g.height - 1: | |
return true | |
elif a.y == b.y: | |
if abs(a.x - b.x) == 1: | |
return true | |
if g.wrapX and abs(a.x - b.x) == g.width - 1: | |
return true | |
else: | |
let aCube = toHexCoord(a) | |
let bCube = toHexCoord(b) | |
let d = abs(aCube.x - bCube.x) + abs(aCube.y - bCube.y) + abs(aCube.z - bCube.z) | |
if d == 1: | |
return true | |
# TODO handle wrapping | |
return false | |
iterator adjacent*[T](g: Grid[T], v: Vec2i, diagonal = false): Vec2i = | |
case g.layout: | |
of gridSquare: | |
if g.wrapX: | |
yield vec2i(wrap(v.x-1,g.width),v.y) | |
yield vec2i(wrap(v.x+1,g.width),v.y) | |
else: | |
if v.x > 0: | |
yield vec2i(v.x-1,v.y) | |
if v.x < g.width - 1: | |
yield vec2i(v.x+1,v.y) | |
if g.wrapY: | |
yield vec2i(v.x, wrap(v.y-1,g.height)) | |
yield vec2i(v.x, wrap(v.y+1,g.height)) | |
else: | |
if v.y > 0: | |
yield vec2i(v.x,v.y-1) | |
if v.y < g.height - 1: | |
yield vec2i(v.x,v.y+1) | |
if diagonal: | |
if v.x > 0: | |
if v.y > 0: | |
yield vec2i(v.x-1,v.y-1) | |
if v.y < g.height - 1: | |
yield vec2i(v.x-1,v.y+1) | |
if v.x < g.width - 1: | |
if v.y > 0: | |
yield vec2i(v.x+1,v.y-1) | |
if v.y < g.height - 1: | |
yield vec2i(v.x+1,v.y+1) | |
of gridHexPointyTop: | |
let cube = v.toHexCoord() | |
for offset in hexNeighbours: | |
let n = cube + offset | |
let pos = n.toOffset() | |
if pos.x >= 0 and pos.x < g.width and pos.y >= 0 and pos.y < g.height: | |
yield pos | |
proc getNeighbor*(g: Grid, start: Vec2i, dir: Vec3i): Vec2i = | |
if g.layout == gridSquare: | |
return start + dir.xyi | |
else: | |
let startCube = start.toHexCoord() | |
let offset = (startCube + dir).toOffset() | |
return offset | |
iterator items*[T](g: Grid[T]): T = | |
for v in g.data: | |
yield v | |
iterator mitems*[T](g: var Grid[T]): var T = | |
for v in g.data.mitems: | |
yield v | |
iterator pairs*[T](g: Grid[T]): (Vec2i,T) = | |
for y in 0..<g.height: | |
for x in 0..<g.width: | |
yield (vec2i(x,y), g[x,y]) | |
iterator mpairs*[T](g: var Grid[T]): (Vec2i, var T) = | |
for y in 0..<g.height: | |
for x in 0..<g.width: | |
yield (vec2i(x,y), g[x,y]) | |
proc newGrid*[T](w,h: int, layout: GridLayout = gridSquare, default: T = default(T)): Grid[T] = | |
result = new(Grid[T]) | |
result.layout = layout | |
result.width = w | |
result.height = h | |
result.default = default | |
result.data = newSeq[T](w*h) | |
for y in 0..<h: | |
for x in 0..<w: | |
result.set(x,y,default) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment