Skip to content

Instantly share code, notes, and snippets.

@ftsf
Created May 5, 2021 01:23
Show Gist options
  • Save ftsf/6d0a5eca332bcf2e1513e58bb54af8c0 to your computer and use it in GitHub Desktop.
Save ftsf/6d0a5eca332bcf2e1513e58bb54af8c0 to your computer and use it in GitHub Desktop.
Simple Grid System for Nico
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