1#[inline]
8#[must_use]
9pub fn shift(start: i64, k: i64, n: i64, forward: bool) -> i64 {
10 if forward {
11 (start + k).rem_euclid(n)
12 } else {
13 (start - k).rem_euclid(n)
14 }
15}
16
17#[inline]
20#[must_use]
21pub fn flying_star(center: i64, k: i64, forward: bool) -> i64 {
22 shift(center - 1, k, 9, forward) + 1
23}
24
25#[inline]
28#[must_use]
29pub fn count_to(start: i64, steps: i64, n: i64, forward: bool) -> i64 {
30 shift(start, steps, n, forward)
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn flying_star_wraps() {
39 assert_eq!(flying_star(8, 0, true), 8);
41 assert_eq!(flying_star(8, 1, true), 9);
42 assert_eq!(flying_star(8, 2, true), 1);
43 assert_eq!(flying_star(8, 3, true), 2);
44 assert_eq!(flying_star(8, 1, false), 7);
46 }
47
48 #[test]
49 fn ziwei_ming_palace_shift() {
50 let after_month = count_to(2, 5 - 1, 12, true); let ming = count_to(after_month, 7, 12, false); assert_eq!(ming, 11); }
56
57 use proptest::prelude::*;
58 proptest! {
59 #[test]
60 fn prop_shift_forward_then_back_is_identity(
61 start in 0i64..1000, k in 0i64..1000, n in 1i64..100,
62 ) {
63 let f = shift(start, k, n, true);
64 prop_assert!(f >= 0 && f < n);
65 prop_assert_eq!(shift(f, k, n, false), start.rem_euclid(n));
66 }
67 #[test]
68 fn prop_flying_star_in_1_9(center in 1i64..10, k in 0i64..1000, fwd in any::<bool>()) {
69 prop_assert!((1..=9).contains(&flying_star(center, k, fwd)));
70 }
71 #[test]
72 fn prop_count_to_in_range(
73 start in -100i64..100, steps in -100i64..100, n in 1i64..50, fwd in any::<bool>(),
74 ) {
75 let c = count_to(start, steps, n, fwd);
76 prop_assert!(c >= 0 && c < n);
77 }
78 }
79}