#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use bit_vec::BitVec; use std::{ fmt::{Display, Error, Formatter}, ops::Coroutine, }; type Person = usize; #[derive(Debug, Clone, Copy)] enum Side { Top, Bot, } #[derive(Clone)] pub struct Seating { amount: usize, people_top: Vec>, people_bot: Vec>, } #[derive(Clone)] pub struct Adjacencies { amap: Vec, } impl Adjacencies { pub fn for_table(seats: &Seating) -> Self { let mut adj = Self::new(seats.amount); seats.get_adjacent(&mut adj); adj } pub fn new(size: usize) -> Self { Adjacencies { amap: (0..size).map(|_| BitVec::from_elem(size, false)).collect(), } } pub fn reset(&mut self) { self.amap.iter_mut().for_each(|bitvec| { if bitvec.any() { bitvec.clear(); } }) } fn is_disjoint(&mut self, other: &Adjacencies) -> bool { self.amap.iter_mut().enumerate().all(|(key, bitvec)| { bitvec.and(&other.amap[key]); bitvec.none() }) } pub fn intersect(&self, other: &Adjacencies) -> Adjacencies { Adjacencies { amap: self .amap .iter() .enumerate() .map(|(key, bitset)| { let mut bc = bitset.clone(); bc.and(&other.amap[key]); bc }) .collect(), } } pub fn union(&self, other: &Adjacencies) -> Adjacencies { Adjacencies { amap: self .amap .iter() .enumerate() .map(|(key, bitset)| { let mut bc = bitset.clone(); bc.or(&other.amap[key]); bc }) .collect(), } } } impl Display for Adjacencies { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { for (key, val) in self.amap.iter().enumerate() { write!(fmt, "{}:", key)?; for other in val { write!(fmt, " {},", other)?; } write!(fmt, "\n")?; } Ok(()) } } impl Display for Seating { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { let width = if self.amount == 0 { 1 } else { (self.amount.ilog10() + 2) as usize }; for peep in self.people_top.iter() { if let Some(perp) = peep { write!(fmt, "{:width$}", perp)?; } else { write!(fmt, "{:>1$}", "X", width)?; } } write!(fmt, "\n")?; for peep in self.people_bot.iter() { if let Some(perp) = peep { write!(fmt, "{:width$}", perp)?; } else { write!(fmt, "{:>1$}", "X", width)?; } } Ok(()) } } impl Seating { pub fn calc_alternatives( size: usize, old_adjacencies: &Adjacencies, ) -> impl Coroutine { let old_adjacencies = old_adjacencies.clone(); #[coroutine] move || { let mut checked_locations = 0; let mut new_adjacencies = Adjacencies::new(size); let mut tree = vec![((0..size).collect::>(), Seating::make_empty(size))]; while let Some((to_place, start)) = tree.pop() { checked_locations += 1; if to_place.len() == 0 { yield start } else { for pos in start.empty_table_coords() { let mut dup = start.clone(); dup.seat_person(to_place[0], pos); new_adjacencies.reset(); dup.get_adjacent(&mut new_adjacencies); if new_adjacencies.is_disjoint(&old_adjacencies) { tree.push((to_place[1..].to_vec(), dup)); } } } } checked_locations } } } impl Seating { pub fn make_seating(size: usize) -> Self { let top_amt = size / 2; let bot_amt = size - top_amt; Seating { amount: size, people_top: (0..top_amt).map(|i| Some(i * 2 + 1)).collect(), people_bot: (0..bot_amt).map(|i| Some(i * 2)).collect(), } } pub fn make_empty(size: usize) -> Self { let top_amt = size / 2; Seating { amount: size, people_top: (0..top_amt).map(|_| None).collect(), people_bot: (top_amt..size).map(|_| None).collect(), } } fn empty_table_coords(&self) -> Vec<(usize, Side)> { self.people_top .iter() .enumerate() .filter_map(|(coord, val)| { if val.is_none() { Some((coord, Side::Top)) } else { None } }) .chain( self.people_bot .iter() .enumerate() .filter_map(|(coord, val)| { if val.is_none() { Some((coord, Side::Bot)) } else { None } }), ) .collect() } fn seat_person(&mut self, person: usize, position: (usize, Side)) { let (x, y) = position; assert!( self.index(x, y) == None, "Can't seat person {} where {} is already sitting", person, self.index(x, y).expect("there was someone sitting there") ); let side = match y { Side::Top => &mut self.people_top, Side::Bot => &mut self.people_bot, }; side[x] = Some(person); } pub fn get_adjacent(&self, prev_adj: &mut Adjacencies) { for (i, person) in self.people_top.iter().enumerate() { if let &Some(person) = person { assert!( prev_adj.amap.len() > person, "adjacencies must contain all possible people" ); if i > 0 { // to their right: if let Some(adjacent) = self.index(i - 1, Side::Top) { prev_adj.amap[person].set(adjacent, true); } // across right: if let Some(adjacent) = self.index(i - 1, Side::Bot) { prev_adj.amap[person].set(adjacent, true) } } // to their left: if let Some(adjacent) = self.index(i + 1, Side::Top) { prev_adj.amap[person].set(adjacent, true); } // across: if let Some(adjacent) = self.index(i, Side::Bot) { prev_adj.amap[person].set(adjacent, true); } // across left: if let Some(adjacent) = self.index(i + 1, Side::Bot) { prev_adj.amap[person].set(adjacent, true); } } } for (i, person) in self.people_bot.iter().enumerate() { if let &Some(person) = person { assert!( prev_adj.amap.len() > person, "adjacencies must contain all possible people" ); // Layout I think I want to use? // [0, 1, 2, 3, 4, 5] // [6, 7, 8, 9,10,11] if i > 0 { // to their left: if let Some(adjacent) = self.index(i - 1, Side::Bot) { prev_adj .amap .get_mut(person) .expect("bitset was created above") .set(adjacent, true); } // across left: if let Some(adjacent) = self.index(i - 1, Side::Top) { prev_adj .amap .get_mut(person) .expect("bitset was created above") .set(adjacent, true); } } // to their right: if let Some(adjacent) = self.index(i + 1, Side::Bot) { prev_adj .amap .get_mut(person) .expect("bitset was created above") .set(adjacent, true); } // across: if let Some(adjacent) = self.index(i, Side::Top) { prev_adj .amap .get_mut(person) .expect("bitset was created above") .set(adjacent, true); } // across right: if let Some(adjacent) = self.index(i + 1, Side::Top) { prev_adj .amap .get_mut(person) .expect("bitset was created above") .set(adjacent, true); } } } } fn index(&self, x: usize, y: Side) -> Option { match y { Side::Top => { if x >= self.people_top.len() { None } else { Some(self.people_top[x]?) } } Side::Bot => { if x >= self.people_bot.len() { None } else { Some(self.people_bot[x]?) } } } } }