/*************

sean mcmillen
ronald yorgason

CS410 Combinatorial Games -- Spring 2002

amazons player. 

amazons -h for options

Project URL:     http://www.yorgalily.org/amazons/

***************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <assert.h>
#include <ctype.h>
#include <sys/poll.h>

//#ifdef GAMAZONS
#include <gnome.h>
//#endif

#include "amazons.h"
#include "unit-test.h"


#define HEVAL heval  // for testing differant hevals
#define MINDEPTH 1
#define VERBOSE 0
#define TIMED 1      // boolean, if 1 then TIMEOUT is in effect, if 0 then no

// macros

//#define MIN(a,b)    (a < b ? a : b)
//#define MAX(a,b)    (a > b ? a : b)
#define MMSET(p,q)    ((p) == 1 ? SHRT_MIN+q : SHRT_MAX-q)

// constants

#define WHITEQUEENS 4
#define BLACKQUEENS 4

/* local prototypes */
move mtdf(state *s, int guess, int tdepth);


// some globals //
FILE *movin;                        // read moves from here
FILE *movout;                       // write moves to here
struct pollfd pollstruct;           // used to poll FILE *movin

int onmove;
int nodes;                        // statitics gatherer
int rawnodes;                     // statitics gatherer
int hevalz;                        // statitics gatherer
int hits;                        // statitics gatherer
int ok;                            // global, if 0 then timeout condition 
time_t start;                    // global, start of search, used for timeout
                                // check
struct options options;
struct game_states states;

#ifdef GAMAZONS
extern int state_hash;
extern GtkWidget *main_window;
#endif

// command line flags -- set defaults here
/*
int white_player = FALSE;
int black_player = FALSE;
int print_statistics = FALSE;
int TIMEOUT = 5;
int MAXDEPTH = 20;
int MAXWIDTH = 5000;
 */

int obst_heval(state *s)
{
   int moves;

   int t1;
   int t2;
   int turn;

   if (onmove > 10)
      return heval(s);

   turn = s->turn;

   s->turn = WHITE_PLAYER;

   t1 =  countobst(s);

   s->turn = BLACK_PLAYER;

   t2 =  countobst(s);

   s->turn = turn;

   moves = t1 - t2;
   return moves;
}






int countobst(state *s)
{
   int i,j;
   int m=0, p=0;
   int xo=0, yo=0;
   int axo=0, ayo=0;
   int dir, adir;
   int QUEENS;

   uchar *queens_x;
   uchar *queens_y;
   ull *board;

   int queen = 0;

   if(s->turn == WHITE_PLAYER)
     {
      queens_x = s->white_q_x;
      queens_y = s->white_q_y;
      board = s->white_bd;
      QUEENS = WHITEQUEENS;
     }
   else
     {
      queens_x = s->black_q_x;
      queens_y = s->black_q_y;
      board = s->black_bd;
      QUEENS = BLACKQUEENS;
     }

   // order: N NE E SE S SW W NW 
   for (queen = 0; queen < QUEENS; queen++)
     {
      for (dir = 0; dir < 8; dir++)
       	{
	 // for tightness not speed
	 switch (dir)
	   {
	     case 0:
		 xo = 0; yo = 1;
		 break;
	     case 1:
		 xo = 1; yo = 1;
		 break;
	     case 2:
		 xo = 1; yo = 0;
		 break;
	     case 3:
		 xo = 1; yo = -1;
		 break;
	     case 4: 
		 xo = 0; yo = -1;
		 break;
	     case 5:
		 xo = -1; yo = -1;
		 break;
	     case 6:
		 xo = -1; yo = 0;
		 break;
	     case 7: 
		 xo = -1; yo = 1;
		 break;
	   }

	 for (i=1; i < 10; i++) 
	   {
	    // out of bounds
	    if (queens_x[queen] + xo*i > 9 ||
		    queens_y[queen] + yo*i > 9 ||
		    queens_x[queen] + xo*i < 0 ||
		    queens_y[queen] + yo*i < 0)
	      {
	       // count obst
	       for (adir = 0; adir < 8; adir++)
		 {
		  // for tightness not speed
		  switch (adir)
		    {
		      case 0:
			  axo = 0; ayo = 1;
			  break;
		      case 1:
			  axo = 1; ayo = 1;
			  break;
		      case 2:
			  axo = 1; ayo = 0;
			  break;
		      case 3:
			  axo = 1; ayo = -1;
			  break;
		      case 4: 
			  axo = 0; ayo = -1;
			  break;
		      case 5:
			  axo = -1; ayo = -1;
			  break;
		      case 6:
			  axo = -1; ayo = 0;
			  break;
		      case 7: 
			  axo = -1; ayo = 1;
			  break;
		    }
		  if (dir == adir) continue;

		  for (j=1; j < 2; j++) 
		    {
		     if (queens_x[queen] + axo*j > 9 ||
			     queens_y[queen] + ayo*j > 9 ||
			     queens_x[queen] + axo*j < 0 ||
			     queens_y[queen] + ayo*j < 0)
		       {
		       	break;
		       }

		     if (test(s, queens_x[queen]+axo*j, 
				 queens_y[queen]+ayo*j))
		       {
		       	break;
		       }
		     m+=1;
		    }
		 }
	       break;
	      }

	    // hit a wall
	    if (test(s, queens_x[queen]+xo*i, queens_y[queen]+yo*i))
	      {
	       for (adir = 0; adir < 8; adir++)
		 {
		  // for tightness not speed
		  switch (adir)
		    {
		      case 0:
			  axo = 0; ayo = 1;
			  break;
		      case 1:
			  axo = 1; ayo = 1;
			  break;
		      case 2:
			  axo = 1; ayo = 0;
			  break;
		      case 3:
			  axo = 1; ayo = -1;
			  break;
		      case 4: 
			  axo = 0; ayo = -1;
			  break;
		      case 5:
			  axo = -1; ayo = -1;
			  break;
		      case 6:
			  axo = -1; ayo = 0;
			  break;
		      case 7: 
			  axo = -1; ayo = 1;
			  break;
		    }
		  //if (dir == adir) continue;
		  if (dir == adir) continue;

		  for (j=1; j < 2; j++) 
		    {
		     if (queens_x[queen] + axo*j > 9 ||
			     queens_y[queen] + ayo*j > 9 ||
			     queens_x[queen] + axo*j < 0 ||
			     queens_y[queen] + ayo*j < 0)
		       {
		       	break;
		       }

		     if (test(s, queens_x[queen]+axo*j, 
				 queens_y[queen]+ayo*j))
		       {
		       	break;
		       }
		     m+=1;
		    }
		 }
	       break;
	      }

	    m+=2;
	    /*
	       xor(board, queens_x[queen], queens_y[queen]);
	       queens_x[queen] += i*xo;
	       queens_y[queen] += i*yo;
	       xor(board, queens_x[queen], queens_y[queen]);

	    // look for arrow moves.
	    // order: N NE E SE S SW W NW 
	    xor(board, queens_x[queen], queens_y[queen]);
	    queens_x[queen] -= i*xo;
	    queens_y[queen] -= i*yo;
	    xor(board, queens_x[queen], queens_y[queen]);
	     */
	   }
       	}
     }
   return m;
}

