lightup.c 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482
  1. /*
  2. * lightup.c: Implementation of the Nikoli game 'Light Up'.
  3. *
  4. * Possible future solver enhancements:
  5. *
  6. * - In a situation where two clues are diagonally adjacent, you can
  7. * deduce bounds on the number of lights shared between them. For
  8. * instance, suppose a 3 clue is diagonally adjacent to a 1 clue:
  9. * of the two squares adjacent to both clues, at least one must be
  10. * a light (or the 3 would be unsatisfiable) and yet at most one
  11. * must be a light (or the 1 would be overcommitted), so in fact
  12. * _exactly_ one must be a light, and hence the other two squares
  13. * adjacent to the 3 must also be lights and the other two adjacent
  14. * to the 1 must not. Likewise if the 3 is replaced with a 2 but
  15. * one of its other two squares is known not to be a light, and so
  16. * on.
  17. *
  18. * - In a situation where two clues are orthogonally separated (not
  19. * necessarily directly adjacent), you may be able to deduce
  20. * something about the squares that align with each other. For
  21. * instance, suppose two clues are vertically adjacent. Consider
  22. * the pair of squares A,B horizontally adjacent to the top clue,
  23. * and the pair C,D horizontally adjacent to the bottom clue.
  24. * Assuming no intervening obstacles, A and C align with each other
  25. * and hence at most one of them can be a light, and B and D
  26. * likewise, so we must have at most two lights between the four
  27. * squares. So if the clues indicate that there are at _least_ two
  28. * lights in those four squares because the top clue requires at
  29. * least one of AB to be a light and the bottom one requires at
  30. * least one of CD, then we can in fact deduce that there are
  31. * _exactly_ two lights between the four squares, and fill in the
  32. * other squares adjacent to each clue accordingly. For instance,
  33. * if both clues are 3s, then we instantly deduce that all four of
  34. * the squares _vertically_ adjacent to the two clues must be
  35. * lights. (For that to happen, of course, there'd also have to be
  36. * a black square in between the clues, so the two inner lights
  37. * don't light each other.)
  38. *
  39. * - I haven't thought it through carefully, but there's always the
  40. * possibility that both of the above deductions are special cases
  41. * of some more general pattern which can be made computationally
  42. * feasible...
  43. */
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <assert.h>
  48. #include <ctype.h>
  49. #include <limits.h>
  50. #ifdef NO_TGMATH_H
  51. # include <math.h>
  52. #else
  53. # include <tgmath.h>
  54. #endif
  55. #include "puzzles.h"
  56. /*
  57. * In standalone solver mode, `verbose' is a variable which can be
  58. * set by command-line option; in debugging mode it's simply always
  59. * true.
  60. */
  61. #if defined STANDALONE_SOLVER
  62. #define SOLVER_DIAGNOSTICS
  63. static int verbose = 0;
  64. #undef debug
  65. #define debug(x) printf x
  66. #elif defined SOLVER_DIAGNOSTICS
  67. #define verbose 2
  68. #endif
  69. /* --- Constants, structure definitions, etc. --- */
  70. #define PREFERRED_TILE_SIZE 32
  71. #define TILE_SIZE (ds->tilesize)
  72. #define BORDER (TILE_SIZE / 2)
  73. #define TILE_RADIUS (ds->crad)
  74. #define COORD(x) ( (x) * TILE_SIZE + BORDER )
  75. #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
  76. #define FLASH_TIME 0.30F
  77. enum {
  78. COL_BACKGROUND,
  79. COL_GRID,
  80. COL_BLACK, /* black */
  81. COL_LIGHT, /* white */
  82. COL_LIT, /* yellow */
  83. COL_ERROR, /* red */
  84. COL_CURSOR,
  85. NCOLOURS
  86. };
  87. enum { SYMM_NONE, SYMM_REF2, SYMM_ROT2, SYMM_REF4, SYMM_ROT4, SYMM_MAX };
  88. #define DIFFCOUNT 2
  89. struct game_params {
  90. int w, h;
  91. int blackpc; /* %age of black squares */
  92. int symm;
  93. int difficulty; /* 0 to DIFFCOUNT */
  94. };
  95. #define F_BLACK 1
  96. /* flags for black squares */
  97. #define F_NUMBERED 2 /* it has a number attached */
  98. #define F_NUMBERUSED 4 /* this number was useful for solving */
  99. /* flags for non-black squares */
  100. #define F_IMPOSSIBLE 8 /* can't put a light here */
  101. #define F_LIGHT 16
  102. #define F_MARK 32
  103. struct game_state {
  104. int w, h, nlights;
  105. int *lights; /* For black squares, (optionally) the number
  106. of surrounding lights. For non-black squares,
  107. the number of times it's lit. size h*w*/
  108. unsigned int *flags; /* size h*w */
  109. bool completed, used_solve;
  110. };
  111. #define GRID(gs,grid,x,y) (gs->grid[(y)*((gs)->w) + (x)])
  112. /* A ll_data holds information about which lights would be lit by
  113. * a particular grid location's light (or conversely, which locations
  114. * could light a specific other location). */
  115. /* most things should consider this struct opaque. */
  116. typedef struct {
  117. int ox,oy;
  118. int minx, maxx, miny, maxy;
  119. bool include_origin;
  120. } ll_data;
  121. /* Macro that executes 'block' once per light in lld, including
  122. * the origin if include_origin is specified. 'block' can use
  123. * lx and ly as the coords. */
  124. #define FOREACHLIT(lld,block) do { \
  125. int lx,ly; \
  126. ly = (lld)->oy; \
  127. for (lx = (lld)->minx; lx <= (lld)->maxx; lx++) { \
  128. if (lx == (lld)->ox) continue; \
  129. block \
  130. } \
  131. lx = (lld)->ox; \
  132. for (ly = (lld)->miny; ly <= (lld)->maxy; ly++) { \
  133. if (!(lld)->include_origin && ly == (lld)->oy) continue; \
  134. block \
  135. } \
  136. } while(0)
  137. typedef struct {
  138. struct { int x, y; unsigned int f; } points[4];
  139. int npoints;
  140. } surrounds;
  141. /* Fills in (doesn't allocate) a surrounds structure with the grid locations
  142. * around a given square, taking account of the edges. */
  143. static void get_surrounds(const game_state *state, int ox, int oy,
  144. surrounds *s)
  145. {
  146. assert(ox >= 0 && ox < state->w && oy >= 0 && oy < state->h);
  147. s->npoints = 0;
  148. #define ADDPOINT(cond,nx,ny) do {\
  149. if (cond) { \
  150. s->points[s->npoints].x = (nx); \
  151. s->points[s->npoints].y = (ny); \
  152. s->points[s->npoints].f = 0; \
  153. s->npoints++; \
  154. } } while(0)
  155. ADDPOINT(ox > 0, ox-1, oy);
  156. ADDPOINT(ox < (state->w-1), ox+1, oy);
  157. ADDPOINT(oy > 0, ox, oy-1);
  158. ADDPOINT(oy < (state->h-1), ox, oy+1);
  159. }
  160. /* --- Game parameter functions --- */
  161. #define DEFAULT_PRESET 0
  162. static const struct game_params lightup_presets[] = {
  163. { 7, 7, 20, SYMM_ROT4, 0 },
  164. { 7, 7, 20, SYMM_ROT4, 1 },
  165. { 7, 7, 20, SYMM_ROT4, 2 },
  166. { 10, 10, 20, SYMM_ROT2, 0 },
  167. { 10, 10, 20, SYMM_ROT2, 1 },
  168. #ifdef SLOW_SYSTEM
  169. { 12, 12, 20, SYMM_ROT2, 0 },
  170. { 12, 12, 20, SYMM_ROT2, 1 },
  171. #else
  172. { 10, 10, 20, SYMM_ROT2, 2 },
  173. { 14, 14, 20, SYMM_ROT2, 0 },
  174. { 14, 14, 20, SYMM_ROT2, 1 },
  175. { 14, 14, 20, SYMM_ROT2, 2 }
  176. #endif
  177. };
  178. static game_params *default_params(void)
  179. {
  180. game_params *ret = snew(game_params);
  181. *ret = lightup_presets[DEFAULT_PRESET];
  182. return ret;
  183. }
  184. static bool game_fetch_preset(int i, char **name, game_params **params)
  185. {
  186. game_params *ret;
  187. char buf[80];
  188. if (i < 0 || i >= lenof(lightup_presets))
  189. return false;
  190. ret = default_params();
  191. *ret = lightup_presets[i];
  192. *params = ret;
  193. sprintf(buf, "%dx%d %s",
  194. ret->w, ret->h,
  195. ret->difficulty == 2 ? "hard" :
  196. ret->difficulty == 1 ? "tricky" : "easy");
  197. *name = dupstr(buf);
  198. return true;
  199. }
  200. static void free_params(game_params *params)
  201. {
  202. sfree(params);
  203. }
  204. static game_params *dup_params(const game_params *params)
  205. {
  206. game_params *ret = snew(game_params);
  207. *ret = *params; /* structure copy */
  208. return ret;
  209. }
  210. #define EATNUM(x) do { \
  211. (x) = atoi(string); \
  212. while (*string && isdigit((unsigned char)*string)) string++; \
  213. } while(0)
  214. static void decode_params(game_params *params, char const *string)
  215. {
  216. EATNUM(params->w);
  217. if (*string == 'x') {
  218. string++;
  219. EATNUM(params->h);
  220. }
  221. if (*string == 'b') {
  222. string++;
  223. EATNUM(params->blackpc);
  224. }
  225. if (*string == 's') {
  226. string++;
  227. EATNUM(params->symm);
  228. } else {
  229. /* cope with user input such as '18x10' by ensuring symmetry
  230. * is not selected by default to be incompatible with dimensions */
  231. if (params->symm == SYMM_ROT4 && params->w != params->h)
  232. params->symm = SYMM_ROT2;
  233. }
  234. params->difficulty = 0;
  235. /* cope with old params */
  236. if (*string == 'r') {
  237. params->difficulty = 2;
  238. string++;
  239. }
  240. if (*string == 'd') {
  241. string++;
  242. EATNUM(params->difficulty);
  243. }
  244. }
  245. static char *encode_params(const game_params *params, bool full)
  246. {
  247. char buf[80];
  248. if (full) {
  249. sprintf(buf, "%dx%db%ds%dd%d",
  250. params->w, params->h, params->blackpc,
  251. params->symm,
  252. params->difficulty);
  253. } else {
  254. sprintf(buf, "%dx%d", params->w, params->h);
  255. }
  256. return dupstr(buf);
  257. }
  258. static config_item *game_configure(const game_params *params)
  259. {
  260. config_item *ret;
  261. char buf[80];
  262. ret = snewn(6, config_item);
  263. ret[0].name = "Width";
  264. ret[0].type = C_STRING;
  265. sprintf(buf, "%d", params->w);
  266. ret[0].u.string.sval = dupstr(buf);
  267. ret[1].name = "Height";
  268. ret[1].type = C_STRING;
  269. sprintf(buf, "%d", params->h);
  270. ret[1].u.string.sval = dupstr(buf);
  271. ret[2].name = "%age of black squares";
  272. ret[2].type = C_STRING;
  273. sprintf(buf, "%d", params->blackpc);
  274. ret[2].u.string.sval = dupstr(buf);
  275. ret[3].name = "Symmetry";
  276. ret[3].type = C_CHOICES;
  277. ret[3].u.choices.choicenames = ":None"
  278. ":2-way mirror:2-way rotational"
  279. ":4-way mirror:4-way rotational";
  280. ret[3].u.choices.selected = params->symm;
  281. ret[4].name = "Difficulty";
  282. ret[4].type = C_CHOICES;
  283. ret[4].u.choices.choicenames = ":Easy:Tricky:Hard";
  284. ret[4].u.choices.selected = params->difficulty;
  285. ret[5].name = NULL;
  286. ret[5].type = C_END;
  287. return ret;
  288. }
  289. static game_params *custom_params(const config_item *cfg)
  290. {
  291. game_params *ret = snew(game_params);
  292. ret->w = atoi(cfg[0].u.string.sval);
  293. ret->h = atoi(cfg[1].u.string.sval);
  294. ret->blackpc = atoi(cfg[2].u.string.sval);
  295. ret->symm = cfg[3].u.choices.selected;
  296. ret->difficulty = cfg[4].u.choices.selected;
  297. return ret;
  298. }
  299. static const char *validate_params(const game_params *params, bool full)
  300. {
  301. if (params->w < 2 || params->h < 2)
  302. return "Width and height must be at least 2";
  303. if (params->w > INT_MAX / params->h)
  304. return "Width times height must not be unreasonably large";
  305. if (full) {
  306. if (params->blackpc < 5 || params->blackpc > 100)
  307. return "Percentage of black squares must be between 5% and 100%";
  308. if (params->w != params->h) {
  309. if (params->symm == SYMM_ROT4)
  310. return "4-fold symmetry is only available with square grids";
  311. }
  312. if ((params->symm == SYMM_ROT4 || params->symm == SYMM_REF4) && params->w < 3 && params->h < 3)
  313. return "Width or height must be at least 3 for 4-way symmetry";
  314. if (params->symm < 0 || params->symm >= SYMM_MAX)
  315. return "Unknown symmetry type";
  316. if (params->difficulty < 0 || params->difficulty > DIFFCOUNT)
  317. return "Unknown difficulty level";
  318. }
  319. return NULL;
  320. }
  321. /* --- Game state construction/freeing helper functions --- */
  322. static game_state *new_state(const game_params *params)
  323. {
  324. game_state *ret = snew(game_state);
  325. ret->w = params->w;
  326. ret->h = params->h;
  327. ret->lights = snewn(ret->w * ret->h, int);
  328. ret->nlights = 0;
  329. memset(ret->lights, 0, ret->w * ret->h * sizeof(int));
  330. ret->flags = snewn(ret->w * ret->h, unsigned int);
  331. memset(ret->flags, 0, ret->w * ret->h * sizeof(unsigned int));
  332. ret->completed = false;
  333. ret->used_solve = false;
  334. return ret;
  335. }
  336. static game_state *dup_game(const game_state *state)
  337. {
  338. game_state *ret = snew(game_state);
  339. ret->w = state->w;
  340. ret->h = state->h;
  341. ret->lights = snewn(ret->w * ret->h, int);
  342. memcpy(ret->lights, state->lights, ret->w * ret->h * sizeof(int));
  343. ret->nlights = state->nlights;
  344. ret->flags = snewn(ret->w * ret->h, unsigned int);
  345. memcpy(ret->flags, state->flags, ret->w * ret->h * sizeof(unsigned int));
  346. ret->completed = state->completed;
  347. ret->used_solve = state->used_solve;
  348. return ret;
  349. }
  350. static void free_game(game_state *state)
  351. {
  352. sfree(state->lights);
  353. sfree(state->flags);
  354. sfree(state);
  355. }
  356. static void debug_state(game_state *state)
  357. {
  358. int x, y;
  359. char c = '?';
  360. (void)c; /* placate -Wunused-but-set-variable if debug() does nothing */
  361. for (y = 0; y < state->h; y++) {
  362. for (x = 0; x < state->w; x++) {
  363. c = '.';
  364. if (GRID(state, flags, x, y) & F_BLACK) {
  365. if (GRID(state, flags, x, y) & F_NUMBERED)
  366. c = GRID(state, lights, x, y) + '0';
  367. else
  368. c = '#';
  369. } else {
  370. if (GRID(state, flags, x, y) & F_LIGHT)
  371. c = 'O';
  372. else if (GRID(state, flags, x, y) & F_IMPOSSIBLE)
  373. c = 'X';
  374. }
  375. debug(("%c", (int)c));
  376. }
  377. debug((" "));
  378. for (x = 0; x < state->w; x++) {
  379. if (GRID(state, flags, x, y) & F_BLACK)
  380. c = '#';
  381. else {
  382. c = (GRID(state, flags, x, y) & F_LIGHT) ? 'A' : 'a';
  383. c += GRID(state, lights, x, y);
  384. }
  385. debug(("%c", (int)c));
  386. }
  387. debug(("\n"));
  388. }
  389. }
  390. /* --- Game completion test routines. --- */
  391. /* These are split up because occasionally functions are only
  392. * interested in one particular aspect. */
  393. /* Returns true if all grid spaces are lit. */
  394. static bool grid_lit(game_state *state)
  395. {
  396. int x, y;
  397. for (x = 0; x < state->w; x++) {
  398. for (y = 0; y < state->h; y++) {
  399. if (GRID(state,flags,x,y) & F_BLACK) continue;
  400. if (GRID(state,lights,x,y) == 0)
  401. return false;
  402. }
  403. }
  404. return true;
  405. }
  406. /* Returns non-zero if any lights are lit by other lights. */
  407. static bool grid_overlap(game_state *state)
  408. {
  409. int x, y;
  410. for (x = 0; x < state->w; x++) {
  411. for (y = 0; y < state->h; y++) {
  412. if (!(GRID(state, flags, x, y) & F_LIGHT)) continue;
  413. if (GRID(state, lights, x, y) > 1)
  414. return true;
  415. }
  416. }
  417. return false;
  418. }
  419. static bool number_wrong(const game_state *state, int x, int y)
  420. {
  421. surrounds s;
  422. int i, n, empty, lights = GRID(state, lights, x, y);
  423. /*
  424. * This function computes the display hint for a number: we
  425. * turn the number red if it is definitely wrong. This means
  426. * that either
  427. *
  428. * (a) it has too many lights around it, or
  429. * (b) it would have too few lights around it even if all the
  430. * plausible squares (not black, lit or F_IMPOSSIBLE) were
  431. * filled with lights.
  432. */
  433. assert(GRID(state, flags, x, y) & F_NUMBERED);
  434. get_surrounds(state, x, y, &s);
  435. empty = n = 0;
  436. for (i = 0; i < s.npoints; i++) {
  437. if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_LIGHT) {
  438. n++;
  439. continue;
  440. }
  441. if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_BLACK)
  442. continue;
  443. if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_IMPOSSIBLE)
  444. continue;
  445. if (GRID(state,lights,s.points[i].x,s.points[i].y))
  446. continue;
  447. empty++;
  448. }
  449. return (n > lights || (n + empty < lights));
  450. }
  451. static bool number_correct(game_state *state, int x, int y)
  452. {
  453. surrounds s;
  454. int n = 0, i, lights = GRID(state, lights, x, y);
  455. assert(GRID(state, flags, x, y) & F_NUMBERED);
  456. get_surrounds(state, x, y, &s);
  457. for (i = 0; i < s.npoints; i++) {
  458. if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_LIGHT)
  459. n++;
  460. }
  461. return n == lights;
  462. }
  463. /* Returns true if any numbers add up incorrectly. */
  464. static bool grid_addsup(game_state *state)
  465. {
  466. int x, y;
  467. for (x = 0; x < state->w; x++) {
  468. for (y = 0; y < state->h; y++) {
  469. if (!(GRID(state, flags, x, y) & F_NUMBERED)) continue;
  470. if (!number_correct(state, x, y)) return false;
  471. }
  472. }
  473. return true;
  474. }
  475. static bool grid_correct(game_state *state)
  476. {
  477. if (grid_lit(state) &&
  478. !grid_overlap(state) &&
  479. grid_addsup(state)) return true;
  480. return false;
  481. }
  482. /* --- Board initial setup (blacks, lights, numbers) --- */
  483. static void clean_board(game_state *state, bool leave_blacks)
  484. {
  485. int x,y;
  486. for (x = 0; x < state->w; x++) {
  487. for (y = 0; y < state->h; y++) {
  488. if (leave_blacks)
  489. GRID(state, flags, x, y) &= F_BLACK;
  490. else
  491. GRID(state, flags, x, y) = 0;
  492. GRID(state, lights, x, y) = 0;
  493. }
  494. }
  495. state->nlights = 0;
  496. }
  497. static void set_blacks(game_state *state, const game_params *params,
  498. random_state *rs)
  499. {
  500. int x, y, degree = 0, nblack;
  501. bool rotate = false;
  502. int rh, rw, i;
  503. int wodd = (state->w % 2) ? 1 : 0;
  504. int hodd = (state->h % 2) ? 1 : 0;
  505. int xs[4], ys[4];
  506. switch (params->symm) {
  507. case SYMM_NONE: degree = 1; rotate = false; break;
  508. case SYMM_ROT2: degree = 2; rotate = true; break;
  509. case SYMM_REF2: degree = 2; rotate = false; break;
  510. case SYMM_ROT4: degree = 4; rotate = true; break;
  511. case SYMM_REF4: degree = 4; rotate = false; break;
  512. default: assert(!"Unknown symmetry type");
  513. }
  514. if (params->symm == SYMM_ROT4 && (state->h != state->w))
  515. assert(!"4-fold symmetry unavailable without square grid");
  516. if (degree == 4) {
  517. rw = state->w/2;
  518. rh = state->h/2;
  519. if (!rotate) rw += wodd; /* ... but see below. */
  520. rh += hodd;
  521. } else if (degree == 2) {
  522. rw = state->w;
  523. rh = state->h/2;
  524. rh += hodd;
  525. } else {
  526. rw = state->w;
  527. rh = state->h;
  528. }
  529. /* clear, then randomise, required region. */
  530. clean_board(state, false);
  531. nblack = (rw * rh * params->blackpc) / 100;
  532. for (i = 0; i < nblack; i++) {
  533. do {
  534. x = random_upto(rs,rw);
  535. y = random_upto(rs,rh);
  536. } while (GRID(state,flags,x,y) & F_BLACK);
  537. GRID(state, flags, x, y) |= F_BLACK;
  538. }
  539. /* Copy required region. */
  540. if (params->symm == SYMM_NONE) return;
  541. for (x = 0; x < rw; x++) {
  542. for (y = 0; y < rh; y++) {
  543. if (degree == 4) {
  544. xs[0] = x;
  545. ys[0] = y;
  546. xs[1] = state->w - 1 - (rotate ? y : x);
  547. ys[1] = rotate ? x : y;
  548. xs[2] = rotate ? (state->w - 1 - x) : x;
  549. ys[2] = state->h - 1 - y;
  550. xs[3] = rotate ? y : (state->w - 1 - x);
  551. ys[3] = state->h - 1 - (rotate ? x : y);
  552. } else {
  553. xs[0] = x;
  554. ys[0] = y;
  555. xs[1] = rotate ? (state->w - 1 - x) : x;
  556. ys[1] = state->h - 1 - y;
  557. }
  558. for (i = 1; i < degree; i++) {
  559. GRID(state, flags, xs[i], ys[i]) =
  560. GRID(state, flags, xs[0], ys[0]);
  561. }
  562. }
  563. }
  564. /* SYMM_ROT4 misses the middle square above; fix that here. */
  565. if (degree == 4 && rotate && wodd &&
  566. (random_upto(rs,100) <= (unsigned int)params->blackpc))
  567. GRID(state,flags,
  568. state->w/2 + wodd - 1, state->h/2 + hodd - 1) |= F_BLACK;
  569. #ifdef SOLVER_DIAGNOSTICS
  570. if (verbose) debug_state(state);
  571. #endif
  572. }
  573. /* Fills in (does not allocate) a ll_data with all the tiles that would
  574. * be illuminated by a light at point (ox,oy). If origin is true then the
  575. * origin is included in this list. */
  576. static void list_lights(game_state *state, int ox, int oy, bool origin,
  577. ll_data *lld)
  578. {
  579. int x,y;
  580. lld->ox = lld->minx = lld->maxx = ox;
  581. lld->oy = lld->miny = lld->maxy = oy;
  582. lld->include_origin = origin;
  583. y = oy;
  584. for (x = ox-1; x >= 0; x--) {
  585. if (GRID(state, flags, x, y) & F_BLACK) break;
  586. if (x < lld->minx) lld->minx = x;
  587. }
  588. for (x = ox+1; x < state->w; x++) {
  589. if (GRID(state, flags, x, y) & F_BLACK) break;
  590. if (x > lld->maxx) lld->maxx = x;
  591. }
  592. x = ox;
  593. for (y = oy-1; y >= 0; y--) {
  594. if (GRID(state, flags, x, y) & F_BLACK) break;
  595. if (y < lld->miny) lld->miny = y;
  596. }
  597. for (y = oy+1; y < state->h; y++) {
  598. if (GRID(state, flags, x, y) & F_BLACK) break;
  599. if (y > lld->maxy) lld->maxy = y;
  600. }
  601. }
  602. /* Makes sure a light is the given state, editing the lights table to suit the
  603. * new state if necessary. */
  604. static void set_light(game_state *state, int ox, int oy, bool on)
  605. {
  606. ll_data lld;
  607. int diff = 0;
  608. assert(!(GRID(state,flags,ox,oy) & F_BLACK));
  609. if (!on && GRID(state,flags,ox,oy) & F_LIGHT) {
  610. diff = -1;
  611. GRID(state,flags,ox,oy) &= ~F_LIGHT;
  612. state->nlights--;
  613. } else if (on && !(GRID(state,flags,ox,oy) & F_LIGHT)) {
  614. diff = 1;
  615. GRID(state,flags,ox,oy) |= F_LIGHT;
  616. state->nlights++;
  617. }
  618. if (diff != 0) {
  619. list_lights(state,ox,oy,true,&lld);
  620. FOREACHLIT(&lld, GRID(state,lights,lx,ly) += diff; );
  621. }
  622. }
  623. /* Returns 1 if removing a light at (x,y) would cause a square to go dark. */
  624. static int check_dark(game_state *state, int x, int y)
  625. {
  626. ll_data lld;
  627. list_lights(state, x, y, true, &lld);
  628. FOREACHLIT(&lld, if (GRID(state,lights,lx,ly) == 1) { return 1; } );
  629. return 0;
  630. }
  631. /* Sets up an initial random correct position (i.e. every
  632. * space lit, and no lights lit by other lights) by filling the
  633. * grid with lights and then removing lights one by one at random. */
  634. static void place_lights(game_state *state, random_state *rs)
  635. {
  636. int i, x, y, n, *numindices, wh = state->w*state->h;
  637. ll_data lld;
  638. numindices = snewn(wh, int);
  639. for (i = 0; i < wh; i++) numindices[i] = i;
  640. shuffle(numindices, wh, sizeof(*numindices), rs);
  641. /* Place a light on all grid squares without lights. */
  642. for (x = 0; x < state->w; x++) {
  643. for (y = 0; y < state->h; y++) {
  644. GRID(state, flags, x, y) &= ~F_MARK; /* we use this later. */
  645. if (GRID(state, flags, x, y) & F_BLACK) continue;
  646. set_light(state, x, y, true);
  647. }
  648. }
  649. for (i = 0; i < wh; i++) {
  650. y = numindices[i] / state->w;
  651. x = numindices[i] % state->w;
  652. if (!(GRID(state, flags, x, y) & F_LIGHT)) continue;
  653. if (GRID(state, flags, x, y) & F_MARK) continue;
  654. list_lights(state, x, y, false, &lld);
  655. /* If we're not lighting any lights ourself, don't remove anything. */
  656. n = 0;
  657. FOREACHLIT(&lld, if (GRID(state,flags,lx,ly) & F_LIGHT) { n += 1; } );
  658. if (n == 0) continue; /* [1] */
  659. /* Check whether removing lights we're lighting would cause anything
  660. * to go dark. */
  661. n = 0;
  662. FOREACHLIT(&lld, if (GRID(state,flags,lx,ly) & F_LIGHT) { n += check_dark(state,lx,ly); } );
  663. if (n == 0) {
  664. /* No, it wouldn't, so we can remove them all. */
  665. FOREACHLIT(&lld, set_light(state,lx,ly, false); );
  666. GRID(state,flags,x,y) |= F_MARK;
  667. }
  668. if (!grid_overlap(state)) {
  669. sfree(numindices);
  670. return; /* we're done. */
  671. }
  672. assert(grid_lit(state));
  673. }
  674. /* could get here if the line at [1] continue'd out of the loop. */
  675. if (grid_overlap(state)) {
  676. debug_state(state);
  677. assert(!"place_lights failed to resolve overlapping lights!");
  678. }
  679. sfree(numindices);
  680. }
  681. /* Fills in all black squares with numbers of adjacent lights. */
  682. static void place_numbers(game_state *state)
  683. {
  684. int x, y, i, n;
  685. surrounds s;
  686. for (x = 0; x < state->w; x++) {
  687. for (y = 0; y < state->h; y++) {
  688. if (!(GRID(state,flags,x,y) & F_BLACK)) continue;
  689. get_surrounds(state, x, y, &s);
  690. n = 0;
  691. for (i = 0; i < s.npoints; i++) {
  692. if (GRID(state,flags,s.points[i].x, s.points[i].y) & F_LIGHT)
  693. n++;
  694. }
  695. GRID(state,flags,x,y) |= F_NUMBERED;
  696. GRID(state,lights,x,y) = n;
  697. }
  698. }
  699. }
  700. /* --- Actual solver, with helper subroutines. --- */
  701. static void tsl_callback(game_state *state,
  702. int lx, int ly, int *x, int *y, int *n)
  703. {
  704. if (GRID(state,flags,lx,ly) & F_IMPOSSIBLE) return;
  705. if (GRID(state,lights,lx,ly) > 0) return;
  706. *x = lx; *y = ly; (*n)++;
  707. }
  708. static bool try_solve_light(game_state *state, int ox, int oy,
  709. unsigned int flags, int lights)
  710. {
  711. ll_data lld;
  712. int sx = 0, sy = 0, n = 0;
  713. if (lights > 0) return false;
  714. if (flags & F_BLACK) return false;
  715. /* We have an unlit square; count how many ways there are left to
  716. * place a light that lights us (including this square); if only
  717. * one, we must put a light there. Squares that could light us
  718. * are, of course, the same as the squares we would light... */
  719. list_lights(state, ox, oy, true, &lld);
  720. FOREACHLIT(&lld, { tsl_callback(state, lx, ly, &sx, &sy, &n); });
  721. if (n == 1) {
  722. set_light(state, sx, sy, true);
  723. #ifdef SOLVER_DIAGNOSTICS
  724. debug(("(%d,%d) can only be lit from (%d,%d); setting to LIGHT\n",
  725. ox,oy,sx,sy));
  726. if (verbose) debug_state(state);
  727. #endif
  728. return true;
  729. }
  730. return false;
  731. }
  732. static bool could_place_light(unsigned int flags, int lights)
  733. {
  734. if (flags & (F_BLACK | F_IMPOSSIBLE)) return false;
  735. return !(lights > 0);
  736. }
  737. static bool could_place_light_xy(game_state *state, int x, int y)
  738. {
  739. int lights = GRID(state,lights,x,y);
  740. unsigned int flags = GRID(state,flags,x,y);
  741. return could_place_light(flags, lights);
  742. }
  743. /* For a given number square, determine whether we have enough info
  744. * to unambiguously place its lights. */
  745. static bool try_solve_number(game_state *state, int nx, int ny,
  746. unsigned int nflags, int nlights)
  747. {
  748. surrounds s;
  749. int x, y, nl, ns, i, lights;
  750. bool ret = false;
  751. unsigned int flags;
  752. if (!(nflags & F_NUMBERED)) return false;
  753. nl = nlights;
  754. get_surrounds(state,nx,ny,&s);
  755. ns = s.npoints;
  756. /* nl is no. of lights we need to place, ns is no. of spaces we
  757. * have to place them in. Try and narrow these down, and mark
  758. * points we can ignore later. */
  759. for (i = 0; i < s.npoints; i++) {
  760. x = s.points[i].x; y = s.points[i].y;
  761. flags = GRID(state,flags,x,y);
  762. lights = GRID(state,lights,x,y);
  763. if (flags & F_LIGHT) {
  764. /* light here already; one less light for one less place. */
  765. nl--; ns--;
  766. s.points[i].f |= F_MARK;
  767. } else if (!could_place_light(flags, lights)) {
  768. ns--;
  769. s.points[i].f |= F_MARK;
  770. }
  771. }
  772. if (ns == 0) return false; /* nowhere to put anything. */
  773. if (nl == 0) {
  774. /* we have placed all lights we need to around here; all remaining
  775. * surrounds are therefore IMPOSSIBLE. */
  776. GRID(state,flags,nx,ny) |= F_NUMBERUSED;
  777. for (i = 0; i < s.npoints; i++) {
  778. if (!(s.points[i].f & F_MARK)) {
  779. GRID(state,flags,s.points[i].x,s.points[i].y) |= F_IMPOSSIBLE;
  780. ret = true;
  781. }
  782. }
  783. #ifdef SOLVER_DIAGNOSTICS
  784. printf("Clue at (%d,%d) full; setting unlit to IMPOSSIBLE.\n",
  785. nx,ny);
  786. if (verbose) debug_state(state);
  787. #endif
  788. } else if (nl == ns) {
  789. /* we have as many lights to place as spaces; fill them all. */
  790. GRID(state,flags,nx,ny) |= F_NUMBERUSED;
  791. for (i = 0; i < s.npoints; i++) {
  792. if (!(s.points[i].f & F_MARK)) {
  793. set_light(state, s.points[i].x,s.points[i].y, true);
  794. ret = true;
  795. }
  796. }
  797. #ifdef SOLVER_DIAGNOSTICS
  798. printf("Clue at (%d,%d) trivial; setting unlit to LIGHT.\n",
  799. nx,ny);
  800. if (verbose) debug_state(state);
  801. #endif
  802. }
  803. return ret;
  804. }
  805. struct setscratch {
  806. int x, y;
  807. int n;
  808. };
  809. #define SCRATCHSZ (state->w+state->h)
  810. /* New solver algorithm: overlapping sets can add IMPOSSIBLE flags.
  811. * Algorithm thanks to Simon:
  812. *
  813. * (a) Any square where you can place a light has a set of squares
  814. * which would become non-lights as a result. (This includes
  815. * squares lit by the first square, and can also include squares
  816. * adjacent to the same clue square if the new light is the last
  817. * one around that clue.) Call this MAKESDARK(x,y) with (x,y) being
  818. * the square you place a light.
  819. * (b) Any unlit square has a set of squares on which you could place
  820. * a light to illuminate it. (Possibly including itself, of
  821. * course.) This set of squares has the property that _at least
  822. * one_ of them must contain a light. Sets of this type also arise
  823. * from clue squares. Call this MAKESLIGHT(x,y), again with (x,y)
  824. * the square you would place a light.
  825. * (c) If there exists (dx,dy) and (lx,ly) such that MAKESDARK(dx,dy) is
  826. * a superset of MAKESLIGHT(lx,ly), this implies that placing a light at
  827. * (dx,dy) would either leave no remaining way to illuminate a certain
  828. * square, or would leave no remaining way to fulfill a certain clue
  829. * (at lx,ly). In either case, a light can be ruled out at that position.
  830. *
  831. * So, we construct all possible MAKESLIGHT sets, both from unlit squares
  832. * and clue squares, and then we look for plausible MAKESDARK sets that include
  833. * our (lx,ly) to see if we can find a (dx,dy) to rule out. By the time we have
  834. * constructed the MAKESLIGHT set we don't care about (lx,ly), just the set
  835. * members.
  836. *
  837. * Once we have such a set, Simon came up with a Cunning Plan to find
  838. * the most sensible MAKESDARK candidate:
  839. *
  840. * (a) for each square S in your set X, find all the squares which _would_
  841. * rule it out. That means any square which would light S, plus
  842. * any square adjacent to the same clue square as S (provided
  843. * that clue square has only one remaining light to be placed).
  844. * It's not hard to make this list. Don't do anything with this
  845. * data at the moment except _count_ the squares.
  846. * (b) Find the square S_min in the original set which has the
  847. * _smallest_ number of other squares which would rule it out.
  848. * (c) Find all the squares that rule out S_min (it's probably
  849. * better to recompute this than to have stored it during step
  850. * (a), since the CPU requirement is modest but the storage
  851. * cost would get ugly.) For each of these squares, see if it
  852. * rules out everything else in the set X. Any which does can
  853. * be marked as not-a-light.
  854. *
  855. */
  856. typedef void (*trl_cb)(game_state *state, int dx, int dy,
  857. struct setscratch *scratch, int n, void *ctx);
  858. static void try_rule_out(game_state *state, int x, int y,
  859. struct setscratch *scratch, int n,
  860. trl_cb cb, void *ctx);
  861. static void trl_callback_search(game_state *state, int dx, int dy,
  862. struct setscratch *scratch, int n, void *ignored)
  863. {
  864. int i;
  865. #ifdef SOLVER_DIAGNOSTICS
  866. if (verbose) debug(("discount cb: light at (%d,%d)\n", dx, dy));
  867. #endif
  868. for (i = 0; i < n; i++) {
  869. if (dx == scratch[i].x && dy == scratch[i].y) {
  870. scratch[i].n = 1;
  871. return;
  872. }
  873. }
  874. }
  875. static void trl_callback_discount(game_state *state, int dx, int dy,
  876. struct setscratch *scratch, int n, void *ctx)
  877. {
  878. bool *didsth = (bool *)ctx;
  879. int i;
  880. if (GRID(state,flags,dx,dy) & F_IMPOSSIBLE) {
  881. #ifdef SOLVER_DIAGNOSTICS
  882. debug(("Square at (%d,%d) already impossible.\n", dx,dy));
  883. #endif
  884. return;
  885. }
  886. /* Check whether a light at (dx,dy) rules out everything
  887. * in scratch, and mark (dx,dy) as IMPOSSIBLE if it does.
  888. * We can use try_rule_out for this as well, as the set of
  889. * squares which would rule out (x,y) is the same as the
  890. * set of squares which (x,y) would rule out. */
  891. #ifdef SOLVER_DIAGNOSTICS
  892. if (verbose) debug(("Checking whether light at (%d,%d) rules out everything in scratch.\n", dx, dy));
  893. #endif
  894. for (i = 0; i < n; i++)
  895. scratch[i].n = 0;
  896. try_rule_out(state, dx, dy, scratch, n, trl_callback_search, NULL);
  897. for (i = 0; i < n; i++) {
  898. if (scratch[i].n == 0) return;
  899. }
  900. /* The light ruled out everything in scratch. Yay. */
  901. GRID(state,flags,dx,dy) |= F_IMPOSSIBLE;
  902. #ifdef SOLVER_DIAGNOSTICS
  903. debug(("Set reduction discounted square at (%d,%d):\n", dx,dy));
  904. if (verbose) debug_state(state);
  905. #endif
  906. *didsth = true;
  907. }
  908. static void trl_callback_incn(game_state *state, int dx, int dy,
  909. struct setscratch *scratch, int n, void *ctx)
  910. {
  911. struct setscratch *s = (struct setscratch *)ctx;
  912. s->n++;
  913. }
  914. static void try_rule_out(game_state *state, int x, int y,
  915. struct setscratch *scratch, int n,
  916. trl_cb cb, void *ctx)
  917. {
  918. /* XXX Find all the squares which would rule out (x,y); anything
  919. * that would light it as well as squares adjacent to same clues
  920. * as X assuming that clue only has one remaining light.
  921. * Call the callback with each square. */
  922. ll_data lld;
  923. surrounds s, ss;
  924. int i, j, curr_lights, tot_lights;
  925. /* Find all squares that would rule out a light at (x,y) and call trl_cb
  926. * with them: anything that would light (x,y)... */
  927. list_lights(state, x, y, false, &lld);
  928. FOREACHLIT(&lld, { if (could_place_light_xy(state, lx, ly)) { cb(state, lx, ly, scratch, n, ctx); } });
  929. /* ... as well as any empty space (that isn't x,y) next to any clue square
  930. * next to (x,y) that only has one light left to place. */
  931. get_surrounds(state, x, y, &s);
  932. for (i = 0; i < s.npoints; i++) {
  933. if (!(GRID(state,flags,s.points[i].x,s.points[i].y) & F_NUMBERED))
  934. continue;
  935. /* we have an adjacent clue square; find /its/ surrounds
  936. * and count the remaining lights it needs. */
  937. get_surrounds(state,s.points[i].x,s.points[i].y,&ss);
  938. curr_lights = 0;
  939. for (j = 0; j < ss.npoints; j++) {
  940. if (GRID(state,flags,ss.points[j].x,ss.points[j].y) & F_LIGHT)
  941. curr_lights++;
  942. }
  943. tot_lights = GRID(state, lights, s.points[i].x, s.points[i].y);
  944. /* We have a clue with tot_lights to fill, and curr_lights currently
  945. * around it. If adding a light at (x,y) fills up the clue (i.e.
  946. * curr_lights + 1 = tot_lights) then we need to discount all other
  947. * unlit squares around the clue. */
  948. if ((curr_lights + 1) == tot_lights) {
  949. for (j = 0; j < ss.npoints; j++) {
  950. int lx = ss.points[j].x, ly = ss.points[j].y;
  951. if (lx == x && ly == y) continue;
  952. if (could_place_light_xy(state, lx, ly))
  953. cb(state, lx, ly, scratch, n, ctx);
  954. }
  955. }
  956. }
  957. }
  958. #ifdef SOLVER_DIAGNOSTICS
  959. static void debug_scratch(const char *msg, struct setscratch *scratch, int n)
  960. {
  961. int i;
  962. debug(("%s scratch (%d elements):\n", msg, n));
  963. for (i = 0; i < n; i++) {
  964. debug((" (%d,%d) n%d\n", scratch[i].x, scratch[i].y, scratch[i].n));
  965. }
  966. }
  967. #endif
  968. static bool discount_set(game_state *state,
  969. struct setscratch *scratch, int n)
  970. {
  971. int i, besti, bestn;
  972. bool didsth = false;
  973. #ifdef SOLVER_DIAGNOSTICS
  974. if (verbose > 1) debug_scratch("discount_set", scratch, n);
  975. #endif
  976. if (n == 0) return false;
  977. for (i = 0; i < n; i++) {
  978. try_rule_out(state, scratch[i].x, scratch[i].y, scratch, n,
  979. trl_callback_incn, (void*)&(scratch[i]));
  980. }
  981. #ifdef SOLVER_DIAGNOSTICS
  982. if (verbose > 1) debug_scratch("discount_set after count", scratch, n);
  983. #endif
  984. besti = -1; bestn = SCRATCHSZ;
  985. for (i = 0; i < n; i++) {
  986. if (scratch[i].n < bestn) {
  987. bestn = scratch[i].n;
  988. besti = i;
  989. }
  990. }
  991. #ifdef SOLVER_DIAGNOSTICS
  992. if (verbose > 1) debug(("best square (%d,%d) with n%d.\n",
  993. scratch[besti].x, scratch[besti].y, scratch[besti].n));
  994. #endif
  995. try_rule_out(state, scratch[besti].x, scratch[besti].y, scratch, n,
  996. trl_callback_discount, (void*)&didsth);
  997. #ifdef SOLVER_DIAGNOSTICS
  998. if (didsth) debug((" [from square (%d,%d)]\n",
  999. scratch[besti].x, scratch[besti].y));
  1000. #endif
  1001. return didsth;
  1002. }
  1003. static void discount_clear(game_state *state, struct setscratch *scratch, int *n)
  1004. {
  1005. *n = 0;
  1006. memset(scratch, 0, SCRATCHSZ * sizeof(struct setscratch));
  1007. }
  1008. static void unlit_cb(game_state *state, int lx, int ly,
  1009. struct setscratch *scratch, int *n)
  1010. {
  1011. if (could_place_light_xy(state, lx, ly)) {
  1012. scratch[*n].x = lx; scratch[*n].y = ly; (*n)++;
  1013. }
  1014. }
  1015. /* Construct a MAKESLIGHT set from an unlit square. */
  1016. static bool discount_unlit(game_state *state, int x, int y,
  1017. struct setscratch *scratch)
  1018. {
  1019. ll_data lld;
  1020. int n;
  1021. bool didsth;
  1022. #ifdef SOLVER_DIAGNOSTICS
  1023. if (verbose) debug(("Trying to discount for unlit square at (%d,%d).\n", x, y));
  1024. if (verbose > 1) debug_state(state);
  1025. #endif
  1026. discount_clear(state, scratch, &n);
  1027. list_lights(state, x, y, true, &lld);
  1028. FOREACHLIT(&lld, { unlit_cb(state, lx, ly, scratch, &n); });
  1029. didsth = discount_set(state, scratch, n);
  1030. #ifdef SOLVER_DIAGNOSTICS
  1031. if (didsth) debug((" [from unlit square at (%d,%d)].\n", x, y));
  1032. #endif
  1033. return didsth;
  1034. }
  1035. /* Construct a series of MAKESLIGHT sets from a clue square.
  1036. * for a clue square with N remaining spaces that must contain M lights, every
  1037. * subset of size N-M+1 of those N spaces forms such a set.
  1038. */
  1039. static bool discount_clue(game_state *state, int x, int y,
  1040. struct setscratch *scratch)
  1041. {
  1042. int slen, m = GRID(state, lights, x, y), n, i, lights;
  1043. bool didsth = false;
  1044. unsigned int flags;
  1045. surrounds s, sempty;
  1046. combi_ctx *combi;
  1047. if (m == 0) return false;
  1048. #ifdef SOLVER_DIAGNOSTICS
  1049. if (verbose) debug(("Trying to discount for sets at clue (%d,%d).\n", x, y));
  1050. if (verbose > 1) debug_state(state);
  1051. #endif
  1052. /* m is no. of lights still to place; starts off at the clue value
  1053. * and decreases when we find a light already down.
  1054. * n is no. of spaces left; starts off at 0 and goes up when we find
  1055. * a plausible space. */
  1056. get_surrounds(state, x, y, &s);
  1057. memset(&sempty, 0, sizeof(surrounds));
  1058. for (i = 0; i < s.npoints; i++) {
  1059. int lx = s.points[i].x, ly = s.points[i].y;
  1060. flags = GRID(state,flags,lx,ly);
  1061. lights = GRID(state,lights,lx,ly);
  1062. if (flags & F_LIGHT) m--;
  1063. if (could_place_light(flags, lights)) {
  1064. sempty.points[sempty.npoints].x = lx;
  1065. sempty.points[sempty.npoints].y = ly;
  1066. sempty.npoints++;
  1067. }
  1068. }
  1069. n = sempty.npoints; /* sempty is now a surrounds of only blank squares. */
  1070. if (n == 0) return false; /* clue is full already. */
  1071. if (m < 0 || m > n) return false; /* become impossible. */
  1072. combi = new_combi(n - m + 1, n);
  1073. while (next_combi(combi)) {
  1074. discount_clear(state, scratch, &slen);
  1075. for (i = 0; i < combi->r; i++) {
  1076. scratch[slen].x = sempty.points[combi->a[i]].x;
  1077. scratch[slen].y = sempty.points[combi->a[i]].y;
  1078. slen++;
  1079. }
  1080. if (discount_set(state, scratch, slen)) didsth = true;
  1081. }
  1082. free_combi(combi);
  1083. #ifdef SOLVER_DIAGNOSTICS
  1084. if (didsth) debug((" [from clue at (%d,%d)].\n", x, y));
  1085. #endif
  1086. return didsth;
  1087. }
  1088. #define F_SOLVE_FORCEUNIQUE 1
  1089. #define F_SOLVE_DISCOUNTSETS 2
  1090. #define F_SOLVE_ALLOWRECURSE 4
  1091. static unsigned int flags_from_difficulty(int difficulty)
  1092. {
  1093. unsigned int sflags = F_SOLVE_FORCEUNIQUE;
  1094. assert(difficulty <= DIFFCOUNT);
  1095. if (difficulty >= 1) sflags |= F_SOLVE_DISCOUNTSETS;
  1096. if (difficulty >= 2) sflags |= F_SOLVE_ALLOWRECURSE;
  1097. return sflags;
  1098. }
  1099. #define MAXRECURSE 5
  1100. static int solve_sub(game_state *state,
  1101. unsigned int solve_flags, int depth,
  1102. int *maxdepth)
  1103. {
  1104. unsigned int flags;
  1105. int x, y, ncanplace, lights;
  1106. bool didstuff;
  1107. int bestx, besty, n, bestn, copy_soluble, self_soluble, ret, maxrecurse = 0;
  1108. game_state *scopy;
  1109. ll_data lld;
  1110. struct setscratch *sscratch = NULL;
  1111. #ifdef SOLVER_DIAGNOSTICS
  1112. printf("solve_sub: depth = %d\n", depth);
  1113. #endif
  1114. if (maxdepth && *maxdepth < depth) *maxdepth = depth;
  1115. if (solve_flags & F_SOLVE_ALLOWRECURSE) maxrecurse = MAXRECURSE;
  1116. while (1) {
  1117. if (grid_overlap(state)) {
  1118. /* Our own solver, from scratch, should never cause this to happen
  1119. * (assuming a soluble grid). However, if we're trying to solve
  1120. * from a half-completed *incorrect* grid this might occur; we
  1121. * just return the 'no solutions' code in this case. */
  1122. ret = 0; goto done;
  1123. }
  1124. if (grid_correct(state)) { ret = 1; goto done; }
  1125. ncanplace = 0;
  1126. didstuff = false;
  1127. /* These 2 loops, and the functions they call, are the critical loops
  1128. * for timing; any optimisations should look here first. */
  1129. for (x = 0; x < state->w; x++) {
  1130. for (y = 0; y < state->h; y++) {
  1131. flags = GRID(state,flags,x,y);
  1132. lights = GRID(state,lights,x,y);
  1133. ncanplace += could_place_light(flags, lights);
  1134. if (try_solve_light(state, x, y, flags, lights))
  1135. didstuff = true;
  1136. if (try_solve_number(state, x, y, flags, lights))
  1137. didstuff = true;
  1138. }
  1139. }
  1140. if (didstuff) continue;
  1141. if (!ncanplace) {
  1142. /* nowhere to put a light, puzzle is unsoluble. */
  1143. ret = 0; goto done;
  1144. }
  1145. if (solve_flags & F_SOLVE_DISCOUNTSETS) {
  1146. if (!sscratch) sscratch = snewn(SCRATCHSZ, struct setscratch);
  1147. /* Try a more cunning (and more involved) way... more details above. */
  1148. for (x = 0; x < state->w; x++) {
  1149. for (y = 0; y < state->h; y++) {
  1150. flags = GRID(state,flags,x,y);
  1151. lights = GRID(state,lights,x,y);
  1152. if (!(flags & F_BLACK) && lights == 0) {
  1153. if (discount_unlit(state, x, y, sscratch)) {
  1154. didstuff = true;
  1155. goto reduction_success;
  1156. }
  1157. } else if (flags & F_NUMBERED) {
  1158. if (discount_clue(state, x, y, sscratch)) {
  1159. didstuff = true;
  1160. goto reduction_success;
  1161. }
  1162. }
  1163. }
  1164. }
  1165. }
  1166. reduction_success:
  1167. if (didstuff) continue;
  1168. /* We now have to make a guess; we have places to put lights but
  1169. * no definite idea about where they can go. */
  1170. if (depth >= maxrecurse) {
  1171. /* mustn't delve any deeper. */
  1172. ret = -1; goto done;
  1173. }
  1174. /* Of all the squares that we could place a light, pick the one
  1175. * that would light the most currently unlit squares. */
  1176. /* This heuristic was just plucked from the air; there may well be
  1177. * a more efficient way of choosing a square to flip to minimise
  1178. * recursion. */
  1179. bestn = 0;
  1180. bestx = besty = -1; /* suyb */
  1181. for (x = 0; x < state->w; x++) {
  1182. for (y = 0; y < state->h; y++) {
  1183. flags = GRID(state,flags,x,y);
  1184. lights = GRID(state,lights,x,y);
  1185. if (!could_place_light(flags, lights)) continue;
  1186. n = 0;
  1187. list_lights(state, x, y, true, &lld);
  1188. FOREACHLIT(&lld, { if (GRID(state,lights,lx,ly) == 0) n++; });
  1189. if (n > bestn) {
  1190. bestn = n; bestx = x; besty = y;
  1191. }
  1192. }
  1193. }
  1194. assert(bestn > 0);
  1195. assert(bestx >= 0 && besty >= 0);
  1196. /* Now we've chosen a plausible (x,y), try to solve it once as 'lit'
  1197. * and once as 'impossible'; we need to make one copy to do this. */
  1198. scopy = dup_game(state);
  1199. #ifdef SOLVER_DIAGNOSTICS
  1200. debug(("Recursing #1: trying (%d,%d) as IMPOSSIBLE\n", bestx, besty));
  1201. #endif
  1202. GRID(state,flags,bestx,besty) |= F_IMPOSSIBLE;
  1203. self_soluble = solve_sub(state, solve_flags, depth+1, maxdepth);
  1204. if (!(solve_flags & F_SOLVE_FORCEUNIQUE) && self_soluble > 0) {
  1205. /* we didn't care about finding all solutions, and we just
  1206. * found one; return with it immediately. */
  1207. free_game(scopy);
  1208. ret = self_soluble;
  1209. goto done;
  1210. }
  1211. #ifdef SOLVER_DIAGNOSTICS
  1212. debug(("Recursing #2: trying (%d,%d) as LIGHT\n", bestx, besty));
  1213. #endif
  1214. set_light(scopy, bestx, besty, true);
  1215. copy_soluble = solve_sub(scopy, solve_flags, depth+1, maxdepth);
  1216. /* If we wanted a unique solution but we hit our recursion limit
  1217. * (on either branch) then we have to assume we didn't find possible
  1218. * extra solutions, and return 'not soluble'. */
  1219. if ((solve_flags & F_SOLVE_FORCEUNIQUE) &&
  1220. ((copy_soluble < 0) || (self_soluble < 0))) {
  1221. ret = -1;
  1222. /* Make sure that whether or not it was self or copy (or both) that
  1223. * were soluble, that we return a solved state in self. */
  1224. } else if (copy_soluble <= 0) {
  1225. /* copy wasn't soluble; keep self state and return that result. */
  1226. ret = self_soluble;
  1227. } else if (self_soluble <= 0) {
  1228. /* copy solved and we didn't, so copy in copy's (now solved)
  1229. * flags and light state. */
  1230. memcpy(state->lights, scopy->lights,
  1231. scopy->w * scopy->h * sizeof(int));
  1232. memcpy(state->flags, scopy->flags,
  1233. scopy->w * scopy->h * sizeof(unsigned int));
  1234. ret = copy_soluble;
  1235. } else {
  1236. ret = copy_soluble + self_soluble;
  1237. }
  1238. free_game(scopy);
  1239. goto done;
  1240. }
  1241. done:
  1242. if (sscratch) sfree(sscratch);
  1243. #ifdef SOLVER_DIAGNOSTICS
  1244. if (ret < 0)
  1245. debug(("solve_sub: depth = %d returning, ran out of recursion.\n",
  1246. depth));
  1247. else
  1248. debug(("solve_sub: depth = %d returning, %d solutions.\n",
  1249. depth, ret));
  1250. #endif
  1251. return ret;
  1252. }
  1253. /* Fills in the (possibly partially-complete) game_state as far as it can,
  1254. * returning the number of possible solutions. If it returns >0 then the
  1255. * game_state will be in a solved state, but you won't know which one. */
  1256. static int dosolve(game_state *state, int solve_flags, int *maxdepth)
  1257. {
  1258. int x, y, nsol;
  1259. for (x = 0; x < state->w; x++) {
  1260. for (y = 0; y < state->h; y++) {
  1261. GRID(state,flags,x,y) &= ~F_NUMBERUSED;
  1262. }
  1263. }
  1264. nsol = solve_sub(state, solve_flags, 0, maxdepth);
  1265. return nsol;
  1266. }
  1267. static int strip_unused_nums(game_state *state)
  1268. {
  1269. int x,y,n=0;
  1270. for (x = 0; x < state->w; x++) {
  1271. for (y = 0; y < state->h; y++) {
  1272. if ((GRID(state,flags,x,y) & F_NUMBERED) &&
  1273. !(GRID(state,flags,x,y) & F_NUMBERUSED)) {
  1274. GRID(state,flags,x,y) &= ~F_NUMBERED;
  1275. GRID(state,lights,x,y) = 0;
  1276. n++;
  1277. }
  1278. }
  1279. }
  1280. debug(("Stripped %d unused numbers.\n", n));
  1281. return n;
  1282. }
  1283. static void unplace_lights(game_state *state)
  1284. {
  1285. int x,y;
  1286. for (x = 0; x < state->w; x++) {
  1287. for (y = 0; y < state->h; y++) {
  1288. if (GRID(state,flags,x,y) & F_LIGHT)
  1289. set_light(state,x,y,false);
  1290. GRID(state,flags,x,y) &= ~F_IMPOSSIBLE;
  1291. GRID(state,flags,x,y) &= ~F_NUMBERUSED;
  1292. }
  1293. }
  1294. }
  1295. static bool puzzle_is_good(game_state *state, int difficulty)
  1296. {
  1297. int nsol, mdepth = 0;
  1298. unsigned int sflags = flags_from_difficulty(difficulty);
  1299. unplace_lights(state);
  1300. #ifdef SOLVER_DIAGNOSTICS
  1301. debug(("Trying to solve with difficulty %d (0x%x):\n",
  1302. difficulty, sflags));
  1303. if (verbose) debug_state(state);
  1304. #endif
  1305. nsol = dosolve(state, sflags, &mdepth);
  1306. /* if we wanted an easy puzzle, make sure we didn't need recursion. */
  1307. if (!(sflags & F_SOLVE_ALLOWRECURSE) && mdepth > 0) {
  1308. debug(("Ignoring recursive puzzle.\n"));
  1309. return false;
  1310. }
  1311. debug(("%d solutions found.\n", nsol));
  1312. if (nsol <= 0) return false;
  1313. if (nsol > 1) return false;
  1314. return true;
  1315. }
  1316. /* --- New game creation and user input code. --- */
  1317. /* The basic algorithm here is to generate the most complex grid possible
  1318. * while honouring two restrictions:
  1319. *
  1320. * * we require a unique solution, and
  1321. * * either we require solubility with no recursion (!params->recurse)
  1322. * * or we require some recursion. (params->recurse).
  1323. *
  1324. * The solver helpfully keeps track of the numbers it needed to use to
  1325. * get its solution, so we use that to remove an initial set of numbers
  1326. * and check we still satsify our requirements (on uniqueness and
  1327. * non-recursiveness, if applicable; we don't check explicit recursiveness
  1328. * until the end).
  1329. *
  1330. * Then we try to remove all numbers in a random order, and see if we
  1331. * still satisfy requirements (putting them back if we didn't).
  1332. *
  1333. * Removing numbers will always, in general terms, make a puzzle require
  1334. * more recursion but it may also mean a puzzle becomes non-unique.
  1335. *
  1336. * Once we're done, if we wanted a recursive puzzle but the most difficult
  1337. * puzzle we could come up with was non-recursive, we give up and try a new
  1338. * grid. */
  1339. #define MAX_GRIDGEN_TRIES 20
  1340. static char *new_game_desc(const game_params *params_in, random_state *rs,
  1341. char **aux, bool interactive)
  1342. {
  1343. game_params params_copy = *params_in; /* structure copy */
  1344. game_params *params = &params_copy;
  1345. game_state *news = new_state(params), *copys;
  1346. int i, j, run, x, y, wh = params->w*params->h, num;
  1347. char *ret, *p;
  1348. int *numindices;
  1349. /* Construct a shuffled list of grid positions; we only
  1350. * do this once, because if it gets used more than once it'll
  1351. * be on a different grid layout. */
  1352. numindices = snewn(wh, int);
  1353. for (j = 0; j < wh; j++) numindices[j] = j;
  1354. shuffle(numindices, wh, sizeof(*numindices), rs);
  1355. while (1) {
  1356. for (i = 0; i < MAX_GRIDGEN_TRIES; i++) {
  1357. set_blacks(news, params, rs); /* also cleans board. */
  1358. /* set up lights and then the numbers, and remove the lights */
  1359. place_lights(news, rs);
  1360. debug(("Generating initial grid.\n"));
  1361. place_numbers(news);
  1362. if (!puzzle_is_good(news, params->difficulty)) continue;
  1363. /* Take a copy, remove numbers we didn't use and check there's
  1364. * still a unique solution; if so, use the copy subsequently. */
  1365. copys = dup_game(news);
  1366. strip_unused_nums(copys);
  1367. if (!puzzle_is_good(copys, params->difficulty)) {
  1368. debug(("Stripped grid is not good, reverting.\n"));
  1369. free_game(copys);
  1370. } else {
  1371. free_game(news);
  1372. news = copys;
  1373. }
  1374. /* Go through grid removing numbers at random one-by-one and
  1375. * trying to solve again; if it ceases to be good put the number back. */
  1376. for (j = 0; j < wh; j++) {
  1377. y = numindices[j] / params->w;
  1378. x = numindices[j] % params->w;
  1379. if (!(GRID(news, flags, x, y) & F_NUMBERED)) continue;
  1380. num = GRID(news, lights, x, y);
  1381. GRID(news, lights, x, y) = 0;
  1382. GRID(news, flags, x, y) &= ~F_NUMBERED;
  1383. if (!puzzle_is_good(news, params->difficulty)) {
  1384. GRID(news, lights, x, y) = num;
  1385. GRID(news, flags, x, y) |= F_NUMBERED;
  1386. } else
  1387. debug(("Removed (%d,%d) still soluble.\n", x, y));
  1388. }
  1389. if (params->difficulty > 0) {
  1390. /* Was the maximally-difficult puzzle difficult enough?
  1391. * Check we can't solve it with a more simplistic solver. */
  1392. if (puzzle_is_good(news, params->difficulty-1)) {
  1393. debug(("Maximally-hard puzzle still not hard enough, skipping.\n"));
  1394. continue;
  1395. }
  1396. }
  1397. goto goodpuzzle;
  1398. }
  1399. /* Couldn't generate a good puzzle in however many goes. Ramp up the
  1400. * %age of black squares (if we didn't already have lots; in which case
  1401. * why couldn't we generate a puzzle?) and try again. */
  1402. if (params->blackpc < 90) params->blackpc += 5;
  1403. debug(("New black layout %d%%.\n", params->blackpc));
  1404. }
  1405. goodpuzzle:
  1406. /* Game is encoded as a long string one character per square;
  1407. * 'S' is a space
  1408. * 'B' is a black square with no number
  1409. * '0', '1', '2', '3', '4' is a black square with a number. */
  1410. ret = snewn((params->w * params->h) + 1, char);
  1411. p = ret;
  1412. run = 0;
  1413. for (y = 0; y < params->h; y++) {
  1414. for (x = 0; x < params->w; x++) {
  1415. if (GRID(news,flags,x,y) & F_BLACK) {
  1416. if (run) {
  1417. *p++ = ('a'-1) + run;
  1418. run = 0;
  1419. }
  1420. if (GRID(news,flags,x,y) & F_NUMBERED)
  1421. *p++ = '0' + GRID(news,lights,x,y);
  1422. else
  1423. *p++ = 'B';
  1424. } else {
  1425. if (run == 26) {
  1426. *p++ = ('a'-1) + run;
  1427. run = 0;
  1428. }
  1429. run++;
  1430. }
  1431. }
  1432. }
  1433. if (run) {
  1434. *p++ = ('a'-1) + run;
  1435. run = 0;
  1436. }
  1437. *p = '\0';
  1438. assert(p - ret <= params->w * params->h);
  1439. free_game(news);
  1440. sfree(numindices);
  1441. return ret;
  1442. }
  1443. static const char *validate_desc(const game_params *params, const char *desc)
  1444. {
  1445. int i;
  1446. for (i = 0; i < params->w*params->h; i++) {
  1447. if (*desc >= '0' && *desc <= '4')
  1448. /* OK */;
  1449. else if (*desc == 'B')
  1450. /* OK */;
  1451. else if (*desc >= 'a' && *desc <= 'z')
  1452. i += *desc - 'a'; /* and the i++ will add another one */
  1453. else if (!*desc)
  1454. return "Game description shorter than expected";
  1455. else
  1456. return "Game description contained unexpected character";
  1457. desc++;
  1458. }
  1459. if (*desc || i > params->w*params->h)
  1460. return "Game description longer than expected";
  1461. return NULL;
  1462. }
  1463. static game_state *new_game(midend *me, const game_params *params,
  1464. const char *desc)
  1465. {
  1466. game_state *ret = new_state(params);
  1467. int x,y;
  1468. int run = 0;
  1469. for (y = 0; y < params->h; y++) {
  1470. for (x = 0; x < params->w; x++) {
  1471. char c = '\0';
  1472. if (run == 0) {
  1473. c = *desc++;
  1474. assert(c != 'S');
  1475. if (c >= 'a' && c <= 'z')
  1476. run = c - 'a' + 1;
  1477. }
  1478. if (run > 0) {
  1479. c = 'S';
  1480. run--;
  1481. }
  1482. switch (c) {
  1483. case '0': case '1': case '2': case '3': case '4':
  1484. GRID(ret,flags,x,y) |= F_NUMBERED;
  1485. GRID(ret,lights,x,y) = (c - '0');
  1486. /* run-on... */
  1487. case 'B':
  1488. GRID(ret,flags,x,y) |= F_BLACK;
  1489. break;
  1490. case 'S':
  1491. /* empty square */
  1492. break;
  1493. default:
  1494. assert(!"Malformed desc.");
  1495. break;
  1496. }
  1497. }
  1498. }
  1499. if (*desc) assert(!"Over-long desc.");
  1500. return ret;
  1501. }
  1502. static char *solve_game(const game_state *state, const game_state *currstate,
  1503. const char *aux, const char **error)
  1504. {
  1505. game_state *solved;
  1506. char *move = NULL, buf[80];
  1507. int movelen, movesize, x, y, len;
  1508. unsigned int oldflags, solvedflags, sflags;
  1509. /* We don't care here about non-unique puzzles; if the
  1510. * user entered one themself then I doubt they care. */
  1511. sflags = F_SOLVE_ALLOWRECURSE | F_SOLVE_DISCOUNTSETS;
  1512. /* Try and solve from where we are now (for non-unique
  1513. * puzzles this may produce a different answer). */
  1514. solved = dup_game(currstate);
  1515. if (dosolve(solved, sflags, NULL) > 0) goto solved;
  1516. free_game(solved);
  1517. /* That didn't work; try solving from the clean puzzle. */
  1518. solved = dup_game(state);
  1519. if (dosolve(solved, sflags, NULL) > 0) goto solved;
  1520. *error = "Unable to find a solution to this puzzle.";
  1521. goto done;
  1522. solved:
  1523. movesize = 256;
  1524. move = snewn(movesize, char);
  1525. movelen = 0;
  1526. move[movelen++] = 'S';
  1527. move[movelen] = '\0';
  1528. for (x = 0; x < currstate->w; x++) {
  1529. for (y = 0; y < currstate->h; y++) {
  1530. len = 0;
  1531. oldflags = GRID(currstate, flags, x, y);
  1532. solvedflags = GRID(solved, flags, x, y);
  1533. if ((oldflags & F_LIGHT) != (solvedflags & F_LIGHT))
  1534. len = sprintf(buf, ";L%d,%d", x, y);
  1535. else if ((oldflags & F_IMPOSSIBLE) != (solvedflags & F_IMPOSSIBLE))
  1536. len = sprintf(buf, ";I%d,%d", x, y);
  1537. if (len) {
  1538. if (movelen + len >= movesize) {
  1539. movesize = movelen + len + 256;
  1540. move = sresize(move, movesize, char);
  1541. }
  1542. strcpy(move + movelen, buf);
  1543. movelen += len;
  1544. }
  1545. }
  1546. }
  1547. done:
  1548. free_game(solved);
  1549. return move;
  1550. }
  1551. static bool game_can_format_as_text_now(const game_params *params)
  1552. {
  1553. return true;
  1554. }
  1555. /* 'borrowed' from slant.c, mainly. I could have printed it one
  1556. * character per cell (like debug_state) but that comes out tiny.
  1557. * 'L' is used for 'light here' because 'O' looks too much like '0'
  1558. * (black square with no surrounding lights). */
  1559. static char *game_text_format(const game_state *state)
  1560. {
  1561. int w = state->w, h = state->h, W = w+1, H = h+1;
  1562. int x, y, len, lights;
  1563. unsigned int flags;
  1564. char *ret, *p;
  1565. len = (h+H) * (w+W+1) + 1;
  1566. ret = snewn(len, char);
  1567. p = ret;
  1568. for (y = 0; y < H; y++) {
  1569. for (x = 0; x < W; x++) {
  1570. *p++ = '+';
  1571. if (x < w)
  1572. *p++ = '-';
  1573. }
  1574. *p++ = '\n';
  1575. if (y < h) {
  1576. for (x = 0; x < W; x++) {
  1577. *p++ = '|';
  1578. if (x < w) {
  1579. /* actual interesting bit. */
  1580. flags = GRID(state, flags, x, y);
  1581. lights = GRID(state, lights, x, y);
  1582. if (flags & F_BLACK) {
  1583. if (flags & F_NUMBERED)
  1584. *p++ = '0' + lights;
  1585. else
  1586. *p++ = '#';
  1587. } else {
  1588. if (flags & F_LIGHT)
  1589. *p++ = 'L';
  1590. else if (flags & F_IMPOSSIBLE)
  1591. *p++ = 'x';
  1592. else if (lights > 0)
  1593. *p++ = '.';
  1594. else
  1595. *p++ = ' ';
  1596. }
  1597. }
  1598. }
  1599. *p++ = '\n';
  1600. }
  1601. }
  1602. *p++ = '\0';
  1603. assert(p - ret == len);
  1604. return ret;
  1605. }
  1606. struct game_ui {
  1607. int cur_x, cur_y;
  1608. bool cur_visible;
  1609. /*
  1610. * User preference: when a square contains both a black blob for
  1611. * 'user is convinced this isn't a light' and a yellow highlight
  1612. * for 'this square is lit by a light', both of which rule out it
  1613. * being a light, should we still bother to show the blob?
  1614. */
  1615. bool draw_blobs_when_lit;
  1616. };
  1617. static void legacy_prefs_override(struct game_ui *ui_out)
  1618. {
  1619. static bool initialised = false;
  1620. static int draw_blobs_when_lit = -1;
  1621. if (!initialised) {
  1622. initialised = true;
  1623. draw_blobs_when_lit = getenv_bool("LIGHTUP_LIT_BLOBS", -1);
  1624. }
  1625. if (draw_blobs_when_lit != -1)
  1626. ui_out->draw_blobs_when_lit = draw_blobs_when_lit;
  1627. }
  1628. static game_ui *new_ui(const game_state *state)
  1629. {
  1630. game_ui *ui = snew(game_ui);
  1631. ui->cur_x = ui->cur_y = 0;
  1632. ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
  1633. ui->draw_blobs_when_lit = true;
  1634. legacy_prefs_override(ui);
  1635. return ui;
  1636. }
  1637. static config_item *get_prefs(game_ui *ui)
  1638. {
  1639. config_item *ret;
  1640. ret = snewn(2, config_item);
  1641. ret[0].name = "Draw non-light marks even when lit";
  1642. ret[0].kw = "show-lit-blobs";
  1643. ret[0].type = C_BOOLEAN;
  1644. ret[0].u.boolean.bval = ui->draw_blobs_when_lit;
  1645. ret[1].name = NULL;
  1646. ret[1].type = C_END;
  1647. return ret;
  1648. }
  1649. static void set_prefs(game_ui *ui, const config_item *cfg)
  1650. {
  1651. ui->draw_blobs_when_lit = cfg[0].u.boolean.bval;
  1652. }
  1653. static void free_ui(game_ui *ui)
  1654. {
  1655. sfree(ui);
  1656. }
  1657. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  1658. const game_state *newstate)
  1659. {
  1660. if (newstate->completed)
  1661. ui->cur_visible = false;
  1662. }
  1663. static const char *current_key_label(const game_ui *ui,
  1664. const game_state *state, int button)
  1665. {
  1666. int cx = ui->cur_x, cy = ui->cur_y;
  1667. unsigned int flags = GRID(state, flags, cx, cy);
  1668. if (!ui->cur_visible) return "";
  1669. if (button == CURSOR_SELECT) {
  1670. if (flags & (F_BLACK | F_IMPOSSIBLE)) return "";
  1671. if (flags & F_LIGHT) return "Clear";
  1672. return "Light";
  1673. }
  1674. if (button == CURSOR_SELECT2) {
  1675. if (flags & (F_BLACK | F_LIGHT)) return "";
  1676. if (flags & F_IMPOSSIBLE) return "Clear";
  1677. return "Mark";
  1678. }
  1679. return "";
  1680. }
  1681. #define DF_BLACK 1 /* black square */
  1682. #define DF_NUMBERED 2 /* black square with number */
  1683. #define DF_LIT 4 /* display (white) square lit up */
  1684. #define DF_LIGHT 8 /* display light in square */
  1685. #define DF_OVERLAP 16 /* display light as overlapped */
  1686. #define DF_CURSOR 32 /* display cursor */
  1687. #define DF_NUMBERWRONG 64 /* display black numbered square as error. */
  1688. #define DF_FLASH 128 /* background flash is on. */
  1689. #define DF_IMPOSSIBLE 256 /* display non-light little square */
  1690. struct game_drawstate {
  1691. int tilesize, crad;
  1692. int w, h;
  1693. unsigned int *flags; /* width * height */
  1694. bool started;
  1695. };
  1696. /* Believe it or not, this empty = "" hack is needed to get around a bug in
  1697. * the prc-tools gcc when optimisation is turned on; before, it produced:
  1698. lightup-sect.c: In function `interpret_move':
  1699. lightup-sect.c:1416: internal error--unrecognizable insn:
  1700. (insn 582 580 583 (set (reg:SI 134)
  1701. (pc)) -1 (nil)
  1702. (nil))
  1703. */
  1704. static char *interpret_move(const game_state *state, game_ui *ui,
  1705. const game_drawstate *ds,
  1706. int x, int y, int button)
  1707. {
  1708. enum { NONE, FLIP_LIGHT, FLIP_IMPOSSIBLE } action = NONE;
  1709. int cx = -1, cy = -1;
  1710. unsigned int flags;
  1711. char buf[80], *nullret = MOVE_UI_UPDATE, *empty = MOVE_UI_UPDATE, c;
  1712. if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
  1713. if (ui->cur_visible)
  1714. nullret = empty;
  1715. ui->cur_visible = false;
  1716. cx = FROMCOORD(x);
  1717. cy = FROMCOORD(y);
  1718. action = (button == LEFT_BUTTON) ? FLIP_LIGHT : FLIP_IMPOSSIBLE;
  1719. } else if (IS_CURSOR_SELECT(button) ||
  1720. button == 'i' || button == 'I') {
  1721. if (ui->cur_visible) {
  1722. /* Only allow cursor-effect operations if the cursor is visible
  1723. * (otherwise you have no idea which square it might be affecting) */
  1724. cx = ui->cur_x;
  1725. cy = ui->cur_y;
  1726. action = (button == 'i' || button == 'I' || button == CURSOR_SELECT2) ?
  1727. FLIP_IMPOSSIBLE : FLIP_LIGHT;
  1728. }
  1729. ui->cur_visible = true;
  1730. } else if (IS_CURSOR_MOVE(button)) {
  1731. move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false);
  1732. ui->cur_visible = true;
  1733. nullret = empty;
  1734. } else
  1735. return NULL;
  1736. switch (action) {
  1737. case FLIP_LIGHT:
  1738. case FLIP_IMPOSSIBLE:
  1739. if (cx < 0 || cy < 0 || cx >= state->w || cy >= state->h)
  1740. return nullret;
  1741. flags = GRID(state, flags, cx, cy);
  1742. if (flags & F_BLACK)
  1743. return nullret;
  1744. if (action == FLIP_LIGHT) {
  1745. #ifdef STYLUS_BASED
  1746. if (flags & F_IMPOSSIBLE || flags & F_LIGHT) c = 'I'; else c = 'L';
  1747. #else
  1748. if (flags & F_IMPOSSIBLE) return nullret;
  1749. c = 'L';
  1750. #endif
  1751. } else {
  1752. #ifdef STYLUS_BASED
  1753. if (flags & F_IMPOSSIBLE || flags & F_LIGHT) c = 'L'; else c = 'I';
  1754. #else
  1755. if (flags & F_LIGHT) return nullret;
  1756. c = 'I';
  1757. #endif
  1758. }
  1759. sprintf(buf, "%c%d,%d", (int)c, cx, cy);
  1760. break;
  1761. case NONE:
  1762. return nullret;
  1763. default:
  1764. assert(!"Shouldn't get here!");
  1765. }
  1766. return dupstr(buf);
  1767. }
  1768. static game_state *execute_move(const game_state *state, const char *move)
  1769. {
  1770. game_state *ret = dup_game(state);
  1771. int x, y, n, flags;
  1772. char c;
  1773. if (!*move) goto badmove;
  1774. while (*move) {
  1775. c = *move;
  1776. if (c == 'S') {
  1777. ret->used_solve = true;
  1778. move++;
  1779. } else if (c == 'L' || c == 'I') {
  1780. move++;
  1781. if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 ||
  1782. x < 0 || y < 0 || x >= ret->w || y >= ret->h)
  1783. goto badmove;
  1784. flags = GRID(ret, flags, x, y);
  1785. if (flags & F_BLACK) goto badmove;
  1786. /* LIGHT and IMPOSSIBLE are mutually exclusive. */
  1787. if (c == 'L') {
  1788. GRID(ret, flags, x, y) &= ~F_IMPOSSIBLE;
  1789. set_light(ret, x, y, !(flags & F_LIGHT));
  1790. } else {
  1791. set_light(ret, x, y, false);
  1792. GRID(ret, flags, x, y) ^= F_IMPOSSIBLE;
  1793. }
  1794. move += n;
  1795. } else goto badmove;
  1796. if (*move == ';')
  1797. move++;
  1798. else if (*move) goto badmove;
  1799. }
  1800. if (grid_correct(ret)) ret->completed = true;
  1801. return ret;
  1802. badmove:
  1803. free_game(ret);
  1804. return NULL;
  1805. }
  1806. /* ----------------------------------------------------------------------
  1807. * Drawing routines.
  1808. */
  1809. /* XXX entirely cloned from fifteen.c; separate out? */
  1810. static void game_compute_size(const game_params *params, int tilesize,
  1811. const game_ui *ui, int *x, int *y)
  1812. {
  1813. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  1814. struct { int tilesize; } ads, *ds = &ads;
  1815. ads.tilesize = tilesize;
  1816. *x = TILE_SIZE * params->w + 2 * BORDER;
  1817. *y = TILE_SIZE * params->h + 2 * BORDER;
  1818. }
  1819. static void game_set_size(drawing *dr, game_drawstate *ds,
  1820. const game_params *params, int tilesize)
  1821. {
  1822. ds->tilesize = tilesize;
  1823. ds->crad = 3*(tilesize-1)/8;
  1824. }
  1825. static float *game_colours(frontend *fe, int *ncolours)
  1826. {
  1827. float *ret = snewn(3 * NCOLOURS, float);
  1828. int i;
  1829. frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
  1830. for (i = 0; i < 3; i++) {
  1831. ret[COL_BLACK * 3 + i] = 0.0F;
  1832. ret[COL_LIGHT * 3 + i] = 1.0F;
  1833. ret[COL_CURSOR * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 2.0F;
  1834. ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 1.5F;
  1835. }
  1836. ret[COL_ERROR * 3 + 0] = 1.0F;
  1837. ret[COL_ERROR * 3 + 1] = 0.25F;
  1838. ret[COL_ERROR * 3 + 2] = 0.25F;
  1839. ret[COL_LIT * 3 + 0] = 1.0F;
  1840. ret[COL_LIT * 3 + 1] = 1.0F;
  1841. ret[COL_LIT * 3 + 2] = 0.0F;
  1842. *ncolours = NCOLOURS;
  1843. return ret;
  1844. }
  1845. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  1846. {
  1847. struct game_drawstate *ds = snew(struct game_drawstate);
  1848. int i;
  1849. ds->tilesize = ds->crad = 0;
  1850. ds->w = state->w; ds->h = state->h;
  1851. ds->flags = snewn(ds->w*ds->h, unsigned int);
  1852. for (i = 0; i < ds->w*ds->h; i++)
  1853. ds->flags[i] = -1;
  1854. ds->started = false;
  1855. return ds;
  1856. }
  1857. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  1858. {
  1859. sfree(ds->flags);
  1860. sfree(ds);
  1861. }
  1862. /* At some stage we should put these into a real options struct.
  1863. * Note that tile_redraw has no #ifdeffery; it relies on tile_flags not
  1864. * to put those flags in. */
  1865. #define HINT_LIGHTS
  1866. #define HINT_OVERLAPS
  1867. #define HINT_NUMBERS
  1868. static unsigned int tile_flags(game_drawstate *ds, const game_state *state,
  1869. const game_ui *ui, int x, int y, bool flashing)
  1870. {
  1871. unsigned int flags = GRID(state, flags, x, y);
  1872. int lights = GRID(state, lights, x, y);
  1873. unsigned int ret = 0;
  1874. if (flashing) ret |= DF_FLASH;
  1875. if (ui && ui->cur_visible && x == ui->cur_x && y == ui->cur_y)
  1876. ret |= DF_CURSOR;
  1877. if (flags & F_BLACK) {
  1878. ret |= DF_BLACK;
  1879. if (flags & F_NUMBERED) {
  1880. #ifdef HINT_NUMBERS
  1881. if (number_wrong(state, x, y))
  1882. ret |= DF_NUMBERWRONG;
  1883. #endif
  1884. ret |= DF_NUMBERED;
  1885. }
  1886. } else {
  1887. #ifdef HINT_LIGHTS
  1888. if (lights > 0) ret |= DF_LIT;
  1889. #endif
  1890. if (flags & F_LIGHT) {
  1891. ret |= DF_LIGHT;
  1892. #ifdef HINT_OVERLAPS
  1893. if (lights > 1) ret |= DF_OVERLAP;
  1894. #endif
  1895. }
  1896. if (flags & F_IMPOSSIBLE) ret |= DF_IMPOSSIBLE;
  1897. }
  1898. return ret;
  1899. }
  1900. static void tile_redraw(drawing *dr, game_drawstate *ds, const game_ui *ui,
  1901. const game_state *state, int x, int y)
  1902. {
  1903. unsigned int ds_flags = GRID(ds, flags, x, y);
  1904. int dx = COORD(x), dy = COORD(y);
  1905. int lit = (ds_flags & DF_FLASH) ? COL_GRID : COL_LIT;
  1906. if (ds_flags & DF_BLACK) {
  1907. draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_BLACK);
  1908. if (ds_flags & DF_NUMBERED) {
  1909. int ccol = (ds_flags & DF_NUMBERWRONG) ? COL_ERROR : COL_LIGHT;
  1910. char str[32];
  1911. /* We know that this won't change over the course of the game
  1912. * so it's OK to ignore this when calculating whether or not
  1913. * to redraw the tile. */
  1914. sprintf(str, "%d", GRID(state, lights, x, y));
  1915. draw_text(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2,
  1916. FONT_VARIABLE, TILE_SIZE*3/5,
  1917. ALIGN_VCENTRE | ALIGN_HCENTRE, ccol, str);
  1918. }
  1919. } else {
  1920. draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE,
  1921. (ds_flags & DF_LIT) ? lit : COL_BACKGROUND);
  1922. draw_rect_outline(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_GRID);
  1923. if (ds_flags & DF_LIGHT) {
  1924. int lcol = (ds_flags & DF_OVERLAP) ? COL_ERROR : COL_LIGHT;
  1925. draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, TILE_RADIUS,
  1926. lcol, COL_BLACK);
  1927. } else if ((ds_flags & DF_IMPOSSIBLE)) {
  1928. if (!(ds_flags & DF_LIT) || ui->draw_blobs_when_lit) {
  1929. int rlen = TILE_SIZE / 4;
  1930. draw_rect(dr, dx + TILE_SIZE/2 - rlen/2,
  1931. dy + TILE_SIZE/2 - rlen/2,
  1932. rlen, rlen, COL_BLACK);
  1933. }
  1934. }
  1935. }
  1936. if (ds_flags & DF_CURSOR) {
  1937. int coff = TILE_SIZE/8;
  1938. draw_rect_outline(dr, dx + coff, dy + coff,
  1939. TILE_SIZE - coff*2, TILE_SIZE - coff*2, COL_CURSOR);
  1940. }
  1941. draw_update(dr, dx, dy, TILE_SIZE, TILE_SIZE);
  1942. }
  1943. static void game_redraw(drawing *dr, game_drawstate *ds,
  1944. const game_state *oldstate, const game_state *state,
  1945. int dir, const game_ui *ui,
  1946. float animtime, float flashtime)
  1947. {
  1948. bool flashing = false;
  1949. int x,y;
  1950. if (flashtime) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1;
  1951. if (!ds->started) {
  1952. draw_rect_outline(dr, COORD(0)-1, COORD(0)-1,
  1953. TILE_SIZE * ds->w + 2,
  1954. TILE_SIZE * ds->h + 2,
  1955. COL_GRID);
  1956. draw_update(dr, 0, 0,
  1957. TILE_SIZE * ds->w + 2 * BORDER,
  1958. TILE_SIZE * ds->h + 2 * BORDER);
  1959. ds->started = true;
  1960. }
  1961. for (x = 0; x < ds->w; x++) {
  1962. for (y = 0; y < ds->h; y++) {
  1963. unsigned int ds_flags = tile_flags(ds, state, ui, x, y, flashing);
  1964. if (ds_flags != GRID(ds, flags, x, y)) {
  1965. GRID(ds, flags, x, y) = ds_flags;
  1966. tile_redraw(dr, ds, ui, state, x, y);
  1967. }
  1968. }
  1969. }
  1970. }
  1971. static float game_anim_length(const game_state *oldstate,
  1972. const game_state *newstate, int dir, game_ui *ui)
  1973. {
  1974. return 0.0F;
  1975. }
  1976. static float game_flash_length(const game_state *oldstate,
  1977. const game_state *newstate, int dir, game_ui *ui)
  1978. {
  1979. if (!oldstate->completed && newstate->completed &&
  1980. !oldstate->used_solve && !newstate->used_solve)
  1981. return FLASH_TIME;
  1982. return 0.0F;
  1983. }
  1984. static void game_get_cursor_location(const game_ui *ui,
  1985. const game_drawstate *ds,
  1986. const game_state *state,
  1987. const game_params *params,
  1988. int *x, int *y, int *w, int *h)
  1989. {
  1990. if(ui->cur_visible) {
  1991. *x = COORD(ui->cur_x);
  1992. *y = COORD(ui->cur_y);
  1993. *w = *h = TILE_SIZE;
  1994. }
  1995. }
  1996. static int game_status(const game_state *state)
  1997. {
  1998. return state->completed ? +1 : 0;
  1999. }
  2000. static void game_print_size(const game_params *params, const game_ui *ui,
  2001. float *x, float *y)
  2002. {
  2003. int pw, ph;
  2004. /*
  2005. * I'll use 6mm squares by default.
  2006. */
  2007. game_compute_size(params, 600, ui, &pw, &ph);
  2008. *x = pw / 100.0F;
  2009. *y = ph / 100.0F;
  2010. }
  2011. static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
  2012. int tilesize)
  2013. {
  2014. int w = state->w, h = state->h;
  2015. int ink = print_mono_colour(dr, 0);
  2016. int paper = print_mono_colour(dr, 1);
  2017. int x, y;
  2018. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  2019. game_drawstate ads, *ds = &ads;
  2020. game_set_size(dr, ds, NULL, tilesize);
  2021. /*
  2022. * Border.
  2023. */
  2024. print_line_width(dr, TILE_SIZE / 16);
  2025. draw_rect_outline(dr, COORD(0), COORD(0),
  2026. TILE_SIZE * w, TILE_SIZE * h, ink);
  2027. /*
  2028. * Grid.
  2029. */
  2030. print_line_width(dr, TILE_SIZE / 24);
  2031. for (x = 1; x < w; x++)
  2032. draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), ink);
  2033. for (y = 1; y < h; y++)
  2034. draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), ink);
  2035. /*
  2036. * Grid contents.
  2037. */
  2038. for (y = 0; y < h; y++)
  2039. for (x = 0; x < w; x++) {
  2040. unsigned int ds_flags = tile_flags(ds, state, NULL, x, y, false);
  2041. int dx = COORD(x), dy = COORD(y);
  2042. if (ds_flags & DF_BLACK) {
  2043. draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, ink);
  2044. if (ds_flags & DF_NUMBERED) {
  2045. char str[32];
  2046. sprintf(str, "%d", GRID(state, lights, x, y));
  2047. draw_text(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2,
  2048. FONT_VARIABLE, TILE_SIZE*3/5,
  2049. ALIGN_VCENTRE | ALIGN_HCENTRE, paper, str);
  2050. }
  2051. } else if (ds_flags & DF_LIGHT) {
  2052. draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2,
  2053. TILE_RADIUS, -1, ink);
  2054. }
  2055. }
  2056. }
  2057. #ifdef COMBINED
  2058. #define thegame lightup
  2059. #endif
  2060. const struct game thegame = {
  2061. "Light Up", "games.lightup", "lightup",
  2062. default_params,
  2063. game_fetch_preset, NULL,
  2064. decode_params,
  2065. encode_params,
  2066. free_params,
  2067. dup_params,
  2068. true, game_configure, custom_params,
  2069. validate_params,
  2070. new_game_desc,
  2071. validate_desc,
  2072. new_game,
  2073. dup_game,
  2074. free_game,
  2075. true, solve_game,
  2076. true, game_can_format_as_text_now, game_text_format,
  2077. get_prefs, set_prefs,
  2078. new_ui,
  2079. free_ui,
  2080. NULL, /* encode_ui */
  2081. NULL, /* decode_ui */
  2082. NULL, /* game_request_keys */
  2083. game_changed_state,
  2084. current_key_label,
  2085. interpret_move,
  2086. execute_move,
  2087. PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
  2088. game_colours,
  2089. game_new_drawstate,
  2090. game_free_drawstate,
  2091. game_redraw,
  2092. game_anim_length,
  2093. game_flash_length,
  2094. game_get_cursor_location,
  2095. game_status,
  2096. true, false, game_print_size, game_print,
  2097. false, /* wants_statusbar */
  2098. false, NULL, /* timing_state */
  2099. 0, /* flags */
  2100. };
  2101. #ifdef STANDALONE_SOLVER
  2102. int main(int argc, char **argv)
  2103. {
  2104. game_params *p;
  2105. game_state *s;
  2106. char *id = NULL, *desc, *result;
  2107. const char *err;
  2108. int nsol, diff, really_verbose = 0;
  2109. unsigned int sflags;
  2110. while (--argc > 0) {
  2111. char *p = *++argv;
  2112. if (!strcmp(p, "-v")) {
  2113. really_verbose++;
  2114. } else if (*p == '-') {
  2115. fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
  2116. return 1;
  2117. } else {
  2118. id = p;
  2119. }
  2120. }
  2121. if (!id) {
  2122. fprintf(stderr, "usage: %s [-v] <game_id>\n", argv[0]);
  2123. return 1;
  2124. }
  2125. desc = strchr(id, ':');
  2126. if (!desc) {
  2127. fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
  2128. return 1;
  2129. }
  2130. *desc++ = '\0';
  2131. p = default_params();
  2132. decode_params(p, id);
  2133. err = validate_desc(p, desc);
  2134. if (err) {
  2135. fprintf(stderr, "%s: %s\n", argv[0], err);
  2136. return 1;
  2137. }
  2138. s = new_game(NULL, p, desc);
  2139. /* Run the solvers easiest to hardest until we find one that
  2140. * can solve our puzzle. If it's soluble we know that the
  2141. * hardest (recursive) solver will always find the solution. */
  2142. nsol = sflags = 0;
  2143. for (diff = 0; diff <= DIFFCOUNT; diff++) {
  2144. printf("\nSolving with difficulty %d.\n", diff);
  2145. sflags = flags_from_difficulty(diff);
  2146. unplace_lights(s);
  2147. nsol = dosolve(s, sflags, NULL);
  2148. if (nsol == 1) break;
  2149. }
  2150. printf("\n");
  2151. if (nsol == 0) {
  2152. printf("Puzzle has no solution.\n");
  2153. } else if (nsol < 0) {
  2154. printf("Unable to find a unique solution.\n");
  2155. } else if (nsol > 1) {
  2156. printf("Puzzle has multiple solutions.\n");
  2157. } else {
  2158. verbose = really_verbose;
  2159. unplace_lights(s);
  2160. printf("Puzzle has difficulty %d: solving...\n", diff);
  2161. dosolve(s, sflags, NULL); /* sflags from last successful solve */
  2162. result = game_text_format(s);
  2163. printf("%s", result);
  2164. sfree(result);
  2165. }
  2166. return 0;
  2167. }
  2168. #endif
  2169. /* vim: set shiftwidth=4 tabstop=8: */