inertia.c 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258
  1. /*
  2. * inertia.c: Game involving navigating round a grid picking up
  3. * gems.
  4. *
  5. * Game rules and basic generator design by Ben Olmstead.
  6. * This re-implementation was written by Simon Tatham.
  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 "puzzles.h"
  20. /* Used in the game_state */
  21. #define BLANK 'b'
  22. #define GEM 'g'
  23. #define MINE 'm'
  24. #define STOP 's'
  25. #define WALL 'w'
  26. /* Used in the game IDs */
  27. #define START 'S'
  28. /* Used in the game generation */
  29. #define POSSGEM 'G'
  30. /* Used only in the game_drawstate*/
  31. #define UNDRAWN '?'
  32. #define DIRECTIONS 8
  33. #define DP1 (DIRECTIONS+1)
  34. #define DX(dir) ( (dir) & 3 ? (((dir) & 7) > 4 ? -1 : +1) : 0 )
  35. #define DY(dir) ( DX((dir)+6) )
  36. /*
  37. * Lvalue macro which expects x and y to be in range.
  38. */
  39. #define LV_AT(w, h, grid, x, y) ( (grid)[(y)*(w)+(x)] )
  40. /*
  41. * Rvalue macro which can cope with x and y being out of range.
  42. */
  43. #define AT(w, h, grid, x, y) ( (x)<0 || (x)>=(w) || (y)<0 || (y)>=(h) ? \
  44. WALL : LV_AT(w, h, grid, x, y) )
  45. enum {
  46. COL_BACKGROUND,
  47. COL_OUTLINE,
  48. COL_HIGHLIGHT,
  49. COL_LOWLIGHT,
  50. COL_PLAYER,
  51. COL_DEAD_PLAYER,
  52. COL_MINE,
  53. COL_GEM,
  54. COL_WALL,
  55. COL_HINT,
  56. NCOLOURS
  57. };
  58. struct game_params {
  59. int w, h;
  60. };
  61. typedef struct soln {
  62. int refcount;
  63. int len;
  64. unsigned char *list;
  65. } soln;
  66. struct game_state {
  67. game_params p;
  68. int px, py;
  69. int gems;
  70. char *grid;
  71. int distance_moved;
  72. bool dead;
  73. bool cheated;
  74. int solnpos;
  75. soln *soln;
  76. };
  77. static game_params *default_params(void)
  78. {
  79. game_params *ret = snew(game_params);
  80. ret->w = 10;
  81. #ifdef PORTRAIT_SCREEN
  82. ret->h = 10;
  83. #else
  84. ret->h = 8;
  85. #endif
  86. return ret;
  87. }
  88. static void free_params(game_params *params)
  89. {
  90. sfree(params);
  91. }
  92. static game_params *dup_params(const game_params *params)
  93. {
  94. game_params *ret = snew(game_params);
  95. *ret = *params; /* structure copy */
  96. return ret;
  97. }
  98. static const struct game_params inertia_presets[] = {
  99. #ifdef PORTRAIT_SCREEN
  100. { 10, 10 },
  101. { 12, 12 },
  102. { 16, 16 },
  103. #else
  104. { 10, 8 },
  105. { 15, 12 },
  106. { 20, 16 },
  107. #endif
  108. };
  109. static bool game_fetch_preset(int i, char **name, game_params **params)
  110. {
  111. game_params p, *ret;
  112. char *retname;
  113. char namebuf[80];
  114. if (i < 0 || i >= lenof(inertia_presets))
  115. return false;
  116. p = inertia_presets[i];
  117. ret = dup_params(&p);
  118. sprintf(namebuf, "%dx%d", ret->w, ret->h);
  119. retname = dupstr(namebuf);
  120. *params = ret;
  121. *name = retname;
  122. return true;
  123. }
  124. static void decode_params(game_params *params, char const *string)
  125. {
  126. params->w = params->h = atoi(string);
  127. while (*string && isdigit((unsigned char)*string)) string++;
  128. if (*string == 'x') {
  129. string++;
  130. params->h = atoi(string);
  131. }
  132. }
  133. static char *encode_params(const game_params *params, bool full)
  134. {
  135. char data[256];
  136. sprintf(data, "%dx%d", params->w, params->h);
  137. return dupstr(data);
  138. }
  139. static config_item *game_configure(const game_params *params)
  140. {
  141. config_item *ret;
  142. char buf[80];
  143. ret = snewn(3, config_item);
  144. ret[0].name = "Width";
  145. ret[0].type = C_STRING;
  146. sprintf(buf, "%d", params->w);
  147. ret[0].u.string.sval = dupstr(buf);
  148. ret[1].name = "Height";
  149. ret[1].type = C_STRING;
  150. sprintf(buf, "%d", params->h);
  151. ret[1].u.string.sval = dupstr(buf);
  152. ret[2].name = NULL;
  153. ret[2].type = C_END;
  154. return ret;
  155. }
  156. static game_params *custom_params(const config_item *cfg)
  157. {
  158. game_params *ret = snew(game_params);
  159. ret->w = atoi(cfg[0].u.string.sval);
  160. ret->h = atoi(cfg[1].u.string.sval);
  161. return ret;
  162. }
  163. static const char *validate_params(const game_params *params, bool full)
  164. {
  165. /*
  166. * Avoid completely degenerate cases which only have one
  167. * row/column. We probably could generate completable puzzles
  168. * of that shape, but they'd be forced to be extremely boring
  169. * and at large sizes would take a while to happen upon at
  170. * random as well.
  171. */
  172. if (params->w < 2 || params->h < 2)
  173. return "Width and height must both be at least two";
  174. if (params->w > INT_MAX / params->h)
  175. return "Width times height must not be unreasonably large";
  176. /*
  177. * The grid construction algorithm creates 1/5 as many gems as
  178. * grid squares, and must create at least one gem to have an
  179. * actual puzzle. However, an area-five grid is ruled out by
  180. * the above constraint, so the practical minimum is six.
  181. */
  182. if (params->w * params->h < 6)
  183. return "Grid area must be at least six squares";
  184. return NULL;
  185. }
  186. /* ----------------------------------------------------------------------
  187. * Solver used by grid generator.
  188. */
  189. struct solver_scratch {
  190. bool *reachable_from, *reachable_to;
  191. int *positions;
  192. };
  193. static struct solver_scratch *new_scratch(int w, int h)
  194. {
  195. struct solver_scratch *sc = snew(struct solver_scratch);
  196. sc->reachable_from = snewn(w * h * DIRECTIONS, bool);
  197. sc->reachable_to = snewn(w * h * DIRECTIONS, bool);
  198. sc->positions = snewn(w * h * DIRECTIONS, int);
  199. return sc;
  200. }
  201. static void free_scratch(struct solver_scratch *sc)
  202. {
  203. sfree(sc->reachable_from);
  204. sfree(sc->reachable_to);
  205. sfree(sc->positions);
  206. sfree(sc);
  207. }
  208. static bool can_go(int w, int h, char *grid,
  209. int x1, int y1, int dir1, int x2, int y2, int dir2)
  210. {
  211. /*
  212. * Returns true if we can transition directly from (x1,y1)
  213. * going in direction dir1, to (x2,y2) going in direction dir2.
  214. */
  215. /*
  216. * If we're actually in the middle of an unoccupyable square,
  217. * we cannot make any move.
  218. */
  219. if (AT(w, h, grid, x1, y1) == WALL ||
  220. AT(w, h, grid, x1, y1) == MINE)
  221. return false;
  222. /*
  223. * If a move is capable of stopping at x1,y1,dir1, and x2,y2 is
  224. * the same coordinate as x1,y1, then we can make the
  225. * transition (by stopping and changing direction).
  226. *
  227. * For this to be the case, we have to either have a wall
  228. * beyond x1,y1,dir1, or have a stop on x1,y1.
  229. */
  230. if (x2 == x1 && y2 == y1 &&
  231. (AT(w, h, grid, x1, y1) == STOP ||
  232. AT(w, h, grid, x1, y1) == START ||
  233. AT(w, h, grid, x1+DX(dir1), y1+DY(dir1)) == WALL))
  234. return true;
  235. /*
  236. * If a move is capable of continuing here, then x1,y1,dir1 can
  237. * move one space further on.
  238. */
  239. if (x2 == x1+DX(dir1) && y2 == y1+DY(dir1) && dir1 == dir2 &&
  240. (AT(w, h, grid, x2, y2) == BLANK ||
  241. AT(w, h, grid, x2, y2) == GEM ||
  242. AT(w, h, grid, x2, y2) == STOP ||
  243. AT(w, h, grid, x2, y2) == START))
  244. return true;
  245. /*
  246. * That's it.
  247. */
  248. return false;
  249. }
  250. static int find_gem_candidates(int w, int h, char *grid,
  251. struct solver_scratch *sc)
  252. {
  253. int wh = w*h;
  254. int head, tail;
  255. int sx, sy, gx, gy, gd, pass, possgems;
  256. /*
  257. * This function finds all the candidate gem squares, which are
  258. * precisely those squares which can be picked up on a loop
  259. * from the starting point back to the starting point. Doing
  260. * this may involve passing through such a square in the middle
  261. * of a move; so simple breadth-first search over the _squares_
  262. * of the grid isn't quite adequate, because it might be that
  263. * we can only reach a gem from the start by moving over it in
  264. * one direction, but can only return to the start if we were
  265. * moving over it in another direction.
  266. *
  267. * Instead, we BFS over a space which mentions each grid square
  268. * eight times - once for each direction. We also BFS twice:
  269. * once to find out what square+direction pairs we can reach
  270. * _from_ the start point, and once to find out what pairs we
  271. * can reach the start point from. Then a square is reachable
  272. * if any of the eight directions for that square has both
  273. * flags set.
  274. */
  275. memset(sc->reachable_from, 0, wh * DIRECTIONS * sizeof(bool));
  276. memset(sc->reachable_to, 0, wh * DIRECTIONS * sizeof(bool));
  277. /*
  278. * Find the starting square.
  279. */
  280. sx = -1; /* placate optimiser */
  281. for (sy = 0; sy < h; sy++) {
  282. for (sx = 0; sx < w; sx++)
  283. if (AT(w, h, grid, sx, sy) == START)
  284. break;
  285. if (sx < w)
  286. break;
  287. }
  288. assert(sy < h);
  289. for (pass = 0; pass < 2; pass++) {
  290. bool *reachable = (pass == 0 ? sc->reachable_from : sc->reachable_to);
  291. int sign = (pass == 0 ? +1 : -1);
  292. int dir;
  293. #ifdef SOLVER_DIAGNOSTICS
  294. printf("starting pass %d\n", pass);
  295. #endif
  296. /*
  297. * `head' and `tail' are indices within sc->positions which
  298. * track the list of board positions left to process.
  299. */
  300. head = tail = 0;
  301. for (dir = 0; dir < DIRECTIONS; dir++) {
  302. int index = (sy*w+sx)*DIRECTIONS+dir;
  303. sc->positions[tail++] = index;
  304. reachable[index] = true;
  305. #ifdef SOLVER_DIAGNOSTICS
  306. printf("starting point %d,%d,%d\n", sx, sy, dir);
  307. #endif
  308. }
  309. /*
  310. * Now repeatedly pick an element off the list and process
  311. * it.
  312. */
  313. while (head < tail) {
  314. int index = sc->positions[head++];
  315. int dir = index % DIRECTIONS;
  316. int x = (index / DIRECTIONS) % w;
  317. int y = index / (w * DIRECTIONS);
  318. int n, x2, y2, d2, i2;
  319. #ifdef SOLVER_DIAGNOSTICS
  320. printf("processing point %d,%d,%d\n", x, y, dir);
  321. #endif
  322. /*
  323. * The places we attempt to switch to here are:
  324. * - each possible direction change (all the other
  325. * directions in this square)
  326. * - one step further in the direction we're going (or
  327. * one step back, if we're in the reachable_to pass).
  328. */
  329. for (n = -1; n < DIRECTIONS; n++) {
  330. if (n < 0) {
  331. x2 = x + sign * DX(dir);
  332. y2 = y + sign * DY(dir);
  333. d2 = dir;
  334. } else {
  335. x2 = x;
  336. y2 = y;
  337. d2 = n;
  338. }
  339. i2 = (y2*w+x2)*DIRECTIONS+d2;
  340. if (x2 >= 0 && x2 < w &&
  341. y2 >= 0 && y2 < h &&
  342. !reachable[i2]) {
  343. bool ok;
  344. #ifdef SOLVER_DIAGNOSTICS
  345. printf(" trying point %d,%d,%d", x2, y2, d2);
  346. #endif
  347. if (pass == 0)
  348. ok = can_go(w, h, grid, x, y, dir, x2, y2, d2);
  349. else
  350. ok = can_go(w, h, grid, x2, y2, d2, x, y, dir);
  351. #ifdef SOLVER_DIAGNOSTICS
  352. printf(" - %sok\n", ok ? "" : "not ");
  353. #endif
  354. if (ok) {
  355. sc->positions[tail++] = i2;
  356. reachable[i2] = true;
  357. }
  358. }
  359. }
  360. }
  361. }
  362. /*
  363. * And that should be it. Now all we have to do is find the
  364. * squares for which there exists _some_ direction such that
  365. * the square plus that direction form a tuple which is both
  366. * reachable from the start and reachable to the start.
  367. */
  368. possgems = 0;
  369. for (gy = 0; gy < h; gy++)
  370. for (gx = 0; gx < w; gx++)
  371. if (AT(w, h, grid, gx, gy) == BLANK) {
  372. for (gd = 0; gd < DIRECTIONS; gd++) {
  373. int index = (gy*w+gx)*DIRECTIONS+gd;
  374. if (sc->reachable_from[index] && sc->reachable_to[index]) {
  375. #ifdef SOLVER_DIAGNOSTICS
  376. printf("space at %d,%d is reachable via"
  377. " direction %d\n", gx, gy, gd);
  378. #endif
  379. LV_AT(w, h, grid, gx, gy) = POSSGEM;
  380. possgems++;
  381. break;
  382. }
  383. }
  384. }
  385. return possgems;
  386. }
  387. /* ----------------------------------------------------------------------
  388. * Grid generation code.
  389. */
  390. static char *gengrid(int w, int h, random_state *rs)
  391. {
  392. int wh = w*h;
  393. char *grid = snewn(wh+1, char);
  394. struct solver_scratch *sc = new_scratch(w, h);
  395. int maxdist_threshold, tries;
  396. maxdist_threshold = 2;
  397. tries = 0;
  398. while (1) {
  399. int i, j;
  400. int possgems;
  401. int *dist, *list, head, tail, maxdist;
  402. /*
  403. * We're going to fill the grid with the five basic piece
  404. * types in about 1/5 proportion. For the moment, though,
  405. * we leave out the gems, because we'll put those in
  406. * _after_ we run the solver to tell us where the viable
  407. * locations are.
  408. */
  409. i = 0;
  410. for (j = 0; j < wh/5; j++)
  411. grid[i++] = WALL;
  412. for (j = 0; j < wh/5; j++)
  413. grid[i++] = STOP;
  414. for (j = 0; j < wh/5; j++)
  415. grid[i++] = MINE;
  416. assert(i < wh);
  417. grid[i++] = START;
  418. while (i < wh)
  419. grid[i++] = BLANK;
  420. shuffle(grid, wh, sizeof(*grid), rs);
  421. /*
  422. * Find the viable gem locations, and immediately give up
  423. * and try again if there aren't enough of them.
  424. */
  425. possgems = find_gem_candidates(w, h, grid, sc);
  426. if (possgems < wh/5)
  427. continue;
  428. /*
  429. * We _could_ now select wh/5 of the POSSGEMs and set them
  430. * to GEM, and have a viable level. However, there's a
  431. * chance that a large chunk of the level will turn out to
  432. * be unreachable, so first we test for that.
  433. *
  434. * We do this by finding the largest distance from any
  435. * square to the nearest POSSGEM, by breadth-first search.
  436. * If this is above a critical threshold, we abort and try
  437. * again.
  438. *
  439. * (This search is purely geometric, without regard to
  440. * walls and long ways round.)
  441. */
  442. dist = sc->positions;
  443. list = sc->positions + wh;
  444. for (i = 0; i < wh; i++)
  445. dist[i] = -1;
  446. head = tail = 0;
  447. for (i = 0; i < wh; i++)
  448. if (grid[i] == POSSGEM) {
  449. dist[i] = 0;
  450. list[tail++] = i;
  451. }
  452. maxdist = 0;
  453. while (head < tail) {
  454. int pos, x, y, d;
  455. pos = list[head++];
  456. if (maxdist < dist[pos])
  457. maxdist = dist[pos];
  458. x = pos % w;
  459. y = pos / w;
  460. for (d = 0; d < DIRECTIONS; d++) {
  461. int x2, y2, p2;
  462. x2 = x + DX(d);
  463. y2 = y + DY(d);
  464. if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h) {
  465. p2 = y2*w+x2;
  466. if (dist[p2] < 0) {
  467. dist[p2] = dist[pos] + 1;
  468. list[tail++] = p2;
  469. }
  470. }
  471. }
  472. }
  473. assert(head == wh && tail == wh);
  474. /*
  475. * Now abandon this grid and go round again if maxdist is
  476. * above the required threshold.
  477. *
  478. * We can safely start the threshold as low as 2. As we
  479. * accumulate failed generation attempts, we gradually
  480. * raise it as we get more desperate.
  481. */
  482. if (maxdist > maxdist_threshold) {
  483. tries++;
  484. if (tries == 50) {
  485. maxdist_threshold++;
  486. tries = 0;
  487. }
  488. continue;
  489. }
  490. /*
  491. * Now our reachable squares are plausibly evenly
  492. * distributed over the grid. I'm not actually going to
  493. * _enforce_ that I place the gems in such a way as not to
  494. * increase that maxdist value; I'm now just going to trust
  495. * to the RNG to pick a sensible subset of the POSSGEMs.
  496. */
  497. j = 0;
  498. for (i = 0; i < wh; i++)
  499. if (grid[i] == POSSGEM)
  500. list[j++] = i;
  501. shuffle(list, j, sizeof(*list), rs);
  502. for (i = 0; i < j; i++)
  503. grid[list[i]] = (i < wh/5 ? GEM : BLANK);
  504. break;
  505. }
  506. free_scratch(sc);
  507. grid[wh] = '\0';
  508. return grid;
  509. }
  510. static char *new_game_desc(const game_params *params, random_state *rs,
  511. char **aux, bool interactive)
  512. {
  513. return gengrid(params->w, params->h, rs);
  514. }
  515. static const char *validate_desc(const game_params *params, const char *desc)
  516. {
  517. int w = params->w, h = params->h, wh = w*h;
  518. int starts = 0, gems = 0, i;
  519. for (i = 0; i < wh; i++) {
  520. if (!desc[i])
  521. return "Not enough data to fill grid";
  522. if (desc[i] != WALL && desc[i] != START && desc[i] != STOP &&
  523. desc[i] != GEM && desc[i] != MINE && desc[i] != BLANK)
  524. return "Unrecognised character in game description";
  525. if (desc[i] == START)
  526. starts++;
  527. if (desc[i] == GEM)
  528. gems++;
  529. }
  530. if (desc[i])
  531. return "Too much data to fill grid";
  532. if (starts < 1)
  533. return "No starting square specified";
  534. if (starts > 1)
  535. return "More than one starting square specified";
  536. if (gems < 1)
  537. return "No gems specified";
  538. return NULL;
  539. }
  540. static game_state *new_game(midend *me, const game_params *params,
  541. const char *desc)
  542. {
  543. int w = params->w, h = params->h, wh = w*h;
  544. int i;
  545. game_state *state = snew(game_state);
  546. state->p = *params; /* structure copy */
  547. state->grid = snewn(wh, char);
  548. assert(strlen(desc) == wh);
  549. memcpy(state->grid, desc, wh);
  550. state->px = state->py = -1;
  551. state->gems = 0;
  552. for (i = 0; i < wh; i++) {
  553. if (state->grid[i] == START) {
  554. state->grid[i] = STOP;
  555. state->px = i % w;
  556. state->py = i / w;
  557. } else if (state->grid[i] == GEM) {
  558. state->gems++;
  559. }
  560. }
  561. assert(state->gems > 0);
  562. assert(state->px >= 0 && state->py >= 0);
  563. state->distance_moved = 0;
  564. state->dead = false;
  565. state->cheated = false;
  566. state->solnpos = 0;
  567. state->soln = NULL;
  568. return state;
  569. }
  570. static game_state *dup_game(const game_state *state)
  571. {
  572. int w = state->p.w, h = state->p.h, wh = w*h;
  573. game_state *ret = snew(game_state);
  574. ret->p = state->p;
  575. ret->px = state->px;
  576. ret->py = state->py;
  577. ret->gems = state->gems;
  578. ret->grid = snewn(wh, char);
  579. ret->distance_moved = state->distance_moved;
  580. ret->dead = false;
  581. memcpy(ret->grid, state->grid, wh);
  582. ret->cheated = state->cheated;
  583. ret->soln = state->soln;
  584. if (ret->soln)
  585. ret->soln->refcount++;
  586. ret->solnpos = state->solnpos;
  587. return ret;
  588. }
  589. static void free_game(game_state *state)
  590. {
  591. if (state->soln && --state->soln->refcount == 0) {
  592. sfree(state->soln->list);
  593. sfree(state->soln);
  594. }
  595. sfree(state->grid);
  596. sfree(state);
  597. }
  598. /*
  599. * Internal function used by solver.
  600. */
  601. static int move_goes_to(int w, int h, char *grid, int x, int y, int d)
  602. {
  603. int dr;
  604. /*
  605. * See where we'd get to if we made this move.
  606. */
  607. dr = -1; /* placate optimiser */
  608. while (1) {
  609. if (AT(w, h, grid, x+DX(d), y+DY(d)) == WALL) {
  610. dr = DIRECTIONS; /* hit a wall, so end up stationary */
  611. break;
  612. }
  613. x += DX(d);
  614. y += DY(d);
  615. if (AT(w, h, grid, x, y) == STOP) {
  616. dr = DIRECTIONS; /* hit a stop, so end up stationary */
  617. break;
  618. }
  619. if (AT(w, h, grid, x, y) == GEM) {
  620. dr = d; /* hit a gem, so we're still moving */
  621. break;
  622. }
  623. if (AT(w, h, grid, x, y) == MINE)
  624. return -1; /* hit a mine, so move is invalid */
  625. }
  626. assert(dr >= 0);
  627. return (y*w+x)*DP1+dr;
  628. }
  629. static int compare_integers(const void *av, const void *bv)
  630. {
  631. const int *a = (const int *)av;
  632. const int *b = (const int *)bv;
  633. if (*a < *b)
  634. return -1;
  635. else if (*a > *b)
  636. return +1;
  637. else
  638. return 0;
  639. }
  640. static char *solve_game(const game_state *state, const game_state *currstate,
  641. const char *aux, const char **error)
  642. {
  643. int w = currstate->p.w, h = currstate->p.h, wh = w*h;
  644. int *nodes, *nodeindex, *edges, *backedges, *edgei, *backedgei, *circuit;
  645. int nedges;
  646. int *dist, *dist2, *list;
  647. int *unvisited;
  648. int circuitlen, circuitsize;
  649. int head, tail, pass, i, j, n, x, y, d, dd;
  650. const char *err;
  651. char *soln, *p;
  652. /*
  653. * Before anything else, deal with the special case in which
  654. * all the gems are already collected.
  655. */
  656. for (i = 0; i < wh; i++)
  657. if (currstate->grid[i] == GEM)
  658. break;
  659. if (i == wh) {
  660. *error = "Game is already solved";
  661. return NULL;
  662. }
  663. /*
  664. * Solving Inertia is a question of first building up the graph
  665. * of where you can get to from where, and secondly finding a
  666. * tour of the graph which takes in every gem.
  667. *
  668. * This is of course a close cousin of the travelling salesman
  669. * problem, which is NP-complete; so I rather doubt that any
  670. * _optimal_ tour can be found in plausible time. Hence I'll
  671. * restrict myself to merely finding a not-too-bad one.
  672. *
  673. * First construct the graph, by bfsing out move by move from
  674. * the current player position. Graph vertices will be
  675. * - every endpoint of a move (place the ball can be
  676. * stationary)
  677. * - every gem (place the ball can go through in motion).
  678. * Vertices of this type have an associated direction, since
  679. * if a gem can be collected by sliding through it in two
  680. * different directions it doesn't follow that you can
  681. * change direction at it.
  682. *
  683. * I'm going to refer to a non-directional vertex as
  684. * (y*w+x)*DP1+DIRECTIONS, and a directional one as
  685. * (y*w+x)*DP1+d.
  686. */
  687. /*
  688. * nodeindex[] maps node codes as shown above to numeric
  689. * indices in the nodes[] array.
  690. */
  691. nodeindex = snewn(DP1*wh, int);
  692. for (i = 0; i < DP1*wh; i++)
  693. nodeindex[i] = -1;
  694. /*
  695. * Do the bfs to find all the interesting graph nodes.
  696. */
  697. nodes = snewn(DP1*wh, int);
  698. head = tail = 0;
  699. nodes[tail] = (currstate->py * w + currstate->px) * DP1 + DIRECTIONS;
  700. nodeindex[nodes[0]] = tail;
  701. tail++;
  702. while (head < tail) {
  703. int nc = nodes[head++], nnc;
  704. d = nc % DP1;
  705. /*
  706. * Plot all possible moves from this node. If the node is
  707. * directed, there's only one.
  708. */
  709. for (dd = 0; dd < DIRECTIONS; dd++) {
  710. x = nc / DP1;
  711. y = x / w;
  712. x %= w;
  713. if (d < DIRECTIONS && d != dd)
  714. continue;
  715. nnc = move_goes_to(w, h, currstate->grid, x, y, dd);
  716. if (nnc >= 0 && nnc != nc) {
  717. if (nodeindex[nnc] < 0) {
  718. nodes[tail] = nnc;
  719. nodeindex[nnc] = tail;
  720. tail++;
  721. }
  722. }
  723. }
  724. }
  725. n = head;
  726. /*
  727. * Now we know how many nodes we have, allocate the edge array
  728. * and go through setting up the edges.
  729. */
  730. edges = snewn(DIRECTIONS*n, int);
  731. edgei = snewn(n+1, int);
  732. nedges = 0;
  733. for (i = 0; i < n; i++) {
  734. int nc = nodes[i];
  735. edgei[i] = nedges;
  736. d = nc % DP1;
  737. x = nc / DP1;
  738. y = x / w;
  739. x %= w;
  740. for (dd = 0; dd < DIRECTIONS; dd++) {
  741. int nnc;
  742. if (d >= DIRECTIONS || d == dd) {
  743. nnc = move_goes_to(w, h, currstate->grid, x, y, dd);
  744. if (nnc >= 0 && nnc != nc)
  745. edges[nedges++] = nodeindex[nnc];
  746. }
  747. }
  748. }
  749. edgei[n] = nedges;
  750. /*
  751. * Now set up the backedges array.
  752. */
  753. backedges = snewn(nedges, int);
  754. backedgei = snewn(n+1, int);
  755. for (i = j = 0; i < nedges; i++) {
  756. while (j+1 < n && i >= edgei[j+1])
  757. j++;
  758. backedges[i] = edges[i] * n + j;
  759. }
  760. qsort(backedges, nedges, sizeof(int), compare_integers);
  761. backedgei[0] = 0;
  762. for (i = j = 0; i < nedges; i++) {
  763. int k = backedges[i] / n;
  764. backedges[i] %= n;
  765. while (j < k)
  766. backedgei[++j] = i;
  767. }
  768. backedgei[n] = nedges;
  769. /*
  770. * Set up the initial tour. At all times, our tour is a circuit
  771. * of graph vertices (which may, and probably will often,
  772. * repeat vertices). To begin with, it's got exactly one vertex
  773. * in it, which is the player's current starting point.
  774. */
  775. circuitsize = 256;
  776. circuit = snewn(circuitsize, int);
  777. circuitlen = 0;
  778. circuit[circuitlen++] = 0; /* node index 0 is the starting posn */
  779. /*
  780. * Track which gems are as yet unvisited.
  781. */
  782. unvisited = snewn(wh, int);
  783. for (i = 0; i < wh; i++)
  784. unvisited[i] = false;
  785. for (i = 0; i < wh; i++)
  786. if (currstate->grid[i] == GEM)
  787. unvisited[i] = true;
  788. /*
  789. * Allocate space for doing bfses inside the main loop.
  790. */
  791. dist = snewn(n, int);
  792. dist2 = snewn(n, int);
  793. list = snewn(n, int);
  794. err = NULL;
  795. soln = NULL;
  796. /*
  797. * Now enter the main loop, in each iteration of which we
  798. * extend the tour to take in an as yet uncollected gem.
  799. */
  800. while (1) {
  801. int target, n1, n2, bestdist, extralen, targetpos;
  802. #ifdef TSP_DIAGNOSTICS
  803. printf("circuit is");
  804. for (i = 0; i < circuitlen; i++) {
  805. int nc = nodes[circuit[i]];
  806. printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1);
  807. }
  808. printf("\n");
  809. printf("moves are ");
  810. x = nodes[circuit[0]] / DP1 % w;
  811. y = nodes[circuit[0]] / DP1 / w;
  812. for (i = 1; i < circuitlen; i++) {
  813. int x2, y2, dx, dy;
  814. if (nodes[circuit[i]] % DP1 != DIRECTIONS)
  815. continue;
  816. x2 = nodes[circuit[i]] / DP1 % w;
  817. y2 = nodes[circuit[i]] / DP1 / w;
  818. dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
  819. dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
  820. for (d = 0; d < DIRECTIONS; d++)
  821. if (DX(d) == dx && DY(d) == dy)
  822. printf("%c", "89632147"[d]);
  823. x = x2;
  824. y = y2;
  825. }
  826. printf("\n");
  827. #endif
  828. /*
  829. * First, start a pair of bfses at _every_ vertex currently
  830. * in the tour, and extend them outwards to find the
  831. * nearest as yet unreached gem vertex.
  832. *
  833. * This is largely a heuristic: we could pick _any_ doubly
  834. * reachable node here and still get a valid tour as
  835. * output. I hope that picking a nearby one will result in
  836. * generally good tours.
  837. */
  838. for (pass = 0; pass < 2; pass++) {
  839. int *ep = (pass == 0 ? edges : backedges);
  840. int *ei = (pass == 0 ? edgei : backedgei);
  841. int *dp = (pass == 0 ? dist : dist2);
  842. head = tail = 0;
  843. for (i = 0; i < n; i++)
  844. dp[i] = -1;
  845. for (i = 0; i < circuitlen; i++) {
  846. int ni = circuit[i];
  847. if (dp[ni] < 0) {
  848. dp[ni] = 0;
  849. list[tail++] = ni;
  850. }
  851. }
  852. while (head < tail) {
  853. int ni = list[head++];
  854. for (i = ei[ni]; i < ei[ni+1]; i++) {
  855. int ti = ep[i];
  856. if (ti >= 0 && dp[ti] < 0) {
  857. dp[ti] = dp[ni] + 1;
  858. list[tail++] = ti;
  859. }
  860. }
  861. }
  862. }
  863. /* Now find the nearest unvisited gem. */
  864. bestdist = -1;
  865. target = -1;
  866. for (i = 0; i < n; i++) {
  867. if (unvisited[nodes[i] / DP1] &&
  868. dist[i] >= 0 && dist2[i] >= 0) {
  869. int thisdist = dist[i] + dist2[i];
  870. if (bestdist < 0 || bestdist > thisdist) {
  871. bestdist = thisdist;
  872. target = i;
  873. }
  874. }
  875. }
  876. if (target < 0) {
  877. /*
  878. * If we get to here, we haven't found a gem we can get
  879. * at all, which means we terminate this loop.
  880. */
  881. break;
  882. }
  883. /*
  884. * Now we have a graph vertex at list[tail-1] which is an
  885. * unvisited gem. We want to add that vertex to our tour.
  886. * So we run two more breadth-first searches: one starting
  887. * from that vertex and following forward edges, and
  888. * another starting from the same vertex and following
  889. * backward edges. This allows us to determine, for each
  890. * node on the current tour, how quickly we can get both to
  891. * and from the target vertex from that node.
  892. */
  893. #ifdef TSP_DIAGNOSTICS
  894. printf("target node is %d (%d,%d,%d)\n", target, nodes[target]/DP1%w,
  895. nodes[target]/DP1/w, nodes[target]%DP1);
  896. #endif
  897. for (pass = 0; pass < 2; pass++) {
  898. int *ep = (pass == 0 ? edges : backedges);
  899. int *ei = (pass == 0 ? edgei : backedgei);
  900. int *dp = (pass == 0 ? dist : dist2);
  901. for (i = 0; i < n; i++)
  902. dp[i] = -1;
  903. head = tail = 0;
  904. dp[target] = 0;
  905. list[tail++] = target;
  906. while (head < tail) {
  907. int ni = list[head++];
  908. for (i = ei[ni]; i < ei[ni+1]; i++) {
  909. int ti = ep[i];
  910. if (ti >= 0 && dp[ti] < 0) {
  911. dp[ti] = dp[ni] + 1;
  912. /*printf("pass %d: set dist of vertex %d to %d (via %d)\n", pass, ti, dp[ti], ni);*/
  913. list[tail++] = ti;
  914. }
  915. }
  916. }
  917. }
  918. /*
  919. * Now for every node n, dist[n] gives the length of the
  920. * shortest path from the target vertex to n, and dist2[n]
  921. * gives the length of the shortest path from n to the
  922. * target vertex.
  923. *
  924. * Our next step is to search linearly along the tour to
  925. * find the optimum place to insert a trip to the target
  926. * vertex and back. Our two options are either
  927. * (a) to find two adjacent vertices A,B in the tour and
  928. * replace the edge A->B with the path A->target->B
  929. * (b) to find a single vertex X in the tour and replace
  930. * it with the complete round trip X->target->X.
  931. * We do whichever takes the fewest moves.
  932. */
  933. n1 = n2 = -1;
  934. bestdist = -1;
  935. for (i = 0; i < circuitlen; i++) {
  936. int thisdist;
  937. /*
  938. * Try a round trip from vertex i.
  939. */
  940. if (dist[circuit[i]] >= 0 &&
  941. dist2[circuit[i]] >= 0) {
  942. thisdist = dist[circuit[i]] + dist2[circuit[i]];
  943. if (bestdist < 0 || thisdist < bestdist) {
  944. bestdist = thisdist;
  945. n1 = n2 = i;
  946. }
  947. }
  948. /*
  949. * Try a trip from vertex i via target to vertex i+1.
  950. */
  951. if (i+1 < circuitlen &&
  952. dist2[circuit[i]] >= 0 &&
  953. dist[circuit[i+1]] >= 0) {
  954. thisdist = dist2[circuit[i]] + dist[circuit[i+1]];
  955. if (bestdist < 0 || thisdist < bestdist) {
  956. bestdist = thisdist;
  957. n1 = i;
  958. n2 = i+1;
  959. }
  960. }
  961. }
  962. if (bestdist < 0) {
  963. /*
  964. * We couldn't find a round trip taking in this gem _at
  965. * all_. Give up.
  966. */
  967. err = "Unable to find a solution from this starting point";
  968. break;
  969. }
  970. #ifdef TSP_DIAGNOSTICS
  971. printf("insertion point: n1=%d, n2=%d, dist=%d\n", n1, n2, bestdist);
  972. #endif
  973. #ifdef TSP_DIAGNOSTICS
  974. printf("circuit before lengthening is");
  975. for (i = 0; i < circuitlen; i++) {
  976. printf(" %d", circuit[i]);
  977. }
  978. printf("\n");
  979. #endif
  980. /*
  981. * Now actually lengthen the tour to take in this round
  982. * trip.
  983. */
  984. extralen = dist2[circuit[n1]] + dist[circuit[n2]];
  985. if (n1 != n2)
  986. extralen--;
  987. circuitlen += extralen;
  988. if (circuitlen >= circuitsize) {
  989. circuitsize = circuitlen + 256;
  990. circuit = sresize(circuit, circuitsize, int);
  991. }
  992. memmove(circuit + n2 + extralen, circuit + n2,
  993. (circuitlen - n2 - extralen) * sizeof(int));
  994. n2 += extralen;
  995. #ifdef TSP_DIAGNOSTICS
  996. printf("circuit in middle of lengthening is");
  997. for (i = 0; i < circuitlen; i++) {
  998. printf(" %d", circuit[i]);
  999. }
  1000. printf("\n");
  1001. #endif
  1002. /*
  1003. * Find the shortest-path routes to and from the target,
  1004. * and write them into the circuit.
  1005. */
  1006. targetpos = n1 + dist2[circuit[n1]];
  1007. assert(targetpos - dist2[circuit[n1]] == n1);
  1008. assert(targetpos + dist[circuit[n2]] == n2);
  1009. for (pass = 0; pass < 2; pass++) {
  1010. int dir = (pass == 0 ? -1 : +1);
  1011. int *ep = (pass == 0 ? backedges : edges);
  1012. int *ei = (pass == 0 ? backedgei : edgei);
  1013. int *dp = (pass == 0 ? dist : dist2);
  1014. int nn = (pass == 0 ? n2 : n1);
  1015. int ni = circuit[nn], ti, dest = nn;
  1016. while (1) {
  1017. circuit[dest] = ni;
  1018. if (dp[ni] == 0)
  1019. break;
  1020. dest += dir;
  1021. ti = -1;
  1022. /*printf("pass %d: looking at vertex %d\n", pass, ni);*/
  1023. for (i = ei[ni]; i < ei[ni+1]; i++) {
  1024. ti = ep[i];
  1025. if (ti >= 0 && dp[ti] == dp[ni] - 1)
  1026. break;
  1027. }
  1028. assert(i < ei[ni+1] && ti >= 0);
  1029. ni = ti;
  1030. }
  1031. }
  1032. #ifdef TSP_DIAGNOSTICS
  1033. printf("circuit after lengthening is");
  1034. for (i = 0; i < circuitlen; i++) {
  1035. printf(" %d", circuit[i]);
  1036. }
  1037. printf("\n");
  1038. #endif
  1039. /*
  1040. * Finally, mark all gems that the new piece of circuit
  1041. * passes through as visited.
  1042. */
  1043. for (i = n1; i <= n2; i++) {
  1044. int pos = nodes[circuit[i]] / DP1;
  1045. assert(pos >= 0 && pos < wh);
  1046. unvisited[pos] = false;
  1047. }
  1048. }
  1049. #ifdef TSP_DIAGNOSTICS
  1050. printf("before reduction, moves are ");
  1051. x = nodes[circuit[0]] / DP1 % w;
  1052. y = nodes[circuit[0]] / DP1 / w;
  1053. for (i = 1; i < circuitlen; i++) {
  1054. int x2, y2, dx, dy;
  1055. if (nodes[circuit[i]] % DP1 != DIRECTIONS)
  1056. continue;
  1057. x2 = nodes[circuit[i]] / DP1 % w;
  1058. y2 = nodes[circuit[i]] / DP1 / w;
  1059. dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
  1060. dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
  1061. for (d = 0; d < DIRECTIONS; d++)
  1062. if (DX(d) == dx && DY(d) == dy)
  1063. printf("%c", "89632147"[d]);
  1064. x = x2;
  1065. y = y2;
  1066. }
  1067. printf("\n");
  1068. #endif
  1069. /*
  1070. * That's got a basic solution. Now optimise it by removing
  1071. * redundant sections of the circuit: it's entirely possible
  1072. * that a piece of circuit we carefully inserted at one stage
  1073. * to collect a gem has become pointless because the steps
  1074. * required to collect some _later_ gem necessarily passed
  1075. * through the same one.
  1076. *
  1077. * So first we go through and work out how many times each gem
  1078. * is collected. Then we look for maximal sections of circuit
  1079. * which are redundant in the sense that their removal would
  1080. * not reduce any gem's collection count to zero, and replace
  1081. * each one with a bfs-derived fastest path between their
  1082. * endpoints.
  1083. */
  1084. while (1) {
  1085. int oldlen = circuitlen;
  1086. int dir;
  1087. for (dir = +1; dir >= -1; dir -= 2) {
  1088. for (i = 0; i < wh; i++)
  1089. unvisited[i] = 0;
  1090. for (i = 0; i < circuitlen; i++) {
  1091. int xy = nodes[circuit[i]] / DP1;
  1092. if (currstate->grid[xy] == GEM)
  1093. unvisited[xy]++;
  1094. }
  1095. /*
  1096. * If there's any gem we didn't end up visiting at all,
  1097. * give up.
  1098. */
  1099. for (i = 0; i < wh; i++) {
  1100. if (currstate->grid[i] == GEM && unvisited[i] == 0) {
  1101. err = "Unable to find a solution from this starting point";
  1102. break;
  1103. }
  1104. }
  1105. if (i < wh)
  1106. break;
  1107. for (i = j = (dir > 0 ? 0 : circuitlen-1);
  1108. i < circuitlen && i >= 0;
  1109. i += dir) {
  1110. int xy = nodes[circuit[i]] / DP1;
  1111. if (currstate->grid[xy] == GEM && unvisited[xy] > 1) {
  1112. unvisited[xy]--;
  1113. } else if (currstate->grid[xy] == GEM || i == circuitlen-1) {
  1114. /*
  1115. * circuit[i] collects a gem for the only time,
  1116. * or is the last node in the circuit.
  1117. * Therefore it cannot be removed; so we now
  1118. * want to replace the path from circuit[j] to
  1119. * circuit[i] with a bfs-shortest path.
  1120. */
  1121. int p, q, k, dest, ni, ti, thisdist;
  1122. /*
  1123. * Set up the upper and lower bounds of the
  1124. * reduced section.
  1125. */
  1126. p = min(i, j);
  1127. q = max(i, j);
  1128. #ifdef TSP_DIAGNOSTICS
  1129. printf("optimising section from %d - %d\n", p, q);
  1130. #endif
  1131. for (k = 0; k < n; k++)
  1132. dist[k] = -1;
  1133. head = tail = 0;
  1134. dist[circuit[p]] = 0;
  1135. list[tail++] = circuit[p];
  1136. while (head < tail && dist[circuit[q]] < 0) {
  1137. int ni = list[head++];
  1138. for (k = edgei[ni]; k < edgei[ni+1]; k++) {
  1139. int ti = edges[k];
  1140. if (ti >= 0 && dist[ti] < 0) {
  1141. dist[ti] = dist[ni] + 1;
  1142. list[tail++] = ti;
  1143. }
  1144. }
  1145. }
  1146. thisdist = dist[circuit[q]];
  1147. assert(thisdist >= 0 && thisdist <= q-p);
  1148. memmove(circuit+p+thisdist, circuit+q,
  1149. (circuitlen - q) * sizeof(int));
  1150. circuitlen -= q-p;
  1151. q = p + thisdist;
  1152. circuitlen += q-p;
  1153. if (dir > 0)
  1154. i = q; /* resume loop from the right place */
  1155. #ifdef TSP_DIAGNOSTICS
  1156. printf("new section runs from %d - %d\n", p, q);
  1157. #endif
  1158. dest = q;
  1159. assert(dest >= 0);
  1160. ni = circuit[q];
  1161. while (1) {
  1162. /* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */
  1163. circuit[dest] = ni;
  1164. if (dist[ni] == 0)
  1165. break;
  1166. dest--;
  1167. ti = -1;
  1168. for (k = backedgei[ni]; k < backedgei[ni+1]; k++) {
  1169. ti = backedges[k];
  1170. if (ti >= 0 && dist[ti] == dist[ni] - 1)
  1171. break;
  1172. }
  1173. assert(k < backedgei[ni+1] && ti >= 0);
  1174. ni = ti;
  1175. }
  1176. /*
  1177. * Now re-increment the visit counts for the
  1178. * new path.
  1179. */
  1180. while (++p < q) {
  1181. int xy = nodes[circuit[p]] / DP1;
  1182. if (currstate->grid[xy] == GEM)
  1183. unvisited[xy]++;
  1184. }
  1185. j = i;
  1186. #ifdef TSP_DIAGNOSTICS
  1187. printf("during reduction, circuit is");
  1188. for (k = 0; k < circuitlen; k++) {
  1189. int nc = nodes[circuit[k]];
  1190. printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1);
  1191. }
  1192. printf("\n");
  1193. printf("moves are ");
  1194. x = nodes[circuit[0]] / DP1 % w;
  1195. y = nodes[circuit[0]] / DP1 / w;
  1196. for (k = 1; k < circuitlen; k++) {
  1197. int x2, y2, dx, dy;
  1198. if (nodes[circuit[k]] % DP1 != DIRECTIONS)
  1199. continue;
  1200. x2 = nodes[circuit[k]] / DP1 % w;
  1201. y2 = nodes[circuit[k]] / DP1 / w;
  1202. dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
  1203. dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
  1204. for (d = 0; d < DIRECTIONS; d++)
  1205. if (DX(d) == dx && DY(d) == dy)
  1206. printf("%c", "89632147"[d]);
  1207. x = x2;
  1208. y = y2;
  1209. }
  1210. printf("\n");
  1211. #endif
  1212. }
  1213. }
  1214. #ifdef TSP_DIAGNOSTICS
  1215. printf("after reduction, moves are ");
  1216. x = nodes[circuit[0]] / DP1 % w;
  1217. y = nodes[circuit[0]] / DP1 / w;
  1218. for (i = 1; i < circuitlen; i++) {
  1219. int x2, y2, dx, dy;
  1220. if (nodes[circuit[i]] % DP1 != DIRECTIONS)
  1221. continue;
  1222. x2 = nodes[circuit[i]] / DP1 % w;
  1223. y2 = nodes[circuit[i]] / DP1 / w;
  1224. dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
  1225. dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
  1226. for (d = 0; d < DIRECTIONS; d++)
  1227. if (DX(d) == dx && DY(d) == dy)
  1228. printf("%c", "89632147"[d]);
  1229. x = x2;
  1230. y = y2;
  1231. }
  1232. printf("\n");
  1233. #endif
  1234. }
  1235. /*
  1236. * If we've managed an entire reduction pass in each
  1237. * direction and not made the solution any shorter, we're
  1238. * _really_ done.
  1239. */
  1240. if (circuitlen == oldlen)
  1241. break;
  1242. }
  1243. /*
  1244. * Encode the solution as a move string.
  1245. */
  1246. if (!err) {
  1247. soln = snewn(circuitlen+2, char);
  1248. p = soln;
  1249. *p++ = 'S';
  1250. x = nodes[circuit[0]] / DP1 % w;
  1251. y = nodes[circuit[0]] / DP1 / w;
  1252. for (i = 1; i < circuitlen; i++) {
  1253. int x2, y2, dx, dy;
  1254. if (nodes[circuit[i]] % DP1 != DIRECTIONS)
  1255. continue;
  1256. x2 = nodes[circuit[i]] / DP1 % w;
  1257. y2 = nodes[circuit[i]] / DP1 / w;
  1258. dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
  1259. dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
  1260. for (d = 0; d < DIRECTIONS; d++)
  1261. if (DX(d) == dx && DY(d) == dy) {
  1262. *p++ = '0' + d;
  1263. break;
  1264. }
  1265. assert(d < DIRECTIONS);
  1266. x = x2;
  1267. y = y2;
  1268. }
  1269. *p++ = '\0';
  1270. assert(p - soln < circuitlen+2);
  1271. }
  1272. sfree(list);
  1273. sfree(dist);
  1274. sfree(dist2);
  1275. sfree(unvisited);
  1276. sfree(circuit);
  1277. sfree(backedgei);
  1278. sfree(backedges);
  1279. sfree(edgei);
  1280. sfree(edges);
  1281. sfree(nodeindex);
  1282. sfree(nodes);
  1283. if (err)
  1284. *error = err;
  1285. return soln;
  1286. }
  1287. static bool game_can_format_as_text_now(const game_params *params)
  1288. {
  1289. return true;
  1290. }
  1291. static char *game_text_format(const game_state *state)
  1292. {
  1293. int w = state->p.w, h = state->p.h, r, c;
  1294. int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh;
  1295. char *board = snewn(len + 1, char);
  1296. sprintf(board, "%*s+\n", len - 2, "");
  1297. for (r = 0; r < h; ++r) {
  1298. for (c = 0; c < w; ++c) {
  1299. int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2;
  1300. int i = r*w + c;
  1301. switch (state->grid[i]) {
  1302. case BLANK: break;
  1303. case GEM: board[center] = 'o'; break;
  1304. case MINE: board[center] = 'M'; break;
  1305. case STOP: board[center-1] = '('; board[center+1] = ')'; break;
  1306. case WALL: memset(board + center - 1, 'X', 3);
  1307. }
  1308. if (r == state->py && c == state->px) {
  1309. if (!state->dead) board[center] = '@';
  1310. else memcpy(board + center - 1, ":-(", 3);
  1311. }
  1312. board[cell] = '+';
  1313. memset(board + cell + 1, '-', cw - 1);
  1314. for (i = 1; i < ch; ++i) board[cell + i*gw] = '|';
  1315. }
  1316. for (c = 0; c < ch; ++c) {
  1317. board[(r*ch+c)*gw + gw - 2] = "|+"[!c];
  1318. board[(r*ch+c)*gw + gw - 1] = '\n';
  1319. }
  1320. }
  1321. memset(board + len - gw, '-', gw - 2);
  1322. for (c = 0; c < w; ++c) board[len - gw + cw*c] = '+';
  1323. return board;
  1324. }
  1325. struct game_ui {
  1326. float anim_length;
  1327. int flashtype;
  1328. int deaths;
  1329. bool just_made_move;
  1330. bool just_died;
  1331. };
  1332. static game_ui *new_ui(const game_state *state)
  1333. {
  1334. game_ui *ui = snew(game_ui);
  1335. ui->anim_length = 0.0F;
  1336. ui->flashtype = 0;
  1337. ui->deaths = 0;
  1338. ui->just_made_move = false;
  1339. ui->just_died = false;
  1340. return ui;
  1341. }
  1342. static void free_ui(game_ui *ui)
  1343. {
  1344. sfree(ui);
  1345. }
  1346. static char *encode_ui(const game_ui *ui)
  1347. {
  1348. char buf[80];
  1349. /*
  1350. * The deaths counter needs preserving across a serialisation.
  1351. */
  1352. sprintf(buf, "D%d", ui->deaths);
  1353. return dupstr(buf);
  1354. }
  1355. static void decode_ui(game_ui *ui, const char *encoding,
  1356. const game_state *state)
  1357. {
  1358. int p = 0;
  1359. sscanf(encoding, "D%d%n", &ui->deaths, &p);
  1360. }
  1361. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  1362. const game_state *newstate)
  1363. {
  1364. /*
  1365. * Increment the deaths counter. We only do this if
  1366. * ui->just_made_move is set (redoing a suicide move doesn't
  1367. * kill you _again_), and also we only do it if the game wasn't
  1368. * already completed (once you're finished, you can play).
  1369. */
  1370. if (!oldstate->dead && newstate->dead && ui->just_made_move &&
  1371. oldstate->gems) {
  1372. ui->deaths++;
  1373. ui->just_died = true;
  1374. } else {
  1375. ui->just_died = false;
  1376. }
  1377. ui->just_made_move = false;
  1378. }
  1379. static const char *current_key_label(const game_ui *ui,
  1380. const game_state *state, int button)
  1381. {
  1382. if (IS_CURSOR_SELECT(button) &&
  1383. state->soln && state->solnpos < state->soln->len)
  1384. return "Advance";
  1385. return "";
  1386. }
  1387. struct game_drawstate {
  1388. game_params p;
  1389. int tilesize;
  1390. bool started;
  1391. unsigned short *grid;
  1392. blitter *player_background;
  1393. bool player_bg_saved;
  1394. int pbgx, pbgy;
  1395. };
  1396. #define PREFERRED_TILESIZE 32
  1397. #define TILESIZE (ds->tilesize)
  1398. #ifdef SMALL_SCREEN
  1399. #define BORDER (TILESIZE / 4)
  1400. #else
  1401. #define BORDER (TILESIZE)
  1402. #endif
  1403. #define HIGHLIGHT_WIDTH (TILESIZE / 10)
  1404. #define COORD(x) ( (x) * TILESIZE + BORDER )
  1405. #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
  1406. static char *interpret_move(const game_state *state, game_ui *ui,
  1407. const game_drawstate *ds,
  1408. int x, int y, int button)
  1409. {
  1410. int w = state->p.w, h = state->p.h /*, wh = w*h */;
  1411. int dir;
  1412. char buf[80];
  1413. dir = -1;
  1414. if (button == LEFT_BUTTON) {
  1415. /*
  1416. * Mouse-clicking near the target point (or, more
  1417. * accurately, in the appropriate octant) is an alternative
  1418. * way to input moves.
  1419. */
  1420. if (FROMCOORD(x) != state->px || FROMCOORD(y) != state->py) {
  1421. int dx, dy;
  1422. float angle;
  1423. dx = FROMCOORD(x) - state->px;
  1424. dy = FROMCOORD(y) - state->py;
  1425. /* I pass dx,dy rather than dy,dx so that the octants
  1426. * end up the right way round. */
  1427. angle = atan2(dx, -dy);
  1428. angle = (angle + (float)(PI/8)) / (float)(PI/4);
  1429. assert(angle > -16.0F);
  1430. dir = (int)(angle + 16.0F) & 7;
  1431. }
  1432. } else if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8'))
  1433. dir = 0;
  1434. else if (button == CURSOR_DOWN || button == (MOD_NUM_KEYPAD | '2'))
  1435. dir = 4;
  1436. else if (button == CURSOR_LEFT || button == (MOD_NUM_KEYPAD | '4'))
  1437. dir = 6;
  1438. else if (button == CURSOR_RIGHT || button == (MOD_NUM_KEYPAD | '6'))
  1439. dir = 2;
  1440. else if (button == (MOD_NUM_KEYPAD | '7'))
  1441. dir = 7;
  1442. else if (button == (MOD_NUM_KEYPAD | '1'))
  1443. dir = 5;
  1444. else if (button == (MOD_NUM_KEYPAD | '9'))
  1445. dir = 1;
  1446. else if (button == (MOD_NUM_KEYPAD | '3'))
  1447. dir = 3;
  1448. else if (IS_CURSOR_SELECT(button) &&
  1449. state->soln && state->solnpos < state->soln->len)
  1450. dir = state->soln->list[state->solnpos];
  1451. if (dir < 0)
  1452. return NULL;
  1453. /*
  1454. * Reject the move if we can't make it at all due to a wall
  1455. * being in the way.
  1456. */
  1457. if (AT(w, h, state->grid, state->px+DX(dir), state->py+DY(dir)) == WALL)
  1458. return NULL;
  1459. /*
  1460. * Reject the move if we're dead!
  1461. */
  1462. if (state->dead)
  1463. return NULL;
  1464. /*
  1465. * Otherwise, we can make the move. All we need to specify is
  1466. * the direction.
  1467. */
  1468. ui->just_made_move = true;
  1469. sprintf(buf, "%d", dir);
  1470. return dupstr(buf);
  1471. }
  1472. static void install_new_solution(game_state *ret, const char *move)
  1473. {
  1474. int i;
  1475. soln *sol;
  1476. assert (*move == 'S');
  1477. ++move;
  1478. sol = snew(soln);
  1479. sol->len = strlen(move);
  1480. sol->list = snewn(sol->len, unsigned char);
  1481. for (i = 0; i < sol->len; ++i) sol->list[i] = move[i] - '0';
  1482. if (ret->soln && --ret->soln->refcount == 0) {
  1483. sfree(ret->soln->list);
  1484. sfree(ret->soln);
  1485. }
  1486. ret->soln = sol;
  1487. sol->refcount = 1;
  1488. ret->cheated = true;
  1489. ret->solnpos = 0;
  1490. }
  1491. static void discard_solution(game_state *ret)
  1492. {
  1493. --ret->soln->refcount;
  1494. assert(ret->soln->refcount > 0); /* ret has a soln-pointing dup */
  1495. ret->soln = NULL;
  1496. ret->solnpos = 0;
  1497. }
  1498. static game_state *execute_move(const game_state *state, const char *move)
  1499. {
  1500. int w = state->p.w, h = state->p.h /*, wh = w*h */;
  1501. int dir;
  1502. game_state *ret;
  1503. if (*move == 'S') {
  1504. /*
  1505. * This is a solve move, so we don't actually _change_ the
  1506. * grid but merely set up a stored solution path.
  1507. */
  1508. if (move[1] == '\0') return NULL; /* Solution must be non-empty. */
  1509. ret = dup_game(state);
  1510. install_new_solution(ret, move);
  1511. return ret;
  1512. }
  1513. dir = atoi(move);
  1514. if (dir < 0 || dir >= DIRECTIONS)
  1515. return NULL; /* huh? */
  1516. if (state->dead)
  1517. return NULL;
  1518. if (AT(w, h, state->grid, state->px+DX(dir), state->py+DY(dir)) == WALL)
  1519. return NULL; /* wall in the way! */
  1520. /*
  1521. * Now make the move.
  1522. */
  1523. ret = dup_game(state);
  1524. ret->distance_moved = 0;
  1525. while (1) {
  1526. ret->px += DX(dir);
  1527. ret->py += DY(dir);
  1528. ret->distance_moved++;
  1529. if (AT(w, h, ret->grid, ret->px, ret->py) == GEM) {
  1530. LV_AT(w, h, ret->grid, ret->px, ret->py) = BLANK;
  1531. ret->gems--;
  1532. }
  1533. if (AT(w, h, ret->grid, ret->px, ret->py) == MINE) {
  1534. ret->dead = true;
  1535. break;
  1536. }
  1537. if (AT(w, h, ret->grid, ret->px, ret->py) == STOP ||
  1538. AT(w, h, ret->grid, ret->px+DX(dir),
  1539. ret->py+DY(dir)) == WALL)
  1540. break;
  1541. }
  1542. if (ret->soln) {
  1543. if (ret->dead || ret->gems == 0)
  1544. discard_solution(ret);
  1545. else if (ret->soln->list[ret->solnpos] == dir &&
  1546. ret->solnpos+1 < ret->soln->len)
  1547. ++ret->solnpos;
  1548. else {
  1549. const char *error = NULL;
  1550. char *soln = solve_game(NULL, ret, NULL, &error);
  1551. if (!error) {
  1552. install_new_solution(ret, soln);
  1553. sfree(soln);
  1554. } else discard_solution(ret);
  1555. }
  1556. }
  1557. return ret;
  1558. }
  1559. /* ----------------------------------------------------------------------
  1560. * Drawing routines.
  1561. */
  1562. static void game_compute_size(const game_params *params, int tilesize,
  1563. const game_ui *ui, int *x, int *y)
  1564. {
  1565. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  1566. struct { int tilesize; } ads, *ds = &ads;
  1567. ads.tilesize = tilesize;
  1568. *x = 2 * BORDER + 1 + params->w * TILESIZE;
  1569. *y = 2 * BORDER + 1 + params->h * TILESIZE;
  1570. }
  1571. static void game_set_size(drawing *dr, game_drawstate *ds,
  1572. const game_params *params, int tilesize)
  1573. {
  1574. ds->tilesize = tilesize;
  1575. assert(!ds->player_background); /* set_size is never called twice */
  1576. assert(!ds->player_bg_saved);
  1577. ds->player_background = blitter_new(dr, TILESIZE, TILESIZE);
  1578. }
  1579. static float *game_colours(frontend *fe, int *ncolours)
  1580. {
  1581. float *ret = snewn(3 * NCOLOURS, float);
  1582. int i;
  1583. game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT);
  1584. ret[COL_OUTLINE * 3 + 0] = 0.0F;
  1585. ret[COL_OUTLINE * 3 + 1] = 0.0F;
  1586. ret[COL_OUTLINE * 3 + 2] = 0.0F;
  1587. ret[COL_PLAYER * 3 + 0] = 0.0F;
  1588. ret[COL_PLAYER * 3 + 1] = 1.0F;
  1589. ret[COL_PLAYER * 3 + 2] = 0.0F;
  1590. ret[COL_DEAD_PLAYER * 3 + 0] = 1.0F;
  1591. ret[COL_DEAD_PLAYER * 3 + 1] = 0.0F;
  1592. ret[COL_DEAD_PLAYER * 3 + 2] = 0.0F;
  1593. ret[COL_MINE * 3 + 0] = 0.0F;
  1594. ret[COL_MINE * 3 + 1] = 0.0F;
  1595. ret[COL_MINE * 3 + 2] = 0.0F;
  1596. ret[COL_GEM * 3 + 0] = 0.6F;
  1597. ret[COL_GEM * 3 + 1] = 1.0F;
  1598. ret[COL_GEM * 3 + 2] = 1.0F;
  1599. for (i = 0; i < 3; i++) {
  1600. ret[COL_WALL * 3 + i] = (3 * ret[COL_BACKGROUND * 3 + i] +
  1601. 1 * ret[COL_HIGHLIGHT * 3 + i]) / 4;
  1602. }
  1603. ret[COL_HINT * 3 + 0] = 1.0F;
  1604. ret[COL_HINT * 3 + 1] = 1.0F;
  1605. ret[COL_HINT * 3 + 2] = 0.0F;
  1606. *ncolours = NCOLOURS;
  1607. return ret;
  1608. }
  1609. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  1610. {
  1611. int w = state->p.w, h = state->p.h, wh = w*h;
  1612. struct game_drawstate *ds = snew(struct game_drawstate);
  1613. int i;
  1614. ds->tilesize = 0;
  1615. /* We can't allocate the blitter rectangle for the player background
  1616. * until we know what size to make it. */
  1617. ds->player_background = NULL;
  1618. ds->player_bg_saved = false;
  1619. ds->pbgx = ds->pbgy = -1;
  1620. ds->p = state->p; /* structure copy */
  1621. ds->started = false;
  1622. ds->grid = snewn(wh, unsigned short);
  1623. for (i = 0; i < wh; i++)
  1624. ds->grid[i] = UNDRAWN;
  1625. return ds;
  1626. }
  1627. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  1628. {
  1629. if (ds->player_background)
  1630. blitter_free(dr, ds->player_background);
  1631. sfree(ds->grid);
  1632. sfree(ds);
  1633. }
  1634. static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
  1635. bool dead, int hintdir)
  1636. {
  1637. if (dead) {
  1638. int coords[DIRECTIONS*4];
  1639. int d;
  1640. for (d = 0; d < DIRECTIONS; d++) {
  1641. float x1, y1, x2, y2, x3, y3, len;
  1642. x1 = DX(d);
  1643. y1 = DY(d);
  1644. len = sqrt(x1*x1+y1*y1); x1 /= len; y1 /= len;
  1645. x3 = DX(d+1);
  1646. y3 = DY(d+1);
  1647. len = sqrt(x3*x3+y3*y3); x3 /= len; y3 /= len;
  1648. x2 = (x1+x3) / 4;
  1649. y2 = (y1+y3) / 4;
  1650. coords[d*4+0] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x1);
  1651. coords[d*4+1] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y1);
  1652. coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2);
  1653. coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2);
  1654. }
  1655. draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE);
  1656. } else {
  1657. draw_circle(dr, x + TILESIZE/2, y + TILESIZE/2,
  1658. TILESIZE/3, COL_PLAYER, COL_OUTLINE);
  1659. }
  1660. if (!dead && hintdir >= 0) {
  1661. float scale = (DX(hintdir) && DY(hintdir) ? 0.8F : 1.0F);
  1662. int ax = (TILESIZE*2/5) * scale * DX(hintdir);
  1663. int ay = (TILESIZE*2/5) * scale * DY(hintdir);
  1664. int px = -ay, py = ax;
  1665. int ox = x + TILESIZE/2, oy = y + TILESIZE/2;
  1666. int coords[14], *c;
  1667. c = coords;
  1668. *c++ = ox + px/9;
  1669. *c++ = oy + py/9;
  1670. *c++ = ox + px/9 + ax*2/3;
  1671. *c++ = oy + py/9 + ay*2/3;
  1672. *c++ = ox + px/3 + ax*2/3;
  1673. *c++ = oy + py/3 + ay*2/3;
  1674. *c++ = ox + ax;
  1675. *c++ = oy + ay;
  1676. *c++ = ox - px/3 + ax*2/3;
  1677. *c++ = oy - py/3 + ay*2/3;
  1678. *c++ = ox - px/9 + ax*2/3;
  1679. *c++ = oy - py/9 + ay*2/3;
  1680. *c++ = ox - px/9;
  1681. *c++ = oy - py/9;
  1682. draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE);
  1683. }
  1684. draw_update(dr, x, y, TILESIZE, TILESIZE);
  1685. }
  1686. #define FLASH_DEAD 0x100
  1687. #define FLASH_WIN 0x200
  1688. #define FLASH_MASK 0x300
  1689. static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, int v)
  1690. {
  1691. int tx = COORD(x), ty = COORD(y);
  1692. int bg = (v & FLASH_DEAD ? COL_DEAD_PLAYER :
  1693. v & FLASH_WIN ? COL_HIGHLIGHT : COL_BACKGROUND);
  1694. v &= ~FLASH_MASK;
  1695. clip(dr, tx+1, ty+1, TILESIZE-1, TILESIZE-1);
  1696. draw_rect(dr, tx+1, ty+1, TILESIZE-1, TILESIZE-1, bg);
  1697. if (v == WALL) {
  1698. int coords[6];
  1699. coords[0] = tx + TILESIZE;
  1700. coords[1] = ty + TILESIZE;
  1701. coords[2] = tx + TILESIZE;
  1702. coords[3] = ty + 1;
  1703. coords[4] = tx + 1;
  1704. coords[5] = ty + TILESIZE;
  1705. draw_polygon(dr, coords, 3, COL_LOWLIGHT, COL_LOWLIGHT);
  1706. coords[0] = tx + 1;
  1707. coords[1] = ty + 1;
  1708. draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
  1709. draw_rect(dr, tx + 1 + HIGHLIGHT_WIDTH, ty + 1 + HIGHLIGHT_WIDTH,
  1710. TILESIZE - 2*HIGHLIGHT_WIDTH,
  1711. TILESIZE - 2*HIGHLIGHT_WIDTH, COL_WALL);
  1712. } else if (v == MINE) {
  1713. int cx = tx + TILESIZE / 2;
  1714. int cy = ty + TILESIZE / 2;
  1715. int r = TILESIZE / 2 - 3;
  1716. draw_circle(dr, cx, cy, 5*r/6, COL_MINE, COL_MINE);
  1717. draw_rect(dr, cx - r/6, cy - r, 2*(r/6)+1, 2*r+1, COL_MINE);
  1718. draw_rect(dr, cx - r, cy - r/6, 2*r+1, 2*(r/6)+1, COL_MINE);
  1719. draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT);
  1720. } else if (v == STOP) {
  1721. draw_circle(dr, tx + TILESIZE/2, ty + TILESIZE/2,
  1722. TILESIZE*3/7, -1, COL_OUTLINE);
  1723. draw_rect(dr, tx + TILESIZE*3/7, ty+1,
  1724. TILESIZE - 2*(TILESIZE*3/7) + 1, TILESIZE-1, bg);
  1725. draw_rect(dr, tx+1, ty + TILESIZE*3/7,
  1726. TILESIZE-1, TILESIZE - 2*(TILESIZE*3/7) + 1, bg);
  1727. } else if (v == GEM) {
  1728. int coords[8];
  1729. coords[0] = tx+TILESIZE/2;
  1730. coords[1] = ty+TILESIZE/2-TILESIZE*5/14;
  1731. coords[2] = tx+TILESIZE/2-TILESIZE*5/14;
  1732. coords[3] = ty+TILESIZE/2;
  1733. coords[4] = tx+TILESIZE/2;
  1734. coords[5] = ty+TILESIZE/2+TILESIZE*5/14;
  1735. coords[6] = tx+TILESIZE/2+TILESIZE*5/14;
  1736. coords[7] = ty+TILESIZE/2;
  1737. draw_polygon(dr, coords, 4, COL_GEM, COL_OUTLINE);
  1738. }
  1739. unclip(dr);
  1740. draw_update(dr, tx, ty, TILESIZE, TILESIZE);
  1741. }
  1742. #define BASE_ANIM_LENGTH 0.1F
  1743. #define FLASH_LENGTH 0.3F
  1744. static void game_redraw(drawing *dr, game_drawstate *ds,
  1745. const game_state *oldstate, const game_state *state,
  1746. int dir, const game_ui *ui,
  1747. float animtime, float flashtime)
  1748. {
  1749. int w = state->p.w, h = state->p.h /*, wh = w*h */;
  1750. int x, y;
  1751. float ap;
  1752. int player_dist;
  1753. int flashtype;
  1754. int gems, deaths;
  1755. char status[256];
  1756. if (flashtime &&
  1757. !((int)(flashtime * 3 / FLASH_LENGTH) % 2))
  1758. flashtype = ui->flashtype;
  1759. else
  1760. flashtype = 0;
  1761. /*
  1762. * Erase the player sprite.
  1763. */
  1764. if (ds->player_bg_saved) {
  1765. assert(ds->player_background);
  1766. blitter_load(dr, ds->player_background, ds->pbgx, ds->pbgy);
  1767. draw_update(dr, ds->pbgx, ds->pbgy, TILESIZE, TILESIZE);
  1768. ds->player_bg_saved = false;
  1769. }
  1770. /*
  1771. * Initialise a fresh drawstate.
  1772. */
  1773. if (!ds->started) {
  1774. /*
  1775. * Draw the grid lines.
  1776. */
  1777. for (y = 0; y <= h; y++)
  1778. draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y),
  1779. COL_LOWLIGHT);
  1780. for (x = 0; x <= w; x++)
  1781. draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h),
  1782. COL_LOWLIGHT);
  1783. ds->started = true;
  1784. }
  1785. /*
  1786. * If we're in the process of animating a move, let's start by
  1787. * working out how far the player has moved from their _older_
  1788. * state.
  1789. */
  1790. if (oldstate) {
  1791. ap = animtime / ui->anim_length;
  1792. player_dist = ap * (dir > 0 ? state : oldstate)->distance_moved;
  1793. } else {
  1794. player_dist = 0;
  1795. ap = 0.0F;
  1796. }
  1797. /*
  1798. * Draw the grid contents.
  1799. *
  1800. * We count the gems as we go round this loop, for the purposes
  1801. * of the status bar. Of course we have a gems counter in the
  1802. * game_state already, but if we do the counting in this loop
  1803. * then it tracks gems being picked up in a sliding move, and
  1804. * updates one by one.
  1805. */
  1806. gems = 0;
  1807. for (y = 0; y < h; y++)
  1808. for (x = 0; x < w; x++) {
  1809. unsigned short v = (unsigned char)state->grid[y*w+x];
  1810. /*
  1811. * Special case: if the player is in the process of
  1812. * moving over a gem, we draw the gem iff they haven't
  1813. * gone past it yet.
  1814. */
  1815. if (oldstate && oldstate->grid[y*w+x] != state->grid[y*w+x]) {
  1816. /*
  1817. * Compute the distance from this square to the
  1818. * original player position.
  1819. */
  1820. int dist = max(abs(x - oldstate->px), abs(y - oldstate->py));
  1821. /*
  1822. * If the player has reached here, use the new grid
  1823. * element. Otherwise use the old one.
  1824. */
  1825. if (player_dist < dist)
  1826. v = oldstate->grid[y*w+x];
  1827. else
  1828. v = state->grid[y*w+x];
  1829. }
  1830. /*
  1831. * Special case: erase the mine the dead player is
  1832. * sitting on. Only at the end of the move.
  1833. */
  1834. if (v == MINE && !oldstate && state->dead &&
  1835. x == state->px && y == state->py)
  1836. v = BLANK;
  1837. if (v == GEM)
  1838. gems++;
  1839. v |= flashtype;
  1840. if (ds->grid[y*w+x] != v) {
  1841. draw_tile(dr, ds, x, y, v);
  1842. ds->grid[y*w+x] = v;
  1843. }
  1844. }
  1845. /*
  1846. * Gem counter in the status bar. We replace it with
  1847. * `COMPLETED!' when it reaches zero ... or rather, when the
  1848. * _current state_'s gem counter is zero. (Thus, `Gems: 0' is
  1849. * shown between the collection of the last gem and the
  1850. * completion of the move animation that did it.)
  1851. */
  1852. if (state->dead && (!oldstate || oldstate->dead)) {
  1853. sprintf(status, "DEAD!");
  1854. } else if (state->gems || (oldstate && oldstate->gems)) {
  1855. if (state->cheated)
  1856. sprintf(status, "Auto-solver used. ");
  1857. else
  1858. *status = '\0';
  1859. sprintf(status + strlen(status), "Gems: %d", gems);
  1860. } else if (state->cheated) {
  1861. sprintf(status, "Auto-solved.");
  1862. } else {
  1863. sprintf(status, "COMPLETED!");
  1864. }
  1865. /* We subtract one from the visible death counter if we're still
  1866. * animating the move at the end of which the death took place. */
  1867. deaths = ui->deaths;
  1868. if (oldstate && ui->just_died) {
  1869. assert(deaths > 0);
  1870. deaths--;
  1871. }
  1872. if (deaths)
  1873. sprintf(status + strlen(status), " Deaths: %d", deaths);
  1874. status_bar(dr, status);
  1875. /*
  1876. * Draw the player sprite.
  1877. */
  1878. assert(!ds->player_bg_saved);
  1879. assert(ds->player_background);
  1880. {
  1881. int ox, oy, nx, ny;
  1882. nx = COORD(state->px);
  1883. ny = COORD(state->py);
  1884. if (oldstate) {
  1885. ox = COORD(oldstate->px);
  1886. oy = COORD(oldstate->py);
  1887. } else {
  1888. ox = nx;
  1889. oy = ny;
  1890. }
  1891. ds->pbgx = ox + ap * (nx - ox);
  1892. ds->pbgy = oy + ap * (ny - oy);
  1893. }
  1894. blitter_save(dr, ds->player_background, ds->pbgx, ds->pbgy);
  1895. draw_player(dr, ds, ds->pbgx, ds->pbgy,
  1896. (state->dead && !oldstate),
  1897. (!oldstate && state->soln ?
  1898. state->soln->list[state->solnpos] : -1));
  1899. ds->player_bg_saved = true;
  1900. }
  1901. static float game_anim_length(const game_state *oldstate,
  1902. const game_state *newstate, int dir, game_ui *ui)
  1903. {
  1904. int dist;
  1905. if (dir > 0)
  1906. dist = newstate->distance_moved;
  1907. else
  1908. dist = oldstate->distance_moved;
  1909. ui->anim_length = sqrt(dist) * BASE_ANIM_LENGTH;
  1910. return ui->anim_length;
  1911. }
  1912. static float game_flash_length(const game_state *oldstate,
  1913. const game_state *newstate, int dir, game_ui *ui)
  1914. {
  1915. if (!oldstate->dead && newstate->dead) {
  1916. ui->flashtype = FLASH_DEAD;
  1917. return FLASH_LENGTH;
  1918. } else if (oldstate->gems && !newstate->gems) {
  1919. ui->flashtype = FLASH_WIN;
  1920. return FLASH_LENGTH;
  1921. }
  1922. return 0.0F;
  1923. }
  1924. static void game_get_cursor_location(const game_ui *ui,
  1925. const game_drawstate *ds,
  1926. const game_state *state,
  1927. const game_params *params,
  1928. int *x, int *y, int *w, int *h)
  1929. {
  1930. *x = ds->pbgx;
  1931. *y = ds->pbgy;
  1932. *w = *h = TILESIZE;
  1933. }
  1934. static int game_status(const game_state *state)
  1935. {
  1936. /*
  1937. * We never report the game as lost, on the grounds that if the
  1938. * player has died they're quite likely to want to undo and carry
  1939. * on.
  1940. */
  1941. return state->gems == 0 ? +1 : 0;
  1942. }
  1943. #ifdef COMBINED
  1944. #define thegame inertia
  1945. #endif
  1946. const struct game thegame = {
  1947. "Inertia", "games.inertia", "inertia",
  1948. default_params,
  1949. game_fetch_preset, NULL,
  1950. decode_params,
  1951. encode_params,
  1952. free_params,
  1953. dup_params,
  1954. true, game_configure, custom_params,
  1955. validate_params,
  1956. new_game_desc,
  1957. validate_desc,
  1958. new_game,
  1959. dup_game,
  1960. free_game,
  1961. true, solve_game,
  1962. true, game_can_format_as_text_now, game_text_format,
  1963. NULL, NULL, /* get_prefs, set_prefs */
  1964. new_ui,
  1965. free_ui,
  1966. encode_ui,
  1967. decode_ui,
  1968. NULL, /* game_request_keys */
  1969. game_changed_state,
  1970. current_key_label,
  1971. interpret_move,
  1972. execute_move,
  1973. PREFERRED_TILESIZE, game_compute_size, game_set_size,
  1974. game_colours,
  1975. game_new_drawstate,
  1976. game_free_drawstate,
  1977. game_redraw,
  1978. game_anim_length,
  1979. game_flash_length,
  1980. game_get_cursor_location,
  1981. game_status,
  1982. false, false, NULL, NULL, /* print_size, print */
  1983. true, /* wants_statusbar */
  1984. false, NULL, /* timing_state */
  1985. 0, /* flags */
  1986. };