// heuristic function
int sean_heval(state *s)
{
   int moves;

   int t1;
   int t2;
   int turn;

   turn = s->turn;

   s->turn = WHITE_PLAYER;

   t1 =  countchildren(s);

   s->turn = BLACK_PLAYER;

   t2 =  countchildren(s);

   s->turn = turn;

   moves = t1 - t2;
   return moves;
}

int countchildren(state *s)
{
   int i,j;
   int m=0;
   int xo=0, yo=0;
   int axo=0, ayo=0;
   int dir, adir;
   int QUEENS;

   uchar *queens_x;
   uchar *queens_y;
   ull *board;

   int queen = 0;

   if(s->turn == WHITE_PLAYER)
     {
      queens_x = s->white_q_x;
      queens_y = s->white_q_y;
      board = s->white_bd;
      QUEENS = WHITEQUEENS;
     }
   else
     {
      queens_x = s->black_q_x;
      queens_y = s->black_q_y;
      board = s->black_bd;
      QUEENS = BLACKQUEENS;
     }

   // look for moves.
   // order: N NE E SE S SW W NW

   // this loop moves a queen, shoots an arrow, all the while 
   // checking to see if its run into things. 
   // populated movelist (passing in as reference) with the valid moves.
   for (queen = 0; queen < QUEENS; queen++)
     {
      for (dir = 0; dir < 8; dir++)
       	{
	 // for tightness not speed
	 switch (dir)
	   {
	     case 0:
		 xo = 0; yo = 1;
		 break;
	     case 1:
		 xo = 1; yo = 1;
		 break;
	     case 2:
		 xo = 1; yo = 0;
		 break;
	     case 3:
		 xo = 1; yo = -1;
		 break;
	     case 4: 
		 xo = 0; yo = -1;
		 break;
	     case 5:
		 xo = -1; yo = -1;
		 break;
	     case 6:
		 xo = -1; yo = 0;
		 break;
	     case 7: 
		 xo = -1; yo = 1;
		 break;
	   }

	 for (i=1; i < 10; i++) 
	   {
	    // out of bounds
	    if (queens_x[queen] + xo*i > 9 ||
		    queens_y[queen] + yo*i > 9 ||
		    queens_x[queen] + xo*i < 0 ||
		    queens_y[queen] + yo*i < 0)
	      {
	       break;
	      }

	    // hit a wall
	    if (test(s, queens_x[queen]+xo*i, queens_y[queen]+yo*i))
	      {
	       break;
	      }

	    xor(board, queens_x[queen], queens_y[queen]);
	    queens_x[queen] += i*xo;
	    queens_y[queen] += i*yo;
	    xor(board, queens_x[queen], queens_y[queen]);

	    // look for arrow moves.
	    // order: N NE E SE S SW W NW 
	    for (adir = 0; adir < 8; adir++)
	      {
	       // for tightness not speed
	       switch (adir)
		 {
		   case 0:
		       axo = 0; ayo = 1;
		       break;
		   case 1:
		       axo = 1; ayo = 1;
		       break;
		   case 2:
		       axo = 1; ayo = 0;
		       break;
		   case 3:
		       axo = 1; ayo = -1;
		       break;
		   case 4: 
		       axo = 0; ayo = -1;
		       break;
		   case 5:
		       axo = -1; ayo = -1;
		       break;
		   case 6:
		       axo = -1; ayo = 0;
		       break;
		   case 7: 
		       axo = -1; ayo = 1;
		       break;
		 }

	       for (j=1; j < 10; j++) 
		 {
		  if (queens_x[queen] + axo*j > 9 ||
			  queens_y[queen] + ayo*j > 9 ||
			  queens_x[queen] + axo*j < 0 ||
			  queens_y[queen] + ayo*j < 0)
		    {
		     break;
		    }

		  if (test(s, queens_x[queen]+axo*j, 
			      queens_y[queen]+ayo*j))
		    {
		     break;
		    }

		  // put arrow
		  m++;
		 }
	      }
	    xor(board, queens_x[queen], queens_y[queen]);
	    queens_x[queen] -= i*xo;
	    queens_y[queen] -= i*yo;
	    xor(board, queens_x[queen], queens_y[queen]);
	   }
       	}
     }
   return m;
}

// populates movelist[] with all possible moves.
// returns the count of moves
// the value of the move is also set here, that means 
// this is the function that calls heval (heuristic) 
//  and tt_lookup (transposition table retrieve)

