/* othello.c
By Denis Moskowitz
http://www.suberic.net/~dmm/othello/othello.html
All rights reversed (K) reuse as you will
Comments and suggestions welcome: dmm@cs.hmc.edu
*/

#include <GL/glut.h>
#include <math.h>
#include <time.h>
#include <stdio.h>

void myinit(void);
void display(void);
void myReshape(GLsizei w, GLsizei h);
void idle (void);

double eyex, eyey, eyez;
double eyer, eyelon, eyelat;

#define SIZE 6
#define PI 3.1415927
#define DEGREES PI/180.0
#define SEPARATION 4.0f
#define STONESIZE 1.0f
#define BOARDSIZE (SIZE/2 - 0.5f) * SEPARATION
#define BOARDSEP (SIZE + 1) * SEPARATION
#define OUTER BOARDSIZE * 10.0f
#define MAXFLIPS SIZE * 13


GLfloat PlayerOne[] = {1.0f, 0.25f, 0.25f, 1.0f};
//GLfloat PlayerOne[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat PlayerTwo[] = {0.25f, 0.25f, 1.0f, 1.0f};
//GLfloat PlayerTwo[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat Felt[] = {0.0f, 0.5f, 0.0f, 1.0f};
GLfloat Nothing[] = {0.0f, 0.0f, 0.0f, 0.0f};
//GLfloat Cursor[] = {1.0f, 1.0f, 0.0f};
GLfloat Option[] = {1.0f, 1.0f, 1.0f, 0.0f};
GLfloat light0[] = {-0.5f,-0.25f,1.0f,0.0f};
GLfloat light0a[] = {0.5f,0.5f,0.5f,1.0f};
int Board[SIZE][SIZE][SIZE];

typedef struct 
{
	int x, y, z;
} coord;
int showgrid;
int first, second;
coord cursor;
int turn;
int player[3];
int score[3];
coord curlist[MAXFLIPS];	//more than the max number of turnable stones
int curlistsize;
coord moves[SIZE*SIZE*SIZE];
int movessize;

int AIstage;
int AIlistsize;
coord AIlist[MAXFLIPS];
coord AItarget;

int * boardpos (coord i) {
	return &Board[i.x][i.y][i.z];
}

void fillscore()
{
	int i, j, k;
	score[0] = score[1] = score[2] = 0;
	for (i = 0; i < SIZE; i++) {
	  for (j = 0; j < SIZE; j++) {
		  for (k = 0; k < SIZE; k++) {
			  score[Board[i][j][k]]++;
		  }
	  }
	}
}

int inbounds(int x, int y, int z) {
	if (x >= SIZE || y >= SIZE || z >= SIZE || x < 0 || y < 0 || z < 0) {
		return 0;
	} else {
		return 1;
	}
}

int cinbounds(coord place) { return inbounds(place.x, place.y, place.z); }

/*
void stonekill (stonelist * target) {
	stonelist * i, * j;
	i= target;
	while(i) {
		j = i->next;
		free(i);
		i = j;
	}
}
*/

int flips(coord move, int player, coord * list) {
	int flipsize;
	int dx, dy, dz;
	if (!cinbounds(move)) return 0;
	if (Board[move.x][move.y][move.z]) return 0;
	flipsize = 0;
	for (dx = -1; dx <= 1; dx++) {
		for (dy = -1; dy <= 1; dy++) {
			for (dz = -1; dz <= 1; dz++) {
				if (dx || dy || dz) {	//ignore null direction
					int i, j, k, ok;
					int cellsize = flipsize;
					i = move.x; j = move.y; k = move.z;
					ok = 0;
					while (1) {
						i += dx; j += dy; k += dz;	//step in direction
						if (!inbounds(i, j, k)) break;	//stop when edge reached
						if (Board[i][j][k] == 0) break;	//stop when blank reached
						if (Board[i][j][k] == player) {	//stop and mark when same color reached
							ok = 1;
							break;
						}	
						//other player: add to cell list
						list[cellsize].x = i;
						list[cellsize].y = j;
						list[cellsize].z = k;
						cellsize++;
					}
					if (ok) {	//commit the found stones
						flipsize = cellsize;
					}
				}
			}
		}
	}
	return flipsize;
}

