#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Place {
Seated(u8),
Watching,
#[default]
Queued,
}
#[derive(Clone, PartialEq, Debug, Default)]
pub struct Peer {
pub place: Place,
pub name: String,
pub watch: bool,
pub silence: f32,
}
impl Peer {
pub fn seat(&self) -> Option<u8> {
match self.place {
Place::Seated(seat) => Some(seat),
Place::Watching | Place::Queued => None,
}
}
pub fn watches(&self) -> bool {
self.place == Place::Watching || self.watch
}
}
#[derive(Clone, PartialEq, Debug, Default)]
pub struct PeerBook(Vec<Peer>);
impl PeerBook {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get(&self, peer: usize) -> Option<&Peer> {
self.0.get(peer)
}
pub fn iter(&self) -> impl Iterator<Item = &Peer> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Peer> {
self.0.iter_mut()
}
pub fn reach(&mut self, count: usize) {
if self.0.len() < count {
self.0.resize_with(count, Peer::default);
}
}
pub fn row(&mut self, peer: usize) -> &mut Peer {
self.reach(peer + 1);
&mut self.0[peer]
}
pub fn fit(&mut self, count: usize) {
self.reach(count);
self.0.truncate(count);
}
pub fn forget(&mut self, peer: usize) {
if peer < self.0.len() {
self.0.remove(peer);
}
}
pub fn heard(&mut self, peer: usize) {
self.row(peer).silence = 0.0;
}
pub fn age(&mut self, delta: f32) {
for peer in &mut self.0 {
peer.silence += delta;
}
}
pub fn hush(&mut self) {
for peer in &mut self.0 {
peer.silence = 0.0;
}
}
pub fn deal(&mut self, plan: &[Option<u8>]) {
self.fit(plan.len());
for (peer, slot) in self.0.iter_mut().zip(plan) {
peer.place = match slot {
Some(seat) => Place::Seated(*seat),
None => Place::Watching,
};
}
}
pub fn planned(&self) -> usize {
self.0
.iter()
.take_while(|peer| peer.place != Place::Queued)
.count()
}
pub fn follows_the_round(&self, peer: usize) -> bool {
let planned = self.planned();
planned == 0 || peer < planned
}
pub fn holder_of(&self, seat: u8) -> Option<usize> {
self.0.iter().position(|peer| peer.seat() == Some(seat))
}
pub fn seat_of(&self, peer: usize) -> Option<u8> {
self.0.get(peer).and_then(Peer::seat)
}
pub fn unseat(&mut self) {
for peer in &mut self.0 {
peer.watch = peer.watches();
peer.place = Place::Queued;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn forgetting_a_peer_moves_the_rows_behind_it_together() {
let mut peers = PeerBook::default();
peers.row(0).name = "Bo".into();
peers.row(1).name = "Cy".into();
peers.row(2).name = "Dee".into();
peers.row(2).watch = true;
peers.row(2).silence = 3.0;
peers.deal(&[Some(1), Some(2), None]);
peers.forget(0);
assert_eq!(peers.len(), 2);
assert_eq!(peers.get(0).map(|p| p.name.as_str()), Some("Cy"));
let dee = peers.get(1).expect("Dee moved down");
assert_eq!(dee.name, "Dee");
assert!(dee.watches(), "the wish followed Dee down");
assert_eq!(dee.silence, 3.0, "and so did the silence");
assert_eq!(dee.place, Place::Watching);
assert_eq!(peers.seat_of(0), Some(2), "Cy keeps the chair it held");
}
#[test]
fn the_plan_is_the_leading_run_and_the_rest_are_in_line() {
let mut peers = PeerBook::default();
peers.deal(&[Some(1), None]);
assert_eq!(peers.planned(), 2);
peers.heard(3);
assert_eq!(peers.len(), 4, "grown to reach the stranger");
assert_eq!(peers.planned(), 2, "and the stranger is in line");
assert_eq!(peers.holder_of(1), Some(0));
assert_eq!(peers.holder_of(0), None, "the host's chair is nobody's");
peers.deal(&[Some(1)]);
assert_eq!(peers.planned(), 1);
assert_eq!(peers.len(), 1);
}
#[test]
fn unseating_keeps_the_watchers_and_frees_the_chairs() {
let mut peers = PeerBook::default();
peers.deal(&[Some(1), None, Some(2)]);
peers.row(2).watch = true;
peers.unseat();
let watching: Vec<bool> = peers.iter().map(Peer::watches).collect();
assert_eq!(watching, [false, true, true]);
assert!(peers.iter().all(|p| p.seat().is_none()));
assert_eq!(peers.planned(), 0);
}
#[test]
fn only_the_table_and_the_watchers_follow_the_round() {
let mut peers = PeerBook::default();
peers.reach(4);
peers.deal(&[Some(1), None]);
peers.reach(4);
assert_eq!(peers.planned(), 2, "a seat and a watching place");
assert!(peers.follows_the_round(0), "the seated peer");
assert!(peers.follows_the_round(1), "the watcher, in step from zero");
assert!(!peers.follows_the_round(2), "the one in line");
assert!(!peers.follows_the_round(3), "and the one behind it");
}
#[test]
fn a_book_with_no_plan_sends_to_everyone() {
let mut peers = PeerBook::default();
peers.reach(2);
assert_eq!(peers.planned(), 0, "nothing was ever dealt");
assert!(peers.follows_the_round(0));
assert!(peers.follows_the_round(1));
}
}