11use cspuz_rs:: graph;
22use cspuz_rs:: serializer:: {
3- problem_to_url_with_context, url_to_problem, Choice , Combinator , Context , ContextBasedGrid ,
4- Dict , HexInt , Optionalize , Rooms , Size , Spaces , Tuple2 ,
3+ problem_to_url_with_context, url_to_problem, Choice , Choice2 , Combinator , Context ,
4+ ContextBasedGrid , Dict , HexInt , Map , MultiDigit , Optionalize , Rooms , Size , Spaces , Tuple3 ,
55} ;
66use cspuz_rs:: solver:: Solver ;
77
88pub fn solve_ripple (
99 borders : & graph:: InnerGridEdges < Vec < Vec < bool > > > ,
1010 clues : & [ Vec < Option < i32 > > ] ,
11+ is_hole : & Option < Vec < Vec < bool > > > ,
1112) -> Option < Vec < Vec < Option < i32 > > > > {
1213 let ( h, w) = borders. base_shape ( ) ;
1314
14- let rooms = graph:: borders_to_rooms ( borders) ;
15+ // Making a copy of the borders for holes
16+ let mut borders_with_holes = graph:: InnerGridEdges {
17+ horizontal : borders. horizontal . clone ( ) ,
18+ vertical : borders. vertical . clone ( ) ,
19+ } ;
20+
21+ // If there are holes, add a border between cells with holes and cells with no holes
22+ if let Some ( is_hole) = is_hole {
23+ for y in 0 ..h {
24+ for x in 0 ..w {
25+ if is_hole[ y] [ x] ^ is_hole[ y] [ ( x + 1 ) . min ( w - 1 ) ] {
26+ borders_with_holes. vertical [ y] [ x] = true ;
27+ }
28+ if is_hole[ ( y + 1 ) . min ( h - 1 ) ] [ x] ^ is_hole[ y] [ x] {
29+ borders_with_holes. horizontal [ y] [ x] = true ;
30+ }
31+ }
32+ }
33+ }
34+
35+ let rooms = graph:: borders_to_rooms ( & borders_with_holes) ;
1536 let mut ranges = vec ! [ vec![ ( 1 , 1 ) ; w] ; h] ;
1637
1738 for room in & rooms {
1839 for & ( y, x) in room {
19- ranges[ y] [ x] = ( 1 , room. len ( ) as i32 ) ;
40+ let hole = if let Some ( is_hole) = is_hole {
41+ is_hole[ y] [ x]
42+ } else {
43+ false
44+ } ;
45+ ranges[ y] [ x] = if hole { ( 0 , 0 ) } else { ( 1 , room. len ( ) as i32 ) } ;
2046 }
2147 }
2248
@@ -35,6 +61,16 @@ pub fn solve_ripple(
3561 }
3662
3763 for room in & rooms {
64+ let hole_only = room. iter ( ) . all ( |& ( y, x) | {
65+ if let Some ( is_hole) = is_hole {
66+ is_hole[ y] [ x]
67+ } else {
68+ false
69+ }
70+ } ) ;
71+ if hole_only {
72+ continue ;
73+ }
3874 let room_nums = num. select ( room) ;
3975 for i in 1 ..=room. len ( ) {
4076 solver. add_expr ( room_nums. eq ( i as i32 ) . count_true ( ) . eq ( 1 ) ) ;
@@ -70,16 +106,28 @@ pub fn solve_ripple(
70106 solver. irrefutable_facts ( ) . map ( |f| f. get ( num) )
71107}
72108
73- pub type Problem = ( graph:: InnerGridEdges < Vec < Vec < bool > > > , Vec < Vec < Option < i32 > > > ) ;
109+ pub type Problem = (
110+ graph:: InnerGridEdges < Vec < Vec < bool > > > ,
111+ Vec < Vec < Option < i32 > > > ,
112+ Option < Vec < Vec < bool > > > ,
113+ ) ;
74114
75115fn combinator ( ) -> impl Combinator < Problem > {
76- Size :: new ( Tuple2 :: new (
116+ Size :: new ( Tuple3 :: new (
77117 Rooms ,
78118 ContextBasedGrid :: new ( Choice :: new ( vec ! [
79119 Box :: new( Optionalize :: new( HexInt ) ) ,
80120 Box :: new( Spaces :: new( None , 'g' ) ) ,
81121 Box :: new( Dict :: new( Some ( -1 ) , "." ) ) ,
82122 ] ) ) ,
123+ Choice2 :: new (
124+ Optionalize :: new ( ContextBasedGrid :: new ( Map :: new (
125+ MultiDigit :: new ( 2 , 5 ) ,
126+ |x : bool | Some ( if x { 1 } else { 0 } ) ,
127+ |n : i32 | Some ( n == 1 ) ,
128+ ) ) ) ,
129+ Dict :: new ( None , "" ) ,
130+ ) ,
83131 ) )
84132}
85133
@@ -124,13 +172,13 @@ mod tests {
124172 vec![ None , None , None , None , Some ( 1 ) ] ,
125173 ] ;
126174
127- ( borders, clues)
175+ ( borders, clues, None )
128176 }
129177
130178 #[ test]
131179 fn test_ripple_problem ( ) {
132- let ( borders, clues) = problem_for_tests ( ) ;
133- let ans = solve_ripple ( & borders, & clues) ;
180+ let ( borders, clues, is_hole ) = problem_for_tests ( ) ;
181+ let ans = solve_ripple ( & borders, & clues, & is_hole ) ;
134182 assert ! ( ans. is_some( ) ) ;
135183 let ans = ans. unwrap ( ) ;
136184
0 commit comments