void AIthink() {
	int i, l, n;
	int bufsize;
	coord buf[MAXFLIPS];
	AItarget.x = AItarget.y = AItarget.z = -1;
	AIlistsize = -1;
	n = 0;
	for (i = 0; i < movessize; i++) {
		coord temp;
		temp = moves[i];
		bufsize = flips(temp, turn, buf);
		if (bufsize && bufsize > AIlistsize) {
			for (l = 0; l < bufsize; l++) {
				AIlist[l] = buf[l];
			}
			AIlistsize = bufsize;
			AItarget = temp;
			n = 1;
		} else if (bufsize == AIlistsize) {
			n++;
			if (rand() * n / RAND_MAX == 1) {
				for (l = 0; l < bufsize; l++) {
					AIlist[l] = buf[l];
				}
				AIlistsize = bufsize;
				AItarget = temp;
			}
		}
	}
}

void AIthink2() {
	int i, l, n;
	int bufsize, moveval;
	coord buf[MAXFLIPS];
	AItarget.x = AItarget.y = AItarget.z = -1;
	AIlistsize = -1;
	n = 0;
	moveval = 0;
	for (i = 0; i < movessize; i++) {
		coord temp;
		int tempval;
		temp = moves[i];
		bufsize = flips(temp, turn, buf);
		tempval = ((temp.x % (SIZE-1) == 0) + (temp.y % (SIZE-1) == 0) + (temp.z % (SIZE-1) == 0));
		if (bufsize && ((tempval > moveval) || (tempval == moveval && bufsize > AIlistsize))) {
			for (l = 0; l < bufsize; l++) {
				AIlist[l] = buf[l];
			}
			AIlistsize = bufsize;
			moveval = tempval;
			AItarget = temp;
			n = 1;
		} else if ((tempval == moveval) && (bufsize == AIlistsize)) {
			n++;
			if (rand() * n / RAND_MAX == 1) {
				for (l = 0; l < bufsize; l++) {
					AIlist[l] = buf[l];
				}
				AIlistsize = bufsize;
				moveval = tempval;
				AItarget = temp;
			}
		}
	}
}

void  keyboard(unsigned char key, int x, int y);

int pass;

void newturn()
{
	coord buf[MAXFLIPS];
	coord i;
	movessize = 0;
	for (i.x = 0; i.x < SIZE; i.x++) {
		for (i.y = 0; i.y < SIZE; i.y++) {
			for (i.z = 0; i.z < SIZE; i.z++) {
				if (flips(i, turn, buf)) {
					moves[movessize] = i;
					movessize++;
				}
			}
		}
	}
	if (movessize == 0) {
		movessize = 0;
	}
	fillscore();
}

void  keyboard(unsigned char key, int x, int y)
{
  if (key < 'a') {
	  switch (key) {
	  case 'J': cursor.y--; break;
	  case 'K': cursor.y++; break;
	  case 'H': cursor.x--; break;
	  case 'L': cursor.x++; break;
	  case 'I': cursor.z++; break;
	  case 'M': cursor.z--; break;
	  case 'P':
		  {
			  if (movessize == 0) {
				  turn = 3 - turn;
				  if (pass == 1) {
					  turn = 0;
				  }
				  pass = 1;
				  newturn();
			  }
			  break;
		  }
	  case ' ': 
		  {
			  if (curlistsize) {
				  int i;
				  for (i = 0; i < curlistsize; i++) { *boardpos(curlist[i]) = turn; }
				  Board[cursor.x][cursor.y][cursor.z] = turn; turn = 3 - turn;
				  newturn();
				  pass = 0;
			  }
			  break;
		  }
	  }
	  cursor.x += SIZE; cursor.y += SIZE; cursor.z += SIZE;
	  cursor.x %= SIZE; cursor.y %= SIZE; cursor.z %= SIZE;
	  curlistsize = flips(cursor, turn, curlist);
  } else {
	  switch (key) {
	  case 'j': { if (eyer < OUTER) eyer += 1.0f;  break;}
	  case 'l': { eyelon +=5.0; break; }
	  case 'h': { eyelon -=5.0; break; }
	  case 'k': { if (eyer > 1) eyer -= 1.0f; break; }
	  case 'i': { if (eyelat + 5.0 < 90) eyelat += 5.0; break; }
	  case 'm': { if (eyelat - 5.0 > -90) eyelat -= 5.0; break; }

	  case 'g': { showgrid = !showgrid; break; }
	  case 'q': exit (0);
	  }
  }
  display();
}

void Diamond(int solid)
{
	glBegin(solid ? GL_QUADS : GL_LINE_LOOP);
	glVertex2i(0,1);
	glVertex2i(1,0);
	glVertex2i(0,-1);
	glVertex2i(-1,0);
	glEnd();
}

