1 // Solve a Fillomino puzzle.
15 uint32_t rcount
, ccount
;
16 if (!scanf("%d %d\n", &rcount
, &ccount
)) die("input error");
17 int board
[rcount
][ccount
];
18 inta_t white
[rcount
][ccount
];
19 inta_t black
[rcount
][ccount
];
20 inta_t must
[rcount
* ccount
];
22 for (int i
= 0; i
< rcount
; i
++) {
24 for (int j
= 0; j
< ccount
; j
++) {
25 inta_init(white
[i
][j
]);
26 inta_init(black
[i
][j
]);
27 inta_init(must
[i
* ccount
+ j
]);
29 if (c
== EOF
|| c
== '\n') die("input error");
47 board
[i
][j
] = encode(c
);
50 if (c
!= '\n') die("input error");
53 inta_t r
, c
, blackr
, blackc
, growth
, dupe
, psize
;
63 // Sacrifice a void * so we can index psize from 1.
64 inta_append(psize
, 0);
66 int onboard(int x
, int y
) {
67 return x
>= 0 && x
< rcount
&& y
>= 0 && y
< ccount
;
70 for (int i
= 0; i
< rcount
; i
++) {
71 for (int j
= 0; j
< ccount
; j
++) {
74 // We store more information than we need in scratch for debugging.
75 // The entry [i][j] is:
76 // -1 when being considered as part of the current polyomino
77 // -2 when already searched from the same home square
78 // -3 when already searched from a different home square
79 // 0 when not involved yet
80 // >0 when a potential site to grow the current polyomino
81 int scratch
[rcount
][ccount
];
82 memset(scratch
, 0, rcount
* ccount
* sizeof(int));
85 void recurse(int x
, int y
, int m
, int lower
) {
86 // Even when m = n we look for sites to grow the polyomino, because
87 // in this case, we blacklist these squares; no other n-omino
88 // may intersect these squares.
89 void check(int x
, int y
) {
90 // See if square is suitable for growing polyomino.
91 if (onboard(x
,y
) && !scratch
[x
][y
] &&
92 (board
[x
][y
] == n
|| board
[x
][y
] == 0)) {
95 scratch
[x
][y
] = inta_count(r
);
96 // Have we seen this polyomino before?
97 if (board
[x
][y
] == n
) {
98 if ((x
< i
|| (x
== i
&& y
< j
))) {
99 // We already handled it last time we encountered it.
100 // Mark it as already searched.
103 inta_append(dupe
, x
* ccount
+ y
);
108 int old
= inta_count(r
);
109 int olddupecount
= inta_count(dupe
);
116 // It has grown to the right size.
117 // Check squares adjacent to polyomino. We need only check
118 // the unsearched growth sites and squares already searched because
119 // these are the only potential trouble spots.
120 for(int k
= 0; k
< inta_count(r
); k
++) {
121 int x
= inta_at(r
, k
);
122 int y
= inta_at(c
, k
);
123 if (scratch
[x
][y
] != -1) {
124 if (board
[x
][y
] == n
) {
125 // An n-polyomino cannot border a square clued with n.
126 inta_remove_all(blackr
);
127 inta_remove_all(blackc
);
130 inta_append(blackr
, x
);
131 inta_append(blackc
, y
);
137 for(int a = 0; a < rcount; a++) {
138 for (int b = 0; b < ccount; b++) {
139 putchar(scratch[a][b] + '0');
146 inta_append(psize
, n
);
147 void checkconflict(int w
) {
148 // If the other polyomino covers our home square then don't
149 // bother reporting the conflict, because we handle this case
151 if (inta_index_of(must
[i
* ccount
+ j
], w
) >= 0) return;
152 if (inta_at(psize
, w
) == n
) {
153 inta_ptr a
= (inta_ptr
) malloc(sizeof(inta_t
));
155 darray_append(adj
, (void *) a
);
158 //printf("conflict %d %d\n", w, v);
161 for(int k
= 0; k
< inta_count(blackr
); k
++) {
162 int x
= inta_at(blackr
, k
);
163 int y
= inta_at(blackc
, k
);
164 inta_append(black
[x
][y
], v
);
165 inta_forall(white
[x
][y
], checkconflict
);
167 inta_remove_all(blackr
);
168 inta_remove_all(blackc
);
169 inta_append(white
[i
][j
], v
);
171 int x
= inta_at(r
, k
);
172 int y
= inta_at(c
, k
);
173 inta_append(white
[x
][y
], v
);
175 inta_forall(growth
, addv
);
176 inta_append(must
[i
* ccount
+ j
], v
);
177 void addmust(int k
) { inta_append(must
[k
], v
); }
178 inta_forall(dupe
, addmust
);
181 // Recurse through each growing site.
182 for(int k
= lower
; k
< inta_count(r
); k
++) {
183 int x
= inta_at(r
, k
);
184 int y
= inta_at(c
, k
);
185 if (scratch
[x
][y
] != -3) {
186 inta_append(growth
, k
);
188 recurse(x
, y
, m
+ 1, k
+ 1);
190 inta_remove_last(growth
);
195 for(int k
= old
; k
< inta_count(r
); k
++) {
196 scratch
[inta_at(r
, k
)][inta_at(c
, k
)] = 0;
198 inta_set_count(r
, old
);
199 inta_set_count(c
, old
);
200 inta_set_count(dupe
, olddupecount
);
209 // Each clue n must be covered by exactly one n-polyomino.
210 for (int i
= 0; i
< rcount
* ccount
; i
++) {
211 if (inta_count(must
[i
]) > 0) {
212 zdd_contains_exactly_1(inta_raw(must
[i
]), inta_count(must
[i
]));
217 // Othewise, each square can be covered by at most one of the polyominoes we
219 for (int i
= 0; i
< rcount
; i
++) {
221 for (int j
= 0; j
< ccount
; j
++) {
222 if (board
[i
][j
] != 0) continue;
223 if (inta_count(white
[i
][j
]) > 1) {
224 zdd_contains_at_most_1(inta_raw(white
[i
][j
]), inta_count(white
[i
][j
]));
225 if (first
) first
= 0; else zdd_intersection();
231 // Adjacent polyominoes must differ in size.
232 void handleadj(void *data
) {
233 inta_ptr list
= (inta_ptr
) data
;
234 zdd_contains_at_most_1(inta_raw(list
), inta_count(list
));
237 darray_forall(adj
, handleadj
);
240 void printsol(int *v
, int count
) {
241 char pic
[rcount
][ccount
];
242 memset(pic
, '.', rcount
* ccount
);
243 for(int k
= 0; k
< count
; k
++) {
244 for (int i
= 0; i
< rcount
; i
++) {
245 for (int j
= 0; j
< ccount
; j
++) {
246 if (inta_index_of(white
[i
][j
], v
[k
]) >= 0) {
247 int n
= inta_at(psize
, v
[k
]);
248 pic
[i
][j
] = n
< 10 ? '0' + n
: 'A' + n
- 10;
253 // Now we have a new problem: tile the remaining squares with polyominoes
254 // of arbitrary size to satisfy the puzzle conditions.
255 // TODO: Brute force search to finish the puzzle. For now, we only check
256 // the simplest cases.
257 for (int i
= 0; i
< rcount
; i
++) {
258 for (int j
= 0; j
< ccount
; j
++) {
259 int scratch
[rcount
][ccount
];
260 memset(scratch
, 0, rcount
* ccount
* sizeof(int));
262 void neighbour_run(void (*fn
)(int, int), int i
, int j
) {
268 if ('.' == pic
[i
][j
]) {
270 void paint(int i
, int j
) {
275 void bleed(int i
, int j
) {
277 pic
[i
][j
] == '.' && !scratch
[i
][j
]) paint(i
, j
);
279 neighbour_run(bleed
, i
, j
);
284 void count1(int i
, int j
) {
285 if (onboard(i
, j
) && pic
[i
][j
] == '1') n1
++;
287 neighbour_run(count1
, i
, j
);
294 } else if (count
== 2) {
296 void count1(int i
, int j
) {
297 if (onboard(i
, j
) && pic
[i
][j
] == '2') {
301 int x
= inta_at(r
, 0);
302 int y
= inta_at(c
, 0);
303 neighbour_run(count1
, x
, y
);
306 neighbour_run(count1
, x
, y
);
325 printf("Solution #%d:\n", ++solcount
);
326 for (int i
= 0; i
< rcount
; i
++) {
327 for (int j
= 0; j
< ccount
; j
++) {
334 zdd_forall(printsol
);