#[inline]
#[must_use]
pub fn shift(start: i64, k: i64, n: i64, forward: bool) -> i64 {
if forward {
(start + k).rem_euclid(n)
} else {
(start - k).rem_euclid(n)
}
}
#[inline]
#[must_use]
pub fn flying_star(center: i64, k: i64, forward: bool) -> i64 {
shift(center - 1, k, 9, forward) + 1
}
#[inline]
#[must_use]
pub fn count_to(start: i64, steps: i64, n: i64, forward: bool) -> i64 {
shift(start, steps, n, forward)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flying_star_wraps() {
assert_eq!(flying_star(8, 0, true), 8);
assert_eq!(flying_star(8, 1, true), 9);
assert_eq!(flying_star(8, 2, true), 1);
assert_eq!(flying_star(8, 3, true), 2);
assert_eq!(flying_star(8, 1, false), 7);
}
#[test]
fn ziwei_ming_palace_shift() {
let after_month = count_to(2, 5 - 1, 12, true); let ming = count_to(after_month, 7, 12, false); assert_eq!(ming, 11); }
use proptest::prelude::*;
proptest! {
#[test]
fn prop_shift_forward_then_back_is_identity(
start in 0i64..1000, k in 0i64..1000, n in 1i64..100,
) {
let f = shift(start, k, n, true);
prop_assert!(f >= 0 && f < n);
prop_assert_eq!(shift(f, k, n, false), start.rem_euclid(n));
}
#[test]
fn prop_flying_star_in_1_9(center in 1i64..10, k in 0i64..1000, fwd in any::<bool>()) {
prop_assert!((1..=9).contains(&flying_star(center, k, fwd)));
}
#[test]
fn prop_count_to_in_range(
start in -100i64..100, steps in -100i64..100, n in 1i64..50, fwd in any::<bool>(),
) {
let c = count_to(start, steps, n, fwd);
prop_assert!(c >= 0 && c < n);
}
}
}