random_pairings/
pairing_generator.rs

1use crate::person::Person;
2
3use std::collections::VecDeque;
4
5use rand::{
6  seq::SliceRandom, Rng,
7};
8
9#[derive(Debug, Clone)]
10pub struct PairingGenerator {
11  people: Vec<Person>,
12}
13
14impl PairingGenerator {
15  pub fn new() -> Self {
16    PairingGenerator {
17      people: Vec::new(),
18    }
19  }
20
21  pub fn add_person(&mut self, name: &str) -> Result<(), String> {
22    if self.people.iter().any(|p| p.name == name) {
23      return Err(format!("Tried to add duplicate person: {}", name));
24    }
25
26    self.people.push(Person::new(name));
27
28    Ok(())
29  }
30
31  pub fn add_couple(&mut self, first_name: &str, second_name: &str) -> Result<(), String> {
32    if self.people.iter().any(|p| p.name == first_name) {
33      return Err(format!("Tried to add duplicate person: {}", first_name));
34    }
35    if self.people.iter().any(|p| p.name == second_name) {
36      return Err(format!("Tried to add duplicate person: {}", second_name));
37    }
38
39    self.people.push(Person::with_spouse(first_name, second_name));
40    self.people.push(Person::with_spouse(second_name, first_name));
41
42    Ok(())
43  }
44
45  pub fn generate_pairings<R>(&self, rng: &mut R) -> Vec<Person> where R: Rng + ?Sized {
46    let mut unassigned_people = self.people.clone();
47    let mut assigned_people: Vec<Person> = Vec::with_capacity(unassigned_people.len());
48    let mut shuffled = unassigned_people.clone();
49    shuffled.shuffle(rng);
50    let mut shuffled = VecDeque::from(shuffled);
51
52    while unassigned_people.len() > 0 {
53      let mut person = unassigned_people.pop().unwrap();
54      let mut choice = shuffled.pop_front().unwrap();
55      let mut name = choice.name.clone();
56      let mut retries = 0;
57      while !person.is_valid_choice(&name) {
58        if retries >= 2 {
59          let swap_index = assigned_people.iter().position(|p| p.is_valid_choice(&name) && person.is_valid_choice(p.choice.as_ref().unwrap())).unwrap();
60          name = match &assigned_people[swap_index].choice {
61            Some(name) => name.clone(),
62            None => panic!("Person with no choice on assigned list"),
63          };
64          assigned_people[swap_index].choice = Some(choice.name.clone());
65          break;
66        } else {
67          shuffled.push_back(choice);
68          choice = shuffled.pop_front().unwrap();
69          name = choice.name.clone();
70          retries += 1;
71        }
72      }
73      person.choice = Some(name.clone());
74      assigned_people.push(person);
75    }
76
77    assigned_people
78  }
79}