///|
/// Validated rising-shed draft. Public accessors return copies. IDs are one-based.
pub struct Draft {
priv shafts : Int
priv threading : Array[Int]
priv lifts : Array[Array[Int]]
} derive(Eq, Debug)
///|
fn valid_set(ids : Array[Int], upper : Int) -> Bool {
let seen : Map[Int, Bool] = Map([])
for id in ids {
if id < 1 || id > upper || seen.contains(id) {
return false
}
seen[id] = true
}
true
}
///|
/// Hard limits: 64 shafts, 2048 threads/picks, 262144 cells.
pub fn draft(
shafts : Int,
threading : Array[Int],
lifts : Array[Array[Int]],
) -> Result[Draft, String] {
if shafts < 1 || shafts > 64 {
return Err("weave.shafts")
}
let w = threading.length()
let h = lifts.length()
if w < 1 || h < 1 || w > 2048 || h > 2048 || w * h > 262144 {
return Err("weave.size")
}
for id in threading {
if id < 1 || id > shafts {
return Err("weave.threading")
}
}
for row in lifts {
if !valid_set(row, shafts) {
return Err("weave.lift")
}
}
let canonical = lifts.map(fn(row) {
let a = row.copy()
a.sort()
a
})
Ok({ shafts, threading: threading.copy(), lifts: canonical, })
}
///|
pub fn Draft::shaft_count(self : Draft) -> Int {
self.shafts
}
///|
pub fn Draft::width(self : Draft) -> Int {
self.threading.length()
}
///|
pub fn Draft::height(self : Draft) -> Int {
self.lifts.length()
}
///|
pub fn Draft::threads(self : Draft) -> Array[Int] {
self.threading.copy()
}
///|
pub fn Draft::liftplan(self : Draft) -> Array[Array[Int]] {
self.lifts.map(fn(a) { a.copy() })
}
///|
/// Row-major; true means warp is above weft on the front face.
pub fn Draft::drawdown(self : Draft) -> Array[Array[Bool]] {
self.lifts.map(fn(row) {
self.threading.map(fn(shaft) { row.contains(shaft) })
})
}