int children(state *s, move movelist[])
{
   int i,j;
   int m=0;
   int xo=0, yo=0;
   int axo=0, ayo=0;
   int dir, adir;
   int QUEENS;

   uchar *queens_x;
   uchar *queens_y;
   ull *board;

   int queen = 0;

   if(s->turn == WHITE_PLAYER)
     {
      queens_x = s->white_q_x;
      queens_y = s->white_q_y;
      board = s->white_bd;
      QUEENS = WHITEQUEENS;
     }
   else
     {
      queens_x = s->black_q_x;
      queens_y = s->black_q_y;
      board = s->black_bd;
      QUEENS = BLACKQUEENS;
     }

   // look for moves.
   // order: N NE E SE S SW W NW

   // this loop moves a queen, shoots an arrow, all the while 
   // checking to see if its run into things. 
   // populated movelist (passing in as reference) with the valid moves.
   for (queen = 0; queen < QUEENS; queen++)
     {
      for (dir = 0; dir < 8; dir++)
       	{
	 // for tightness not speed
	 switch (dir)
	   {
	     case 0:
		 xo = 0; yo = 1;
		 break;
	     case 1:
		 xo = 1; yo = 1;
		 break;
	     case 2:
		 xo = 1; yo = 0;
		 break;
	     case 3:
		 xo = 1; yo = -1;
		 break;
	     case 4: 
		 xo = 0; yo = -1;
		 break;
	     case 5:
		 xo = -1; yo = -1;
		 break;
	     case 6:
		 xo = -1; yo = 0;
		 break;
	     case 7: 
		 xo = -1; yo = 1;
		 break;
	   }

	 for (i=1; i < 10; i++) 
	   {
	    // out of bounds
	    if (queens_x[queen] + xo*i > 9 ||
		    queens_y[queen] + yo*i > 9 ||
		    queens_x[queen] + xo*i < 0 ||
		    queens_y[queen] + yo*i < 0)
	      {
	       break;
	      }

	    // hit a wall
	    if (test(s, queens_x[queen]+xo*i, queens_y[queen]+yo*i))
	      {
	       break;
	      }

	    xor(board, queens_x[queen], queens_y[queen]);
	    queens_x[queen] += i*xo;
	    queens_y[queen] += i*yo;
	    xor(board, queens_x[queen], queens_y[queen]);

	    // look for arrow moves.
	    // order: N NE E SE S SW W NW 
	    for (adir = 0; adir < 8; adir++)
	      {
	       // for tightness not speed
	       switch (adir)
		 {
		   case 0:
		       axo = 0; ayo = 1;
		       break;
		   case 1:
		       axo = 1; ayo = 1;
		       break;
		   case 2:
		       axo = 1; ayo = 0;
		       break;
		   case 3:
		       axo = 1; ayo = -1;
		       break;
		   case 4: 
		       axo = 0; ayo = -1;
		       break;
		   case 5:
		       axo = -1; ayo = -1;
		       break;
		   case 6:
		       axo = -1; ayo = 0;
		       break;
		   case 7: 
		       axo = -1; ayo = 1;
		       break;
		 }

	       for (j=1; j < 10; j++) 
		 {
		  if (queens_x[queen] + axo*j > 9 ||
			  queens_y[queen] + ayo*j > 9 ||
			  queens_x[queen] + axo*j < 0 ||
			  queens_y[queen] + ayo*j < 0)
		    {
		     break;
		    }

		  if (test(s, queens_x[queen]+axo*j, 
			      queens_y[queen]+ayo*j))
		    {
		     break;
		    }

		  /*
		  // put arrow
		  xor(s->blocks_bd, queens_x[queen]+axo*j, queens_y[queen]+ayo*j);
		  s->turn ^= 3;

		  //                        printf("evaluating board:");
		  //                        pboard(*s);
		  if ((stt = tt_lookup(s)))
		  {
		  //tt_yes++;
		  hits++;
		  movelist[m].val = stt->value;
		  movelist[m].depth = stt->depth;
		  }
		  else
		  {
		  //tt_no++;
		  movelist[m].val = HEVAL(s);
		  hevalz++;
		  s->value = movelist[m].val;
		  s->depth = 1;
		  tt_store(s, SHRT_MIN, SHRT_MAX);
		  }

		  // remove arrow
		  xor(s->blocks_bd, queens_x[queen]+axo*j, queens_y[queen]+ayo*j);
		  s->turn ^= 3;

		   */
		  movelist[m].queen=queen;
		  movelist[m].tocol=queens_x[queen];
		  movelist[m].torow=queens_y[queen];
		  movelist[m].wallcol=queens_x[queen]+axo*j;
		  movelist[m].wallrow=queens_y[queen]+ayo*j;

		  //                        pmove(movelist[m]);
		  //                        printf("\n");

		  m++;
		 }
	      }
	    xor(board, queens_x[queen], queens_y[queen]);
	    queens_x[queen] -= i*xo;
	    queens_y[queen] -= i*yo;
	    xor(board, queens_x[queen], queens_y[queen]);
	   }
       	}
     }
   return m;
}

// for qsort
int mincompare(move *m1, move *m2) // USED BY MAXIMIZER
{
   if (m1->val > m2->val)
      return -1;
   else if (m1->val < m2->val)
      return 1;
   return 0;
}

// for qsort
int maxcompare(move *m1, move *m2)
{
   if (m1->val < m2->val)
      return -1;
   else if (m1->val > m2->val)
      return 1;
   return 0;
}

// top level iterative search function. called from main, pretty
// self explanatory
move isearch(state *s, int think)
{
   int i;
   move temp1, temp2;
   move even, odd;
   int temp2_valid = FALSE;

   even.val = 0;
   odd.val = 0;

   for (i=MINDEPTH; i <= options.engine.maxdepth; i++)
     {
      rawnodes = 0;
      nodes = 0;
      hits = 0;
      hevalz =0;


      temp1 = search(s, 0, SHRT_MIN, SHRT_MAX, i, think);

      /*

      // for mtdf NOT WORKING CURRENTLY
      if (i & 1)
      {
      temp1 = mtdf(s, odd.val, i);
      even = temp1;
      }
      else
      {
      temp1 = mtdf(s, even.val, i);
      odd = temp1;
      }
       */

      //printf("Searched to depth %d, %d cache hits of %d lookups. %d nodes searched.\n", i,hits,rawnodes, nodes);
      //printf("hevals = %d\n", hevalz);
      if (ok)          // using this global ok is pretty sloppy but works.
      	{
	 temp2 = temp1;
	 temp2_valid = TRUE;
       	}
      else
       	{
	 if (think)
	   {
#ifdef DEBUG
	    printf("searched %d nodes on your time\n", nodes);
#endif
	   }
#ifdef DEBUG
	 printf("time's up at depth %d\n", i);
#endif
	 break;
       	}

     }
   if (temp2_valid)
      return temp2;
   else
      return temp1;
}

// NOT WORKING
move mtdf(state *s, int guess, int tdepth)
{
   move temp;
   //int f;
   int lowerbound = SHRT_MIN;
   int upperbound = SHRT_MAX;
   int beta;

   temp.val = guess;

   do
     {
      if (temp.val == lowerbound)
       	{
	 beta = temp.val + 1;
       	}
      else
       	{
	 beta = temp.val;
       	}

      //temp = search(s, 0, beta - 1, beta, tdepth, think);

      if (temp.val < beta)
       	{
	 upperbound = temp.val;
       	}
      else
       	{
	 lowerbound = temp.val;
       	}
     }
   while (!(lowerbound >= upperbound));

   return temp;
}