void display(void)
{
  int i, j, k;
  int s;
  char scorestring[2][8];
  GLfloat shiny[] = {100.0f};
  GLfloat dull[] = {1.0f};
  //compute things
  eyex = eyer*cos(eyelat*DEGREES)*cos(eyelon*DEGREES);
  eyey = eyer*cos(eyelat*DEGREES)*sin(eyelon*DEGREES);
  eyez = eyer*sin(eyelat*DEGREES);

  sprintf(scorestring[0], "%d", score[1]);
  sprintf(scorestring[1], "%d", score[2]);
// draw things
// first window
  glutSetWindow(first);
  glEnable(GL_LIGHTING);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();



  gluLookAt(eyex, eyey, eyez, 0, 0, 0, 0, 0, 1);
  glMaterialfv(GL_FRONT, GL_SHININESS, shiny);
  glLightfv(GL_LIGHT0, GL_POSITION, light0);
  glPushMatrix();
  if (showgrid) {
	  glDisable(GL_LIGHTING);
	  glColor3f(1.0f, 1.0f, 1.0f);
	  for (i = -SIZE +1; i < SIZE; i+=2) {
		  glBegin(GL_LINES);
		  for (j = -SIZE +1; j < SIZE; j+=2) {
			  glVertex3f(-BOARDSIZE, i*SEPARATION/2, j* SEPARATION/2);
			  glVertex3f(BOARDSIZE, i*SEPARATION/2, j* SEPARATION/2);
			  glVertex3f(i*SEPARATION/2, -BOARDSIZE,  j* SEPARATION/2);
			  glVertex3f(i*SEPARATION/2, BOARDSIZE,  j* SEPARATION/2);
			  glVertex3f(i*SEPARATION/2, j* SEPARATION/2, -BOARDSIZE);
			  glVertex3f(i*SEPARATION/2, j* SEPARATION/2, BOARDSIZE);
		  }
		  glEnd();
	  }
	  glEnable(GL_LIGHTING);
  }
  glTranslatef(-BOARDSIZE, -BOARDSIZE, -BOARDSIZE);
  for (i = 0; i < SIZE; i++) {
    for (j = 0; j < SIZE; j++) {
      for (k = 0; k < SIZE; k++) {
      	glPushMatrix();
		glTranslatef(
			SEPARATION * i,
			SEPARATION * j,
			SEPARATION * k
		);

		if (Board[i][j][k]) {
			glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Board[i][j][k] == 1 ? PlayerOne : PlayerTwo);
			glMaterialfv(GL_FRONT, GL_SPECULAR, Board[i][j][k] == 1 ? PlayerOne : PlayerTwo);
			//glMaterialfv(GL_FRONT, GL_SPECULAR,  PlayerOne);
			glScalef(STONESIZE, STONESIZE, STONESIZE);
			//switch (Board[i][j][k]) {
			//case 1:
				//glutSolidSphere(1.0, 20, 10); break;
				//glutSolidTeapot(1.0); break;
			//case 2:
				glutSolidOctahedron(); //break;
				//glutSolidCube(1.0f);
			//}
		}
		glPopMatrix();
      }
    }
  }
  glDisable(GL_LIGHTING);
  if (turn) {
	glPushMatrix();
	glTranslatef(SEPARATION * cursor.x, SEPARATION * cursor.y, SEPARATION * cursor.z);
	glColor3fv((turn==1) ? PlayerOne : PlayerTwo);
	glScalef(2.0f, 2.0f, 2.0f);
	//switch(turn) {
	//case 1:
		//glutWireSphere(1.0, 10, 5); break;
	//case 2:
		glutWireOctahedron(); //break;
	//}
	if (curlist) {
		//glScalef(0.5f, 0.5f, 0.5f);
		  //glutWireOctahedron();
	}
	glPopMatrix();
  }
  glPushMatrix();
