#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Move<T> {
pub to: T,
pub from: T,
}
impl<T> Move<T> {
pub const fn new(to: T, from: T) -> Self {
Self { to, from }
}
}
#[must_use]
pub fn sequence<T: Copy + PartialEq>(moves: &[Move<T>], scratch: T) -> Vec<Move<T>> {
let mut pending: Vec<Move<T>> =
moves.iter().copied().filter(|one| one.to != one.from).collect();
for (index, one) in pending.iter().enumerate() {
assert!(
!pending[..index].iter().any(|earlier| earlier.to == one.to),
"two parallel moves write the same place"
);
}
let mut order = Vec::with_capacity(pending.len());
while !pending.is_empty() {
let ready = pending.iter().position(|one| {
!pending.iter().any(|other| other.from == one.to && other.to != one.to)
});
match ready {
Some(index) => order.push(pending.remove(index)),
None => break_cycle(&mut pending, &mut order, scratch),
}
}
order
}
fn break_cycle<T: Copy + PartialEq>(pending: &mut [Move<T>], order: &mut Vec<Move<T>>, scratch: T) {
let source = pending[0].from;
order.push(Move::new(scratch, source));
for one in pending.iter_mut().filter(|one| one.from == source) {
one.from = scratch;
}
}
#[cfg(test)]
mod tests {
use super::*;
fn moves(pairs: &[(char, char)]) -> Vec<Move<char>> {
pairs.iter().map(|&(to, from)| Move::new(to, from)).collect()
}
fn run(order: &[Move<char>]) -> Vec<(char, char)> {
let mut held: Vec<(char, char)> = ('a'..='z').map(|place| (place, place)).collect();
for one in order {
let value = held.iter().find(|&&(place, _)| place == one.from).expect("a place").1;
held.iter_mut().find(|(place, _)| *place == one.to).expect("a place").1 = value;
}
held
}
fn correct(parallel: &[Move<char>], order: &[Move<char>]) -> bool {
let held = run(order);
parallel.iter().all(|one| {
held.iter().find(|&&(place, _)| place == one.to).expect("a place").1 == one.from
})
}
#[test]
fn moves_that_get_in_nobody_s_way_are_made_in_any_order() {
let parallel = moves(&[('a', 'b'), ('c', 'd')]);
let order = sequence(¶llel, 'z');
assert_eq!(order.len(), 2);
assert!(correct(¶llel, &order));
}
#[test]
fn a_chain_is_made_from_the_end_of_it() {
let parallel = moves(&[('b', 'c'), ('a', 'b')]);
let order = sequence(¶llel, 'z');
assert_eq!(order, moves(&[('a', 'b'), ('b', 'c')]));
assert!(correct(¶llel, &order));
}
#[test]
fn two_values_that_swap_need_somewhere_to_put_one_of_them() {
let parallel = moves(&[('a', 'b'), ('b', 'a')]);
let order = sequence(¶llel, 'z');
assert!(correct(¶llel, &order));
assert_eq!(order.len(), 3);
assert!(order.iter().any(|one| one.to == 'z'));
}
#[test]
fn a_longer_cycle_costs_the_same_one_extra_move() {
let parallel = moves(&[('a', 'b'), ('b', 'c'), ('c', 'a')]);
let order = sequence(¶llel, 'z');
assert!(correct(¶llel, &order));
assert_eq!(order.len(), 4);
}
#[test]
fn two_cycles_are_broken_one_at_a_time() {
let parallel = moves(&[('a', 'b'), ('b', 'a'), ('c', 'd'), ('d', 'c')]);
let order = sequence(¶llel, 'z');
assert!(correct(¶llel, &order));
assert_eq!(order.len(), 6);
}
#[test]
fn a_value_wanted_in_two_places_is_read_twice() {
let parallel = moves(&[('a', 'c'), ('b', 'c')]);
let order = sequence(¶llel, 'z');
assert!(correct(¶llel, &order));
assert_eq!(order.len(), 2);
assert!(!order.iter().any(|one| one.to == 'z'));
}
#[test]
fn a_cycle_with_a_tail_hanging_off_it_is_still_one_extra_move() {
let parallel = moves(&[('a', 'b'), ('b', 'a'), ('d', 'a')]);
let order = sequence(¶llel, 'z');
assert!(correct(¶llel, &order));
assert_eq!(order.len(), 4);
}
#[test]
fn a_move_from_a_place_to_itself_is_nothing_to_do() {
let order = sequence(&moves(&[('a', 'a'), ('b', 'c')]), 'z');
assert_eq!(order, moves(&[('b', 'c')]));
}
#[test]
fn nothing_to_move_is_nothing_to_do() {
assert_eq!(sequence::<char>(&[], 'z'), []);
}
#[test]
#[should_panic(expected = "two parallel moves write the same place")]
fn two_moves_that_write_one_place_are_not_a_question_this_can_answer() {
let _ = sequence(&moves(&[('a', 'b'), ('a', 'c')]), 'z');
}
}