// minimax search.
// tdepth is "target depth", that is the current iterative target level
move search(state *s, int depth, int alpha, int beta, int tdepth, int think)
{
   state_t *stt;
   move movelist[3000];
   int i;
   int index=0;
   move stemp;
   move temp;
   int randomizer;
   //    int tt_yes=0;
   //    int tt_no=0;

   int movecount;

   int done;

   nodes++;

   if ((time_t)time(NULL) - start > options.engine.timeout && TIMED && !think)
     {
      ok = 0;
      return movelist[0];
     }

   if (think)
     {
      if (poll(&pollstruct, 1, 0))
       	{
	 ok = 0;
	 return movelist[0];
       	}
     }

   movecount = children(s, movelist);

   if (movecount == 0) // no more moves
     {
      if (depth == 0)
       	{
#ifdef DEBUG
	 printf("player %d wins!\n", s->turn^3);
#endif
	 s->winner = s->turn^3;
	 if (options.print_statistics)
	    print_stats();
#ifndef GAMAZONS
	 exit(1);
#endif
       	}

      // if no more moves, then set the value here to 
      // a very high value plus/minus the depth
      // this ensure that the loser will select the longest path
      // to loss, and the winner will select the shortest path to
      // a win.
      movelist[0].val = MMSET(s->turn, depth);
     }

   // for node reordering, make sure everything has a value.
   for (i=0; i <movecount; i++)
     {

#ifdef GAMAZONS
      //Make the game responsive while the AI is thinking
      while (gtk_events_pending())
	 gtk_main_iteration();
#endif

      temp = savemove(s, movelist[i]);
      makemove(s, movelist[i]);
      if ((stt = tt_lookup(s)))
       	{
	 if (alpha >= stt->alpha && beta <= stt->beta) // correct
	   {
	    hits++;
	    movelist[i].val = stt->value;
	    movelist[i].depth = stt->depth;
	   }
	 else
	   {
	    movelist[i].val = HEVAL(s);
	    hevalz++;
	    s->value = movelist[i].val;
	    s->depth = 1;
	    tt_update(s, SHRT_MIN, SHRT_MAX);
	   }
       	}
      else
       	{
	 movelist[i].val = HEVAL(s);
	 hevalz++;
	 s->value = movelist[i].val;
	 s->depth = 1;
	 tt_store(s, SHRT_MIN, SHRT_MAX);
       	}
      undomove(s, temp);
     }

   rawnodes += movecount;

   // node reordering here.

   if (s->turn == WHITE_PLAYER)
      qsort(movelist, movecount, sizeof(move), (void*)mincompare);
   else
      qsort(movelist, movecount, sizeof(move), (void*)maxcompare);

   // this is the end of the line, return best move.
   if (depth+1 >= tdepth)
      return movelist[0];

   done = 0;
   for (i=0; i < movecount && !done && i < options.engine.maxdepth; i++)

     {
      // already searched farther than we will in the TT, just return it.
      if (movelist[i].depth > tdepth - depth)
	 return movelist[i];

      temp = savemove(s, movelist[i]);
      makemove(s, movelist[i]);

      stemp = search(s, depth+1, alpha, beta, tdepth, think);

      if (ok)
       	{
	 // this should perhaps check if tt_lookup still works 
	 // not life changing
	 if (tdepth-depth > movelist[i].depth)
	   {
	    s->value = stemp.val;
	    s->depth = tdepth-depth;
	    tt_update(s, alpha, beta);
	   }

	 movelist[i].val = stemp.val;
	 undomove(s,temp); // undo move.
      	}
      else // times up, return back up the tree as fast as possible.
      	{
	 undomove(s,temp); // undo move.
       	 return movelist[i];
       	}

      nodes++;

      // alpha-beta stuff:

      if (s->turn == WHITE_PLAYER) 
	{
	 if (movelist[i].val > alpha)
	   {
	    alpha = movelist[i].val;
	    index = i;
	   }
       	}
      else
       	{
	 if (movelist[i].val < beta)
	   {
	    beta = movelist[i].val;
	    index = i;
	   }
       	}

      if (alpha >= beta)
       	{
	 done = 1;
       	}
     }

   /* XXX
   printf("movelist index = %d\n", index);
   if (movecount > 3)
     {
      randomizer = rand() %3;
      printf("randomizer = %d\n", randomizer);
     }
     */

   return movelist[index];
}

// print out a longlong in binary
int pvec(ull v)
{
   int i;

   printf("->");
   for (i=49; i >= 0; i--)
     {
      printf("%d", (int)((v >> i) & (ull)1));
      if (i%10 == 0)
	 printf(" ");
     }
   printf("<-\n");

   return 0;
}

// bring out a nice representation of the playing board
int pboard(state s)
{
   int board[12][12];
   int i,j;
   int row, col;

   // make the whole board blanks
   for (i=0; i < 12; i++)
      for (j=0; j < 12; j++)
	 board[i][j] = '.';

   // place player1 queens
   for (i=0; i < WHITEQUEENS; i++)
     {
      col = s.white_q_x[i];
      row = s.white_q_y[i];
      if (options.white_player == HUMAN) board[col][row] = i+48;
      else board[col][row] = 'W';
     }

   // place player2 queens
   for (i=0; i < BLACKQUEENS; i++)
     {
      col = s.black_q_x[i];
      row = s.black_q_y[i];
      if (options.black_player == HUMAN) board[col][row] = i+48;
      else  board[col][row] = 'B';
     }

   // put walls on the board
   //pvec(s.blocks_bd[1]);
   for (i=0; i < 50; i++)
     {
      if ((s.blocks_bd[1] >> i) & 1)
       	{
	 board[i%10][i/10+5] = 'x';
       	}
     }
   //pvec(s.blocks_bd[0]);

   for (i=0; i < 50; i++)
     {
      if ((s.blocks_bd[0] >> i) & 1)
       	{
	 board[i%10][i/10] = 'x';
       	}
     }
   printf("\n");

   // print out the board
   for (i=9; i >= 0; i--)
     {
      printf("%2d ", i);
      for (j=0; j < 10; j++)
       	{
	 printf(" %c", board[j][i]);
       	}
      printf("\n");
     }

   printf("    a b c d e f g h i j\n");
   //printf("    0 1 2 3 4 5 6 7 8 9\n");
   printf("\n");
   return 0;
}

/*==============================================================================
 * getmove
 *
 * Gets the move coordinates from stdin.  Does lots of nice error checking on the
 * input, and makes sure the move was legal.  If no moves are available, the human
 * must have lost, so the game ends.
 */
move getmove(state *s, int player)
{
   char tok;
   int done = FALSE;
   move movelist[3000];
   int move_count;
   move m;
   char move_str[10];
   int i;

   move_count = children(s, movelist);
   if (move_count == 0)
     {
      printf("Ha ha ha, you lose SUCKER!\n");
      s->winner = s->turn^3;
#ifndef GAMAZONS
      exit(0);
#endif
     }

   do 
     {
      i = 0;

      printf("player %d's move.\n", player);
      printf("queen newcol newrow burncol burnrow (ex. \"0 c4 c1\")\n");
      printf("Move> ");
      fflush(stdout);

      ok = 1;
      isearch(s, THINK);

      tok = get_token();
      if (isdigit(tok))
       	{
	 m.queen = tok - '0';
	 move_str[i++] = tok;
	 move_str[i++] = ' ';
       	}
      else
       	{
	 printf("%c is not a valid queen\n\n", tok);
	 clear_buf();
	 continue;
       	}

      tok = get_token();
      if (isdigit(tok - '1')) //convert from alpha char to alpha num
       	{
	 m.tocol = tok - 'a';
	 move_str[i++] = tok;
       	}
      else
       	{
	 printf("%c is not a valid column\n\n", tok);
	 clear_buf();
	 continue;
       	}

      tok = get_token();
      if (isdigit(tok))
       	{
	 m.torow = tok - '0';
	 move_str[i++] = tok;
	 move_str[i++] = ' ';
       	}
      else
       	{
	 printf("%c is not a valid row\n\n", tok);
	 clear_buf();
	 continue;
       	}

      tok = get_token();
      if (isdigit(tok - '1')) //convert from alpha char to alpha num
       	{
	 m.wallcol = tok - 'a';
	 move_str[i++] = tok;
       	}
      else
       	{
	 printf("%c is not a valid column\n\n", tok);
	 clear_buf();
	 continue;
       	}


      tok = get_token();
      if (isdigit(tok))
       	{
	 m.wallrow = tok - '0';
	 move_str[i++] = tok;
       	}
      else
       	{
	 printf("%c is not a valid row\n\n", tok);
	 clear_buf();
	 continue;
       	}

      move_str[i] = '\0';

      //make sure it's a valid move
      if (!move_lookup(&m, movelist, move_count))
       	{
	 printf("%s is not a legal move\n", move_str);
	 continue;
       	}

      //User input verified
      done = TRUE;
     }
   while (done == FALSE);

   return m;
}

