loopgen.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /*
  2. * loopgen.c: loop generation functions for grid.[ch].
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <stddef.h>
  7. #include <string.h>
  8. #include <assert.h>
  9. #include <ctype.h>
  10. #ifdef NO_TGMATH_H
  11. # include <math.h>
  12. #else
  13. # include <tgmath.h>
  14. #endif
  15. #include "puzzles.h"
  16. #include "tree234.h"
  17. #include "grid.h"
  18. #include "loopgen.h"
  19. /* We're going to store lists of current candidate faces for colouring black
  20. * or white.
  21. * Each face gets a 'score', which tells us how adding that face right
  22. * now would affect the curliness of the solution loop. We're trying to
  23. * maximise that quantity so will bias our random selection of faces to
  24. * colour those with high scores */
  25. struct face_score {
  26. int white_score;
  27. int black_score;
  28. unsigned long random;
  29. /* No need to store a grid_face* here. The 'face_scores' array will
  30. * be a list of 'face_score' objects, one for each face of the grid, so
  31. * the position (index) within the 'face_scores' array will determine
  32. * which face corresponds to a particular face_score.
  33. * Having a single 'face_scores' array for all faces simplifies memory
  34. * management, and probably improves performance, because we don't have to
  35. * malloc/free each individual face_score, and we don't have to maintain
  36. * a mapping from grid_face* pointers to face_score* pointers.
  37. */
  38. };
  39. static int generic_sort_cmpfn(void *v1, void *v2, size_t offset)
  40. {
  41. struct face_score *f1 = v1;
  42. struct face_score *f2 = v2;
  43. int r;
  44. r = *(int *)((char *)f2 + offset) - *(int *)((char *)f1 + offset);
  45. if (r) {
  46. return r;
  47. }
  48. if (f1->random < f2->random)
  49. return -1;
  50. else if (f1->random > f2->random)
  51. return 1;
  52. /*
  53. * It's _just_ possible that two faces might have been given
  54. * the same random value. In that situation, fall back to
  55. * comparing based on the positions within the face_scores list.
  56. * This introduces a tiny directional bias, but not a significant one.
  57. */
  58. return f1 - f2;
  59. }
  60. static int white_sort_cmpfn(void *v1, void *v2)
  61. {
  62. return generic_sort_cmpfn(v1, v2, offsetof(struct face_score,white_score));
  63. }
  64. static int black_sort_cmpfn(void *v1, void *v2)
  65. {
  66. return generic_sort_cmpfn(v1, v2, offsetof(struct face_score,black_score));
  67. }
  68. /* 'board' is an array of enum face_colour, indicating which faces are
  69. * currently black/white/grey. 'colour' is FACE_WHITE or FACE_BLACK.
  70. * Returns whether it's legal to colour the given face with this colour. */
  71. static bool can_colour_face(grid *g, char* board, int face_index,
  72. enum face_colour colour)
  73. {
  74. int i, j;
  75. grid_face *test_face = g->faces[face_index];
  76. grid_face *starting_face, *current_face;
  77. grid_dot *starting_dot;
  78. int transitions;
  79. bool current_state, s; /* equal or not-equal to 'colour' */
  80. bool found_same_coloured_neighbour = false;
  81. assert(board[face_index] != colour);
  82. /* Can only consider a face for colouring if it's adjacent to a face
  83. * with the same colour. */
  84. for (i = 0; i < test_face->order; i++) {
  85. grid_edge *e = test_face->edges[i];
  86. grid_face *f = (e->face1 == test_face) ? e->face2 : e->face1;
  87. if (FACE_COLOUR(f) == colour) {
  88. found_same_coloured_neighbour = true;
  89. break;
  90. }
  91. }
  92. if (!found_same_coloured_neighbour)
  93. return false;
  94. /* Need to avoid creating a loop of faces of this colour around some
  95. * differently-coloured faces.
  96. * Also need to avoid meeting a same-coloured face at a corner, with
  97. * other-coloured faces in between. Here's a simple test that (I believe)
  98. * takes care of both these conditions:
  99. *
  100. * Take the circular path formed by this face's edges, and inflate it
  101. * slightly outwards. Imagine walking around this path and consider
  102. * the faces that you visit in sequence. This will include all faces
  103. * touching the given face, either along an edge or just at a corner.
  104. * Count the number of 'colour'/not-'colour' transitions you encounter, as
  105. * you walk along the complete loop. This will obviously turn out to be
  106. * an even number.
  107. * If 0, we're either in the middle of an "island" of this colour (should
  108. * be impossible as we're not supposed to create black or white loops),
  109. * or we're about to start a new island - also not allowed.
  110. * If 4 or greater, there are too many separate coloured regions touching
  111. * this face, and colouring it would create a loop or a corner-violation.
  112. * The only allowed case is when the count is exactly 2. */
  113. /* i points to a dot around the test face.
  114. * j points to a face around the i^th dot.
  115. * The current face will always be:
  116. * test_face->dots[i]->faces[j]
  117. * We assume dots go clockwise around the test face,
  118. * and faces go clockwise around dots. */
  119. /*
  120. * The end condition is slightly fiddly. In sufficiently strange
  121. * degenerate grids, our test face may be adjacent to the same
  122. * other face multiple times (typically if it's the exterior
  123. * face). Consider this, in particular:
  124. *
  125. * +--+
  126. * | |
  127. * +--+--+
  128. * | | |
  129. * +--+--+
  130. *
  131. * The bottom left face there is adjacent to the exterior face
  132. * twice, so we can't just terminate our iteration when we reach
  133. * the same _face_ we started at. Furthermore, we can't
  134. * condition on having the same (i,j) pair either, because
  135. * several (i,j) pairs identify the bottom left contiguity with
  136. * the exterior face! We canonicalise the (i,j) pair by taking
  137. * one step around before we set the termination tracking.
  138. */
  139. i = j = 0;
  140. current_face = test_face->dots[0]->faces[0];
  141. if (current_face == test_face) {
  142. j = 1;
  143. current_face = test_face->dots[0]->faces[1];
  144. }
  145. transitions = 0;
  146. current_state = (FACE_COLOUR(current_face) == colour);
  147. starting_dot = NULL;
  148. starting_face = NULL;
  149. while (true) {
  150. /* Advance to next face.
  151. * Need to loop here because it might take several goes to
  152. * find it. */
  153. while (true) {
  154. j++;
  155. if (j == test_face->dots[i]->order)
  156. j = 0;
  157. if (test_face->dots[i]->faces[j] == test_face) {
  158. /* Advance to next dot round test_face, then
  159. * find current_face around new dot
  160. * and advance to the next face clockwise */
  161. i++;
  162. if (i == test_face->order)
  163. i = 0;
  164. for (j = 0; j < test_face->dots[i]->order; j++) {
  165. if (test_face->dots[i]->faces[j] == current_face)
  166. break;
  167. }
  168. /* Must actually find current_face around new dot,
  169. * or else something's wrong with the grid. */
  170. assert(j != test_face->dots[i]->order);
  171. /* Found, so advance to next face and try again */
  172. } else {
  173. break;
  174. }
  175. }
  176. /* (i,j) are now advanced to next face */
  177. current_face = test_face->dots[i]->faces[j];
  178. s = (FACE_COLOUR(current_face) == colour);
  179. if (!starting_dot) {
  180. starting_dot = test_face->dots[i];
  181. starting_face = current_face;
  182. current_state = s;
  183. } else {
  184. if (s != current_state) {
  185. ++transitions;
  186. current_state = s;
  187. if (transitions > 2)
  188. break;
  189. }
  190. if (test_face->dots[i] == starting_dot &&
  191. current_face == starting_face)
  192. break;
  193. }
  194. }
  195. return (transitions == 2) ? true : false;
  196. }
  197. /* Count the number of neighbours of 'face', having colour 'colour' */
  198. static int face_num_neighbours(grid *g, char *board, grid_face *face,
  199. enum face_colour colour)
  200. {
  201. int colour_count = 0;
  202. int i;
  203. grid_face *f;
  204. grid_edge *e;
  205. for (i = 0; i < face->order; i++) {
  206. e = face->edges[i];
  207. f = (e->face1 == face) ? e->face2 : e->face1;
  208. if (FACE_COLOUR(f) == colour)
  209. ++colour_count;
  210. }
  211. return colour_count;
  212. }
  213. /* The 'score' of a face reflects its current desirability for selection
  214. * as the next face to colour white or black. We want to encourage moving
  215. * into grey areas and increasing loopiness, so we give scores according to
  216. * how many of the face's neighbours are currently coloured the same as the
  217. * proposed colour. */
  218. static int face_score(grid *g, char *board, grid_face *face,
  219. enum face_colour colour)
  220. {
  221. /* Simple formula: score = 0 - num. same-coloured neighbours,
  222. * so a higher score means fewer same-coloured neighbours. */
  223. return -face_num_neighbours(g, board, face, colour);
  224. }
  225. /*
  226. * Generate a new complete random closed loop for the given grid.
  227. *
  228. * The method is to generate a WHITE/BLACK colouring of all the faces,
  229. * such that the WHITE faces will define the inside of the path, and the
  230. * BLACK faces define the outside.
  231. * To do this, we initially colour all faces GREY. The infinite space outside
  232. * the grid is coloured BLACK, and we choose a random face to colour WHITE.
  233. * Then we gradually grow the BLACK and the WHITE regions, eliminating GREY
  234. * faces, until the grid is filled with BLACK/WHITE. As we grow the regions,
  235. * we avoid creating loops of a single colour, to preserve the topological
  236. * shape of the WHITE and BLACK regions.
  237. * We also try to make the boundary as loopy and twisty as possible, to avoid
  238. * generating paths that are uninteresting.
  239. * The algorithm works by choosing a BLACK/WHITE colour, then choosing a GREY
  240. * face that can be coloured with that colour (without violating the
  241. * topological shape of that region). It's not obvious, but I think this
  242. * algorithm is guaranteed to terminate without leaving any GREY faces behind.
  243. * Indeed, if there are any GREY faces at all, both the WHITE and BLACK
  244. * regions can be grown.
  245. * This is checked using assert()ions, and I haven't seen any failures yet.
  246. *
  247. * Hand-wavy proof: imagine what can go wrong...
  248. *
  249. * Could the white faces get completely cut off by the black faces, and still
  250. * leave some grey faces remaining?
  251. * No, because then the black faces would form a loop around both the white
  252. * faces and the grey faces, which is disallowed because we continually
  253. * maintain the correct topological shape of the black region.
  254. * Similarly, the black faces can never get cut off by the white faces. That
  255. * means both the WHITE and BLACK regions always have some room to grow into
  256. * the GREY regions.
  257. * Could it be that we can't colour some GREY face, because there are too many
  258. * WHITE/BLACK transitions as we walk round the face? (see the
  259. * can_colour_face() function for details)
  260. * No. Imagine otherwise, and we see WHITE/BLACK/WHITE/BLACK as we walk
  261. * around the face. The two WHITE faces would be connected by a WHITE path,
  262. * and the BLACK faces would be connected by a BLACK path. These paths would
  263. * have to cross, which is impossible.
  264. * Another thing that could go wrong: perhaps we can't find any GREY face to
  265. * colour WHITE, because it would create a loop-violation or a corner-violation
  266. * with the other WHITE faces?
  267. * This is a little bit tricky to prove impossible. Imagine you have such a
  268. * GREY face (that is, if you coloured it WHITE, you would create a WHITE loop
  269. * or corner violation).
  270. * That would cut all the non-white area into two blobs. One of those blobs
  271. * must be free of BLACK faces (because the BLACK stuff is a connected blob).
  272. * So we have a connected GREY area, completely surrounded by WHITE
  273. * (including the GREY face we've tentatively coloured WHITE).
  274. * A well-known result in graph theory says that you can always find a GREY
  275. * face whose removal leaves the remaining GREY area connected. And it says
  276. * there are at least two such faces, so we can always choose the one that
  277. * isn't the "tentative" GREY face. Colouring that face WHITE leaves
  278. * everything nice and connected, including that "tentative" GREY face which
  279. * acts as a gateway to the rest of the non-WHITE grid.
  280. */
  281. void generate_loop(grid *g, char *board, random_state *rs,
  282. loopgen_bias_fn_t bias, void *biasctx)
  283. {
  284. int i, j;
  285. int num_faces = g->num_faces;
  286. struct face_score *face_scores; /* Array of face_score objects */
  287. struct face_score *fs; /* Points somewhere in the above list */
  288. struct grid_face *cur_face;
  289. tree234 *lightable_faces_sorted;
  290. tree234 *darkable_faces_sorted;
  291. int *face_list;
  292. bool do_random_pass;
  293. /* Make a board */
  294. memset(board, FACE_GREY, num_faces);
  295. /* Create and initialise the list of face_scores */
  296. face_scores = snewn(num_faces, struct face_score);
  297. for (i = 0; i < num_faces; i++) {
  298. face_scores[i].random = random_bits(rs, 31);
  299. face_scores[i].black_score = face_scores[i].white_score = 0;
  300. }
  301. /* Colour a random, finite face white. The infinite face is implicitly
  302. * coloured black. Together, they will seed the random growth process
  303. * for the black and white areas. */
  304. i = random_upto(rs, num_faces);
  305. board[i] = FACE_WHITE;
  306. /* We need a way of favouring faces that will increase our loopiness.
  307. * We do this by maintaining a list of all candidate faces sorted by
  308. * their score and choose randomly from that with appropriate skew.
  309. * In order to avoid consistently biasing towards particular faces, we
  310. * need the sort order _within_ each group of scores to be completely
  311. * random. But it would be abusing the hospitality of the tree234 data
  312. * structure if our comparison function were nondeterministic :-). So with
  313. * each face we associate a random number that does not change during a
  314. * particular run of the generator, and use that as a secondary sort key.
  315. * Yes, this means we will be biased towards particular random faces in
  316. * any one run but that doesn't actually matter. */
  317. lightable_faces_sorted = newtree234(white_sort_cmpfn);
  318. darkable_faces_sorted = newtree234(black_sort_cmpfn);
  319. /* Initialise the lists of lightable and darkable faces. This is
  320. * slightly different from the code inside the while-loop, because we need
  321. * to check every face of the board (the grid structure does not keep a
  322. * list of the infinite face's neighbours). */
  323. for (i = 0; i < num_faces; i++) {
  324. grid_face *f = g->faces[i];
  325. struct face_score *fs = face_scores + i;
  326. if (board[i] != FACE_GREY) continue;
  327. /* We need the full colourability check here, it's not enough simply
  328. * to check neighbourhood. On some grids, a neighbour of the infinite
  329. * face is not necessarily darkable. */
  330. if (can_colour_face(g, board, i, FACE_BLACK)) {
  331. fs->black_score = face_score(g, board, f, FACE_BLACK);
  332. add234(darkable_faces_sorted, fs);
  333. }
  334. if (can_colour_face(g, board, i, FACE_WHITE)) {
  335. fs->white_score = face_score(g, board, f, FACE_WHITE);
  336. add234(lightable_faces_sorted, fs);
  337. }
  338. }
  339. /* Colour faces one at a time until no more faces are colourable. */
  340. while (true)
  341. {
  342. enum face_colour colour;
  343. tree234 *faces_to_pick;
  344. int c_lightable = count234(lightable_faces_sorted);
  345. int c_darkable = count234(darkable_faces_sorted);
  346. if (c_lightable == 0 && c_darkable == 0) {
  347. /* No more faces we can use at all. */
  348. break;
  349. }
  350. assert(c_lightable != 0 && c_darkable != 0);
  351. /* Choose a colour, and colour the best available face
  352. * with that colour. */
  353. colour = random_upto(rs, 2) ? FACE_WHITE : FACE_BLACK;
  354. if (colour == FACE_WHITE)
  355. faces_to_pick = lightable_faces_sorted;
  356. else
  357. faces_to_pick = darkable_faces_sorted;
  358. if (bias) {
  359. /*
  360. * Go through all the candidate faces and pick the one the
  361. * bias function likes best, breaking ties using the
  362. * ordering in our tree234 (which is why we replace only
  363. * if score > bestscore, not >=).
  364. */
  365. int j, k;
  366. struct face_score *best = NULL;
  367. int score, bestscore = 0;
  368. for (j = 0;
  369. (fs = (struct face_score *)index234(faces_to_pick, j))!=NULL;
  370. j++) {
  371. assert(fs);
  372. k = fs - face_scores;
  373. assert(board[k] == FACE_GREY);
  374. board[k] = colour;
  375. score = bias(biasctx, board, k);
  376. board[k] = FACE_GREY;
  377. bias(biasctx, board, k); /* let bias know we put it back */
  378. if (!best || score > bestscore) {
  379. bestscore = score;
  380. best = fs;
  381. }
  382. }
  383. fs = best;
  384. } else {
  385. fs = (struct face_score *)index234(faces_to_pick, 0);
  386. }
  387. assert(fs);
  388. i = fs - face_scores;
  389. assert(board[i] == FACE_GREY);
  390. board[i] = colour;
  391. if (bias)
  392. bias(biasctx, board, i); /* notify bias function of the change */
  393. /* Remove this newly-coloured face from the lists. These lists should
  394. * only contain grey faces. */
  395. del234(lightable_faces_sorted, fs);
  396. del234(darkable_faces_sorted, fs);
  397. /* Remember which face we've just coloured */
  398. cur_face = g->faces[i];
  399. /* The face we've just coloured potentially affects the colourability
  400. * and the scores of any neighbouring faces (touching at a corner or
  401. * edge). So the search needs to be conducted around all faces
  402. * touching the one we've just lit. Iterate over its corners, then
  403. * over each corner's faces. For each such face, we remove it from
  404. * the lists, recalculate any scores, then add it back to the lists
  405. * (depending on whether it is lightable, darkable or both). */
  406. for (i = 0; i < cur_face->order; i++) {
  407. grid_dot *d = cur_face->dots[i];
  408. for (j = 0; j < d->order; j++) {
  409. grid_face *f = d->faces[j];
  410. int fi; /* face index of f */
  411. if (f == NULL)
  412. continue;
  413. if (f == cur_face)
  414. continue;
  415. /* If the face is already coloured, it won't be on our
  416. * lightable/darkable lists anyway, so we can skip it without
  417. * bothering with the removal step. */
  418. if (FACE_COLOUR(f) != FACE_GREY) continue;
  419. /* Find the face index and face_score* corresponding to f */
  420. fi = f->index;
  421. fs = face_scores + fi;
  422. /* Remove from lightable list if it's in there. We do this,
  423. * even if it is still lightable, because the score might
  424. * be different, and we need to remove-then-add to maintain
  425. * correct sort order. */
  426. del234(lightable_faces_sorted, fs);
  427. if (can_colour_face(g, board, fi, FACE_WHITE)) {
  428. fs->white_score = face_score(g, board, f, FACE_WHITE);
  429. add234(lightable_faces_sorted, fs);
  430. }
  431. /* Do the same for darkable list. */
  432. del234(darkable_faces_sorted, fs);
  433. if (can_colour_face(g, board, fi, FACE_BLACK)) {
  434. fs->black_score = face_score(g, board, f, FACE_BLACK);
  435. add234(darkable_faces_sorted, fs);
  436. }
  437. }
  438. }
  439. }
  440. /* Clean up */
  441. freetree234(lightable_faces_sorted);
  442. freetree234(darkable_faces_sorted);
  443. sfree(face_scores);
  444. /* The next step requires a shuffled list of all faces */
  445. face_list = snewn(num_faces, int);
  446. for (i = 0; i < num_faces; ++i) {
  447. face_list[i] = i;
  448. }
  449. shuffle(face_list, num_faces, sizeof(int), rs);
  450. /* The above loop-generation algorithm can often leave large clumps
  451. * of faces of one colour. In extreme cases, the resulting path can be
  452. * degenerate and not very satisfying to solve.
  453. * This next step alleviates this problem:
  454. * Go through the shuffled list, and flip the colour of any face we can
  455. * legally flip, and which is adjacent to only one face of the opposite
  456. * colour - this tends to grow 'tendrils' into any clumps.
  457. * Repeat until we can find no more faces to flip. This will
  458. * eventually terminate, because each flip increases the loop's
  459. * perimeter, which cannot increase for ever.
  460. * The resulting path will have maximal loopiness (in the sense that it
  461. * cannot be improved "locally". Unfortunately, this allows a player to
  462. * make some illicit deductions. To combat this (and make the path more
  463. * interesting), we do one final pass making random flips. */
  464. /* Set to true for final pass */
  465. do_random_pass = false;
  466. while (true) {
  467. /* Remember whether a flip occurred during this pass */
  468. bool flipped = false;
  469. for (i = 0; i < num_faces; ++i) {
  470. int j = face_list[i];
  471. enum face_colour opp =
  472. (board[j] == FACE_WHITE) ? FACE_BLACK : FACE_WHITE;
  473. if (can_colour_face(g, board, j, opp)) {
  474. grid_face *face = g->faces[j];
  475. if (do_random_pass) {
  476. /* final random pass */
  477. if (!random_upto(rs, 10))
  478. board[j] = opp;
  479. } else {
  480. /* normal pass - flip when neighbour count is 1 */
  481. if (face_num_neighbours(g, board, face, opp) == 1) {
  482. board[j] = opp;
  483. flipped = true;
  484. }
  485. }
  486. }
  487. }
  488. if (do_random_pass) break;
  489. if (!flipped) do_random_pass = true;
  490. }
  491. sfree(face_list);
  492. }