⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

OpenGL

[[File:knight-C.png|thumb|right|100px]] {{libheader|GLUT}} OpenGL program with glut. Compile with gcc -std=c99 -lglut -lGL -lGLU, run with a.out -s [size]. Program will print a help message at start.

#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>

struct timeval last_update, last_move;
/* board width */
int bw = 7;
/* power of 2 */
int twid = 1;
int W = 240, H = 240, gwin;

void *board;
typedef struct { int x, y; } cell_t;
cell_t *moves;
cell_t ofs[8] = {{2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}, {1, 2}};
cell_t start;
int n_moves, need_move = 1, stopped = 0, failed = 0, paused = 0, skip_draw = 0;
int delay = 1024 * 128;

GLubyte *tex;
GLuint texture;

int good(int x)
{
	return x >= 0 && x < bw;
}

void init_board()
{
	int (*b)[bw] = board;
	for (int i = 0; i < bw; i++)
		memset(b[i], 0, sizeof(int) * bw);

	n_moves = b[start.y][start.x] = 1;
	moves[0] = start;
	need_move = 1;
	stopped = 0;
}

int n_vacant(int x, int y)
{
	int (*b)[bw] = board;
	int cnt = 0;

	for (int i = 0; i < 8; i++) {
		int nx = x + ofs[i].x;
		if (!good(nx)) continue;

		int ny = y + ofs[i].y;
		if (!good(ny)) continue;

		if (!b[ny][nx]) cnt++;
	}

	return cnt;
}

int restart()
{
	if (++start.x < bw) {
		init_board();
		return 1;
	}
	start.x = 0;
	if (++start.y < bw) {
		init_board();
		return 1;
	}
	start.y = 0;
	printf("Already tried all starting positions\n");
	need_move = 0;
	failed = 1;
	return 0;
}

int next_move()
{
	if (!need_move || stopped || paused)
		return 0;

	int (*b)[bw] = board;
	cell_t cur = moves[n_moves - 1];
	cell_t dest;
	int least = 9;

	for (int i = 0; i < 8; i++) {
		int x = cur.x + ofs[i].x;
		if (!good(x)) continue;

		int y = cur.y + ofs[i].y;
		if (!good(y)) continue;

		if (b[y][x]) continue;

		int n = n_vacant(x, y);
		if (n < least) {
			least = n;
			dest.x = x;
			dest.y = y;
		}
	}

	if (least == 9) {
		stopped = 1;
		need_move = 0;
		if (n_moves == bw * bw)
			printf("Tour complete.\n");
		else
			printf("Stuck at %d moves\n", n_moves);
		printf("Press SPACE to continue\n");
		return 0;
	}

	moves[n_moves++] = dest;
	b[dest.y][dest.x] = 1;

	need_move = 1;
	return 1;
}

void resize(int w, int h)
{
	int dx = 0, dy = 0;
	W = w; H = h;

	if (w > h) dx = w - h;
	else	   dy = h - w;

	glViewport(dx / 2, dy / 2, W - dx, H - dy);
	glOrtho(0, bw, 0, bw, -1, 1);
}