/*==============================================================================
 * get_token
 *
 * Retreives a token from stdin, ignores beginning whitespace.
 */
char get_token()
{
   char tok;
   tok = getc(movin);
   while (isspace(tok))
      tok = getc(movin);

   return tok;
}

/*==============================================================================
 * clear_buf
 *
 * Clears chars in the stdin buffer all the way up to and including the carriage 
 * return.
 */
void clear_buf()
{
   while (getc(movin) != '\n');
}


/*==============================================================================
 * move_lookup
 *
 * Compares a given move with a move with the moves in the given movelist.  If it's
 * found in the list, returns TRUE, otherwise returns FALSE.
 */
int move_lookup(move *m, move movelist[], int move_count)
{
   int i;

   for (i=0; i<move_count; i++)
     {
      if (m->queen != movelist[i].queen)
	 continue;
      if (m->tocol != movelist[i].tocol)
	 continue;
      if (m->torow != movelist[i].torow)
	 continue;
      if (m->wallcol != movelist[i].wallcol)
	 continue;
      if (m->wallrow != movelist[i].wallrow)
	 continue;
      else
       	{
	 return TRUE;
       	}
     }
   return FALSE;
}


// returns 1 if bit is set.
int test(state *s, uchar col, uchar row)
{
   //printf("sigh %d %d\n", col, row);
   if (row < 5)
     {
      if ( (s->blocks_bd[0] | s->white_bd[0] | s->black_bd[0] ) & 
	      (ull)1 << ((row*10) + col))
	 return 1;

      return 0;
     }
   else // row > 5
     {
      if ( (s->blocks_bd[1] | s->white_bd[1] | s->black_bd[1]) & 
	      (ull)1 << ((((row-5)*10) + col)))
       	{
	 return 1;
       	}
      return 0;
     }
}


// xor bit at col,row
int xor(ull bd[2], uchar col, uchar row)
{
   if (row < 5)
     {
      bd[0] ^= (ull)1 << ((row*10) + col);
     }
   else // row > 5
     {
      bd[1] ^= (ull)1 << ((((row-5)*10) + col));
     }
   return 1;
}

// takes a move that is to be made and returns a move that will
// undo it.
move savemove(state *s, move m)
{
   move temp;

   temp.wallcol = m.wallcol;
   temp.wallrow = m.wallrow;
   temp.queen = m.queen;

   if (s->turn == WHITE_PLAYER)
     {
      temp.tocol = s->white_q_x[m.queen];
      temp.torow = s->white_q_y[m.queen];
     }
   else
     {
      temp.tocol = s->black_q_x[m.queen];
      temp.torow = s->black_q_y[m.queen];
     }
   return temp;
}

int undomove(state *s, move m)
{
   s->turn ^= 3;

   if (s->turn == WHITE_PLAYER)
     {
      xor(s->white_bd, s->white_q_x[m.queen], s->white_q_y[m.queen]);
      s->white_q_x[m.queen] = m.tocol;
      s->white_q_y[m.queen] = m.torow;
      xor(s->white_bd, s->white_q_x[m.queen], s->white_q_y[m.queen]);
     }
   else
     {
      xor(s->black_bd, s->black_q_x[m.queen], s->black_q_y[m.queen]);
      s->black_q_x[m.queen] = m.tocol;
      s->black_q_y[m.queen] = m.torow;
      xor(s->black_bd, s->black_q_x[m.queen], s->black_q_y[m.queen]);
     }

   xor(s->blocks_bd, m.wallcol, m.wallrow);
   return 1;
}

// takes a move and does it. 
int makemove(state *s, move m)
{
   if (s->turn == WHITE_PLAYER)
     {
      //printf("registering move w/ engine for white\n");
      xor(s->white_bd, s->white_q_x[m.queen], s->white_q_y[m.queen]);
      s->white_q_x[m.queen] = m.tocol;
      s->white_q_y[m.queen] = m.torow;
      xor(s->white_bd, s->white_q_x[m.queen], s->white_q_y[m.queen]);
     }
   else
     {
      //printf("registering move w/ engine for black\n");
      xor(s->black_bd, s->black_q_x[m.queen], s->black_q_y[m.queen]);
      s->black_q_x[m.queen] = m.tocol;
      s->black_q_y[m.queen] = m.torow;
      xor(s->black_bd, s->black_q_x[m.queen], s->black_q_y[m.queen]);
     }

   xor(s->blocks_bd, m.wallcol, m.wallrow);
   s->turn ^= 3;
   return 1;
}

// print out a move struct
int pmove(move m)
{
   printf("%d) %d -> %c%d ---> %c%d, val = %d\n", onmove, 
	   m.queen, m.tocol+97, m.torow, m.wallcol+97, m.wallrow, m.val);

   if (movin != stdin) // ?
     {
      fprintf(movout, "%d  %c%d  %c%d\n", 
	      m.queen, m.tocol+97, m.torow, m.wallcol+97, m.wallrow);
      fflush(movout);
      fseek(movout,0,0);
      //sleep(6);
     }

   return 0;
}

// set up the state
int init(state *s)
{
   int i;

   s->blocks_bd[0] = s->blocks_bd[1] = 0;
   s->white_bd[0] = s->white_bd[1] = 0;
   s->black_bd[0] = s->black_bd[1] = 0;

   s->turn = WHITE_PLAYER;

   for (i=0; i < 4; i++)
     {
      s->white_q_x[i] = 0;
      s->white_q_y[i] = 0;
      s->black_q_x[i] = 0;
      s->black_q_y[i] = 0;
     }

   // some lines to trip things up

   //    xor(s->blocks_bd, 0,2);
   //    xor(s->blocks_bd, 1,2);
   //    xor(s->blocks_bd, 2,2);
   //    xor(s->blocks_bd, 3,2);
   //    xor(s->blocks_bd, 4,2);
   //    xor(s->blocks_bd, 5,2);
   //    xor(s->blocks_bd, 6,2);
   //    xor(s->blocks_bd, 7,2);
   //    xor(s->blocks_bd, 8,3);
   //    xor(s->blocks_bd, 9,2);

   // place queen on the board
   xor(s->white_bd, 6, 0);
   s->white_q_x[0] = 6;
   s->white_q_y[0] = 0;

   xor(s->white_bd, 3, 0);
   s->white_q_x[1] = 3;
   s->white_q_y[1] = 0;

   xor(s->white_bd, 0, 3);
   s->white_q_x[2] = 0;
   s->white_q_y[2] = 3;

   xor(s->white_bd,9,3);
   s->white_q_x[3] = 9;
   s->white_q_y[3] = 3;

   xor(s->black_bd, 3, 9);
   s->black_q_x[0] = 3;
   s->black_q_y[0] = 9;

   xor(s->black_bd, 6, 9);
   s->black_q_x[1] = 6;
   s->black_q_y[1] = 9;

   xor(s->black_bd, 0, 6);
   s->black_q_x[2] = 0;
   s->black_q_y[2] = 6;

   xor(s->black_bd,9,6);
   s->black_q_x[3] = 9;
   s->black_q_y[3] = 6;


   return 0;
}

