Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1252 lines
27 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <malloc.h>
  6. #include <time.h>
  7. #include <math.h>
  8. #include "tk.h"
  9. #include "trackbal.h"
  10. #define WIDTH 4
  11. #define HEIGHT 5
  12. #define PIECES 10
  13. #define OFFSETX -2
  14. #define OFFSETY -2.5
  15. #define OFFSETZ -0.5
  16. typedef char Config[HEIGHT][WIDTH];
  17. struct puzzle {
  18. struct puzzle *backptr;
  19. struct puzzle *solnptr;
  20. Config pieces;
  21. struct puzzle *next;
  22. unsigned hashvalue;
  23. };
  24. #define HASHSIZE 10691
  25. struct puzzlelist {
  26. struct puzzle *puzzle;
  27. struct puzzlelist *next;
  28. };
  29. static char convert[PIECES+1] = {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};
  30. static unsigned char colors[PIECES+1][3] = {
  31. { 0, 0, 0},
  32. {255,255,127},
  33. {255,255,127},
  34. {255,255,127},
  35. {255,255,127},
  36. {255,127,255},
  37. {255,127,255},
  38. {255,127,255},
  39. {255,127,255},
  40. {255,127,127},
  41. {255,255,255},
  42. };
  43. static struct puzzle *hashtable[HASHSIZE];
  44. static struct puzzle *startPuzzle;
  45. static struct puzzlelist *puzzles;
  46. static struct puzzlelist *lastentry;
  47. #define MOVE_SPEED 0.2
  48. static unsigned char movingPiece;
  49. static float move_x,move_y;
  50. static float curquat[4];
  51. static int doubleBuffer=1;
  52. static int depth=1;
  53. static char xsize[PIECES+1] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
  54. static char ysize[PIECES+1] = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2 };
  55. static float zsize[PIECES+1] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.6 };
  56. static GLuint listbase;
  57. static Config startConfig = {
  58. { 8, 10, 10, 7 },
  59. { 8, 10, 10, 7 },
  60. { 6, 9, 9, 5 },
  61. { 6, 4, 3, 5 },
  62. { 2, 0, 0, 1 }
  63. };
  64. static Config thePuzzle = {
  65. { 8, 10, 10, 7 },
  66. { 8, 10, 10, 7 },
  67. { 6, 9, 9, 5 },
  68. { 6, 4, 3, 5 },
  69. { 2, 0, 0, 1 }
  70. };
  71. static int xadds[4]={-1, 0, 1, 0};
  72. static int yadds[4]={ 0,-1, 0, 1};
  73. static long W = 400, H = 300;
  74. static GLint viewport[4];
  75. #define srandom srand
  76. #define random() (rand() >> 2)
  77. unsigned hash(Config config)
  78. {
  79. int i,j,value;
  80. value=0;
  81. for (i=0; i<HEIGHT; i++) {
  82. for (j=0; j<WIDTH; j++) {
  83. value=value+convert[config[i][j]];
  84. value*=6;
  85. }
  86. }
  87. return(value);
  88. }
  89. int solution(Config config)
  90. {
  91. if (config[4][1]==10 && config[4][2]==10) return(1);
  92. return(0);
  93. }
  94. float boxcoords[][3] = {
  95. { 0.2, 0.2, 0.9 },
  96. { 0.8, 0.2, 0.9 },
  97. { 0.8, 0.8, 0.9 },
  98. { 0.2, 0.8, 0.9 },
  99. { 0.2, 0.1, 0.8 },
  100. { 0.8, 0.1, 0.8 },
  101. { 0.9, 0.2, 0.8 },
  102. { 0.9, 0.8, 0.8 },
  103. { 0.8, 0.9, 0.8 },
  104. { 0.2, 0.9, 0.8 },
  105. { 0.1, 0.8, 0.8 },
  106. { 0.1, 0.2, 0.8 },
  107. { 0.2, 0.1, 0.2 },
  108. { 0.8, 0.1, 0.2 },
  109. { 0.9, 0.2, 0.2 },
  110. { 0.9, 0.8, 0.2 },
  111. { 0.8, 0.9, 0.2 },
  112. { 0.2, 0.9, 0.2 },
  113. { 0.1, 0.8, 0.2 },
  114. { 0.1, 0.2, 0.2 },
  115. { 0.2, 0.2, 0.1 },
  116. { 0.8, 0.2, 0.1 },
  117. { 0.8, 0.8, 0.1 },
  118. { 0.2, 0.8, 0.1 },
  119. };
  120. float boxnormals[][3] = {
  121. { 0, 0, 1 }, /* 0 */
  122. { 0, 1, 0 },
  123. { 1, 0, 0 },
  124. { 0, 0,-1 },
  125. { 0,-1, 0 },
  126. {-1, 0, 0 },
  127. { 0.7071, 0.7071, 0.0000}, /* 6 */
  128. { 0.7071,-0.7071, 0.0000},
  129. {-0.7071, 0.7071, 0.0000},
  130. {-0.7071,-0.7071, 0.0000},
  131. { 0.7071, 0.0000, 0.7071}, /* 10 */
  132. { 0.7071, 0.0000,-0.7071},
  133. {-0.7071, 0.0000, 0.7071},
  134. {-0.7071, 0.0000,-0.7071},
  135. { 0.0000, 0.7071, 0.7071}, /* 14 */
  136. { 0.0000, 0.7071,-0.7071},
  137. { 0.0000,-0.7071, 0.7071},
  138. { 0.0000,-0.7071,-0.7071},
  139. { 0.5774, 0.5774, 0.5774}, /* 18 */
  140. { 0.5774, 0.5774,-0.5774},
  141. { 0.5774,-0.5774, 0.5774},
  142. { 0.5774,-0.5774,-0.5774},
  143. {-0.5774, 0.5774, 0.5774},
  144. {-0.5774, 0.5774,-0.5774},
  145. {-0.5774,-0.5774, 0.5774},
  146. {-0.5774,-0.5774,-0.5774},
  147. };
  148. int boxfaces[][4] = {
  149. { 0, 1, 2, 3 }, /* 0 */
  150. { 9, 8, 16, 17 },
  151. { 6, 14, 15, 7 },
  152. { 20, 23, 22, 21 },
  153. { 12, 13, 5, 4 },
  154. { 19, 11, 10, 18 },
  155. { 7, 15, 16, 8 }, /* 6 */
  156. { 13, 14, 6, 5 },
  157. { 18, 10, 9, 17 },
  158. { 19, 12, 4, 11 },
  159. { 1, 6, 7, 2 }, /* 10 */
  160. { 14, 21, 22, 15 },
  161. { 11, 0, 3, 10 },
  162. { 20, 19, 18, 23 },
  163. { 3, 2, 8, 9 }, /* 14 */
  164. { 17, 16, 22, 23 },
  165. { 4, 5, 1, 0 },
  166. { 20, 21, 13, 12 },
  167. { 2, 7, 8, -1 }, /* 18 */
  168. { 16, 15, 22, -1 },
  169. { 5, 6, 1, -1 },
  170. { 13, 21, 14, -1 },
  171. { 10, 3, 9, -1 },
  172. { 18, 17, 23, -1 },
  173. { 11, 4, 0, -1 },
  174. { 20, 12, 19, -1 },
  175. };
  176. #define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))
  177. /* Draw a box. Bevel as desired. */
  178. void drawBox(int piece, float xoff, float yoff)
  179. {
  180. int xlen, ylen;
  181. int i,j,k;
  182. float x,y,z;
  183. float zlen;
  184. float *v;
  185. xlen=xsize[piece];
  186. ylen=ysize[piece];
  187. zlen=zsize[piece];
  188. glColor3ubv(colors[piece]);
  189. glBegin(GL_QUADS);
  190. for (i=0; i<18; i++) {
  191. glNormal3fv(boxnormals[i]);
  192. for (k=0; k<4; k++) {
  193. if (boxfaces[i][k] == -1) continue;
  194. v=boxcoords[boxfaces[i][k]];
  195. x=v[0] + OFFSETX;
  196. if (v[0] > 0.5) x += xlen-1;
  197. y=v[1] + OFFSETY;
  198. if (v[1] > 0.5) y += ylen-1;
  199. z=v[2] + OFFSETZ;
  200. if (v[2] > 0.5) z += zlen-1;
  201. glVertex3f(xoff+x,yoff+y,z);
  202. }
  203. }
  204. glEnd();
  205. glBegin(GL_TRIANGLES);
  206. for (i=18; i<NBOXFACES; i++) {
  207. glNormal3fv(boxnormals[i]);
  208. for (k=0; k<3; k++) {
  209. if (boxfaces[i][k] == -1) continue;
  210. v=boxcoords[boxfaces[i][k]];
  211. x=v[0] + OFFSETX;
  212. if (v[0] > 0.5) x += xlen-1;
  213. y=v[1] + OFFSETY;
  214. if (v[1] > 0.5) y += ylen-1;
  215. z=v[2] + OFFSETZ;
  216. if (v[2] > 0.5) z += zlen-1;
  217. glVertex3f(xoff+x,yoff+y,z);
  218. }
  219. }
  220. glEnd();
  221. }
  222. float containercoords[][3] = {
  223. { -0.1, -0.1, 1.0 },
  224. { -0.1, -0.1, -0.1 },
  225. { 4.1, -0.1, -0.1 },
  226. { 4.1, -0.1, 1.0 },
  227. { 1.0, -0.1, 0.6 }, /* 4 */
  228. { 3.0, -0.1, 0.6 },
  229. { 1.0, -0.1, 0.0 },
  230. { 3.0, -0.1, 0.0 },
  231. { 1.0, 0.0, 0.0 }, /* 8 */
  232. { 3.0, 0.0, 0.0 },
  233. { 3.0, 0.0, 0.6 },
  234. { 1.0, 0.0, 0.6 },
  235. { 0.0, 0.0, 1.0 }, /* 12 */
  236. { 4.0, 0.0, 1.0 },
  237. { 4.0, 0.0, 0.0 },
  238. { 0.0, 0.0, 0.0 },
  239. { 0.0, 5.0, 0.0 }, /* 16 */
  240. { 0.0, 5.0, 1.0 },
  241. { 4.0, 5.0, 1.0 },
  242. { 4.0, 5.0, 0.0 },
  243. { -0.1, 5.1, -0.1 }, /* 20 */
  244. { 4.1, 5.1, -0.1 },
  245. { 4.1, 5.1, 1.0 },
  246. { -0.1, 5.1, 1.0 },
  247. };
  248. float containernormals[][3] = {
  249. { 0,-1, 0 },
  250. { 0,-1, 0 },
  251. { 0,-1, 0 },
  252. { 0,-1, 0 },
  253. { 0,-1, 0 },
  254. { 0, 1, 0 },
  255. { 0, 1, 0 },
  256. { 0, 1, 0 },
  257. { 1, 0, 0 },
  258. { 1, 0, 0 },
  259. { 1, 0, 0 },
  260. {-1, 0, 0 },
  261. {-1, 0, 0 },
  262. {-1, 0, 0 },
  263. { 0, 1, 0 },
  264. { 0, 0,-1 },
  265. { 0, 0,-1 },
  266. { 0, 0, 1 },
  267. { 0, 0, 1 },
  268. { 0, 0, 1 },
  269. { 0, 0, 1 },
  270. { 0, 0, 1 },
  271. { 0, 0, 1 },
  272. { 0, 0, 1 },
  273. };
  274. int containerfaces[][4] = {
  275. { 1, 6, 4, 0 },
  276. { 0, 4, 5, 3 },
  277. { 1, 2, 7, 6 },
  278. { 7, 2, 3, 5 },
  279. { 16, 19, 18, 17 },
  280. { 23, 22, 21, 20 },
  281. { 12, 11, 8, 15 },
  282. { 10, 13, 14, 9 },
  283. { 15, 16, 17, 12 },
  284. { 2, 21, 22, 3 },
  285. { 6, 8, 11, 4 },
  286. { 1, 0, 23, 20 },
  287. { 14, 13, 18, 19 },
  288. { 9, 7, 5, 10 },
  289. { 12, 13, 10, 11 },
  290. { 1, 20, 21, 2 },
  291. { 4, 11, 10, 5 },
  292. { 15, 8, 19, 16 },
  293. { 19, 8, 9, 14 },
  294. { 8, 6, 7, 9 },
  295. { 0, 3, 13, 12 },
  296. { 13, 3, 22, 18 },
  297. { 18, 22, 23, 17 },
  298. { 17, 23, 0, 12 },
  299. };
  300. #define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))
  301. /* Draw the container */
  302. void drawContainer(void)
  303. {
  304. int i,k;
  305. float *v;
  306. /* Y is reversed here because the model has it reversed */
  307. /* Arbitrary bright wood-like color */
  308. glColor3ub(209, 103, 23);
  309. glBegin(GL_QUADS);
  310. for (i=0; i<NCONTFACES; i++) {
  311. v=containernormals[i];
  312. glNormal3f(v[0], -v[1], v[2]);
  313. for (k=3; k>=0; k--) {
  314. v=containercoords[containerfaces[i][k]];
  315. glVertex3f(v[0]+OFFSETX, -(v[1]+OFFSETY), v[2]+OFFSETZ);
  316. }
  317. }
  318. glEnd();
  319. }
  320. void drawAll(int withTags)
  321. {
  322. int i,j;
  323. int piece;
  324. char done[PIECES+1];
  325. float m[4][4];
  326. build_rotmatrix(m, curquat);
  327. glMatrixMode(GL_MODELVIEW);
  328. glLoadIdentity();
  329. gluLookAt(0,0,10, 0,0,0, 0,-1,0);
  330. glMultMatrixf(&(m[0][0]));
  331. if (depth) {
  332. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  333. } else {
  334. glClear(GL_COLOR_BUFFER_BIT);
  335. }
  336. for (i=1; i <= PIECES; i++) {
  337. done[i] = 0;
  338. }
  339. glLoadName(0);
  340. drawContainer();
  341. for (i=0; i<HEIGHT; i++) {
  342. for (j=0; j<WIDTH; j++) {
  343. piece = thePuzzle[i][j];
  344. if (piece == 0) continue;
  345. if (done[piece]) continue;
  346. done[piece] = 1;
  347. glLoadName(piece);
  348. if (piece == movingPiece) {
  349. drawBox(piece, move_x, move_y);
  350. } else {
  351. drawBox(piece, j, i);
  352. }
  353. }
  354. }
  355. }
  356. void redraw(void)
  357. {
  358. glMatrixMode(GL_PROJECTION);
  359. glLoadIdentity();
  360. gluPerspective(45, 1.0, 0.1, 100.0);
  361. drawAll(GL_FALSE);
  362. if (doubleBuffer) tkSwapBuffers();
  363. }
  364. void solidifyChain(struct puzzle *puzzle)
  365. {
  366. int i;
  367. i=0;
  368. while (puzzle->backptr) {
  369. i++;
  370. puzzle->backptr->solnptr = puzzle;
  371. puzzle=puzzle->backptr;
  372. }
  373. printf("%d moves to complete!\n", i);
  374. }
  375. int addConfig(Config config, struct puzzle *back)
  376. {
  377. unsigned hashvalue;
  378. struct puzzle *newpiece;
  379. struct puzzlelist *newlistentry;
  380. hashvalue=hash(config);
  381. newpiece=hashtable[hashvalue % HASHSIZE];
  382. while (newpiece != NULL) {
  383. if (newpiece->hashvalue == hashvalue) {
  384. int i,j;
  385. for (i=0; i<WIDTH; i++) {
  386. for (j=0; j<HEIGHT; j++) {
  387. if (convert[config[j][i]] !=
  388. convert[newpiece->pieces[j][i]]) goto nomatch;
  389. }
  390. }
  391. return 0;
  392. }
  393. nomatch:
  394. newpiece=newpiece->next;
  395. }
  396. newpiece=(struct puzzle *) malloc(sizeof(struct puzzle));
  397. newpiece->next=hashtable[hashvalue % HASHSIZE];
  398. newpiece->hashvalue=hashvalue;
  399. memcpy(newpiece->pieces, config, HEIGHT*WIDTH);
  400. newpiece->backptr=back;
  401. newpiece->solnptr=NULL;
  402. hashtable[hashvalue % HASHSIZE]=newpiece;
  403. newlistentry=(struct puzzlelist *) malloc(sizeof(struct puzzlelist));
  404. newlistentry->puzzle=newpiece;
  405. newlistentry->next=NULL;
  406. if (lastentry) {
  407. lastentry->next=newlistentry;
  408. } else {
  409. puzzles=newlistentry;
  410. }
  411. lastentry=newlistentry;
  412. if (back == NULL) {
  413. startPuzzle = newpiece;
  414. }
  415. if (solution(config)) {
  416. solidifyChain(newpiece);
  417. return 1;
  418. }
  419. return 0;
  420. }
  421. /* Checks if a space can move */
  422. int canmove0(Config pieces, int x, int y, int dir, Config newpieces)
  423. {
  424. char piece;
  425. int xadd, yadd;
  426. int l,m;
  427. xadd=xadds[dir];
  428. yadd=yadds[dir];
  429. if (x+xadd<0 || x+xadd>=WIDTH ||
  430. y+yadd<0 || y+yadd>=HEIGHT) return 0;
  431. piece=pieces[y+yadd][x+xadd];
  432. if (piece==0) return 0;
  433. memcpy(newpieces, pieces, HEIGHT*WIDTH);
  434. for (l=0; l<WIDTH; l++) {
  435. for (m=0; m<HEIGHT; m++) {
  436. if (newpieces[m][l]==piece)
  437. newpieces[m][l]=0;
  438. }
  439. }
  440. xadd= -xadd;
  441. yadd= -yadd;
  442. for (l=0; l<WIDTH; l++) {
  443. for (m=0; m<HEIGHT; m++) {
  444. if (pieces[m][l]==piece) {
  445. int newx, newy;
  446. newx=l+xadd;
  447. newy=m+yadd;
  448. if (newx<0 || newx>=WIDTH ||
  449. newy<0 || newy>=HEIGHT) return 0;
  450. if (newpieces[newy][newx] != 0) return 0;
  451. newpieces[newy][newx]=piece;
  452. }
  453. }
  454. }
  455. return 1;
  456. }
  457. /* Checks if a piece can move */
  458. int canmove(Config pieces, int x, int y, int dir, Config newpieces)
  459. {
  460. int xadd, yadd;
  461. xadd=xadds[dir];
  462. yadd=yadds[dir];
  463. if (x+xadd<0 || x+xadd>=WIDTH ||
  464. y+yadd<0 || y+yadd>=HEIGHT) return 0;
  465. if (pieces[y+yadd][x+xadd] == pieces[y][x]) {
  466. return canmove(pieces, x+xadd, y+yadd, dir, newpieces);
  467. }
  468. if (pieces[y+yadd][x+xadd] != 0) return 0;
  469. return canmove0(pieces, x+xadd, y+yadd, (dir+2) % 4, newpieces);
  470. }
  471. int generateNewConfigs(struct puzzle *puzzle)
  472. {
  473. int i,j,k;
  474. Config pieces;
  475. Config newpieces;
  476. memcpy(pieces, puzzle->pieces, HEIGHT*WIDTH);
  477. for (i=0; i<WIDTH; i++) {
  478. for (j=0; j<HEIGHT; j++) {
  479. if (pieces[j][i] == 0) {
  480. for (k=0; k<4; k++) {
  481. if (canmove0(pieces, i, j, k, newpieces)) {
  482. if (addConfig(newpieces, puzzle)) return 1;
  483. }
  484. }
  485. }
  486. }
  487. }
  488. return 0;
  489. }
  490. void freeSolutions(void)
  491. {
  492. struct puzzlelist *nextpuz;
  493. struct puzzle *puzzle, *next;
  494. int i;
  495. while (puzzles) {
  496. nextpuz = puzzles->next;
  497. free((char *) puzzles);
  498. puzzles=nextpuz;
  499. }
  500. lastentry = NULL;
  501. for (i=0; i<HASHSIZE; i++) {
  502. puzzle = hashtable[i];
  503. hashtable[i] = NULL;
  504. while (puzzle) {
  505. next = puzzle->next;
  506. free((char *) puzzle);
  507. puzzle = next;
  508. }
  509. }
  510. startPuzzle = NULL;
  511. }
  512. int continueSolving(void)
  513. {
  514. struct puzzle *nextpuz;
  515. int i,j;
  516. int movedPiece;
  517. int movedir;
  518. int fromx, fromy;
  519. int tox, toy;
  520. if (startPuzzle == NULL) return 0;
  521. if (startPuzzle->solnptr == NULL) {
  522. freeSolutions();
  523. return 0;
  524. }
  525. nextpuz = startPuzzle->solnptr;
  526. movedPiece=0;
  527. movedir=0;
  528. for (i=0; i<HEIGHT; i++) {
  529. for (j=0; j<WIDTH; j++) {
  530. if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
  531. if (startPuzzle->pieces[i][j]) {
  532. movedPiece=startPuzzle->pieces[i][j];
  533. fromx=j;
  534. fromy=i;
  535. if (i<HEIGHT-1 && nextpuz->pieces[i+1][j] == movedPiece) {
  536. movedir=3;
  537. } else {
  538. movedir=2;
  539. }
  540. goto found_piece;
  541. } else {
  542. movedPiece=nextpuz->pieces[i][j];
  543. if (i<HEIGHT-1 &&
  544. startPuzzle->pieces[i+1][j] == movedPiece) {
  545. fromx=j;
  546. fromy=i+1;
  547. movedir=1;
  548. } else {
  549. fromx=j+1;
  550. fromy=i;
  551. movedir=0;
  552. }
  553. goto found_piece;
  554. }
  555. }
  556. }
  557. }
  558. printf("What! No change?\n");
  559. freeSolutions();
  560. return 0;
  561. found_piece:
  562. if (!movingPiece) {
  563. movingPiece = movedPiece;
  564. move_x = fromx;
  565. move_y = fromy;
  566. }
  567. move_x += xadds[movedir] * MOVE_SPEED;
  568. move_y += yadds[movedir] * MOVE_SPEED;
  569. tox = fromx + xadds[movedir];
  570. toy = fromy + yadds[movedir];
  571. if (move_x > tox - MOVE_SPEED/2 && move_x < tox + MOVE_SPEED/2 &&
  572. move_y > toy - MOVE_SPEED/2 && move_y < toy + MOVE_SPEED/2) {
  573. startPuzzle = nextpuz;
  574. movingPiece=0;
  575. }
  576. memcpy(thePuzzle, startPuzzle->pieces, HEIGHT*WIDTH);
  577. return 1;
  578. }
  579. int solvePuzzle(void)
  580. {
  581. struct puzzlelist *nextpuz;
  582. int i;
  583. if (solution(thePuzzle)) {
  584. printf("Puzzle already solved!\n");
  585. return 0;
  586. }
  587. addConfig(thePuzzle, NULL);
  588. i=0;
  589. while (puzzles) {
  590. i++;
  591. if (generateNewConfigs(puzzles->puzzle)) break;
  592. nextpuz=puzzles->next;
  593. free((char *) puzzles);
  594. puzzles=nextpuz;
  595. }
  596. if (puzzles == NULL) {
  597. freeSolutions();
  598. printf("I can't solve it! (%d positions examined)\n", i);
  599. return 1;
  600. }
  601. return 1;
  602. }
  603. int selectPiece(int mousex, int mousey)
  604. {
  605. long hits;
  606. GLuint selectBuf[1024];
  607. GLuint closest;
  608. GLuint dist;
  609. glSelectBuffer(1024, selectBuf);
  610. (void) glRenderMode(GL_SELECT);
  611. glInitNames();
  612. /* Because LoadName() won't work with no names on the stack */
  613. glPushName(-1);
  614. glMatrixMode(GL_PROJECTION);
  615. glLoadIdentity();
  616. gluPickMatrix(mousex, H-mousey, 4, 4, viewport);
  617. gluPerspective(45, 1.0, 0.1, 100.0);
  618. drawAll(GL_TRUE);
  619. hits = glRenderMode(GL_RENDER);
  620. if (hits <= 0) {
  621. return 0;
  622. }
  623. closest=0;
  624. dist=4294967295;
  625. while (hits) {
  626. if (selectBuf[(hits-1)*4+1] < dist) {
  627. dist = selectBuf[(hits-1)*4+1];
  628. closest = selectBuf[(hits-1)*4+3];
  629. }
  630. hits--;
  631. }
  632. return closest;
  633. }
  634. void nukePiece(int piece)
  635. {
  636. int i,j;
  637. for (i=0; i<HEIGHT; i++) {
  638. for (j=0; j<WIDTH; j++) {
  639. if (thePuzzle[i][j] == piece) {
  640. thePuzzle[i][j] = 0;
  641. }
  642. }
  643. }
  644. }
  645. void multMatrices(const GLfloat a[16], const GLfloat b[16], GLfloat r[16])
  646. {
  647. int i, j;
  648. for (i = 0; i < 4; i++) {
  649. for (j = 0; j < 4; j++) {
  650. r[i*4+j] =
  651. a[i*4+0]*b[0*4+j] +
  652. a[i*4+1]*b[1*4+j] +
  653. a[i*4+2]*b[2*4+j] +
  654. a[i*4+3]*b[3*4+j];
  655. }
  656. }
  657. }
  658. void makeIdentity(GLfloat m[16])
  659. {
  660. m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
  661. m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
  662. m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
  663. m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
  664. }
  665. /*
  666. ** inverse = invert(src)
  667. */
  668. int invertMatrix(const GLfloat src[16], GLfloat inverse[16])
  669. {
  670. int i, j, k, swap;
  671. double t;
  672. GLfloat temp[4][4];
  673. for (i=0; i<4; i++) {
  674. for (j=0; j<4; j++) {
  675. temp[i][j] = src[i*4+j];
  676. }
  677. }
  678. makeIdentity(inverse);
  679. for (i = 0; i < 4; i++) {
  680. /*
  681. ** Look for largest element in column
  682. */
  683. swap = i;
  684. for (j = i + 1; j < 4; j++) {
  685. if (fabs(temp[j][i]) > fabs(temp[i][i])) {
  686. swap = j;
  687. }
  688. }
  689. if (swap != i) {
  690. /*
  691. ** Swap rows.
  692. */
  693. for (k = 0; k < 4; k++) {
  694. t = temp[i][k];
  695. temp[i][k] = temp[swap][k];
  696. temp[swap][k] = t;
  697. t = inverse[i*4+k];
  698. inverse[i*4+k] = inverse[swap*4+k];
  699. inverse[swap*4+k] = t;
  700. }
  701. }
  702. if (temp[i][i] == 0) {
  703. /*
  704. ** No non-zero pivot. The matrix is singular, which shouldn't
  705. ** happen. This means the user gave us a bad matrix.
  706. */
  707. return 0;
  708. }
  709. t = temp[i][i];
  710. for (k = 0; k < 4; k++) {
  711. temp[i][k] /= t;
  712. inverse[i*4+k] /= t;
  713. }
  714. for (j = 0; j < 4; j++) {
  715. if (j != i) {
  716. t = temp[j][i];
  717. for (k = 0; k < 4; k++) {
  718. temp[j][k] -= temp[i][k]*t;
  719. inverse[j*4+k] -= inverse[i*4+k]*t;
  720. }
  721. }
  722. }
  723. }
  724. return 1;
  725. }
  726. /*
  727. ** This is a screwball function. What it does is the following:
  728. ** Given screen x and y coordinates, compute the corresponding object space
  729. ** x and y coordinates given that the object space z is 0.9 + OFFSETZ.
  730. ** Since the tops of (most) pieces are at z = 0.9 + OFFSETZ, we use that
  731. ** number.
  732. */
  733. int computeCoords(int piece, int mousex, int mousey,
  734. GLfloat *selx, GLfloat *sely)
  735. {
  736. GLfloat modelMatrix[16];
  737. GLfloat projMatrix[16];
  738. GLfloat finalMatrix[16];
  739. GLfloat in[4];
  740. GLfloat a,b,c,d;
  741. GLfloat top, bot;
  742. GLfloat z;
  743. GLfloat w;
  744. GLfloat height;
  745. if (piece == 0) return 0;
  746. height = zsize[piece] - 0.1 + OFFSETZ;
  747. glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
  748. glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
  749. multMatrices(modelMatrix, projMatrix, finalMatrix);
  750. if (!invertMatrix(finalMatrix, finalMatrix)) return 0;
  751. in[0] = (2.0 * (mousex - viewport[0]) / viewport[2]) - 1;
  752. in[1] = (2.0 * ((H - mousey) - viewport[1]) / viewport[3]) - 1;
  753. a = in[0] * finalMatrix[0*4+2] +
  754. in[1] * finalMatrix[1*4+2] +
  755. finalMatrix[3*4+2];
  756. b = finalMatrix[2*4+2];
  757. c = in[0] * finalMatrix[0*4+3] +
  758. in[1] * finalMatrix[1*4+3] +
  759. finalMatrix[3*4+3];
  760. d = finalMatrix[2*4+3];
  761. /*
  762. ** Ok, now we need to solve for z:
  763. ** (a + b z) / (c + d z) = height.
  764. ** ("height" is the height in object space we want to solve z for)
  765. **
  766. ** ==> a + b z = height c + height d z
  767. ** bz - height d z = height c - a
  768. ** z = (height c - a) / (b - height d)
  769. */
  770. top = height * c - a;
  771. bot = b - height * d;
  772. if (bot == 0.0) return 0;
  773. z = top / bot;
  774. /*
  775. ** Ok, no problem.
  776. ** Now we solve for x and y. We know that w = c + d z, so we compute it.
  777. */
  778. w = c + d * z;
  779. /*
  780. ** Now for x and y:
  781. */
  782. *selx = (in[0] * finalMatrix[0*4+0] +
  783. in[1] * finalMatrix[1*4+0] +
  784. z * finalMatrix[2*4+0] +
  785. finalMatrix[3*4+0]) / w - OFFSETX;
  786. *sely = (in[0] * finalMatrix[0*4+1] +
  787. in[1] * finalMatrix[1*4+1] +
  788. z * finalMatrix[2*4+1] +
  789. finalMatrix[3*4+1]) / w - OFFSETY;
  790. return 1;
  791. }
  792. static int selected;
  793. static int selectx, selecty;
  794. static float selstartx, selstarty;
  795. void grabPiece(int piece, float selx, float sely)
  796. {
  797. int hit;
  798. selectx=selx;
  799. selecty=sely;
  800. if (selectx < 0 || selecty < 0 || selectx >= WIDTH || selecty >= HEIGHT) {
  801. return;
  802. }
  803. hit = thePuzzle[selecty][selectx];
  804. if (hit != piece) return;
  805. if (hit) {
  806. movingPiece=hit;
  807. while (selectx > 0 && thePuzzle[selecty][selectx-1] == movingPiece) {
  808. selectx--;
  809. }
  810. while (selecty > 0 && thePuzzle[selecty-1][selectx] == movingPiece) {
  811. selecty--;
  812. }
  813. move_x=selectx;
  814. move_y=selecty;
  815. selected=1;
  816. selstartx=selx;
  817. selstarty=sely;
  818. } else {
  819. selected=0;
  820. }
  821. }
  822. void moveSelection(float selx, float sely)
  823. {
  824. float deltax, deltay;
  825. int dir;
  826. Config newpieces;
  827. if (!selected) return;
  828. deltax = selx - selstartx;
  829. deltay = sely - selstarty;
  830. if (fabs(deltax) > fabs(deltay)) {
  831. deltay = 0;
  832. if (deltax > 0) {
  833. if (deltax > 1) deltax = 1;
  834. dir = 2;
  835. } else {
  836. if (deltax < -1) deltax = -1;
  837. dir = 0;
  838. }
  839. } else {
  840. deltax = 0;
  841. if (deltay > 0) {
  842. if (deltay > 1) deltay = 1;
  843. dir = 3;
  844. } else {
  845. if (deltay < -1) deltay = -1;
  846. dir = 1;
  847. }
  848. }
  849. if (canmove(thePuzzle, selectx, selecty, dir, newpieces)) {
  850. move_x = deltax + selectx;
  851. move_y = deltay + selecty;
  852. if (deltax > 0.5) {
  853. memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
  854. selectx++;
  855. selstartx++;
  856. } else if (deltax < -0.5) {
  857. memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
  858. selectx--;
  859. selstartx--;
  860. } else if (deltay > 0.5) {
  861. memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
  862. selecty++;
  863. selstarty++;
  864. } else if (deltay < -0.5) {
  865. memcpy(thePuzzle, newpieces, HEIGHT*WIDTH);
  866. selecty--;
  867. selstarty--;
  868. }
  869. } else {
  870. if (deltay > 0 && thePuzzle[selecty][selectx] == 10 &&
  871. selectx == 1 && selecty == 3) {
  872. /* Allow visual movement of solution piece outside of the box */
  873. move_x = selectx;
  874. move_y = sely - selstarty + selecty;
  875. } else {
  876. move_x = selectx;
  877. move_y = selecty;
  878. }
  879. }
  880. }
  881. void dropSelection(void)
  882. {
  883. if (!selected) return;
  884. movingPiece = 0;
  885. selected = 0;
  886. }
  887. static int left_mouse, right_mouse;
  888. static int mousex, mousey;
  889. static int solving;
  890. static int spinning;
  891. static float lastquat[4];
  892. static int sel_piece;
  893. static void Reshape(int width, int height)
  894. {
  895. W = width;
  896. H = height;
  897. glViewport(0, 0, W, H);
  898. glGetIntegerv(GL_VIEWPORT, viewport);
  899. }
  900. static GLenum Key(int key, GLenum mask)
  901. {
  902. int piece;
  903. int x, y;
  904. if (!left_mouse && !right_mouse) {
  905. switch(key) {
  906. case TK_ESCAPE:
  907. tkQuit();
  908. case TK_d:
  909. case TK_D:
  910. if (solving) {
  911. freeSolutions();
  912. solving=0;
  913. movingPiece=0;
  914. }
  915. tkGetMouseLoc(&x, &y);
  916. piece = selectPiece(x, y);
  917. if (piece) {
  918. nukePiece(piece);
  919. }
  920. break;
  921. case TK_S:
  922. case TK_s:
  923. if (solving) {
  924. freeSolutions();
  925. solving=0;
  926. movingPiece=0;
  927. } else {
  928. printf("Solving...\n");
  929. if (solvePuzzle()) {
  930. solving = 1;
  931. }
  932. }
  933. break;
  934. case TK_R:
  935. case TK_r:
  936. if (solving) {
  937. freeSolutions();
  938. solving=0;
  939. movingPiece=0;
  940. }
  941. memcpy(thePuzzle, startConfig, HEIGHT*WIDTH);
  942. break;
  943. case TK_b:
  944. case TK_B:
  945. depth=1-depth;
  946. if (depth) {
  947. glEnable(GL_DEPTH_TEST);
  948. } else {
  949. glDisable(GL_DEPTH_TEST);
  950. }
  951. break;
  952. default:
  953. return GL_FALSE;
  954. }
  955. }
  956. return GL_TRUE;
  957. }
  958. static GLenum MouseUp(int mouseX, int mouseY, GLenum button)
  959. {
  960. if (button & TK_LEFTBUTTON) {
  961. left_mouse = GL_FALSE;
  962. dropSelection();
  963. return GL_TRUE;
  964. } else if (button & TK_RIGHTBUTTON) {
  965. right_mouse = GL_FALSE;
  966. return GL_TRUE;
  967. }
  968. return GL_FALSE;
  969. }
  970. static GLenum MouseDown(int mouseX, int mouseY, GLenum button)
  971. {
  972. int piece;
  973. float selx, sely;
  974. mousex = mouseX;
  975. mousey = mouseY;
  976. if (button & TK_LEFTBUTTON) {
  977. if (solving) {
  978. freeSolutions();
  979. solving=0;
  980. movingPiece=0;
  981. }
  982. left_mouse = GL_TRUE;
  983. sel_piece = selectPiece(mousex, mousey);
  984. if (computeCoords(sel_piece, mousex, mousey, &selx, &sely)) {
  985. grabPiece(sel_piece, selx, sely);
  986. }
  987. return GL_TRUE;
  988. } else if (button & TK_RIGHTBUTTON) {
  989. right_mouse = GL_TRUE;
  990. return GL_TRUE;
  991. }
  992. return GL_FALSE;
  993. }
  994. void animate(void)
  995. {
  996. int piece;
  997. float selx, sely;
  998. int x, y;
  999. if (right_mouse || left_mouse) {
  1000. tkGetMouseLoc(&x, &y);
  1001. if (right_mouse && !left_mouse) {
  1002. if (mousex != x || mousey != y) {
  1003. trackball(lastquat,
  1004. 2.0*(W-mousex)/W - 1.0,
  1005. 2.0*mousey/H - 1.0,
  1006. 2.0*(W-x)/W - 1.0,
  1007. 2.0*y/H - 1.0);
  1008. spinning = 1;
  1009. } else {
  1010. spinning = 0;
  1011. }
  1012. } else {
  1013. computeCoords(sel_piece, x, y, &selx, &sely);
  1014. moveSelection(selx, sely);
  1015. }
  1016. mousex = x;
  1017. mousey = y;
  1018. }
  1019. if (spinning) {
  1020. add_quats(lastquat, curquat, curquat);
  1021. }
  1022. redraw();
  1023. if (solving) {
  1024. if (!continueSolving()) {
  1025. solving = 0;
  1026. }
  1027. }
  1028. }
  1029. void init(void)
  1030. {
  1031. static float lmodel_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
  1032. static float lmodel_twoside[] = { GL_FALSE };
  1033. static float lmodel_local[] = { GL_FALSE };
  1034. static float light0_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  1035. static float light0_diffuse[] = { 1.0, 1.0, 1.0, 0.0 };
  1036. static float light0_position[] = { 0.8660254, 0.5, 1, 0 };
  1037. static float light0_specular[] = { 0.0, 0.0, 0.0, 0.0 };
  1038. static float bevel_mat_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
  1039. static float bevel_mat_shininess[] = { 40.0 };
  1040. static float bevel_mat_specular[] = { 0.0, 0.0, 0.0, 0.0 };
  1041. static float bevel_mat_diffuse[] = { 1.0, 0.0, 0.0, 0.0 };
  1042. glEnable(GL_CULL_FACE);
  1043. glCullFace(GL_BACK);
  1044. glEnable(GL_DEPTH_TEST);
  1045. glClearDepth(1.0);
  1046. glClearColor(0.5, 0.5, 0.5, 0.0);
  1047. glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  1048. glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  1049. glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
  1050. glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
  1051. glEnable(GL_LIGHT0);
  1052. glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local);
  1053. glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
  1054. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  1055. glEnable(GL_LIGHTING);
  1056. glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient);
  1057. glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess);
  1058. glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular);
  1059. glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse);
  1060. glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  1061. glEnable(GL_COLOR_MATERIAL);
  1062. glShadeModel(GL_FLAT);
  1063. trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  1064. srandom(time(NULL));
  1065. }
  1066. static void Usage(void)
  1067. {
  1068. printf("Usage: puzzle [-s]\n");
  1069. printf(" -s: Run in single buffered mode\n");
  1070. exit(-1);
  1071. }
  1072. void main(long argc, char** argv)
  1073. {
  1074. long i;
  1075. for (i = 1; i < argc; i++) {
  1076. if (argv[i][0] == '-') {
  1077. switch (argv[i][1]) {
  1078. case 's':
  1079. doubleBuffer = 0;
  1080. break;
  1081. default:
  1082. Usage();
  1083. }
  1084. } else {
  1085. Usage();
  1086. }
  1087. }
  1088. tkInitPosition(0, 0, W, H);
  1089. tkInitDisplayMode(TK_DEPTH16|TK_RGB|TK_DOUBLE|TK_DIRECT);
  1090. if (tkInitWindow("Puzzle") == GL_FALSE) {
  1091. tkQuit();
  1092. }
  1093. init();
  1094. glGetIntegerv(GL_VIEWPORT, viewport);
  1095. printf("\n\n\n\n\n\n");
  1096. printf("r Reset puzzle\n");
  1097. printf("s Solve puzzle (may take a few seconds to compute)\n");
  1098. printf("d Destroy a piece - makes the puzzle easier\n");
  1099. printf("b Toggles the depth buffer on and off\n");
  1100. printf("\n");
  1101. printf("Right mouse spins the puzzle\n");
  1102. printf("Left mouse moves pieces\n");
  1103. tkExposeFunc(Reshape);
  1104. tkReshapeFunc(Reshape);
  1105. tkKeyDownFunc(Key);
  1106. tkMouseDownFunc(MouseDown);
  1107. tkMouseUpFunc(MouseUp);
  1108. tkIdleFunc(animate);
  1109. tkExec();
  1110. }