@@ -6,7 +6,9 @@ use rayon::iter::IndexedParallelIterator;
66use rayon:: iter:: IntoParallelRefIterator ;
77use rayon:: iter:: IntoParallelRefMutIterator ;
88use rayon:: iter:: ParallelIterator ;
9+ use std:: collections:: BTreeMap ;
910use std:: collections:: HashMap ;
11+ use std:: collections:: VecDeque ;
1012use std:: fmt;
1113use std:: iter:: Sum ;
1214use std:: marker:: PhantomData ;
@@ -179,7 +181,7 @@ impl Grid<2> {
179181 let segs = iters. segments_2d ( self , 1 ) ;
180182
181183 // Testing horizontal segments for imbalance.
182- for seg in & segs. c [ 0 ] {
184+ for seg in segs. moves ( 0 ) {
183185 if seg. at != 0 {
184186 // Test if we can move segment down.
185187 let moved_cells = ( seg. start ..seg. end ) . map ( |x| [ x, seg. at - 1 ] ) ;
@@ -213,7 +215,7 @@ impl Grid<2> {
213215 }
214216
215217 // Testing vertical segments for imbalance.
216- for seg in & segs. c [ 1 ] {
218+ for seg in segs. moves ( 1 ) {
217219 if seg. at != 0 {
218220 // Test if we can move segment left.
219221 let moved_cells = ( seg. start ..seg. end ) . map ( |y| [ seg. at - 1 , y] ) ;
@@ -247,7 +249,7 @@ impl Grid<2> {
247249 }
248250
249251 // Testing horizontal segments for lambda cut.
250- for seg in & segs. c [ 0 ] {
252+ for seg in segs. moves ( 0 ) {
251253 if seg. at >= 2 {
252254 // Test if we can move segment down.
253255 let a = ( seg. start ..seg. end ) . map ( |x| [ x, seg. at ] ) ;
@@ -275,7 +277,7 @@ impl Grid<2> {
275277 }
276278
277279 // Testing vertical segments for lambda cut.
278- for seg in & segs. c [ 1 ] {
280+ for seg in segs. moves ( 1 ) {
279281 if seg. at >= 2 {
280282 // Test if we can move segment down.
281283 let a = ( seg. start ..seg. end ) . map ( |y| [ seg. at , y] ) ;
@@ -631,7 +633,7 @@ impl SplitTree {
631633 }
632634}
633635
634- #[ derive( Debug ) ]
636+ #[ derive( Clone , Debug ) ]
635637pub struct Segment {
636638 start : usize ,
637639 end : usize ,
@@ -656,6 +658,22 @@ impl Segment {
656658 } ,
657659 ) )
658660 }
661+
662+ pub fn p_start_2d ( & self , coord : usize ) -> [ usize ; 2 ] {
663+ if coord == 0 {
664+ [ self . at , self . start ]
665+ } else {
666+ [ self . start , self . at ]
667+ }
668+ }
669+
670+ pub fn p_end_2d ( & self , coord : usize ) -> [ usize ; 2 ] {
671+ if coord == 0 {
672+ [ self . at , self . end ]
673+ } else {
674+ [ self . end , self . at ]
675+ }
676+ }
659677}
660678
661679#[ derive( Debug ) ]
@@ -664,11 +682,74 @@ pub struct Segments<const D: usize> {
664682 grid : Grid < D > ,
665683}
666684
667- //impl Segments<2> {
668- // pub fn moves(&self) -> impl Iterator<Item = Segment> {
669- // // TODO
670- // }
671- //}
685+ impl Segments < 2 > {
686+ pub fn moves ( & self , coord : usize ) -> impl IntoIterator < Item = Segment > {
687+ let mut occs: BTreeMap < [ usize ; 2 ] , Vec < & Segment > > = BTreeMap :: new ( ) ;
688+
689+ for seg in & self . c [ coord] {
690+ let p1 = seg. p_start_2d ( coord) ;
691+ let p2 = seg. p_end_2d ( coord) ;
692+ occs. entry ( p1) . or_default ( ) . push ( seg) ;
693+ occs. entry ( p2) . or_default ( ) . push ( seg) ;
694+ }
695+
696+ occs. retain ( |_, segs| segs. len ( ) > 1 ) ;
697+
698+ let mut moves = self . c [ coord] . clone ( ) ;
699+
700+ while let Some ( ( joint, segs) ) = occs. pop_first ( ) {
701+ debug_assert_eq ! ( segs. len( ) , 2 ) ;
702+ let seg1 = segs[ 0 ] ;
703+ let seg2 = segs[ 1 ] ;
704+
705+ let mut multi_seg = VecDeque :: new ( ) ;
706+
707+ if seg1. p_end_2d ( coord) == joint {
708+ // seg1 is before seg2
709+ multi_seg. push_back ( seg1) ;
710+ multi_seg. push_back ( seg2) ;
711+ } else {
712+ // seg1 is after seg2
713+ multi_seg. push_back ( seg2) ;
714+ multi_seg. push_back ( seg1) ;
715+ }
716+
717+ loop {
718+ // Add segments to the left of the multi-segment.
719+ let joint = multi_seg. front ( ) . unwrap ( ) . p_start_2d ( coord) ;
720+ let Some ( segs) = occs. remove ( & joint) else { break } ;
721+ let seg = * segs
722+ . iter ( )
723+ . find ( |seg| seg. p_end_2d ( coord) == joint)
724+ . unwrap ( ) ;
725+ multi_seg. push_front ( seg) ;
726+ }
727+ loop {
728+ // Add segments to the right of the multi-segment.
729+ let joint = multi_seg. back ( ) . unwrap ( ) . p_end_2d ( coord) ;
730+ let Some ( segs) = occs. remove ( & joint) else { break } ;
731+ let seg = * segs
732+ . iter ( )
733+ . find ( |seg| seg. p_start_2d ( coord) == joint)
734+ . unwrap ( ) ;
735+ multi_seg. push_back ( seg) ;
736+ }
737+
738+ for i in 0 ..multi_seg. len ( ) {
739+ // i+1 because "moves" already contains individual segments.
740+ for j in i + 1 ..multi_seg. len ( ) {
741+ moves. push ( Segment {
742+ start : multi_seg[ i] . start ,
743+ end : multi_seg[ j] . end ,
744+ at : multi_seg[ i] . at ,
745+ } ) ;
746+ }
747+ }
748+ }
749+
750+ moves
751+ }
752+ }
672753
673754#[ cfg( test) ]
674755mod tests {
0 commit comments