int meta_init()
{
   if (!movin)
     {
#ifdef DEBUG
      printf("not using fifos\n");
#endif
      movin = stdin;
      movout = stdout;
     }

   pollstruct.fd = fileno(movin);
   pollstruct.events = POLLIN;
   pollstruct.revents = 0;

   return 1;
}

// test init function, used to set up potentially interesting 
// board states. Change call in main of init to x_init to put into
// action.
int x_init(state *s)
{
   int i;

   s->blocks_bd[0] = s->blocks_bd[1] = 0;
   s->white_bd[0] = s->white_bd[1] = 0;
   s->black_bd[0] = s->black_bd[1] = 0;

   s->turn = WHITE_PLAYER;

   for (i=0; i < 4; i++)
     {
      s->white_q_x[i] = 0;
      s->white_q_y[i] = 0;
      s->black_q_x[i] = 0;
      s->black_q_y[i] = 0;
     }

   // place queen on the board
   xor(s->white_bd, 0, 0);
   s->white_q_x[0] = 0;
   s->white_q_y[0] = 0;

   xor(s->white_bd, 1, 0);
   s->white_q_x[1] = 1;
   s->white_q_y[1] = 0;

   xor(s->white_bd, 0, 1);
   s->white_q_x[2] = 0;
   s->white_q_y[2] = 1;

   xor(s->white_bd, 6, 0);
   s->white_q_x[3] = 6;
   s->white_q_y[3] = 0;


   xor(s->black_bd, 8, 0);
   s->black_q_x[0] = 8;
   s->black_q_y[0] = 0;

   xor(s->black_bd, 2, 0);
   s->black_q_x[1] = 2;
   s->black_q_y[1] = 0;

   xor(s->black_bd, 2, 1);
   s->black_q_x[2] = 2;
   s->black_q_y[2] = 1;

   xor(s->black_bd, 2, 2);
   s->black_q_x[3] = 2;
   s->black_q_y[3] = 2;

   /*
      xor(s->blocks_bd, 1,1);
      xor(s->blocks_bd, 1,2);
      xor(s->blocks_bd, 0,2);
    */

   xor(s->blocks_bd, 3,0);
   xor(s->blocks_bd, 3,1);
   xor(s->blocks_bd, 3,2);
   xor(s->blocks_bd, 3,3);
   xor(s->blocks_bd, 0,3);
   xor(s->blocks_bd, 1,3);
   xor(s->blocks_bd, 2,3);

   xor(s->blocks_bd, 4,3);
   xor(s->blocks_bd, 4,4);
   xor(s->blocks_bd, 5,4);
   xor(s->blocks_bd, 6,4);
   xor(s->blocks_bd, 7,4);
   xor(s->blocks_bd, 8,4);
   xor(s->blocks_bd, 9,4);

   /*
      xor(s->blocks_bd, 4,2);
      xor(s->blocks_bd, 5,2);
      xor(s->blocks_bd, 6,2);
      xor(s->blocks_bd, 7,2);
      xor(s->blocks_bd, 8,2);
      xor(s->blocks_bd, 9,2);
    */

   /*
      xor(s->blocks_bd, 4,0);
      xor(s->blocks_bd, 4,1);
      xor(s->blocks_bd, 5,0);
      xor(s->blocks_bd, 5,1);
    */



   /*
      xor(s->blocks_bd, 5,0);
      xor(s->blocks_bd, 5,1);
      xor(s->blocks_bd, 6,1);
      xor(s->blocks_bd, 7,0);
      xor(s->blocks_bd, 7,1);
      xor(s->blocks_bd, 8,1);
      xor(s->blocks_bd, 9,1);
      xor(s->blocks_bd, 9,0);
    */


   return 0;
}

#ifndef GAMAZONS
/*==============================================================================
 * main 
 *
 *
 */
int main(int argc, char *argv[])
{
   state *s;
   //struct move m;
   move temp;
   int i;

   // Initialize game states
   for (i=0; i<100; i++)
      states.s[i] = (state *) malloc(sizeof(state));
   states.current_state = 0;
   states.max_state = 0;
   s = states.s[0];

   parse_args(argc, argv);
   meta_init();
   init(s);

   printf("size of move = %d\n", sizeof(move));
   printf("size of state = %d\n", sizeof(state));

   pboard(*s);

   //test_fdiag(s);
   //test_bdiag(s);
   //test_gen_web_stream(s);
   //test_put_col(s);
   //test_put_row(s);
   //test_put_fdiag(s);
   //test_put_bdiag(s);

#ifdef DEBUG_HEVAL
   xor(s->white_bd, 9, 3);
   xor(s->white_bd, 8, 2);
   s->white_q_x[3] = 8;
   s->white_q_y[3] = 2;
   xor(s->blocks_bd, 8, 3);
   s->turn = BLACK_PLAYER;

   pboard(*s);
   printf("board value is %d\n", HEVAL(s));

   pbvec(s->white_bd[0], s->white_bd[1]);
#endif

#ifndef DEBUG_HEVAL

   /* the main play loop. Gets a move, does a move, repeats.
      lobal ok is set to 1 for use with timeouts 
    */
   for (;;)
     {
      dup_state(s, states.s[++(states.current_state)]);
      s = states.s[states.current_state];
      if (states.current_state > states.max_state)
	 states.max_state = states.current_state;

      if (options.white_player == HUMAN)
       	{
	 temp = getmove(s, 1);
	 makemove(s, temp);
	 onmove++;
	 pboard(*s);
       	}
      else
       	{
	 ok = 1;
	 start = time(NULL);
	 temp = isearch(s, NOTHINK);
	 printf("WHITE selected: ");
	 pmove(temp);
	 makemove(s,temp);
	 onmove++;
	 pboard(*s);
       	}

      dup_state(s, states.s[++(states.current_state)]);
      s = states.s[states.current_state];
      if (states.current_state > states.max_state)
	 states.max_state = states.current_state;

      if (options.black_player == HUMAN)
       	{
	 temp = getmove(s, 2);
	 makemove(s, temp);
	 onmove++;
	 pboard(*s);
       	}
      else
       	{
	 ok = 1;
	 start = time(NULL);
	 temp = isearch(s, NOTHINK);
	 printf("BLACK selected: ");
	 pmove(temp);
	 makemove(s,temp);
	 onmove++;
	 pboard(*s);
       	}
     }
#endif

   return 0;

}
#endif //ifndef GAMAZONS


#ifdef GAMAZONS
/*==============================================================================
 * init_engine
 *
 * 
 * 
 */
