11use crate :: map:: RegionId ;
22use crate :: Map ;
33
4- #[ derive( Debug ) ]
4+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
55pub struct ColorMap {
6- // possible colors by regionid. A color is represented as a 4 bit bitmask.
6+ // possible colors by regionid. A color is represented as a 4 bit bitmask and each element
7+ // contains the possible colors for 2 regions.
78 possible_colors : Vec < u8 > ,
9+
10+ // number of regions of this colormap.
11+ regions : usize ,
812}
913
1014#[ derive( Debug , Clone , Copy ) ]
@@ -16,6 +20,12 @@ pub enum Color {
1620 C4 = 1 << 3 ,
1721}
1822
23+ enum SolutionState {
24+ CannotSolve ,
25+ Solved ,
26+ Unknown ,
27+ }
28+
1929impl ColorMap {
2030 pub fn color ( m : & Map ) -> Option < ColorMap > {
2131 Self :: all_possible_colorings ( m) . next ( )
@@ -26,7 +36,8 @@ impl ColorMap {
2636 }
2737
2838 pub fn color_of_region ( & self , rid : RegionId ) -> Color {
29- let c = self . possible_colors [ rid] ;
39+ let c = self . at ( rid) ;
40+
3041 if c == Color :: C1 as u8 {
3142 return Color :: C1 ;
3243 }
@@ -50,29 +61,94 @@ impl ColorMap {
5061 unreachable ! ( )
5162 }
5263 }
64+
65+ fn at ( & self , rid : RegionId ) -> u8 {
66+ assert ! ( rid < self . regions) ;
67+
68+ let pcs = self . possible_colors [ rid / 2 ] ;
69+ if rid & 1 != 0 {
70+ pcs >> 4
71+ } else {
72+ pcs & 0xf
73+ }
74+ }
75+
76+ fn set ( & mut self , rid : RegionId , v : u8 ) {
77+ assert ! ( rid < self . regions) ;
78+
79+ let old = self . possible_colors [ rid / 2 ] ;
80+ let pcs = if rid & 1 != 0 {
81+ ( v << 4 ) | ( old & 0xf )
82+ } else {
83+ ( old & 0xf0 ) | ( v & 0xf )
84+ } ;
85+
86+ self . possible_colors [ rid / 2 ] = pcs;
87+ }
88+
89+ fn remove_conflicts ( & mut self , map : & Map ) -> SolutionState {
90+ loop {
91+ // first find regions with a single possible colors and remove that color from its
92+ // neighbors until no regions change its respective colors. If any of the regions cannot be
93+ // colored then this map cannot be colored. On the other hand, if all the regions have a
94+ // single possible color then that's the solution.
95+ let mut stalled = true ;
96+ let mut solved = true ;
97+
98+ for rid in 0 ..self . regions {
99+ let c = self . at ( rid) ;
100+ if c == 0 {
101+ return SolutionState :: CannotSolve ;
102+ }
103+
104+ if c. count_ones ( ) != 1 {
105+ solved = false ;
106+ continue ;
107+ }
108+
109+ for & neigh in & map. regions [ rid] . neighbors {
110+ let old = self . at ( neigh) ;
111+ let new = old & !c;
112+
113+ self . set ( neigh, new) ;
114+ if old != new {
115+ stalled = false ;
116+ solved = false ;
117+ }
118+ }
119+ }
120+
121+ if stalled {
122+ break if solved {
123+ SolutionState :: Solved
124+ } else {
125+ SolutionState :: Unknown
126+ } ;
127+ }
128+ }
129+ }
53130}
54131
55132#[ derive( Debug ) ]
56133struct SolutionIter < ' m > {
57- stack : Vec < Vec < u8 > > ,
134+ stack : Vec < ColorMap > ,
58135 map : & ' m Map ,
59136}
60137
61138impl < ' m > SolutionIter < ' m > {
62139 fn new ( map : & ' m Map ) -> Self {
140+ let cm = vec ! [ 0xff ; map. regions. len( ) / 2 + ( map. regions. len( ) & 1 ) ] ;
141+
63142 SolutionIter {
64143 map,
65- stack : vec ! [ vec![ 0xf ; map. regions. len( ) ] ] ,
144+ stack : vec ! [ ColorMap {
145+ possible_colors: cm,
146+ regions: map. regions. len( ) ,
147+ } ] ,
66148 }
67149 }
68150}
69151
70- enum SolutionState {
71- CannotSolve ,
72- Solved ,
73- Unknown ,
74- }
75-
76152impl Iterator for SolutionIter < ' _ > {
77153 type Item = ColorMap ;
78154
@@ -81,19 +157,17 @@ impl Iterator for SolutionIter<'_> {
81157 let possible_colors_len =
82158 |pc : u8 | ( ( pc >> 3 ) & 1 ) + ( ( pc >> 2 ) & 1 ) + ( ( pc >> 1 ) & 1 ) + ( pc & 1 ) ;
83159
84- while let Some ( mut possible_colors ) = self . stack . pop ( ) {
85- let state = remove_conflicts ( & mut possible_colors , & self . map ) ;
160+ while let Some ( mut color_map ) = self . stack . pop ( ) {
161+ let state = color_map . remove_conflicts ( self . map ) ;
86162
87163 match state {
88- SolutionState :: Solved => return Some ( ColorMap { possible_colors } ) ,
164+ SolutionState :: Solved => return Some ( color_map ) ,
89165 SolutionState :: CannotSolve => continue ,
90166 SolutionState :: Unknown => {
91167 // pick the region with the smallest amount of possible colors to choose from so that we
92168 // have to explore less space
93- let ( candidate_i, _) = possible_colors
94- . iter ( )
95- . enumerate ( )
96- . map ( |( i, & pc) | ( i, possible_colors_len ( pc) ) )
169+ let ( candidate_rid, _) = ( 0 ..color_map. regions )
170+ . map ( |rid| ( rid, possible_colors_len ( color_map. at ( rid) ) ) )
97171 . filter ( |( _, pcl) | {
98172 // regions that have a single possible color are fixed and cannot be
99173 // changed, aka they're not candidates
@@ -102,16 +176,16 @@ impl Iterator for SolutionIter<'_> {
102176 . min_by_key ( |( _, pcl) | * pcl) ?;
103177
104178 // try all the possible colors for the candidate and recursively find a solution
105- let pcs = possible_colors [ candidate_i ] ;
179+ let pcs = color_map . at ( candidate_rid ) ;
106180 self . stack . extend (
107181 [ Color :: C1 , Color :: C2 , Color :: C3 , Color :: C4 ]
108182 . iter ( )
109183 . rev ( )
110184 . filter ( |& & c| has_color ( pcs, c) )
111185 . map ( |& c| {
112- let mut new_possible_colors = possible_colors . clone ( ) ;
113- new_possible_colors [ candidate_i ] = c as u8 ;
114- new_possible_colors
186+ let mut new_color_map = color_map . clone ( ) ;
187+ new_color_map . set ( candidate_rid , c as u8 ) ;
188+ new_color_map
115189 } ) ,
116190 ) ;
117191 }
@@ -121,44 +195,3 @@ impl Iterator for SolutionIter<'_> {
121195 None
122196 }
123197}
124-
125- fn remove_conflicts ( possible_colors : & mut [ u8 ] , map : & Map ) -> SolutionState {
126- loop {
127- // first find regions with a single possible colors and remove that color from its
128- // neighbors until no regions change its respective colors. If any of the regions cannot be
129- // colored then this map cannot be colored. On the other hand, if all the regions have a
130- // single possible color then that's the solution.
131- let mut stalled = true ;
132- let mut solved = true ;
133-
134- for rid in 0 ..possible_colors. len ( ) {
135- let c = possible_colors[ rid] ;
136- if c == 0 {
137- return SolutionState :: CannotSolve ;
138- }
139-
140- if c. count_ones ( ) != 1 {
141- solved = false ;
142- continue ;
143- }
144-
145- for & neigh in & map. regions [ rid] . neighbors {
146- let old = possible_colors[ neigh] ;
147- possible_colors[ neigh] &= !c;
148-
149- if old != possible_colors[ neigh] {
150- stalled = false ;
151- solved = false ;
152- }
153- }
154- }
155-
156- if stalled {
157- break if solved {
158- SolutionState :: Solved
159- } else {
160- SolutionState :: Unknown
161- } ;
162- }
163- }
164- }
0 commit comments