pub fn generate(pattern: &[usize], phases: usize, cycle_length: usize) -> Vec<Vec<usize>> {
if pattern.is_empty() || cycle_length == 0 {
return vec![vec![]; phases];
}
let mut result = Vec::with_capacity(phases);
for phase_num in 0..phases {
let mut shifted_pattern = Vec::with_capacity(pattern.len());
for &hit in pattern {
let shifted_hit = (hit + phase_num) % cycle_length;
shifted_pattern.push(shifted_hit);
}
result.push(shifted_pattern);
}
result
}
pub fn clapping_music() -> Vec<Vec<usize>> {
let pattern = vec![0, 2, 3, 5, 6, 8, 9, 10];
let mut phases = generate(&pattern, 12, 12);
phases.push(pattern);
phases
}
pub fn phase_shift_by(
pattern: &[usize],
phases: usize,
shift_amount: usize,
cycle_length: usize,
) -> Vec<Vec<usize>> {
if pattern.is_empty() || cycle_length == 0 {
return vec![vec![]; phases];
}
let mut result = Vec::with_capacity(phases);
for phase_num in 0..phases {
let mut shifted_pattern = Vec::with_capacity(pattern.len());
let shift = (phase_num * shift_amount) % cycle_length;
for &hit in pattern {
let shifted_hit = (hit + shift) % cycle_length;
shifted_pattern.push(shifted_hit);
}
result.push(shifted_pattern);
}
result
}
pub fn phase_shift_timed(
pattern: &[usize],
phases: usize,
cycle_length: usize,
duration_per_phase: f32,
) -> Vec<(f32, Vec<usize>)> {
let shifted_patterns = generate(pattern, phases, cycle_length);
shifted_patterns
.into_iter()
.enumerate()
.map(|(i, pattern)| (i as f32 * duration_per_phase, pattern))
.collect()
}
pub fn phase_relationship(
pattern_a: &[usize],
pattern_b: &[usize],
cycle_length: usize,
) -> Option<usize> {
if pattern_a.len() != pattern_b.len() || pattern_a.is_empty() || cycle_length == 0 {
return None;
}
let potential_shift = if pattern_b[0] >= pattern_a[0] {
pattern_b[0] - pattern_a[0]
} else {
cycle_length - (pattern_a[0] - pattern_b[0])
};
for (a, b) in pattern_a.iter().zip(pattern_b.iter()) {
let expected_b = (a + potential_shift) % cycle_length;
if *b != expected_b {
return None;
}
}
Some(potential_shift)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_phase_shift_basic() {
let pattern = vec![0, 2, 5];
let phases = generate(&pattern, 3, 8);
assert_eq!(phases.len(), 3);
assert_eq!(phases[0], vec![0, 2, 5]);
assert_eq!(phases[1], vec![1, 3, 6]);
assert_eq!(phases[2], vec![2, 4, 7]);
}
#[test]
fn test_phase_shift_wrapping() {
let pattern = vec![7];
let phases = generate(&pattern, 3, 8);
assert_eq!(phases[0], vec![7]);
assert_eq!(phases[1], vec![0]); assert_eq!(phases[2], vec![1]);
}
#[test]
fn test_phase_shift_empty_pattern() {
let pattern = vec![];
let phases = generate(&pattern, 3, 8);
assert_eq!(phases.len(), 3);
for phase in phases {
assert_eq!(phase, vec![]);
}
}
#[test]
fn test_phase_shift_zero_cycle() {
let pattern = vec![0, 2];
let phases = generate(&pattern, 2, 0);
assert_eq!(phases.len(), 2);
for phase in phases {
assert_eq!(phase, vec![]);
}
}
#[test]
fn test_clapping_music() {
let phases = clapping_music();
assert_eq!(phases.len(), 13); assert_eq!(phases[0], phases[12]);
for phase in &phases {
assert_eq!(phase.len(), 8);
}
}
#[test]
fn test_clapping_music_pattern() {
let phases = clapping_music();
let expected_original = vec![0, 2, 3, 5, 6, 8, 9, 10];
assert_eq!(phases[0], expected_original);
}
#[test]
fn test_phase_shift_by() {
let pattern = vec![0, 4];
let phases = phase_shift_by(&pattern, 4, 2, 8);
assert_eq!(phases[0], vec![0, 4]); assert_eq!(phases[1], vec![2, 6]); assert_eq!(phases[2], vec![4, 0]); assert_eq!(phases[3], vec![6, 2]); }
#[test]
fn test_phase_shift_by_one_equals_regular() {
let pattern = vec![0, 3, 7];
let phases1 = generate(&pattern, 4, 12);
let phases2 = phase_shift_by(&pattern, 4, 1, 12);
assert_eq!(phases1, phases2);
}
#[test]
fn test_phase_shift_timed() {
let pattern = vec![0, 2];
let timed = phase_shift_timed(&pattern, 3, 8, 1.5);
assert_eq!(timed.len(), 3);
assert_eq!(timed[0].0, 0.0);
assert_eq!(timed[0].1, vec![0, 2]);
assert_eq!(timed[1].0, 1.5);
assert_eq!(timed[1].1, vec![1, 3]);
assert_eq!(timed[2].0, 3.0);
assert_eq!(timed[2].1, vec![2, 4]);
}
#[test]
fn test_phase_relationship_simple() {
let pattern_a = vec![0, 2, 5];
let pattern_b = vec![3, 5, 8];
assert_eq!(phase_relationship(&pattern_a, &pattern_b, 12), Some(3));
}
#[test]
fn test_phase_relationship_wrapping() {
let pattern_a = vec![10, 11];
let pattern_b = vec![0, 1];
assert_eq!(phase_relationship(&pattern_a, &pattern_b, 12), Some(2));
}
#[test]
fn test_phase_relationship_no_shift() {
let pattern = vec![0, 3, 7];
assert_eq!(phase_relationship(&pattern, &pattern, 12), Some(0));
}
#[test]
fn test_phase_relationship_unrelated() {
let pattern_a = vec![0, 2, 4];
let pattern_b = vec![0, 3, 6];
assert_eq!(phase_relationship(&pattern_a, &pattern_b, 12), None);
}
#[test]
fn test_phase_relationship_different_lengths() {
let pattern_a = vec![0, 2, 4];
let pattern_b = vec![0, 2];
assert_eq!(phase_relationship(&pattern_a, &pattern_b, 12), None);
}
#[test]
fn test_phase_relationship_empty() {
let pattern_a = vec![];
let pattern_b = vec![];
assert_eq!(phase_relationship(&pattern_a, &pattern_b, 12), None);
}
#[test]
fn test_phase_shift_full_cycle() {
let pattern = vec![0, 3];
let phases = generate(&pattern, 9, 8);
assert_eq!(phases[8], vec![0, 3]); }
#[test]
fn test_phase_shift_preserves_pattern_length() {
let pattern = vec![0, 2, 4, 6, 8];
let phases = generate(&pattern, 10, 16);
for phase in phases {
assert_eq!(phase.len(), pattern.len());
}
}
#[test]
fn test_phase_shift_by_larger_than_cycle() {
let pattern = vec![0, 4];
let phases = phase_shift_by(&pattern, 3, 10, 8);
assert_eq!(phases[0], vec![0, 4]);
assert_eq!(phases[1], vec![2, 6]); assert_eq!(phases[2], vec![4, 0]); }
#[test]
fn test_all_phases_have_same_length() {
let pattern = vec![0, 1, 5, 9];
let phases = generate(&pattern, 12, 12);
for phase in phases {
assert_eq!(phase.len(), pattern.len());
}
}
#[test]
fn test_phase_shift_single_element() {
let pattern = vec![3];
let phases = generate(&pattern, 5, 8);
assert_eq!(phases[0], vec![3]);
assert_eq!(phases[1], vec![4]);
assert_eq!(phases[2], vec![5]);
assert_eq!(phases[3], vec![6]);
assert_eq!(phases[4], vec![7]);
}
#[test]
fn test_phase_relationship_full_cycle() {
let pattern = vec![0, 3, 7];
let shifted = vec![0, 3, 7];
let rel = phase_relationship(&pattern, &shifted, 12);
assert_eq!(rel, Some(0));
}
}