void init_engine()
{
   state *s;
   //struct move m;
   move temp;
   int i;
   char *home_env;

   srand(time(NULL));

   // Initialize game states
   for (i=0; i<100; i++)
      states.s[i] = (state *) malloc(sizeof(state));
   states.current_state = 0;
   states.max_state = 0;

   s = states.s[0];
   s->turn = WHITE_PLAYER;
   s->winner = 0;
   state_hash = create_hash(s);


   meta_init();
   init(s);
   dup_state(s, states.s[++(states.current_state)]);

   /* set default options */
   options.engine.maxdepth=20;
   options.engine.maxwidth=3000;
   options.engine.timeout=1;
   options.white_player=HUMAN;
   options.black_player=HUMAN;
   options.print_statistics=FALSE;

   home_env = getenv("HOME");
   strcpy(options.hist_dir, home_env);
   strcat(options.hist_dir, "/");


   if (!load_images_from_theme(PACKAGE_DATA_DIR "/gamazons/default.theme"))
     {
      fprintf(stderr, "Cannot find theme file %s\n", PACKAGE_DATA_DIR "/gamazons/default.theme");
      exit(1);
     }

#ifdef DEBUG
   printf("white piece image = %s\n", options.images.white_piece);
#endif
   load_values_from_file();

}


/*==============================================================================
 * load_values_from_file
 *
 * If a .gamazons file is found in the user's home directory, it will attempt to
 * load the values stored therein.  Any variables it doesn't recognize will be
 * silently ignored.
 */
void load_values_from_file()
{
   char *home, file[256];
   FILE *rc_fd;
   char variable[256];
   char buffer[256];
   int value;
   char ch;


   if (!(home = getenv("HOME")))
      return;

   strcpy(file, home);
   strcat(file, "/.gamazons");
#ifdef DEBUG
   printf("looking for the file %s\n", file);
#endif

   rc_fd = fopen(file, "r");
   if(rc_fd == NULL)
      return;

   while (fscanf(rc_fd, "%s", variable) != EOF)
     {
      while (ch = fgetc(rc_fd))
	{
	 if (ch == EOF)
	    return;
	 if (ch == '=')
	    break;
	}

      if (strcmp(variable, "WHITE_PLAYER") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 options.white_player = value;
	}
      else if (strcmp(variable, "BLACK_PLAYER") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 options.black_player = value;
	}
      else if (strcmp(variable, "TIMEOUT") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 if (value > 0)
	    options.engine.timeout = value;
	 else
	    options.engine.timeout = 1;
	}
      else if (strcmp(variable, "MAXWIDTH") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 if (value > 0)
	    options.engine.maxwidth = value;
	 else
	    options.engine.maxwidth = 1;
	}
      else if (strcmp(variable, "MAXDEPTH") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 if (value > 0)
	    options.engine.maxdepth = value;
	 else
	    options.engine.maxdepth = 1;
	}
      else if (strcmp(variable, "REPLAY_DELAY") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 if (value > 0)
	    options.replay_delay = value;
	 else
	    options.replay_delay = 1;
	}
      else if (strcmp(variable, "MOVEMENT_SPEED") == 0)
	{
	 fscanf(rc_fd, "%d", &value);
	 if (value > 0 && value <= 10)
	    options.movement_speed = value;
	 else
	    options.movement_speed = 1;
	}
      else if (strcmp(variable, "WHITE_PIECE") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 strcpy(options.images.white_piece, buffer);
	}
      else if (strcmp(variable, "BLACK_PIECE") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 strcpy(options.images.black_piece, buffer);
	}
      else if (strcmp(variable, "WHITE_SQUARE") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 strcpy(options.images.white_sq, buffer);
	}
      else if (strcmp(variable, "GREY_SQUARE") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 strcpy(options.images.grey_sq, buffer);
	}
      else if (strcmp(variable, "ARROW_SQUARE") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 strcpy(options.images.arrow_sq, buffer);
	}
      else if (strcmp(variable, "HIST_DIR") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 strcpy(options.hist_dir, buffer);
	}
      else if (strcmp(variable, "DRAW_GRID") == 0)
	{
	 fscanf(rc_fd, "%s", buffer);
	 if (strcmp(buffer, "TRUE") == 0)
	    options.images.grid = TRUE;
	 else
	    options.images.grid = FALSE;
	}


     }

   fclose(rc_fd);

}

/*==============================================================================
 * store_values_in_file
 *
 * Creates/overwrites a .gamazons file in the user's home directory.  Stores
 * the values in the options struct in it.
 */
void store_values_in_file()
{
   char *home, file[256];
   FILE *rc_fd;
#ifdef GAMAZONS
   GtkWidget *delay = (GtkWidget *)lookup_widget(main_window, "ReplayDelaySpinner");
   GtkWidget *speed = (GtkWidget *)lookup_widget(main_window, "MovementSpeedSpinner");
#endif

   if (!(home = getenv("HOME")))
      return;

   strcpy(file, home);
   strcat(file, "/.gamazons");
#ifdef DEBUG
   printf("looking for the file %s\n", file);
#endif

   rc_fd = fopen(file, "w");
   if (rc_fd == NULL)
      return;
   
   fprintf(rc_fd, "WHITE_PLAYER = ");
   fprintf(rc_fd, "%d\n", options.white_player);

   fprintf(rc_fd, "BLACK_PLAYER = ");
   fprintf(rc_fd, "%d\n", options.black_player);

   fprintf(rc_fd, "TIMEOUT = ");
   fprintf(rc_fd, "%d\n", options.engine.timeout);

   fprintf(rc_fd, "MAXWIDTH = ");
   fprintf(rc_fd, "%d\n", options.engine.maxwidth);

   fprintf(rc_fd, "MAXDEPTH = ");
   fprintf(rc_fd, "%d\n", options.engine.maxdepth);

   fprintf(rc_fd, "WHITE_PIECE = ");
   fprintf(rc_fd, "%s\n", options.images.white_piece);

   fprintf(rc_fd, "BLACK_PIECE = ");
   fprintf(rc_fd, "%s\n", options.images.black_piece);

   fprintf(rc_fd, "WHITE_SQUARE = ");
   fprintf(rc_fd, "%s\n", options.images.white_sq);

   fprintf(rc_fd, "GREY_SQUARE = ");
   fprintf(rc_fd, "%s\n", options.images.grey_sq);

   fprintf(rc_fd, "ARROW_SQUARE = ");
   fprintf(rc_fd, "%s\n", options.images.arrow_sq);

   fprintf(rc_fd, "HIST_DIR = ");
   fprintf(rc_fd, "%s\n", options.hist_dir);

   fprintf(rc_fd, "DRAW_GRID = ");
   if (options.images.grid == TRUE)
      fprintf(rc_fd, "%s\n", "TRUE");
   else
      fprintf(rc_fd, "%s\n", "FALSE");

#ifdef GAMAZONS
   fprintf(rc_fd, "REPLAY_DELAY = ");
   options.replay_delay = gtk_spin_button_get_value_as_int((GtkSpinButton *)delay);
   fprintf(rc_fd, "%d\n", options.replay_delay);

   fprintf(rc_fd, "MOVEMENT_SPEED = ");
   options.movement_speed = gtk_spin_button_get_value_as_int((GtkSpinButton *)speed);
   fprintf(rc_fd, "%d\n", options.movement_speed);
#endif

   fclose(rc_fd);
}

