///|
/// D2Q9 lattice Boltzmann state. Distribution arrays are stored in
/// cell-major order: `(y * width + x) * 9 + direction`.
pub(all) struct Lattice {
  size : Size
  config : Config
  f : Array[Double]
  next : Array[Double]
  solid : Array[Bool]
  mut step_count : Int
} derive(Debug)

///|
/// Create an equilibrium lattice with density 1 and zero velocity.
pub fn Lattice::new(size~ : Size, config~ : Config) -> Lattice {
  let cells = size.width * size.height
  let f = Array::make(cells * q, 0.0)
  for id in 0.. Int {
  y * self.size.width + x
}

///|
/// Convert coordinates and direction to a distribution index.
pub fn Lattice::dist_index(self : Lattice, x : Int, y : Int, d : Int) -> Int {
  self.cell_index(x, y) * q + d
}

///|
/// True when the coordinate is inside the domain.
pub fn Lattice::contains(self : Lattice, x : Int, y : Int) -> Bool {
  x >= 0 && y >= 0 && x < self.size.width && y < self.size.height
}

///|
/// Mark or clear a solid bounce-back cell.
pub fn Lattice::set_solid(
  self : Lattice,
  x : Int,
  y : Int,
  solid~ : Bool,
) -> Unit {
  if self.contains(x, y) {
    self.solid[self.cell_index(x, y)] = solid
  }
}

///|
/// Read whether a cell is solid.
pub fn Lattice::is_solid(self : Lattice, x : Int, y : Int) -> Bool {
  if self.contains(x, y) {
    self.solid[self.cell_index(x, y)]
  } else {
    true
  }
}