//  glBegin(GL_LINES);
  for (s = 0; s < curlistsize; s++){
	  glPushMatrix();
	  glTranslatef(SEPARATION * curlist[s].x, SEPARATION * curlist[s].y, SEPARATION * curlist[s].z);
	  //glColor3fv((turn==1) ? PlayerOne : PlayerTwo);
	  glScalef(1.5f, 1.5f, 1.5f);
	  glutWireOctahedron();
	  glPopMatrix();
//	  glVertex3i(cx, cy, cz);
//	  glVertex3i(sl->x, sl->y, sl->z);
  }
  glColor3fv(Option);
  for (s = 0; s < movessize; s++){
	  glPushMatrix();
	  glTranslatef(SEPARATION * moves[s].x, SEPARATION * moves[s].y, SEPARATION * moves[s].z);
	  //glColor3fv((turn==1) ? PlayerOne : PlayerTwo);
	  glScalef(0.5f, 0.5f, 0.5f);
	  if (moves[s].x == cursor.x && moves[s].y == cursor.y && moves[s].z == cursor.z) {
		  glutSolidOctahedron();
	  } else {
		glutWireOctahedron();
	  }
	  glPopMatrix();
//	  glVertex3i(cx, cy, cz);
//	  glVertex3i(sl->x, sl->y, sl->z);
  }
  //glEnd();
  glPopMatrix();
  glEnable (GL_LIGHTING);
  glPopMatrix();
  glDisable(GL_LIGHTING);
  glEnable (GL_LIGHTING);

  glMaterialfv(GL_FRONT, GL_SHININESS, dull);
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Felt);
  glMaterialfv(GL_FRONT, GL_SPECULAR, Nothing);
  glPushMatrix();
  glScalef (SEPARATION * SIZE * 0.5f, SEPARATION * SIZE * 0.5f, SEPARATION * SIZE * 0.5f);
  glNormal3i(0,0,1);
  glBegin(GL_QUADS);
  glVertex3i(1,1,-1);
  glVertex3i(-1,1,-1);
  glVertex3i(-1,-1,-1);
  glVertex3i(1,-1,-1);
  glEnd();
  glPopMatrix();
  glutSwapBuffers();	/* doublebuffer is my friend */
  glFinish();

  
  // next window
  glutSetWindow(second);
  glClear(GL_COLOR_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glColor3fv(Felt);
  glMaterialfv(GL_FRONT, GL_SPECULAR, Nothing);
  glPushMatrix();
  glScalef (SEPARATION * SIZE, SEPARATION * SIZE, 0.0f);
  glBegin(GL_QUADS);
  glVertex2i(0,0);
  glVertex2i(1,0);
  glVertex2i(1,1);
  glVertex2i(0,1);
  glEnd();
  glPopMatrix();
  
  if (1) {
	  glPushMatrix();
	  glTranslatef(SEPARATION * 0.5f, SEPARATION * 0.5f, 0.0f);
	  glColor3f(1.0f, 1.0f, 1.0f);
	  for (i = 0; i < SIZE; i++) {
		  glBegin(GL_LINES);
		  for (j = 0; j < SIZE; j++) {
			  glVertex2f(SEPARATION * i, BOARDSEP * j);
			  glVertex2f(SEPARATION * i, BOARDSEP * j + BOARDSIZE * 2.0f);
			  glVertex2f(0.0f, SEPARATION * i + BOARDSEP * j);
			  glVertex2f(BOARDSIZE * 2.0f, SEPARATION * i + BOARDSEP * j);
		  }
		  glEnd();
	  }
	  glPopMatrix();
  }
  glPushMatrix();
  glTranslatef(SEPARATION * 0.5f, SEPARATION * 0.5f, 0.0f);
  for (i = 0; i < SIZE; i++) {
    for (j = 0; j < SIZE; j++) {
      for (k = 0; k < SIZE; k++) {
      	glPushMatrix();
		glTranslatef(
			SEPARATION * i,
			SEPARATION * j + BOARDSEP * k,
			0.0f
		);

		if (Board[i][j][k]) {
			glColor3fv(Board[i][j][k] == 1 ? PlayerOne : PlayerTwo);
			glScalef(STONESIZE, STONESIZE, STONESIZE);
			Diamond(1);
		}
		glPopMatrix();
      }
    }
  }
  glPopMatrix();
  if (turn) {
	glPushMatrix();
			glTranslatef(SEPARATION * 0.5f, SEPARATION * 0.5f, 0.0f);
			glTranslatef(
				SEPARATION * cursor.x,
				SEPARATION * cursor.y + BOARDSEP * cursor.z,
				0.0f
			);
	glColor3fv((turn==1) ? PlayerOne : PlayerTwo);
	glScalef(2.0f, 2.0f, 2.0f);
	Diamond(0);
	if (curlist) {
		  //glScalef(0.5f, 0.5f, 0.5f);
		  //glutWireOctahedron();
	}
	  glPopMatrix();
  }
  glPushMatrix();
  glTranslatef(SEPARATION * 0.5f, SEPARATION * 0.5f, 0.0f);
//  glBegin(GL_LINES);
  for (s = 0; s < curlistsize; s++){
	  glPushMatrix();
		glTranslatef(
			SEPARATION * curlist[s].x,
			SEPARATION * curlist[s].y + BOARDSEP * curlist[s].z,
			0.0f
		);
	  //glColor3fv((turn==1) ? PlayerOne : PlayerTwo);
	  glScalef(1.5f, 1.5f, 1.5f);
	  Diamond(0);
	  glPopMatrix();
//	  glVertex3i(cx, cy, cz);
//	  glVertex3i(sl->x, sl->y, sl->z);
  }
  glColor3fv(Option);
  for (s = 0; s < movessize; s++){
	  glPushMatrix();
		glTranslatef(
			SEPARATION * moves[s].x,
			SEPARATION * moves[s].y + BOARDSEP * moves[s].z,
			0.0f
		);
	  //glColor3fv((turn==1) ? PlayerOne : PlayerTwo);
	  glScalef(0.5f, 0.5f, 0.5f);
	  Diamond(0);
	  glPopMatrix();
//	  glVertex3i(cx, cy, cz);
//	  glVertex3i(sl->x, sl->y, sl->z);
  }
  //glEnd();
  glPopMatrix();
  // write score
  glPushMatrix();
  glTranslatef(0.0f,  BOARDSEP * (SIZE - 1) + SEPARATION * SIZE, 0.0f);
  glPushMatrix();
   glTranslatef(SEPARATION / 2.0f, 0.0f, 0.0f);
   glScalef(0.025f, 0.025f, 0.025f);
   glColor3fv(PlayerOne);
   for (i=0; scorestring[0][i]; i++) {
	   glutStrokeCharacter(GLUT_STROKE_ROMAN, scorestring[0][i]);
   }
  glPopMatrix();
  glPushMatrix();
   glTranslatef(SEPARATION * SIZE / 2.0f, 0.0f, 0.0f);
   glScalef(0.025f, 0.025f, 0.025f);
   glColor3fv(PlayerTwo);
   for (i=0; scorestring[1][i]; i++) {
	   glutStrokeCharacter(GLUT_STROKE_ROMAN, scorestring[1][i]);
   }
  glPopMatrix();

  glPopMatrix();
  glutSwapBuffers();	/* doublebuffer is my friend */
  glFinish();
}