/*==============================================================================
 * load_images_from_theme
 *
 * This file will read image paths from a theme file.  These values get loaded 
 * into the options struct, and subsequently used to draw the board.
 */
int load_images_from_theme(char *theme)
{
   char *home, file[256];
   FILE *theme_fd;
   char variable[256];
   char buffer[256];
   int value;
   char ch;


   theme_fd = fopen(theme, "r");
   if(theme_fd == NULL)
     {
      fprintf(stderr, "Can't open theme file %s\n", theme);
      return FALSE;
     }

   while (fscanf(theme_fd, "%s", variable) != EOF)
     {
      while (ch = fgetc(theme_fd))
	{
	 if (ch == EOF)
	    return TRUE;
	 if (ch == '=')
	    break;
	}

      if (strcmp(variable, "WHITE_PIECE") == 0)
	{
	 fscanf(theme_fd, "%s", buffer);
	 strcpy(options.images.white_piece, PACKAGE_DATA_DIR "/pixmaps/gamazons/");
	 strcat(options.images.white_piece, buffer);
	}
      else if (strcmp(variable, "BLACK_PIECE") == 0)
	{
	 fscanf(theme_fd, "%s", buffer);
	 strcpy(options.images.black_piece, PACKAGE_DATA_DIR "/pixmaps/gamazons/");
	 strcat(options.images.black_piece, buffer);
	}
      else if (strcmp(variable, "WHITE_SQUARE") == 0)
	{
	 fscanf(theme_fd, "%s", buffer);
	 strcpy(options.images.white_sq, PACKAGE_DATA_DIR "/pixmaps/gamazons/");
	 strcat(options.images.white_sq, buffer);
	}
      else if (strcmp(variable, "GREY_SQUARE") == 0)
	{
	 fscanf(theme_fd, "%s", buffer);
	 strcpy(options.images.grey_sq, PACKAGE_DATA_DIR "/pixmaps/gamazons/");
	 strcat(options.images.grey_sq, buffer);
	}
      else if (strcmp(variable, "ARROW_SQUARE") == 0)
	{
	 fscanf(theme_fd, "%s", buffer);
	 strcpy(options.images.arrow_sq, PACKAGE_DATA_DIR "/pixmaps/gamazons/");
	 strcat(options.images.arrow_sq, buffer);
	}
      else if (strcmp(variable, "DRAW_GRID") == 0)
	{
	 fscanf(theme_fd, "%s", buffer);
	 if (strcmp(buffer, "TRUE") == 0)
	    options.images.grid = TRUE;
	 else
	    options.images.grid = FALSE;
	}


     }

   fclose(theme_fd);
   return TRUE;
}
#endif

/*============================================================================== 
 * print_usage_menu 
 *
 * Displays a list of all command line options
 */
void print_usage_menu()
{
   printf("Amazons Usage:\n");
   printf("amazons [OPTIONS]\n");
   printf("     -d #:   Sets the maximum search depth\n");
   printf("     -h:     Prints this help menu\n");
   printf("     -p #:   User plays against the computer (1 white, 2 black)\n");
   printf("     -s:     Prints out interesting statistics\n");
   printf("     -t #:   Sets the time limit between moves\n");
   printf("\n\n");
}


/* parse args
 *
 * Handles the arguments passed into the program.  
 *
 * Note: this expects all arguments to be listed separately, 
 * each with it's own '-'
 */
void parse_args(int argc, char *argv[])
{
   int i = 1;

   //Set defaults
   options.engine.maxdepth=20;
   options.engine.maxwidth=5000;
   options.engine.timeout=2;
   options.white_player=HUMAN;
   options.black_player=AI;
   options.print_statistics=FALSE;


   while (i < argc)
     {
      switch(argv[i][1])
       	{
	  case 'd':
	      options.engine.maxdepth = atoi(argv[++i]);
	      i++;
	      break;
	  case 'h':
	      print_usage_menu();
	      exit(0);
	  case 'p':
	      if (atoi(argv[++i]) == 1)
		 options.white_player = HUMAN;
	      else
		 options.black_player = HUMAN;
	      i++;
	      break;
	  case 'f':
#ifdef DEBUG
	      printf("opening movin\n");
#endif
	      movin = fopen(argv[++i], "r+");
#ifdef DEBUG
	      printf("success\n");
	      printf("opening movout\n");
#endif
	      movout = fopen(argv[++i], "r+");
#ifdef DEBUG
	      printf("success\n");
#endif
	      //fprintf(fifop, "wubba wubba\n");
	      //fflush(fifop);
	      //printf("open success\n");
	      i++;
	      break;
	  case 's':
	      options.print_statistics = TRUE;
	      i++;
	      break;
	  case 't':
	      options.engine.timeout = atoi(argv[++i]);
	      i++;
	      break;
	  case 'w':
	      options.engine.maxdepth = atoi(argv[++i]);
	      i++;
	      break;
	  default:
	      printf("Unknown argument  %s\n", argv[i]);
	      print_usage_menu();
	      exit(1);
       	}
     }
}


void print_stats()
{

   printf("TT Stats:\n");
   printf("   # nodes over written: %d\n", tt_overwrite);
   printf("   # of nodes stored:    %d\n", tt_stores);
   printf("   # of updates made:    %d\n", tt_updates);
   printf("   # of lookups made:    %d\n", tt_lookups);
   printf("   # of lookups found:   %d\n", tt_lookup_finds);
   printf("\n");
   printf("Heuristic Stats:\n");
   printf("   # of heuristic calls  %d\n", heval_calls);
}

void dup_state(state *s_old, state *s_new)
{
   int i;

   s_new->white_bd[0] = s_old->white_bd[0];
   s_new->white_bd[1] = s_old->white_bd[1];

   s_new->blocks_bd[0] = s_old->blocks_bd[0];
   s_new->blocks_bd[1] = s_old->blocks_bd[1];

   s_new->black_bd[0] = s_old->black_bd[0];
   s_new->black_bd[1] = s_old->black_bd[1];

   for (i=0; i<4; i++)
     {
      s_new->white_q_x[i] = s_old->white_q_x[i]; 
      s_new->black_q_x[i] = s_old->black_q_x[i];

      s_new->white_q_y[i] = s_old->white_q_y[i]; 
      s_new->black_q_y[i] = s_old->black_q_y[i]; 
     }

   s_new->turn = s_old->turn;
#ifdef DEBUG
   printf("old turn is %d, new turn is %d\n", s_old->turn, s_new->turn);
#endif
   s_new->value = s_old->value;
   s_new->depth = s_old->depth;
   s_new->winner = s_old->winner;
}


