mines.c 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293
  1. /*
  2. * mines.c: Minesweeper clone with sophisticated grid generation.
  3. *
  4. * Still TODO:
  5. *
  6. * - think about configurably supporting question marks.
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #include <ctype.h>
  13. #include <limits.h>
  14. #ifdef NO_TGMATH_H
  15. # include <math.h>
  16. #else
  17. # include <tgmath.h>
  18. #endif
  19. #include "tree234.h"
  20. #include "puzzles.h"
  21. enum {
  22. COL_BACKGROUND, COL_BACKGROUND2,
  23. COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8,
  24. COL_MINE, COL_BANG, COL_CROSS, COL_FLAG, COL_FLAGBASE, COL_QUERY,
  25. COL_HIGHLIGHT, COL_LOWLIGHT,
  26. COL_WRONGNUMBER,
  27. COL_CURSOR,
  28. NCOLOURS
  29. };
  30. #define PREFERRED_TILE_SIZE 20
  31. #define TILE_SIZE (ds->tilesize)
  32. #ifdef SMALL_SCREEN
  33. #define BORDER 8
  34. #else
  35. #define BORDER (TILE_SIZE * 3 / 2)
  36. #endif
  37. #define HIGHLIGHT_WIDTH (TILE_SIZE / 10 ? TILE_SIZE / 10 : 1)
  38. #define OUTER_HIGHLIGHT_WIDTH (BORDER / 10 ? BORDER / 10 : 1)
  39. #define COORD(x) ( (x) * TILE_SIZE + BORDER )
  40. #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
  41. #define FLASH_FRAME 0.13F
  42. struct game_params {
  43. int w, h, n;
  44. bool unique;
  45. };
  46. struct mine_layout {
  47. /*
  48. * This structure is shared between all the game_states for a
  49. * given instance of the puzzle, so we reference-count it.
  50. */
  51. int refcount;
  52. bool *mines;
  53. /*
  54. * If we haven't yet actually generated the mine layout, here's
  55. * all the data we will need to do so.
  56. */
  57. int n;
  58. bool unique;
  59. random_state *rs;
  60. midend *me; /* to give back the new game desc */
  61. };
  62. struct game_state {
  63. int w, h, n;
  64. bool dead, won, used_solve;
  65. struct mine_layout *layout; /* real mine positions */
  66. signed char *grid; /* player knowledge */
  67. /*
  68. * Each item in the `grid' array is one of the following values:
  69. *
  70. * - 0 to 8 mean the square is open and has a surrounding mine
  71. * count.
  72. *
  73. * - -1 means the square is marked as a mine.
  74. *
  75. * - -2 means the square is unknown.
  76. *
  77. * - -3 means the square is marked with a question mark
  78. * (FIXME: do we even want to bother with this?).
  79. *
  80. * - 64 means the square has had a mine revealed when the game
  81. * was lost.
  82. *
  83. * - 65 means the square had a mine revealed and this was the
  84. * one the player hits.
  85. *
  86. * - 66 means the square has a crossed-out mine because the
  87. * player had incorrectly marked it.
  88. */
  89. };
  90. static game_params *default_params(void)
  91. {
  92. game_params *ret = snew(game_params);
  93. ret->w = ret->h = 9;
  94. ret->n = 10;
  95. ret->unique = true;
  96. return ret;
  97. }
  98. static const struct game_params mines_presets[] = {
  99. {9, 9, 10, true},
  100. {9, 9, 35, true},
  101. {16, 16, 40, true},
  102. {16, 16, 99, true},
  103. #ifndef SMALL_SCREEN
  104. {30, 16, 99, true},
  105. {30, 16, 170, true},
  106. #endif
  107. };
  108. static bool game_fetch_preset(int i, char **name, game_params **params)
  109. {
  110. game_params *ret;
  111. char str[80];
  112. if (i < 0 || i >= lenof(mines_presets))
  113. return false;
  114. ret = snew(game_params);
  115. *ret = mines_presets[i];
  116. sprintf(str, "%dx%d, %d mines", ret->w, ret->h, ret->n);
  117. *name = dupstr(str);
  118. *params = ret;
  119. return true;
  120. }
  121. static void free_params(game_params *params)
  122. {
  123. sfree(params);
  124. }
  125. static game_params *dup_params(const game_params *params)
  126. {
  127. game_params *ret = snew(game_params);
  128. *ret = *params; /* structure copy */
  129. return ret;
  130. }
  131. static void decode_params(game_params *params, char const *string)
  132. {
  133. char const *p = string;
  134. params->w = atoi(p);
  135. while (*p && isdigit((unsigned char)*p)) p++;
  136. if (*p == 'x') {
  137. p++;
  138. params->h = atoi(p);
  139. while (*p && isdigit((unsigned char)*p)) p++;
  140. } else {
  141. params->h = params->w;
  142. }
  143. if (*p == 'n') {
  144. p++;
  145. params->n = atoi(p);
  146. while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
  147. } else {
  148. if (params->h > 0 && params->w > 0 &&
  149. params->w <= INT_MAX / params->h)
  150. params->n = params->w * params->h / 10;
  151. }
  152. while (*p) {
  153. if (*p == 'a') {
  154. p++;
  155. params->unique = false;
  156. } else
  157. p++; /* skip any other gunk */
  158. }
  159. }
  160. static char *encode_params(const game_params *params, bool full)
  161. {
  162. char ret[400];
  163. int len;
  164. len = sprintf(ret, "%dx%d", params->w, params->h);
  165. /*
  166. * Mine count is a generation-time parameter, since it can be
  167. * deduced from the mine bitmap!
  168. */
  169. if (full)
  170. len += sprintf(ret+len, "n%d", params->n);
  171. if (full && !params->unique)
  172. ret[len++] = 'a';
  173. assert(len < lenof(ret));
  174. ret[len] = '\0';
  175. return dupstr(ret);
  176. }
  177. static config_item *game_configure(const game_params *params)
  178. {
  179. config_item *ret;
  180. char buf[80];
  181. ret = snewn(5, config_item);
  182. ret[0].name = "Width";
  183. ret[0].type = C_STRING;
  184. sprintf(buf, "%d", params->w);
  185. ret[0].u.string.sval = dupstr(buf);
  186. ret[1].name = "Height";
  187. ret[1].type = C_STRING;
  188. sprintf(buf, "%d", params->h);
  189. ret[1].u.string.sval = dupstr(buf);
  190. ret[2].name = "Mines";
  191. ret[2].type = C_STRING;
  192. sprintf(buf, "%d", params->n);
  193. ret[2].u.string.sval = dupstr(buf);
  194. ret[3].name = "Ensure solubility";
  195. ret[3].type = C_BOOLEAN;
  196. ret[3].u.boolean.bval = params->unique;
  197. ret[4].name = NULL;
  198. ret[4].type = C_END;
  199. return ret;
  200. }
  201. static game_params *custom_params(const config_item *cfg)
  202. {
  203. game_params *ret = snew(game_params);
  204. ret->w = atoi(cfg[0].u.string.sval);
  205. ret->h = atoi(cfg[1].u.string.sval);
  206. ret->n = atoi(cfg[2].u.string.sval);
  207. if (strchr(cfg[2].u.string.sval, '%'))
  208. ret->n = ret->n * (ret->w * ret->h) / 100;
  209. ret->unique = cfg[3].u.boolean.bval;
  210. return ret;
  211. }
  212. static const char *validate_params(const game_params *params, bool full)
  213. {
  214. /*
  215. * Lower limit on grid size: each dimension must be at least 3.
  216. * 1 is theoretically workable if rather boring, but 2 is a
  217. * real problem: there is often _no_ way to generate a uniquely
  218. * solvable 2xn Mines grid. You either run into two mines
  219. * blocking the way and no idea what's behind them, or one mine
  220. * and no way to know which of the two rows it's in. If the
  221. * mine count is even you can create a soluble grid by packing
  222. * all the mines at one end (so that when you hit a two-mine
  223. * wall there are only as many covered squares left as there
  224. * are mines); but if it's odd, you are doomed, because you
  225. * _have_ to have a gap somewhere which you can't determine the
  226. * position of.
  227. */
  228. if (full && params->unique && (params->w <= 2 || params->h <= 2))
  229. return "Width and height must both be greater than two";
  230. if (params->w < 1 || params->h < 1)
  231. return "Width and height must both be at least one";
  232. if (params->w > SHRT_MAX || params->h > SHRT_MAX)
  233. return "Neither width nor height may be unreasonably large";
  234. /*
  235. * We use random_upto() to place mines, and its maximum limit is 2^28-1.
  236. */
  237. #if (1<<28)-1 < INT_MAX
  238. if (params->w > ((1<<28)-1) / params->h)
  239. #else
  240. if (params->w > INT_MAX / params->h)
  241. #endif
  242. return "Width times height must not be unreasonably large";
  243. if (params->n < 0)
  244. return "Mine count may not be negative";
  245. if (params->n > params->w * params->h - 9)
  246. return "Too many mines for grid size";
  247. /*
  248. * FIXME: Need more constraints here. Not sure what the
  249. * sensible limits for Minesweeper actually are. The limits
  250. * probably ought to change, however, depending on uniqueness.
  251. */
  252. return NULL;
  253. }
  254. /* ----------------------------------------------------------------------
  255. * Minesweeper solver, used to ensure the generated grids are
  256. * solvable without having to take risks.
  257. */
  258. /*
  259. * Count the bits in a word. Only needs to cope with 16 bits.
  260. */
  261. static int bitcount16(int inword)
  262. {
  263. unsigned int word = inword;
  264. word = ((word & 0xAAAA) >> 1) + (word & 0x5555);
  265. word = ((word & 0xCCCC) >> 2) + (word & 0x3333);
  266. word = ((word & 0xF0F0) >> 4) + (word & 0x0F0F);
  267. word = ((word & 0xFF00) >> 8) + (word & 0x00FF);
  268. return (int)word;
  269. }
  270. /*
  271. * We use a tree234 to store a large number of small localised
  272. * sets, each with a mine count. We also keep some of those sets
  273. * linked together into a to-do list.
  274. */
  275. struct set {
  276. short x, y, mask, mines;
  277. bool todo;
  278. struct set *prev, *next;
  279. };
  280. static int setcmp(void *av, void *bv)
  281. {
  282. struct set *a = (struct set *)av;
  283. struct set *b = (struct set *)bv;
  284. if (a->y < b->y)
  285. return -1;
  286. else if (a->y > b->y)
  287. return +1;
  288. else if (a->x < b->x)
  289. return -1;
  290. else if (a->x > b->x)
  291. return +1;
  292. else if (a->mask < b->mask)
  293. return -1;
  294. else if (a->mask > b->mask)
  295. return +1;
  296. else
  297. return 0;
  298. }
  299. struct setstore {
  300. tree234 *sets;
  301. struct set *todo_head, *todo_tail;
  302. };
  303. static struct setstore *ss_new(void)
  304. {
  305. struct setstore *ss = snew(struct setstore);
  306. ss->sets = newtree234(setcmp);
  307. ss->todo_head = ss->todo_tail = NULL;
  308. return ss;
  309. }
  310. /*
  311. * Take two input sets, in the form (x,y,mask). Munge the first by
  312. * taking either its intersection with the second or its difference
  313. * with the second. Return the new mask part of the first set.
  314. */
  315. static int setmunge(int x1, int y1, int mask1, int x2, int y2, int mask2,
  316. bool diff)
  317. {
  318. /*
  319. * Adjust the second set so that it has the same x,y
  320. * coordinates as the first.
  321. */
  322. if (abs(x2-x1) >= 3 || abs(y2-y1) >= 3) {
  323. mask2 = 0;
  324. } else {
  325. while (x2 > x1) {
  326. mask2 &= ~(4|32|256);
  327. mask2 <<= 1;
  328. x2--;
  329. }
  330. while (x2 < x1) {
  331. mask2 &= ~(1|8|64);
  332. mask2 >>= 1;
  333. x2++;
  334. }
  335. while (y2 > y1) {
  336. mask2 &= ~(64|128|256);
  337. mask2 <<= 3;
  338. y2--;
  339. }
  340. while (y2 < y1) {
  341. mask2 &= ~(1|2|4);
  342. mask2 >>= 3;
  343. y2++;
  344. }
  345. }
  346. /*
  347. * Invert the second set if `diff' is set (we're after A &~ B
  348. * rather than A & B).
  349. */
  350. if (diff)
  351. mask2 ^= 511;
  352. /*
  353. * Now all that's left is a logical AND.
  354. */
  355. return mask1 & mask2;
  356. }
  357. static void ss_add_todo(struct setstore *ss, struct set *s)
  358. {
  359. if (s->todo)
  360. return; /* already on it */
  361. #ifdef SOLVER_DIAGNOSTICS
  362. printf("adding set on todo list: %d,%d %03x %d\n",
  363. s->x, s->y, s->mask, s->mines);
  364. #endif
  365. s->prev = ss->todo_tail;
  366. if (s->prev)
  367. s->prev->next = s;
  368. else
  369. ss->todo_head = s;
  370. ss->todo_tail = s;
  371. s->next = NULL;
  372. s->todo = true;
  373. }
  374. static void ss_add(struct setstore *ss, int x, int y, int mask, int mines)
  375. {
  376. struct set *s;
  377. assert(mask != 0);
  378. /*
  379. * Normalise so that x and y are genuinely the bounding
  380. * rectangle.
  381. */
  382. while (!(mask & (1|8|64)))
  383. mask >>= 1, x++;
  384. while (!(mask & (1|2|4)))
  385. mask >>= 3, y++;
  386. /*
  387. * Create a set structure and add it to the tree.
  388. */
  389. s = snew(struct set);
  390. assert(SHRT_MIN <= x && x <= SHRT_MAX);
  391. s->x = x;
  392. assert(SHRT_MIN <= y && y <= SHRT_MAX);
  393. s->y = y;
  394. s->mask = mask;
  395. s->mines = mines;
  396. s->todo = false;
  397. if (add234(ss->sets, s) != s) {
  398. /*
  399. * This set already existed! Free it and return.
  400. */
  401. sfree(s);
  402. return;
  403. }
  404. /*
  405. * We've added a new set to the tree, so put it on the todo
  406. * list.
  407. */
  408. ss_add_todo(ss, s);
  409. }
  410. static void ss_remove(struct setstore *ss, struct set *s)
  411. {
  412. struct set *next = s->next, *prev = s->prev;
  413. #ifdef SOLVER_DIAGNOSTICS
  414. printf("removing set %d,%d %03x\n", s->x, s->y, s->mask);
  415. #endif
  416. /*
  417. * Remove s from the todo list.
  418. */
  419. if (prev)
  420. prev->next = next;
  421. else if (s == ss->todo_head)
  422. ss->todo_head = next;
  423. if (next)
  424. next->prev = prev;
  425. else if (s == ss->todo_tail)
  426. ss->todo_tail = prev;
  427. s->todo = false;
  428. /*
  429. * Remove s from the tree.
  430. */
  431. del234(ss->sets, s);
  432. /*
  433. * Destroy the actual set structure.
  434. */
  435. sfree(s);
  436. }
  437. /*
  438. * Return a dynamically allocated list of all the sets which
  439. * overlap a provided input set.
  440. */
  441. static struct set **ss_overlap(struct setstore *ss, int x, int y, int mask)
  442. {
  443. struct set **ret = NULL;
  444. int nret = 0, retsize = 0;
  445. int xx, yy;
  446. for (xx = x-3; xx < x+3; xx++)
  447. for (yy = y-3; yy < y+3; yy++) {
  448. struct set stmp, *s;
  449. int pos;
  450. /*
  451. * Find the first set with these top left coordinates.
  452. */
  453. assert(SHRT_MIN <= xx && xx <= SHRT_MAX);
  454. stmp.x = xx;
  455. assert(SHRT_MIN <= yy && yy <= SHRT_MAX);
  456. stmp.y = yy;
  457. stmp.mask = 0;
  458. if (findrelpos234(ss->sets, &stmp, NULL, REL234_GE, &pos)) {
  459. while ((s = index234(ss->sets, pos)) != NULL &&
  460. s->x == xx && s->y == yy) {
  461. /*
  462. * This set potentially overlaps the input one.
  463. * Compute the intersection to see if they
  464. * really overlap, and add it to the list if
  465. * so.
  466. */
  467. if (setmunge(x, y, mask, s->x, s->y, s->mask, false)) {
  468. /*
  469. * There's an overlap.
  470. */
  471. if (nret >= retsize) {
  472. retsize = nret + 32;
  473. ret = sresize(ret, retsize, struct set *);
  474. }
  475. ret[nret++] = s;
  476. }
  477. pos++;
  478. }
  479. }
  480. }
  481. ret = sresize(ret, nret+1, struct set *);
  482. ret[nret] = NULL;
  483. return ret;
  484. }
  485. /*
  486. * Get an element from the head of the set todo list.
  487. */
  488. static struct set *ss_todo(struct setstore *ss)
  489. {
  490. if (ss->todo_head) {
  491. struct set *ret = ss->todo_head;
  492. ss->todo_head = ret->next;
  493. if (ss->todo_head)
  494. ss->todo_head->prev = NULL;
  495. else
  496. ss->todo_tail = NULL;
  497. ret->next = ret->prev = NULL;
  498. ret->todo = false;
  499. return ret;
  500. } else {
  501. return NULL;
  502. }
  503. }
  504. struct squaretodo {
  505. int *next;
  506. int head, tail;
  507. };
  508. static void std_add(struct squaretodo *std, int i)
  509. {
  510. if (std->tail >= 0)
  511. std->next[std->tail] = i;
  512. else
  513. std->head = i;
  514. std->tail = i;
  515. std->next[i] = -1;
  516. }
  517. typedef int (*open_cb)(void *, int, int);
  518. static void known_squares(int w, int h, struct squaretodo *std,
  519. signed char *grid,
  520. open_cb open, void *openctx,
  521. int x, int y, int mask, bool mine)
  522. {
  523. int xx, yy, bit;
  524. bit = 1;
  525. for (yy = 0; yy < 3; yy++)
  526. for (xx = 0; xx < 3; xx++) {
  527. if (mask & bit) {
  528. int i = (y + yy) * w + (x + xx);
  529. /*
  530. * It's possible that this square is _already_
  531. * known, in which case we don't try to add it to
  532. * the list twice.
  533. */
  534. if (grid[i] == -2) {
  535. if (mine) {
  536. grid[i] = -1; /* and don't open it! */
  537. } else {
  538. grid[i] = open(openctx, x + xx, y + yy);
  539. assert(grid[i] != -1); /* *bang* */
  540. }
  541. std_add(std, i);
  542. }
  543. }
  544. bit <<= 1;
  545. }
  546. }
  547. /*
  548. * This is data returned from the `perturb' function. It details
  549. * which squares have become mines and which have become clear. The
  550. * solver is (of course) expected to honourably not use that
  551. * knowledge directly, but to efficently adjust its internal data
  552. * structures and proceed based on only the information it
  553. * legitimately has.
  554. */
  555. struct perturbation {
  556. int x, y;
  557. int delta; /* +1 == become a mine; -1 == cleared */
  558. };
  559. struct perturbations {
  560. int n;
  561. struct perturbation *changes;
  562. };
  563. /*
  564. * Main solver entry point. You give it a grid of existing
  565. * knowledge (-1 for a square known to be a mine, 0-8 for empty
  566. * squares with a given number of neighbours, -2 for completely
  567. * unknown), plus a function which you can call to open new squares
  568. * once you're confident of them. It fills in as much more of the
  569. * grid as it can.
  570. *
  571. * Return value is:
  572. *
  573. * - -1 means deduction stalled and nothing could be done
  574. * - 0 means deduction succeeded fully
  575. * - >0 means deduction succeeded but some number of perturbation
  576. * steps were required; the exact return value is the number of
  577. * perturb calls.
  578. */
  579. typedef struct perturbations *(*perturb_cb) (void *, signed char *, int, int, int);
  580. static int minesolve(int w, int h, int n, signed char *grid,
  581. open_cb open,
  582. perturb_cb perturb,
  583. void *ctx, random_state *rs)
  584. {
  585. struct setstore *ss = ss_new();
  586. struct set **list;
  587. struct squaretodo astd, *std = &astd;
  588. int x, y, i, j;
  589. int nperturbs = 0;
  590. /*
  591. * Set up a linked list of squares with known contents, so that
  592. * we can process them one by one.
  593. */
  594. std->next = snewn(w*h, int);
  595. std->head = std->tail = -1;
  596. /*
  597. * Initialise that list with all known squares in the input
  598. * grid.
  599. */
  600. for (y = 0; y < h; y++) {
  601. for (x = 0; x < w; x++) {
  602. i = y*w+x;
  603. if (grid[i] != -2)
  604. std_add(std, i);
  605. }
  606. }
  607. /*
  608. * Main deductive loop.
  609. */
  610. while (1) {
  611. bool done_something = false;
  612. struct set *s;
  613. /*
  614. * If there are any known squares on the todo list, process
  615. * them and construct a set for each.
  616. */
  617. while (std->head != -1) {
  618. i = std->head;
  619. #ifdef SOLVER_DIAGNOSTICS
  620. printf("known square at %d,%d [%d]\n", i%w, i/w, grid[i]);
  621. #endif
  622. std->head = std->next[i];
  623. if (std->head == -1)
  624. std->tail = -1;
  625. x = i % w;
  626. y = i / w;
  627. if (grid[i] >= 0) {
  628. int dx, dy, mines, bit, val;
  629. #ifdef SOLVER_DIAGNOSTICS
  630. printf("creating set around this square\n");
  631. #endif
  632. /*
  633. * Empty square. Construct the set of non-known squares
  634. * around this one, and determine its mine count.
  635. */
  636. mines = grid[i];
  637. bit = 1;
  638. val = 0;
  639. for (dy = -1; dy <= +1; dy++) {
  640. for (dx = -1; dx <= +1; dx++) {
  641. #ifdef SOLVER_DIAGNOSTICS
  642. printf("grid %d,%d = %d\n", x+dx, y+dy, grid[i+dy*w+dx]);
  643. #endif
  644. if (x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= h)
  645. /* ignore this one */;
  646. else if (grid[i+dy*w+dx] == -1)
  647. mines--;
  648. else if (grid[i+dy*w+dx] == -2)
  649. val |= bit;
  650. bit <<= 1;
  651. }
  652. }
  653. if (val)
  654. ss_add(ss, x-1, y-1, val, mines);
  655. }
  656. /*
  657. * Now, whether the square is empty or full, we must
  658. * find any set which contains it and replace it with
  659. * one which does not.
  660. */
  661. {
  662. #ifdef SOLVER_DIAGNOSTICS
  663. printf("finding sets containing known square %d,%d\n", x, y);
  664. #endif
  665. list = ss_overlap(ss, x, y, 1);
  666. for (j = 0; list[j]; j++) {
  667. int newmask, newmines;
  668. s = list[j];
  669. /*
  670. * Compute the mask for this set minus the
  671. * newly known square.
  672. */
  673. newmask = setmunge(s->x, s->y, s->mask, x, y, 1, true);
  674. /*
  675. * Compute the new mine count.
  676. */
  677. newmines = s->mines - (grid[i] == -1);
  678. /*
  679. * Insert the new set into the collection,
  680. * unless it's been whittled right down to
  681. * nothing.
  682. */
  683. if (newmask)
  684. ss_add(ss, s->x, s->y, newmask, newmines);
  685. /*
  686. * Destroy the old one; it is actually obsolete.
  687. */
  688. ss_remove(ss, s);
  689. }
  690. sfree(list);
  691. }
  692. /*
  693. * Marking a fresh square as known certainly counts as
  694. * doing something.
  695. */
  696. done_something = true;
  697. }
  698. /*
  699. * Now pick a set off the to-do list and attempt deductions
  700. * based on it.
  701. */
  702. if ((s = ss_todo(ss)) != NULL) {
  703. #ifdef SOLVER_DIAGNOSTICS
  704. printf("set to do: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
  705. #endif
  706. /*
  707. * Firstly, see if this set has a mine count of zero or
  708. * of its own cardinality.
  709. */
  710. if (s->mines == 0 || s->mines == bitcount16(s->mask)) {
  711. /*
  712. * If so, we can immediately mark all the squares
  713. * in the set as known.
  714. */
  715. #ifdef SOLVER_DIAGNOSTICS
  716. printf("easy\n");
  717. #endif
  718. known_squares(w, h, std, grid, open, ctx,
  719. s->x, s->y, s->mask, (s->mines != 0));
  720. /*
  721. * Having done that, we need do nothing further
  722. * with this set; marking all the squares in it as
  723. * known will eventually eliminate it, and will
  724. * also permit further deductions about anything
  725. * that overlaps it.
  726. */
  727. continue;
  728. }
  729. /*
  730. * Failing that, we now search through all the sets
  731. * which overlap this one.
  732. */
  733. list = ss_overlap(ss, s->x, s->y, s->mask);
  734. for (j = 0; list[j]; j++) {
  735. struct set *s2 = list[j];
  736. int swing, s2wing, swc, s2wc;
  737. /*
  738. * Find the non-overlapping parts s2-s and s-s2,
  739. * and their cardinalities.
  740. *
  741. * I'm going to refer to these parts as `wings'
  742. * surrounding the central part common to both
  743. * sets. The `s wing' is s-s2; the `s2 wing' is
  744. * s2-s.
  745. */
  746. swing = setmunge(s->x, s->y, s->mask, s2->x, s2->y, s2->mask,
  747. true);
  748. s2wing = setmunge(s2->x, s2->y, s2->mask, s->x, s->y, s->mask,
  749. true);
  750. swc = bitcount16(swing);
  751. s2wc = bitcount16(s2wing);
  752. /*
  753. * If one set has more mines than the other, and
  754. * the number of extra mines is equal to the
  755. * cardinality of that set's wing, then we can mark
  756. * every square in the wing as a known mine, and
  757. * every square in the other wing as known clear.
  758. */
  759. if (swc == s->mines - s2->mines ||
  760. s2wc == s2->mines - s->mines) {
  761. known_squares(w, h, std, grid, open, ctx,
  762. s->x, s->y, swing,
  763. (swc == s->mines - s2->mines));
  764. known_squares(w, h, std, grid, open, ctx,
  765. s2->x, s2->y, s2wing,
  766. (s2wc == s2->mines - s->mines));
  767. continue;
  768. }
  769. /*
  770. * Failing that, see if one set is a subset of the
  771. * other. If so, we can divide up the mine count of
  772. * the larger set between the smaller set and its
  773. * complement, even if neither smaller set ends up
  774. * being immediately clearable.
  775. */
  776. if (swc == 0 && s2wc != 0) {
  777. /* s is a subset of s2. */
  778. assert(s2->mines > s->mines);
  779. ss_add(ss, s2->x, s2->y, s2wing, s2->mines - s->mines);
  780. } else if (s2wc == 0 && swc != 0) {
  781. /* s2 is a subset of s. */
  782. assert(s->mines > s2->mines);
  783. ss_add(ss, s->x, s->y, swing, s->mines - s2->mines);
  784. }
  785. }
  786. sfree(list);
  787. /*
  788. * In this situation we have definitely done
  789. * _something_, even if it's only reducing the size of
  790. * our to-do list.
  791. */
  792. done_something = true;
  793. } else if (n >= 0) {
  794. /*
  795. * We have nothing left on our todo list, which means
  796. * all localised deductions have failed. Our next step
  797. * is to resort to global deduction based on the total
  798. * mine count. This is computationally expensive
  799. * compared to any of the above deductions, which is
  800. * why we only ever do it when all else fails, so that
  801. * hopefully it won't have to happen too often.
  802. *
  803. * If you pass n<0 into this solver, that informs it
  804. * that you do not know the total mine count, so it
  805. * won't even attempt these deductions.
  806. */
  807. int minesleft, squaresleft;
  808. int nsets, cursor;
  809. bool setused[10];
  810. /*
  811. * Start by scanning the current grid state to work out
  812. * how many unknown squares we still have, and how many
  813. * mines are to be placed in them.
  814. */
  815. squaresleft = 0;
  816. minesleft = n;
  817. for (i = 0; i < w*h; i++) {
  818. if (grid[i] == -1)
  819. minesleft--;
  820. else if (grid[i] == -2)
  821. squaresleft++;
  822. }
  823. #ifdef SOLVER_DIAGNOSTICS
  824. printf("global deduction time: squaresleft=%d minesleft=%d\n",
  825. squaresleft, minesleft);
  826. for (y = 0; y < h; y++) {
  827. for (x = 0; x < w; x++) {
  828. int v = grid[y*w+x];
  829. if (v == -1)
  830. putchar('*');
  831. else if (v == -2)
  832. putchar('?');
  833. else if (v == 0)
  834. putchar('-');
  835. else
  836. putchar('0' + v);
  837. }
  838. putchar('\n');
  839. }
  840. #endif
  841. /*
  842. * If there _are_ no unknown squares, we have actually
  843. * finished.
  844. */
  845. if (squaresleft == 0) {
  846. assert(minesleft == 0);
  847. break;
  848. }
  849. /*
  850. * First really simple case: if there are no more mines
  851. * left, or if there are exactly as many mines left as
  852. * squares to play them in, then it's all easy.
  853. */
  854. if (minesleft == 0 || minesleft == squaresleft) {
  855. for (i = 0; i < w*h; i++)
  856. if (grid[i] == -2)
  857. known_squares(w, h, std, grid, open, ctx,
  858. i % w, i / w, 1, minesleft != 0);
  859. continue; /* now go back to main deductive loop */
  860. }
  861. /*
  862. * Failing that, we have to do some _real_ work.
  863. * Ideally what we do here is to try every single
  864. * combination of the currently available sets, in an
  865. * attempt to find a disjoint union (i.e. a set of
  866. * squares with a known mine count between them) such
  867. * that the remaining unknown squares _not_ contained
  868. * in that union either contain no mines or are all
  869. * mines.
  870. *
  871. * Actually enumerating all 2^n possibilities will get
  872. * a bit slow for large n, so I artificially cap this
  873. * recursion at n=10 to avoid too much pain.
  874. */
  875. nsets = count234(ss->sets);
  876. if (nsets <= lenof(setused)) {
  877. /*
  878. * Doing this with actual recursive function calls
  879. * would get fiddly because a load of local
  880. * variables from this function would have to be
  881. * passed down through the recursion. So instead
  882. * I'm going to use a virtual recursion within this
  883. * function. The way this works is:
  884. *
  885. * - we have an array `setused', such that setused[n]
  886. * is true if set n is currently in the union we
  887. * are considering.
  888. *
  889. * - we have a value `cursor' which indicates how
  890. * much of `setused' we have so far filled in.
  891. * It's conceptually the recursion depth.
  892. *
  893. * We begin by setting `cursor' to zero. Then:
  894. *
  895. * - if cursor can advance, we advance it by one. We
  896. * set the value in `setused' that it went past to
  897. * true if that set is disjoint from anything else
  898. * currently in `setused', or to false otherwise.
  899. *
  900. * - If cursor cannot advance because it has
  901. * reached the end of the setused list, then we
  902. * have a maximal disjoint union. Check to see
  903. * whether its mine count has any useful
  904. * properties. If so, mark all the squares not
  905. * in the union as known and terminate.
  906. *
  907. * - If cursor has reached the end of setused and the
  908. * algorithm _hasn't_ terminated, back cursor up to
  909. * the nearest true entry, reset it to false, and
  910. * advance cursor just past it.
  911. *
  912. * - If we attempt to back up to the nearest 1 and
  913. * there isn't one at all, then we have gone
  914. * through all disjoint unions of sets in the
  915. * list and none of them has been helpful, so we
  916. * give up.
  917. */
  918. struct set *sets[lenof(setused)];
  919. for (i = 0; i < nsets; i++)
  920. sets[i] = index234(ss->sets, i);
  921. cursor = 0;
  922. while (1) {
  923. if (cursor < nsets) {
  924. bool ok = true;
  925. /* See if any existing set overlaps this one. */
  926. for (i = 0; i < cursor; i++)
  927. if (setused[i] &&
  928. setmunge(sets[cursor]->x,
  929. sets[cursor]->y,
  930. sets[cursor]->mask,
  931. sets[i]->x, sets[i]->y, sets[i]->mask,
  932. false)) {
  933. ok = false;
  934. break;
  935. }
  936. if (ok) {
  937. /*
  938. * We're adding this set to our union,
  939. * so adjust minesleft and squaresleft
  940. * appropriately.
  941. */
  942. minesleft -= sets[cursor]->mines;
  943. squaresleft -= bitcount16(sets[cursor]->mask);
  944. }
  945. setused[cursor++] = ok;
  946. } else {
  947. #ifdef SOLVER_DIAGNOSTICS
  948. printf("trying a set combination with %d %d\n",
  949. squaresleft, minesleft);
  950. #endif /* SOLVER_DIAGNOSTICS */
  951. /*
  952. * We've reached the end. See if we've got
  953. * anything interesting.
  954. */
  955. if (squaresleft > 0 &&
  956. (minesleft == 0 || minesleft == squaresleft)) {
  957. /*
  958. * We have! There is at least one
  959. * square not contained within the set
  960. * union we've just found, and we can
  961. * deduce that either all such squares
  962. * are mines or all are not (depending
  963. * on whether minesleft==0). So now all
  964. * we have to do is actually go through
  965. * the grid, find those squares, and
  966. * mark them.
  967. */
  968. for (i = 0; i < w*h; i++)
  969. if (grid[i] == -2) {
  970. bool outside = true;
  971. y = i / w;
  972. x = i % w;
  973. for (j = 0; j < nsets; j++)
  974. if (setused[j] &&
  975. setmunge(sets[j]->x, sets[j]->y,
  976. sets[j]->mask, x, y, 1,
  977. false)) {
  978. outside = false;
  979. break;
  980. }
  981. if (outside)
  982. known_squares(w, h, std, grid,
  983. open, ctx,
  984. x, y, 1, minesleft != 0);
  985. }
  986. done_something = true;
  987. break; /* return to main deductive loop */
  988. }
  989. /*
  990. * If we reach here, then this union hasn't
  991. * done us any good, so move on to the
  992. * next. Backtrack cursor to the nearest 1,
  993. * change it to a 0 and continue.
  994. */
  995. while (--cursor >= 0 && !setused[cursor]);
  996. if (cursor >= 0) {
  997. assert(setused[cursor]);
  998. /*
  999. * We're removing this set from our
  1000. * union, so re-increment minesleft and
  1001. * squaresleft.
  1002. */
  1003. minesleft += sets[cursor]->mines;
  1004. squaresleft += bitcount16(sets[cursor]->mask);
  1005. setused[cursor++] = false;
  1006. } else {
  1007. /*
  1008. * We've backtracked all the way to the
  1009. * start without finding a single 1,
  1010. * which means that our virtual
  1011. * recursion is complete and nothing
  1012. * helped.
  1013. */
  1014. break;
  1015. }
  1016. }
  1017. }
  1018. }
  1019. }
  1020. if (done_something)
  1021. continue;
  1022. #ifdef SOLVER_DIAGNOSTICS
  1023. /*
  1024. * Dump the current known state of the grid.
  1025. */
  1026. printf("solver ran out of steam, ret=%d, grid:\n", nperturbs);
  1027. for (y = 0; y < h; y++) {
  1028. for (x = 0; x < w; x++) {
  1029. int v = grid[y*w+x];
  1030. if (v == -1)
  1031. putchar('*');
  1032. else if (v == -2)
  1033. putchar('?');
  1034. else if (v == 0)
  1035. putchar('-');
  1036. else
  1037. putchar('0' + v);
  1038. }
  1039. putchar('\n');
  1040. }
  1041. {
  1042. struct set *s;
  1043. for (i = 0; (s = index234(ss->sets, i)) != NULL; i++)
  1044. printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
  1045. }
  1046. #endif
  1047. /*
  1048. * Now we really are at our wits' end as far as solving
  1049. * this grid goes. Our only remaining option is to call
  1050. * a perturb function and ask it to modify the grid to
  1051. * make it easier.
  1052. */
  1053. if (perturb) {
  1054. struct perturbations *ret;
  1055. struct set *s;
  1056. nperturbs++;
  1057. /*
  1058. * Choose a set at random from the current selection,
  1059. * and ask the perturb function to either fill or empty
  1060. * it.
  1061. *
  1062. * If we have no sets at all, we must give up.
  1063. */
  1064. if (count234(ss->sets) == 0) {
  1065. #ifdef SOLVER_DIAGNOSTICS
  1066. printf("perturbing on entire unknown set\n");
  1067. #endif
  1068. ret = perturb(ctx, grid, 0, 0, 0);
  1069. } else {
  1070. s = index234(ss->sets, random_upto(rs, count234(ss->sets)));
  1071. #ifdef SOLVER_DIAGNOSTICS
  1072. printf("perturbing on set %d,%d %03x\n", s->x, s->y, s->mask);
  1073. #endif
  1074. ret = perturb(ctx, grid, s->x, s->y, s->mask);
  1075. }
  1076. if (ret) {
  1077. assert(ret->n > 0); /* otherwise should have been NULL */
  1078. /*
  1079. * A number of squares have been fiddled with, and
  1080. * the returned structure tells us which. Adjust
  1081. * the mine count in any set which overlaps one of
  1082. * those squares, and put them back on the to-do
  1083. * list. Also, if the square itself is marked as a
  1084. * known non-mine, put it back on the squares-to-do
  1085. * list.
  1086. */
  1087. for (i = 0; i < ret->n; i++) {
  1088. #ifdef SOLVER_DIAGNOSTICS
  1089. printf("perturbation %s mine at %d,%d\n",
  1090. ret->changes[i].delta > 0 ? "added" : "removed",
  1091. ret->changes[i].x, ret->changes[i].y);
  1092. #endif
  1093. if (ret->changes[i].delta < 0 &&
  1094. grid[ret->changes[i].y*w+ret->changes[i].x] != -2) {
  1095. std_add(std, ret->changes[i].y*w+ret->changes[i].x);
  1096. }
  1097. list = ss_overlap(ss,
  1098. ret->changes[i].x, ret->changes[i].y, 1);
  1099. for (j = 0; list[j]; j++) {
  1100. list[j]->mines += ret->changes[i].delta;
  1101. ss_add_todo(ss, list[j]);
  1102. }
  1103. sfree(list);
  1104. }
  1105. /*
  1106. * Now free the returned data.
  1107. */
  1108. sfree(ret->changes);
  1109. sfree(ret);
  1110. #ifdef SOLVER_DIAGNOSTICS
  1111. /*
  1112. * Dump the current known state of the grid.
  1113. */
  1114. printf("state after perturbation:\n");
  1115. for (y = 0; y < h; y++) {
  1116. for (x = 0; x < w; x++) {
  1117. int v = grid[y*w+x];
  1118. if (v == -1)
  1119. putchar('*');
  1120. else if (v == -2)
  1121. putchar('?');
  1122. else if (v == 0)
  1123. putchar('-');
  1124. else
  1125. putchar('0' + v);
  1126. }
  1127. putchar('\n');
  1128. }
  1129. {
  1130. struct set *s;
  1131. for (i = 0; (s = index234(ss->sets, i)) != NULL; i++)
  1132. printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
  1133. }
  1134. #endif
  1135. /*
  1136. * And now we can go back round the deductive loop.
  1137. */
  1138. continue;
  1139. }
  1140. }
  1141. /*
  1142. * If we get here, even that didn't work (either we didn't
  1143. * have a perturb function or it returned failure), so we
  1144. * give up entirely.
  1145. */
  1146. break;
  1147. }
  1148. /*
  1149. * See if we've got any unknown squares left.
  1150. */
  1151. for (y = 0; y < h; y++)
  1152. for (x = 0; x < w; x++)
  1153. if (grid[y*w+x] == -2) {
  1154. nperturbs = -1; /* failed to complete */
  1155. break;
  1156. }
  1157. /*
  1158. * Free the set list and square-todo list.
  1159. */
  1160. {
  1161. struct set *s;
  1162. while ((s = delpos234(ss->sets, 0)) != NULL)
  1163. sfree(s);
  1164. freetree234(ss->sets);
  1165. sfree(ss);
  1166. sfree(std->next);
  1167. }
  1168. return nperturbs;
  1169. }
  1170. /* ----------------------------------------------------------------------
  1171. * Grid generator which uses the above solver.
  1172. */
  1173. struct minectx {
  1174. bool *grid;
  1175. int w, h;
  1176. int sx, sy;
  1177. bool allow_big_perturbs;
  1178. random_state *rs;
  1179. };
  1180. static int mineopen(void *vctx, int x, int y)
  1181. {
  1182. struct minectx *ctx = (struct minectx *)vctx;
  1183. int i, j, n;
  1184. assert(x >= 0 && x < ctx->w && y >= 0 && y < ctx->h);
  1185. if (ctx->grid[y * ctx->w + x])
  1186. return -1; /* *bang* */
  1187. n = 0;
  1188. for (i = -1; i <= +1; i++) {
  1189. if (x + i < 0 || x + i >= ctx->w)
  1190. continue;
  1191. for (j = -1; j <= +1; j++) {
  1192. if (y + j < 0 || y + j >= ctx->h)
  1193. continue;
  1194. if (i == 0 && j == 0)
  1195. continue;
  1196. if (ctx->grid[(y+j) * ctx->w + (x+i)])
  1197. n++;
  1198. }
  1199. }
  1200. return n;
  1201. }
  1202. /* Structure used internally to mineperturb(). */
  1203. struct square {
  1204. int x, y, type, random;
  1205. };
  1206. static int squarecmp(const void *av, const void *bv)
  1207. {
  1208. const struct square *a = (const struct square *)av;
  1209. const struct square *b = (const struct square *)bv;
  1210. if (a->type < b->type)
  1211. return -1;
  1212. else if (a->type > b->type)
  1213. return +1;
  1214. else if (a->random < b->random)
  1215. return -1;
  1216. else if (a->random > b->random)
  1217. return +1;
  1218. else if (a->y < b->y)
  1219. return -1;
  1220. else if (a->y > b->y)
  1221. return +1;
  1222. else if (a->x < b->x)
  1223. return -1;
  1224. else if (a->x > b->x)
  1225. return +1;
  1226. return 0;
  1227. }
  1228. /*
  1229. * Normally this function is passed an (x,y,mask) set description.
  1230. * On occasions, though, there is no _localised_ set being used,
  1231. * and the set being perturbed is supposed to be the entirety of
  1232. * the unreachable area. This is signified by the special case
  1233. * mask==0: in this case, anything labelled -2 in the grid is part
  1234. * of the set.
  1235. *
  1236. * Allowing perturbation in this special case appears to make it
  1237. * guaranteeably possible to generate a workable grid for any mine
  1238. * density, but they tend to be a bit boring, with mines packed
  1239. * densely into far corners of the grid and the remainder being
  1240. * less dense than one might like. Therefore, to improve overall
  1241. * grid quality I disable this feature for the first few attempts,
  1242. * and fall back to it after no useful grid has been generated.
  1243. */
  1244. static struct perturbations *mineperturb(void *vctx, signed char *grid,
  1245. int setx, int sety, int mask)
  1246. {
  1247. struct minectx *ctx = (struct minectx *)vctx;
  1248. struct square *sqlist;
  1249. int x, y, dx, dy, i, n, nfull, nempty;
  1250. struct square **tofill, **toempty, **todo;
  1251. int ntofill, ntoempty, ntodo, dtodo, dset;
  1252. struct perturbations *ret;
  1253. int *setlist;
  1254. if (!mask && !ctx->allow_big_perturbs)
  1255. return NULL;
  1256. /*
  1257. * Make a list of all the squares in the grid which we can
  1258. * possibly use. This list should be in preference order, which
  1259. * means
  1260. *
  1261. * - first, unknown squares on the boundary of known space
  1262. * - next, unknown squares beyond that boundary
  1263. * - as a very last resort, known squares, but not within one
  1264. * square of the starting position.
  1265. *
  1266. * Each of these sections needs to be shuffled independently.
  1267. * We do this by preparing list of all squares and then sorting
  1268. * it with a random secondary key.
  1269. */
  1270. sqlist = snewn(ctx->w * ctx->h, struct square);
  1271. n = 0;
  1272. for (y = 0; y < ctx->h; y++)
  1273. for (x = 0; x < ctx->w; x++) {
  1274. /*
  1275. * If this square is too near the starting position,
  1276. * don't put it on the list at all.
  1277. */
  1278. if (abs(y - ctx->sy) <= 1 && abs(x - ctx->sx) <= 1)
  1279. continue;
  1280. /*
  1281. * If this square is in the input set, also don't put
  1282. * it on the list!
  1283. */
  1284. if ((mask == 0 && grid[y*ctx->w+x] == -2) ||
  1285. (x >= setx && x < setx + 3 &&
  1286. y >= sety && y < sety + 3 &&
  1287. mask & (1 << ((y-sety)*3+(x-setx)))))
  1288. continue;
  1289. sqlist[n].x = x;
  1290. sqlist[n].y = y;
  1291. if (grid[y*ctx->w+x] != -2) {
  1292. sqlist[n].type = 3; /* known square */
  1293. } else {
  1294. /*
  1295. * Unknown square. Examine everything around it and
  1296. * see if it borders on any known squares. If it
  1297. * does, it's class 1, otherwise it's 2.
  1298. */
  1299. sqlist[n].type = 2;
  1300. for (dy = -1; dy <= +1; dy++)
  1301. for (dx = -1; dx <= +1; dx++)
  1302. if (x+dx >= 0 && x+dx < ctx->w &&
  1303. y+dy >= 0 && y+dy < ctx->h &&
  1304. grid[(y+dy)*ctx->w+(x+dx)] != -2) {
  1305. sqlist[n].type = 1;
  1306. break;
  1307. }
  1308. }
  1309. /*
  1310. * Finally, a random number to cause qsort to
  1311. * shuffle within each group.
  1312. */
  1313. sqlist[n].random = random_bits(ctx->rs, 31);
  1314. n++;
  1315. }
  1316. qsort(sqlist, n, sizeof(struct square), squarecmp);
  1317. /*
  1318. * Now count up the number of full and empty squares in the set
  1319. * we've been provided.
  1320. */
  1321. nfull = nempty = 0;
  1322. if (mask) {
  1323. for (dy = 0; dy < 3; dy++)
  1324. for (dx = 0; dx < 3; dx++)
  1325. if (mask & (1 << (dy*3+dx))) {
  1326. assert(setx+dx <= ctx->w);
  1327. assert(sety+dy <= ctx->h);
  1328. if (ctx->grid[(sety+dy)*ctx->w+(setx+dx)])
  1329. nfull++;
  1330. else
  1331. nempty++;
  1332. }
  1333. } else {
  1334. for (y = 0; y < ctx->h; y++)
  1335. for (x = 0; x < ctx->w; x++)
  1336. if (grid[y*ctx->w+x] == -2) {
  1337. if (ctx->grid[y*ctx->w+x])
  1338. nfull++;
  1339. else
  1340. nempty++;
  1341. }
  1342. }
  1343. /*
  1344. * Now go through our sorted list until we find either `nfull'
  1345. * empty squares, or `nempty' full squares; these will be
  1346. * swapped with the appropriate squares in the set to either
  1347. * fill or empty the set while keeping the same number of mines
  1348. * overall.
  1349. */
  1350. ntofill = ntoempty = 0;
  1351. if (mask) {
  1352. tofill = snewn(9, struct square *);
  1353. toempty = snewn(9, struct square *);
  1354. } else {
  1355. tofill = snewn(ctx->w * ctx->h, struct square *);
  1356. toempty = snewn(ctx->w * ctx->h, struct square *);
  1357. }
  1358. for (i = 0; i < n; i++) {
  1359. struct square *sq = &sqlist[i];
  1360. if (ctx->grid[sq->y * ctx->w + sq->x])
  1361. toempty[ntoempty++] = sq;
  1362. else
  1363. tofill[ntofill++] = sq;
  1364. if (ntofill == nfull || ntoempty == nempty)
  1365. break;
  1366. }
  1367. /*
  1368. * If we haven't found enough empty squares outside the set to
  1369. * empty it into _or_ enough full squares outside it to fill it
  1370. * up with, we'll have to settle for doing only a partial job.
  1371. * In this case we choose to always _fill_ the set (because
  1372. * this case will tend to crop up when we're working with very
  1373. * high mine densities and the only way to get a solvable grid
  1374. * is going to be to pack most of the mines solidly around the
  1375. * edges). So now our job is to make a list of the empty
  1376. * squares in the set, and shuffle that list so that we fill a
  1377. * random selection of them.
  1378. */
  1379. if (ntofill != nfull && ntoempty != nempty) {
  1380. int k;
  1381. assert(ntoempty != 0);
  1382. setlist = snewn(ctx->w * ctx->h, int);
  1383. i = 0;
  1384. if (mask) {
  1385. for (dy = 0; dy < 3; dy++)
  1386. for (dx = 0; dx < 3; dx++)
  1387. if (mask & (1 << (dy*3+dx))) {
  1388. assert(setx+dx <= ctx->w);
  1389. assert(sety+dy <= ctx->h);
  1390. if (!ctx->grid[(sety+dy)*ctx->w+(setx+dx)])
  1391. setlist[i++] = (sety+dy)*ctx->w+(setx+dx);
  1392. }
  1393. } else {
  1394. for (y = 0; y < ctx->h; y++)
  1395. for (x = 0; x < ctx->w; x++)
  1396. if (grid[y*ctx->w+x] == -2) {
  1397. if (!ctx->grid[y*ctx->w+x])
  1398. setlist[i++] = y*ctx->w+x;
  1399. }
  1400. }
  1401. assert(i > ntoempty);
  1402. /*
  1403. * Now pick `ntoempty' items at random from the list.
  1404. */
  1405. for (k = 0; k < ntoempty; k++) {
  1406. int index = k + random_upto(ctx->rs, i - k);
  1407. int tmp;
  1408. tmp = setlist[k];
  1409. setlist[k] = setlist[index];
  1410. setlist[index] = tmp;
  1411. }
  1412. } else
  1413. setlist = NULL;
  1414. /*
  1415. * Now we're pretty much there. We need to either
  1416. * (a) put a mine in each of the empty squares in the set, and
  1417. * take one out of each square in `toempty'
  1418. * (b) take a mine out of each of the full squares in the set,
  1419. * and put one in each square in `tofill'
  1420. * depending on which one we've found enough squares to do.
  1421. *
  1422. * So we start by constructing our list of changes to return to
  1423. * the solver, so that it can update its data structures
  1424. * efficiently rather than having to rescan the whole grid.
  1425. */
  1426. ret = snew(struct perturbations);
  1427. if (ntofill == nfull) {
  1428. todo = tofill;
  1429. ntodo = ntofill;
  1430. dtodo = +1;
  1431. dset = -1;
  1432. sfree(toempty);
  1433. } else {
  1434. /*
  1435. * (We also fall into this case if we've constructed a
  1436. * setlist.)
  1437. */
  1438. todo = toempty;
  1439. ntodo = ntoempty;
  1440. dtodo = -1;
  1441. dset = +1;
  1442. sfree(tofill);
  1443. }
  1444. ret->n = 2 * ntodo;
  1445. ret->changes = snewn(ret->n, struct perturbation);
  1446. for (i = 0; i < ntodo; i++) {
  1447. ret->changes[i].x = todo[i]->x;
  1448. ret->changes[i].y = todo[i]->y;
  1449. ret->changes[i].delta = dtodo;
  1450. }
  1451. /* now i == ntodo */
  1452. if (setlist) {
  1453. int j;
  1454. assert(todo == toempty);
  1455. for (j = 0; j < ntoempty; j++) {
  1456. ret->changes[i].x = setlist[j] % ctx->w;
  1457. ret->changes[i].y = setlist[j] / ctx->w;
  1458. ret->changes[i].delta = dset;
  1459. i++;
  1460. }
  1461. sfree(setlist);
  1462. } else if (mask) {
  1463. for (dy = 0; dy < 3; dy++)
  1464. for (dx = 0; dx < 3; dx++)
  1465. if (mask & (1 << (dy*3+dx))) {
  1466. int currval = (ctx->grid[(sety+dy)*ctx->w+(setx+dx)] ? +1 : -1);
  1467. if (dset == -currval) {
  1468. ret->changes[i].x = setx + dx;
  1469. ret->changes[i].y = sety + dy;
  1470. ret->changes[i].delta = dset;
  1471. i++;
  1472. }
  1473. }
  1474. } else {
  1475. for (y = 0; y < ctx->h; y++)
  1476. for (x = 0; x < ctx->w; x++)
  1477. if (grid[y*ctx->w+x] == -2) {
  1478. int currval = (ctx->grid[y*ctx->w+x] ? +1 : -1);
  1479. if (dset == -currval) {
  1480. ret->changes[i].x = x;
  1481. ret->changes[i].y = y;
  1482. ret->changes[i].delta = dset;
  1483. i++;
  1484. }
  1485. }
  1486. }
  1487. assert(i == ret->n);
  1488. sfree(sqlist);
  1489. sfree(todo);
  1490. /*
  1491. * Having set up the precise list of changes we're going to
  1492. * make, we now simply make them and return.
  1493. */
  1494. for (i = 0; i < ret->n; i++) {
  1495. int delta;
  1496. x = ret->changes[i].x;
  1497. y = ret->changes[i].y;
  1498. delta = ret->changes[i].delta;
  1499. /*
  1500. * Check we're not trying to add an existing mine or remove
  1501. * an absent one.
  1502. */
  1503. assert((delta < 0) ^ (ctx->grid[y*ctx->w+x] == 0));
  1504. /*
  1505. * Actually make the change.
  1506. */
  1507. ctx->grid[y*ctx->w+x] = (delta > 0);
  1508. /*
  1509. * Update any numbers already present in the grid.
  1510. */
  1511. for (dy = -1; dy <= +1; dy++)
  1512. for (dx = -1; dx <= +1; dx++)
  1513. if (x+dx >= 0 && x+dx < ctx->w &&
  1514. y+dy >= 0 && y+dy < ctx->h &&
  1515. grid[(y+dy)*ctx->w+(x+dx)] != -2) {
  1516. if (dx == 0 && dy == 0) {
  1517. /*
  1518. * The square itself is marked as known in
  1519. * the grid. Mark it as a mine if it's a
  1520. * mine, or else work out its number.
  1521. */
  1522. if (delta > 0) {
  1523. grid[y*ctx->w+x] = -1;
  1524. } else {
  1525. int dx2, dy2, minecount = 0;
  1526. for (dy2 = -1; dy2 <= +1; dy2++)
  1527. for (dx2 = -1; dx2 <= +1; dx2++)
  1528. if (x+dx2 >= 0 && x+dx2 < ctx->w &&
  1529. y+dy2 >= 0 && y+dy2 < ctx->h &&
  1530. ctx->grid[(y+dy2)*ctx->w+(x+dx2)])
  1531. minecount++;
  1532. grid[y*ctx->w+x] = minecount;
  1533. }
  1534. } else {
  1535. if (grid[(y+dy)*ctx->w+(x+dx)] >= 0)
  1536. grid[(y+dy)*ctx->w+(x+dx)] += delta;
  1537. }
  1538. }
  1539. }
  1540. #ifdef GENERATION_DIAGNOSTICS
  1541. {
  1542. int yy, xx;
  1543. printf("grid after perturbing:\n");
  1544. for (yy = 0; yy < ctx->h; yy++) {
  1545. for (xx = 0; xx < ctx->w; xx++) {
  1546. int v = ctx->grid[yy*ctx->w+xx];
  1547. if (yy == ctx->sy && xx == ctx->sx) {
  1548. assert(!v);
  1549. putchar('S');
  1550. } else if (v) {
  1551. putchar('*');
  1552. } else {
  1553. putchar('-');
  1554. }
  1555. }
  1556. putchar('\n');
  1557. }
  1558. printf("\n");
  1559. }
  1560. #endif
  1561. return ret;
  1562. }
  1563. static bool *minegen(int w, int h, int n, int x, int y, bool unique,
  1564. random_state *rs)
  1565. {
  1566. bool *ret = snewn(w*h, bool);
  1567. bool success;
  1568. int ntries = 0;
  1569. do {
  1570. success = false;
  1571. ntries++;
  1572. memset(ret, 0, w*h);
  1573. /*
  1574. * Start by placing n mines, none of which is at x,y or within
  1575. * one square of it.
  1576. */
  1577. {
  1578. int *tmp = snewn(w*h, int);
  1579. int i, j, k, nn;
  1580. /*
  1581. * Write down the list of possible mine locations.
  1582. */
  1583. k = 0;
  1584. for (i = 0; i < h; i++)
  1585. for (j = 0; j < w; j++)
  1586. if (abs(i - y) > 1 || abs(j - x) > 1)
  1587. tmp[k++] = i*w+j;
  1588. /*
  1589. * Now pick n off the list at random.
  1590. */
  1591. nn = n;
  1592. while (nn-- > 0) {
  1593. i = random_upto(rs, k);
  1594. ret[tmp[i]] = true;
  1595. tmp[i] = tmp[--k];
  1596. }
  1597. sfree(tmp);
  1598. }
  1599. #ifdef GENERATION_DIAGNOSTICS
  1600. {
  1601. int yy, xx;
  1602. printf("grid after initial generation:\n");
  1603. for (yy = 0; yy < h; yy++) {
  1604. for (xx = 0; xx < w; xx++) {
  1605. int v = ret[yy*w+xx];
  1606. if (yy == y && xx == x) {
  1607. assert(!v);
  1608. putchar('S');
  1609. } else if (v) {
  1610. putchar('*');
  1611. } else {
  1612. putchar('-');
  1613. }
  1614. }
  1615. putchar('\n');
  1616. }
  1617. printf("\n");
  1618. }
  1619. #endif
  1620. /*
  1621. * Now set up a results grid to run the solver in, and a
  1622. * context for the solver to open squares. Then run the solver
  1623. * repeatedly; if the number of perturb steps ever goes up or
  1624. * it ever returns -1, give up completely.
  1625. *
  1626. * We bypass this bit if we're not after a unique grid.
  1627. */
  1628. if (unique) {
  1629. signed char *solvegrid = snewn(w*h, signed char);
  1630. struct minectx actx, *ctx = &actx;
  1631. int solveret, prevret = -2;
  1632. ctx->grid = ret;
  1633. ctx->w = w;
  1634. ctx->h = h;
  1635. ctx->sx = x;
  1636. ctx->sy = y;
  1637. ctx->rs = rs;
  1638. ctx->allow_big_perturbs = (ntries > 100);
  1639. while (1) {
  1640. memset(solvegrid, -2, w*h);
  1641. solvegrid[y*w+x] = mineopen(ctx, x, y);
  1642. assert(solvegrid[y*w+x] == 0); /* by deliberate arrangement */
  1643. solveret =
  1644. minesolve(w, h, n, solvegrid, mineopen, mineperturb, ctx, rs);
  1645. if (solveret < 0 || (prevret >= 0 && solveret >= prevret)) {
  1646. success = false;
  1647. break;
  1648. } else if (solveret == 0) {
  1649. success = true;
  1650. break;
  1651. }
  1652. }
  1653. sfree(solvegrid);
  1654. } else {
  1655. success = true;
  1656. }
  1657. } while (!success);
  1658. return ret;
  1659. }
  1660. static char *describe_layout(bool *grid, int area, int x, int y,
  1661. bool obfuscate)
  1662. {
  1663. char *ret, *p;
  1664. unsigned char *bmp;
  1665. int i;
  1666. /*
  1667. * Set up the mine bitmap and obfuscate it.
  1668. */
  1669. bmp = snewn((area + 7) / 8, unsigned char);
  1670. memset(bmp, 0, (area + 7) / 8);
  1671. for (i = 0; i < area; i++) {
  1672. if (grid[i])
  1673. bmp[i / 8] |= 0x80 >> (i % 8);
  1674. }
  1675. if (obfuscate)
  1676. obfuscate_bitmap(bmp, area, false);
  1677. /*
  1678. * Now encode the resulting bitmap in hex. We can work to
  1679. * nibble rather than byte granularity, since the obfuscation
  1680. * function guarantees to return a bit string of the same
  1681. * length as its input.
  1682. */
  1683. ret = snewn((area+3)/4 + 100, char);
  1684. p = ret + sprintf(ret, "%d,%d,%s", x, y,
  1685. obfuscate ? "m" : "u"); /* 'm' == masked */
  1686. for (i = 0; i < (area+3)/4; i++) {
  1687. int v = bmp[i/2];
  1688. if (i % 2 == 0)
  1689. v >>= 4;
  1690. *p++ = "0123456789abcdef"[v & 0xF];
  1691. }
  1692. *p = '\0';
  1693. sfree(bmp);
  1694. return ret;
  1695. }
  1696. static bool *new_mine_layout(int w, int h, int n, int x, int y, bool unique,
  1697. random_state *rs, char **game_desc)
  1698. {
  1699. bool *grid = minegen(w, h, n, x, y, unique, rs);
  1700. if (game_desc)
  1701. *game_desc = describe_layout(grid, w * h, x, y, true);
  1702. return grid;
  1703. }
  1704. static char *new_game_desc(const game_params *params, random_state *rs,
  1705. char **aux, bool interactive)
  1706. {
  1707. /*
  1708. * We generate the coordinates of an initial click even if they
  1709. * aren't actually used. This has the effect of harmonising the
  1710. * random number usage between interactive and batch use: if
  1711. * you use `mines --generate' with an explicit random seed, you
  1712. * should get exactly the same results as if you type the same
  1713. * random seed into the interactive game and click in the same
  1714. * initial location. (Of course you won't get the same grid if
  1715. * you click in a _different_ initial location, but there's
  1716. * nothing to be done about that.)
  1717. */
  1718. int x = random_upto(rs, params->w);
  1719. int y = random_upto(rs, params->h);
  1720. if (!interactive) {
  1721. /*
  1722. * For batch-generated grids, pre-open one square.
  1723. */
  1724. bool *grid;
  1725. char *desc;
  1726. grid = new_mine_layout(params->w, params->h, params->n,
  1727. x, y, params->unique, rs, &desc);
  1728. sfree(grid);
  1729. return desc;
  1730. } else {
  1731. char *rsdesc, *desc;
  1732. rsdesc = random_state_encode(rs);
  1733. desc = snewn(strlen(rsdesc) + 100, char);
  1734. sprintf(desc, "r%d,%c,%s", params->n, (char)(params->unique ? 'u' : 'a'), rsdesc);
  1735. sfree(rsdesc);
  1736. return desc;
  1737. }
  1738. }
  1739. static const char *validate_desc(const game_params *params, const char *desc)
  1740. {
  1741. int wh = params->w * params->h;
  1742. int x, y;
  1743. if (*desc == 'r') {
  1744. desc++;
  1745. if (!*desc || !isdigit((unsigned char)*desc))
  1746. return "No initial mine count in game description";
  1747. if (atoi(desc) > wh - 9)
  1748. return "Too many mines for grid size";
  1749. while (*desc && isdigit((unsigned char)*desc))
  1750. desc++; /* skip over mine count */
  1751. if (*desc != ',')
  1752. return "No ',' after initial x-coordinate in game description";
  1753. desc++;
  1754. if (*desc != 'u' && *desc != 'a')
  1755. return "No uniqueness specifier in game description";
  1756. desc++;
  1757. if (*desc != ',')
  1758. return "No ',' after uniqueness specifier in game description";
  1759. /* now ignore the rest */
  1760. } else {
  1761. if (*desc && isdigit((unsigned char)*desc)) {
  1762. x = atoi(desc);
  1763. if (x < 0 || x >= params->w)
  1764. return "Initial x-coordinate was out of range";
  1765. while (*desc && isdigit((unsigned char)*desc))
  1766. desc++; /* skip over x coordinate */
  1767. if (*desc != ',')
  1768. return "No ',' after initial x-coordinate in game description";
  1769. desc++; /* eat comma */
  1770. if (!*desc || !isdigit((unsigned char)*desc))
  1771. return "No initial y-coordinate in game description";
  1772. y = atoi(desc);
  1773. if (y < 0 || y >= params->h)
  1774. return "Initial y-coordinate was out of range";
  1775. while (*desc && isdigit((unsigned char)*desc))
  1776. desc++; /* skip over y coordinate */
  1777. if (*desc != ',')
  1778. return "No ',' after initial y-coordinate in game description";
  1779. desc++; /* eat comma */
  1780. }
  1781. /* eat `m' for `masked' or `u' for `unmasked', if present */
  1782. if (*desc == 'm' || *desc == 'u')
  1783. desc++;
  1784. /* now just check length of remainder */
  1785. if (strlen(desc) != (wh+3)/4)
  1786. return "Game description is wrong length";
  1787. }
  1788. return NULL;
  1789. }
  1790. static int open_square(game_state *state, int x, int y)
  1791. {
  1792. int w = state->w, h = state->h;
  1793. int xx, yy, nmines, ncovered;
  1794. if (!state->layout->mines) {
  1795. /*
  1796. * We have a preliminary game in which the mine layout
  1797. * hasn't been generated yet. Generate it based on the
  1798. * initial click location.
  1799. */
  1800. char *desc, *privdesc;
  1801. state->layout->mines = new_mine_layout(w, h, state->layout->n,
  1802. x, y, state->layout->unique,
  1803. state->layout->rs,
  1804. &desc);
  1805. /*
  1806. * Find the trailing substring of the game description
  1807. * corresponding to just the mine layout; we will use this
  1808. * as our second `private' game ID for serialisation.
  1809. */
  1810. privdesc = desc;
  1811. while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++;
  1812. if (*privdesc == ',') privdesc++;
  1813. while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++;
  1814. if (*privdesc == ',') privdesc++;
  1815. assert(*privdesc == 'm');
  1816. midend_supersede_game_desc(state->layout->me, desc, privdesc);
  1817. sfree(desc);
  1818. random_free(state->layout->rs);
  1819. state->layout->rs = NULL;
  1820. }
  1821. if (state->layout->mines[y*w+x]) {
  1822. /*
  1823. * The player has landed on a mine. Bad luck. Expose the
  1824. * mine that killed them, but not the rest (in case they
  1825. * want to Undo and carry on playing).
  1826. */
  1827. state->dead = true;
  1828. state->grid[y*w+x] = 65;
  1829. return -1;
  1830. }
  1831. /*
  1832. * Otherwise, the player has opened a safe square. Mark it to-do.
  1833. */
  1834. state->grid[y*w+x] = -10; /* `todo' value internal to this func */
  1835. /*
  1836. * Now go through the grid finding all `todo' values and
  1837. * opening them. Every time one of them turns out to have no
  1838. * neighbouring mines, we add all its unopened neighbours to
  1839. * the list as well.
  1840. *
  1841. * FIXME: We really ought to be able to do this better than
  1842. * using repeated N^2 scans of the grid.
  1843. */
  1844. while (1) {
  1845. bool done_something = false;
  1846. for (yy = 0; yy < h; yy++)
  1847. for (xx = 0; xx < w; xx++)
  1848. if (state->grid[yy*w+xx] == -10) {
  1849. int dx, dy, v;
  1850. assert(!state->layout->mines[yy*w+xx]);
  1851. v = 0;
  1852. for (dx = -1; dx <= +1; dx++)
  1853. for (dy = -1; dy <= +1; dy++)
  1854. if (xx+dx >= 0 && xx+dx < state->w &&
  1855. yy+dy >= 0 && yy+dy < state->h &&
  1856. state->layout->mines[(yy+dy)*w+(xx+dx)])
  1857. v++;
  1858. state->grid[yy*w+xx] = v;
  1859. if (v == 0) {
  1860. for (dx = -1; dx <= +1; dx++)
  1861. for (dy = -1; dy <= +1; dy++)
  1862. if (xx+dx >= 0 && xx+dx < state->w &&
  1863. yy+dy >= 0 && yy+dy < state->h &&
  1864. state->grid[(yy+dy)*w+(xx+dx)] == -2)
  1865. state->grid[(yy+dy)*w+(xx+dx)] = -10;
  1866. }
  1867. done_something = true;
  1868. }
  1869. if (!done_something)
  1870. break;
  1871. }
  1872. /* If the player has already lost, don't let them win as well. */
  1873. if (state->dead) return 0;
  1874. /*
  1875. * Finally, scan the grid and see if exactly as many squares
  1876. * are still covered as there are mines. If so, set the `won'
  1877. * flag and fill in mine markers on all covered squares.
  1878. */
  1879. nmines = ncovered = 0;
  1880. for (yy = 0; yy < h; yy++)
  1881. for (xx = 0; xx < w; xx++) {
  1882. if (state->grid[yy*w+xx] < 0)
  1883. ncovered++;
  1884. if (state->layout->mines[yy*w+xx])
  1885. nmines++;
  1886. }
  1887. assert(ncovered >= nmines);
  1888. if (ncovered == nmines) {
  1889. for (yy = 0; yy < h; yy++)
  1890. for (xx = 0; xx < w; xx++) {
  1891. if (state->grid[yy*w+xx] < 0)
  1892. state->grid[yy*w+xx] = -1;
  1893. }
  1894. state->won = true;
  1895. }
  1896. return 0;
  1897. }
  1898. static game_state *new_game(midend *me, const game_params *params,
  1899. const char *desc)
  1900. {
  1901. game_state *state = snew(game_state);
  1902. int i, wh, x, y;
  1903. bool masked;
  1904. unsigned char *bmp;
  1905. state->w = params->w;
  1906. state->h = params->h;
  1907. state->n = params->n;
  1908. state->dead = state->won = false;
  1909. state->used_solve = false;
  1910. wh = state->w * state->h;
  1911. state->layout = snew(struct mine_layout);
  1912. memset(state->layout, 0, sizeof(struct mine_layout));
  1913. state->layout->refcount = 1;
  1914. state->grid = snewn(wh, signed char);
  1915. memset(state->grid, -2, wh);
  1916. if (*desc == 'r') {
  1917. desc++;
  1918. state->layout->n = atoi(desc);
  1919. while (*desc && isdigit((unsigned char)*desc))
  1920. desc++; /* skip over mine count */
  1921. if (*desc) desc++; /* eat comma */
  1922. if (*desc == 'a')
  1923. state->layout->unique = false;
  1924. else
  1925. state->layout->unique = true;
  1926. desc++;
  1927. if (*desc) desc++; /* eat comma */
  1928. state->layout->mines = NULL;
  1929. state->layout->rs = random_state_decode(desc);
  1930. state->layout->me = me;
  1931. } else {
  1932. state->layout->rs = NULL;
  1933. state->layout->me = NULL;
  1934. state->layout->mines = snewn(wh, bool);
  1935. if (*desc && isdigit((unsigned char)*desc)) {
  1936. x = atoi(desc);
  1937. while (*desc && isdigit((unsigned char)*desc))
  1938. desc++; /* skip over x coordinate */
  1939. if (*desc) desc++; /* eat comma */
  1940. y = atoi(desc);
  1941. while (*desc && isdigit((unsigned char)*desc))
  1942. desc++; /* skip over y coordinate */
  1943. if (*desc) desc++; /* eat comma */
  1944. } else {
  1945. x = y = -1;
  1946. }
  1947. if (*desc == 'm') {
  1948. masked = true;
  1949. desc++;
  1950. } else {
  1951. if (*desc == 'u')
  1952. desc++;
  1953. /*
  1954. * We permit game IDs to be entered by hand without the
  1955. * masking transformation.
  1956. */
  1957. masked = false;
  1958. }
  1959. bmp = snewn((wh + 7) / 8, unsigned char);
  1960. memset(bmp, 0, (wh + 7) / 8);
  1961. for (i = 0; i < (wh+3)/4; i++) {
  1962. int c = desc[i];
  1963. int v;
  1964. assert(c != 0); /* validate_desc should have caught */
  1965. if (c >= '0' && c <= '9')
  1966. v = c - '0';
  1967. else if (c >= 'a' && c <= 'f')
  1968. v = c - 'a' + 10;
  1969. else if (c >= 'A' && c <= 'F')
  1970. v = c - 'A' + 10;
  1971. else
  1972. v = 0;
  1973. bmp[i / 2] |= v << (4 * (1 - (i % 2)));
  1974. }
  1975. if (masked)
  1976. obfuscate_bitmap(bmp, wh, true);
  1977. memset(state->layout->mines, 0, wh * sizeof(bool));
  1978. for (i = 0; i < wh; i++) {
  1979. if (bmp[i / 8] & (0x80 >> (i % 8)))
  1980. state->layout->mines[i] = true;
  1981. }
  1982. if (x >= 0 && y >= 0)
  1983. open_square(state, x, y);
  1984. sfree(bmp);
  1985. }
  1986. return state;
  1987. }
  1988. static game_state *dup_game(const game_state *state)
  1989. {
  1990. game_state *ret = snew(game_state);
  1991. ret->w = state->w;
  1992. ret->h = state->h;
  1993. ret->n = state->n;
  1994. ret->dead = state->dead;
  1995. ret->won = state->won;
  1996. ret->used_solve = state->used_solve;
  1997. ret->layout = state->layout;
  1998. ret->layout->refcount++;
  1999. ret->grid = snewn(ret->w * ret->h, signed char);
  2000. memcpy(ret->grid, state->grid, ret->w * ret->h);
  2001. return ret;
  2002. }
  2003. static void free_game(game_state *state)
  2004. {
  2005. if (--state->layout->refcount <= 0) {
  2006. sfree(state->layout->mines);
  2007. if (state->layout->rs)
  2008. random_free(state->layout->rs);
  2009. sfree(state->layout);
  2010. }
  2011. sfree(state->grid);
  2012. sfree(state);
  2013. }
  2014. static char *solve_game(const game_state *state, const game_state *currstate,
  2015. const char *aux, const char **error)
  2016. {
  2017. if (!state->layout->mines) {
  2018. *error = "Game has not been started yet";
  2019. return NULL;
  2020. }
  2021. return dupstr("S");
  2022. }
  2023. static bool game_can_format_as_text_now(const game_params *params)
  2024. {
  2025. return true;
  2026. }
  2027. static char *game_text_format(const game_state *state)
  2028. {
  2029. char *ret;
  2030. int x, y;
  2031. ret = snewn((state->w + 1) * state->h + 1, char);
  2032. for (y = 0; y < state->h; y++) {
  2033. for (x = 0; x < state->w; x++) {
  2034. int v = state->grid[y*state->w+x];
  2035. if (v == 0)
  2036. v = '-';
  2037. else if (v >= 1 && v <= 8)
  2038. v = '0' + v;
  2039. else if (v == -1)
  2040. v = '*';
  2041. else if (v == -2 || v == -3)
  2042. v = '?';
  2043. else if (v >= 64)
  2044. v = '!';
  2045. ret[y * (state->w+1) + x] = v;
  2046. }
  2047. ret[y * (state->w+1) + state->w] = '\n';
  2048. }
  2049. ret[(state->w + 1) * state->h] = '\0';
  2050. return ret;
  2051. }
  2052. struct game_ui {
  2053. int hx, hy, hradius; /* for mouse-down highlights */
  2054. int validradius;
  2055. bool flash_is_death;
  2056. int deaths;
  2057. bool completed;
  2058. int cur_x, cur_y;
  2059. bool cur_visible;
  2060. };
  2061. static game_ui *new_ui(const game_state *state)
  2062. {
  2063. game_ui *ui = snew(game_ui);
  2064. ui->hx = ui->hy = -1;
  2065. ui->hradius = ui->validradius = 0;
  2066. ui->deaths = 0;
  2067. ui->completed = false;
  2068. ui->flash_is_death = false; /* *shrug* */
  2069. ui->cur_x = ui->cur_y = 0;
  2070. ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
  2071. return ui;
  2072. }
  2073. static void free_ui(game_ui *ui)
  2074. {
  2075. sfree(ui);
  2076. }
  2077. static char *encode_ui(const game_ui *ui)
  2078. {
  2079. char buf[80];
  2080. /*
  2081. * The deaths counter and completion status need preserving
  2082. * across a serialisation.
  2083. */
  2084. sprintf(buf, "D%d", ui->deaths);
  2085. if (ui->completed)
  2086. strcat(buf, "C");
  2087. return dupstr(buf);
  2088. }
  2089. static void decode_ui(game_ui *ui, const char *encoding,
  2090. const game_state *state)
  2091. {
  2092. int p= 0;
  2093. sscanf(encoding, "D%d%n", &ui->deaths, &p);
  2094. if (encoding[p] == 'C')
  2095. ui->completed = true;
  2096. }
  2097. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  2098. const game_state *newstate)
  2099. {
  2100. if (newstate->won)
  2101. ui->completed = true;
  2102. }
  2103. static const char *current_key_label(const game_ui *ui,
  2104. const game_state *state, int button)
  2105. {
  2106. int cx = ui->cur_x, cy = ui->cur_y;
  2107. int v = state->grid[cy * state->w + cx];
  2108. if (state->dead || state->won || !ui->cur_visible) return "";
  2109. if (button == CURSOR_SELECT2) {
  2110. if (v == -2) return "Mark";
  2111. if (v == -1) return "Unmark";
  2112. return "";
  2113. }
  2114. if (button == CURSOR_SELECT) {
  2115. int dy, dx, n = 0;
  2116. if (v == -2 || v == -3) return "Uncover";
  2117. if (v == 0) return "";
  2118. /* Count mine markers. */
  2119. for (dy = -1; dy <= +1; dy++)
  2120. for (dx = -1; dx <= +1; dx++)
  2121. if (cx+dx >= 0 && cx+dx < state->w &&
  2122. cy+dy >= 0 && cy+dy < state->h) {
  2123. if (state->grid[(cy+dy)*state->w+(cx+dx)] == -1)
  2124. n++;
  2125. }
  2126. if (n == v) return "Clear";
  2127. }
  2128. return "";
  2129. }
  2130. struct game_drawstate {
  2131. int w, h, tilesize, bg;
  2132. bool started;
  2133. signed char *grid;
  2134. /*
  2135. * Items in this `grid' array have all the same values as in
  2136. * the game_state grid, and in addition:
  2137. *
  2138. * - -10 means the tile was drawn `specially' as a result of a
  2139. * flash, so it will always need redrawing.
  2140. *
  2141. * - -22 and -23 mean the tile is highlighted for a possible
  2142. * click.
  2143. */
  2144. int cur_x, cur_y; /* -1, -1 for no cursor displayed. */
  2145. };
  2146. static char *interpret_move(const game_state *from, game_ui *ui,
  2147. const game_drawstate *ds,
  2148. int x, int y, int button)
  2149. {
  2150. int cx, cy;
  2151. char buf[256];
  2152. if (from->dead || from->won)
  2153. return NULL; /* no further moves permitted */
  2154. cx = FROMCOORD(x);
  2155. cy = FROMCOORD(y);
  2156. if (IS_CURSOR_MOVE(button)) {
  2157. move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false);
  2158. ui->cur_visible = true;
  2159. return MOVE_UI_UPDATE;
  2160. }
  2161. if (IS_CURSOR_SELECT(button)) {
  2162. int v = from->grid[ui->cur_y * from->w + ui->cur_x];
  2163. if (!ui->cur_visible) {
  2164. ui->cur_visible = true;
  2165. return MOVE_UI_UPDATE;
  2166. }
  2167. if (button == CURSOR_SELECT2) {
  2168. /* As for RIGHT_BUTTON; only works on covered square. */
  2169. if (v != -2 && v != -1)
  2170. return MOVE_NO_EFFECT;
  2171. sprintf(buf, "F%d,%d", ui->cur_x, ui->cur_y);
  2172. return dupstr(buf);
  2173. }
  2174. /* Otherwise, treat as LEFT_BUTTON, for a single square. */
  2175. if (v == -2 || v == -3) {
  2176. if (from->layout->mines &&
  2177. from->layout->mines[ui->cur_y * from->w + ui->cur_x])
  2178. ui->deaths++;
  2179. sprintf(buf, "O%d,%d", ui->cur_x, ui->cur_y);
  2180. return dupstr(buf);
  2181. }
  2182. cx = ui->cur_x; cy = ui->cur_y;
  2183. ui->validradius = 1;
  2184. goto uncover;
  2185. }
  2186. if (button == LEFT_BUTTON || button == LEFT_DRAG ||
  2187. button == MIDDLE_BUTTON || button == MIDDLE_DRAG) {
  2188. if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
  2189. return MOVE_UNUSED;
  2190. /*
  2191. * Mouse-downs and mouse-drags just cause highlighting
  2192. * updates.
  2193. */
  2194. ui->hx = cx;
  2195. ui->hy = cy;
  2196. ui->hradius = (from->grid[cy*from->w+cx] >= 0 ? 1 : 0);
  2197. if (button == LEFT_BUTTON)
  2198. ui->validradius = ui->hradius;
  2199. else if (button == MIDDLE_BUTTON)
  2200. ui->validradius = 1;
  2201. ui->cur_visible = false;
  2202. return MOVE_UI_UPDATE;
  2203. }
  2204. if (button == RIGHT_BUTTON) {
  2205. if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
  2206. return MOVE_UNUSED;
  2207. /*
  2208. * Right-clicking only works on a covered square, and it
  2209. * toggles between -1 (marked as mine) and -2 (not marked
  2210. * as mine).
  2211. *
  2212. * FIXME: question marks.
  2213. */
  2214. if (from->grid[cy * from->w + cx] != -2 &&
  2215. from->grid[cy * from->w + cx] != -1)
  2216. return MOVE_NO_EFFECT;
  2217. sprintf(buf, "F%d,%d", cx, cy);
  2218. return dupstr(buf);
  2219. }
  2220. if (button == LEFT_RELEASE || button == MIDDLE_RELEASE) {
  2221. ui->hx = ui->hy = -1;
  2222. ui->hradius = 0;
  2223. /*
  2224. * At this stage we must never return MOVE_UNUSED or
  2225. * MOVE_NO_EFFECT: we have adjusted the ui, so at worst we
  2226. * return MOVE_UI_UPDATE.
  2227. */
  2228. if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
  2229. return MOVE_UI_UPDATE;
  2230. /*
  2231. * Left-clicking on a covered square opens a tile. Not
  2232. * permitted if the tile is marked as a mine, for safety.
  2233. * (Unmark it and _then_ open it.)
  2234. */
  2235. if (button == LEFT_RELEASE &&
  2236. (from->grid[cy * from->w + cx] == -2 ||
  2237. from->grid[cy * from->w + cx] == -3) &&
  2238. ui->validradius == 0) {
  2239. /* Check if you've killed yourself. */
  2240. if (from->layout->mines && from->layout->mines[cy * from->w + cx])
  2241. ui->deaths++;
  2242. sprintf(buf, "O%d,%d", cx, cy);
  2243. return dupstr(buf);
  2244. }
  2245. goto uncover;
  2246. }
  2247. return MOVE_UNUSED;
  2248. uncover:
  2249. {
  2250. /*
  2251. * Left-clicking or middle-clicking on an uncovered tile:
  2252. * first we check to see if the number of mine markers
  2253. * surrounding the tile is equal to its mine count, and if
  2254. * so then we open all other surrounding squares.
  2255. */
  2256. if (from->grid[cy * from->w + cx] > 0 && ui->validradius == 1) {
  2257. int dy, dx, n;
  2258. /* Count mine markers. */
  2259. n = 0;
  2260. for (dy = -1; dy <= +1; dy++)
  2261. for (dx = -1; dx <= +1; dx++)
  2262. if (cx+dx >= 0 && cx+dx < from->w &&
  2263. cy+dy >= 0 && cy+dy < from->h) {
  2264. if (from->grid[(cy+dy)*from->w+(cx+dx)] == -1)
  2265. n++;
  2266. }
  2267. if (n == from->grid[cy * from->w + cx]) {
  2268. /*
  2269. * Now see if any of the squares we're clearing
  2270. * contains a mine (which will happen iff you've
  2271. * incorrectly marked the mines around the clicked
  2272. * square). If so, we open _just_ those squares, to
  2273. * reveal as little additional information as we
  2274. * can.
  2275. */
  2276. char *p = buf;
  2277. const char *sep = "";
  2278. for (dy = -1; dy <= +1; dy++)
  2279. for (dx = -1; dx <= +1; dx++)
  2280. if (cx+dx >= 0 && cx+dx < from->w &&
  2281. cy+dy >= 0 && cy+dy < from->h) {
  2282. if (from->grid[(cy+dy)*from->w+(cx+dx)] != -1 &&
  2283. from->layout->mines &&
  2284. from->layout->mines[(cy+dy)*from->w+(cx+dx)]) {
  2285. p += sprintf(p, "%sO%d,%d", sep, cx+dx, cy+dy);
  2286. sep = ";";
  2287. }
  2288. }
  2289. if (p > buf) {
  2290. ui->deaths++;
  2291. } else {
  2292. sprintf(buf, "C%d,%d", cx, cy);
  2293. }
  2294. return dupstr(buf);
  2295. }
  2296. }
  2297. return MOVE_UI_UPDATE;
  2298. }
  2299. }
  2300. static game_state *execute_move(const game_state *from, const char *move)
  2301. {
  2302. int cy, cx;
  2303. game_state *ret;
  2304. if (!strcmp(move, "S")) {
  2305. int yy, xx;
  2306. if (!from->layout->mines) return NULL; /* Game not started. */
  2307. ret = dup_game(from);
  2308. if (!ret->dead) {
  2309. /*
  2310. * If the player is still alive at the moment of pressing
  2311. * Solve, expose the entire grid as if it were a completed
  2312. * solution.
  2313. */
  2314. for (yy = 0; yy < ret->h; yy++)
  2315. for (xx = 0; xx < ret->w; xx++) {
  2316. if (ret->layout->mines[yy*ret->w+xx]) {
  2317. ret->grid[yy*ret->w+xx] = -1;
  2318. } else {
  2319. int dx, dy, v;
  2320. v = 0;
  2321. for (dx = -1; dx <= +1; dx++)
  2322. for (dy = -1; dy <= +1; dy++)
  2323. if (xx+dx >= 0 && xx+dx < ret->w &&
  2324. yy+dy >= 0 && yy+dy < ret->h &&
  2325. ret->layout->mines[(yy+dy)*ret->w+(xx+dx)])
  2326. v++;
  2327. ret->grid[yy*ret->w+xx] = v;
  2328. }
  2329. }
  2330. } else {
  2331. /*
  2332. * If the player pressed Solve _after dying_, show a full
  2333. * corrections grid in the style of standard Minesweeper.
  2334. * Players who don't like Mines's behaviour on death of
  2335. * only showing the mine that killed you (so that in case
  2336. * of a typo you can undo and carry on without the rest of
  2337. * the grid being spoiled) can use this to get the display
  2338. * that ordinary Minesweeper would have given them.
  2339. */
  2340. for (yy = 0; yy < ret->h; yy++)
  2341. for (xx = 0; xx < ret->w; xx++) {
  2342. int pos = yy*ret->w+xx;
  2343. if ((ret->grid[pos] == -2 || ret->grid[pos] == -3) &&
  2344. ret->layout->mines[pos]) {
  2345. ret->grid[pos] = 64;
  2346. } else if (ret->grid[pos] == -1 &&
  2347. !ret->layout->mines[pos]) {
  2348. ret->grid[pos] = 66;
  2349. }
  2350. }
  2351. }
  2352. ret->used_solve = true;
  2353. return ret;
  2354. } else {
  2355. /* Dead players should stop trying to move. */
  2356. if (from->dead)
  2357. return NULL;
  2358. ret = dup_game(from);
  2359. while (*move) {
  2360. if (move[0] == 'F' &&
  2361. sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
  2362. cx >= 0 && cx < from->w && cy >= 0 && cy < from->h &&
  2363. (ret->grid[cy * from->w + cx] == -1 ||
  2364. ret->grid[cy * from->w + cx] == -2)) {
  2365. ret->grid[cy * from->w + cx] ^= (-2 ^ -1);
  2366. } else if (move[0] == 'O' &&
  2367. sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
  2368. cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
  2369. open_square(ret, cx, cy);
  2370. } else if (move[0] == 'C' &&
  2371. sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
  2372. cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
  2373. int dx, dy;
  2374. for (dy = -1; dy <= +1; dy++)
  2375. for (dx = -1; dx <= +1; dx++)
  2376. if (cx+dx >= 0 && cx+dx < ret->w &&
  2377. cy+dy >= 0 && cy+dy < ret->h &&
  2378. (ret->grid[(cy+dy)*ret->w+(cx+dx)] == -2 ||
  2379. ret->grid[(cy+dy)*ret->w+(cx+dx)] == -3))
  2380. open_square(ret, cx+dx, cy+dy);
  2381. } else {
  2382. free_game(ret);
  2383. return NULL;
  2384. }
  2385. while (*move && *move != ';') move++;
  2386. if (*move) move++;
  2387. }
  2388. return ret;
  2389. }
  2390. }
  2391. /* ----------------------------------------------------------------------
  2392. * Drawing routines.
  2393. */
  2394. static void game_compute_size(const game_params *params, int tilesize,
  2395. const game_ui *ui, int *x, int *y)
  2396. {
  2397. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  2398. struct { int tilesize; } ads, *ds = &ads;
  2399. ads.tilesize = tilesize;
  2400. *x = BORDER * 2 + TILE_SIZE * params->w;
  2401. *y = BORDER * 2 + TILE_SIZE * params->h;
  2402. }
  2403. static void game_set_size(drawing *dr, game_drawstate *ds,
  2404. const game_params *params, int tilesize)
  2405. {
  2406. ds->tilesize = tilesize;
  2407. }
  2408. static float *game_colours(frontend *fe, int *ncolours)
  2409. {
  2410. float *ret = snewn(3 * NCOLOURS, float);
  2411. frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
  2412. ret[COL_BACKGROUND2 * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 19.0F / 20.0F;
  2413. ret[COL_BACKGROUND2 * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 19.0F / 20.0F;
  2414. ret[COL_BACKGROUND2 * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 19.0F / 20.0F;
  2415. ret[COL_1 * 3 + 0] = 0.0F;
  2416. ret[COL_1 * 3 + 1] = 0.0F;
  2417. ret[COL_1 * 3 + 2] = 1.0F;
  2418. ret[COL_2 * 3 + 0] = 0.0F;
  2419. ret[COL_2 * 3 + 1] = 0.5F;
  2420. ret[COL_2 * 3 + 2] = 0.0F;
  2421. ret[COL_3 * 3 + 0] = 1.0F;
  2422. ret[COL_3 * 3 + 1] = 0.0F;
  2423. ret[COL_3 * 3 + 2] = 0.0F;
  2424. ret[COL_4 * 3 + 0] = 0.0F;
  2425. ret[COL_4 * 3 + 1] = 0.0F;
  2426. ret[COL_4 * 3 + 2] = 0.5F;
  2427. ret[COL_5 * 3 + 0] = 0.5F;
  2428. ret[COL_5 * 3 + 1] = 0.0F;
  2429. ret[COL_5 * 3 + 2] = 0.0F;
  2430. ret[COL_6 * 3 + 0] = 0.0F;
  2431. ret[COL_6 * 3 + 1] = 0.5F;
  2432. ret[COL_6 * 3 + 2] = 0.5F;
  2433. ret[COL_7 * 3 + 0] = 0.0F;
  2434. ret[COL_7 * 3 + 1] = 0.0F;
  2435. ret[COL_7 * 3 + 2] = 0.0F;
  2436. ret[COL_8 * 3 + 0] = 0.5F;
  2437. ret[COL_8 * 3 + 1] = 0.5F;
  2438. ret[COL_8 * 3 + 2] = 0.5F;
  2439. ret[COL_MINE * 3 + 0] = 0.0F;
  2440. ret[COL_MINE * 3 + 1] = 0.0F;
  2441. ret[COL_MINE * 3 + 2] = 0.0F;
  2442. ret[COL_BANG * 3 + 0] = 1.0F;
  2443. ret[COL_BANG * 3 + 1] = 0.0F;
  2444. ret[COL_BANG * 3 + 2] = 0.0F;
  2445. ret[COL_CROSS * 3 + 0] = 1.0F;
  2446. ret[COL_CROSS * 3 + 1] = 0.0F;
  2447. ret[COL_CROSS * 3 + 2] = 0.0F;
  2448. ret[COL_FLAG * 3 + 0] = 1.0F;
  2449. ret[COL_FLAG * 3 + 1] = 0.0F;
  2450. ret[COL_FLAG * 3 + 2] = 0.0F;
  2451. ret[COL_FLAGBASE * 3 + 0] = 0.0F;
  2452. ret[COL_FLAGBASE * 3 + 1] = 0.0F;
  2453. ret[COL_FLAGBASE * 3 + 2] = 0.0F;
  2454. ret[COL_QUERY * 3 + 0] = 0.0F;
  2455. ret[COL_QUERY * 3 + 1] = 0.0F;
  2456. ret[COL_QUERY * 3 + 2] = 0.0F;
  2457. ret[COL_HIGHLIGHT * 3 + 0] = 1.0F;
  2458. ret[COL_HIGHLIGHT * 3 + 1] = 1.0F;
  2459. ret[COL_HIGHLIGHT * 3 + 2] = 1.0F;
  2460. ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F;
  2461. ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F;
  2462. ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F;
  2463. ret[COL_WRONGNUMBER * 3 + 0] = 1.0F;
  2464. ret[COL_WRONGNUMBER * 3 + 1] = 0.6F;
  2465. ret[COL_WRONGNUMBER * 3 + 2] = 0.6F;
  2466. /* Red tinge to a light colour, for the cursor. */
  2467. ret[COL_CURSOR * 3 + 0] = ret[COL_HIGHLIGHT * 3 + 0];
  2468. ret[COL_CURSOR * 3 + 1] = ret[COL_HIGHLIGHT * 3 + 0] / 2.0F;
  2469. ret[COL_CURSOR * 3 + 2] = ret[COL_HIGHLIGHT * 3 + 0] / 2.0F;
  2470. *ncolours = NCOLOURS;
  2471. return ret;
  2472. }
  2473. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  2474. {
  2475. struct game_drawstate *ds = snew(struct game_drawstate);
  2476. ds->w = state->w;
  2477. ds->h = state->h;
  2478. ds->started = false;
  2479. ds->tilesize = 0; /* not decided yet */
  2480. ds->grid = snewn(ds->w * ds->h, signed char);
  2481. ds->bg = -1;
  2482. ds->cur_x = ds->cur_y = -1;
  2483. memset(ds->grid, -99, ds->w * ds->h);
  2484. return ds;
  2485. }
  2486. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  2487. {
  2488. sfree(ds->grid);
  2489. sfree(ds);
  2490. }
  2491. static void draw_tile(drawing *dr, game_drawstate *ds,
  2492. int x, int y, int v, int bg)
  2493. {
  2494. if (v < 0) {
  2495. int coords[12];
  2496. int hl = 0;
  2497. if (v == -22 || v == -23) {
  2498. v += 20;
  2499. /*
  2500. * Omit the highlights in this case.
  2501. */
  2502. draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
  2503. bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg);
  2504. draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
  2505. draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
  2506. } else {
  2507. /*
  2508. * Draw highlights to indicate the square is covered.
  2509. */
  2510. coords[0] = x + TILE_SIZE - 1;
  2511. coords[1] = y + TILE_SIZE - 1;
  2512. coords[2] = x + TILE_SIZE - 1;
  2513. coords[3] = y;
  2514. coords[4] = x;
  2515. coords[5] = y + TILE_SIZE - 1;
  2516. draw_polygon(dr, coords, 3, COL_LOWLIGHT ^ hl, COL_LOWLIGHT ^ hl);
  2517. coords[0] = x;
  2518. coords[1] = y;
  2519. draw_polygon(dr, coords, 3, COL_HIGHLIGHT ^ hl,
  2520. COL_HIGHLIGHT ^ hl);
  2521. draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH,
  2522. TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH,
  2523. bg);
  2524. }
  2525. if (v == -1) {
  2526. /*
  2527. * Draw a flag.
  2528. */
  2529. #define SETCOORD(n, dx, dy) do { \
  2530. coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \
  2531. coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \
  2532. } while (0)
  2533. SETCOORD(0, 0.6F, 0.35F);
  2534. SETCOORD(1, 0.6F, 0.7F);
  2535. SETCOORD(2, 0.8F, 0.8F);
  2536. SETCOORD(3, 0.25F, 0.8F);
  2537. SETCOORD(4, 0.55F, 0.7F);
  2538. SETCOORD(5, 0.55F, 0.35F);
  2539. draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
  2540. SETCOORD(0, 0.6F, 0.2F);
  2541. SETCOORD(1, 0.6F, 0.5F);
  2542. SETCOORD(2, 0.2F, 0.35F);
  2543. draw_polygon(dr, coords, 3, COL_FLAG, COL_FLAG);
  2544. #undef SETCOORD
  2545. } else if (v == -3) {
  2546. /*
  2547. * Draw a question mark.
  2548. */
  2549. draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
  2550. FONT_VARIABLE, TILE_SIZE * 6 / 8,
  2551. ALIGN_VCENTRE | ALIGN_HCENTRE,
  2552. COL_QUERY, "?");
  2553. }
  2554. } else {
  2555. /*
  2556. * Clear the square to the background colour, and draw thin
  2557. * grid lines along the top and left.
  2558. *
  2559. * Exception is that for value 65 (mine we've just trodden
  2560. * on), we clear the square to COL_BANG.
  2561. */
  2562. if (v & 32) {
  2563. bg = COL_WRONGNUMBER;
  2564. v &= ~32;
  2565. }
  2566. draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
  2567. (v == 65 ? COL_BANG :
  2568. bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg));
  2569. draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
  2570. draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
  2571. if (v > 0 && v <= 8) {
  2572. /*
  2573. * Mark a number.
  2574. */
  2575. char str[2];
  2576. str[0] = v + '0';
  2577. str[1] = '\0';
  2578. draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
  2579. FONT_VARIABLE, TILE_SIZE * 7 / 8,
  2580. ALIGN_VCENTRE | ALIGN_HCENTRE,
  2581. (COL_1 - 1) + v, str);
  2582. } else if (v >= 64) {
  2583. /*
  2584. * Mark a mine.
  2585. */
  2586. {
  2587. int cx = x + TILE_SIZE / 2;
  2588. int cy = y + TILE_SIZE / 2;
  2589. int r = TILE_SIZE / 2 - 3;
  2590. draw_circle(dr, cx, cy, 5*r/6, COL_MINE, COL_MINE);
  2591. draw_rect(dr, cx - r/6, cy - r, 2*(r/6)+1, 2*r+1, COL_MINE);
  2592. draw_rect(dr, cx - r, cy - r/6, 2*r+1, 2*(r/6)+1, COL_MINE);
  2593. draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT);
  2594. }
  2595. if (v == 66) {
  2596. /*
  2597. * Cross through the mine.
  2598. */
  2599. int dx;
  2600. for (dx = -1; dx <= +1; dx++) {
  2601. draw_line(dr, x + 3 + dx, y + 2,
  2602. x + TILE_SIZE - 3 + dx,
  2603. y + TILE_SIZE - 2, COL_CROSS);
  2604. draw_line(dr, x + TILE_SIZE - 3 + dx, y + 2,
  2605. x + 3 + dx, y + TILE_SIZE - 2,
  2606. COL_CROSS);
  2607. }
  2608. }
  2609. }
  2610. }
  2611. draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
  2612. }
  2613. static void game_redraw(drawing *dr, game_drawstate *ds,
  2614. const game_state *oldstate, const game_state *state,
  2615. int dir, const game_ui *ui,
  2616. float animtime, float flashtime)
  2617. {
  2618. int x, y;
  2619. int mines, markers, closed, bg;
  2620. int cx = -1, cy = -1;
  2621. bool cmoved;
  2622. if (flashtime) {
  2623. int frame = (int)(flashtime / FLASH_FRAME);
  2624. if (frame % 2)
  2625. bg = (ui->flash_is_death ? COL_BACKGROUND : COL_LOWLIGHT);
  2626. else
  2627. bg = (ui->flash_is_death ? COL_BANG : COL_HIGHLIGHT);
  2628. } else
  2629. bg = COL_BACKGROUND;
  2630. if (!ds->started) {
  2631. int coords[10];
  2632. /*
  2633. * Recessed area containing the whole puzzle.
  2634. */
  2635. coords[0] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1;
  2636. coords[1] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
  2637. coords[2] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1;
  2638. coords[3] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
  2639. coords[4] = coords[2] - TILE_SIZE;
  2640. coords[5] = coords[3] + TILE_SIZE;
  2641. coords[8] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
  2642. coords[9] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
  2643. coords[6] = coords[8] + TILE_SIZE;
  2644. coords[7] = coords[9] - TILE_SIZE;
  2645. draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
  2646. coords[1] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
  2647. coords[0] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
  2648. draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
  2649. ds->started = true;
  2650. }
  2651. if (ui->cur_visible) cx = ui->cur_x;
  2652. if (ui->cur_visible) cy = ui->cur_y;
  2653. cmoved = (cx != ds->cur_x || cy != ds->cur_y);
  2654. /*
  2655. * Now draw the tiles. Also in this loop, count up the number
  2656. * of mines, mine markers, and closed squares.
  2657. */
  2658. mines = markers = closed = 0;
  2659. for (y = 0; y < ds->h; y++)
  2660. for (x = 0; x < ds->w; x++) {
  2661. int v = state->grid[y*ds->w+x];
  2662. bool cc = false;
  2663. if (v < 0)
  2664. closed++;
  2665. if (v == -1)
  2666. markers++;
  2667. if (state->layout->mines && state->layout->mines[y*ds->w+x])
  2668. mines++;
  2669. if (v >= 0 && v <= 8) {
  2670. /*
  2671. * Count up the flags around this tile, and if
  2672. * there are too _many_, highlight the tile.
  2673. */
  2674. int dx, dy, flags = 0;
  2675. for (dy = -1; dy <= +1; dy++)
  2676. for (dx = -1; dx <= +1; dx++) {
  2677. int nx = x+dx, ny = y+dy;
  2678. if (nx >= 0 && nx < ds->w &&
  2679. ny >= 0 && ny < ds->h &&
  2680. state->grid[ny*ds->w+nx] == -1)
  2681. flags++;
  2682. }
  2683. if (flags > v)
  2684. v |= 32;
  2685. }
  2686. if ((v == -2 || v == -3) &&
  2687. (abs(x-ui->hx) <= ui->hradius && abs(y-ui->hy) <= ui->hradius))
  2688. v -= 20;
  2689. if (cmoved && /* if cursor has moved, force redraw of curr and prev pos */
  2690. ((x == cx && y == cy) || (x == ds->cur_x && y == ds->cur_y)))
  2691. cc = true;
  2692. if (ds->grid[y*ds->w+x] != v || bg != ds->bg || cc) {
  2693. draw_tile(dr, ds, COORD(x), COORD(y), v,
  2694. (x == cx && y == cy) ? COL_CURSOR : bg);
  2695. ds->grid[y*ds->w+x] = v;
  2696. }
  2697. }
  2698. ds->bg = bg;
  2699. ds->cur_x = cx; ds->cur_y = cy;
  2700. if (!state->layout->mines)
  2701. mines = state->layout->n;
  2702. /*
  2703. * Update the status bar.
  2704. */
  2705. {
  2706. char statusbar[512];
  2707. if (state->dead) {
  2708. sprintf(statusbar, "DEAD!");
  2709. } else if (state->won) {
  2710. if (state->used_solve)
  2711. sprintf(statusbar, "Auto-solved.");
  2712. else
  2713. sprintf(statusbar, "COMPLETED!");
  2714. } else {
  2715. int safe_closed = closed - mines;
  2716. sprintf(statusbar, "Marked: %d / %d", markers, mines);
  2717. if (safe_closed > 0 && safe_closed <= 9) {
  2718. /*
  2719. * In the situation where there's a very small number
  2720. * of _non_-mine squares left unopened, it's helpful
  2721. * to mention that number in the status line, to save
  2722. * the player from having to count it up
  2723. * painstakingly. This is particularly important if
  2724. * the player has turned up the mine density to the
  2725. * point where game generation resorts to its weird
  2726. * pathological fallback of a very dense mine area
  2727. * with a clearing in the middle, because that often
  2728. * leads to a deduction you can only make by knowing
  2729. * that there is (say) exactly one non-mine square to
  2730. * find, and it's a real pain to have to count up two
  2731. * large numbers of squares and subtract them to get
  2732. * that value of 1.
  2733. *
  2734. * The threshold value of 8 for displaying this
  2735. * information is because that's the largest number of
  2736. * non-mine squares that might conceivably fit around
  2737. * a single central square, and the most likely way to
  2738. * _use_ this information is to observe that if all
  2739. * the remaining safe squares are adjacent to _this_
  2740. * square then everything else can be immediately
  2741. * flagged as a mine.
  2742. */
  2743. if (safe_closed == 1) {
  2744. sprintf(statusbar + strlen(statusbar),
  2745. " (1 safe square remains)");
  2746. } else {
  2747. sprintf(statusbar + strlen(statusbar),
  2748. " (%d safe squares remain)", safe_closed);
  2749. }
  2750. }
  2751. }
  2752. if (ui->deaths)
  2753. sprintf(statusbar + strlen(statusbar),
  2754. " Deaths: %d", ui->deaths);
  2755. status_bar(dr, statusbar);
  2756. }
  2757. }
  2758. static float game_anim_length(const game_state *oldstate,
  2759. const game_state *newstate, int dir, game_ui *ui)
  2760. {
  2761. return 0.0F;
  2762. }
  2763. static float game_flash_length(const game_state *oldstate,
  2764. const game_state *newstate, int dir, game_ui *ui)
  2765. {
  2766. if (oldstate->used_solve || newstate->used_solve)
  2767. return 0.0F;
  2768. if (dir > 0 && !oldstate->dead && !oldstate->won) {
  2769. if (newstate->dead) {
  2770. ui->flash_is_death = true;
  2771. return 3 * FLASH_FRAME;
  2772. }
  2773. if (newstate->won) {
  2774. ui->flash_is_death = false;
  2775. return 2 * FLASH_FRAME;
  2776. }
  2777. }
  2778. return 0.0F;
  2779. }
  2780. static void game_get_cursor_location(const game_ui *ui,
  2781. const game_drawstate *ds,
  2782. const game_state *state,
  2783. const game_params *params,
  2784. int *x, int *y, int *w, int *h)
  2785. {
  2786. if(ui->cur_visible) {
  2787. *x = COORD(ui->cur_x);
  2788. *y = COORD(ui->cur_y);
  2789. *w = *h = TILE_SIZE;
  2790. }
  2791. }
  2792. static int game_status(const game_state *state)
  2793. {
  2794. /*
  2795. * We report the game as lost only if the player has used the
  2796. * Solve function to reveal all the mines. Otherwise, we assume
  2797. * they'll undo and continue play.
  2798. */
  2799. return state->won ? (state->used_solve ? -1 : +1) : 0;
  2800. }
  2801. static bool game_timing_state(const game_state *state, game_ui *ui)
  2802. {
  2803. if (state->dead || state->won || ui->completed || !state->layout->mines)
  2804. return false;
  2805. return true;
  2806. }
  2807. #ifdef COMBINED
  2808. #define thegame mines
  2809. #endif
  2810. const struct game thegame = {
  2811. "Mines", "games.mines", "mines",
  2812. default_params,
  2813. game_fetch_preset, NULL,
  2814. decode_params,
  2815. encode_params,
  2816. free_params,
  2817. dup_params,
  2818. true, game_configure, custom_params,
  2819. validate_params,
  2820. new_game_desc,
  2821. validate_desc,
  2822. new_game,
  2823. dup_game,
  2824. free_game,
  2825. true, solve_game,
  2826. true, game_can_format_as_text_now, game_text_format,
  2827. NULL, NULL, /* get_prefs, set_prefs */
  2828. new_ui,
  2829. free_ui,
  2830. encode_ui,
  2831. decode_ui,
  2832. NULL, /* game_request_keys */
  2833. game_changed_state,
  2834. current_key_label,
  2835. interpret_move,
  2836. execute_move,
  2837. PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
  2838. game_colours,
  2839. game_new_drawstate,
  2840. game_free_drawstate,
  2841. game_redraw,
  2842. game_anim_length,
  2843. game_flash_length,
  2844. game_get_cursor_location,
  2845. game_status,
  2846. false, false, NULL, NULL, /* print_size, print */
  2847. true, /* wants_statusbar */
  2848. true, game_timing_state,
  2849. BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON,
  2850. };
  2851. #ifdef STANDALONE_OBFUSCATOR
  2852. /*
  2853. * Vaguely useful stand-alone program which translates between
  2854. * obfuscated and clear Mines game descriptions. Pass in a game
  2855. * description on the command line, and if it's clear it will be
  2856. * obfuscated and vice versa. The output text should also be a
  2857. * valid game ID describing the same game. Like this:
  2858. *
  2859. * $ ./mineobfusc 9x9:4,4,mb071b49fbd1cb6a0d5868
  2860. * 9x9:4,4,004000007c00010022080
  2861. * $ ./mineobfusc 9x9:4,4,004000007c00010022080
  2862. * 9x9:4,4,mb071b49fbd1cb6a0d5868
  2863. */
  2864. int main(int argc, char **argv)
  2865. {
  2866. game_params *p;
  2867. game_state *s;
  2868. char *id = NULL, *desc;
  2869. const char *err;
  2870. int y, x;
  2871. while (--argc > 0) {
  2872. char *p = *++argv;
  2873. if (*p == '-') {
  2874. fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
  2875. return 1;
  2876. } else {
  2877. id = p;
  2878. }
  2879. }
  2880. if (!id) {
  2881. fprintf(stderr, "usage: %s <game_id>\n", argv[0]);
  2882. return 1;
  2883. }
  2884. desc = strchr(id, ':');
  2885. if (!desc) {
  2886. fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
  2887. return 1;
  2888. }
  2889. *desc++ = '\0';
  2890. p = default_params();
  2891. decode_params(p, id);
  2892. err = validate_desc(p, desc);
  2893. if (err) {
  2894. fprintf(stderr, "%s: %s\n", argv[0], err);
  2895. return 1;
  2896. }
  2897. s = new_game(NULL, p, desc);
  2898. x = atoi(desc);
  2899. while (*desc && *desc != ',') desc++;
  2900. if (*desc) desc++;
  2901. y = atoi(desc);
  2902. while (*desc && *desc != ',') desc++;
  2903. if (*desc) desc++;
  2904. printf("%s:%s\n", id, describe_layout(s->layout->mines,
  2905. p->w * p->h,
  2906. x, y,
  2907. (*desc != 'm')));
  2908. return 0;
  2909. }
  2910. #endif
  2911. /* vim: set shiftwidth=4 tabstop=8: */