void firstGraphInit(void)
{
  glShadeModel(GL_FLAT);
  /* glEnable(GL_BLEND);*/
  glEnable(GL_CULL_FACE);
  glEnable(GL_NORMALIZE);
  glCullFace(GL_BACK);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_LIGHTING);
  glLightfv(GL_LIGHT0, GL_AMBIENT, light0a);
  glEnable(GL_LIGHT0);
//  glClearColor(Felt[0], Felt[1], Felt[2], Felt[3]);
  glDepthFunc(GL_LEQUAL);
  glEnable(GL_DEPTH_TEST);
  glPolygonMode(GL_BACK, GL_LINE);
}

void secondGraphInit(void)
{
  glShadeModel(GL_FLAT);
  /* glEnable(GL_BLEND);*/
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDisable(GL_LIGHTING);
//  glClearColor(Felt[0], Felt[1], Felt[2], Felt[3]);
//  glPolygonMode(GL_BACK, GL_LINE);
}

void myinit (void) 
{
  int i, j, k;
  srand ( (unsigned)time( NULL ) );
  for (i = SIZE / 2 - 1; i <= SIZE / 2; i++) {
    for (j = SIZE / 2 - 1; j <= SIZE / 2; j++) {
      for (k = SIZE / 2 - 1; k <= SIZE / 2; k++) {
	Board[i][j][k] = (i + j + k) % 2 + 1;
      }
    }
  }
  eyer = SEPARATION * SIZE * 3.0f;
  eyelon = 270.0;
  eyelat = 0.01;
  showgrid = 0;
  cursor.x = cursor.y = cursor.z = 0;
  turn = 1;
  curlistsize = flips(cursor, turn, curlist);
  AIstage=0;
  newturn();
}

void myReshape(GLsizei w, GLsizei h)
{
  h = (h == 0) ? 1 : h;
  glViewport(0,0,w,h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-w/500.0,w/500.0,-h/500.0,h/500.0,2.5,40000.0);/*This call keeps*/
  glMatrixMode(GL_MODELVIEW);				/*the scale constant*/
  glLoadIdentity();
}

