Skip to content

Instantly share code, notes, and snippets.

@atsapura
Created April 14, 2020 11:27
Show Gist options
  • Save atsapura/1a3285d449d71474072b13cbfbecb23e to your computer and use it in GitHub Desktop.
Save atsapura/1a3285d449d71474072b13cbfbecb23e to your computer and use it in GitHub Desktop.
Hex grid using cubical coordinates.
module HexGrid =
[<Struct>]
type HexId =
{
X: int
Y: int
Z: int
}
with
member this.Sum = this.X + this.Y + this.Z
[<RequireQualifiedAccess>]
module HexId =
let addX id x = { id with X = id.X + x }
let addY id y = { id with Y = id.Y + y }
let addZ id z = { id with Z = id.Z + z }
[<Struct>]
type TileId = private TileId of HexId
with
member this.Value = let (TileId v) = this in v
static member Center =
TileId { X = 0; Y = 0; Z = 0 }
static member create (hexId: HexId) =
if hexId.Sum = 0 then
TileId hexId |> Some
else None
let (|TileId|) id = let (TileId v) = id in v
[<Struct>]
type VertixId = private VertixId of HexId
with
member this.Value = let (VertixId v) = this in v
static member create (hexId: HexId) =
if abs hexId.Sum = 1 then
VertixId hexId |> Some
else None
let (|VertixId|) id = let (VertixId v) = id in v
let withinRadius radius (TileId id) =
abs id.X <= radius && abs id.Y <= radius && abs id.Z <= radius
let private allVariants (a, b, c) =
seq {
{ X = a; Y = b; Z = c }
{ X = b; Y = c; Z = a }
{ X = c; Y = a; Z = b }
}
let ringTiles distance =
seq {
for i in 0 .. distance do
yield! allVariants (-i, i - distance, distance)
yield! allVariants (i, distance - i, -distance)
}
|> Seq.distinct
|> Seq.map TileId
let neighbours maxRadius (TileId id) =
seq {
TileId { id with X = id.X + 1; Y = id.Y - 1 }
TileId { id with X = id.X - 1; Y = id.Y + 1 }
TileId { id with Z = id.Z + 1; Y = id.Y - 1 }
TileId { id with Z = id.Z - 1; Y = id.Y + 1 }
TileId { id with X = id.X + 1; Z = id.Z - 1 }
TileId { id with X = id.X - 1; Z = id.Z + 1 }
}
|> Seq.filter (withinRadius maxRadius)
let vertices (TileId id) =
seq {
HexId.addX id 1 |> VertixId
HexId.addX id -1 |> VertixId
HexId.addY id 1 |> VertixId
HexId.addY id -1 |> VertixId
HexId.addZ id 1 |> VertixId
HexId.addZ id -1 |> VertixId
}
let adjustingTiles maxRadius (VertixId id) =
match id.Sum with
| -1 ->
seq {
HexId.addX id 1 |> TileId
HexId.addY id 1 |> TileId
HexId.addZ id 1 |> TileId
}
| 1 ->
seq {
HexId.addX id -1 |> TileId
HexId.addY id -1 |> TileId
HexId.addZ id -1 |> TileId
}
| _ -> Seq.empty
|> Seq.filter (withinRadius maxRadius)
let generateField radius =
seq {
TileId.Center
for i in 1 .. radius do
yield! ringTiles i
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment