palisade.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. /* -*- indent-tabs-mode: nil; tab-width: 1000 -*- */
  2. /*
  3. * palisade.c: Nikoli's `Five Cells' puzzle.
  4. *
  5. * See http://nikoli.co.jp/en/puzzles/five_cells.html
  6. */
  7. /* TODO:
  8. *
  9. * - better solver: implement the sketched-out deductions
  10. *
  11. * - improve the victory flash?
  12. * - the LINE_NOs look ugly against COL_FLASH.
  13. * - white-blink the edges (instead), a la loopy?
  14. */
  15. #include <assert.h>
  16. #include <ctype.h>
  17. #include <limits.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "puzzles.h"
  23. #define setmem(ptr, byte, len) memset((ptr), (byte), (len) * sizeof (ptr)[0])
  24. #define scopy(dst, src, len) memcpy((dst), (src), (len) * sizeof (dst)[0])
  25. #define dupmem(p, n) memcpy(smalloc(n * sizeof (*p)), p, n * sizeof (*p))
  26. #define snewa(ptr, len) (ptr) = smalloc((len) * sizeof (*ptr))
  27. #define clone(ptr) (dupmem((ptr), 1))
  28. static char *string(int n, const char *fmt, ...)
  29. {
  30. va_list va;
  31. char *ret;
  32. int m;
  33. va_start(va, fmt);
  34. m = vsprintf(snewa(ret, n + 1), fmt, va);
  35. va_end(va);
  36. if (m > n) fatal("memory corruption");
  37. return ret;
  38. }
  39. struct game_params {
  40. int w, h, k;
  41. };
  42. typedef signed char clue;
  43. typedef unsigned char borderflag;
  44. typedef struct shared_state {
  45. game_params params;
  46. clue *clues;
  47. int refcount;
  48. } shared_state;
  49. struct game_state {
  50. shared_state *shared;
  51. borderflag *borders; /* length w*h */
  52. bool completed, cheated;
  53. };
  54. #define DEFAULT_PRESET 0
  55. static struct game_params presets[] = {
  56. {5, 5, 5}, {8, 6, 6}, {10, 8, 8}, {15, 12, 10}
  57. /* I definitely want 5x5n5 since that gives "Five Cells" its name.
  58. * But how about the others? By which criteria do I choose? */
  59. };
  60. static game_params *default_params(void)
  61. {
  62. return clone(&presets[DEFAULT_PRESET]);
  63. }
  64. static bool game_fetch_preset(int i, char **name, game_params **params)
  65. {
  66. if (i < 0 || i >= lenof(presets)) return false;
  67. *params = clone(&presets[i]);
  68. *name = string(60, "%d x %d, regions of size %d",
  69. presets[i].w, presets[i].h, presets[i].k);
  70. return true;
  71. }
  72. static void free_params(game_params *params)
  73. {
  74. sfree(params);
  75. }
  76. static game_params *dup_params(const game_params *params)
  77. {
  78. return clone(params);
  79. }
  80. static void decode_params(game_params *params, char const *string)
  81. {
  82. params->w = params->h = params->k = atoi(string);
  83. while (*string && isdigit((unsigned char)*string)) ++string;
  84. if (*string == 'x') {
  85. params->h = atoi(++string);
  86. while (*string && isdigit((unsigned char)*string)) ++string;
  87. }
  88. if (*string == 'n') params->k = atoi(++string);
  89. }
  90. static char *encode_params(const game_params *params, bool full)
  91. {
  92. return string(40, "%dx%dn%d", params->w, params->h, params->k);
  93. }
  94. #define CONFIG(i, nm, ty, iv, sv) \
  95. (ret[i].name = nm, ret[i].type = ty, ret[i].ival = iv, ret[i].sval = sv)
  96. static config_item *game_configure(const game_params *params)
  97. {
  98. config_item *ret = snewn(4, config_item);
  99. ret[0].name = "Width";
  100. ret[0].type = C_STRING;
  101. ret[0].u.string.sval = string(20, "%d", params->w);
  102. ret[1].name = "Height";
  103. ret[1].type = C_STRING;
  104. ret[1].u.string.sval = string(20, "%d", params->h);
  105. ret[2].name = "Region size";
  106. ret[2].type = C_STRING;
  107. ret[2].u.string.sval = string(20, "%d", params->k);
  108. ret[3].name = NULL;
  109. ret[3].type = C_END;
  110. return ret;
  111. }
  112. static game_params *custom_params(const config_item *cfg)
  113. {
  114. game_params *params = snew(game_params);
  115. params->w = atoi(cfg[0].u.string.sval);
  116. params->h = atoi(cfg[1].u.string.sval);
  117. params->k = atoi(cfg[2].u.string.sval);
  118. return params;
  119. }
  120. /* +---+ << The one possible domino (up to symmetry). +---+---+
  121. * | 3 | | 3 | 3 |
  122. * | | If two dominos are adjacent as depicted here >> +---+---+
  123. * | 3 | then it's ambiguous whether the edge between | 3 | 3 |
  124. * +---+ the dominos is horizontal or vertical. +---+---+
  125. */
  126. static const char *validate_params(const game_params *params, bool full)
  127. {
  128. int w = params->w, h = params->h, k = params->k, wh;
  129. if (k < 1) return "Region size must be at least one";
  130. if (w < 1) return "Width must be at least one";
  131. if (h < 1) return "Height must be at least one";
  132. if (w > INT_MAX / h)
  133. return "Width times height must not be unreasonably large";
  134. wh = w * h;
  135. if (wh % k) return "Region size must divide grid area";
  136. if (!full) return NULL; /* succeed partial validation */
  137. /* MAYBE FIXME: we (just?) don't have the UI for winning these. */
  138. if (k == wh) return "Region size must be less than the grid area";
  139. assert (k < wh); /* or wh % k != 0 */
  140. if (k == 2 && w != 1 && h != 1)
  141. return "Region size can't be two unless width or height is one";
  142. return NULL; /* succeed full validation */
  143. }
  144. /* --- Solver ------------------------------------------------------- */
  145. /* the solver may write at will to these arrays, but shouldn't free them */
  146. /* it's up to the client to dup/free as needed */
  147. typedef struct solver_ctx {
  148. const game_params *params; /* also in shared_state */
  149. clue *clues; /* also in shared_state */
  150. borderflag *borders; /* also in game_state */
  151. DSF *dsf; /* particular to the solver */
  152. } solver_ctx;
  153. /* Deductions:
  154. *
  155. * - If two adjacent clues do not have a border between them, this
  156. * gives a lower limit on the size of their region (which is also an
  157. * upper limit if both clues are 3). Rule out any non-border which
  158. * would make its region either too large or too small.
  159. *
  160. * - If a clue, k, is adjacent to k borders or (4 - k) non-borders,
  161. * the remaining edges incident to the clue are readily decided.
  162. *
  163. * - If a region has only one other region (e.g. square) to grow into
  164. * and it's not of full size yet, grow it into that one region.
  165. *
  166. * - If two regions are adjacent and their combined size would be too
  167. * large, put an edge between them.
  168. *
  169. * - If a border is adjacent to two non-borders, its last vertex-mate
  170. * must also be a border. If a maybe-border is adjacent to three
  171. * nonborders, the maybe-border is a non-border.
  172. *
  173. * - If a clue square is adjacent to several squares belonging to the
  174. * same region, and enabling (disabling) those borders would violate
  175. * the clue, those borders must be disabled (enabled).
  176. *
  177. * - If there's a path crossing only non-borders between two squares,
  178. * the maybe-border between them is a non-border.
  179. * (This is implicitly computed in the dsf representation)
  180. */
  181. /* TODO deductions:
  182. *
  183. * If a vertex is adjacent to a LINE_YES and (4-3)*LINE_NO, at least
  184. * one of the last two edges are LINE_YES. If they're adjacent to a
  185. * 1, then the other two edges incident to that 1 are LINE_NO.
  186. *
  187. * For each square: set all as unknown, then for each k-omino and each
  188. * way of placing it on that square, if that way is consistent with
  189. * the board, mark its edges and interior as possible LINE_YES and
  190. * LINE_NO, respectively. When all k-ominos are through, see what
  191. * isn't possible and remove those impossibilities from the board.
  192. * (Sounds pretty nasty for k > 4 or so.)
  193. *
  194. * A black-bordered subregion must have a size divisible by k. So,
  195. * draw a graph with one node per dsf component and edges between
  196. * those dsf components which have adjacent squares. Identify cut
  197. * vertices and edges. If a cut-vertex-delimited component contains a
  198. * number of squares not divisible by k, cut vertex not included, then
  199. * the cut vertex must belong to the component. If it has exactly one
  200. * edge _out_ of the component, the line(s) corresponding to that edge
  201. * are all LINE_YES (i.e. a BORDER()).
  202. * (This sounds complicated, but visually it is rather easy.)
  203. *
  204. * [Look at loopy and see how the at-least/-most k out of m edges
  205. * thing is done. See how it is propagated across multiple squares.]
  206. */
  207. #define EMPTY (~0)
  208. #define BIT(i) (1 << (i))
  209. #define BORDER(i) BIT(i)
  210. #define BORDER_U BORDER(0)
  211. #define BORDER_R BORDER(1)
  212. #define BORDER_D BORDER(2)
  213. #define BORDER_L BORDER(3)
  214. #define FLIP(i) ((i) ^ 2)
  215. #define BORDER_MASK (BORDER_U|BORDER_R|BORDER_D|BORDER_L)
  216. #define DISABLED(border) ((border) << 4)
  217. #define UNDISABLED(border) ((border) >> 4)
  218. static const int dx[4] = { 0, +1, 0, -1};
  219. static const int dy[4] = {-1, 0, +1, 0};
  220. static const int bitcount[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
  221. /* bitcount[x & BORDER_MASK] == number of enabled borders */
  222. #define COMPUTE_J (-1)
  223. static void connect(solver_ctx *ctx, int i, int j)
  224. {
  225. dsf_merge(ctx->dsf, i, j);
  226. }
  227. static bool connected(solver_ctx *ctx, int i, int j, int dir)
  228. {
  229. if (j == COMPUTE_J) j = i + dx[dir] + ctx->params->w*dy[dir];
  230. return dsf_equivalent(ctx->dsf, i, j);
  231. }
  232. static void disconnect(solver_ctx *ctx, int i, int j, int dir)
  233. {
  234. if (j == COMPUTE_J) j = i + dx[dir] + ctx->params->w*dy[dir];
  235. ctx->borders[i] |= BORDER(dir);
  236. ctx->borders[j] |= BORDER(FLIP(dir));
  237. }
  238. static bool disconnected(solver_ctx *ctx, int i, int j, int dir)
  239. {
  240. assert (j == COMPUTE_J || j == i + dx[dir] + ctx->params->w*dy[dir]);
  241. return ctx->borders[i] & BORDER(dir);
  242. }
  243. static bool maybe(solver_ctx *ctx, int i, int j, int dir)
  244. {
  245. assert (j == COMPUTE_J || j == i + dx[dir] + ctx->params->w*dy[dir]);
  246. return !disconnected(ctx, i, j, dir) && !connected(ctx, i, j, dir);
  247. /* the ordering is important: disconnected works for invalid
  248. * squares (i.e. out of bounds), connected doesn't. */
  249. }
  250. static void solver_connected_clues_versus_region_size(solver_ctx *ctx)
  251. {
  252. int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir;
  253. /* If i is connected to j and i has borders with p of the
  254. * remaining three squares and j with q of the remaining three
  255. * squares, then the region has size at least 1+(3-p) + 1+(3-q).
  256. * If p = q = 3 then the region has size exactly 2. */
  257. for (i = 0; i < wh; ++i) {
  258. if (ctx->clues[i] == EMPTY) continue;
  259. for (dir = 0; dir < 4; ++dir) {
  260. int j = i + dx[dir] + w*dy[dir];
  261. if (disconnected(ctx, i, j, dir)) continue;
  262. if (ctx->clues[j] == EMPTY) continue;
  263. if ((8 - ctx->clues[i] - ctx->clues[j] > ctx->params->k) ||
  264. (ctx->clues[i] == 3 && ctx->clues[j] == 3 &&
  265. ctx->params->k != 2))
  266. {
  267. disconnect(ctx, i, j, dir);
  268. /* changed = true, but this is a one-shot... */
  269. }
  270. }
  271. }
  272. }
  273. static bool solver_number_exhausted(solver_ctx *ctx)
  274. {
  275. int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir, off;
  276. bool changed = false;
  277. for (i = 0; i < wh; ++i) {
  278. if (ctx->clues[i] == EMPTY) continue;
  279. if (bitcount[(ctx->borders[i] & BORDER_MASK)] == ctx->clues[i]) {
  280. for (dir = 0; dir < 4; ++dir) {
  281. int j = i + dx[dir] + w*dy[dir];
  282. if (!maybe(ctx, i, j, dir)) continue;
  283. connect(ctx, i, j);
  284. changed = true;
  285. }
  286. continue;
  287. }
  288. for (off = dir = 0; dir < 4; ++dir) {
  289. int j = i + dx[dir] + w*dy[dir];
  290. if (!disconnected(ctx, i, j, dir) && connected(ctx, i, j, dir))
  291. ++off; /* ^^^ bounds checking before ^^^^^ */
  292. }
  293. if (ctx->clues[i] == 4 - off)
  294. for (dir = 0; dir < 4; ++dir) {
  295. int j = i + dx[dir] + w*dy[dir];
  296. if (!maybe(ctx, i, j, dir)) continue;
  297. disconnect(ctx, i, j, dir);
  298. changed = true;
  299. }
  300. }
  301. return changed;
  302. }
  303. static bool solver_not_too_big(solver_ctx *ctx)
  304. {
  305. int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir;
  306. bool changed = false;
  307. for (i = 0; i < wh; ++i) {
  308. int size = dsf_size(ctx->dsf, i);
  309. for (dir = 0; dir < 4; ++dir) {
  310. int j = i + dx[dir] + w*dy[dir];
  311. if (!maybe(ctx, i, j, dir)) continue;
  312. if (size + dsf_size(ctx->dsf, j) <= ctx->params->k) continue;
  313. disconnect(ctx, i, j, dir);
  314. changed = true;
  315. }
  316. }
  317. return changed;
  318. }
  319. static bool solver_not_too_small(solver_ctx *ctx)
  320. {
  321. int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir;
  322. int *outs, k = ctx->params->k, ci;
  323. bool changed = false;
  324. snewa(outs, wh);
  325. setmem(outs, -1, wh);
  326. for (i = 0; i < wh; ++i) {
  327. ci = dsf_canonify(ctx->dsf, i);
  328. if (dsf_size(ctx->dsf, ci) == k) continue;
  329. for (dir = 0; dir < 4; ++dir) {
  330. int j = i + dx[dir] + w*dy[dir];
  331. if (!maybe(ctx, i, j, dir)) continue;
  332. if (outs[ci] == -1) outs[ci] = dsf_canonify(ctx->dsf, j);
  333. else if (outs[ci] != dsf_canonify(ctx->dsf, j)) outs[ci] = -2;
  334. }
  335. }
  336. for (i = 0; i < wh; ++i) {
  337. int j = outs[i];
  338. if (i != dsf_canonify(ctx->dsf, i)) continue;
  339. if (j < 0) continue;
  340. connect(ctx, i, j); /* only one place for i to grow */
  341. changed = true;
  342. }
  343. sfree(outs);
  344. return changed;
  345. }
  346. static bool solver_no_dangling_edges(solver_ctx *ctx)
  347. {
  348. int w = ctx->params->w, h = ctx->params->h, r, c;
  349. bool changed = false;
  350. /* for each vertex */
  351. for (r = 1; r < h; ++r)
  352. for (c = 1; c < w; ++c) {
  353. int i = r * w + c, j = i - w - 1, noline = 0, dir;
  354. int squares[4], e = -1, f = -1, de = -1, df = -1;
  355. /* feels hacky: I align these with BORDER_[U0 R1 D2 L3] */
  356. squares[1] = squares[2] = j;
  357. squares[0] = squares[3] = i;
  358. /* for each edge adjacent to the vertex */
  359. for (dir = 0; dir < 4; ++dir)
  360. if (!connected(ctx, squares[dir], COMPUTE_J, dir)) {
  361. df = dir;
  362. f = squares[df];
  363. if (e != -1) continue;
  364. e = f;
  365. de = df;
  366. } else ++noline;
  367. if (4 - noline == 1) {
  368. assert (e != -1);
  369. disconnect(ctx, e, COMPUTE_J, de);
  370. changed = true;
  371. continue;
  372. }
  373. if (4 - noline != 2) continue;
  374. assert (e != -1);
  375. assert (f != -1);
  376. if (ctx->borders[e] & BORDER(de)) {
  377. if (!(ctx->borders[f] & BORDER(df))) {
  378. disconnect(ctx, f, COMPUTE_J, df);
  379. changed = true;
  380. }
  381. } else if (ctx->borders[f] & BORDER(df)) {
  382. disconnect(ctx, e, COMPUTE_J, de);
  383. changed = true;
  384. }
  385. }
  386. return changed;
  387. }
  388. static bool solver_equivalent_edges(solver_ctx *ctx)
  389. {
  390. int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dirj;
  391. bool changed = false;
  392. /* if a square is adjacent to two connected squares, the two
  393. * borders (i,j) and (i,k) are either both on or both off. */
  394. for (i = 0; i < wh; ++i) {
  395. int n_on = 0, n_off = 0;
  396. if (ctx->clues[i] < 1 || ctx->clues[i] > 3) continue;
  397. if (ctx->clues[i] == 2 /* don't need it otherwise */)
  398. for (dirj = 0; dirj < 4; ++dirj) {
  399. int j = i + dx[dirj] + w*dy[dirj];
  400. if (disconnected(ctx, i, j, dirj)) ++n_on;
  401. else if (connected(ctx, i, j, dirj)) ++n_off;
  402. }
  403. for (dirj = 0; dirj < 4; ++dirj) {
  404. int j = i + dx[dirj] + w*dy[dirj], dirk;
  405. if (!maybe(ctx, i, j, dirj)) continue;
  406. for (dirk = dirj + 1; dirk < 4; ++dirk) {
  407. int k = i + dx[dirk] + w*dy[dirk];
  408. if (!maybe(ctx, i, k, dirk)) continue;
  409. if (!connected(ctx, j, k, -1)) continue;
  410. if (n_on + 2 > ctx->clues[i]) {
  411. connect(ctx, i, j);
  412. connect(ctx, i, k);
  413. changed = true;
  414. } else if (n_off + 2 > 4 - ctx->clues[i]) {
  415. disconnect(ctx, i, j, dirj);
  416. disconnect(ctx, i, k, dirk);
  417. changed = true;
  418. }
  419. }
  420. }
  421. }
  422. return changed;
  423. }
  424. /* build connected components in `dsf', along the lines of `borders'. */
  425. static void build_dsf(int w, int h, borderflag *border, DSF *dsf, bool black)
  426. {
  427. int x, y;
  428. for (y = 0; y < h; y++) {
  429. for (x = 0; x < w; x++) {
  430. if (x+1 < w && (black ? !(border[y*w+x] & BORDER_R) :
  431. (border[y*w+x] & DISABLED(BORDER_R))))
  432. dsf_merge(dsf, y*w+x, y*w+(x+1));
  433. if (y+1 < h && (black ? !(border[y*w+x] & BORDER_D) :
  434. (border[y*w+x] & DISABLED(BORDER_D))))
  435. dsf_merge(dsf, y*w+x, (y+1)*w+x);
  436. }
  437. }
  438. }
  439. static bool is_solved(const game_params *params, clue *clues,
  440. borderflag *border)
  441. {
  442. int w = params->w, h = params->h, wh = w*h, k = params->k;
  443. int i, x, y;
  444. DSF *dsf = dsf_new(wh);
  445. build_dsf(w, h, border, dsf, true);
  446. /*
  447. * A game is solved if:
  448. *
  449. * - the borders drawn on the grid divide it into connected
  450. * components such that every square is in a component of the
  451. * correct size
  452. * - the borders also satisfy the clue set
  453. */
  454. for (i = 0; i < wh; ++i) {
  455. if (dsf_size(dsf, i) != k) goto error;
  456. if (clues[i] == EMPTY) continue;
  457. if (clues[i] != bitcount[border[i] & BORDER_MASK]) goto error;
  458. }
  459. /*
  460. * ... and thirdly:
  461. *
  462. * - there are no *stray* borders, in that every border is
  463. * actually part of the division between two components.
  464. * Otherwise you could cheat by finding a subdivision which did
  465. * not *exceed* any clue square's counter, and then adding a
  466. * few extra edges.
  467. */
  468. for (y = 0; y < h; y++) {
  469. for (x = 0; x < w; x++) {
  470. if (x+1 < w && (border[y*w+x] & BORDER_R) &&
  471. dsf_equivalent(dsf, y*w+x, y*w+(x+1)))
  472. goto error;
  473. if (y+1 < h && (border[y*w+x] & BORDER_D) &&
  474. dsf_equivalent(dsf, y*w+x, (y+1)*w+x))
  475. goto error;
  476. }
  477. }
  478. dsf_free(dsf);
  479. return true;
  480. error:
  481. dsf_free(dsf);
  482. return false;
  483. }
  484. static bool solver(const game_params *params, clue *clues, borderflag *borders)
  485. {
  486. int w = params->w, h = params->h, wh = w*h;
  487. bool changed;
  488. solver_ctx ctx;
  489. ctx.params = params;
  490. ctx.clues = clues;
  491. ctx.borders = borders;
  492. ctx.dsf = dsf_new(wh);
  493. solver_connected_clues_versus_region_size(&ctx); /* idempotent */
  494. do {
  495. changed = false;
  496. changed |= solver_number_exhausted(&ctx);
  497. changed |= solver_not_too_big(&ctx);
  498. changed |= solver_not_too_small(&ctx);
  499. changed |= solver_no_dangling_edges(&ctx);
  500. changed |= solver_equivalent_edges(&ctx);
  501. } while (changed);
  502. dsf_free(ctx.dsf);
  503. return is_solved(params, clues, borders);
  504. }
  505. /* --- Generator ---------------------------------------------------- */
  506. static void init_borders(int w, int h, borderflag *borders)
  507. {
  508. int r, c;
  509. setmem(borders, 0, w*h);
  510. for (c = 0; c < w; ++c) {
  511. borders[c] |= BORDER_U;
  512. borders[w*h-1 - c] |= BORDER_D;
  513. }
  514. for (r = 0; r < h; ++r) {
  515. borders[r*w] |= BORDER_L;
  516. borders[w*h-1 - r*w] |= BORDER_R;
  517. }
  518. }
  519. #define OUT_OF_BOUNDS(x, y, w, h) \
  520. ((x) < 0 || (x) >= (w) || (y) < 0 || (y) >= (h))
  521. #define xshuffle(ptr, len, rs) shuffle((ptr), (len), sizeof (ptr)[0], (rs))
  522. static char *new_game_desc(const game_params *params, random_state *rs,
  523. char **aux, bool interactive)
  524. {
  525. int w = params->w, h = params->h, wh = w*h, k = params->k;
  526. clue *numbers = snewn(wh + 1, clue);
  527. borderflag *rim = snewn(wh, borderflag);
  528. borderflag *scratch_borders = snewn(wh, borderflag);
  529. char *soln = snewa(*aux, wh + 2);
  530. int *shuf = snewn(wh, int);
  531. DSF *dsf = NULL;
  532. int i, r, c;
  533. for (i = 0; i < wh; ++i) shuf[i] = i;
  534. xshuffle(shuf, wh, rs);
  535. init_borders(w, h, rim);
  536. assert (!('@' & BORDER_MASK));
  537. *soln++ = 'S';
  538. soln[wh] = '\0';
  539. do {
  540. setmem(soln, '@', wh);
  541. dsf_free(dsf);
  542. dsf = divvy_rectangle(w, h, k, rs);
  543. for (r = 0; r < h; ++r)
  544. for (c = 0; c < w; ++c) {
  545. int i = r * w + c, dir;
  546. numbers[i] = 0;
  547. for (dir = 0; dir < 4; ++dir) {
  548. int rr = r + dy[dir], cc = c + dx[dir], ii = rr * w + cc;
  549. if (OUT_OF_BOUNDS(cc, rr, w, h) ||
  550. !dsf_equivalent(dsf, i, ii)) {
  551. ++numbers[i];
  552. soln[i] |= BORDER(dir);
  553. }
  554. }
  555. }
  556. scopy(scratch_borders, rim, wh);
  557. } while (!solver(params, numbers, scratch_borders));
  558. for (i = 0; i < wh; ++i) {
  559. int j = shuf[i];
  560. clue copy = numbers[j];
  561. scopy(scratch_borders, rim, wh);
  562. numbers[j] = EMPTY; /* strip away unnecssary clues */
  563. if (!solver(params, numbers, scratch_borders))
  564. numbers[j] = copy;
  565. }
  566. numbers[wh] = '\0';
  567. sfree(scratch_borders);
  568. sfree(rim);
  569. sfree(shuf);
  570. dsf_free(dsf);
  571. char *output = snewn(wh + 1, char), *p = output;
  572. r = 0;
  573. for (i = 0; i < wh; ++i) {
  574. if (numbers[i] != EMPTY) {
  575. while (r) {
  576. while (r > 26) {
  577. *p++ = 'z';
  578. r -= 26;
  579. }
  580. *p++ = 'a'-1 + r;
  581. r = 0;
  582. }
  583. *p++ = '0' + numbers[i];
  584. } else ++r;
  585. }
  586. *p++ = '\0';
  587. sfree(numbers);
  588. return sresize(output, p - output, char);
  589. }
  590. static const char *validate_desc(const game_params *params, const char *desc)
  591. {
  592. int w = params->w, h = params->h, wh = w*h, squares = 0;
  593. for (/* nop */; *desc; ++desc) {
  594. if (islower((unsigned char)*desc)) {
  595. squares += *desc - 'a' + 1;
  596. } else if (isdigit((unsigned char)*desc)) {
  597. if (*desc > '4') {
  598. static char buf[] = "Invalid (too large) number: '5'";
  599. assert (isdigit((unsigned char)buf[lenof(buf) - 3]));
  600. buf[lenof(buf) - 3] = *desc; /* ... or 6, 7, 8, 9 :-) */
  601. return buf;
  602. }
  603. ++squares;
  604. } else if (isprint((unsigned char)*desc)) {
  605. static char buf[] = "Invalid character in data: '?'";
  606. buf[lenof(buf) - 3] = *desc;
  607. return buf;
  608. } else return "Invalid (unprintable) character in data";
  609. }
  610. if (squares > wh) return "Data describes too many squares";
  611. return NULL;
  612. }
  613. static game_state *new_game(midend *me, const game_params *params,
  614. const char *desc)
  615. {
  616. int w = params->w, h = params->h, wh = w*h, i;
  617. game_state *state = snew(game_state);
  618. state->shared = snew(shared_state);
  619. state->shared->refcount = 1;
  620. state->shared->params = *params; /* struct copy */
  621. snewa(state->shared->clues, wh);
  622. setmem(state->shared->clues, EMPTY, wh);
  623. for (i = 0; *desc; ++desc) {
  624. if (isdigit((unsigned char)*desc)) state->shared->clues[i++] = *desc - '0';
  625. else if (isalpha((unsigned char)*desc)) i += *desc - 'a' + 1;
  626. }
  627. snewa(state->borders, wh);
  628. init_borders(w, h, state->borders);
  629. state->completed = (params->k == wh);
  630. state->cheated = false;
  631. return state;
  632. }
  633. static game_state *dup_game(const game_state *state)
  634. {
  635. int wh = state->shared->params.w * state->shared->params.h;
  636. game_state *ret = snew(game_state);
  637. ret->borders = dupmem(state->borders, wh);
  638. ret->shared = state->shared;
  639. ++ret->shared->refcount;
  640. ret->completed = state->completed;
  641. ret->cheated = state->cheated;
  642. return ret;
  643. }
  644. static void free_game(game_state *state)
  645. {
  646. if (--state->shared->refcount == 0) {
  647. sfree(state->shared->clues);
  648. sfree(state->shared);
  649. }
  650. sfree(state->borders);
  651. sfree(state);
  652. }
  653. static char *solve_game(const game_state *state, const game_state *currstate,
  654. const char *aux, const char **error)
  655. {
  656. int w = state->shared->params.w, h = state->shared->params.h, wh = w*h;
  657. borderflag *move;
  658. if (aux) return dupstr(aux);
  659. snewa(move, wh + 2);
  660. move[0] = 'S';
  661. init_borders(w, h, move + 1);
  662. move[wh + 1] = '\0';
  663. if (solver(&state->shared->params, state->shared->clues, move + 1)) {
  664. int i;
  665. for (i = 0; i < wh; i++)
  666. move[i+1] |= '@'; /* turn into sensible ASCII */
  667. return (char *) move;
  668. }
  669. *error = "Sorry, I can't solve this puzzle";
  670. sfree(move);
  671. return NULL;
  672. {
  673. /* compile-time-assert (borderflag is-a-kind-of char).
  674. *
  675. * depends on zero-size arrays being disallowed. GCC says
  676. * ISO C forbids this, pointing to [-Werror=edantic]. Also,
  677. * it depends on type-checking of (obviously) dead code. */
  678. borderflag b[sizeof (borderflag) == sizeof (char)];
  679. char c = b[0]; b[0] = c;
  680. /* we could at least in principle put this anywhere, but it
  681. * seems silly to not put it where the assumption is used. */
  682. }
  683. }
  684. static bool game_can_format_as_text_now(const game_params *params)
  685. {
  686. return true;
  687. }
  688. static char *game_text_format(const game_state *state)
  689. {
  690. int w = state->shared->params.w, h = state->shared->params.h, r, c;
  691. int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh;
  692. char *board;
  693. setmem(snewa(board, len + 1), ' ', len);
  694. for (r = 0; r < h; ++r) {
  695. for (c = 0; c < w; ++c) {
  696. int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2;
  697. int i = r * w + c, clue = state->shared->clues[i];
  698. if (clue != EMPTY) board[center] = '0' + clue;
  699. board[cell] = '+';
  700. if (state->borders[i] & BORDER_U)
  701. setmem(board + cell + 1, '-', cw - 1);
  702. else if (state->borders[i] & DISABLED(BORDER_U))
  703. board[cell + cw / 2] = 'x';
  704. if (state->borders[i] & BORDER_L)
  705. board[cell + gw] = '|';
  706. else if (state->borders[i] & DISABLED(BORDER_L))
  707. board[cell + gw] = 'x';
  708. }
  709. for (c = 0; c < ch; ++c) {
  710. board[(r*ch + c)*gw + gw - 2] = c ? '|' : '+';
  711. board[(r*ch + c)*gw + gw - 1] = '\n';
  712. }
  713. }
  714. scopy(board + len - gw, board, gw);
  715. board[len] = '\0';
  716. return board;
  717. }
  718. struct game_ui {
  719. int x, y;
  720. bool show;
  721. };
  722. static game_ui *new_ui(const game_state *state)
  723. {
  724. game_ui *ui = snew(game_ui);
  725. ui->x = ui->y = 0;
  726. ui->show = getenv_bool("PUZZLES_SHOW_CURSOR", false);
  727. return ui;
  728. }
  729. static void free_ui(game_ui *ui)
  730. {
  731. sfree(ui);
  732. }
  733. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  734. const game_state *newstate)
  735. {
  736. }
  737. typedef unsigned short dsflags;
  738. struct game_drawstate {
  739. int tilesize;
  740. dsflags *grid;
  741. };
  742. #define TILESIZE (ds->tilesize)
  743. #define MARGIN (ds->tilesize / 2)
  744. #define WIDTH (3*TILESIZE/32 > 1 ? 3*TILESIZE/32 : 1)
  745. #define CENTER ((ds->tilesize / 2) + WIDTH/2)
  746. #define FROMCOORD(x) (((x) - MARGIN) / TILESIZE)
  747. enum {MAYBE_LEFT, MAYBE_RIGHT, ON_LEFT, ON_RIGHT, OFF_LEFT, OFF_RIGHT};
  748. static char *interpret_move(const game_state *state, game_ui *ui,
  749. const game_drawstate *ds, int x, int y, int button)
  750. {
  751. int w = state->shared->params.w, h = state->shared->params.h;
  752. bool control = button & MOD_CTRL, shift = button & MOD_SHFT;
  753. button &= ~MOD_MASK;
  754. if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
  755. int gx = FROMCOORD(x), gy = FROMCOORD(y), possible = BORDER_MASK;
  756. int px = (x - MARGIN) % TILESIZE, py = (y - MARGIN) % TILESIZE;
  757. int hx, hy, dir, i;
  758. if (OUT_OF_BOUNDS(gx, gy, w, h)) return NULL;
  759. ui->x = gx;
  760. ui->y = gy;
  761. /* find edge closest to click point */
  762. possible &=~ (2*px < TILESIZE ? BORDER_R : BORDER_L);
  763. possible &=~ (2*py < TILESIZE ? BORDER_D : BORDER_U);
  764. px = min(px, TILESIZE - px);
  765. py = min(py, TILESIZE - py);
  766. possible &=~ (px < py ? (BORDER_U|BORDER_D) : (BORDER_L|BORDER_R));
  767. for (dir = 0; dir < 4 && BORDER(dir) != possible; ++dir);
  768. if (dir == 4) return NULL; /* there's not exactly one such edge */
  769. hx = gx + dx[dir];
  770. hy = gy + dy[dir];
  771. if (OUT_OF_BOUNDS(hx, hy, w, h)) return NULL;
  772. ui->show = false;
  773. i = gy * w + gx;
  774. switch ((button == RIGHT_BUTTON) |
  775. ((state->borders[i] & BORDER(dir)) >> dir << 1) |
  776. ((state->borders[i] & DISABLED(BORDER(dir))) >> dir >> 2)) {
  777. case MAYBE_LEFT:
  778. case ON_LEFT:
  779. case ON_RIGHT:
  780. return string(80, "F%d,%d,%dF%d,%d,%d",
  781. gx, gy, BORDER(dir),
  782. hx, hy, BORDER(FLIP(dir)));
  783. case MAYBE_RIGHT:
  784. case OFF_LEFT:
  785. case OFF_RIGHT:
  786. return string(80, "F%d,%d,%dF%d,%d,%d",
  787. gx, gy, DISABLED(BORDER(dir)),
  788. hx, hy, DISABLED(BORDER(FLIP(dir))));
  789. }
  790. }
  791. if (IS_CURSOR_MOVE(button)) {
  792. ui->show = true;
  793. if (control || shift) {
  794. borderflag flag = 0, newflag;
  795. int dir, i = ui->y * w + ui->x;
  796. x = ui->x;
  797. y = ui->y;
  798. move_cursor(button, &x, &y, w, h, false);
  799. if (OUT_OF_BOUNDS(x, y, w, h)) return NULL;
  800. for (dir = 0; dir < 4; ++dir)
  801. if (dx[dir] == x - ui->x && dy[dir] == y - ui->y) break;
  802. if (dir == 4) return NULL; /* how the ... ?! */
  803. if (control) flag |= BORDER(dir);
  804. if (shift) flag |= DISABLED(BORDER(dir));
  805. newflag = state->borders[i] ^ flag;
  806. if (newflag & BORDER(dir) && newflag & DISABLED(BORDER(dir)))
  807. return NULL;
  808. newflag = 0;
  809. if (control) newflag |= BORDER(FLIP(dir));
  810. if (shift) newflag |= DISABLED(BORDER(FLIP(dir)));
  811. return string(80, "F%d,%d,%dF%d,%d,%d",
  812. ui->x, ui->y, flag, x, y, newflag);
  813. } else {
  814. move_cursor(button, &ui->x, &ui->y, w, h, false);
  815. return MOVE_UI_UPDATE;
  816. }
  817. }
  818. return NULL;
  819. }
  820. static game_state *execute_move(const game_state *state, const char *move)
  821. {
  822. int w = state->shared->params.w, h = state->shared->params.h, wh = w * h;
  823. game_state *ret = dup_game(state);
  824. int nchars, x, y, flag, i;
  825. if (*move == 'S') {
  826. ++move;
  827. for (i = 0; i < wh && move[i]; ++i)
  828. ret->borders[i] =
  829. (move[i] & BORDER_MASK) | DISABLED(~move[i] & BORDER_MASK);
  830. if (i < wh || move[i]) goto badmove;
  831. ret->cheated = ret->completed = true;
  832. return ret;
  833. }
  834. while (sscanf(move, "F%d,%d,%d%n", &x, &y, &flag, &nchars) == 3 &&
  835. !OUT_OF_BOUNDS(x, y, w, h)) {
  836. move += nchars;
  837. for (i = 0; i < 4; i++)
  838. if ((flag & BORDER(i)) &&
  839. OUT_OF_BOUNDS(x+dx[i], y+dy[i], w, h))
  840. /* No toggling the borders of the grid! */
  841. goto badmove;
  842. ret->borders[y*w + x] ^= flag;
  843. }
  844. if (*move) goto badmove;
  845. if (!ret->completed)
  846. ret->completed = is_solved(&ret->shared->params, ret->shared->clues,
  847. ret->borders);
  848. return ret;
  849. badmove:
  850. free_game(ret);
  851. return NULL;
  852. }
  853. /* --- Drawing routines --------------------------------------------- */
  854. static void game_compute_size(const game_params *params, int tilesize,
  855. const game_ui *ui, int *x, int *y)
  856. {
  857. *x = (params->w + 1) * tilesize;
  858. *y = (params->h + 1) * tilesize;
  859. }
  860. static void game_set_size(drawing *dr, game_drawstate *ds,
  861. const game_params *params, int tilesize)
  862. {
  863. ds->tilesize = tilesize;
  864. }
  865. enum {
  866. COL_BACKGROUND,
  867. COL_FLASH,
  868. COL_GRID,
  869. COL_CLUE = COL_GRID,
  870. COL_LINE_YES = COL_GRID,
  871. COL_LINE_MAYBE,
  872. COL_LINE_NO,
  873. COL_ERROR,
  874. NCOLOURS
  875. };
  876. #define COLOUR(i, r, g, b) \
  877. ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b)))
  878. #define DARKER 0.9F
  879. static float *game_colours(frontend *fe, int *ncolours)
  880. {
  881. float *ret = snewn(3 * NCOLOURS, float);
  882. game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_FLASH);
  883. COLOUR(COL_GRID, 0.0F, 0.0F, 0.0F); /* black */
  884. COLOUR(COL_ERROR, 1.0F, 0.0F, 0.0F); /* red */
  885. COLOUR(COL_LINE_MAYBE, /* yellow */
  886. ret[COL_BACKGROUND*3 + 0] * DARKER,
  887. ret[COL_BACKGROUND*3 + 1] * DARKER,
  888. 0.0F);
  889. COLOUR(COL_LINE_NO,
  890. ret[COL_BACKGROUND*3 + 0] * DARKER,
  891. ret[COL_BACKGROUND*3 + 1] * DARKER,
  892. ret[COL_BACKGROUND*3 + 2] * DARKER);
  893. *ncolours = NCOLOURS;
  894. return ret;
  895. }
  896. #undef COLOUR
  897. #define BORDER_ERROR(x) ((x) << 8)
  898. #define F_ERROR_U BORDER_ERROR(BORDER_U) /* BIT( 8) */
  899. #define F_ERROR_R BORDER_ERROR(BORDER_R) /* BIT( 9) */
  900. #define F_ERROR_D BORDER_ERROR(BORDER_D) /* BIT(10) */
  901. #define F_ERROR_L BORDER_ERROR(BORDER_L) /* BIT(11) */
  902. #define F_ERROR_CLUE BIT(12)
  903. #define F_FLASH BIT(13)
  904. #define F_CURSOR BIT(14)
  905. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  906. {
  907. struct game_drawstate *ds = snew(struct game_drawstate);
  908. ds->tilesize = 0;
  909. ds->grid = NULL;
  910. return ds;
  911. }
  912. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  913. {
  914. sfree(ds->grid);
  915. sfree(ds);
  916. }
  917. #define COLOUR(border) \
  918. (flags & BORDER_ERROR((border)) ? COL_ERROR : \
  919. flags & (border) ? COL_LINE_YES : \
  920. flags & DISABLED((border)) ? COL_LINE_NO : \
  921. COL_LINE_MAYBE)
  922. static void draw_tile(drawing *dr, game_drawstate *ds, int r, int c,
  923. dsflags flags, int clue)
  924. {
  925. int x = MARGIN + TILESIZE * c, y = MARGIN + TILESIZE * r;
  926. clip(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH); /* { */
  927. draw_rect(dr, x + WIDTH, y + WIDTH, TILESIZE - WIDTH, TILESIZE - WIDTH,
  928. (flags & F_FLASH ? COL_FLASH : COL_BACKGROUND));
  929. if (flags & F_CURSOR)
  930. draw_rect_corners(dr, x + CENTER, y + CENTER, TILESIZE / 3, COL_GRID);
  931. if (clue != EMPTY) {
  932. char buf[2];
  933. buf[0] = '0' + clue;
  934. buf[1] = '\0';
  935. draw_text(dr, x + CENTER, y + CENTER, FONT_VARIABLE,
  936. TILESIZE / 2, ALIGN_VCENTRE | ALIGN_HCENTRE,
  937. (flags & F_ERROR_CLUE ? COL_ERROR : COL_CLUE), buf);
  938. }
  939. #define ts TILESIZE
  940. #define w WIDTH
  941. draw_rect(dr, x + w, y, ts - w, w, COLOUR(BORDER_U));
  942. draw_rect(dr, x + ts, y + w, w, ts - w, COLOUR(BORDER_R));
  943. draw_rect(dr, x + w, y + ts, ts - w, w, COLOUR(BORDER_D));
  944. draw_rect(dr, x, y + w, w, ts - w, COLOUR(BORDER_L));
  945. #undef ts
  946. #undef w
  947. unclip(dr); /* } */
  948. draw_update(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH);
  949. }
  950. #define FLASH_TIME 0.7F
  951. static void game_redraw(drawing *dr, game_drawstate *ds,
  952. const game_state *oldstate, const game_state *state,
  953. int dir, const game_ui *ui,
  954. float animtime, float flashtime)
  955. {
  956. int w = state->shared->params.w, h = state->shared->params.h, wh = w*h;
  957. int r, c, flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2;
  958. DSF *black_border_dsf = dsf_new(wh), *yellow_border_dsf = dsf_new(wh);
  959. int k = state->shared->params.k;
  960. if (!ds->grid) {
  961. char buf[40];
  962. int bgw = (w+1) * ds->tilesize, bgh = (h+1) * ds->tilesize;
  963. for (r = 0; r <= h; ++r)
  964. for (c = 0; c <= w; ++c)
  965. draw_rect(dr, MARGIN + TILESIZE * c, MARGIN + TILESIZE * r,
  966. WIDTH, WIDTH, COL_GRID);
  967. draw_update(dr, 0, 0, bgw, bgh);
  968. snewa(ds->grid, wh);
  969. setmem(ds->grid, ~0, wh);
  970. sprintf(buf, "Region size: %d", state->shared->params.k);
  971. status_bar(dr, buf);
  972. }
  973. build_dsf(w, h, state->borders, black_border_dsf, true);
  974. build_dsf(w, h, state->borders, yellow_border_dsf, false);
  975. for (r = 0; r < h; ++r)
  976. for (c = 0; c < w; ++c) {
  977. int i = r * w + c, clue = state->shared->clues[i], flags, dir;
  978. int on = bitcount[state->borders[i] & BORDER_MASK];
  979. int off = bitcount[(state->borders[i] >> 4) & BORDER_MASK];
  980. flags = state->borders[i];
  981. if (flash) flags |= F_FLASH;
  982. if (clue != EMPTY && (on > clue || clue > 4 - off))
  983. flags |= F_ERROR_CLUE;
  984. if (ui->show && ui->x == c && ui->y == r)
  985. flags |= F_CURSOR;
  986. /* border errors */
  987. for (dir = 0; dir < 4; ++dir) {
  988. int rr = r + dy[dir], cc = c + dx[dir], ii = rr * w + cc;
  989. if (OUT_OF_BOUNDS(cc, rr, w, h)) continue;
  990. /* we draw each border twice, except the outermost
  991. * big border, so we have to check for errors on
  992. * both sides of each border.*/
  993. if (/* region too large */
  994. ((dsf_size(yellow_border_dsf, i) > k ||
  995. dsf_size(yellow_border_dsf, ii) > k) &&
  996. (dsf_canonify(yellow_border_dsf, i) !=
  997. dsf_canonify(yellow_border_dsf, ii)))
  998. ||
  999. /* region too small */
  1000. ((dsf_size(black_border_dsf, i) < k ||
  1001. dsf_size(black_border_dsf, ii) < k) &&
  1002. dsf_canonify(black_border_dsf, i) !=
  1003. dsf_canonify(black_border_dsf, ii))
  1004. ||
  1005. /* dangling borders within a single region */
  1006. ((state->borders[i] & BORDER(dir)) &&
  1007. /* we know it's a single region because there's a
  1008. * path crossing no border from i to ii... */
  1009. (dsf_canonify(yellow_border_dsf, i) ==
  1010. dsf_canonify(yellow_border_dsf, ii) ||
  1011. /* or because any such border would be an error */
  1012. (dsf_size(black_border_dsf, i) <= k &&
  1013. dsf_canonify(black_border_dsf, i) ==
  1014. dsf_canonify(black_border_dsf, ii)))))
  1015. flags |= BORDER_ERROR(BORDER(dir));
  1016. }
  1017. if (flags == ds->grid[i]) continue;
  1018. ds->grid[i] = flags;
  1019. draw_tile(dr, ds, r, c, ds->grid[i], clue);
  1020. }
  1021. dsf_free(black_border_dsf);
  1022. dsf_free(yellow_border_dsf);
  1023. }
  1024. static float game_anim_length(const game_state *oldstate,
  1025. const game_state *newstate,
  1026. int dir, game_ui *ui)
  1027. {
  1028. return 0.0F;
  1029. }
  1030. static float game_flash_length(const game_state *oldstate,
  1031. const game_state *newstate,
  1032. int dir, game_ui *ui)
  1033. {
  1034. if (newstate->completed && !newstate->cheated && !oldstate->completed)
  1035. return FLASH_TIME;
  1036. return 0.0F;
  1037. }
  1038. static void game_get_cursor_location(const game_ui *ui,
  1039. const game_drawstate *ds,
  1040. const game_state *state,
  1041. const game_params *params,
  1042. int *x, int *y, int *w, int *h)
  1043. {
  1044. if(ui->show) {
  1045. *x = MARGIN + TILESIZE * ui->x;
  1046. *y = MARGIN + TILESIZE * ui->y;
  1047. *w = *h = TILESIZE;
  1048. }
  1049. }
  1050. static int game_status(const game_state *state)
  1051. {
  1052. return state->completed ? +1 : 0;
  1053. }
  1054. static void game_print_size(const game_params *params, const game_ui *ui,
  1055. float *x, float *y)
  1056. {
  1057. int pw, ph;
  1058. game_compute_size(params, 700, ui, &pw, &ph); /* 7mm, like loopy */
  1059. *x = pw / 100.0F;
  1060. *y = ph / 100.0F;
  1061. }
  1062. static void print_line(drawing *dr, int x1, int y1, int x2, int y2,
  1063. int colour, bool full)
  1064. {
  1065. if (!full) {
  1066. int i, subdivisions = 8;
  1067. for (i = 1; i < subdivisions; ++i) {
  1068. int x = (x1 * (subdivisions - i) + x2 * i) / subdivisions;
  1069. int y = (y1 * (subdivisions - i) + y2 * i) / subdivisions;
  1070. draw_circle(dr, x, y, 3, colour, colour);
  1071. }
  1072. } else draw_line(dr, x1, y1, x2, y2, colour);
  1073. }
  1074. static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
  1075. int tilesize)
  1076. {
  1077. int w = state->shared->params.w, h = state->shared->params.h;
  1078. int ink = print_mono_colour(dr, 0);
  1079. game_drawstate for_tilesize_macros, *ds = &for_tilesize_macros;
  1080. int r, c;
  1081. ds->tilesize = tilesize;
  1082. for (r = 0; r < h; ++r)
  1083. for (c = 0; c < w; ++c) {
  1084. int x = MARGIN + TILESIZE * c, y = MARGIN + TILESIZE * r;
  1085. int i = r * w + c, clue = state->shared->clues[i];
  1086. if (clue != EMPTY) {
  1087. char buf[2];
  1088. buf[0] = '0' + clue;
  1089. buf[1] = '\0';
  1090. draw_text(dr, x + CENTER, y + CENTER, FONT_VARIABLE,
  1091. TILESIZE / 2, ALIGN_VCENTRE | ALIGN_HCENTRE,
  1092. ink, buf);
  1093. }
  1094. #define ts TILESIZE
  1095. #define FULL(DIR) (state->borders[i] & (BORDER_ ## DIR))
  1096. print_line(dr, x, y, x + ts, y, ink, FULL(U));
  1097. print_line(dr, x + ts, y, x + ts, y + ts, ink, FULL(R));
  1098. print_line(dr, x, y + ts, x + ts, y + ts, ink, FULL(D));
  1099. print_line(dr, x, y, x, y + ts, ink, FULL(L));
  1100. #undef ts
  1101. #undef FULL
  1102. }
  1103. for (r = 1; r < h; ++r)
  1104. for (c = 1; c < w; ++c) {
  1105. int j = r * w + c, i = j - 1 - w;
  1106. int x = MARGIN + TILESIZE * c, y = MARGIN + TILESIZE * r;
  1107. if (state->borders[i] & (BORDER_D|BORDER_R)) continue;
  1108. if (state->borders[j] & (BORDER_U|BORDER_L)) continue;
  1109. draw_circle(dr, x, y, 3, ink, ink);
  1110. }
  1111. }
  1112. #ifdef COMBINED
  1113. #define thegame palisade
  1114. #endif
  1115. const struct game thegame = {
  1116. "Palisade", "games.palisade", "palisade",
  1117. default_params,
  1118. game_fetch_preset, NULL,
  1119. decode_params,
  1120. encode_params,
  1121. free_params,
  1122. dup_params,
  1123. true, game_configure, custom_params,
  1124. validate_params,
  1125. new_game_desc,
  1126. validate_desc,
  1127. new_game,
  1128. dup_game,
  1129. free_game,
  1130. true, solve_game,
  1131. true, game_can_format_as_text_now, game_text_format,
  1132. NULL, NULL, /* get_prefs, set_prefs */
  1133. new_ui,
  1134. free_ui,
  1135. NULL, /* encode_ui */
  1136. NULL, /* decode_ui */
  1137. NULL, /* game_request_keys */
  1138. game_changed_state,
  1139. NULL, /* current_key_label */
  1140. interpret_move,
  1141. execute_move,
  1142. 48, game_compute_size, game_set_size,
  1143. game_colours,
  1144. game_new_drawstate,
  1145. game_free_drawstate,
  1146. game_redraw,
  1147. game_anim_length,
  1148. game_flash_length,
  1149. game_get_cursor_location,
  1150. game_status,
  1151. true, false, game_print_size, game_print,
  1152. true, /* wants_statusbar */
  1153. false, NULL, /* timing_state */
  1154. 0, /* flags */
  1155. };