void render()
{
	double tw = (double) bw / twid;

	struct timeval tv;
	gettimeofday(&tv, 0);
	long usec = (tv.tv_sec - last_move.tv_sec) * 1000000
			+ tv.tv_usec - last_move.tv_usec;
	if (usec > delay || skip_draw) {
		next_move();
		last_move = tv;
	}

	if (skip_draw && !stopped) return;

	usec = (tv.tv_sec - last_update.tv_sec) * 1000000
			+ tv.tv_usec - last_update.tv_usec;
	if (usec < 25000) return;
	last_update = tv;

	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();
	glBindTexture(GL_TEXTURE_2D, texture);

	glColor3f(1, 1, 1);
	glBegin(GL_QUADS);
	glTexCoord2f( 0,  0); glVertex2i(0, 0);
	glTexCoord2f( 0, tw); glVertex2i(0, bw);
	glTexCoord2f(tw, tw); glVertex2i(bw, bw);
	glTexCoord2f(tw,  0); glVertex2i(bw, 0);
	glEnd();

	glBegin(GL_QUADS);
	glColor3f(0, .5, 1);
	int x = moves[0].x, y = moves[0].y;

	glVertex2i(x + 0, y + 0);
	glVertex2i(x + 0, y + 1);
	glVertex2i(x + 1, y + 1);
	glVertex2i(x + 1, y + 0);

	glColor4f(.5, .7, .5, .7);
	for (int i = (n_moves == bw * bw) ? n_moves - 1 : 1; i < n_moves; i++) {
		if (i == n_moves - 1)
			glColor3f(1, 0, 0);
		x = moves[i].x, y = moves[i].y;
		glVertex2f(x + 0, y + 0);
		glVertex2f(x + 0, y + 1);
		glVertex2f(x + 1, y + 1);
		glVertex2f(x + 1, y + 0);
	}
	glEnd();

	glBegin(GL_LINE_STRIP);
	if (n_moves == bw * bw)
		glColor3f(0, .4, .4);
	else
		glColor3f(0, 0, 0);

	for (int i = 0; i < n_moves; i++)
		glVertex2f(moves[i].x + .5, moves[i].y + .5);
	glEnd();

	glutSwapBuffers();
	need_move = 1;
}

void init_texture()
{
	int i, j;
	while (twid < bw) twid <<= 1;

	GLubyte * ptr = tex = malloc(twid * twid * 3);

	for (i = 0; i < twid; i++)
		for (j = 0; j < twid; j++, ptr += 3)
			if ((i & 1) != (j & 1))
				ptr[0] = ptr[1] = ptr[2] = 255;
			else
				ptr[0] = 120, ptr[1] = 255, ptr[2] = 200;

	glEnable(GL_TEXTURE_2D);
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, twid, twid,
		0, GL_RGB, GL_UNSIGNED_BYTE, tex);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	free(tex);
}

void set_delay(int inc)
{
	if (inc) {
		delay *= 2;
		if (!delay) delay = 1;
		if (delay >= 1 << 20) {
			delay = 1 << 20;
			paused = 1;
			printf("Paused\n");
			return;
		}
	} else
		delay /= 2;
	paused = 0;
	printf("Delay = %d usec\n", delay);
}

void keypress(unsigned char key, int x, int y)
{
	switch(key) {
	case ' ':
		if (stopped && !failed) restart();
		break;
	case 'q':
	case 27:
		glFinish();
		glutDestroyWindow(gwin);
		return;
	case ',':
	case '<':
		set_delay(1);
		return;
	case '.':
	case '>':
		set_delay(0);
		return;
	case 's':
		skip_draw = !skip_draw;
		return;
	}
}

void init_graphics(int c, char **v)
{
	glutInit(&c, v);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowSize(W, H);
	glutDisplayFunc(render);
	glutIdleFunc(render);
	glutDisplayFunc(render);

	gwin = glutCreateWindow("Board");

	glutKeyboardFunc(keypress);
	glutReshapeFunc(resize);

	glClearColor(.2, .2, .2, 1);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, bw, 0, bw, -1, 1);
	glMatrixMode(GL_MODELVIEW);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	init_texture();
}

int main(int c, char **v)
{
	if (c >= 3 && !strcmp(v[1], "-s")) {
		bw = atoi(v[2]);
		if (bw < 3) {
			printf("bad argument -s %s, size set to 3\n", v[2]);
			bw = 3;
		}
	}
	printf("Keys:\n\tQ, Esc: exit\n\t<: slow down\n\t>: speed up\n\t"
		"s: skip to finish\n<space>: try a new tour\n");

	int b[bw][bw];
	cell_t g[bw * bw];
	moves = g;
	board = b;
	start.x = start.y = 0;

	init_board();

	init_graphics(c, v);
	gettimeofday(&last_update, 0);
	last_move = last_update;

	glutMainLoop();
	return 0;
}