pearl.c 87 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927
  1. /*
  2. * pearl.c: Nikoli's `Masyu' puzzle.
  3. */
  4. /*
  5. * TODO:
  6. *
  7. * - The current keyboard cursor mechanism works well on ordinary PC
  8. * keyboards, but for platforms with only arrow keys and a select
  9. * button or two, we may at some point need a simpler one which can
  10. * handle 'x' markings without needing shift keys. For instance, a
  11. * cursor with twice the grid resolution, so that it can range
  12. * across face centres, edge centres and vertices; 'clicks' on face
  13. * centres begin a drag as currently, clicks on edges toggle
  14. * markings, and clicks on vertices are ignored (but it would be
  15. * too confusing not to let the cursor rest on them). But I'm
  16. * pretty sure that would be less pleasant to play on a full
  17. * keyboard, so probably a #ifdef would be the thing.
  18. *
  19. * - Generation is still pretty slow, due to difficulty coming up in
  20. * the first place with a loop that makes a soluble puzzle even
  21. * with all possible clues filled in.
  22. * + A possible alternative strategy to further tuning of the
  23. * existing loop generator would be to throw the entire
  24. * mechanism out and instead write a different generator from
  25. * scratch which evolves the solution along with the puzzle:
  26. * place a few clues, nail down a bit of the loop, place another
  27. * clue, nail down some more, etc. However, I don't have a
  28. * detailed plan for any such mechanism, so it may be a pipe
  29. * dream.
  30. */
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <assert.h>
  35. #include <ctype.h>
  36. #include <limits.h>
  37. #ifdef NO_TGMATH_H
  38. # include <math.h>
  39. #else
  40. # include <tgmath.h>
  41. #endif
  42. #include "puzzles.h"
  43. #include "grid.h"
  44. #include "loopgen.h"
  45. #define SWAP(i,j) do { int swaptmp = (i); (i) = (j); (j) = swaptmp; } while (0)
  46. #define NOCLUE 0
  47. #define CORNER 1
  48. #define STRAIGHT 2
  49. #define R 1
  50. #define U 2
  51. #define L 4
  52. #define D 8
  53. #define DX(d) ( ((d)==R) - ((d)==L) )
  54. #define DY(d) ( ((d)==D) - ((d)==U) )
  55. #define F(d) (((d << 2) | (d >> 2)) & 0xF)
  56. #define C(d) (((d << 3) | (d >> 1)) & 0xF)
  57. #define A(d) (((d << 1) | (d >> 3)) & 0xF)
  58. #define LR (L | R)
  59. #define RL (R | L)
  60. #define UD (U | D)
  61. #define DU (D | U)
  62. #define LU (L | U)
  63. #define UL (U | L)
  64. #define LD (L | D)
  65. #define DL (D | L)
  66. #define RU (R | U)
  67. #define UR (U | R)
  68. #define RD (R | D)
  69. #define DR (D | R)
  70. #define BLANK 0
  71. #define UNKNOWN 15
  72. #define bLR (1 << LR)
  73. #define bRL (1 << RL)
  74. #define bUD (1 << UD)
  75. #define bDU (1 << DU)
  76. #define bLU (1 << LU)
  77. #define bUL (1 << UL)
  78. #define bLD (1 << LD)
  79. #define bDL (1 << DL)
  80. #define bRU (1 << RU)
  81. #define bUR (1 << UR)
  82. #define bRD (1 << RD)
  83. #define bDR (1 << DR)
  84. #define bBLANK (1 << BLANK)
  85. enum {
  86. COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT,
  87. COL_CURSOR_BACKGROUND = COL_LOWLIGHT,
  88. COL_BLACK, COL_WHITE,
  89. COL_ERROR, COL_GRID, COL_FLASH,
  90. COL_DRAGON, COL_DRAGOFF,
  91. NCOLOURS
  92. };
  93. /* Macro ickery copied from slant.c */
  94. #define DIFFLIST(A) \
  95. A(EASY,Easy,e) \
  96. A(TRICKY,Tricky,t)
  97. #define ENUM(upper,title,lower) DIFF_ ## upper,
  98. #define TITLE(upper,title,lower) #title,
  99. #define ENCODE(upper,title,lower) #lower
  100. #define CONFIG(upper,title,lower) ":" #title
  101. enum { DIFFLIST(ENUM) DIFFCOUNT };
  102. static char const *const pearl_diffnames[] = { DIFFLIST(TITLE) "(count)" };
  103. static char const pearl_diffchars[] = DIFFLIST(ENCODE);
  104. #define DIFFCONFIG DIFFLIST(CONFIG)
  105. struct game_params {
  106. int w, h;
  107. int difficulty;
  108. bool nosolve; /* XXX remove me! */
  109. };
  110. struct shared_state {
  111. int w, h, sz;
  112. char *clues; /* size w*h */
  113. int refcnt;
  114. };
  115. #define INGRID(state, gx, gy) ((gx) >= 0 && (gx) < (state)->shared->w && \
  116. (gy) >= 0 && (gy) < (state)->shared->h)
  117. struct game_state {
  118. struct shared_state *shared;
  119. char *lines; /* size w*h: lines placed */
  120. char *errors; /* size w*h: errors detected */
  121. char *marks; /* size w*h: 'no line here' marks placed. */
  122. bool completed, used_solve;
  123. };
  124. #define DEFAULT_PRESET 3
  125. static const struct game_params pearl_presets[] = {
  126. {6, 6, DIFF_EASY},
  127. {6, 6, DIFF_TRICKY},
  128. {8, 8, DIFF_EASY},
  129. {8, 8, DIFF_TRICKY},
  130. {10, 10, DIFF_EASY},
  131. {10, 10, DIFF_TRICKY},
  132. {12, 8, DIFF_EASY},
  133. {12, 8, DIFF_TRICKY},
  134. };
  135. static game_params *default_params(void)
  136. {
  137. game_params *ret = snew(game_params);
  138. *ret = pearl_presets[DEFAULT_PRESET];
  139. ret->nosolve = false;
  140. return ret;
  141. }
  142. static bool game_fetch_preset(int i, char **name, game_params **params)
  143. {
  144. game_params *ret;
  145. char buf[64];
  146. if (i < 0 || i >= lenof(pearl_presets)) return false;
  147. ret = default_params();
  148. *ret = pearl_presets[i]; /* struct copy */
  149. *params = ret;
  150. sprintf(buf, "%dx%d %s",
  151. pearl_presets[i].w, pearl_presets[i].h,
  152. pearl_diffnames[pearl_presets[i].difficulty]);
  153. *name = dupstr(buf);
  154. return true;
  155. }
  156. static void free_params(game_params *params)
  157. {
  158. sfree(params);
  159. }
  160. static game_params *dup_params(const game_params *params)
  161. {
  162. game_params *ret = snew(game_params);
  163. *ret = *params; /* structure copy */
  164. return ret;
  165. }
  166. static void decode_params(game_params *ret, char const *string)
  167. {
  168. ret->w = ret->h = atoi(string);
  169. while (*string && isdigit((unsigned char) *string)) ++string;
  170. if (*string == 'x') {
  171. string++;
  172. ret->h = atoi(string);
  173. while (*string && isdigit((unsigned char)*string)) string++;
  174. }
  175. ret->difficulty = DIFF_EASY;
  176. if (*string == 'd') {
  177. int i;
  178. string++;
  179. for (i = 0; i < DIFFCOUNT; i++)
  180. if (*string == pearl_diffchars[i])
  181. ret->difficulty = i;
  182. if (*string) string++;
  183. }
  184. ret->nosolve = false;
  185. if (*string == 'n') {
  186. ret->nosolve = true;
  187. string++;
  188. }
  189. }
  190. static char *encode_params(const game_params *params, bool full)
  191. {
  192. char buf[256];
  193. sprintf(buf, "%dx%d", params->w, params->h);
  194. if (full)
  195. sprintf(buf + strlen(buf), "d%c%s",
  196. pearl_diffchars[params->difficulty],
  197. params->nosolve ? "n" : "");
  198. return dupstr(buf);
  199. }
  200. static config_item *game_configure(const game_params *params)
  201. {
  202. config_item *ret;
  203. char buf[64];
  204. ret = snewn(5, config_item);
  205. ret[0].name = "Width";
  206. ret[0].type = C_STRING;
  207. sprintf(buf, "%d", params->w);
  208. ret[0].u.string.sval = dupstr(buf);
  209. ret[1].name = "Height";
  210. ret[1].type = C_STRING;
  211. sprintf(buf, "%d", params->h);
  212. ret[1].u.string.sval = dupstr(buf);
  213. ret[2].name = "Difficulty";
  214. ret[2].type = C_CHOICES;
  215. ret[2].u.choices.choicenames = DIFFCONFIG;
  216. ret[2].u.choices.selected = params->difficulty;
  217. ret[3].name = "Allow unsoluble";
  218. ret[3].type = C_BOOLEAN;
  219. ret[3].u.boolean.bval = params->nosolve;
  220. ret[4].name = NULL;
  221. ret[4].type = C_END;
  222. return ret;
  223. }
  224. static game_params *custom_params(const config_item *cfg)
  225. {
  226. game_params *ret = snew(game_params);
  227. ret->w = atoi(cfg[0].u.string.sval);
  228. ret->h = atoi(cfg[1].u.string.sval);
  229. ret->difficulty = cfg[2].u.choices.selected;
  230. ret->nosolve = cfg[3].u.boolean.bval;
  231. return ret;
  232. }
  233. static const char *validate_params(const game_params *params, bool full)
  234. {
  235. if (params->w < 5) return "Width must be at least five";
  236. if (params->h < 5) return "Height must be at least five";
  237. if (params->w > INT_MAX / params->h)
  238. return "Width times height must not be unreasonably large";
  239. if (params->difficulty < 0 || params->difficulty >= DIFFCOUNT)
  240. return "Unknown difficulty level";
  241. if (params->difficulty >= DIFF_TRICKY && params->w + params->h < 11)
  242. return "Width or height must be at least six for Tricky";
  243. return NULL;
  244. }
  245. /* ----------------------------------------------------------------------
  246. * Solver.
  247. */
  248. static int pearl_solve(int w, int h, char *clues, char *result,
  249. int difficulty, bool partial)
  250. {
  251. int W = 2*w+1, H = 2*h+1;
  252. short *workspace;
  253. DSF *dsf;
  254. int *dsfsize;
  255. int x, y, b, d;
  256. int ret = -1;
  257. /*
  258. * workspace[(2*y+1)*W+(2*x+1)] indicates the possible nature
  259. * of the square (x,y), as a logical OR of bitfields.
  260. *
  261. * workspace[(2*y)*W+(2*x+1)], for x odd and y even, indicates
  262. * whether the horizontal edge between (x,y) and (x+1,y) is
  263. * connected (1), disconnected (2) or unknown (3).
  264. *
  265. * workspace[(2*y+1)*W+(2*x)], indicates the same about the
  266. * vertical edge between (x,y) and (x,y+1).
  267. *
  268. * Initially, every square is considered capable of being in
  269. * any of the seven possible states (two straights, four
  270. * corners and empty), except those corresponding to clue
  271. * squares which are more restricted.
  272. *
  273. * Initially, all edges are unknown, except the ones around the
  274. * grid border which are known to be disconnected.
  275. */
  276. workspace = snewn(W*H, short);
  277. for (x = 0; x < W*H; x++)
  278. workspace[x] = 0;
  279. /* Square states */
  280. for (y = 0; y < h; y++)
  281. for (x = 0; x < w; x++)
  282. switch (clues[y*w+x]) {
  283. case CORNER:
  284. workspace[(2*y+1)*W+(2*x+1)] = bLU|bLD|bRU|bRD;
  285. break;
  286. case STRAIGHT:
  287. workspace[(2*y+1)*W+(2*x+1)] = bLR|bUD;
  288. break;
  289. default:
  290. workspace[(2*y+1)*W+(2*x+1)] = bLR|bUD|bLU|bLD|bRU|bRD|bBLANK;
  291. break;
  292. }
  293. /* Horizontal edges */
  294. for (y = 0; y <= h; y++)
  295. for (x = 0; x < w; x++)
  296. workspace[(2*y)*W+(2*x+1)] = (y==0 || y==h ? 2 : 3);
  297. /* Vertical edges */
  298. for (y = 0; y < h; y++)
  299. for (x = 0; x <= w; x++)
  300. workspace[(2*y+1)*W+(2*x)] = (x==0 || x==w ? 2 : 3);
  301. /*
  302. * We maintain a dsf of connected squares, together with a
  303. * count of the size of each equivalence class.
  304. */
  305. dsf = dsf_new(w*h);
  306. dsfsize = snewn(w*h, int);
  307. /*
  308. * Now repeatedly try to find something we can do.
  309. */
  310. while (1) {
  311. bool done_something = false;
  312. #ifdef SOLVER_DIAGNOSTICS
  313. for (y = 0; y < H; y++) {
  314. for (x = 0; x < W; x++)
  315. printf("%*x", (x&1) ? 5 : 2, workspace[y*W+x]);
  316. printf("\n");
  317. }
  318. #endif
  319. /*
  320. * Go through the square state words, and discard any
  321. * square state which is inconsistent with known facts
  322. * about the edges around the square.
  323. */
  324. for (y = 0; y < h; y++)
  325. for (x = 0; x < w; x++) {
  326. for (b = 0; b < 0xD; b++)
  327. if (workspace[(2*y+1)*W+(2*x+1)] & (1<<b)) {
  328. /*
  329. * If any edge of this square is known to
  330. * be connected when state b would require
  331. * it disconnected, or vice versa, discard
  332. * the state.
  333. */
  334. for (d = 1; d <= 8; d += d) {
  335. int ex = 2*x+1 + DX(d), ey = 2*y+1 + DY(d);
  336. if (workspace[ey*W+ex] ==
  337. ((b & d) ? 2 : 1)) {
  338. workspace[(2*y+1)*W+(2*x+1)] &= ~(1<<b);
  339. #ifdef SOLVER_DIAGNOSTICS
  340. printf("edge (%d,%d)-(%d,%d) rules out state"
  341. " %d for square (%d,%d)\n",
  342. ex/2, ey/2, (ex+1)/2, (ey+1)/2,
  343. b, x, y);
  344. #endif
  345. done_something = true;
  346. break;
  347. }
  348. }
  349. }
  350. /*
  351. * Consistency check: each square must have at
  352. * least one state left!
  353. */
  354. if (!workspace[(2*y+1)*W+(2*x+1)]) {
  355. #ifdef SOLVER_DIAGNOSTICS
  356. printf("edge check at (%d,%d): inconsistency\n", x, y);
  357. #endif
  358. ret = 0;
  359. goto cleanup;
  360. }
  361. }
  362. /*
  363. * Now go through the states array again, and nail down any
  364. * unknown edge if one of its neighbouring squares makes it
  365. * known.
  366. */
  367. for (y = 0; y < h; y++)
  368. for (x = 0; x < w; x++) {
  369. int edgeor = 0, edgeand = 15;
  370. for (b = 0; b < 0xD; b++)
  371. if (workspace[(2*y+1)*W+(2*x+1)] & (1<<b)) {
  372. edgeor |= b;
  373. edgeand &= b;
  374. }
  375. /*
  376. * Now any bit clear in edgeor marks a disconnected
  377. * edge, and any bit set in edgeand marks a
  378. * connected edge.
  379. */
  380. /* First check consistency: neither bit is both! */
  381. if (edgeand & ~edgeor) {
  382. #ifdef SOLVER_DIAGNOSTICS
  383. printf("square check at (%d,%d): inconsistency\n", x, y);
  384. #endif
  385. ret = 0;
  386. goto cleanup;
  387. }
  388. for (d = 1; d <= 8; d += d) {
  389. int ex = 2*x+1 + DX(d), ey = 2*y+1 + DY(d);
  390. if (!(edgeor & d) && workspace[ey*W+ex] == 3) {
  391. workspace[ey*W+ex] = 2;
  392. done_something = true;
  393. #ifdef SOLVER_DIAGNOSTICS
  394. printf("possible states of square (%d,%d) force edge"
  395. " (%d,%d)-(%d,%d) to be disconnected\n",
  396. x, y, ex/2, ey/2, (ex+1)/2, (ey+1)/2);
  397. #endif
  398. } else if ((edgeand & d) && workspace[ey*W+ex] == 3) {
  399. workspace[ey*W+ex] = 1;
  400. done_something = true;
  401. #ifdef SOLVER_DIAGNOSTICS
  402. printf("possible states of square (%d,%d) force edge"
  403. " (%d,%d)-(%d,%d) to be connected\n",
  404. x, y, ex/2, ey/2, (ex+1)/2, (ey+1)/2);
  405. #endif
  406. }
  407. }
  408. }
  409. if (done_something)
  410. continue;
  411. /*
  412. * Now for longer-range clue-based deductions (using the
  413. * rules that a corner clue must connect to two straight
  414. * squares, and a straight clue must connect to at least
  415. * one corner square).
  416. */
  417. for (y = 0; y < h; y++)
  418. for (x = 0; x < w; x++)
  419. switch (clues[y*w+x]) {
  420. case CORNER:
  421. for (d = 1; d <= 8; d += d) {
  422. int ex = 2*x+1 + DX(d), ey = 2*y+1 + DY(d);
  423. int fx = ex + DX(d), fy = ey + DY(d);
  424. int type = d | F(d);
  425. if (workspace[ey*W+ex] == 1) {
  426. /*
  427. * If a corner clue is connected on any
  428. * edge, then we can immediately nail
  429. * down the square beyond that edge as
  430. * being a straight in the appropriate
  431. * direction.
  432. */
  433. if (workspace[fy*W+fx] != (1<<type)) {
  434. workspace[fy*W+fx] = (1<<type);
  435. done_something = true;
  436. #ifdef SOLVER_DIAGNOSTICS
  437. printf("corner clue at (%d,%d) forces square "
  438. "(%d,%d) into state %d\n", x, y,
  439. fx/2, fy/2, type);
  440. #endif
  441. }
  442. } else if (workspace[ey*W+ex] == 3) {
  443. /*
  444. * Conversely, if a corner clue is
  445. * separated by an unknown edge from a
  446. * square which _cannot_ be a straight
  447. * in the appropriate direction, we can
  448. * mark that edge as disconnected.
  449. */
  450. if (!(workspace[fy*W+fx] & (1<<type))) {
  451. workspace[ey*W+ex] = 2;
  452. done_something = true;
  453. #ifdef SOLVER_DIAGNOSTICS
  454. printf("corner clue at (%d,%d), plus square "
  455. "(%d,%d) not being state %d, "
  456. "disconnects edge (%d,%d)-(%d,%d)\n",
  457. x, y, fx/2, fy/2, type,
  458. ex/2, ey/2, (ex+1)/2, (ey+1)/2);
  459. #endif
  460. }
  461. }
  462. }
  463. break;
  464. case STRAIGHT:
  465. /*
  466. * If a straight clue is between two squares
  467. * neither of which is capable of being a
  468. * corner connected to it, then the straight
  469. * clue cannot point in that direction.
  470. */
  471. for (d = 1; d <= 2; d += d) {
  472. int fx = 2*x+1 + 2*DX(d), fy = 2*y+1 + 2*DY(d);
  473. int gx = 2*x+1 - 2*DX(d), gy = 2*y+1 - 2*DY(d);
  474. int type = d | F(d);
  475. if (!(workspace[(2*y+1)*W+(2*x+1)] & (1<<type)))
  476. continue;
  477. if (!(workspace[fy*W+fx] & ((1<<(F(d)|A(d))) |
  478. (1<<(F(d)|C(d))))) &&
  479. !(workspace[gy*W+gx] & ((1<<( d |A(d))) |
  480. (1<<( d |C(d)))))) {
  481. workspace[(2*y+1)*W+(2*x+1)] &= ~(1<<type);
  482. done_something = true;
  483. #ifdef SOLVER_DIAGNOSTICS
  484. printf("straight clue at (%d,%d) cannot corner at "
  485. "(%d,%d) or (%d,%d) so is not state %d\n",
  486. x, y, fx/2, fy/2, gx/2, gy/2, type);
  487. #endif
  488. }
  489. }
  490. /*
  491. * If a straight clue with known direction is
  492. * connected on one side to a known straight,
  493. * then on the other side it must be a corner.
  494. */
  495. for (d = 1; d <= 8; d += d) {
  496. int fx = 2*x+1 + 2*DX(d), fy = 2*y+1 + 2*DY(d);
  497. int gx = 2*x+1 - 2*DX(d), gy = 2*y+1 - 2*DY(d);
  498. int type = d | F(d);
  499. if (workspace[(2*y+1)*W+(2*x+1)] != (1<<type))
  500. continue;
  501. if (!(workspace[fy*W+fx] &~ (bLR|bUD)) &&
  502. (workspace[gy*W+gx] &~ (bLU|bLD|bRU|bRD))) {
  503. workspace[gy*W+gx] &= (bLU|bLD|bRU|bRD);
  504. done_something = true;
  505. #ifdef SOLVER_DIAGNOSTICS
  506. printf("straight clue at (%d,%d) connecting to "
  507. "straight at (%d,%d) makes (%d,%d) a "
  508. "corner\n", x, y, fx/2, fy/2, gx/2, gy/2);
  509. #endif
  510. }
  511. }
  512. break;
  513. }
  514. if (done_something)
  515. continue;
  516. /*
  517. * Now detect shortcut loops.
  518. */
  519. {
  520. int nonblanks, loopclass;
  521. dsf_reinit(dsf);
  522. for (x = 0; x < w*h; x++)
  523. dsfsize[x] = 1;
  524. /*
  525. * First go through the edge entries and update the dsf
  526. * of which squares are connected to which others. We
  527. * also track the number of squares in each equivalence
  528. * class, and count the overall number of
  529. * known-non-blank squares.
  530. *
  531. * In the process of doing this, we must notice if a
  532. * loop has already been formed. If it has, we blank
  533. * out any square which isn't part of that loop
  534. * (failing a consistency check if any such square does
  535. * not have BLANK as one of its remaining options) and
  536. * exit the deduction loop with success.
  537. */
  538. nonblanks = 0;
  539. loopclass = -1;
  540. for (y = 1; y < H-1; y++)
  541. for (x = 1; x < W-1; x++)
  542. if ((y ^ x) & 1) {
  543. /*
  544. * (x,y) are the workspace coordinates of
  545. * an edge field. Compute the normal-space
  546. * coordinates of the squares it connects.
  547. */
  548. int ax = (x-1)/2, ay = (y-1)/2, ac = ay*w+ax;
  549. int bx = x/2, by = y/2, bc = by*w+bx;
  550. /*
  551. * If the edge is connected, do the dsf
  552. * thing.
  553. */
  554. if (workspace[y*W+x] == 1) {
  555. int ae, be;
  556. ae = dsf_canonify(dsf, ac);
  557. be = dsf_canonify(dsf, bc);
  558. if (ae == be) {
  559. /*
  560. * We have a loop!
  561. */
  562. if (loopclass != -1) {
  563. /*
  564. * In fact, we have two
  565. * separate loops, which is
  566. * doom.
  567. */
  568. #ifdef SOLVER_DIAGNOSTICS
  569. printf("two loops found in grid!\n");
  570. #endif
  571. ret = 0;
  572. goto cleanup;
  573. }
  574. loopclass = ae;
  575. } else {
  576. /*
  577. * Merge the two equivalence
  578. * classes.
  579. */
  580. int size = dsfsize[ae] + dsfsize[be];
  581. dsf_merge(dsf, ac, bc);
  582. ae = dsf_canonify(dsf, ac);
  583. dsfsize[ae] = size;
  584. }
  585. }
  586. } else if ((y & x) & 1) {
  587. /*
  588. * (x,y) are the workspace coordinates of a
  589. * square field. If the square is
  590. * definitely not blank, count it.
  591. */
  592. if (!(workspace[y*W+x] & bBLANK))
  593. nonblanks++;
  594. }
  595. /*
  596. * If we discovered an existing loop above, we must now
  597. * blank every square not part of it, and exit the main
  598. * deduction loop.
  599. */
  600. if (loopclass != -1) {
  601. #ifdef SOLVER_DIAGNOSTICS
  602. printf("loop found in grid!\n");
  603. #endif
  604. for (y = 0; y < h; y++)
  605. for (x = 0; x < w; x++)
  606. if (dsf_canonify(dsf, y*w+x) != loopclass) {
  607. if (workspace[(y*2+1)*W+(x*2+1)] & bBLANK) {
  608. workspace[(y*2+1)*W+(x*2+1)] = bBLANK;
  609. } else {
  610. /*
  611. * This square is not part of the
  612. * loop, but is known non-blank. We
  613. * have goofed.
  614. */
  615. #ifdef SOLVER_DIAGNOSTICS
  616. printf("non-blank square (%d,%d) found outside"
  617. " loop!\n", x, y);
  618. #endif
  619. ret = 0;
  620. goto cleanup;
  621. }
  622. }
  623. /*
  624. * And we're done.
  625. */
  626. ret = 1;
  627. break;
  628. }
  629. /* Further deductions are considered 'tricky'. */
  630. if (difficulty == DIFF_EASY) goto done_deductions;
  631. /*
  632. * Now go through the workspace again and mark any edge
  633. * which would cause a shortcut loop (i.e. would
  634. * connect together two squares in the same equivalence
  635. * class, and that equivalence class does not contain
  636. * _all_ the known-non-blank squares currently in the
  637. * grid) as disconnected. Also, mark any _square state_
  638. * which would cause a shortcut loop as disconnected.
  639. */
  640. for (y = 1; y < H-1; y++)
  641. for (x = 1; x < W-1; x++)
  642. if ((y ^ x) & 1) {
  643. /*
  644. * (x,y) are the workspace coordinates of
  645. * an edge field. Compute the normal-space
  646. * coordinates of the squares it connects.
  647. */
  648. int ax = (x-1)/2, ay = (y-1)/2, ac = ay*w+ax;
  649. int bx = x/2, by = y/2, bc = by*w+bx;
  650. /*
  651. * If the edge is currently unknown, and
  652. * sits between two squares in the same
  653. * equivalence class, and the size of that
  654. * class is less than nonblanks, then
  655. * connecting this edge would be a shortcut
  656. * loop and so we must not do so.
  657. */
  658. if (workspace[y*W+x] == 3) {
  659. int ae, be;
  660. ae = dsf_canonify(dsf, ac);
  661. be = dsf_canonify(dsf, bc);
  662. if (ae == be) {
  663. /*
  664. * We have a loop. Is it a shortcut?
  665. */
  666. if (dsfsize[ae] < nonblanks) {
  667. /*
  668. * Yes! Mark this edge disconnected.
  669. */
  670. workspace[y*W+x] = 2;
  671. done_something = true;
  672. #ifdef SOLVER_DIAGNOSTICS
  673. printf("edge (%d,%d)-(%d,%d) would create"
  674. " a shortcut loop, hence must be"
  675. " disconnected\n", x/2, y/2,
  676. (x+1)/2, (y+1)/2);
  677. #endif
  678. }
  679. }
  680. }
  681. } else if ((y & x) & 1) {
  682. /*
  683. * (x,y) are the workspace coordinates of a
  684. * square field. Go through its possible
  685. * (non-blank) states and see if any gives
  686. * rise to a shortcut loop.
  687. *
  688. * This is slightly fiddly, because we have
  689. * to check whether this square is already
  690. * part of the same equivalence class as
  691. * the things it's joining.
  692. */
  693. int ae = dsf_canonify(dsf, (y/2)*w+(x/2));
  694. for (b = 2; b < 0xD; b++)
  695. if (workspace[y*W+x] & (1<<b)) {
  696. /*
  697. * Find the equivalence classes of
  698. * the two squares this one would
  699. * connect if it were in this
  700. * state.
  701. */
  702. int e = -1;
  703. for (d = 1; d <= 8; d += d) if (b & d) {
  704. int xx = x/2 + DX(d), yy = y/2 + DY(d);
  705. int ee = dsf_canonify(dsf, yy*w+xx);
  706. if (e == -1)
  707. ee = e;
  708. else if (e != ee)
  709. e = -2;
  710. }
  711. if (e >= 0) {
  712. /*
  713. * This square state would form
  714. * a loop on equivalence class
  715. * e. Measure the size of that
  716. * loop, and see if it's a
  717. * shortcut.
  718. */
  719. int loopsize = dsfsize[e];
  720. if (e != ae)
  721. loopsize++;/* add the square itself */
  722. if (loopsize < nonblanks) {
  723. /*
  724. * It is! Mark this square
  725. * state invalid.
  726. */
  727. workspace[y*W+x] &= ~(1<<b);
  728. done_something = true;
  729. #ifdef SOLVER_DIAGNOSTICS
  730. printf("square (%d,%d) would create a "
  731. "shortcut loop in state %d, "
  732. "hence cannot be\n",
  733. x/2, y/2, b);
  734. #endif
  735. }
  736. }
  737. }
  738. }
  739. }
  740. done_deductions:
  741. if (done_something)
  742. continue;
  743. /*
  744. * If we reach here, there is nothing left we can do.
  745. * Return 2 for ambiguous puzzle.
  746. */
  747. ret = 2;
  748. break;
  749. }
  750. cleanup:
  751. /*
  752. * If ret = 1 then we've successfully achieved a solution. This
  753. * means that we expect every square to be nailed down to
  754. * exactly one possibility. If this is the case, or if the caller
  755. * asked for a partial solution anyway, transcribe those
  756. * possibilities into the result array.
  757. */
  758. if (ret == 1 || partial) {
  759. for (y = 0; y < h; y++) {
  760. for (x = 0; x < w; x++) {
  761. for (b = 0; b < 0xD; b++)
  762. if (workspace[(2*y+1)*W+(2*x+1)] == (1<<b)) {
  763. result[y*w+x] = b;
  764. break;
  765. }
  766. if (ret == 1) assert(b < 0xD); /* we should have had a break by now */
  767. }
  768. }
  769. /*
  770. * Ensure we haven't left the _data structure_ inconsistent,
  771. * regardless of the consistency of the _puzzle_. In
  772. * particular, we should never have marked one square as
  773. * linked to its neighbour if the neighbour is not
  774. * reciprocally linked back to the original square.
  775. *
  776. * This can happen if we get part way through solving an
  777. * impossible puzzle and then give up trying to make further
  778. * progress. So here we fix it up to avoid confusing the rest
  779. * of the game.
  780. */
  781. for (y = 0; y < h; y++) {
  782. for (x = 0; x < w; x++) {
  783. for (d = 1; d <= 8; d += d) {
  784. int nx = x + DX(d), ny = y + DY(d);
  785. int rlink;
  786. if (0 <= nx && nx < w && 0 <= ny && ny < h)
  787. rlink = result[ny*w+nx] & F(d);
  788. else
  789. rlink = 0; /* off-board squares don't link back */
  790. /* If other square doesn't link to us, don't link to it */
  791. if (!rlink)
  792. result[y*w+x] &= ~d;
  793. }
  794. }
  795. }
  796. }
  797. sfree(dsfsize);
  798. dsf_free(dsf);
  799. sfree(workspace);
  800. assert(ret >= 0);
  801. return ret;
  802. }
  803. /* ----------------------------------------------------------------------
  804. * Loop generator.
  805. */
  806. /*
  807. * We use the loop generator code from loopy, hard-coding to a square
  808. * grid of the appropriate size. Knowing the grid layout and the tile
  809. * size we can shrink that to our small grid and then make our line
  810. * layout from the face colour info.
  811. *
  812. * We provide a bias function to the loop generator which tries to
  813. * bias in favour of loops with more scope for Pearl black clues. This
  814. * seems to improve the success rate of the puzzle generator, in that
  815. * such loops have a better chance of being soluble with all valid
  816. * clues put in.
  817. */
  818. struct pearl_loopgen_bias_ctx {
  819. /*
  820. * Our bias function counts the number of 'black clue' corners
  821. * (i.e. corners adjacent to two straights) in both the
  822. * BLACK/nonBLACK and WHITE/nonWHITE boundaries. In order to do
  823. * this, we must:
  824. *
  825. * - track the edges that are part of each of those loops
  826. * - track the types of vertex in each loop (corner, straight,
  827. * none)
  828. * - track the current black-clue status of each vertex in each
  829. * loop.
  830. *
  831. * Each of these chunks of data is updated incrementally from the
  832. * previous one, to avoid slowdown due to the bias function
  833. * rescanning the whole grid every time it's called.
  834. *
  835. * So we need a lot of separate arrays, plus a tdq for each one,
  836. * and we must repeat it all twice for the BLACK and WHITE
  837. * boundaries.
  838. */
  839. struct pearl_loopgen_bias_ctx_boundary {
  840. int colour; /* FACE_WHITE or FACE_BLACK */
  841. bool *edges; /* is each edge part of the loop? */
  842. tdq *edges_todo;
  843. char *vertextypes; /* bits 0-3 == outgoing edge bitmap;
  844. * bit 4 set iff corner clue.
  845. * Hence, 0 means non-vertex;
  846. * nonzero but bit 4 zero = straight. */
  847. int *neighbour[2]; /* indices of neighbour vertices in loop */
  848. tdq *vertextypes_todo;
  849. char *blackclues; /* is each vertex a black clue site? */
  850. tdq *blackclues_todo;
  851. } boundaries[2]; /* boundaries[0]=WHITE, [1]=BLACK */
  852. char *faces; /* remember last-seen colour of each face */
  853. tdq *faces_todo;
  854. int score;
  855. grid *g;
  856. };
  857. static int pearl_loopgen_bias(void *vctx, char *board, int face)
  858. {
  859. struct pearl_loopgen_bias_ctx *ctx = (struct pearl_loopgen_bias_ctx *)vctx;
  860. grid *g = ctx->g;
  861. int oldface, newface;
  862. int i, j, k;
  863. tdq_add(ctx->faces_todo, face);
  864. while ((j = tdq_remove(ctx->faces_todo)) >= 0) {
  865. oldface = ctx->faces[j];
  866. ctx->faces[j] = newface = board[j];
  867. for (i = 0; i < 2; i++) {
  868. struct pearl_loopgen_bias_ctx_boundary *b = &ctx->boundaries[i];
  869. int c = b->colour;
  870. /*
  871. * If the face has changed either from or to colour c, we need
  872. * to reprocess the edges for this boundary.
  873. */
  874. if (oldface == c || newface == c) {
  875. grid_face *f = g->faces[face];
  876. for (k = 0; k < f->order; k++)
  877. tdq_add(b->edges_todo, f->edges[k]->index);
  878. }
  879. }
  880. }
  881. for (i = 0; i < 2; i++) {
  882. struct pearl_loopgen_bias_ctx_boundary *b = &ctx->boundaries[i];
  883. int c = b->colour;
  884. /*
  885. * Go through the to-do list of edges. For each edge, decide
  886. * anew whether it's part of this boundary or not. Any edge
  887. * that changes state has to have both its endpoints put on
  888. * the vertextypes_todo list.
  889. */
  890. while ((j = tdq_remove(b->edges_todo)) >= 0) {
  891. grid_edge *e = g->edges[j];
  892. int fc1 = e->face1 ? board[e->face1->index] : FACE_BLACK;
  893. int fc2 = e->face2 ? board[e->face2->index] : FACE_BLACK;
  894. bool oldedge = b->edges[j];
  895. bool newedge = (fc1==c) ^ (fc2==c);
  896. if (oldedge != newedge) {
  897. b->edges[j] = newedge;
  898. tdq_add(b->vertextypes_todo, e->dot1->index);
  899. tdq_add(b->vertextypes_todo, e->dot2->index);
  900. }
  901. }
  902. /*
  903. * Go through the to-do list of vertices whose types need
  904. * refreshing. For each one, decide whether it's a corner, a
  905. * straight, or a vertex not in the loop, and in the former
  906. * two cases also work out the indices of its neighbour
  907. * vertices along the loop. Any vertex that changes state must
  908. * be put back on the to-do list for deciding if it's a black
  909. * clue site, and so must its two new neighbours _and_ its two
  910. * old neighbours.
  911. */
  912. while ((j = tdq_remove(b->vertextypes_todo)) >= 0) {
  913. grid_dot *d = g->dots[j];
  914. int neighbours[2], type = 0, n = 0;
  915. for (k = 0; k < d->order; k++) {
  916. grid_edge *e = d->edges[k];
  917. grid_dot *d2 = (e->dot1 == d ? e->dot2 : e->dot1);
  918. /* dir == 0,1,2,3 for an edge going L,U,R,D */
  919. int dir = (d->y == d2->y) + 2*(d->x+d->y > d2->x+d2->y);
  920. int ei = e->index;
  921. if (b->edges[ei]) {
  922. type |= 1 << dir;
  923. neighbours[n] = d2->index;
  924. n++;
  925. }
  926. }
  927. /*
  928. * Decide if it's a corner, and set the corner flag if so.
  929. */
  930. if (type != 0 && type != 0x5 && type != 0xA)
  931. type |= 0x10;
  932. if (type != b->vertextypes[j]) {
  933. /*
  934. * Recompute old neighbours, if any.
  935. */
  936. if (b->vertextypes[j]) {
  937. tdq_add(b->blackclues_todo, b->neighbour[0][j]);
  938. tdq_add(b->blackclues_todo, b->neighbour[1][j]);
  939. }
  940. /*
  941. * Recompute this vertex.
  942. */
  943. tdq_add(b->blackclues_todo, j);
  944. b->vertextypes[j] = type;
  945. /*
  946. * Recompute new neighbours, if any.
  947. */
  948. if (b->vertextypes[j]) {
  949. b->neighbour[0][j] = neighbours[0];
  950. b->neighbour[1][j] = neighbours[1];
  951. tdq_add(b->blackclues_todo, b->neighbour[0][j]);
  952. tdq_add(b->blackclues_todo, b->neighbour[1][j]);
  953. }
  954. }
  955. }
  956. /*
  957. * Go through the list of vertices which we must check to see
  958. * if they're black clue sites. Each one is a black clue site
  959. * iff it is a corner and its loop neighbours are non-corners.
  960. * Adjust the running total of black clues we've counted.
  961. */
  962. while ((j = tdq_remove(b->blackclues_todo)) >= 0) {
  963. ctx->score -= b->blackclues[j];
  964. b->blackclues[j] = ((b->vertextypes[j] & 0x10) &&
  965. !((b->vertextypes[b->neighbour[0][j]] |
  966. b->vertextypes[b->neighbour[1][j]])
  967. & 0x10));
  968. ctx->score += b->blackclues[j];
  969. }
  970. }
  971. return ctx->score;
  972. }
  973. static void pearl_loopgen(int w, int h, char *lines, random_state *rs)
  974. {
  975. grid *g = grid_new(GRID_SQUARE, w-1, h-1, NULL);
  976. char *board = snewn(g->num_faces, char);
  977. int i, s = g->tilesize;
  978. struct pearl_loopgen_bias_ctx biasctx;
  979. memset(lines, 0, w*h);
  980. /*
  981. * Initialise the context for the bias function. Initially we fill
  982. * all the to-do lists, so that the first call will scan
  983. * everything; thereafter the lists stay empty so we make
  984. * incremental changes.
  985. */
  986. biasctx.g = g;
  987. biasctx.faces = snewn(g->num_faces, char);
  988. biasctx.faces_todo = tdq_new(g->num_faces);
  989. tdq_fill(biasctx.faces_todo);
  990. biasctx.score = 0;
  991. memset(biasctx.faces, FACE_GREY, g->num_faces);
  992. for (i = 0; i < 2; i++) {
  993. biasctx.boundaries[i].edges = snewn(g->num_edges, bool);
  994. memset(biasctx.boundaries[i].edges, 0, g->num_edges * sizeof(bool));
  995. biasctx.boundaries[i].edges_todo = tdq_new(g->num_edges);
  996. tdq_fill(biasctx.boundaries[i].edges_todo);
  997. biasctx.boundaries[i].vertextypes = snewn(g->num_dots, char);
  998. memset(biasctx.boundaries[i].vertextypes, 0, g->num_dots);
  999. biasctx.boundaries[i].neighbour[0] = snewn(g->num_dots, int);
  1000. biasctx.boundaries[i].neighbour[1] = snewn(g->num_dots, int);
  1001. biasctx.boundaries[i].vertextypes_todo = tdq_new(g->num_dots);
  1002. tdq_fill(biasctx.boundaries[i].vertextypes_todo);
  1003. biasctx.boundaries[i].blackclues = snewn(g->num_dots, char);
  1004. memset(biasctx.boundaries[i].blackclues, 0, g->num_dots);
  1005. biasctx.boundaries[i].blackclues_todo = tdq_new(g->num_dots);
  1006. tdq_fill(biasctx.boundaries[i].blackclues_todo);
  1007. }
  1008. biasctx.boundaries[0].colour = FACE_WHITE;
  1009. biasctx.boundaries[1].colour = FACE_BLACK;
  1010. generate_loop(g, board, rs, pearl_loopgen_bias, &biasctx);
  1011. sfree(biasctx.faces);
  1012. tdq_free(biasctx.faces_todo);
  1013. for (i = 0; i < 2; i++) {
  1014. sfree(biasctx.boundaries[i].edges);
  1015. tdq_free(biasctx.boundaries[i].edges_todo);
  1016. sfree(biasctx.boundaries[i].vertextypes);
  1017. sfree(biasctx.boundaries[i].neighbour[0]);
  1018. sfree(biasctx.boundaries[i].neighbour[1]);
  1019. tdq_free(biasctx.boundaries[i].vertextypes_todo);
  1020. sfree(biasctx.boundaries[i].blackclues);
  1021. tdq_free(biasctx.boundaries[i].blackclues_todo);
  1022. }
  1023. for (i = 0; i < g->num_edges; i++) {
  1024. grid_edge *e = g->edges[i];
  1025. enum face_colour c1 = FACE_COLOUR(e->face1);
  1026. enum face_colour c2 = FACE_COLOUR(e->face2);
  1027. assert(c1 != FACE_GREY);
  1028. assert(c2 != FACE_GREY);
  1029. if (c1 != c2) {
  1030. /* This grid edge is on the loop: lay line along it */
  1031. int x1 = e->dot1->x/s, y1 = e->dot1->y/s;
  1032. int x2 = e->dot2->x/s, y2 = e->dot2->y/s;
  1033. /* (x1,y1) and (x2,y2) are now in our grid coords (0-w,0-h). */
  1034. if (x1 == x2) {
  1035. if (y1 > y2) SWAP(y1,y2);
  1036. assert(y1+1 == y2);
  1037. lines[y1*w+x1] |= D;
  1038. lines[y2*w+x1] |= U;
  1039. } else if (y1 == y2) {
  1040. if (x1 > x2) SWAP(x1,x2);
  1041. assert(x1+1 == x2);
  1042. lines[y1*w+x1] |= R;
  1043. lines[y1*w+x2] |= L;
  1044. } else
  1045. assert(!"grid with diagonal coords?!");
  1046. }
  1047. }
  1048. grid_free(g);
  1049. sfree(board);
  1050. #if defined LOOPGEN_DIAGNOSTICS && !defined GENERATION_DIAGNOSTICS
  1051. printf("as returned:\n");
  1052. for (y = 0; y < h; y++) {
  1053. for (x = 0; x < w; x++) {
  1054. int type = lines[y*w+x];
  1055. char s[5], *p = s;
  1056. if (type & L) *p++ = 'L';
  1057. if (type & R) *p++ = 'R';
  1058. if (type & U) *p++ = 'U';
  1059. if (type & D) *p++ = 'D';
  1060. *p = '\0';
  1061. printf("%3s", s);
  1062. }
  1063. printf("\n");
  1064. }
  1065. printf("\n");
  1066. #endif
  1067. }
  1068. static int new_clues(const game_params *params, random_state *rs,
  1069. char *clues, char *grid)
  1070. {
  1071. int w = params->w, h = params->h, diff = params->difficulty;
  1072. int ngen = 0, x, y, d, ret, i;
  1073. /*
  1074. * Difficulty exception: 5x5 Tricky is not generable (the
  1075. * generator will spin forever trying) and so we fudge it to Easy.
  1076. */
  1077. if (w == 5 && h == 5 && diff > DIFF_EASY)
  1078. diff = DIFF_EASY;
  1079. while (1) {
  1080. ngen++;
  1081. pearl_loopgen(w, h, grid, rs);
  1082. #ifdef GENERATION_DIAGNOSTICS
  1083. printf("grid array:\n");
  1084. for (y = 0; y < h; y++) {
  1085. for (x = 0; x < w; x++) {
  1086. int type = grid[y*w+x];
  1087. char s[5], *p = s;
  1088. if (type & L) *p++ = 'L';
  1089. if (type & R) *p++ = 'R';
  1090. if (type & U) *p++ = 'U';
  1091. if (type & D) *p++ = 'D';
  1092. *p = '\0';
  1093. printf("%2s ", s);
  1094. }
  1095. printf("\n");
  1096. }
  1097. printf("\n");
  1098. #endif
  1099. /*
  1100. * Set up the maximal clue array.
  1101. */
  1102. for (y = 0; y < h; y++)
  1103. for (x = 0; x < w; x++) {
  1104. int type = grid[y*w+x];
  1105. clues[y*w+x] = NOCLUE;
  1106. if ((bLR|bUD) & (1 << type)) {
  1107. /*
  1108. * This is a straight; see if it's a viable
  1109. * candidate for a straight clue. It qualifies if
  1110. * at least one of the squares it connects to is a
  1111. * corner.
  1112. */
  1113. for (d = 1; d <= 8; d += d) if (type & d) {
  1114. int xx = x + DX(d), yy = y + DY(d);
  1115. assert(xx >= 0 && xx < w && yy >= 0 && yy < h);
  1116. if ((bLU|bLD|bRU|bRD) & (1 << grid[yy*w+xx]))
  1117. break;
  1118. }
  1119. if (d <= 8) /* we found one */
  1120. clues[y*w+x] = STRAIGHT;
  1121. } else if ((bLU|bLD|bRU|bRD) & (1 << type)) {
  1122. /*
  1123. * This is a corner; see if it's a viable candidate
  1124. * for a corner clue. It qualifies if all the
  1125. * squares it connects to are straights.
  1126. */
  1127. for (d = 1; d <= 8; d += d) if (type & d) {
  1128. int xx = x + DX(d), yy = y + DY(d);
  1129. assert(xx >= 0 && xx < w && yy >= 0 && yy < h);
  1130. if (!((bLR|bUD) & (1 << grid[yy*w+xx])))
  1131. break;
  1132. }
  1133. if (d > 8) /* we didn't find a counterexample */
  1134. clues[y*w+x] = CORNER;
  1135. }
  1136. }
  1137. #ifdef GENERATION_DIAGNOSTICS
  1138. printf("clue array:\n");
  1139. for (y = 0; y < h; y++) {
  1140. for (x = 0; x < w; x++) {
  1141. printf("%c", " *O"[(unsigned char)clues[y*w+x]]);
  1142. }
  1143. printf("\n");
  1144. }
  1145. printf("\n");
  1146. #endif
  1147. if (!params->nosolve) {
  1148. int *cluespace, *straights, *corners;
  1149. int nstraights, ncorners, nstraightpos, ncornerpos;
  1150. /*
  1151. * See if we can solve the puzzle just like this.
  1152. */
  1153. ret = pearl_solve(w, h, clues, grid, diff, false);
  1154. assert(ret > 0); /* shouldn't be inconsistent! */
  1155. if (ret != 1)
  1156. continue; /* go round and try again */
  1157. /*
  1158. * Check this puzzle isn't too easy.
  1159. */
  1160. if (diff > DIFF_EASY) {
  1161. ret = pearl_solve(w, h, clues, grid, diff-1, false);
  1162. assert(ret > 0);
  1163. if (ret == 1)
  1164. continue; /* too easy: try again */
  1165. }
  1166. /*
  1167. * Now shuffle the grid points and gradually remove the
  1168. * clues to find a minimal set which still leaves the
  1169. * puzzle soluble.
  1170. *
  1171. * We preferentially attempt to remove whichever type of
  1172. * clue is currently most numerous, to combat a general
  1173. * tendency of plain random generation to bias in favour
  1174. * of many white clues and few black.
  1175. *
  1176. * 'nstraights' and 'ncorners' count the number of clues
  1177. * of each type currently remaining in the grid;
  1178. * 'nstraightpos' and 'ncornerpos' count the clues of each
  1179. * type we have left to try to remove. (Clues which we
  1180. * have tried and failed to remove are counted by the
  1181. * former but not the latter.)
  1182. */
  1183. cluespace = snewn(w*h, int);
  1184. straights = cluespace;
  1185. nstraightpos = 0;
  1186. for (i = 0; i < w*h; i++)
  1187. if (clues[i] == STRAIGHT)
  1188. straights[nstraightpos++] = i;
  1189. corners = straights + nstraightpos;
  1190. ncornerpos = 0;
  1191. for (i = 0; i < w*h; i++)
  1192. if (clues[i] == STRAIGHT)
  1193. corners[ncornerpos++] = i;
  1194. nstraights = nstraightpos;
  1195. ncorners = ncornerpos;
  1196. shuffle(straights, nstraightpos, sizeof(*straights), rs);
  1197. shuffle(corners, ncornerpos, sizeof(*corners), rs);
  1198. while (nstraightpos > 0 || ncornerpos > 0) {
  1199. int cluepos;
  1200. int clue;
  1201. /*
  1202. * Decide which clue to try to remove next. If both
  1203. * types are available, we choose whichever kind is
  1204. * currently overrepresented; otherwise we take
  1205. * whatever we can get.
  1206. */
  1207. if (nstraightpos > 0 && ncornerpos > 0) {
  1208. if (nstraights >= ncorners)
  1209. cluepos = straights[--nstraightpos];
  1210. else
  1211. cluepos = straights[--ncornerpos];
  1212. } else {
  1213. if (nstraightpos > 0)
  1214. cluepos = straights[--nstraightpos];
  1215. else
  1216. cluepos = straights[--ncornerpos];
  1217. }
  1218. y = cluepos / w;
  1219. x = cluepos % w;
  1220. clue = clues[y*w+x];
  1221. clues[y*w+x] = 0; /* try removing this clue */
  1222. ret = pearl_solve(w, h, clues, grid, diff, false);
  1223. assert(ret > 0);
  1224. if (ret != 1)
  1225. clues[y*w+x] = clue; /* oops, put it back again */
  1226. }
  1227. sfree(cluespace);
  1228. }
  1229. #ifdef FINISHED_PUZZLE
  1230. printf("clue array:\n");
  1231. for (y = 0; y < h; y++) {
  1232. for (x = 0; x < w; x++) {
  1233. printf("%c", " *O"[(unsigned char)clues[y*w+x]]);
  1234. }
  1235. printf("\n");
  1236. }
  1237. printf("\n");
  1238. #endif
  1239. break; /* got it */
  1240. }
  1241. debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h));
  1242. return ngen;
  1243. }
  1244. static char *new_game_desc(const game_params *params, random_state *rs,
  1245. char **aux, bool interactive)
  1246. {
  1247. char *grid, *clues;
  1248. char *desc;
  1249. int w = params->w, h = params->h, i, j;
  1250. grid = snewn(w*h, char);
  1251. clues = snewn(w*h, char);
  1252. new_clues(params, rs, clues, grid);
  1253. desc = snewn(w * h + 1, char);
  1254. for (i = j = 0; i < w*h; i++) {
  1255. if (clues[i] == NOCLUE && j > 0 &&
  1256. desc[j-1] >= 'a' && desc[j-1] < 'z')
  1257. desc[j-1]++;
  1258. else if (clues[i] == NOCLUE)
  1259. desc[j++] = 'a';
  1260. else if (clues[i] == CORNER)
  1261. desc[j++] = 'B';
  1262. else if (clues[i] == STRAIGHT)
  1263. desc[j++] = 'W';
  1264. }
  1265. desc[j] = '\0';
  1266. *aux = snewn(w*h+1, char);
  1267. for (i = 0; i < w*h; i++)
  1268. (*aux)[i] = (grid[i] < 10) ? (grid[i] + '0') : (grid[i] + 'A' - 10);
  1269. (*aux)[w*h] = '\0';
  1270. sfree(grid);
  1271. sfree(clues);
  1272. return desc;
  1273. }
  1274. static const char *validate_desc(const game_params *params, const char *desc)
  1275. {
  1276. int i, sizesofar;
  1277. const int totalsize = params->w * params->h;
  1278. sizesofar = 0;
  1279. for (i = 0; desc[i]; i++) {
  1280. if (desc[i] >= 'a' && desc[i] <= 'z')
  1281. sizesofar += desc[i] - 'a' + 1;
  1282. else if (desc[i] == 'B' || desc[i] == 'W')
  1283. sizesofar++;
  1284. else
  1285. return "unrecognised character in string";
  1286. }
  1287. if (sizesofar > totalsize)
  1288. return "string too long";
  1289. else if (sizesofar < totalsize)
  1290. return "string too short";
  1291. return NULL;
  1292. }
  1293. static game_state *new_game(midend *me, const game_params *params,
  1294. const char *desc)
  1295. {
  1296. game_state *state = snew(game_state);
  1297. int i, j, sz = params->w*params->h;
  1298. state->completed = false;
  1299. state->used_solve = false;
  1300. state->shared = snew(struct shared_state);
  1301. state->shared->w = params->w;
  1302. state->shared->h = params->h;
  1303. state->shared->sz = sz;
  1304. state->shared->refcnt = 1;
  1305. state->shared->clues = snewn(sz, char);
  1306. for (i = j = 0; desc[i]; i++) {
  1307. assert(j < sz);
  1308. if (desc[i] >= 'a' && desc[i] <= 'z') {
  1309. int n = desc[i] - 'a' + 1;
  1310. assert(j + n <= sz);
  1311. while (n-- > 0)
  1312. state->shared->clues[j++] = NOCLUE;
  1313. } else if (desc[i] == 'B') {
  1314. state->shared->clues[j++] = CORNER;
  1315. } else if (desc[i] == 'W') {
  1316. state->shared->clues[j++] = STRAIGHT;
  1317. }
  1318. }
  1319. state->lines = snewn(sz, char);
  1320. state->errors = snewn(sz, char);
  1321. state->marks = snewn(sz, char);
  1322. for (i = 0; i < sz; i++)
  1323. state->lines[i] = state->errors[i] = state->marks[i] = BLANK;
  1324. return state;
  1325. }
  1326. static game_state *dup_game(const game_state *state)
  1327. {
  1328. game_state *ret = snew(game_state);
  1329. int sz = state->shared->sz, i;
  1330. ret->shared = state->shared;
  1331. ret->completed = state->completed;
  1332. ret->used_solve = state->used_solve;
  1333. ++ret->shared->refcnt;
  1334. ret->lines = snewn(sz, char);
  1335. ret->errors = snewn(sz, char);
  1336. ret->marks = snewn(sz, char);
  1337. for (i = 0; i < sz; i++) {
  1338. ret->lines[i] = state->lines[i];
  1339. ret->errors[i] = state->errors[i];
  1340. ret->marks[i] = state->marks[i];
  1341. }
  1342. return ret;
  1343. }
  1344. static void free_game(game_state *state)
  1345. {
  1346. assert(state);
  1347. if (--state->shared->refcnt == 0) {
  1348. sfree(state->shared->clues);
  1349. sfree(state->shared);
  1350. }
  1351. sfree(state->lines);
  1352. sfree(state->errors);
  1353. sfree(state->marks);
  1354. sfree(state);
  1355. }
  1356. static char nbits[16] = { 0, 1, 1, 2,
  1357. 1, 2, 2, 3,
  1358. 1, 2, 2, 3,
  1359. 2, 3, 3, 4 };
  1360. #define NBITS(l) ( ((l) < 0 || (l) > 15) ? 4 : nbits[l] )
  1361. #define ERROR_CLUE 16
  1362. /* Returns false if the state is invalid. */
  1363. static bool dsf_update_completion(game_state *state, int ax, int ay, char dir,
  1364. DSF *dsf)
  1365. {
  1366. int w = state->shared->w /*, h = state->shared->h */;
  1367. int ac = ay*w+ax, bx, by, bc;
  1368. if (!(state->lines[ac] & dir)) return true; /* no link */
  1369. bx = ax + DX(dir); by = ay + DY(dir);
  1370. if (!INGRID(state, bx, by))
  1371. return false; /* should not have a link off grid */
  1372. bc = by*w+bx;
  1373. if (!(state->lines[bc] & F(dir)))
  1374. return false; /* should have reciprocal link */
  1375. if (!(state->lines[bc] & F(dir))) return true;
  1376. dsf_merge(dsf, ac, bc);
  1377. return true;
  1378. }
  1379. /* Returns false if the state is invalid. */
  1380. static bool check_completion(game_state *state, bool mark)
  1381. {
  1382. int w = state->shared->w, h = state->shared->h, x, y, i, d;
  1383. bool had_error = false;
  1384. DSF *dsf;
  1385. int *component_state;
  1386. int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize;
  1387. enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY };
  1388. if (mark) {
  1389. for (i = 0; i < w*h; i++) {
  1390. state->errors[i] = 0;
  1391. }
  1392. }
  1393. #define ERROR(x,y,e) do { had_error = true; if (mark) state->errors[(y)*w+(x)] |= (e); } while(0)
  1394. /*
  1395. * Analyse the solution into loops, paths and stranger things.
  1396. * Basic strategy here is all the same as in Loopy - see the big
  1397. * comment in loopy.c's check_completion() - and for exactly the
  1398. * same reasons, since Loopy and Pearl have basically the same
  1399. * form of expected solution.
  1400. */
  1401. dsf = dsf_new(w*h);
  1402. /* Build the dsf. */
  1403. for (x = 0; x < w; x++) {
  1404. for (y = 0; y < h; y++) {
  1405. if (!dsf_update_completion(state, x, y, R, dsf) ||
  1406. !dsf_update_completion(state, x, y, D, dsf)) {
  1407. dsf_free(dsf);
  1408. return false;
  1409. }
  1410. }
  1411. }
  1412. /* Initialise a state variable for each connected component. */
  1413. component_state = snewn(w*h, int);
  1414. for (i = 0; i < w*h; i++) {
  1415. if (dsf_canonify(dsf, i) == i)
  1416. component_state[i] = COMP_LOOP;
  1417. else
  1418. component_state[i] = COMP_NONE;
  1419. }
  1420. /*
  1421. * Classify components, and mark errors where a square has more
  1422. * than two line segments.
  1423. */
  1424. for (x = 0; x < w; x++) {
  1425. for (y = 0; y < h; y++) {
  1426. int type = state->lines[y*w+x];
  1427. int degree = NBITS(type);
  1428. int comp = dsf_canonify(dsf, y*w+x);
  1429. if (degree > 2) {
  1430. ERROR(x,y,type);
  1431. component_state[comp] = COMP_SILLY;
  1432. } else if (degree == 0) {
  1433. component_state[comp] = COMP_EMPTY;
  1434. } else if (degree == 1) {
  1435. if (component_state[comp] != COMP_SILLY)
  1436. component_state[comp] = COMP_PATH;
  1437. }
  1438. }
  1439. }
  1440. /* Count the components, and find the largest sensible one. */
  1441. nsilly = nloop = npath = 0;
  1442. total_pathsize = 0;
  1443. largest_comp = largest_size = -1;
  1444. for (i = 0; i < w*h; i++) {
  1445. if (component_state[i] == COMP_SILLY) {
  1446. nsilly++;
  1447. } else if (component_state[i] == COMP_PATH) {
  1448. total_pathsize += dsf_size(dsf, i);
  1449. npath = 1;
  1450. } else if (component_state[i] == COMP_LOOP) {
  1451. int this_size;
  1452. nloop++;
  1453. if ((this_size = dsf_size(dsf, i)) > largest_size) {
  1454. largest_comp = i;
  1455. largest_size = this_size;
  1456. }
  1457. }
  1458. }
  1459. if (largest_size < total_pathsize) {
  1460. largest_comp = -1; /* means the paths */
  1461. largest_size = total_pathsize;
  1462. }
  1463. if (nloop > 0 && nloop + npath > 1) {
  1464. /*
  1465. * If there are at least two sensible components including at
  1466. * least one loop, highlight every sensible component that is
  1467. * not the largest one.
  1468. */
  1469. for (i = 0; i < w*h; i++) {
  1470. int comp = dsf_canonify(dsf, i);
  1471. if ((component_state[comp] == COMP_PATH &&
  1472. -1 != largest_comp) ||
  1473. (component_state[comp] == COMP_LOOP &&
  1474. comp != largest_comp))
  1475. ERROR(i%w, i/w, state->lines[i]);
  1476. }
  1477. }
  1478. /* Now we've finished with the dsf and component states. The only
  1479. * thing we'll need to remember later on is whether all edges were
  1480. * part of a single loop, for which our counter variables
  1481. * nsilly,nloop,npath are enough. */
  1482. sfree(component_state);
  1483. dsf_free(dsf);
  1484. /*
  1485. * Check that no clues are contradicted. This code is similar to
  1486. * the code that sets up the maximal clue array for any given
  1487. * loop.
  1488. */
  1489. for (x = 0; x < w; x++) {
  1490. for (y = 0; y < h; y++) {
  1491. int type = state->lines[y*w+x];
  1492. if (state->shared->clues[y*w+x] == CORNER) {
  1493. /* Supposed to be a corner: will find a contradiction if
  1494. * it actually contains a straight line, or if it touches any
  1495. * corners. */
  1496. if ((bLR|bUD) & (1 << type)) {
  1497. ERROR(x,y,ERROR_CLUE); /* actually straight */
  1498. }
  1499. for (d = 1; d <= 8; d += d) if (type & d) {
  1500. int xx = x + DX(d), yy = y + DY(d);
  1501. if (!INGRID(state, xx, yy)) {
  1502. ERROR(x,y,d); /* leads off grid */
  1503. } else {
  1504. if ((bLU|bLD|bRU|bRD) & (1 << state->lines[yy*w+xx])) {
  1505. ERROR(x,y,ERROR_CLUE); /* touches corner */
  1506. }
  1507. }
  1508. }
  1509. } else if (state->shared->clues[y*w+x] == STRAIGHT) {
  1510. /* Supposed to be straight: will find a contradiction if
  1511. * it actually contains a corner, or if it only touches
  1512. * straight lines. */
  1513. if ((bLU|bLD|bRU|bRD) & (1 << type)) {
  1514. ERROR(x,y,ERROR_CLUE); /* actually a corner */
  1515. }
  1516. i = 0;
  1517. for (d = 1; d <= 8; d += d) if (type & d) {
  1518. int xx = x + DX(d), yy = y + DY(d);
  1519. if (!INGRID(state, xx, yy)) {
  1520. ERROR(x,y,d); /* leads off grid */
  1521. } else {
  1522. if ((bLR|bUD) & (1 << state->lines[yy*w+xx]))
  1523. i++; /* a straight */
  1524. }
  1525. }
  1526. if (i >= 2 && NBITS(type) >= 2) {
  1527. ERROR(x,y,ERROR_CLUE); /* everything touched is straight */
  1528. }
  1529. }
  1530. }
  1531. }
  1532. if (nloop == 1 && nsilly == 0 && npath == 0) {
  1533. /*
  1534. * If there's exactly one loop (so that the puzzle is at least
  1535. * potentially complete), we need to ensure it hasn't left any
  1536. * clue out completely.
  1537. */
  1538. for (x = 0; x < w; x++) {
  1539. for (y = 0; y < h; y++) {
  1540. if (state->lines[y*w+x] == BLANK) {
  1541. if (state->shared->clues[y*w+x] != NOCLUE) {
  1542. /* the loop doesn't include this clue square! */
  1543. ERROR(x, y, ERROR_CLUE);
  1544. }
  1545. }
  1546. }
  1547. }
  1548. /*
  1549. * But if not, then we're done!
  1550. */
  1551. if (!had_error)
  1552. state->completed = true;
  1553. }
  1554. return true;
  1555. }
  1556. /* completion check:
  1557. *
  1558. * - no clues must be contradicted (highlight clue itself in error if so)
  1559. * - if there is a closed loop it must include every line segment laid
  1560. * - if there's a smaller closed loop then highlight whole loop as error
  1561. * - no square must have more than 2 lines radiating from centre point
  1562. * (highlight all lines in that square as error if so)
  1563. */
  1564. static char *solve_for_diff(game_state *state, char *old_lines, char *new_lines)
  1565. {
  1566. int w = state->shared->w, h = state->shared->h, i;
  1567. char *move = snewn(w*h*40, char), *p = move;
  1568. *p++ = 'S';
  1569. for (i = 0; i < w*h; i++) {
  1570. if (old_lines[i] != new_lines[i]) {
  1571. p += sprintf(p, ";R%d,%d,%d", new_lines[i], i%w, i/w);
  1572. }
  1573. }
  1574. *p++ = '\0';
  1575. move = sresize(move, p - move, char);
  1576. return move;
  1577. }
  1578. static char *solve_game(const game_state *state, const game_state *currstate,
  1579. const char *aux, const char **error)
  1580. {
  1581. game_state *solved = dup_game(state);
  1582. int i, ret, sz = state->shared->sz;
  1583. char *move;
  1584. if (aux) {
  1585. for (i = 0; i < sz; i++) {
  1586. if (aux[i] >= '0' && aux[i] <= '9')
  1587. solved->lines[i] = aux[i] - '0';
  1588. else if (aux[i] >= 'A' && aux[i] <= 'F')
  1589. solved->lines[i] = aux[i] - 'A' + 10;
  1590. else {
  1591. *error = "invalid char in aux";
  1592. move = NULL;
  1593. goto done;
  1594. }
  1595. }
  1596. ret = 1;
  1597. } else {
  1598. /* Try to solve with present (half-solved) state first: if there's no
  1599. * solution from there go back to original state. */
  1600. ret = pearl_solve(currstate->shared->w, currstate->shared->h,
  1601. currstate->shared->clues, solved->lines,
  1602. DIFFCOUNT, false);
  1603. if (ret < 1)
  1604. ret = pearl_solve(state->shared->w, state->shared->h,
  1605. state->shared->clues, solved->lines,
  1606. DIFFCOUNT, false);
  1607. }
  1608. if (ret < 1) {
  1609. *error = "Unable to find solution";
  1610. move = NULL;
  1611. } else {
  1612. move = solve_for_diff(solved, currstate->lines, solved->lines);
  1613. }
  1614. done:
  1615. free_game(solved);
  1616. return move;
  1617. }
  1618. static bool game_can_format_as_text_now(const game_params *params)
  1619. {
  1620. return true;
  1621. }
  1622. static char *game_text_format(const game_state *state)
  1623. {
  1624. int w = state->shared->w, h = state->shared->h, cw = 4, ch = 2;
  1625. int gw = cw*(w-1) + 2, gh = ch*(h-1) + 1, len = gw * gh, r, c, j;
  1626. char *board = snewn(len + 1, char);
  1627. assert(board);
  1628. memset(board, ' ', len);
  1629. for (r = 0; r < h; ++r) {
  1630. for (c = 0; c < w; ++c) {
  1631. int i = r*w + c, cell = r*ch*gw + c*cw;
  1632. board[cell] = "+BW"[(unsigned char)state->shared->clues[i]];
  1633. if (c < w - 1 && (state->lines[i] & R || state->lines[i+1] & L))
  1634. memset(board + cell + 1, '-', cw - 1);
  1635. if (r < h - 1 && (state->lines[i] & D || state->lines[i+w] & U))
  1636. for (j = 1; j < ch; ++j) board[cell + j*gw] = '|';
  1637. if (c < w - 1 && (state->marks[i] & R || state->marks[i+1] & L))
  1638. board[cell + cw/2] = 'x';
  1639. if (r < h - 1 && (state->marks[i] & D || state->marks[i+w] & U))
  1640. board[cell + (ch/2 * gw)] = 'x';
  1641. }
  1642. for (j = 0; j < (r == h - 1 ? 1 : ch); ++j)
  1643. board[r*ch*gw + (gw - 1) + j*gw] = '\n';
  1644. }
  1645. board[len] = '\0';
  1646. return board;
  1647. }
  1648. struct game_ui {
  1649. int *dragcoords; /* list of (y*w+x) coords in drag so far */
  1650. int ndragcoords; /* number of entries in dragcoords.
  1651. * 0 = click but no drag yet. -1 = no drag at all */
  1652. int clickx, clicky; /* pixel position of initial click */
  1653. int curx, cury; /* grid position of keyboard cursor */
  1654. bool cursor_active; /* true iff cursor is shown */
  1655. /*
  1656. * User preference: general visual style of the GUI. GUI_MASYU is
  1657. * how this puzzle is traditionally presented, with clue dots in
  1658. * the middle of grid squares, and the solution loop connecting
  1659. * square-centres. GUI_LOOPY shifts the grid by half a square in
  1660. * each direction, so that the clue dots are at _vertices_ of the
  1661. * grid and the solution loop follows the grid edges, which you
  1662. * could argue is more logical.
  1663. */
  1664. enum { GUI_MASYU, GUI_LOOPY } gui_style;
  1665. };
  1666. static void legacy_prefs_override(struct game_ui *ui_out)
  1667. {
  1668. static bool initialised = false;
  1669. static int gui_style = -1;
  1670. if (!initialised) {
  1671. initialised = true;
  1672. switch (getenv_bool("PEARL_GUI_LOOPY", -1)) {
  1673. case 0:
  1674. gui_style = GUI_MASYU;
  1675. break;
  1676. case 1:
  1677. gui_style = GUI_LOOPY;
  1678. break;
  1679. }
  1680. }
  1681. if (gui_style != -1)
  1682. ui_out->gui_style = gui_style;
  1683. }
  1684. static game_ui *new_ui(const game_state *state)
  1685. {
  1686. game_ui *ui = snew(game_ui);
  1687. ui->ndragcoords = -1;
  1688. ui->dragcoords = state ? snewn(state->shared->sz, int) : NULL;
  1689. ui->cursor_active = getenv_bool("PUZZLES_SHOW_CURSOR", false);
  1690. ui->curx = ui->cury = 0;
  1691. ui->gui_style = GUI_MASYU;
  1692. legacy_prefs_override(ui);
  1693. return ui;
  1694. }
  1695. static void free_ui(game_ui *ui)
  1696. {
  1697. sfree(ui->dragcoords);
  1698. sfree(ui);
  1699. }
  1700. static config_item *get_prefs(game_ui *ui)
  1701. {
  1702. config_item *ret;
  1703. ret = snewn(2, config_item);
  1704. ret[0].name = "Puzzle appearance";
  1705. ret[0].kw = "appearance";
  1706. ret[0].type = C_CHOICES;
  1707. ret[0].u.choices.choicenames = ":Traditional:Loopy-style";
  1708. ret[0].u.choices.choicekws = ":traditional:loopy";
  1709. ret[0].u.choices.selected = ui->gui_style;
  1710. ret[1].name = NULL;
  1711. ret[1].type = C_END;
  1712. return ret;
  1713. }
  1714. static void set_prefs(game_ui *ui, const config_item *cfg)
  1715. {
  1716. ui->gui_style = cfg[0].u.choices.selected;
  1717. }
  1718. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  1719. const game_state *newstate)
  1720. {
  1721. }
  1722. static const char *current_key_label(const game_ui *ui,
  1723. const game_state *state, int button)
  1724. {
  1725. if (IS_CURSOR_SELECT(button) && ui->cursor_active) {
  1726. if (button == CURSOR_SELECT) {
  1727. if (ui->ndragcoords == -1) return "Start";
  1728. return "Stop";
  1729. }
  1730. if (button == CURSOR_SELECT2 && ui->ndragcoords >= 0)
  1731. return "Cancel";
  1732. }
  1733. return "";
  1734. }
  1735. #define PREFERRED_TILE_SIZE 31
  1736. #define HALFSZ (ds->halfsz)
  1737. #define TILE_SIZE (ds->halfsz*2 + 1)
  1738. #define BORDER ((ui->gui_style == GUI_LOOPY) ? (TILE_SIZE/8) : (TILE_SIZE/2))
  1739. #define BORDER_WIDTH (max(TILE_SIZE / 32, 1))
  1740. #define COORD(x) ( (x) * TILE_SIZE + BORDER )
  1741. #define CENTERED_COORD(x) ( COORD(x) + TILE_SIZE/2 )
  1742. #define FROMCOORD(x) ( ((x) < BORDER) ? -1 : ( ((x) - BORDER) / TILE_SIZE) )
  1743. #define DS_ESHIFT 4 /* R/U/L/D shift, for error flags */
  1744. #define DS_DSHIFT 8 /* R/U/L/D shift, for drag-in-progress flags */
  1745. #define DS_MSHIFT 12 /* shift for no-line mark */
  1746. #define DS_ERROR_CLUE (1 << 20)
  1747. #define DS_FLASH (1 << 21)
  1748. #define DS_CURSOR (1 << 22)
  1749. struct game_drawstate {
  1750. int halfsz;
  1751. bool started;
  1752. int w, h, sz;
  1753. unsigned int *lflags; /* size w*h */
  1754. char *draglines; /* size w*h; lines flipped by current drag */
  1755. };
  1756. /*
  1757. * Routine shared between multiple callers to work out the intended
  1758. * effect of a drag path on the grid.
  1759. *
  1760. * Call it in a loop, like this:
  1761. *
  1762. * bool clearing = true;
  1763. * for (i = 0; i < ui->ndragcoords - 1; i++) {
  1764. * int sx, sy, dx, dy, dir, oldstate, newstate;
  1765. * interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
  1766. * &dir, &oldstate, &newstate);
  1767. *
  1768. * [do whatever is needed to handle the fact that the drag
  1769. * wants the edge from sx,sy to dx,dy (heading in direction
  1770. * 'dir' at the sx,sy end) to be changed from state oldstate
  1771. * to state newstate, each of which equals either 0 or dir]
  1772. * }
  1773. */
  1774. static void interpret_ui_drag(const game_state *state, const game_ui *ui,
  1775. bool *clearing, int i, int *sx, int *sy,
  1776. int *dx, int *dy, int *dir,
  1777. int *oldstate, int *newstate)
  1778. {
  1779. int w = state->shared->w;
  1780. int sp = ui->dragcoords[i], dp = ui->dragcoords[i+1];
  1781. *sy = sp/w;
  1782. *sx = sp%w;
  1783. *dy = dp/w;
  1784. *dx = dp%w;
  1785. *dir = (*dy>*sy ? D : *dy<*sy ? U : *dx>*sx ? R : L);
  1786. *oldstate = state->lines[sp] & *dir;
  1787. if (*oldstate) {
  1788. /*
  1789. * The edge we've dragged over was previously
  1790. * present. Set it to absent, unless we've already
  1791. * stopped doing that.
  1792. */
  1793. *newstate = *clearing ? 0 : *dir;
  1794. } else {
  1795. /*
  1796. * The edge we've dragged over was previously
  1797. * absent. Set it to present, and cancel the
  1798. * 'clearing' flag so that all subsequent edges in
  1799. * the drag are set rather than cleared.
  1800. */
  1801. *newstate = *dir;
  1802. *clearing = false;
  1803. }
  1804. }
  1805. static void update_ui_drag(const game_state *state, game_ui *ui,
  1806. int gx, int gy)
  1807. {
  1808. int /* sz = state->shared->sz, */ w = state->shared->w;
  1809. int i, ox, oy, pos;
  1810. int lastpos;
  1811. if (!INGRID(state, gx, gy))
  1812. return; /* square is outside grid */
  1813. if (ui->ndragcoords < 0)
  1814. return; /* drag not in progress anyway */
  1815. pos = gy * w + gx;
  1816. lastpos = ui->dragcoords[ui->ndragcoords > 0 ? ui->ndragcoords-1 : 0];
  1817. if (pos == lastpos)
  1818. return; /* same square as last visited one */
  1819. /* Drag confirmed, if it wasn't already. */
  1820. if (ui->ndragcoords == 0)
  1821. ui->ndragcoords = 1;
  1822. /*
  1823. * Dragging the mouse into a square that's already been visited by
  1824. * the drag path so far has the effect of truncating the path back
  1825. * to that square, so a player can back out part of an uncommitted
  1826. * drag without having to let go of the mouse.
  1827. *
  1828. * An exception is that you're allowed to drag round in a loop
  1829. * back to the very start of the drag, provided that doesn't
  1830. * create a vertex of the wrong degree. This allows a player who's
  1831. * after an extra challenge to draw the entire loop in a single
  1832. * drag, without it cancelling itself just before release.
  1833. */
  1834. for (i = 1; i < ui->ndragcoords; i++)
  1835. if (pos == ui->dragcoords[i]) {
  1836. ui->ndragcoords = i+1;
  1837. return;
  1838. }
  1839. if (pos == ui->dragcoords[0]) {
  1840. /* More complex check for a loop-shaped drag, which has to go
  1841. * through interpret_ui_drag to decide on the final degree of
  1842. * the start/end vertex. */
  1843. ui->dragcoords[ui->ndragcoords] = pos;
  1844. bool clearing = true;
  1845. int lines = state->lines[pos] & (L|R|U|D);
  1846. for (i = 0; i < ui->ndragcoords; i++) {
  1847. int sx, sy, dx, dy, dir, oldstate, newstate;
  1848. interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
  1849. &dir, &oldstate, &newstate);
  1850. if (sx == gx && sy == gy)
  1851. lines ^= (oldstate ^ newstate);
  1852. if (dx == gx && dy == gy)
  1853. lines ^= (F(oldstate) ^ F(newstate));
  1854. }
  1855. if (NBITS(lines) > 2) {
  1856. /* Bad vertex degree: fall back to the backtracking behaviour. */
  1857. ui->ndragcoords = 1;
  1858. return;
  1859. }
  1860. }
  1861. /*
  1862. * Otherwise, dragging the mouse into a square that's a rook-move
  1863. * away from the last one on the path extends the path.
  1864. */
  1865. oy = ui->dragcoords[ui->ndragcoords-1] / w;
  1866. ox = ui->dragcoords[ui->ndragcoords-1] % w;
  1867. if (ox == gx || oy == gy) {
  1868. int dx = (gx < ox ? -1 : gx > ox ? +1 : 0);
  1869. int dy = (gy < oy ? -1 : gy > oy ? +1 : 0);
  1870. int dir = (dy>0 ? D : dy<0 ? U : dx>0 ? R : L);
  1871. while (ox != gx || oy != gy) {
  1872. /*
  1873. * If the drag attempts to cross a 'no line here' mark,
  1874. * stop there. We physically don't allow the user to drag
  1875. * over those marks.
  1876. */
  1877. if (state->marks[oy*w+ox] & dir)
  1878. break;
  1879. ox += dx;
  1880. oy += dy;
  1881. ui->dragcoords[ui->ndragcoords++] = oy * w + ox;
  1882. }
  1883. }
  1884. /*
  1885. * Failing that, we do nothing at all: if the user has dragged
  1886. * diagonally across the board, they'll just have to return the
  1887. * mouse to the last known position and do whatever they meant to
  1888. * do again, more slowly and clearly.
  1889. */
  1890. }
  1891. static char *mark_in_direction(const game_state *state, int x, int y, int dir,
  1892. bool primary, char *buf)
  1893. {
  1894. int w = state->shared->w /*, h = state->shared->h, sz = state->shared->sz */;
  1895. int x2 = x + DX(dir);
  1896. int y2 = y + DY(dir);
  1897. int dir2 = F(dir);
  1898. char ch = primary ? 'F' : 'M', *other;
  1899. if (!INGRID(state, x, y) || !INGRID(state, x2, y2)) return MOVE_UI_UPDATE;
  1900. /* disallow laying a mark over a line, or vice versa. */
  1901. other = primary ? state->marks : state->lines;
  1902. if (other[y*w+x] & dir || other[y2*w+x2] & dir2) return MOVE_UI_UPDATE;
  1903. sprintf(buf, "%c%d,%d,%d;%c%d,%d,%d", ch, dir, x, y, ch, dir2, x2, y2);
  1904. return dupstr(buf);
  1905. }
  1906. #define KEY_DIRECTION(btn) (\
  1907. (btn) == CURSOR_DOWN ? D : (btn) == CURSOR_UP ? U :\
  1908. (btn) == CURSOR_LEFT ? L : R)
  1909. static char *interpret_move(const game_state *state, game_ui *ui,
  1910. const game_drawstate *ds,
  1911. int x, int y, int button)
  1912. {
  1913. int w = state->shared->w, h = state->shared->h /*, sz = state->shared->sz */;
  1914. int gx = FROMCOORD(x), gy = FROMCOORD(y), i;
  1915. bool release = false;
  1916. char tmpbuf[80];
  1917. bool shift = button & MOD_SHFT, control = button & MOD_CTRL;
  1918. button &= ~MOD_MASK;
  1919. if (IS_MOUSE_DOWN(button)) {
  1920. ui->cursor_active = false;
  1921. if (!INGRID(state, gx, gy)) {
  1922. ui->ndragcoords = -1;
  1923. return MOVE_UI_UPDATE;
  1924. }
  1925. ui->clickx = x; ui->clicky = y;
  1926. ui->dragcoords[0] = gy * w + gx;
  1927. ui->ndragcoords = 0; /* will be 1 once drag is confirmed */
  1928. return MOVE_UI_UPDATE;
  1929. }
  1930. if (button == LEFT_DRAG && ui->ndragcoords >= 0) {
  1931. update_ui_drag(state, ui, gx, gy);
  1932. return MOVE_UI_UPDATE;
  1933. }
  1934. if (IS_MOUSE_RELEASE(button)) release = true;
  1935. if (IS_CURSOR_MOVE(button)) {
  1936. if (!ui->cursor_active) {
  1937. ui->cursor_active = true;
  1938. } else if (control || shift) {
  1939. char *move;
  1940. if (ui->ndragcoords > 0) return MOVE_NO_EFFECT;
  1941. ui->ndragcoords = -1;
  1942. move = mark_in_direction(state, ui->curx, ui->cury,
  1943. KEY_DIRECTION(button), control, tmpbuf);
  1944. if (control && !shift && *move)
  1945. move_cursor(button, &ui->curx, &ui->cury, w, h, false);
  1946. return move;
  1947. } else {
  1948. move_cursor(button, &ui->curx, &ui->cury, w, h, false);
  1949. if (ui->ndragcoords >= 0)
  1950. update_ui_drag(state, ui, ui->curx, ui->cury);
  1951. }
  1952. return MOVE_UI_UPDATE;
  1953. }
  1954. if (IS_CURSOR_SELECT(button)) {
  1955. if (!ui->cursor_active) {
  1956. ui->cursor_active = true;
  1957. return MOVE_UI_UPDATE;
  1958. } else if (button == CURSOR_SELECT) {
  1959. if (ui->ndragcoords == -1) {
  1960. ui->ndragcoords = 0;
  1961. ui->dragcoords[0] = ui->cury * w + ui->curx;
  1962. ui->clickx = CENTERED_COORD(ui->curx);
  1963. ui->clicky = CENTERED_COORD(ui->cury);
  1964. return MOVE_UI_UPDATE;
  1965. } else release = true;
  1966. } else if (button == CURSOR_SELECT2) {
  1967. if (ui->ndragcoords >= 0) {
  1968. ui->ndragcoords = -1;
  1969. return MOVE_UI_UPDATE;
  1970. }
  1971. return MOVE_NO_EFFECT;
  1972. }
  1973. }
  1974. if (button == 27 || button == '\b') {
  1975. if (ui->ndragcoords >= 0) {
  1976. ui->ndragcoords = -1;
  1977. return MOVE_UI_UPDATE;
  1978. }
  1979. return MOVE_NO_EFFECT;
  1980. }
  1981. if (release) {
  1982. if (ui->ndragcoords > 0) {
  1983. /* End of a drag: process the cached line data. */
  1984. int buflen = 0, bufsize = 256, tmplen;
  1985. char *buf = NULL;
  1986. const char *sep = "";
  1987. bool clearing = true;
  1988. for (i = 0; i < ui->ndragcoords - 1; i++) {
  1989. int sx, sy, dx, dy, dir, oldstate, newstate;
  1990. interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
  1991. &dir, &oldstate, &newstate);
  1992. if (oldstate != newstate) {
  1993. if (!buf) buf = snewn(bufsize, char);
  1994. tmplen = sprintf(tmpbuf, "%sF%d,%d,%d;F%d,%d,%d", sep,
  1995. dir, sx, sy, F(dir), dx, dy);
  1996. if (buflen + tmplen >= bufsize) {
  1997. bufsize = (buflen + tmplen) * 5 / 4 + 256;
  1998. buf = sresize(buf, bufsize, char);
  1999. }
  2000. strcpy(buf + buflen, tmpbuf);
  2001. buflen += tmplen;
  2002. sep = ";";
  2003. }
  2004. }
  2005. ui->ndragcoords = -1;
  2006. return buf ? buf : MOVE_UI_UPDATE;
  2007. } else if (ui->ndragcoords == 0) {
  2008. /* Click (or tiny drag). Work out which edge we were
  2009. * closest to. */
  2010. int cx, cy;
  2011. ui->ndragcoords = -1;
  2012. /*
  2013. * We process clicks based on the mouse-down location,
  2014. * because that's more natural for a user to carefully
  2015. * control than the mouse-up.
  2016. */
  2017. x = ui->clickx;
  2018. y = ui->clicky;
  2019. gx = FROMCOORD(x);
  2020. gy = FROMCOORD(y);
  2021. cx = CENTERED_COORD(gx);
  2022. cy = CENTERED_COORD(gy);
  2023. if (!INGRID(state, gx, gy)) return MOVE_UI_UPDATE;
  2024. if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) {
  2025. /* TODO closer to centre of grid: process as a cell click not an edge click. */
  2026. return MOVE_UI_UPDATE;
  2027. } else {
  2028. int direction;
  2029. if (abs(x-cx) < abs(y-cy)) {
  2030. /* Closest to top/bottom edge. */
  2031. direction = (y < cy) ? U : D;
  2032. } else {
  2033. /* Closest to left/right edge. */
  2034. direction = (x < cx) ? L : R;
  2035. }
  2036. return mark_in_direction(state, gx, gy, direction,
  2037. (button == LEFT_RELEASE), tmpbuf);
  2038. }
  2039. }
  2040. }
  2041. if (button == 'H' || button == 'h')
  2042. return dupstr("H");
  2043. return MOVE_UNUSED;
  2044. }
  2045. static game_state *execute_move(const game_state *state, const char *move)
  2046. {
  2047. int w = state->shared->w, h = state->shared->h;
  2048. char c;
  2049. int x, y, l, n;
  2050. game_state *ret = dup_game(state);
  2051. debug(("move: %s\n", move));
  2052. while (*move) {
  2053. c = *move;
  2054. if (c == 'S') {
  2055. ret->used_solve = true;
  2056. move++;
  2057. } else if (c == 'L' || c == 'N' || c == 'R' || c == 'F' || c == 'M') {
  2058. /* 'line' or 'noline' or 'replace' or 'flip' or 'mark' */
  2059. move++;
  2060. if (sscanf(move, "%d,%d,%d%n", &l, &x, &y, &n) != 3)
  2061. goto badmove;
  2062. if (!INGRID(state, x, y)) goto badmove;
  2063. if (l < 0 || l > 15) goto badmove;
  2064. if (c == 'L')
  2065. ret->lines[y*w + x] |= (char)l;
  2066. else if (c == 'N')
  2067. ret->lines[y*w + x] &= ~((char)l);
  2068. else if (c == 'R') {
  2069. ret->lines[y*w + x] = (char)l;
  2070. ret->marks[y*w + x] &= ~((char)l); /* erase marks too */
  2071. } else if (c == 'F')
  2072. ret->lines[y*w + x] ^= (char)l;
  2073. else if (c == 'M')
  2074. ret->marks[y*w + x] ^= (char)l;
  2075. /*
  2076. * If we ended up trying to lay a line _over_ a mark,
  2077. * that's a failed move: interpret_move() should have
  2078. * ensured we never received a move string like that in
  2079. * the first place.
  2080. */
  2081. if ((ret->lines[y*w + x] & (char)l) &&
  2082. (ret->marks[y*w + x] & (char)l))
  2083. goto badmove;
  2084. move += n;
  2085. } else if (strcmp(move, "H") == 0) {
  2086. pearl_solve(ret->shared->w, ret->shared->h,
  2087. ret->shared->clues, ret->lines, DIFFCOUNT, true);
  2088. for (n = 0; n < w*h; n++)
  2089. ret->marks[n] &= ~ret->lines[n]; /* erase marks too */
  2090. move++;
  2091. } else {
  2092. goto badmove;
  2093. }
  2094. if (*move == ';')
  2095. move++;
  2096. else if (*move)
  2097. goto badmove;
  2098. }
  2099. if (!check_completion(ret, true)) goto badmove;
  2100. return ret;
  2101. badmove:
  2102. free_game(ret);
  2103. return NULL;
  2104. }
  2105. /* ----------------------------------------------------------------------
  2106. * Drawing routines.
  2107. */
  2108. #define FLASH_TIME 0.5F
  2109. static void game_compute_size(const game_params *params, int tilesize,
  2110. const game_ui *ui, int *x, int *y)
  2111. {
  2112. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  2113. struct { int halfsz; } ads, *ds = &ads;
  2114. ads.halfsz = (tilesize-1)/2;
  2115. *x = (params->w) * TILE_SIZE + 2 * BORDER;
  2116. *y = (params->h) * TILE_SIZE + 2 * BORDER;
  2117. }
  2118. static void game_set_size(drawing *dr, game_drawstate *ds,
  2119. const game_params *params, int tilesize)
  2120. {
  2121. ds->halfsz = (tilesize-1)/2;
  2122. }
  2123. static float *game_colours(frontend *fe, int *ncolours)
  2124. {
  2125. float *ret = snewn(3 * NCOLOURS, float);
  2126. int i;
  2127. game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT);
  2128. for (i = 0; i < 3; i++) {
  2129. ret[COL_BLACK * 3 + i] = 0.0F;
  2130. ret[COL_WHITE * 3 + i] = 1.0F;
  2131. ret[COL_GRID * 3 + i] = 0.4F;
  2132. }
  2133. ret[COL_ERROR * 3 + 0] = 1.0F;
  2134. ret[COL_ERROR * 3 + 1] = 0.0F;
  2135. ret[COL_ERROR * 3 + 2] = 0.0F;
  2136. ret[COL_DRAGON * 3 + 0] = 0.0F;
  2137. ret[COL_DRAGON * 3 + 1] = 0.0F;
  2138. ret[COL_DRAGON * 3 + 2] = 1.0F;
  2139. ret[COL_DRAGOFF * 3 + 0] = 0.8F;
  2140. ret[COL_DRAGOFF * 3 + 1] = 0.8F;
  2141. ret[COL_DRAGOFF * 3 + 2] = 1.0F;
  2142. ret[COL_FLASH * 3 + 0] = 1.0F;
  2143. ret[COL_FLASH * 3 + 1] = 1.0F;
  2144. ret[COL_FLASH * 3 + 2] = 1.0F;
  2145. *ncolours = NCOLOURS;
  2146. return ret;
  2147. }
  2148. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  2149. {
  2150. struct game_drawstate *ds = snew(struct game_drawstate);
  2151. int i;
  2152. ds->halfsz = 0;
  2153. ds->started = false;
  2154. ds->w = state->shared->w;
  2155. ds->h = state->shared->h;
  2156. ds->sz = state->shared->sz;
  2157. ds->lflags = snewn(ds->sz, unsigned int);
  2158. for (i = 0; i < ds->sz; i++)
  2159. ds->lflags[i] = 0;
  2160. ds->draglines = snewn(ds->sz, char);
  2161. return ds;
  2162. }
  2163. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  2164. {
  2165. sfree(ds->draglines);
  2166. sfree(ds->lflags);
  2167. sfree(ds);
  2168. }
  2169. static void draw_lines_specific(drawing *dr, game_drawstate *ds,
  2170. const game_ui *ui, int x, int y,
  2171. unsigned int lflags, unsigned int shift, int c)
  2172. {
  2173. int ox = COORD(x), oy = COORD(y);
  2174. int t2 = HALFSZ, t16 = HALFSZ/4;
  2175. int cx = ox + t2, cy = oy + t2;
  2176. int d;
  2177. /* Draw each of the four directions, where laid (or error, or drag, etc.) */
  2178. for (d = 1; d < 16; d *= 2) {
  2179. int xoff = t2 * DX(d), yoff = t2 * DY(d);
  2180. int xnudge = abs(t16 * DX(C(d))), ynudge = abs(t16 * DY(C(d)));
  2181. if ((lflags >> shift) & d) {
  2182. int lx = cx + ((xoff < 0) ? xoff : 0) - xnudge;
  2183. int ly = cy + ((yoff < 0) ? yoff : 0) - ynudge;
  2184. if (c == COL_DRAGOFF && !(lflags & d))
  2185. continue;
  2186. if (c == COL_DRAGON && (lflags & d))
  2187. continue;
  2188. draw_rect(dr, lx, ly,
  2189. abs(xoff)+2*xnudge+1,
  2190. abs(yoff)+2*ynudge+1, c);
  2191. /* end cap */
  2192. draw_rect(dr, cx - t16, cy - t16, 2*t16+1, 2*t16+1, c);
  2193. }
  2194. }
  2195. }
  2196. static void draw_square(drawing *dr, game_drawstate *ds, const game_ui *ui,
  2197. int x, int y, unsigned int lflags, char clue)
  2198. {
  2199. int ox = COORD(x), oy = COORD(y);
  2200. int t2 = HALFSZ, t16 = HALFSZ/4;
  2201. int cx = ox + t2, cy = oy + t2;
  2202. int d;
  2203. assert(dr);
  2204. /* Clip to the grid square. */
  2205. clip(dr, ox, oy, TILE_SIZE, TILE_SIZE);
  2206. /* Clear the square. */
  2207. draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE,
  2208. (lflags & DS_CURSOR) ?
  2209. COL_CURSOR_BACKGROUND : COL_BACKGROUND);
  2210. if (ui->gui_style == GUI_LOOPY) {
  2211. /* Draw small dot, underneath any lines. */
  2212. draw_circle(dr, cx, cy, t16, COL_GRID, COL_GRID);
  2213. } else {
  2214. /* Draw outline of grid square */
  2215. draw_line(dr, ox, oy, COORD(x+1), oy, COL_GRID);
  2216. draw_line(dr, ox, oy, ox, COORD(y+1), COL_GRID);
  2217. }
  2218. /* Draw grid: either thin gridlines, or no-line marks.
  2219. * We draw these first because the thick laid lines should be on top. */
  2220. for (d = 1; d < 16; d *= 2) {
  2221. int xoff = t2 * DX(d), yoff = t2 * DY(d);
  2222. if ((x == 0 && d == L) ||
  2223. (y == 0 && d == U) ||
  2224. (x == ds->w-1 && d == R) ||
  2225. (y == ds->h-1 && d == D))
  2226. continue; /* no gridlines out to the border. */
  2227. if ((lflags >> DS_MSHIFT) & d) {
  2228. /* either a no-line mark ... */
  2229. int mx = cx + xoff, my = cy + yoff, msz = t16;
  2230. draw_line(dr, mx-msz, my-msz, mx+msz, my+msz, COL_BLACK);
  2231. draw_line(dr, mx-msz, my+msz, mx+msz, my-msz, COL_BLACK);
  2232. } else {
  2233. if (ui->gui_style == GUI_LOOPY) {
  2234. /* draw grid lines connecting centre of cells */
  2235. draw_line(dr, cx, cy, cx+xoff, cy+yoff, COL_GRID);
  2236. }
  2237. }
  2238. }
  2239. /* Draw each of the four directions, where laid (or error, or drag, etc.)
  2240. * Order is important here, specifically for the eventual colours of the
  2241. * exposed end caps. */
  2242. draw_lines_specific(dr, ds, ui, x, y, lflags, 0,
  2243. (lflags & DS_FLASH ? COL_FLASH : COL_BLACK));
  2244. draw_lines_specific(dr, ds, ui, x, y, lflags, DS_ESHIFT, COL_ERROR);
  2245. draw_lines_specific(dr, ds, ui, x, y, lflags, DS_DSHIFT, COL_DRAGOFF);
  2246. draw_lines_specific(dr, ds, ui, x, y, lflags, DS_DSHIFT, COL_DRAGON);
  2247. /* Draw a clue, if present */
  2248. if (clue != NOCLUE) {
  2249. int c = (lflags & DS_FLASH) ? COL_FLASH :
  2250. (clue == STRAIGHT) ? COL_WHITE : COL_BLACK;
  2251. if (lflags & DS_ERROR_CLUE) /* draw a bigger 'error' clue circle. */
  2252. draw_circle(dr, cx, cy, TILE_SIZE*3/8, COL_ERROR, COL_ERROR);
  2253. draw_circle(dr, cx, cy, TILE_SIZE/4, c, COL_BLACK);
  2254. }
  2255. unclip(dr);
  2256. draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE);
  2257. }
  2258. static void game_redraw(drawing *dr, game_drawstate *ds,
  2259. const game_state *oldstate, const game_state *state,
  2260. int dir, const game_ui *ui,
  2261. float animtime, float flashtime)
  2262. {
  2263. int w = state->shared->w, h = state->shared->h, sz = state->shared->sz;
  2264. int x, y, flashing = 0;
  2265. bool force = false;
  2266. if (!ds->started) {
  2267. if (ui->gui_style == GUI_MASYU) {
  2268. /*
  2269. * Black rectangle which is the main grid.
  2270. */
  2271. draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH,
  2272. w*TILE_SIZE + 2*BORDER_WIDTH + 1,
  2273. h*TILE_SIZE + 2*BORDER_WIDTH + 1,
  2274. COL_GRID);
  2275. }
  2276. draw_update(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER);
  2277. ds->started = true;
  2278. force = true;
  2279. }
  2280. if (flashtime > 0 &&
  2281. (flashtime <= FLASH_TIME/3 ||
  2282. flashtime >= FLASH_TIME*2/3))
  2283. flashing = DS_FLASH;
  2284. memset(ds->draglines, 0, sz);
  2285. if (ui->ndragcoords > 0) {
  2286. int i;
  2287. bool clearing = true;
  2288. for (i = 0; i < ui->ndragcoords - 1; i++) {
  2289. int sx, sy, dx, dy, dir, oldstate, newstate;
  2290. interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
  2291. &dir, &oldstate, &newstate);
  2292. ds->draglines[sy*w+sx] ^= (oldstate ^ newstate);
  2293. ds->draglines[dy*w+dx] ^= (F(oldstate) ^ F(newstate));
  2294. }
  2295. }
  2296. for (x = 0; x < w; x++) {
  2297. for (y = 0; y < h; y++) {
  2298. unsigned int f = (unsigned int)state->lines[y*w+x];
  2299. unsigned int eline = (unsigned int)(state->errors[y*w+x] & (R|U|L|D));
  2300. f |= eline << DS_ESHIFT;
  2301. f |= ((unsigned int)ds->draglines[y*w+x]) << DS_DSHIFT;
  2302. f |= ((unsigned int)state->marks[y*w+x]) << DS_MSHIFT;
  2303. if (state->errors[y*w+x] & ERROR_CLUE)
  2304. f |= DS_ERROR_CLUE;
  2305. f |= flashing;
  2306. if (ui->cursor_active && x == ui->curx && y == ui->cury)
  2307. f |= DS_CURSOR;
  2308. if (f != ds->lflags[y*w+x] || force) {
  2309. ds->lflags[y*w+x] = f;
  2310. draw_square(dr, ds, ui, x, y, f, state->shared->clues[y*w+x]);
  2311. }
  2312. }
  2313. }
  2314. }
  2315. static float game_anim_length(const game_state *oldstate,
  2316. const game_state *newstate, int dir, game_ui *ui)
  2317. {
  2318. return 0.0F;
  2319. }
  2320. static float game_flash_length(const game_state *oldstate,
  2321. const game_state *newstate, int dir, game_ui *ui)
  2322. {
  2323. if (!oldstate->completed && newstate->completed &&
  2324. !oldstate->used_solve && !newstate->used_solve)
  2325. return FLASH_TIME;
  2326. else
  2327. return 0.0F;
  2328. }
  2329. static void game_get_cursor_location(const game_ui *ui,
  2330. const game_drawstate *ds,
  2331. const game_state *state,
  2332. const game_params *params,
  2333. int *x, int *y, int *w, int *h)
  2334. {
  2335. if(ui->cursor_active) {
  2336. *x = COORD(ui->curx);
  2337. *y = COORD(ui->cury);
  2338. *w = *h = TILE_SIZE;
  2339. }
  2340. }
  2341. static int game_status(const game_state *state)
  2342. {
  2343. return state->completed ? +1 : 0;
  2344. }
  2345. static void game_print_size(const game_params *params, const game_ui *ui,
  2346. float *x, float *y)
  2347. {
  2348. int pw, ph;
  2349. /*
  2350. * I'll use 6mm squares by default.
  2351. */
  2352. game_compute_size(params, 600, ui, &pw, &ph);
  2353. *x = pw / 100.0F;
  2354. *y = ph / 100.0F;
  2355. }
  2356. static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
  2357. int tilesize)
  2358. {
  2359. int w = state->shared->w, h = state->shared->h, x, y;
  2360. int black = print_mono_colour(dr, 0);
  2361. int white = print_mono_colour(dr, 1);
  2362. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  2363. game_drawstate *ds = game_new_drawstate(dr, state);
  2364. game_set_size(dr, ds, NULL, tilesize);
  2365. if (ui->gui_style == GUI_MASYU) {
  2366. /* Draw grid outlines (black). */
  2367. for (x = 0; x <= w; x++)
  2368. draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black);
  2369. for (y = 0; y <= h; y++)
  2370. draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black);
  2371. } else {
  2372. /* Draw small dots, and dotted lines connecting them. For
  2373. * added clarity, try to start and end the dotted lines a
  2374. * little way away from the dots. */
  2375. print_line_width(dr, TILE_SIZE / 40);
  2376. print_line_dotted(dr, true);
  2377. for (x = 0; x < w; x++) {
  2378. for (y = 0; y < h; y++) {
  2379. int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ;
  2380. draw_circle(dr, cx, cy, tilesize/10, black, black);
  2381. if (x+1 < w)
  2382. draw_line(dr, cx+tilesize/5, cy,
  2383. cx+tilesize-tilesize/5, cy, black);
  2384. if (y+1 < h)
  2385. draw_line(dr, cx, cy+tilesize/5,
  2386. cx, cy+tilesize-tilesize/5, black);
  2387. }
  2388. }
  2389. print_line_dotted(dr, false);
  2390. }
  2391. for (x = 0; x < w; x++) {
  2392. for (y = 0; y < h; y++) {
  2393. int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ;
  2394. int clue = state->shared->clues[y*w+x];
  2395. draw_lines_specific(dr, ds, ui, x, y,
  2396. state->lines[y*w+x], 0, black);
  2397. if (clue != NOCLUE) {
  2398. int c = (clue == CORNER) ? black : white;
  2399. draw_circle(dr, cx, cy, TILE_SIZE/4, c, black);
  2400. }
  2401. }
  2402. }
  2403. game_free_drawstate(dr, ds);
  2404. }
  2405. #ifdef COMBINED
  2406. #define thegame pearl
  2407. #endif
  2408. const struct game thegame = {
  2409. "Pearl", "games.pearl", "pearl",
  2410. default_params,
  2411. game_fetch_preset, NULL,
  2412. decode_params,
  2413. encode_params,
  2414. free_params,
  2415. dup_params,
  2416. true, game_configure, custom_params,
  2417. validate_params,
  2418. new_game_desc,
  2419. validate_desc,
  2420. new_game,
  2421. dup_game,
  2422. free_game,
  2423. true, solve_game,
  2424. true, game_can_format_as_text_now, game_text_format,
  2425. get_prefs, set_prefs,
  2426. new_ui,
  2427. free_ui,
  2428. NULL, /* encode_ui */
  2429. NULL, /* decode_ui */
  2430. NULL, /* game_request_keys */
  2431. game_changed_state,
  2432. current_key_label,
  2433. interpret_move,
  2434. execute_move,
  2435. PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
  2436. game_colours,
  2437. game_new_drawstate,
  2438. game_free_drawstate,
  2439. game_redraw,
  2440. game_anim_length,
  2441. game_flash_length,
  2442. game_get_cursor_location,
  2443. game_status,
  2444. true, false, game_print_size, game_print,
  2445. false, /* wants_statusbar */
  2446. false, NULL, /* timing_state */
  2447. 0, /* flags */
  2448. };
  2449. #ifdef STANDALONE_SOLVER
  2450. #include <time.h>
  2451. #include <stdarg.h>
  2452. static const char *quis = NULL;
  2453. static void usage(FILE *out) {
  2454. fprintf(out, "usage: %s <params>\n", quis);
  2455. }
  2456. static void pnum(int n, int ntot, const char *desc)
  2457. {
  2458. printf("%2.1f%% (%d) %s", (double)n*100.0 / (double)ntot, n, desc);
  2459. }
  2460. static void start_soak(game_params *p, random_state *rs, int nsecs)
  2461. {
  2462. time_t tt_start, tt_now, tt_last;
  2463. int n = 0, nsolved = 0, nimpossible = 0, ret;
  2464. char *grid, *clues;
  2465. tt_start = tt_last = time(NULL);
  2466. /* Currently this generates puzzles of any difficulty (trying to solve it
  2467. * on the maximum difficulty level and not checking it's not too easy). */
  2468. printf("Soak-testing a %dx%d grid (any difficulty)", p->w, p->h);
  2469. if (nsecs > 0) printf(" for %d seconds", nsecs);
  2470. printf(".\n");
  2471. p->nosolve = true;
  2472. grid = snewn(p->w*p->h, char);
  2473. clues = snewn(p->w*p->h, char);
  2474. while (1) {
  2475. n += new_clues(p, rs, clues, grid); /* should be 1, with nosolve */
  2476. ret = pearl_solve(p->w, p->h, clues, grid, DIFF_TRICKY, false);
  2477. if (ret <= 0) nimpossible++;
  2478. if (ret == 1) nsolved++;
  2479. tt_now = time(NULL);
  2480. if (tt_now > tt_last) {
  2481. tt_last = tt_now;
  2482. printf("%d total, %3.1f/s, ",
  2483. n, (double)n / ((double)tt_now - tt_start));
  2484. pnum(nsolved, n, "solved"); printf(", ");
  2485. printf("%3.1f/s", (double)nsolved / ((double)tt_now - tt_start));
  2486. if (nimpossible > 0)
  2487. pnum(nimpossible, n, "impossible");
  2488. printf("\n");
  2489. }
  2490. if (nsecs > 0 && (tt_now - tt_start) > nsecs) {
  2491. printf("\n");
  2492. break;
  2493. }
  2494. }
  2495. sfree(grid);
  2496. sfree(clues);
  2497. }
  2498. int main(int argc, char *argv[])
  2499. {
  2500. game_params *p = NULL;
  2501. random_state *rs = NULL;
  2502. time_t seed = time(NULL);
  2503. char *id = NULL;
  2504. const char *err;
  2505. setvbuf(stdout, NULL, _IONBF, 0);
  2506. quis = argv[0];
  2507. while (--argc > 0) {
  2508. char *p = (char*)(*++argv);
  2509. if (!strcmp(p, "-e") || !strcmp(p, "--seed")) {
  2510. seed = atoi(*++argv);
  2511. argc--;
  2512. } else if (*p == '-') {
  2513. fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
  2514. usage(stderr);
  2515. exit(1);
  2516. } else {
  2517. id = p;
  2518. }
  2519. }
  2520. rs = random_new((void*)&seed, sizeof(time_t));
  2521. p = default_params();
  2522. if (id) {
  2523. if (strchr(id, ':')) {
  2524. fprintf(stderr, "soak takes params only.\n");
  2525. goto done;
  2526. }
  2527. decode_params(p, id);
  2528. err = validate_params(p, true);
  2529. if (err) {
  2530. fprintf(stderr, "%s: %s", argv[0], err);
  2531. goto done;
  2532. }
  2533. start_soak(p, rs, 0); /* run forever */
  2534. } else {
  2535. int i;
  2536. for (i = 5; i <= 12; i++) {
  2537. p->w = p->h = i;
  2538. start_soak(p, rs, 5);
  2539. }
  2540. }
  2541. done:
  2542. free_params(p);
  2543. random_free(rs);
  2544. return 0;
  2545. }
  2546. #endif
  2547. /* vim: set shiftwidth=4 tabstop=8: */