Código Fonte da Interface:
#ifdef _WIN32
#include <windows>
#endif
#include <GL/glut.h>
#include <cmath>
#include "jogo.hpp"
#define FI_MIN .4
float teta(5.40732), fi(.937066), raio(12.);
int xant, yant;
bool rodando(false), arrastando(false);
Jogo jogo;
int H;
double X, Y, Z;
float const LARG = 10./7.;
int ii, ji;
GLuint peca, posicao;
GLint matrizViewport[4];
GLdouble matrizModelview[16], matrizProjecao[16];
bool luz(true), procurando(false), acabou(false);
// Mostra texto na tela
void mostrar(char * c) {
glRasterPos3f(-1, -1, .3);
while (*c)
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *c++);
}
// Checa intervalo de angulos
inline void checar_angulos() {
if (fi < FI_MIN) fi = FI_MIN;
else if (fi > M_PI/2.) fi = M_PI/2.;
if (teta < 0.) teta += M_PI * 2.;
else if (teta > M_PI * 2.) teta -= M_PI * 2.;
}
void linhas(float max, float x) {
glVertex3f(x, max*LARG, .01);
glVertex3f(x, -max*LARG, .01);
glVertex3f(max*LARG, x, .01);
glVertex3f(-max*LARG, x, .01);
}
void desenhar_posicao() {
GLfloat tabu[] = {1., 1., 1., 0.};
GLfloat posi[] = {.1, .1, .1, 0.};
glPushMatrix();
glPushMatrix();
glMaterialfv(GL_FRONT, GL_DIFFUSE, posi);
glColor3f(.0, .0, .0);
glTranslatef(0., 0., -.25);
glScalef(LARG*3., LARG*7., .5);
glutSolidCube(1.);
glScalef(7./3., 3./7., 1.);
glutSolidCube(1.);
glPopMatrix();
glMaterialfv(GL_FRONT, GL_DIFFUSE, tabu);
glTranslatef(0., 0., -.75);
glScalef(2.5, 2.5, .1);
glColor3f(.5, .5, .5);
glutSolidCube(5.);
glPopMatrix();
glColor3f(0, 0, 0);
glBegin(GL_LINES);
for (float x = -3.5*LARG; x <= 3.5 * LARG; x += LARG)
linhas(1.5, x);
for (float x = -1.5*LARG; x <= 1.5 * LARG; x += LARG)
linhas(3.5, x);
glEnd();
}
void desenhar_peca() {
GLfloat cor_peca[] = {.9, .8, .7, 0.};
GLUquadric * quad = gluNewQuadric();
glMaterialfv(GL_FRONT, GL_DIFFUSE, cor_peca);
glColor3f(1., 1., 1.);
gluCylinder(quad, .3, .3, .5, 10, 10);
glTranslatef(0., 0., .5);
gluSphere(quad, .3, 12, 12);
gluDeleteQuadric(quad);
}
void desenhar() {
GLfloat luz[] = { 1.0, 1.0, 1.0, 0.0};
GLfloat pos1[] = { 0., 0., 10., 0.};
glPushMatrix();
// Limpar tela
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Posicionamento
gluLookAt(raio*cos(teta)*cos(fi), -raio*sin(teta)*cos(fi), raio*sin(fi), 0., 0., 0., -sin(fi)*cos(teta), sin(fi)*sin(teta), cos(fi));
if (acabou)
mostrar("Jogo Encerrado");
glCallList(posicao);
// Pecas
for (int i = 0; i < 7; ++i)
for (int j = 0; j < 7; ++j)
if ((i != ii || j != ji) && jogo(i, j)) {
glPushMatrix();
glTranslatef((i-3)*LARG, (j-3)*LARG, 0.);
glCallList(peca);
glPopMatrix();
}
// Peca enquanto movendo
if (arrastando) {
glPushMatrix();
glTranslatef(X, Y, 0.);
glCallList(peca);
glPopMatrix();
}
glLightfv(GL_LIGHT1, GL_DIFFUSE, luz);
glLightfv(GL_LIGHT1, GL_POSITION, pos1);
glGetIntegerv(GL_VIEWPORT, matrizViewport);
glGetDoublev(GL_MODELVIEW_MATRIX, matrizModelview);
glGetDoublev(GL_PROJECTION_MATRIX, matrizProjecao);
glPopMatrix();
glutSwapBuffers();
}
void mapear(int x, int y, double & x1, double & y1, double & z1) {
GLfloat z;
glReadPixels(x, H-y-1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
gluUnProject (x, H-y-1, z, matrizModelview, matrizProjecao, matrizViewport, &x1, &y1, &z1);
}
void movimento(int x, int y) {
if (rodando) {
fi += (y-yant)/500.;
teta += (x-xant)/500.;
xant = x;
yant = y;
checar_angulos();
desenhar();
}
if (arrastando) {
mapear(x, y, X, Y, Z);
desenhar();
}
}
void mouse(int button, int state, int x, int y) {
switch (button) {
case GLUT_RIGHT_BUTTON:
if (rodando = state == GLUT_DOWN) { // botao direito foi pressionado
xant = x;
yant = y;
}
break;
case GLUT_LEFT_BUTTON:
mapear(x, y, X, Y, Z);
int i = int(X/LARG + 3.5), j = int(Y/LARG + 3.5);
if (state == GLUT_DOWN) { // Botao esquerdo foi pressionado
if (jogo.pode_origem(i,j)) {
ii = i;
ji = j;
arrastando = true;
desenhar();
}
} else if (arrastando) { // Botao esquerdo foi solto
jogo.mover(ii, ji, i, j);
arrastando = false;
ii = ji = -1;
acabou = !jogo.pode_jogar();
desenhar();
}
}
}
void teclado(unsigned char tecla, int x, int y) {
bool redesenhar(true);
switch (tecla) {
case 'n': jogo.reiniciar(); acabou = false; break;
case 'l': ((luz = !luz) ? glEnable : glDisable)(GL_LIGHTING); break;
case '+': raio -= .5; break;
case '-': raio += .5; break;
case 'q': case 27: exit(0);
default: redesenhar = false;
}
if (raio < 2.) raio = 2.;
if (redesenhar) desenhar();
}
void especial(int key, int x, int y) {
bool redesenhar(true);
switch (key) {
case GLUT_KEY_LEFT: teta += .09; break;
case GLUT_KEY_RIGHT: teta -= .09; break;
case GLUT_KEY_UP: fi += .09; break;
case GLUT_KEY_DOWN: fi -= .09; break;
default: redesenhar = false;
}
if (redesenhar) {
checar_angulos();
desenhar();
}
}
GLuint criar_lista(void (*func)()) {
GLuint res = glGenLists(1);
glNewList(res, GL_COMPILE);
func();
glEndList();
return res;
}
void iniciar() {
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);
glClearColor(0., 0., 0., 0.);
glEnable(GL_DEPTH_TEST);
// Cria listas
peca = criar_lista(desenhar_peca);
posicao = criar_lista(desenhar_posicao);
}
void reshape(int w, int h) {
H = h;
glViewport (0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, GLfloat(w)/h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char ** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Jogo Resta 1");
iniciar();
glutKeyboardFunc(teclado);
glutReshapeFunc(reshape);
glutDisplayFunc(desenhar);
glutSpecialFunc(especial);
glutMouseFunc(mouse);
glutMotionFunc(movimento);
//glutFullScreen();
desenhar();
glutMainLoop();
return 0;
}
Código Fonte da Lógica do Jogo: (Jogo.cpp)
#include "jogo.hpp"
#include <cstdlib>
// Tabuleiro inicial, "#" indica posicao invalida, "P" indica Peca, "B" posicao em Branco (livre)
char inicial[7][8] = {
"##PPP##",
"##PPP##",
"PPPPPPP",
"PPPBPPP",
"PPPPPPP",
"##PPP##",
"##PPP##"
};
// Construtor da classe jogo, reinicia o mesmo
Jogo::Jogo() { reiniciar(); }
// Reinicio copia a configuracao inicial (acima) para o tabuleiro do jogo
void Jogo::reiniciar() { memcpy(tab, inicial, sizeof(tab)); }
// Verifica se a jogada de (dx,dy) para (px,py) eh valida. Eh assumido que a posicao (dx,dy) jah tenha sido verificada com "pode_origem".
bool Jogo::pode_mover(int dx, int dy, int px, int py) const {
return (valida(px, py) && tab[px][py] == 'B' &&
((px == dx && abs(dy-py) == 2) || (py == dy && abs(dx-px) == 2)) &&
tab[(px-dx)/2 + dx][(py-dy)/2 + dy] == 'P');
}
// Verifica o movimento de (dx,dy) para (px,py), e o executa caso seja possivel, atualizando o tabuleiro.
bool Jogo::mover(int dx, int dy, int px, int py) {
if (pode_mover(dx, dy, px, py)) {
tab[px][py] = 'P';
tab[dx][dy] = tab[(px-dx)/2 + dx][(py-dy)/2 + dy] = 'B';
return true;
}
return false;
}
// Verifica se o jogador ainda tem algum movimento possivel, no pior caso (quando o jogador nao tem mais movimentos) testa todas as possibilidades de jogada.
bool Jogo::pode_jogar() const {
static int const T[4][2] = {{-2,0},{2,0},{0,-2},{0,2}};
for (unsigned i(0); i < 7; ++i)
for (unsigned j(0); j < 7; ++j)
if (pode_origem(i, j))
for (unsigned t(0); t < sizeof(T)/sizeof(*T); ++t)
if (pode_mover(i, j, i+T[t][0], j+T[t][1]))
return true;
return false;
}
Código Fonte da Lógica do Jogo: (Jogo.hpp)
#ifndef _JOGO_H_
#define _JOGO_H_
#include <iostream>
using namespace std;
class Jogo {
public:
Jogo(); // construtor
void reiniciar(); // reiniciar o jogo
bool pode_jogar() const; // verifica se ainda ha jogadas possiveis
// verifica se pode mover de (dx, dy) para (px, py)
bool pode_mover(int dx, int dy, int px, int py) const;
// verifica se a posicao (i,j) eh uma origem de movimento valida
bool pode_origem(int i, int j) const { return valida(i,j) && tab[i][j]=='P'; }
// executa, se for possivel, o movimento de (dx,dy) para (px,py)
bool mover(int dx, int dy, int px, int py);
// verifica se a posicao (i,j) tem uma peca
bool operator()(int i, int j) const { return tab[i][j] == 'P'; }
// verifica se a posicao (i,j) eh uma posicao valida
bool valida(unsigned i, unsigned j) const { return i<7 && j<7 && tab[i][j]!='#'; }
private:
char tab[7][8]; // tabuleiro do objeto instanciado
};
#endif