home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / OpenGL / puzzle / puzzle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  28.5 KB  |  1,289 lines

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