fifteen.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. /*
  2. * fifteen.c: standard 15-puzzle.
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #include <ctype.h>
  9. #include <limits.h>
  10. #ifdef NO_TGMATH_H
  11. # include <math.h>
  12. #else
  13. # include <tgmath.h>
  14. #endif
  15. #include "puzzles.h"
  16. #define PREFERRED_TILE_SIZE 48
  17. #define TILE_SIZE (ds->tilesize)
  18. #define BORDER (TILE_SIZE / 2)
  19. #define HIGHLIGHT_WIDTH (TILE_SIZE / 20)
  20. #define COORD(x) ( (x) * TILE_SIZE + BORDER )
  21. #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
  22. #define ANIM_TIME 0.13F
  23. #define FLASH_FRAME 0.13F
  24. #define X(state, i) ( (i) % (state)->w )
  25. #define Y(state, i) ( (i) / (state)->w )
  26. #define C(state, x, y) ( (y) * (state)->w + (x) )
  27. #define PARITY_P(params, gap) (((X((params), (gap)) - ((params)->w - 1)) ^ \
  28. (Y((params), (gap)) - ((params)->h - 1)) ^ \
  29. (((params)->w * (params)->h) + 1)) & 1)
  30. #define PARITY_S(state) PARITY_P((state), ((state)->gap_pos))
  31. enum {
  32. COL_BACKGROUND,
  33. COL_TEXT,
  34. COL_HIGHLIGHT,
  35. COL_LOWLIGHT,
  36. NCOLOURS
  37. };
  38. struct game_params {
  39. int w, h;
  40. };
  41. struct game_state {
  42. int w, h, n;
  43. int *tiles;
  44. int gap_pos;
  45. int completed; /* move count at time of completion */
  46. bool used_solve; /* used to suppress completion flash */
  47. int movecount;
  48. };
  49. static game_params *default_params(void)
  50. {
  51. game_params *ret = snew(game_params);
  52. ret->w = ret->h = 4;
  53. return ret;
  54. }
  55. static bool game_fetch_preset(int i, char **name, game_params **params)
  56. {
  57. if (i == 0) {
  58. *params = default_params();
  59. *name = dupstr("4x4");
  60. return true;
  61. }
  62. return false;
  63. }
  64. static void free_params(game_params *params)
  65. {
  66. sfree(params);
  67. }
  68. static game_params *dup_params(const game_params *params)
  69. {
  70. game_params *ret = snew(game_params);
  71. *ret = *params; /* structure copy */
  72. return ret;
  73. }
  74. static void decode_params(game_params *ret, char const *string)
  75. {
  76. ret->w = ret->h = atoi(string);
  77. while (*string && isdigit((unsigned char)*string)) string++;
  78. if (*string == 'x') {
  79. string++;
  80. ret->h = atoi(string);
  81. }
  82. }
  83. static char *encode_params(const game_params *params, bool full)
  84. {
  85. char data[256];
  86. sprintf(data, "%dx%d", params->w, params->h);
  87. return dupstr(data);
  88. }
  89. static config_item *game_configure(const game_params *params)
  90. {
  91. config_item *ret;
  92. char buf[80];
  93. ret = snewn(3, config_item);
  94. ret[0].name = "Width";
  95. ret[0].type = C_STRING;
  96. sprintf(buf, "%d", params->w);
  97. ret[0].u.string.sval = dupstr(buf);
  98. ret[1].name = "Height";
  99. ret[1].type = C_STRING;
  100. sprintf(buf, "%d", params->h);
  101. ret[1].u.string.sval = dupstr(buf);
  102. ret[2].name = NULL;
  103. ret[2].type = C_END;
  104. return ret;
  105. }
  106. static game_params *custom_params(const config_item *cfg)
  107. {
  108. game_params *ret = snew(game_params);
  109. ret->w = atoi(cfg[0].u.string.sval);
  110. ret->h = atoi(cfg[1].u.string.sval);
  111. return ret;
  112. }
  113. static const char *validate_params(const game_params *params, bool full)
  114. {
  115. if (params->w < 2 || params->h < 2)
  116. return "Width and height must both be at least two";
  117. if (params->w > INT_MAX / params->h)
  118. return "Width times height must not be unreasonably large";
  119. return NULL;
  120. }
  121. static int perm_parity(int *perm, int n)
  122. {
  123. int i, j, ret;
  124. ret = 0;
  125. for (i = 0; i < n-1; i++)
  126. for (j = i+1; j < n; j++)
  127. if (perm[i] > perm[j])
  128. ret = !ret;
  129. return ret;
  130. }
  131. static int is_completed(int *tiles, int n) {
  132. int p;
  133. for (p = 0; p < n; p++)
  134. if (tiles[p] != (p < n-1 ? p+1 : 0))
  135. return 0;
  136. return 1;
  137. }
  138. static char *new_game_desc(const game_params *params, random_state *rs,
  139. char **aux, bool interactive)
  140. {
  141. int gap, n, i, x;
  142. int x1, x2, p1, p2, parity;
  143. int *tiles;
  144. bool *used;
  145. char *ret;
  146. int retlen;
  147. n = params->w * params->h;
  148. tiles = snewn(n, int);
  149. used = snewn(n, bool);
  150. do {
  151. for (i = 0; i < n; i++) {
  152. tiles[i] = -1;
  153. used[i] = false;
  154. }
  155. gap = random_upto(rs, n);
  156. tiles[gap] = 0;
  157. used[0] = true;
  158. /*
  159. * Place everything else except the last two tiles.
  160. */
  161. for (x = 0, i = n - 1; i > 2; i--) {
  162. int k = random_upto(rs, i);
  163. int j;
  164. for (j = 0; j < n; j++)
  165. if (!used[j] && (k-- == 0))
  166. break;
  167. assert(j < n && !used[j]);
  168. used[j] = true;
  169. while (tiles[x] >= 0)
  170. x++;
  171. assert(x < n);
  172. tiles[x] = j;
  173. }
  174. /*
  175. * Find the last two locations, and the last two pieces.
  176. */
  177. while (tiles[x] >= 0)
  178. x++;
  179. assert(x < n);
  180. x1 = x;
  181. x++;
  182. while (tiles[x] >= 0)
  183. x++;
  184. assert(x < n);
  185. x2 = x;
  186. for (i = 0; i < n; i++)
  187. if (!used[i])
  188. break;
  189. p1 = i;
  190. for (i = p1 + 1; i < n; i++)
  191. if (!used[i])
  192. break;
  193. p2 = i;
  194. /*
  195. * Determine the required parity of the overall permutation.
  196. * This is the XOR of:
  197. *
  198. * - The chessboard parity ((x^y)&1) of the gap square. The
  199. * bottom right counts as even.
  200. *
  201. * - The parity of n. (The target permutation is 1,...,n-1,0
  202. * rather than 0,...,n-1; this is a cyclic permutation of
  203. * the starting point and hence is odd iff n is even.)
  204. */
  205. parity = PARITY_P(params, gap);
  206. /*
  207. * Try the last two tiles one way round. If that fails, swap
  208. * them.
  209. */
  210. tiles[x1] = p1;
  211. tiles[x2] = p2;
  212. if (perm_parity(tiles, n) != parity) {
  213. tiles[x1] = p2;
  214. tiles[x2] = p1;
  215. assert(perm_parity(tiles, n) == parity);
  216. }
  217. } while (is_completed(tiles, n));
  218. /*
  219. * Now construct the game description, by describing the tile
  220. * array as a simple sequence of comma-separated integers.
  221. */
  222. ret = NULL;
  223. retlen = 0;
  224. for (i = 0; i < n; i++) {
  225. char buf[80];
  226. int k;
  227. k = sprintf(buf, "%d,", tiles[i]);
  228. ret = sresize(ret, retlen + k + 1, char);
  229. strcpy(ret + retlen, buf);
  230. retlen += k;
  231. }
  232. ret[retlen-1] = '\0'; /* delete last comma */
  233. sfree(tiles);
  234. sfree(used);
  235. return ret;
  236. }
  237. static const char *validate_desc(const game_params *params, const char *desc)
  238. {
  239. const char *p;
  240. const char *err;
  241. int i, area;
  242. bool *used;
  243. area = params->w * params->h;
  244. p = desc;
  245. err = NULL;
  246. used = snewn(area, bool);
  247. for (i = 0; i < area; i++)
  248. used[i] = false;
  249. for (i = 0; i < area; i++) {
  250. const char *q = p;
  251. int n;
  252. if (*p < '0' || *p > '9') {
  253. err = "Not enough numbers in string";
  254. goto leave;
  255. }
  256. while (*p >= '0' && *p <= '9')
  257. p++;
  258. if (i < area-1 && *p != ',') {
  259. err = "Expected comma after number";
  260. goto leave;
  261. }
  262. else if (i == area-1 && *p) {
  263. err = "Excess junk at end of string";
  264. goto leave;
  265. }
  266. n = atoi(q);
  267. if (n < 0 || n >= area) {
  268. err = "Number out of range";
  269. goto leave;
  270. }
  271. if (used[n]) {
  272. err = "Number used twice";
  273. goto leave;
  274. }
  275. used[n] = true;
  276. if (*p) p++; /* eat comma */
  277. }
  278. leave:
  279. sfree(used);
  280. return err;
  281. }
  282. static game_state *new_game(midend *me, const game_params *params,
  283. const char *desc)
  284. {
  285. game_state *state = snew(game_state);
  286. int i;
  287. const char *p;
  288. state->w = params->w;
  289. state->h = params->h;
  290. state->n = params->w * params->h;
  291. state->tiles = snewn(state->n, int);
  292. state->gap_pos = 0;
  293. p = desc;
  294. i = 0;
  295. for (i = 0; i < state->n; i++) {
  296. assert(*p);
  297. state->tiles[i] = atoi(p);
  298. if (state->tiles[i] == 0)
  299. state->gap_pos = i;
  300. while (*p && *p != ',')
  301. p++;
  302. if (*p) p++; /* eat comma */
  303. }
  304. assert(!*p);
  305. assert(state->tiles[state->gap_pos] == 0);
  306. state->completed = state->movecount = 0;
  307. state->used_solve = false;
  308. return state;
  309. }
  310. static game_state *dup_game(const game_state *state)
  311. {
  312. game_state *ret = snew(game_state);
  313. ret->w = state->w;
  314. ret->h = state->h;
  315. ret->n = state->n;
  316. ret->tiles = snewn(state->w * state->h, int);
  317. memcpy(ret->tiles, state->tiles, state->w * state->h * sizeof(int));
  318. ret->gap_pos = state->gap_pos;
  319. ret->completed = state->completed;
  320. ret->movecount = state->movecount;
  321. ret->used_solve = state->used_solve;
  322. return ret;
  323. }
  324. static void free_game(game_state *state)
  325. {
  326. sfree(state->tiles);
  327. sfree(state);
  328. }
  329. static char *solve_game(const game_state *state, const game_state *currstate,
  330. const char *aux, const char **error)
  331. {
  332. return dupstr("S");
  333. }
  334. static bool game_can_format_as_text_now(const game_params *params)
  335. {
  336. return true;
  337. }
  338. static char *game_text_format(const game_state *state)
  339. {
  340. char *ret, *p, buf[80];
  341. int x, y, col, maxlen;
  342. /*
  343. * First work out how many characters we need to display each
  344. * number.
  345. */
  346. col = sprintf(buf, "%d", state->n-1);
  347. /*
  348. * Now we know the exact total size of the grid we're going to
  349. * produce: it's got h rows, each containing w lots of col, w-1
  350. * spaces and a trailing newline.
  351. */
  352. maxlen = state->h * state->w * (col+1);
  353. ret = snewn(maxlen+1, char);
  354. p = ret;
  355. for (y = 0; y < state->h; y++) {
  356. for (x = 0; x < state->w; x++) {
  357. int v = state->tiles[state->w*y+x];
  358. if (v == 0)
  359. sprintf(buf, "%*s", col, "");
  360. else
  361. sprintf(buf, "%*d", col, v);
  362. memcpy(p, buf, col);
  363. p += col;
  364. if (x+1 == state->w)
  365. *p++ = '\n';
  366. else
  367. *p++ = ' ';
  368. }
  369. }
  370. assert(p - ret == maxlen);
  371. *p = '\0';
  372. return ret;
  373. }
  374. struct game_ui {
  375. /*
  376. * User-preference option: invert the direction of arrow-key
  377. * control, so that the arrow on the key you press indicates in
  378. * which direction you want the _space_ to move, rather than in
  379. * which direction you want a tile to move to fill the space.
  380. */
  381. bool invert_cursor;
  382. };
  383. static void legacy_prefs_override(struct game_ui *ui_out)
  384. {
  385. static bool initialised = false;
  386. static int invert_cursor = -1;
  387. if (!initialised) {
  388. initialised = true;
  389. invert_cursor = getenv_bool("FIFTEEN_INVERT_CURSOR", -1);
  390. }
  391. if (invert_cursor != -1)
  392. ui_out->invert_cursor = invert_cursor;
  393. }
  394. static game_ui *new_ui(const game_state *state)
  395. {
  396. struct game_ui *ui = snew(struct game_ui);
  397. ui->invert_cursor = false;
  398. legacy_prefs_override(ui);
  399. return ui;
  400. }
  401. static config_item *get_prefs(game_ui *ui)
  402. {
  403. config_item *ret;
  404. ret = snewn(2, config_item);
  405. ret[0].name = "Sense of arrow keys";
  406. ret[0].kw = "arrow-semantics";
  407. ret[0].type = C_CHOICES;
  408. ret[0].u.choices.choicenames = ":Move the tile:Move the gap";
  409. ret[0].u.choices.choicekws = ":tile:gap";
  410. ret[0].u.choices.selected = ui->invert_cursor;
  411. ret[1].name = NULL;
  412. ret[1].type = C_END;
  413. return ret;
  414. }
  415. static void set_prefs(game_ui *ui, const config_item *cfg)
  416. {
  417. ui->invert_cursor = cfg[0].u.choices.selected;
  418. }
  419. static void free_ui(game_ui *ui)
  420. {
  421. sfree(ui);
  422. }
  423. static void game_changed_state(game_ui *ui, const game_state *oldstate,
  424. const game_state *newstate)
  425. {
  426. }
  427. struct game_drawstate {
  428. bool started;
  429. int w, h, bgcolour;
  430. int *tiles;
  431. int tilesize;
  432. };
  433. static int flip_cursor(int button)
  434. {
  435. switch (button) {
  436. case CURSOR_UP: return CURSOR_DOWN;
  437. case CURSOR_DOWN: return CURSOR_UP;
  438. case CURSOR_LEFT: return CURSOR_RIGHT;
  439. case CURSOR_RIGHT: return CURSOR_LEFT;
  440. }
  441. return 0;
  442. }
  443. static void next_move_3x2(int ax, int ay, int bx, int by,
  444. int gx, int gy, int *dx, int *dy)
  445. {
  446. /* When w = 3 and h = 2 and the tile going in the top left corner
  447. * is at (ax, ay) and the tile going in the bottom left corner is
  448. * at (bx, by) and the blank tile is at (gx, gy), how do you move? */
  449. /* Hard-coded shortest solutions. Sorry. */
  450. static const unsigned char move[120] = {
  451. 1,2,0,1,2,2,
  452. 2,0,0,2,0,0,
  453. 0,0,2,0,2,0,
  454. 0,0,0,2,0,2,
  455. 2,0,0,0,2,0,
  456. 0,3,0,1,1,1,
  457. 3,0,3,2,1,2,
  458. 2,1,1,0,1,0,
  459. 2,1,2,1,0,1,
  460. 1,2,0,2,1,2,
  461. 0,1,3,1,3,0,
  462. 1,3,1,3,0,3,
  463. 0,0,3,3,0,0,
  464. 0,0,0,1,2,1,
  465. 3,0,0,1,1,1,
  466. 3,1,1,1,3,0,
  467. 1,1,1,1,1,1,
  468. 1,3,1,1,3,0,
  469. 1,1,3,3,1,3,
  470. 1,3,0,0,0,0
  471. };
  472. static const struct { int dx, dy; } d[4] = {{+1,0},{-1,0},{0,+1},{0,-1}};
  473. int ea = 3*ay + ax, eb = 3*by + bx, eg = 3*gy + gx, v;
  474. if (eb > ea) --eb;
  475. if (eg > ea) --eg;
  476. if (eg > eb) --eg;
  477. v = move[ea + eb*6 + eg*5*6];
  478. *dx = d[v].dx;
  479. *dy = d[v].dy;
  480. }
  481. static void next_move(int nx, int ny, int ox, int oy, int gx, int gy,
  482. int tx, int ty, int w, int *dx, int *dy)
  483. {
  484. const int to_tile_x = (gx < nx ? +1 : -1);
  485. const int to_goal_x = (gx < tx ? +1 : -1);
  486. const bool gap_x_on_goal_side = ((nx-tx) * (nx-gx) > 0);
  487. assert (nx != tx || ny != ty); /* not already in place */
  488. assert (nx != gx || ny != gy); /* not placing the gap */
  489. assert (ty <= ny); /* because we're greedy (and flipping) */
  490. assert (ty <= gy); /* because we're greedy (and flipping) */
  491. /* TODO: define a termination function. Idea: 0 if solved, or
  492. * the number of moves to solve the next piece plus the number of
  493. * further unsolved pieces times an upper bound on the number of
  494. * moves required to solve any piece. If such a function can be
  495. * found, we have (termination && (termination => correctness)).
  496. * The catch is our temporary disturbance of 2x3 corners. */
  497. /* handles end-of-row, when 3 and 4 are in the top right 2x3 box */
  498. if (tx == w - 2 &&
  499. ny <= ty + 2 && (nx == tx || nx == tx + 1) &&
  500. oy <= ty + 2 && (ox == tx || ox == tx + 1) &&
  501. gy <= ty + 2 && (gx == tx || gx == tx + 1))
  502. {
  503. next_move_3x2(oy - ty, tx + 1 - ox,
  504. ny - ty, tx + 1 - nx,
  505. gy - ty, tx + 1 - gx, dy, dx);
  506. *dx *= -1;
  507. return;
  508. }
  509. if (tx == w - 1) {
  510. if (ny <= ty + 2 && (nx == tx || nx == tx - 1) &&
  511. gy <= ty + 2 && (gx == tx || gx == tx - 1)) {
  512. next_move_3x2(ny - ty, tx - nx, 0, 1, gy - ty, tx - gx, dy, dx);
  513. *dx *= -1;
  514. } else if (gy == ty)
  515. *dy = +1;
  516. else if (nx != tx || ny != ty + 1) {
  517. next_move((w - 1) - nx, ny, -1, -1, (w - 1) - gx, gy,
  518. 0, ty + 1, -1, dx, dy);
  519. *dx *= -1;
  520. } else if (gx == nx)
  521. *dy = -1;
  522. else
  523. *dx = +1;
  524. return;
  525. }
  526. /* note that *dy = -1 is unsafe when gy = ty + 1 and gx < tx */
  527. if (gy < ny)
  528. if (nx == gx || (gy == ty && gx == tx))
  529. *dy = +1;
  530. else if (!gap_x_on_goal_side)
  531. *dx = to_tile_x;
  532. else if (ny - ty > abs(nx - tx))
  533. *dx = to_tile_x;
  534. else *dy = +1;
  535. else if (gy == ny)
  536. if (nx == tx) /* then we know ny > ty */
  537. if (gx > nx || ny > ty + 1)
  538. *dy = -1; /* ... so this is safe */
  539. else
  540. *dy = +1;
  541. else if (gap_x_on_goal_side)
  542. *dx = to_tile_x;
  543. else if (gy == ty || (gy == ty + 1 && gx < tx))
  544. *dy = +1;
  545. else
  546. *dy = -1;
  547. else if (nx == tx) /* gy > ny */
  548. if (gx > nx)
  549. *dy = -1;
  550. else
  551. *dx = +1;
  552. else if (gx == nx)
  553. *dx = to_goal_x;
  554. else if (gap_x_on_goal_side)
  555. if (gy == ty + 1 && gx < tx)
  556. *dx = to_tile_x;
  557. else
  558. *dy = -1;
  559. else if (ny - ty > abs(nx - tx))
  560. *dy = -1;
  561. else
  562. *dx = to_tile_x;
  563. }
  564. static bool compute_hint(const game_state *state, int *out_x, int *out_y)
  565. {
  566. /* The overall solving process is this:
  567. * 1. Find the next piece to be put in its place
  568. * 2. Move it diagonally towards its place
  569. * 3. Move it horizontally or vertically towards its place
  570. * (Modulo the last two tiles at the end of each row/column)
  571. */
  572. int gx = X(state, state->gap_pos);
  573. int gy = Y(state, state->gap_pos);
  574. int tx, ty, nx, ny, ox, oy, /* {target,next,next2}_{x,y} */ i;
  575. int dx = 0, dy = 0;
  576. /* 1. Find the next piece
  577. * if (there are no more unfinished columns than rows) {
  578. * fill the top-most row, left to right
  579. * } else { fill the left-most column, top to bottom }
  580. */
  581. const int w = state->w, h = state->h, n = w*h;
  582. int next_piece = 0, next_piece_2 = 0, solr = 0, solc = 0;
  583. int unsolved_rows = h, unsolved_cols = w;
  584. assert(out_x);
  585. assert(out_y);
  586. while (solr < h && solc < w) {
  587. int start, step, stop;
  588. if (unsolved_cols <= unsolved_rows)
  589. start = solr*w + solc, step = 1, stop = unsolved_cols;
  590. else
  591. start = solr*w + solc, step = w, stop = unsolved_rows;
  592. for (i = 0; i < stop; ++i) {
  593. const int j = start + i*step;
  594. if (state->tiles[j] != j + 1) {
  595. next_piece = j + 1;
  596. next_piece_2 = next_piece + step;
  597. break;
  598. }
  599. }
  600. if (i < stop) break;
  601. (unsolved_cols <= unsolved_rows)
  602. ? (++solr, --unsolved_rows)
  603. : (++solc, --unsolved_cols);
  604. }
  605. if (next_piece == n)
  606. return false;
  607. /* 2, 3. Move the next piece towards its place */
  608. /* gx, gy already set */
  609. tx = X(state, next_piece - 1); /* where we're going */
  610. ty = Y(state, next_piece - 1);
  611. for (i = 0; i < n && state->tiles[i] != next_piece; ++i);
  612. nx = X(state, i); /* where we're at */
  613. ny = Y(state, i);
  614. for (i = 0; i < n && state->tiles[i] != next_piece_2; ++i);
  615. ox = X(state, i);
  616. oy = Y(state, i);
  617. if (unsolved_cols <= unsolved_rows)
  618. next_move(nx, ny, ox, oy, gx, gy, tx, ty, w, &dx, &dy);
  619. else
  620. next_move(ny, nx, oy, ox, gy, gx, ty, tx, h, &dy, &dx);
  621. assert (dx || dy);
  622. *out_x = gx + dx;
  623. *out_y = gy + dy;
  624. return true;
  625. }
  626. static char *interpret_move(const game_state *state, game_ui *ui,
  627. const game_drawstate *ds,
  628. int x, int y, int button)
  629. {
  630. int cx = X(state, state->gap_pos), nx = cx;
  631. int cy = Y(state, state->gap_pos), ny = cy;
  632. char buf[80];
  633. button &= ~MOD_MASK;
  634. if (button == LEFT_BUTTON) {
  635. nx = FROMCOORD(x);
  636. ny = FROMCOORD(y);
  637. if (nx < 0 || nx >= state->w || ny < 0 || ny >= state->h)
  638. return MOVE_UNUSED; /* out of bounds */
  639. } else if (IS_CURSOR_MOVE(button)) {
  640. button = flip_cursor(button); /* the default */
  641. if (ui->invert_cursor)
  642. button = flip_cursor(button); /* undoes the first flip */
  643. move_cursor(button, &nx, &ny, state->w, state->h, false);
  644. } else if ((button == 'h' || button == 'H') && !state->completed) {
  645. if (!compute_hint(state, &nx, &ny))
  646. return MOVE_NO_EFFECT;/* shouldn't happen, since ^^we^^checked^^ */
  647. } else
  648. return MOVE_UNUSED; /* no move */
  649. /*
  650. * Any click location should be equal to the gap location
  651. * in _precisely_ one coordinate.
  652. */
  653. if ((cx == nx) ^ (cy == ny)) {
  654. sprintf(buf, "M%d,%d", nx, ny);
  655. return dupstr(buf);
  656. }
  657. return MOVE_NO_EFFECT;
  658. }
  659. static game_state *execute_move(const game_state *from, const char *move)
  660. {
  661. int gx, gy, dx, dy, ux, uy, up, p;
  662. game_state *ret;
  663. if (!strcmp(move, "S")) {
  664. int i;
  665. ret = dup_game(from);
  666. /*
  667. * Simply replace the grid with a solved one. For this game,
  668. * this isn't a useful operation for actually telling the user
  669. * what they should have done, but it is useful for
  670. * conveniently being able to get hold of a clean state from
  671. * which to practise manoeuvres.
  672. */
  673. for (i = 0; i < ret->n; i++)
  674. ret->tiles[i] = (i+1) % ret->n;
  675. ret->gap_pos = ret->n-1;
  676. ret->used_solve = true;
  677. ret->completed = ret->movecount = 1;
  678. return ret;
  679. }
  680. gx = X(from, from->gap_pos);
  681. gy = Y(from, from->gap_pos);
  682. if (move[0] != 'M' ||
  683. sscanf(move+1, "%d,%d", &dx, &dy) != 2 ||
  684. (dx == gx && dy == gy) || (dx != gx && dy != gy) ||
  685. dx < 0 || dx >= from->w || dy < 0 || dy >= from->h)
  686. return NULL;
  687. /*
  688. * Find the unit displacement from the original gap
  689. * position towards this one.
  690. */
  691. ux = (dx < gx ? -1 : dx > gx ? +1 : 0);
  692. uy = (dy < gy ? -1 : dy > gy ? +1 : 0);
  693. up = C(from, ux, uy);
  694. ret = dup_game(from);
  695. ret->gap_pos = C(from, dx, dy);
  696. assert(ret->gap_pos >= 0 && ret->gap_pos < ret->n);
  697. ret->tiles[ret->gap_pos] = 0;
  698. for (p = from->gap_pos; p != ret->gap_pos; p += up) {
  699. assert(p >= 0 && p < from->n);
  700. ret->tiles[p] = from->tiles[p + up];
  701. ret->movecount++;
  702. }
  703. /*
  704. * See if the game has been completed.
  705. */
  706. if (!ret->completed && is_completed(ret->tiles, ret->n)) {
  707. ret->completed = ret->movecount;
  708. }
  709. return ret;
  710. }
  711. /* ----------------------------------------------------------------------
  712. * Drawing routines.
  713. */
  714. static void game_compute_size(const game_params *params, int tilesize,
  715. const game_ui *ui, int *x, int *y)
  716. {
  717. /* Ick: fake up `ds->tilesize' for macro expansion purposes */
  718. struct { int tilesize; } ads, *ds = &ads;
  719. ads.tilesize = tilesize;
  720. *x = TILE_SIZE * params->w + 2 * BORDER;
  721. *y = TILE_SIZE * params->h + 2 * BORDER;
  722. }
  723. static void game_set_size(drawing *dr, game_drawstate *ds,
  724. const game_params *params, int tilesize)
  725. {
  726. ds->tilesize = tilesize;
  727. }
  728. static float *game_colours(frontend *fe, int *ncolours)
  729. {
  730. float *ret = snewn(3 * NCOLOURS, float);
  731. int i;
  732. game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT);
  733. for (i = 0; i < 3; i++)
  734. ret[COL_TEXT * 3 + i] = 0.0;
  735. *ncolours = NCOLOURS;
  736. return ret;
  737. }
  738. static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
  739. {
  740. struct game_drawstate *ds = snew(struct game_drawstate);
  741. int i;
  742. ds->started = false;
  743. ds->w = state->w;
  744. ds->h = state->h;
  745. ds->bgcolour = COL_BACKGROUND;
  746. ds->tiles = snewn(ds->w*ds->h, int);
  747. ds->tilesize = 0; /* haven't decided yet */
  748. for (i = 0; i < ds->w*ds->h; i++)
  749. ds->tiles[i] = -1;
  750. return ds;
  751. }
  752. static void game_free_drawstate(drawing *dr, game_drawstate *ds)
  753. {
  754. sfree(ds->tiles);
  755. sfree(ds);
  756. }
  757. static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state,
  758. int x, int y, int tile, int flash_colour)
  759. {
  760. if (tile == 0) {
  761. draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
  762. flash_colour);
  763. } else {
  764. int coords[6];
  765. char str[40];
  766. coords[0] = x + TILE_SIZE - 1;
  767. coords[1] = y + TILE_SIZE - 1;
  768. coords[2] = x + TILE_SIZE - 1;
  769. coords[3] = y;
  770. coords[4] = x;
  771. coords[5] = y + TILE_SIZE - 1;
  772. draw_polygon(dr, coords, 3, COL_LOWLIGHT, COL_LOWLIGHT);
  773. coords[0] = x;
  774. coords[1] = y;
  775. draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
  776. draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH,
  777. TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH,
  778. flash_colour);
  779. sprintf(str, "%d", tile);
  780. draw_text(dr, x + TILE_SIZE/2, y + TILE_SIZE/2,
  781. FONT_VARIABLE, TILE_SIZE/3, ALIGN_VCENTRE | ALIGN_HCENTRE,
  782. COL_TEXT, str);
  783. }
  784. draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
  785. }
  786. static void game_redraw(drawing *dr, game_drawstate *ds,
  787. const game_state *oldstate, const game_state *state,
  788. int dir, const game_ui *ui,
  789. float animtime, float flashtime)
  790. {
  791. int i, pass, bgcolour;
  792. if (flashtime > 0) {
  793. int frame = (int)(flashtime / FLASH_FRAME);
  794. bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT);
  795. } else
  796. bgcolour = COL_BACKGROUND;
  797. if (!ds->started) {
  798. int coords[10];
  799. /*
  800. * Recessed area containing the whole puzzle.
  801. */
  802. coords[0] = COORD(state->w) + HIGHLIGHT_WIDTH - 1;
  803. coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1;
  804. coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1;
  805. coords[3] = COORD(0) - HIGHLIGHT_WIDTH;
  806. coords[4] = coords[2] - TILE_SIZE;
  807. coords[5] = coords[3] + TILE_SIZE;
  808. coords[8] = COORD(0) - HIGHLIGHT_WIDTH;
  809. coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1;
  810. coords[6] = coords[8] + TILE_SIZE;
  811. coords[7] = coords[9] - TILE_SIZE;
  812. draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
  813. coords[1] = COORD(0) - HIGHLIGHT_WIDTH;
  814. coords[0] = COORD(0) - HIGHLIGHT_WIDTH;
  815. draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
  816. ds->started = true;
  817. }
  818. /*
  819. * Now draw each tile. We do this in two passes to make
  820. * animation easy.
  821. */
  822. for (pass = 0; pass < 2; pass++) {
  823. for (i = 0; i < state->n; i++) {
  824. int t, t0;
  825. /*
  826. * Figure out what should be displayed at this
  827. * location. It's either a simple tile, or it's a
  828. * transition between two tiles (in which case we say
  829. * -1 because it must always be drawn).
  830. */
  831. if (oldstate && oldstate->tiles[i] != state->tiles[i])
  832. t = -1;
  833. else
  834. t = state->tiles[i];
  835. t0 = t;
  836. if (ds->bgcolour != bgcolour || /* always redraw when flashing */
  837. ds->tiles[i] != t || ds->tiles[i] == -1 || t == -1) {
  838. int x, y;
  839. /*
  840. * Figure out what to _actually_ draw, and where to
  841. * draw it.
  842. */
  843. if (t == -1) {
  844. int x0, y0, x1, y1;
  845. int j;
  846. /*
  847. * On the first pass, just blank the tile.
  848. */
  849. if (pass == 0) {
  850. x = COORD(X(state, i));
  851. y = COORD(Y(state, i));
  852. t = 0;
  853. } else {
  854. float c;
  855. t = state->tiles[i];
  856. /*
  857. * Don't bother moving the gap; just don't
  858. * draw it.
  859. */
  860. if (t == 0)
  861. continue;
  862. /*
  863. * Find the coordinates of this tile in the old and
  864. * new states.
  865. */
  866. x1 = COORD(X(state, i));
  867. y1 = COORD(Y(state, i));
  868. for (j = 0; j < oldstate->n; j++)
  869. if (oldstate->tiles[j] == state->tiles[i])
  870. break;
  871. assert(j < oldstate->n);
  872. x0 = COORD(X(state, j));
  873. y0 = COORD(Y(state, j));
  874. c = (animtime / ANIM_TIME);
  875. if (c < 0.0F) c = 0.0F;
  876. if (c > 1.0F) c = 1.0F;
  877. x = x0 + (int)(c * (x1 - x0));
  878. y = y0 + (int)(c * (y1 - y0));
  879. }
  880. } else {
  881. if (pass == 0)
  882. continue;
  883. x = COORD(X(state, i));
  884. y = COORD(Y(state, i));
  885. }
  886. draw_tile(dr, ds, state, x, y, t, bgcolour);
  887. }
  888. ds->tiles[i] = t0;
  889. }
  890. }
  891. ds->bgcolour = bgcolour;
  892. /*
  893. * Update the status bar.
  894. */
  895. {
  896. char statusbuf[256];
  897. /*
  898. * Don't show the new status until we're also showing the
  899. * new _state_ - after the game animation is complete.
  900. */
  901. if (oldstate)
  902. state = oldstate;
  903. if (state->used_solve)
  904. sprintf(statusbuf, "Moves since auto-solve: %d",
  905. state->movecount - state->completed);
  906. else
  907. sprintf(statusbuf, "%sMoves: %d",
  908. (state->completed ? "COMPLETED! " : ""),
  909. (state->completed ? state->completed : state->movecount));
  910. status_bar(dr, statusbuf);
  911. }
  912. }
  913. static float game_anim_length(const game_state *oldstate,
  914. const game_state *newstate, int dir, game_ui *ui)
  915. {
  916. return ANIM_TIME;
  917. }
  918. static float game_flash_length(const game_state *oldstate,
  919. const game_state *newstate, int dir, game_ui *ui)
  920. {
  921. if (!oldstate->completed && newstate->completed &&
  922. !oldstate->used_solve && !newstate->used_solve)
  923. return 2 * FLASH_FRAME;
  924. else
  925. return 0.0F;
  926. }
  927. static void game_get_cursor_location(const game_ui *ui,
  928. const game_drawstate *ds,
  929. const game_state *state,
  930. const game_params *params,
  931. int *x, int *y, int *w, int *h)
  932. {
  933. *x = COORD(X(state, state->gap_pos));
  934. *y = COORD(Y(state, state->gap_pos));
  935. *w = *h = TILE_SIZE;
  936. }
  937. static int game_status(const game_state *state)
  938. {
  939. return state->completed ? +1 : 0;
  940. }
  941. #ifdef COMBINED
  942. #define thegame fifteen
  943. #endif
  944. const struct game thegame = {
  945. "Fifteen", "games.fifteen", "fifteen",
  946. default_params,
  947. game_fetch_preset, NULL,
  948. decode_params,
  949. encode_params,
  950. free_params,
  951. dup_params,
  952. true, game_configure, custom_params,
  953. validate_params,
  954. new_game_desc,
  955. validate_desc,
  956. new_game,
  957. dup_game,
  958. free_game,
  959. true, solve_game,
  960. true, game_can_format_as_text_now, game_text_format,
  961. get_prefs, set_prefs,
  962. new_ui,
  963. free_ui,
  964. NULL, /* encode_ui */
  965. NULL, /* decode_ui */
  966. NULL, /* game_request_keys */
  967. game_changed_state,
  968. NULL, /* current_key_label */
  969. interpret_move,
  970. execute_move,
  971. PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
  972. game_colours,
  973. game_new_drawstate,
  974. game_free_drawstate,
  975. game_redraw,
  976. game_anim_length,
  977. game_flash_length,
  978. game_get_cursor_location,
  979. game_status,
  980. false, false, NULL, NULL, /* print_size, print */
  981. true, /* wants_statusbar */
  982. false, NULL, /* timing_state */
  983. 0, /* flags */
  984. };
  985. #ifdef STANDALONE_SOLVER
  986. int main(int argc, char **argv)
  987. {
  988. game_params *params;
  989. game_state *state;
  990. char *id = NULL, *desc;
  991. const char *err;
  992. bool grade = false;
  993. char *progname = argv[0];
  994. char buf[80];
  995. int limit, x, y;
  996. bool solvable;
  997. while (--argc > 0) {
  998. char *p = *++argv;
  999. if (!strcmp(p, "-v")) {
  1000. /* solver_show_working = true; */
  1001. } else if (!strcmp(p, "-g")) {
  1002. grade = true;
  1003. } else if (*p == '-') {
  1004. fprintf(stderr, "%s: unrecognised option `%s'\n", progname, p);
  1005. return 1;
  1006. } else {
  1007. id = p;
  1008. }
  1009. }
  1010. if (!id) {
  1011. fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]);
  1012. return 1;
  1013. }
  1014. desc = strchr(id, ':');
  1015. if (!desc) {
  1016. fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
  1017. return 1;
  1018. }
  1019. *desc++ = '\0';
  1020. params = default_params();
  1021. decode_params(params, id);
  1022. err = validate_desc(params, desc);
  1023. if (err) {
  1024. free_params(params);
  1025. fprintf(stderr, "%s: %s\n", argv[0], err);
  1026. return 1;
  1027. }
  1028. state = new_game(NULL, params, desc);
  1029. free_params(params);
  1030. solvable = (PARITY_S(state) == perm_parity(state->tiles, state->n));
  1031. if (grade || !solvable) {
  1032. free_game(state);
  1033. fputs(solvable ? "Game is solvable" : "Game is unsolvable",
  1034. grade ? stdout : stderr);
  1035. return !grade;
  1036. }
  1037. for (limit = 5 * state->n * state->n * state->n; limit; --limit) {
  1038. game_state *next_state;
  1039. if (!compute_hint(state, &x, &y)) {
  1040. fprintf(stderr, "couldn't compute next move while solving %s:%s",
  1041. id, desc);
  1042. return 1;
  1043. }
  1044. printf("Move the space to (%d, %d), moving %d into the space\n",
  1045. x + 1, y + 1, state->tiles[C(state, x, y)]);
  1046. sprintf(buf, "M%d,%d", x, y);
  1047. next_state = execute_move(state, buf);
  1048. free_game(state);
  1049. if (!next_state) {
  1050. fprintf(stderr, "invalid move when solving %s:%s\n", id, desc);
  1051. return 1;
  1052. }
  1053. state = next_state;
  1054. if (next_state->completed) {
  1055. free_game(state);
  1056. return 0;
  1057. }
  1058. }
  1059. free_game(state);
  1060. fprintf(stderr, "ran out of moves for %s:%s\n", id, desc);
  1061. return 1;
  1062. }
  1063. #endif