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 (tennessb@unbc.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, (caddr_t) "false" },
51 {"-rotate", ".queens.rotate", XrmoptionNoArg, (caddr_t) "true" },
56 static argtype vars[] = {
57 {(caddr_t *) &rotate, "rotate", "Rotate", "True", t_Bool},
60 ModeSpecOpt queens_opts = {countof(opts), opts, countof(vars), vars, NULL};
63 ModStruct queens_description =
64 {"queens", "init_queens", "draw_queens", "release_queens",
65 "draw_queens", "init_queens", NULL, &queens_opts,
66 1000, 1, 2, 1, 4, 1.0, "",
72 GLXContext *glx_context;
74 trackball_state *trackball;
78 static Queenscreen *qs = NULL;
86 #define M_PI 3.14159265
94 /* definition of white/black colors */
95 GLfloat colors[2][3] = { {0.5, 0.7, 0.9},
98 int board[MAXBOARD][MAXBOARD];
99 int work = 0, vb = 0, steps = 0, BOARDSIZE = 8; /* 8 cuz its classic */
102 queens_handle_event (ModeInfo *mi, XEvent *event)
104 Queenscreen *c = &qs[MI_SCREEN(mi)];
106 if (event->xany.type == ButtonPress &&
107 event->xbutton.button & Button1)
109 c->button_down_p = True;
110 gltrackball_start (c->trackball,
111 event->xbutton.x, event->xbutton.y,
112 MI_WIDTH (mi), MI_HEIGHT (mi));
115 else if (event->xany.type == ButtonRelease &&
116 event->xbutton.button & Button1)
118 c->button_down_p = False;
121 else if (event->xany.type == MotionNotify &&
124 gltrackball_track (c->trackball,
125 event->xmotion.x, event->xmotion.y,
126 MI_WIDTH (mi), MI_HEIGHT (mi));
135 /* returns true if placing a queen on column c causes a conflict */
136 int conflictsCols(int c) {
139 for(i = 0; i < BOARDSIZE; ++i)
146 /* returns true if placing a queen on (r,c) causes a diagonal conflict */
147 int conflictsDiag(int r, int c) {
151 int n = r < c ? r : c;
152 for(i = 0; i < BOARDSIZE-abs(r-c); ++i)
153 if(board[r-n+i][c-n+i])
157 n = r < BOARDSIZE - (c+1) ? r : BOARDSIZE - (c+1);
158 for(i = 0; i < BOARDSIZE-abs(BOARDSIZE - (1+r+c)); ++i)
159 if(board[r-n+i][c+n-i])
165 /* returns true if placing a queen at (r,c) causes a conflict */
166 int conflicts(int r, int c) {
167 return !conflictsCols(c) ? conflictsDiag(r, c) : 1;
174 for(i = 0; i < MAXBOARD; ++i)
175 for(j = 0; j < MAXBOARD; ++j)
179 /* recursively determine solution */
180 int findSolution(int row) {
186 while(col < BOARDSIZE) {
187 if(!conflicts(row, col)) {
188 board[row][col] = QUEEN;
190 if(findSolution(row+1))
193 board[row][col] = NONE;
202 /* driver for finding solution */
203 void go(void) { findSolution(0); }
205 /* configure lighting */
206 void setup_lights(void) {
207 GLfloat position[] = { 4.0, 8.0, 4.0, 1.0 };
209 glEnable(GL_LIGHTING);
210 glLightfv(GL_LIGHT0, GL_POSITION, position);
214 /* return alpha value for fading */
215 GLfloat findAlpha(void) {
216 return steps < 128 ? steps/128.0 : steps < 512-128 ? 1.0 : (512-steps)/128.0;
220 void drawPieces(void) {
223 for(i = 0; i < BOARDSIZE; ++i) {
224 for(j = 0; j < BOARDSIZE; ++j) {
226 glColor4f(colors[i%2][0], colors[i%2][1], colors[i%2][2], findAlpha());
230 glTranslatef(1.0, 0.0, 0.0);
233 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
238 void drawBoard(int wire) {
241 if (!wire) glBegin(GL_QUADS);
243 for(i = 0; i < BOARDSIZE; ++i)
244 for(j = 0; j < BOARDSIZE; ++j) {
245 int par = (i-j+BOARDSIZE)%2;
246 glColor4f(colors[par][0], colors[par][1], colors[par][2], findAlpha());
247 glNormal3f(0.0, 1.0, 0.0);
248 if (wire) glBegin(GL_LINE_LOOP);
249 glVertex3f(j - 0.5, -0.01, i - 0.5);
250 glVertex3f(j + 0.5, -0.01, i - 0.5);
251 glVertex3f(j + 0.5, -0.01, i + 0.5);
252 glVertex3f(j - 0.5, -0.01, i + 0.5);
261 void display(Queenscreen *c, int wire) {
262 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
264 glMatrixMode(GL_MODELVIEW);
266 gluLookAt(0.0, 1.0+(0.8*fabs(sin(theta)))*10.0, -1.2*BOARDSIZE,
271 gltrackball_rotate (c->trackball); /* Apply mouse-based camera position */
274 glRotatef(theta*100, 0.0, 1.0, 0.0);
275 glTranslatef(-0.5 * (BOARDSIZE-1), 0.0, -0.5 * (BOARDSIZE-1));
278 glEnable(GL_LIGHTING);
279 glEnable(GL_COLOR_MATERIAL);
284 glTranslatef(0.0, 0.01, 0.0);
287 glDisable(GL_COLOR_MATERIAL);
289 glDisable(GL_LIGHTING);
293 /* zero out board, find new solution of size MINBOARD <= i <= MAXBOARD */
297 BOARDSIZE = MINBOARD + (random() % (MAXBOARD - MINBOARD + 1));
302 #define piece_size 0.1
303 #define EPSILON 0.001
305 /* Make a revolved piece */
306 void revolve_line(double *trace_r, double *trace_h, double max_iheight,
308 double theta, norm_theta, sin_theta, cos_theta;
309 double norm_ptheta = 0.0, sin_ptheta = 0.0, cos_ptheta = 1.0;
310 double radius, pradius;
311 double max_height = max_iheight, height, pheight;
314 double dtheta = (2.0*M_PI) / rot;
316 /* Get the number of points */
318 fabs(trace_r[npoints]) > EPSILON || fabs(trace_h[npoints]) > EPSILON;
321 /* If less than two points, can not revolve */
325 /* If the max_height hasn't been defined, find it */
326 if(max_height < EPSILON)
327 for(p = 0; p < npoints; ++p)
328 if(max_height < trace_h[p])
329 max_height = trace_h[p];
331 /* Draw the revolution */
332 for(theta = dtheta; rot > 0; --rot) {
333 sin_theta = sin(theta);
334 cos_theta = cos(theta);
335 norm_theta = theta / (2.0 * M_PI);
336 pradius = trace_r[0] * piece_size;
337 pheight = trace_h[0] * piece_size;
339 for(p = 0; p < npoints; ++p) {
340 radius = trace_r[p] * piece_size;
341 height = trace_h[p] * piece_size;
343 /* Get the normalized lengths of the normal vector */
344 dx = radius - pradius;
345 dy = height - pheight;
346 len = sqrt(dx*dx + dy*dy);
350 /* If only triangles required */
351 if (fabs(radius) < EPSILON) {
352 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
354 glNormal3f(dy * sin_ptheta, -dx, dy * cos_ptheta);
355 glTexCoord2f(norm_ptheta, pheight / max_height);
356 glVertex3f(pradius * sin_ptheta, pheight, pradius * cos_ptheta);
358 glNormal3f(dy * sin_theta, -dx, dy * cos_theta);
359 glTexCoord2f(norm_theta, pheight / max_height);
360 glVertex3f(pradius * sin_theta, pheight, pradius * cos_theta);
362 glTexCoord2f(0.5 * (norm_theta + norm_ptheta),
363 height / max_height);
364 glVertex3f(0.0, height, 0.0);
370 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
372 glNormal3f(dy * sin_ptheta, -dx, dy * cos_ptheta);
373 glTexCoord2f(norm_ptheta, pheight / max_height);
374 glVertex3f(pradius * sin_ptheta, pheight, pradius * cos_ptheta);
376 glNormal3f(dy * sin_theta, -dx, dy * cos_theta);
377 glTexCoord2f(norm_theta, pheight / max_height);
378 glVertex3f(pradius * sin_theta, pheight, pradius * cos_theta);
380 glTexCoord2f(norm_theta, height / max_height);
381 glVertex3f(radius * sin_theta, height, radius * cos_theta);
383 glNormal3f(dy * sin_ptheta, -dx, dy * cos_ptheta);
384 glTexCoord2f(norm_ptheta, height / max_height);
385 glVertex3f(radius * sin_ptheta, height, radius * cos_ptheta);
394 sin_ptheta = sin_theta;
395 cos_ptheta = cos_theta;
396 norm_ptheta = norm_theta;
401 void draw_queen(int wire) {
403 { 4.8, 4.8, 3.4, 3.4, 1.8, 1.4, 2.9, 1.8, 1.8, 2.0,
404 2.7, 2.4, 1.7, 0.95, 0.7, 0.0, 0.0 }; /*, 0.9, 0.7, 0.0, 0.0};*/
406 { 0.0, 2.2, 4.0, 5.0, 8.0, 11.8, 11.8, 13.6, 15.2, 17.8,
407 19.2, 20.0, 20.0, 20.8, 20.8, 22.0, 0.0 };/*,21.4, 22.0, 22.0, 0.0 };*/
409 revolve_line(trace_r, trace_h, 0.0, 8, wire);
412 void reshape_queens(ModeInfo *mi, int width, int height) {
413 GLfloat h = (GLfloat) height / (GLfloat) width;
414 glViewport(0,0, width, height);
415 glMatrixMode(GL_PROJECTION);
417 gluPerspective(45, 1/h, 2.0, 30.0);
418 glMatrixMode(GL_MODELVIEW);
421 void init_queens(ModeInfo *mi) {
422 GLfloat mat_shininess[] = { 90.0 };
423 GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
425 int screen = MI_SCREEN(mi);
426 int wire = MI_IS_WIREFRAME(mi);
430 !(qs = (Queenscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Queenscreen))))
434 c->window = MI_WINDOW(mi);
435 c->trackball = gltrackball_init ();
437 if((c->glx_context = init_GL(mi)))
438 reshape_queens(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
442 glClearColor(0.0, 0.0, 0.0, 0.0);
445 glNewList(1, GL_COMPILE);
450 glColorMaterial(GL_FRONT, GL_DIFFUSE);
452 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
453 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
455 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
456 glShadeModel(GL_SMOOTH);
457 glEnable(GL_DEPTH_TEST);
460 /* find a solution */
464 void draw_queens(ModeInfo *mi) {
465 Queenscreen *c = &qs[MI_SCREEN(mi)];
466 Window w = MI_WINDOW(mi);
467 Display *disp = MI_DISPLAY(mi);
472 glXMakeCurrent(disp, w, *(c->glx_context));
474 display(c, MI_IS_WIREFRAME(mi));
476 if(mi->fps_p) do_fps(mi);
478 glXSwapBuffers(disp, w);
481 void release_queens(ModeInfo *mi) {