2 * queens - solves n queens problem, displays
3 * i make no claims that this is an optimal solution to the problem,
7 * version 1.0 - May 10, 2002
9 * Copyright (C) 2002 Blair Tennessy (tennessy@cs.ubc.ca)
11 * Permission to use, copy, modify, distribute, and sell this software and its
12 * documentation for any purpose is hereby granted without fee, provided that
13 * the above copyright notice appear in all copies and that both that
14 * copyright notice and this permission notice appear in supporting
15 * documentation. No representations are made about the suitability of this
16 * software for any purpose. It is provided "as is" without express or
20 #include <X11/Intrinsic.h>
23 # define PROGCLASS "Queens"
24 # define HACK_INIT init_queens
25 # define HACK_DRAW draw_queens
26 # define HACK_RESHAPE reshape_queens
27 # define HACK_HANDLE_EVENT queens_handle_event
28 # define EVENT_MASK PointerMotionMask
29 # define queens_opts xlockmore_opts
31 #define DEFAULTS "*delay: 20000 \n" \
32 "*showFPS: False \n" \
33 "*wireframe: False \n" \
35 # include "xlockmore.h"
44 #include "gltrackball.h"
47 #define countof(x) (sizeof((x))/sizeof((*x)))
49 static XrmOptionDescRec opts[] = {
50 {"+rotate", ".queens.rotate", XrmoptionNoArg, "false" },
51 {"-rotate", ".queens.rotate", XrmoptionNoArg, "true" },
52 {"+flat", ".queens.flat", XrmoptionNoArg, "false" },
53 {"-flat", ".queens.flat", XrmoptionNoArg, "true" },
56 int rotate, wire, clearbits, flat;
58 static argtype vars[] = {
59 {&rotate, "rotate", "Rotate", "True", t_Bool},
60 {&flat, "flat", "Flat", "False", t_Bool},
63 ModeSpecOpt queens_opts = {countof(opts), opts, countof(vars), vars, NULL};
66 ModStruct queens_description =
67 {"queens", "init_queens", "draw_queens", "release_queens",
68 "draw_queens", "init_queens", NULL, &queens_opts,
69 1000, 1, 2, 1, 4, 1.0, "",
75 GLXContext *glx_context;
77 trackball_state *trackball;
81 static Queenscreen *qs = NULL;
89 #define M_PI 3.14159265
98 /* definition of white/black colors */
99 GLfloat colors[COLORSETS][2][3] =
101 {{0.43, 0.54, 0.76}, {0.8, 0.8, 0.8}},
102 {{0.5, 0.7, 0.9}, {0.2, 0.3, 0.6}},
103 {{0.53725490196, 0.360784313725, 0.521568627451}, {0.6, 0.6, 0.6}},
104 {{0.15, 0.77, 0.54}, {0.5, 0.5, 0.5}},
105 {{0.9, 0.45, 0.0}, {0.5, 0.5, 0.5}},
108 int board[MAXBOARD][MAXBOARD];
109 int steps = 0, colorset = 0, BOARDSIZE = 8; /* 8 cuz its classic */
113 queens_handle_event (ModeInfo *mi, XEvent *event)
115 Queenscreen *c = &qs[MI_SCREEN(mi)];
117 if (event->xany.type == ButtonPress &&
118 event->xbutton.button == Button1)
120 c->button_down_p = True;
121 gltrackball_start (c->trackball,
122 event->xbutton.x, event->xbutton.y,
123 MI_WIDTH (mi), MI_HEIGHT (mi));
126 else if (event->xany.type == ButtonRelease &&
127 event->xbutton.button == Button1)
129 c->button_down_p = False;
132 else if (event->xany.type == ButtonPress &&
133 (event->xbutton.button == Button4 ||
134 event->xbutton.button == Button5))
136 gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
137 !event->xbutton.state);
140 else if (event->xany.type == MotionNotify &&
143 gltrackball_track (c->trackball,
144 event->xmotion.x, event->xmotion.y,
145 MI_WIDTH (mi), MI_HEIGHT (mi));
154 /* returns true if placing a queen on column c causes a conflict */
155 int conflictsCols(int c) {
158 for(i = 0; i < BOARDSIZE; ++i)
165 /* returns true if placing a queen on (r,c) causes a diagonal conflict */
166 int conflictsDiag(int r, int c) {
170 int n = r < c ? r : c;
171 for(i = 0; i < BOARDSIZE-abs(r-c); ++i)
172 if(board[r-n+i][c-n+i])
176 n = r < BOARDSIZE - (c+1) ? r : BOARDSIZE - (c+1);
177 for(i = 0; i < BOARDSIZE-abs(BOARDSIZE - (1+r+c)); ++i)
178 if(board[r-n+i][c+n-i])
184 /* returns true if placing a queen at (r,c) causes a conflict */
185 int conflicts(int r, int c) {
186 return !conflictsCols(c) ? conflictsDiag(r, c) : 1;
193 for(i = 0; i < MAXBOARD; ++i)
194 for(j = 0; j < MAXBOARD; ++j)
198 /* recursively determine solution */
199 int findSolution(int row, int col) {
203 while(col < BOARDSIZE) {
204 if(!conflicts(row, col)) {
207 if(findSolution(row+1, 0))
219 /** driver for finding solution */
220 void go(void) { while(!findSolution(0, random()%BOARDSIZE)); }
222 /* lighting variables */
223 GLfloat front_shininess[] = {60.0};
224 GLfloat front_specular[] = {0.4, 0.4, 0.4, 1.0};
225 GLfloat ambient[] = {0.3, 0.3, 0.3, 1.0};
226 GLfloat diffuse[] = {0.8, 0.8, 0.8, 1.0};
227 GLfloat position[] = { 0.0, 5.0, 5.0, 1.0 };
228 GLfloat lmodel_ambient[] = {0.6, 0.6, 0.6, 1.0};
229 GLfloat lmodel_twoside[] = {GL_TRUE};
231 /* configure lighting */
232 void setup_lights(void) {
234 /* setup twoside lighting */
235 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
236 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
237 glLightfv(GL_LIGHT0, GL_POSITION, position);
238 glEnable(GL_LIGHTING);
241 /* setup material properties */
242 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
243 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
245 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
248 #define checkImageWidth 8
249 #define checkImageHeight 8
250 GLubyte checkImage[checkImageWidth][checkImageHeight][3];
252 /* return alpha value for fading */
253 GLfloat findAlpha(void) {
254 return steps < 128 ? steps/128.0 : steps < 1024-128 ?1.0:(1024-steps)/128.0;
258 void drawPieces(void) {
261 for(i = 0; i < BOARDSIZE; ++i) {
262 for(j = 0; j < BOARDSIZE; ++j) {
264 glColor3fv(colors[colorset][i%2]);
268 glTranslatef(1.0, 0.0, 0.0);
271 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
275 /** reflectionboard */
276 void draw_reflections(void) {
279 glEnable(GL_STENCIL_TEST);
280 glStencilFunc(GL_ALWAYS, 1, 1);
281 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
282 glColorMask(0,0,0,0);
283 glDisable(GL_CULL_FACE);
285 glDisable(GL_DEPTH_TEST);
288 /* only draw white squares */
289 for(i = 0; i < BOARDSIZE; ++i) {
290 for(j = (BOARDSIZE+i) % 2; j < BOARDSIZE; j += 2) {
291 glVertex3f(i, 0.0, j + 1.0);
292 glVertex3f(i + 1.0, 0.0, j + 1.0);
293 glVertex3f(i + 1.0, 0.0, j);
294 glVertex3f(i, 0.0, j);
298 glEnable(GL_DEPTH_TEST);
300 glColorMask(1, 1, 1, 1);
301 glStencilFunc(GL_EQUAL, 1, 1);
302 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
305 glScalef(1.0, -1.0, 1.0);
306 glTranslatef(0.5, 0.001, 0.5);
307 glLightfv(GL_LIGHT0, GL_POSITION, position);
310 glDisable(GL_STENCIL_TEST);
313 glLightfv(GL_LIGHT0, GL_POSITION, position);
315 glEnable(GL_CULL_FACE);
317 glColorMask(1,1,1,1);
321 void drawBoard(void) {
326 for(i = 0; i < BOARDSIZE; ++i)
327 for(j = 0; j < BOARDSIZE; ++j) {
328 int par = (i-j+BOARDSIZE)%2;
329 glColor4f(colors[colorset][par][0],
330 colors[colorset][par][1],
331 colors[colorset][par][2],
333 glNormal3f(0.0, 1.0, 0.0);
334 glVertex3f(i, 0.0, j + 1.0);
335 glVertex3f(i + 1.0, 0.0, j + 1.0);
336 glVertex3f(i + 1.0, 0.0, j);
337 glVertex3f(i, 0.0, j);
343 void display(Queenscreen *c) {
346 glMatrixMode(GL_MODELVIEW);
349 /* setup light attenuation */
350 glEnable(GL_COLOR_MATERIAL);
351 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.8/(0.01+findAlpha()));
352 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.06);
354 /** setup perspective */
355 glTranslatef(0.0, 0.0, -1.5*BOARDSIZE);
356 glRotatef(30.0, 1.0, 0.0, 0.0);
357 gltrackball_rotate (c->trackball);
358 glRotatef(theta*100, 0.0, 1.0, 0.0);
359 glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
361 /* find light positions */
362 position[0] = BOARDSIZE/2.0 + BOARDSIZE/1.4*-sin(theta*100*M_PI/180.0);
363 position[2] = BOARDSIZE/2.0 + BOARDSIZE/1.4*cos(theta*100*M_PI/180.0);
367 glEnable(GL_LIGHTING);
368 glLightfv(GL_LIGHT0, GL_POSITION, position);
372 /* draw reflections */
381 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.1);
383 glTranslatef(0.5, 0.0, 0.5);
387 if(!c->button_down_p)
390 /* zero out board, find new solution of size MINBOARD <= i <= MAXBOARD */
391 if(++steps == 1024) {
394 BOARDSIZE = MINBOARD + (random() % (MAXBOARD - MINBOARD + 1));
395 colorset = (colorset+1)%COLORSETS;
401 GLfloat spidermodel[][3] =
420 #define EPSILON 0.001
422 /** draws cylindermodel */
423 void draw_model(int chunks, GLfloat model[][3], int r) {
425 GLUquadricObj *quadric = gluNewQuadric();
427 glRotatef(-90.0, 1.0, 0.0, 0.0);
429 for(i = 0; i < chunks; ++i) {
430 if(model[i][0] > EPSILON || model[i][1] > EPSILON)
431 gluCylinder(quadric, model[i][0], model[i][1], model[i][2], r, 1);
432 glTranslatef(0.0, 0.0, model[i][2]);
438 void reshape_queens(ModeInfo *mi, int width, int height) {
439 GLfloat h = (GLfloat) height / (GLfloat) width;
440 glViewport(0,0, width, height);
441 glMatrixMode(GL_PROJECTION);
443 gluPerspective(45, 1/h, 2.0, 30.0);
444 glMatrixMode(GL_MODELVIEW);
447 void init_queens(ModeInfo *mi) {
448 int screen = MI_SCREEN(mi);
450 wire = MI_IS_WIREFRAME(mi);
453 !(qs = (Queenscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Queenscreen))))
457 c->window = MI_WINDOW(mi);
458 c->trackball = gltrackball_init ();
460 if((c->glx_context = init_GL(mi)))
461 reshape_queens(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
465 glClearColor(0.0, 0.0, 0.0, 0.0);
466 glNewList(QUEEN, GL_COMPILE);
467 draw_model(schunks, spidermodel, 24);
471 glShadeModel(GL_FLAT);
473 clearbits = GL_COLOR_BUFFER_BIT;
475 glColorMaterial(GL_FRONT, GL_DIFFUSE);
476 glEnable(GL_COLOR_MATERIAL);
480 glEnable(GL_DEPTH_TEST);
481 clearbits |= GL_DEPTH_BUFFER_BIT;
482 clearbits |= GL_STENCIL_BUFFER_BIT;
483 glEnable(GL_CULL_FACE);
487 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
489 /* find a solution */
493 void draw_queens(ModeInfo *mi) {
494 Queenscreen *c = &qs[MI_SCREEN(mi)];
495 Window w = MI_WINDOW(mi);
496 Display *disp = MI_DISPLAY(mi);
501 glXMakeCurrent(disp, w, *(c->glx_context));
505 if(mi->fps_p) do_fps(mi);
507 glXSwapBuffers(disp, w);
510 void release_queens(ModeInfo *mi) {