void secondReshape(GLsizei w, GLsizei h)
{
  h = (h == 0) ? 1 : h;
  glViewport(0,0,w,h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0.0, SEPARATION*SIZE, 0.0, SEPARATION*SIZE*(SIZE+1), -1.0, 1.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void idle(void)
{
	if (player[turn]) {
		switch (AIstage) {
		case 0: //thinking
			{
				switch(player[turn]) {
				case 1:	//extremely stupid computer player
					{
						if (movessize) {
							AItarget = moves[rand() * movessize / RAND_MAX];
						} else {
							AItarget.x = AItarget.y = AItarget.z = -1;
						}
						AIstage++;
						break;
					}
				case 2: //slightly less stupid computer player
					{
						AIthink();
						AIstage++;
						break;
					}
				case 3: //Marc's smarter computer player
					{
						AIthink2();
						if (AItarget.x == -1) {
							AItarget.x = -1;
						}
						AIstage++;
						break;
					}
				}
				if (AItarget.x == -1 && movessize > 0)
				{
					AIstage--;
				}
				break;
			}
		case 1: //moving
			{
				//big ugly if structure
				if (AItarget.x == -1) {
					keyboard('P', 0, 0);
					AIstage = 0;
				}
				else if (cursor.x < AItarget.x) keyboard('L', 0, 0);
				else if (cursor.x > AItarget.x) keyboard('H', 0, 0);
				else if (cursor.y < AItarget.y) keyboard('K', 0, 0);
				else if (cursor.y > AItarget.y) keyboard('J', 0, 0);
				else if (cursor.z < AItarget.z) keyboard('I', 0, 0);
				else if (cursor.z > AItarget.z) keyboard('M', 0, 0);
				else {
					keyboard(' ', 0, 0);
					AIstage = 0;
				}
				break;
			}
		}
	}
}

void usage() {
	fprintf (stderr, "Usage: othello [-1 (c1|c2|c3|h)] [-2 (c1|c2|c3|h)]\n");
	fprintf (stderr, "                 ^player 1  cpu players^--^--^ ^human(default)\n");
	fprintf (stderr, "    View: h/l = spin left/right\n");
	fprintf (stderr, "          i/m = tilt up/down\n");
	fprintf (stderr, "          k/j = zoom in/out\n");
	fprintf (stderr, "    Move: H/L = move west/east\n");
	fprintf (stderr, "          I/M = move up/down\n");
	fprintf (stderr, "          K/J = move north/south\n");
	fprintf (stderr, "          P = pass    space = place stone\n");
	fprintf (stderr, "    Xtra: q = quit    g = toggle grid\n");
	exit(1);
}

/*  Main Loop
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
	player[1] = player[2] = 0;
	if (argc > 1) {
		int i = 1;
		while (i < argc) {
			if (!strcmp(argv[i], "-1") && i+1 < argc) {
				i++;
				if (!strcmp(argv[i], "c1")) player[1] = 1;
				else if (!strcmp(argv[i], "c2")) player[1] = 2;
				else if (!strcmp(argv[i], "c3")) player[1] = 3;
				else if (!strcmp(argv[i], "h")) player[1] = 0;
				else usage();
				i++;
			}
			else if (!strcmp(argv[i], "-2") && i+1 < argc) {
				i++;
				if (!strcmp(argv[i], "c1")) player[2] = 1;
				else if (!strcmp(argv[i], "c2")) player[2] = 2;
				else if (!strcmp(argv[i], "c3")) player[2] = 3;
				else if (!strcmp(argv[i], "h")) player[2] = 0;
				else usage();
				i++;
			}
			else usage();
		}
	}
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
 
	myinit ();
	
	glutInitWindowPosition(135, 0);
	glutInitWindowSize(250, 250);
	first = glutCreateWindow("Othello");
    firstGraphInit();
	glutIdleFunc(idle); 
    glutKeyboardFunc(keyboard);
    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);

	glutInitWindowPosition(0, 0);
	glutInitWindowSize(125, 125 * SIZE);
	second = glutCreateWindow("Othello");
	secondGraphInit();
	glutIdleFunc(idle);
	glutKeyboardFunc(keyboard);
	glutReshapeFunc(secondReshape);
	glutDisplayFunc(display);
    
	glutMainLoop();
    return(0);
}

