1use std::cmp::{Ordering, max};
4use std::collections::{HashMap, HashSet};
5use std::iter::Extend;
6use std::ops::{Add, Index, RangeBounds};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
10pub struct Shaft(pub u32);
11
12#[derive(Debug, Clone, Copy, PartialEq)]
14pub struct Treadle(pub u32);
15
16#[derive(Debug, PartialEq, Clone)]
18pub struct Threading {
19 shaft_count: u32,
20 threading: Vec<u32>,
21}
22
23impl Index<usize> for Threading {
24 type Output = u32;
25
26 fn index(&self, index: usize) -> &Self::Output {
27 &self.threading[index]
28 }
29}
30
31impl Threading {
32 #[must_use]
37 pub fn new(shaft_count: u32, threading: Vec<u32>) -> Self {
38 for shaft in &threading {
39 assert!(
40 shaft <= &shaft_count,
41 "shaft count is {shaft_count} but found shaft {shaft}"
42 );
43 }
44
45 Threading {
46 shaft_count,
47 threading,
48 }
49 }
50
51 fn validate(&self, other: &[u32]) -> Result<(), usize> {
52 let index = other.iter().position(|s| s > &self.shaft_count);
53 match index {
54 None => Ok(()),
55 Some(i) => Err(i),
56 }
57 }
58
59 pub fn splice<R>(&mut self, range: R, replace_with: &[u32]) -> Result<Vec<u32>, usize>
79 where
80 R: RangeBounds<usize>,
81 {
82 self.validate(replace_with)?;
83 let replaced: Vec<u32> = self
84 .threading
85 .splice(range, replace_with.to_owned())
86 .collect();
87
88 Ok(replaced)
89 }
90
91 #[must_use]
93 pub fn len(&self) -> usize {
94 self.threading.len()
95 }
96
97 #[must_use]
99 pub fn is_empty(&self) -> bool {
100 self.threading.is_empty()
101 }
102
103 #[must_use]
105 pub fn threading(&self) -> &Vec<u32> {
106 &self.threading
107 }
108
109 pub fn push(&mut self, shaft: u32) -> Result<(), u32> {
113 if shaft > self.shaft_count {
114 return Err(shaft);
115 }
116 self.threading.push(shaft);
117 Ok(())
118 }
119
120 pub fn insert(&mut self, shaft: Shaft, index: usize) -> Result<(), Shaft> {
128 if shaft.0 > self.shaft_count {
129 return Err(shaft);
130 }
131 self.threading.insert(index, shaft.0);
132 Ok(())
133 }
134
135 pub fn try_insert(&mut self, shaft: Shaft, index: usize) -> Result<Result<(), Shaft>, usize> {
140 let len = self.threading.len();
141 if index > len {
142 Err(len)
143 } else {
144 Ok(self.insert(shaft, index))
145 }
146 }
147
148 pub fn remove(&mut self, index: usize) -> Shaft {
153 Shaft(self.threading.remove(index))
154 }
155
156 #[must_use]
158 pub fn get(&self, index: usize) -> Option<&u32> {
159 self.threading.get(index)
160 }
161
162 pub fn put(&mut self, index: usize, shaft: Shaft) -> Shaft {
167 let old = self.threading[index];
168 self.threading[index] = shaft.0;
169 Shaft(old)
170 }
171
172 pub fn try_put(&mut self, index: usize, shaft: Shaft) -> Result<Option<Shaft>, usize> {
178 let len = self.threading.len();
179 match index.cmp(&len) {
180 Ordering::Less => Ok(Some(self.put(index, shaft))),
181 Ordering::Equal => {
182 self.threading.push(shaft.0);
183 Ok(None)
184 }
185 Ordering::Greater => Err(len),
186 }
187 }
188
189 #[must_use]
191 pub fn max_shaft(&self) -> u32 {
192 let max = self.threading.iter().max();
193 *max.unwrap_or(&0)
194 }
195
196 pub fn set_shaft_count(&mut self, shaft_count: u32) -> Result<(), usize> {
204 if shaft_count == 0 {
205 panic!("shaft count is 0");
206 } else if shaft_count >= self.max_shaft() {
207 self.shaft_count = shaft_count;
208 Ok(())
209 } else {
210 let pos = self
212 .threading
213 .iter()
214 .position(|s| s > &shaft_count)
215 .unwrap();
216 Err(pos)
217 }
218 }
219
220 pub fn trim_shafts(&mut self) -> &Self {
223 if let Some(&max) = self.threading.iter().max() {
224 if max < self.shaft_count {
225 self.shaft_count = max;
226 }
227 }
228 self
229 }
230
231 #[must_use]
241 pub fn used_shafts(&self) -> HashSet<u32> {
242 let mut set = HashSet::new();
243 for shaft in &self.threading {
244 set.insert(*shaft);
245 }
246 set
247 }
248
249 #[allow(clippy::cast_possible_truncation)]
251 #[allow(clippy::missing_panics_doc)]
252 pub fn trim_and_squish_shafts(&mut self) -> &Self {
253 let mut used_shafts: Vec<u32> = self.used_shafts().into_iter().collect();
254 used_shafts.sort_unstable();
255 self.shaft_count = used_shafts.len() as u32;
256 let mapping: HashMap<u32, u32> = used_shafts
257 .into_iter()
258 .enumerate()
259 .map(|(i, s)| (s, i as u32 + 1))
260 .collect();
261
262 self.threading
263 .iter_mut()
264 .for_each(|s| *s = *mapping.get(s).unwrap());
266 self
267 }
268
269 pub fn flip_vertical(&mut self) -> &Self {
272 for thread in &mut self.threading {
273 *thread = self.shaft_count - *thread;
274 }
275 self
276 }
277
278 pub fn mirror(&mut self) -> &Self {
287 if self.threading.len() <= 1 {
288 return self;
289 }
290 let mirror_section = self.threading[..(self.threading.len() - 1)].to_vec();
291 self.threading.extend(mirror_section.iter().rev());
292
293 self
294 }
295
296 pub fn reverse(&mut self) -> &Self {
298 self.threading.reverse();
299 self
300 }
301}
302
303impl IntoIterator for Threading {
304 type Item = u32;
305 type IntoIter = std::vec::IntoIter<Self::Item>;
306
307 fn into_iter(self) -> Self::IntoIter {
308 self.threading.into_iter()
309 }
310}
311
312impl Add for &Threading {
313 type Output = Threading;
314
315 fn add(self, rhs: Self) -> Self::Output {
316 let mut threading = self.threading.clone();
317 threading.extend(&rhs.threading);
318 Threading {
319 shaft_count: max(self.shaft_count, rhs.shaft_count),
320 threading,
321 }
322 }
323}
324
325impl Add<Threading> for &Threading {
326 type Output = Threading;
327
328 fn add(self, rhs: Threading) -> Self::Output {
329 let mut threading = self.threading.clone();
330 threading.extend(rhs.threading);
331 Threading {
332 shaft_count: max(self.shaft_count, rhs.shaft_count),
333 threading,
334 }
335 }
336}
337
338impl Add for Threading {
339 type Output = Self;
340
341 fn add(self, rhs: Self) -> Self::Output {
342 let mut threading = self.threading;
343 threading.extend(rhs.threading);
344
345 Threading {
346 shaft_count: max(self.shaft_count, rhs.shaft_count),
347 threading,
348 }
349 }
350}
351
352impl Add<&Threading> for Threading {
353 type Output = Threading;
354
355 fn add(self, rhs: &Threading) -> Self::Output {
356 let mut threading = self.threading;
357 threading.extend(&rhs.threading);
358
359 Threading {
360 shaft_count: max(self.shaft_count, rhs.shaft_count),
361 threading,
362 }
363 }
364}
365
366#[derive(Debug, PartialEq, Clone)]
369pub struct TreadlingInfo {
370 shaft_count: u32,
371 rise_sink: RiseSink,
372 tie_up: TieUpKind,
373 treadling: Treadling,
374}
375
376#[derive(Debug, Clone, Copy, PartialEq)]
378pub enum TieUpCreate {
379 Direct,
381 Indirect(u32),
383}
384
385impl TreadlingInfo {
386 #[must_use]
391 pub fn new(shaft_count: u32, tie_up: TieUpCreate, rise_sink: RiseSink) -> Self {
392 assert_ne!(shaft_count, 0, "shaft count is 0");
393 let tie_up = match tie_up {
394 TieUpCreate::Direct => TieUpKind::Direct,
395 TieUpCreate::Indirect(treadles) => {
396 assert_ne!(treadles, 0, "treadle count is 0");
397
398 TieUpKind::Indirect(TieUp {
399 treadle_count: treadles,
400 tie_up: vec![HashSet::new(); treadles as usize],
401 })
402 }
403 };
404
405 TreadlingInfo {
406 shaft_count,
407 tie_up,
408 treadling: Treadling::new(),
409 rise_sink,
410 }
411 }
412
413 #[must_use]
415 pub fn shaft_count(&self) -> u32 {
416 self.shaft_count
417 }
418
419 #[must_use]
423 pub fn max_shaft_used(&self) -> u32 {
424 match &self.tie_up {
425 TieUpKind::Direct => self.treadling.max_shaft(),
426 TieUpKind::Indirect(tie_up) => tie_up.max_shaft(),
427 }
428 }
429
430 pub fn set_shaft_count(&mut self, shaft_count: u32) -> Result<(), u32> {
435 let max = self.max_shaft_used();
436 if shaft_count >= max {
437 self.shaft_count = shaft_count;
438 Ok(())
439 } else {
440 Err(max)
441 }
442 }
443
444 #[must_use]
446 pub fn tie_up(&self) -> &TieUpKind {
447 &self.tie_up
448 }
449
450 #[must_use]
452 pub fn treadle_count(&self) -> u32 {
453 match self.tie_up {
454 TieUpKind::Direct => self.shaft_count,
455 TieUpKind::Indirect(TieUp { treadle_count, .. }) => treadle_count,
456 }
457 }
458
459 #[must_use]
461 pub fn rise_sink(&self) -> RiseSink {
462 self.rise_sink
463 }
464
465 #[must_use]
467 pub fn len(&self) -> usize {
468 self.treadling.0.len()
469 }
470
471 #[must_use]
473 pub fn is_empty(&self) -> bool {
474 self.treadling.0.len() == 0
475 }
476
477 pub fn push_single(&mut self, treadle: u32) -> Result<(), u32> {
482 if treadle > self.treadle_count() {
483 return Err(treadle);
484 } else if treadle == 0 {
485 self.treadling.0.push(HashSet::new());
487 } else {
488 self.treadling.0.push(HashSet::from([treadle]));
489 }
490 Ok(())
491 }
492
493 fn validate_treadle(&self, treadle: u32) -> Result<(), u32> {
494 if treadle == 0 || treadle > self.treadle_count() {
495 Err(treadle)
496 } else {
497 Ok(())
498 }
499 }
500
501 fn validate(&self, treadles: &HashSet<u32>) -> Result<(), u32> {
502 let t_count = self.treadle_count();
503 match treadles.iter().find(|&&t| t == 0 || t > t_count) {
504 None => Ok(()),
505 Some(&t) => Err(t),
506 }
507 }
508
509 pub fn push(&mut self, treadles: HashSet<u32>) -> Result<(), u32> {
514 self.validate(&treadles)?;
515 self.treadling.0.push(treadles);
516
517 Ok(())
518 }
519
520 pub fn toggle_treadle(&mut self, index: usize, treadle: Treadle) -> Result<bool, u32> {
527 self.validate_treadle(treadle.0)?;
528 let pick = &mut self.treadling.0[index];
529 if pick.contains(&treadle.0) {
530 pick.remove(&treadle.0);
531 Ok(false)
532 } else {
533 pick.insert(treadle.0);
534 Ok(true)
535 }
536 }
537
538 pub fn insert(&mut self, index: usize, treadles: HashSet<u32>) -> Result<(), u32> {
545 self.validate(&treadles)?;
546 self.treadling.0.insert(index, treadles);
547
548 Ok(())
549 }
550
551 pub fn splice<R>(
558 &mut self,
559 range: R,
560 replace_with: Vec<HashSet<u32>>,
561 ) -> Result<Vec<HashSet<u32>>, u32>
562 where
563 R: RangeBounds<usize>,
564 {
565 for pick in &replace_with {
566 self.validate(pick)?;
567 }
568
569 let replaced: Vec<HashSet<u32>> = self.treadling.0.splice(range, replace_with).collect();
570
571 Ok(replaced)
572 }
573
574 pub fn put(
582 &mut self,
583 index: usize,
584 treadles: HashSet<u32>,
585 ) -> Result<Option<HashSet<u32>>, u32> {
586 self.validate(&treadles)?;
587
588 match index.cmp(&self.len()) {
589 Ordering::Less => {
590 let old = self.treadling.0[index].clone();
591 self.treadling.0[index] = treadles;
592 Ok(Some(old))
593 }
594 Ordering::Equal => {
595 self.treadling.0.push(treadles);
596 Ok(None)
597 }
598 Ordering::Greater => {
599 panic!("Index {index} out of bounds")
600 }
601 }
602 }
603
604 pub fn make_rising(&mut self) {
606 match self.rise_sink {
607 RiseSink::Rising => (),
608 RiseSink::Sinking => self.invert(),
609 }
610 }
611
612 pub fn make_sinking(&mut self) {
614 match self.rise_sink {
615 RiseSink::Rising => self.invert(),
616 RiseSink::Sinking => (),
617 }
618 }
619
620 pub fn make_lift_plan(&mut self) -> bool {
623 match &mut self.tie_up {
624 TieUpKind::Direct => false,
625 TieUpKind::Indirect(tie_up) => {
626 for entry in &mut self.treadling.0 {
627 *entry = tie_up.compute_shafts(entry);
628 }
629 self.tie_up = TieUpKind::Direct;
630 true
631 }
632 }
633 }
634
635 pub fn invert(&mut self) {
637 match &mut self.tie_up {
638 TieUpKind::Direct => self.treadling.invert(self.shaft_count),
639 TieUpKind::Indirect(tie_up) => tie_up.invert(self.shaft_count),
640 }
641
642 self.rise_sink = self.rise_sink.invert();
643 }
644}
645
646impl Index<usize> for TreadlingInfo {
647 type Output = HashSet<u32>;
648 fn index(&self, index: usize) -> &Self::Output {
649 &self.treadling[index]
650 }
651}
652
653fn invert(set: &HashSet<u32>, max: u32) -> HashSet<u32> {
654 assert_ne!(max, 0, "cannot invert when max is 0");
655 let inversion = (1..=max).collect::<HashSet<u32>>();
656
657 &inversion - set
658}
659
660#[derive(Debug, Clone, PartialEq)]
662pub enum TieUpKind {
663 Direct,
665 Indirect(TieUp),
667}
668
669impl TieUpKind {
670 #[must_use]
672 pub fn tie_up(&self) -> Option<&TieUp> {
673 match self {
674 TieUpKind::Direct => None,
675 TieUpKind::Indirect(tie_up) => Some(tie_up),
676 }
677 }
678
679 #[must_use]
681 pub fn raw_tie_up(&self) -> Option<&Vec<HashSet<u32>>> {
682 match self {
683 TieUpKind::Direct => None,
684 TieUpKind::Indirect(tie_up) => Some(&tie_up.tie_up),
685 }
686 }
687}
688
689#[derive(Debug, Clone, PartialEq)]
691pub struct TieUp {
692 treadle_count: u32,
693 tie_up: Vec<HashSet<u32>>,
694}
695
696impl TieUp {
697 fn invert(&mut self, shaft_count: u32) {
698 self.tie_up
699 .iter_mut()
700 .for_each(|t| *t = invert(t, shaft_count));
701 }
702
703 fn max_shaft(&self) -> u32 {
704 max_vec_hash(&self.tie_up)
705 }
706
707 #[must_use]
711 pub fn get_shafts(&self, treadle: &u32) -> Option<&HashSet<u32>> {
712 self.tie_up.get((treadle - 1) as usize)
713 }
714
715 #[must_use]
717 pub fn compute_shafts(&self, treadles: &HashSet<u32>) -> HashSet<u32> {
718 let mut shafts = HashSet::new();
719 for treadle in treadles {
720 if let Some(tied_shafts) = self.get_shafts(treadle) {
721 for shaft in tied_shafts {
722 shafts.insert(*shaft);
723 }
724 }
725 }
726 shafts
727 }
728}
729
730#[derive(Debug, Clone, PartialEq, Copy)]
732pub enum RiseSink {
733 Rising,
735 Sinking,
737}
738
739impl RiseSink {
740 #[must_use]
742 pub fn invert(self) -> Self {
743 match self {
744 RiseSink::Rising => Self::Sinking,
745 RiseSink::Sinking => Self::Rising,
746 }
747 }
748}
749
750impl Default for RiseSink {
751 fn default() -> Self {
753 Self::Rising
754 }
755}
756
757#[derive(Debug, Clone, PartialEq)]
758pub struct Treadling(Vec<HashSet<u32>>);
759
760fn max_vec_hash(vec: &[HashSet<u32>]) -> u32 {
761 *vec.iter()
762 .map(|s| s.iter().max().unwrap_or(&0))
763 .max()
764 .unwrap_or(&0)
765}
766
767impl Treadling {
768 fn new() -> Treadling {
769 Treadling(Vec::new())
770 }
771
772 fn invert(&mut self, shaft_count: u32) {
773 self.0.iter_mut().for_each(|t| *t = invert(t, shaft_count));
774 }
775
776 fn max_shaft(&self) -> u32 {
777 max_vec_hash(&self.0)
778 }
779}
780
781impl Add for Treadling {
782 type Output = Treadling;
783
784 fn add(self, rhs: Self) -> Self::Output {
785 let mut new = self.0;
786 new.extend(rhs.0);
787 Treadling(new)
788 }
789}
790
791impl Add<&Treadling> for Treadling {
792 type Output = Treadling;
793 fn add(self, rhs: &Treadling) -> Self::Output {
794 let mut new = self.0;
795 new.extend_from_slice(&rhs.0);
796
797 Treadling(new)
798 }
799}
800
801impl Add for &Treadling {
802 type Output = Treadling;
803
804 fn add(self, rhs: Self) -> Self::Output {
805 let mut new = self.0.clone();
806 new.extend_from_slice(&rhs.0);
807 Treadling(new)
808 }
809}
810
811impl Add<Treadling> for &Treadling {
812 type Output = Treadling;
813 fn add(self, rhs: Treadling) -> Self::Output {
814 let mut new = self.0.clone();
815 new.extend(rhs.0);
816 Treadling(new)
817 }
818}
819
820impl Index<usize> for Treadling {
821 type Output = HashSet<u32>;
822 fn index(&self, index: usize) -> &Self::Output {
823 &self.0[index]
824 }
825}
826
827#[cfg(test)]
828mod tests {
829 use super::*;
830
831 #[test]
832 #[should_panic(expected = "shaft count is 2 but found shaft 3")]
833 fn test_validate_threading() {
834 let _ = Threading::new(2, vec![1, 2, 3, 4]);
835 }
836
837 #[test]
838 fn test_add_threading() {
839 let threading_1 = Threading::new(4, vec![1, 2, 3, 4]);
840 let threading_2 = Threading::new(6, vec![3, 4, 5, 6, 1]);
841 assert_eq!(
842 threading_1 + threading_2,
843 Threading::new(6, vec![1, 2, 3, 4, 3, 4, 5, 6, 1])
844 );
845 }
846
847 #[test]
848 fn test_squish_threading() {
849 let mut threading = Threading::new(8, vec![1, 3, 4, 6, 3]);
850 assert_eq!(
851 threading.trim_and_squish_shafts(),
852 &Threading::new(4, vec![1, 2, 3, 4, 2])
853 );
854 }
855
856 #[test]
857 fn test_invert_set() {
858 let set = HashSet::from([1, 3, 5, 7]);
859 assert_eq!(invert(&set, 8), HashSet::from([2, 4, 6, 8]));
860 }
861
862 #[test]
863 #[should_panic(expected = "cannot invert when max is 0")]
864 fn test_invert_panic() {
865 let set = HashSet::from([1, 3, 5, 7]);
866 let _ = invert(&set, 0);
867 }
868
869 #[test]
870 fn test_invert_tie_up() {
871 let mut tie_up = TieUp {
872 treadle_count: 4,
873 tie_up: vec![
874 HashSet::from([1, 2]),
875 HashSet::from([2, 3]),
876 HashSet::from([3, 4]),
877 HashSet::from([4, 1]),
878 ],
879 };
880 tie_up.invert(4);
881 assert_eq!(
882 tie_up,
883 TieUp {
884 treadle_count: 4,
885 tie_up: vec![
886 HashSet::from([3, 4]),
887 HashSet::from([1, 4]),
888 HashSet::from([1, 2]),
889 HashSet::from([2, 3])
890 ]
891 }
892 );
893 }
894}