+static int mark_region(int *board, int w, int h, int i, int n, int m) {
+ int j;
+
+ board[i] = -1;
+
+ for (j = 0; j < 4; ++j) {
+ const int x = (i % w) + dx[j], y = (i / w) + dy[j], ii = w*y + x;
+ if (x < 0 || x >= w || y < 0 || y >= h) continue;
+ if (board[ii] == m) return FALSE;
+ if (board[ii] != n) continue;
+ if (!mark_region(board, w, h, ii, n, m)) return FALSE;
+ }
+ return TRUE;
+}
+
+static int region_size(int *board, int w, int h, int i) {
+ const int sz = w * h;
+ int j, size, copy;
+ if (board[i] == 0) return 0;
+ copy = board[i];
+ mark_region(board, w, h, i, board[i], SENTINEL);
+ for (size = j = 0; j < sz; ++j) {
+ if (board[j] != -1) continue;
+ ++size;
+ board[j] = copy;
+ }
+ return size;
+}
+
+static void merge_ones(int *board, int w, int h)
+{
+ const int sz = w * h;
+ const int maxsize = min(max(max(w, h), 3), 9);
+ int i, j, k, change;
+ do {
+ change = FALSE;
+ for (i = 0; i < sz; ++i) {
+ if (board[i] != 1) continue;
+
+ for (j = 0; j < 4; ++j, board[i] = 1) {
+ const int x = (i % w) + dx[j], y = (i / w) + dy[j];
+ int oldsize, newsize, ok, ii = w*y + x;
+ if (x < 0 || x >= w || y < 0 || y >= h) continue;
+ if (board[ii] == maxsize) continue;
+
+ oldsize = board[ii];
+ board[i] = oldsize;
+ newsize = region_size(board, w, h, i);
+
+ if (newsize > maxsize) continue;
+
+ ok = mark_region(board, w, h, i, oldsize, newsize);
+
+ for (k = 0; k < sz; ++k)
+ if (board[k] == -1)
+ board[k] = ok ? newsize : oldsize;
+
+ if (ok) break;
+ }
+ if (j < 4) change = TRUE;
+ }
+ } while (change);
+}
+