use std::{
cmp,
ops::{Bound, Range, RangeBounds},
};
use crate::{Bell, InvalidRowError, Stage};
use itertools::Itertools;
pub fn run_len(iter: impl IntoIterator<Item = Bell>) -> usize {
iter.into_iter()
.map(|b| b.index())
.tuple_windows::<(usize, usize)>()
.take_while(|&(i1, i2)| (i1 as i8 - i2 as i8).abs() == 1)
.count()
+ 1
}
pub(crate) fn check_duplicate_or_out_of_stage(
bells: impl IntoIterator<Item = Bell>,
stage: Stage,
) -> Result<(), InvalidRowError> {
let mut checklist = vec![false; stage.num_bells()];
for b in bells {
match checklist.get_mut(b.index()) {
None => return Err(InvalidRowError::BellOutOfStage(b, stage)),
Some(&mut true) => return Err(InvalidRowError::DuplicateBell(b)),
Some(x) => *x = true,
}
}
Ok(())
}
pub fn clamp_range(range: impl RangeBounds<usize>, length: usize) -> Range<usize> {
let range_min_inclusive = match range.start_bound() {
Bound::Included(v) => *v,
Bound::Excluded(v) => *v + 1,
Bound::Unbounded => 0,
};
let range_max_exclusive = match range.end_bound() {
Bound::Included(v) => *v + 1,
Bound::Excluded(v) => *v,
Bound::Unbounded => length,
};
range_min_inclusive..range_max_exclusive
}
pub fn split_vec<T>(vec: Vec<T>, index: usize) -> Option<(Vec<T>, Vec<T>)> {
if index > vec.len() {
return None; }
let mut left_vec = vec;
let right_vec = left_vec.split_off(index);
Some((left_vec, right_vec))
}
pub fn choice(n: usize, k: usize) -> Option<usize> {
let k = cmp::min(k, n - k);
let mut numerator = 1usize;
let mut denominator = 1usize;
for i in 1..=k {
numerator = numerator.checked_mul(n - k + i)?; denominator *= i; }
Some(numerator / denominator)
}
#[cfg(test)]
mod tests {
use crate::{run_len as rl, RowBuf};
#[test]
fn run_len() {
for &(row, run_len_f) in &[("123456", 6), ("456231", 3), ("612345", 1)] {
assert_eq!(rl(RowBuf::parse(row).unwrap().bell_iter()), run_len_f);
}
}
}