#include <time.h>
#include <assert.h>
#include <gnome.h>

#include "amazons.h"
#include "board.h"
#include "callbacks.h"

/* local Prototypes */


static void fill_a_square(GnomeCanvasGroup *group,
       	double x1, double y1, double x2, double y2, char *color);
static void get_square_color(int square, char *color);
static void draw_a_line(GnomeCanvasGroup *group, 
	int x1, int y1, int x2, int y2, char *color);
static void draw_grid();


/* Globals */
extern Board *board;
extern struct options options;
extern struct game_states states;
extern int ok;
extern time_t start;
extern GtkWidget *main_window;
extern int new_game;
Square legal_moves[100];
int state_hash;

static Board_State bstate;


void init_game_board(GtkWidget *GamazonsMain)
{
   int i,j;
   char color[256];
   GtkWidget *w = (GtkWidget *) lookup_widget(GamazonsMain, BOARD_NAME);
   GtkWidget *force_button, *undo_button;
   GtkTextView *view;
   GtkTextBuffer *buffer;
   static int first_run = TRUE;
   
   if (w == NULL)
      printf("Couldn't find board!!!!!!!!\n");

   board = (Board *) malloc(sizeof(Board));
   board->canvas = GNOME_CANVAS(w);
   board->root = GNOME_CANVAS_GROUP(gnome_canvas_item_new(gnome_canvas_root(board->canvas),
	       gnome_canvas_group_get_type(),
	       NULL));
   
   gnome_canvas_set_scroll_region(board->canvas, 0.0, 0.0,
	   400.0,
	   400.0);


   /* initialize pieces */
   for (i=0; i<BOARD_SIZE; i++)
     {
      for (j=0; j<BOARD_SIZE; j++)
	{
	 board->squares[i][j] = NOTHING;
	}
     }
   gtk_signal_connect(GTK_OBJECT(board->canvas), "event",
	   GTK_SIGNAL_FUNC(arrow_fire_cb), NULL);

   //Place amazon queens on the board
   board->squares[9][3] = WHITE;
   board->squares[9][6] = WHITE;
   board->squares[6][0] = WHITE;
   board->squares[6][9] = WHITE;

   board->squares[0][3] = BLACK;
   board->squares[0][6] = BLACK;
   board->squares[3][0] = BLACK;
   board->squares[3][9] = BLACK;

   board->square_to_wh_queen_map[0] = 96;
   board->square_to_wh_queen_map[1] = 93;
   board->square_to_wh_queen_map[2] = 60;
   board->square_to_wh_queen_map[3] = 69;

   board->square_to_bl_queen_map[0] = 3;
   board->square_to_bl_queen_map[1] = 6;
   board->square_to_bl_queen_map[2] = 30;
   board->square_to_bl_queen_map[3] = 39;

   //Set up move history window
   view = (GtkTextView *) lookup_widget(main_window, "textview1");
   buffer = gtk_text_buffer_new(NULL);
   gtk_text_view_set_buffer(view, buffer);

   //Initialize buttons
   force_button = (GtkWidget *)lookup_widget(main_window, "BT_FORCEMOVE");
   gtk_widget_set_sensitive (force_button, FALSE);
   undo_button = (GtkWidget *)lookup_widget(main_window, "BT_UNDO");
   gtk_widget_set_sensitive (undo_button, FALSE);
   
   draw_board();
   if (first_run)
     {
      first_run = FALSE;
      bstate_set_just_finished(START_GAME);
     }

}


void fill_a_square(GnomeCanvasGroup *group,
       	double x1, double y1, double x2, double y2, char *color)
{
   /* draw a box*/
   gnome_canvas_item_new(group,
	   gnome_canvas_rect_get_type(),
	   "x1", x1,
	   "y1", y1,
	   "x2", x2,
	   "y2", y2,
	   "outline_color", "black",
	   "fill_color", color,
	   "width_pixels", (double)THICKNESS,
	   NULL, NULL);

}

static void get_square_color(int square, char *color)
{
   if ((square % 2) == 0)
      strcpy(color, SQUARE_COLOR_1);
   else
      strcpy(color, SQUARE_COLOR_2);
}


static void draw_grid()
{
   int x,y;

   for (x=0; x<=10; x++)
     {
      for (y=0; y<=10; y++)
	{
	 //draw horiz
	 draw_a_line(board->root, //gnome_canvas_root(board->canvas),
		 0, y*CELL_SIZE, BOARD_SIZE*CELL_SIZE, y*CELL_SIZE, "black");

	 //draw vert
	 draw_a_line(board->root, //gnome_canvas_root(board->canvas),
		 x*CELL_SIZE, 0, x*CELL_SIZE, BOARD_SIZE*CELL_SIZE, "black");
	}
     }


}

static void draw_a_line(GnomeCanvasGroup *group,
       	int x1, int y1, int x2, int y2, char *color)
{
   GnomeCanvasPoints *points;

   /* allocate a new points array */
   points = gnome_canvas_points_new (2);

   /* fill out the points */
   points->coords[0] = x1;
   points->coords[1] = y1;
   points->coords[2] = x2;
   points->coords[3] = y2;
   /* draw the line */
   gnome_canvas_item_new(group,
	   gnome_canvas_line_get_type(),
	   "points", points,
	   "fill_color", color,
	   "width_units", (double)THICKNESS,
	   NULL);

   /* free the points array */
   gnome_canvas_points_free(points);
}

void draw_board()
{
   int i,j,k;
   int black_i = 0;
   GdkPixbuf *white_pb, *black_pb;
   GdkPixbuf *white_sq, *grey_sq, *arrow_sq;
   char color[256];
   GnomeCanvasItem *image;
   GnomeCanvasGroup *root = GNOME_CANVAS_GROUP(gnome_canvas_root (GNOME_CANVAS (board->canvas)));
   static int first_game = 1;
   


   /* Find images */
   white_pb = gdk_pixbuf_new_from_file(options.images.white_piece, NULL);
   if (white_pb == NULL)
     {
      fprintf(stderr, "Cannot find white piece image: %s\n", options.images.white_piece);
      exit(1);
     }

   black_pb = gdk_pixbuf_new_from_file(options.images.black_piece, NULL);
   if (black_pb == NULL)
     {
      fprintf(stderr, "Cannot find black piece image: %s\n", options.images.black_piece);
      exit(1);
     }

   white_sq = gdk_pixbuf_new_from_file(options.images.white_sq, NULL);
   if (white_sq == NULL)
     {
      fprintf(stderr, "Cannot find white square image: %s\n", options.images.white_sq);
      exit(1);
     }

   grey_sq = gdk_pixbuf_new_from_file(options.images.grey_sq, NULL);
   if (grey_sq == NULL)
     {
      fprintf(stderr, "Cannot find grey square image: %s\n", options.images.grey_sq);
      exit(1);
     }
   arrow_sq = gdk_pixbuf_new_from_file(options.images.arrow_sq, NULL);
   if (arrow_sq == NULL)
     {
      fprintf(stderr, "Cannot find arrow square image: %s\n", options.images.arrow_sq);
      exit(1);
     }



   /* fill alternate squares */
   for(j=0;j<BOARD_SIZE;j++) 
     {
      for(i=0;i<BOARD_SIZE;i++) 
	{
	 board->square_items[j*10+i] = NULL;
	 if ((i + j) % 2)
	   {
	    board->square_items[j*10+i] = gnome_canvas_item_new (board->root,
		    gnome_canvas_pixbuf_get_type (),
		    "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
		    "width", CELL_SIZE, "height", CELL_SIZE,
		    "width_set", TRUE, "height_set", TRUE,
		    "pixbuf", grey_sq,
		    NULL);
	   }
	 else
	   {
	    board->square_items[j*10+i] = gnome_canvas_item_new (board->root,
		    gnome_canvas_pixbuf_get_type (),
		    "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
		    "width", CELL_SIZE, "height", CELL_SIZE,
		    "width_set", TRUE, "height_set", TRUE,
		    "pixbuf", white_sq,
		    NULL);
	   }



	 //Place the queen images on the board in the right order
	 if (board->squares[j][i] == WHITE)
	   {
#ifdef DEBUG
	    printf("Square %c%c contains a white queen\n",i+'a',10-j+'0');
#endif
	    image = gnome_canvas_item_new (board->root,
		    gnome_canvas_pixbuf_get_type (),
		    "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
		    "width", CELL_SIZE, "height", CELL_SIZE,
		    "width_set", TRUE, "height_set", TRUE,
		    "pixbuf", white_pb,
		    NULL);
	    //We need to do some funky checking to make sure board->white_queens[] matches
	    //up exactly with state->white_q_x[], state->white_q_y[]
	    for (k=0; k<4; k++)
	      {
	       if(j*10 +i == board->square_to_wh_queen_map[k])
		 {
		  board->white_queens[k] = image;
#ifdef DEBUG
		  printf("registering queen %d\n", k);
#endif
		  break;
		 }
	      }

#ifdef DEBUG
	    printf("connecting signal to queen\n");
#endif
	    gtk_signal_connect(GTK_OBJECT(image), "event",
		    GTK_SIGNAL_FUNC(board_press_cb), NULL);
	   }
	 else if (board->squares[j][i] == BLACK)
	   {
#ifdef DEBUG
	    printf("Square %c%c contains a black queen\n",i+'a',10-j+'0');
#endif
	    image = gnome_canvas_item_new (board->root,
		    gnome_canvas_pixbuf_get_type (),
		    "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
		    "width", CELL_SIZE, "height", CELL_SIZE,
		    "width_set", TRUE, "height_set", TRUE,
		    "pixbuf", black_pb,
		    NULL);
	    for (k=0; k<4; k++)
	      {
	       if(j*10 +i == board->square_to_bl_queen_map[k])
		 {
		  board->black_queens[k] = image;
#ifdef DEBUG
		  printf("registering queen %d\n", k);
#endif
		  break;
		 }
	      }

#ifdef DEBUG
	    printf("connecting signal to queen\n");
#endif
	    gtk_signal_connect(GTK_OBJECT(image), "event",
		    GTK_SIGNAL_FUNC(board_press_cb), NULL);
	   }
	 else if (board->squares[j][i] == ARROW)
	   {
	    image = gnome_canvas_item_new (board->root,
		    gnome_canvas_pixbuf_get_type (),
		    "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
		    "width", CELL_SIZE, "height", CELL_SIZE,
		    "width_set", TRUE, "height_set", TRUE,
		    "pixbuf", arrow_sq,
		    NULL);
	   }
	    

	}
     }

   if (options.images.grid == TRUE)
      draw_grid();

   /*
   image = gnome_canvas_item_new (root,
	   gnome_canvas_pixbuf_get_type (),
	   "x", 10.0, "y", 10.0,
	   "width", 40.0, "height", 40.0,
	   "width_set", TRUE, "height_set", TRUE,
	   "pixbuf", white_pb,
	   NULL);
	   */


   gtk_widget_show_now(main_window);
   gtk_widget_queue_draw ((GtkWidget *) board->canvas);
   gtk_widget_show_now((GtkWidget *) board->canvas);
}



void mark_square (GnomeCanvasItem *square)
{
   gnome_canvas_item_set (square, "outline_color", "red", NULL);
}

Square get_square (double x, double y)
{
   Square from;
   int x_square;
   int y_square;

   /*
   x -= (BOARD_BORDER - CELL_PAD);
   y -= (BOARD_BORDER - CELL_PAD);
   */

   if (x < 0)
      x = 0.0;
   else if (x > ((BOARD_SIZE-1) * CELL_SIZE))
      x = (BOARD_SIZE-1) * CELL_SIZE;
   if (y < 0)
      y = 0.0;
   else if (y > ((BOARD_SIZE-1) * CELL_SIZE))
      y = (BOARD_SIZE-1) * CELL_SIZE;

   x_square = x / CELL_SIZE;
   y_square = y / CELL_SIZE;

#ifdef DEBUG
   printf("x coord = %f   y coord = %f\n", x, y);
   printf("x coord = %d   y coord = %d\n", x_square, y_square);
#endif

   from = x_square + y_square * 10;

   return from;
}

void clear_square (GnomeCanvasItem **square)
{
   gnome_canvas_item_set (*square, "outline_color", NULL, NULL);
   *square = NULL;
}

/*==============================================================================
 * try_move
 *
 * Attempts to move a piece from one square to the next.  If the piece successfully
 * arrives to its destination, it returns TRUE.  If the move is aborted, returns
 * FALSE
 */
int try_move (Board *board, GnomeCanvasItem *item)
{
   double Lx, Uy, Rx, By;
   double to_Lx, to_Uy;
   int x, y;
   int inc = 1;
   int i,j;

   to_Lx = get_x_from_square(board->to);
   to_Uy = get_y_from_square(board->to);
      
#ifdef DEBUG
   printf("We want the queen at coords %f, %f\n", to_Lx, to_Uy);
#endif
   gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
#ifdef DEBUG
   printf("The queen is at coords %f, %f\n", Lx, Uy);
#endif
   while (Lx != to_Lx || Uy != to_Uy)
     {
      bstate_set_moving_piece(TRUE);
      if (Lx < to_Lx)
	 x = inc;
      else if (Lx > to_Lx)
	 x = -inc;
      else
	 x = 0;

      if (Uy < to_Uy)
	 y = inc;
      else if (Uy > to_Uy)
	 y = -inc;
      else
	 y = 0;


      gnome_canvas_item_move (item, (double)x, (double)y);
      gnome_canvas_item_raise_to_top (item);

      //update the board
      while (gtk_events_pending())
	 gtk_main_iteration();

      if (bstate_get_quit_game())
	 exit(0);

      if (bstate_get_stop_moving())
	{
	 bstate_set_stop_moving(FALSE);
	 return FALSE;
	}
      gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
     }

   gnome_canvas_item_raise_to_top (item);
   bstate_set_moving_piece(FALSE);
	   //see where it landed
   gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
#ifdef DEBUG
   printf("The queen landed at coords %f, %f\n", Lx, Uy);
   printf("this time the queen is on square %d\n", board->to);
#endif
   return TRUE;
}


double get_x_from_square(int sq)
{
   double x;

   x = (double) ((sq % 10) * CELL_SIZE+QUEEN_OFFSET);

   return x;

}

double get_y_from_square(int sq)
{
   double y;

   y = (double) ((sq / 10) * CELL_SIZE+QUEEN_OFFSET);

   return y;


}

int get_x_int_from_square(int sq)
{
   return(sq % 10);
}

int get_y_int_from_square(int sq)
{
   return(sq / 10);
}

int get_grid_num_from_square(int sq)
{
   return(10 - sq/10);
}

char get_grid_alpha_from_square(int sq)
{
   return('a' + sq % 10);
}

int engine_x_to_board_x(int eng_x)
{
   return(eng_x);//hey, these are the same, no conversion necessary
}

int engine_y_to_board_y(int eng_y)
{
   return(9 - eng_y);
}

int board_x_to_engine_x(int brd_x)
{
   return(brd_x);
}

int board_y_to_engine_y(int brd_y)
{
   return(9 - brd_y);
}

int get_square_from_engine(int x, int y)
{
   return((9 - y) * 10 + x);
}


void fire_arrow(Square sq)
{
   int x,y;
   GdkPixbuf *arrow_sq;
   GnomeCanvasItem *image;
   GnomeCanvasGroup *root = GNOME_CANVAS_GROUP(gnome_canvas_root (GNOME_CANVAS (board->canvas)));

   x = sq % 10;
   y = sq / 10;

   board->squares[y][x] = ARROW;

   arrow_sq = gdk_pixbuf_new_from_file(options.images.arrow_sq, NULL);
   if (arrow_sq == NULL)
     {
      fprintf(stderr, "Cannot find arrow image: %s\n", options.images.arrow_sq);
      exit(1);
     }

   image = gnome_canvas_item_new (board->root,
	   gnome_canvas_pixbuf_get_type (),
	   "x", x*CELL_SIZE+QUEEN_OFFSET, "y", y*CELL_SIZE+QUEEN_OFFSET,
	   "width", CELL_SIZE, "height", CELL_SIZE,
	   "width_set", TRUE, "height_set", TRUE,
	   "pixbuf", arrow_sq,
	   NULL);

}

void square_contains(Square sq)
{
   int row, col;

   col = get_x_int_from_square(sq);
   row = get_y_int_from_square(sq);

   if (board->squares[row][col] == NOTHING)
      printf("Nothing is found at square %d\n", sq);
   else if (board->squares[row][col] == WHITE)
      printf("A White Queen is found at square %d\n", sq);
   else if (board->squares[row][col] == BLACK)
      printf("A Black Queen is found at square %d\n", sq);
   else if (board->squares[row][col] == ARROW)
      printf("An arrow is found at square %d\n", sq);
   else
      printf("Whoa, I don't know _what_ is on square %d\n", sq);
}


/*==============================================================================
 * move_ai
 *
 * Checks to see if an AI oppenent is next to move.  If it is, it starts the 
 * move process, and checks for a win afterwards.  If not, it just checks for 
 * the win.  Returns TRUE if an AI opponent moves next.  False if human.
 *
 * NOTE: If you have 2 AI players, this function would just keep thinking and 
 * never let the board update or respond.  So there are several checks to see
 * if any new events occured that should be handled, or critical changes have
 * been made (like starting a new game, etc..).  If something critical has changed
 * the function will exit after learning about it.
 */
int move_ai()
{
   state *s = states.s[states.current_state];
   move temp;
   move movelist[3000];
   int ai = FALSE;
   int current_hash;
   //GtkWidget *auto_button, *force_button;

   current_hash = state_hash = create_hash(s);

   //It's sometimes necessary to know if we're in the middle of a move, because
   //if an event causes another move to start and that event is processed and then
   //this function finishes, it leaves the board in an unstable result

   //XXX This should call a function to disable certain event handling instead of
   //just having a silly global variable.  For instance, it could gray out the
   //Auto Finish button so the user knows it's not going to do anything when he 
   //presses it.  Perhaps the 'Force Move' button should be greyed out until the AI
   //is thinking, or since Force Move & Auto Finish are mutually exclusive, it would
   //be cool to have the button switch labels depending on the state of the game.
   /*
   moving_ai = TRUE;
   auto_button = (GtkWidget *) lookup_widget(main_window, "BT_AUTOFINISH");
   force_button = (GtkWidget *) lookup_widget(main_window, "BT_FORCEMOVE");
   gtk_widget_set_sensitive (auto_button, FALSE);
   gtk_widget_set_sensitive (force_button, TRUE);
   */




   //quit this function if a 'New Game' option was selected since this
   //function was started.
   if (bstate_get_new_game())
     {
      bstate_set_new_game(FALSE);
      return FALSE;
     }

   //gnome_canvas_item_request_update(board->canvas);
   /*
   if (((states.s[states.current_state]->turn == WHITE_PLAYER) && (options.white_player == AI)) ||
       ((states.s[states.current_state]->turn == BLACK_PLAYER) && (options.black_player == AI)))
     {
      what_next = WAIT_FOR_AI;
      update_status_bar();
     */
      ok = 1;
      ai = TRUE;
      start = time(NULL);
      temp = isearch(s, NOTHINK);
      if (s->winner) //XXX does this if statement do any good?  I thot winner was handled elsewhere
	 return FALSE;
      makemove(s,temp);

      //update the board before drawing the new move
      //the program would segfault if you closed it while it was thinking
      while (gtk_events_pending())
	 gtk_main_iteration();
      if (current_hash != state_hash)
	 return FALSE;

   if (bstate_get_new_game())
     {
      bstate_set_new_game(FALSE);
      return FALSE;
     }

   if (bstate_get_quit_game())
      exit(0);


      //register move on graphical board
      if (move_piece(temp))
	{
	 print_move_in_text_window(&temp);
	 dup_state(s, states.s[++(states.current_state)]);
	}
      else
	 return FALSE;
      /*
     }
   else
     {
#ifdef DEBUG
      printf("the AI doesn't move next:\n");
#endif
     }
     */

   /*
   if (s->turn == WHITE_PLAYER)
      what_next = MOVE_WHITE_QUEEN;
   if (s->turn == BLACK_PLAYER)
      what_next = MOVE_BLACK_QUEEN;
   update_status_bar();
   */
   bstate_set_just_finished(WAIT_FOR_AI);
      

#ifdef DEBUG
   if (options.white_player == AI)
      printf("White is AI\n");
   if (options.black_player == AI)
      printf("Black is AI\n");
   printf("Turn is %d\n", states.s[states.current_state]->turn );
#endif

   if (game_over(movelist))
     {
      //XXX should I set ai = FALSE?
      ai = FALSE;
      return (ai);
     }


   /*
   gtk_widget_set_sensitive (auto_button, TRUE);
   gtk_widget_set_sensitive (force_button, FALSE);
   moving_ai = FALSE;
   */
   return ai;
}

/*==============================================================================
 * move_piece
 *
 * Takes a move struct generated by the engine, and extracts the necessary info
 * to update the GUI data structs and have the GUI reflect the move.
 *
 * Returns FALSE if the move failed or aborted, TRUE if successful.
 */
int move_piece(move m)
{
   GnomeCanvasItem *item;
   int from_row, from_col;
   int to_row, to_col;

   board->to = get_square_from_engine(m.tocol, m.torow);
   to_col = get_x_int_from_square(board->to);
   to_row = get_y_int_from_square(board->to);
   //Note: by the time the state gets here, it's signaled the other player's turn
   //so if it says it's white's turn, black just moved and we need to move black's
   //piece.
   if (states.s[states.current_state]->turn == WHITE_PLAYER)
     {
      board->from = get_square_from_engine(states.s[states.current_state -1]->black_q_x[m.queen],
	      states.s[states.current_state -1]->black_q_y[m.queen]);
      
      board->squares[to_row][to_col] = BLACK;
#ifdef DEBUG
      printf("Moving black queen\n");
#endif
      item = board->black_queens[m.queen];
      board->square_to_bl_queen_map[m.queen] = to_row*10 +to_col;
     }
   else
     {
      board->from = get_square_from_engine(states.s[states.current_state -1]->white_q_x[m.queen],
	      states.s[states.current_state -1]->white_q_y[m.queen]);
      board->squares[to_row][to_col] = WHITE;
#ifdef DEBUG
      printf("Moving white queen\n");
#endif
      item = board->white_queens[m.queen];
      board->square_to_wh_queen_map[m.queen] = to_row*10 +to_col;
     }


   from_col = get_x_int_from_square(board->from);
   from_row = get_y_int_from_square(board->from);
   board->squares[from_row][from_col] = NOTHING;

   if (try_move(board, item))
      fire_arrow(get_square_from_engine(m.wallcol, m.wallrow));
   else 
      return FALSE;
#ifdef DEBUG
   printf("Engine coords for arrow: %d, %d\n", m.wallcol, m.wallrow);
   printf("fired arrow to square %d\n", get_square_from_engine(m.wallcol, m.wallrow));
   pmove(m);
#endif
   return TRUE;
}

/*==============================================================================
 * register_move_with_engine
 *
 * Fills out a move struct with the human's move and calls makemove() to update
 * the state struct, so the AI engine knows what happened.
 */
void register_move_with_engine(Square arrow_sq)
{
   state *s = states.s[states.current_state];
   move m;
   move movelist[3000];
   int move_count;
   int i;
   int tocol, torow;
   int found = FALSE;
   char move_str[32];
   char err_msg[256];

   //find out the index of the queen that was just moved.  
   //weird things will happen if it's not found.
   for (i=0; i<4; i++)
     {
      if (board->selected_queen == board->white_queens[i] || 
	  board->selected_queen == board->black_queens[i])
	{
	 found = TRUE;
	 break;
	}
     }

   if (!found)
      fprintf(stderr, "Error registering move w/ AI engine!  Game play will now be weird.\n");

   m.queen = i;
   m.torow = board_y_to_engine_y(get_y_int_from_square(board->to));
   m.tocol = board_x_to_engine_x(get_x_int_from_square(board->to));

   m.wallrow = board_y_to_engine_y(get_y_int_from_square(arrow_sq));
   m.wallcol = board_x_to_engine_x(get_x_int_from_square(arrow_sq));

   //make sure it's a valid move
   move_count = children(s, movelist);
   if (move_count == 0)
     {
      gnome_error_dialog("The AI engine thinks the game is over.  Please use the menu item Game->New to start a new game");
      return;
     }
   if (!move_lookup(&m, movelist, move_count))
     {
      get_move_str(&m, move_str);
      strcpy(err_msg, "You've hit a bug.  The following illegal move was just attempted: ");
      strcat(err_msg, move_str);
      gnome_error_dialog(err_msg);
      return;
     }

   makemove(s, m);
   print_move_in_text_window(&m);

}

/*==============================================================================
 * is_queen_square
 *
 * Compares the given square with the information stored in board->squares[][]
 * to see if a queen is there.
 */
int is_queen_square(Square sq)
{
   int row, col;

   col = get_x_int_from_square(sq);
   row = get_y_int_from_square(sq);

   if ((board->squares[row][col] == BLACK) ||
       (board->squares[row][col] == WHITE))
      return TRUE;
   else
      return FALSE;
}


/*==============================================================================
 * gen_legal_moves
 *
 * Given a square, this generates an array of all legal moves that can be made
 * from it.  This works for both queen movement, as well as firing an arrow, 
 * since both move the same way.
 *
 * The array terminator is 100
 */
void gen_legal_moves(Square sq)
{
   int arr_i = 0;
   int i;
   int row, col, sq_row, sq_col;
   int scanning;

   sq_col = get_x_int_from_square(sq);
   sq_row = get_y_int_from_square(sq);

   //make sure the player can drop the piece on the same square if he changes
   //his mind
   legal_moves[arr_i++] = sq;

   //get vertical moves
   row = sq_row + 1;
   col = sq_col;
   while (board->squares[row][col] == NOTHING && row < 10)
     {
      legal_moves[arr_i++] = (row*10) + col;
      row++;
     }

   row = sq_row - 1;
   while (board->squares[row][col] == NOTHING && row >= 0)
     {
      legal_moves[arr_i++] = (row*10) + col;
      row--;
     }

   //get horizontal moves
   row = sq_row;
   col = sq_col + 1;
   while (board->squares[row][col] == NOTHING && col < 10)
     {
      legal_moves[arr_i++] = (row*10) + col;
      col++;
     }

   col = sq_col - 1;
   while (board->squares[row][col] == NOTHING && col >= 0)
     {
      legal_moves[arr_i++] = (row*10) + col;
      col--;
     }

   //get forward diagonal moves
   row = sq_row + 1;
   col = sq_col + 1;
   while (board->squares[row][col] == NOTHING && col < 10 && row < 10)
     {
      legal_moves[arr_i++] = (row*10) + col;
      col++;
      row++;
     }

   row = sq_row - 1;
   col = sq_col - 1;
   while (board->squares[row][col] == NOTHING && col >= 0 && row >= 0)
     {
      legal_moves[arr_i++] = (row*10) + col;
      col--;
      row--;
     }

   //get backward diagonal moves
   row = sq_row + 1;
   col = sq_col - 1;
   while (board->squares[row][col] == NOTHING && col >= 0 && row < 10)
     {
      legal_moves[arr_i++] = (row*10) + col;
      col--;
      row++;
     }

   row = sq_row - 1;
   col = sq_col + 1;
   while (board->squares[row][col] == NOTHING && col < 10 && row >= 0)
     {
      legal_moves[arr_i++] = (row*10) + col;
      col++;
      row--;
     }


   legal_moves[arr_i] = 100;
#ifdef DEBUG
   printf("legal move list for %d of length %d: \n", sq, arr_i);
   i = 0;
   while (legal_moves[i] < 100)
      printf(" %d", legal_moves[i++]);
   printf("\n");
#endif

}

/*==============================================================================
 * is_move_legal
 *
 * Looks up the given square in the current legal_moves array.  If it doesn't 
 * exist, it's not a legal move and returns FALSE.  Returns TRUE if it is there.
 */
int is_move_legal(Square sq)
{
   int i=0;

#ifdef DEBUG
   printf("checking to see if a move is legal\n");
#endif
   while (legal_moves[i] < 100)
     {
      if (sq == legal_moves[i++])
	{
#ifdef DEBUG
	 printf("%d is a legal move\n", sq);
#endif
	 return TRUE;
	}
     }

#ifdef DEBUG
   printf("Can't move to square.  Legal moves are: %d\n", sq);
   i=0;
   while (legal_moves[i] < 100)
      printf(" %d", legal_moves[i++]);
   printf("\n");
#endif
   return FALSE;
}

/*==============================================================================
 * count_queens
 *
 * DEBUG - counts the number of queens on the GUI representation and prints
 * out a bunch of XXXX's whenever there are not 4 of both kinds.
 */ 
void count_queens()
{
   int black=0, white=0;
   int i,j;

   for(i=0; i<10; i++)
     {
      for(j=0; j<10; j++)
	{
	 if (board->squares[i][j] == WHITE)
	    white++;
	 if (board->squares[i][j] == BLACK)
	    black++;
	}
     }
   if (black > 4) 
      printf("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY Gained a black queen\n");
   if (white > 4)
      printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Gained a white queen\n");
   if (black < 4)
      printf("XYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXXYXYX Lost a black queen\n");
   if (white < 4)
      printf("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ Lost a white queen\n");
}



/*==============================================================================
 * free_all_memory
 *
 * When a new game is started, we want to free all the memory we've allocated
 * so we can start all over without leaking all the memory.
 */
void free_all_memory()
{
   int i;

   //free states
   for (i=0; i< states.max_state; i++)
      free (states.s[i]);

   //Oh, this is ugly!  Do I really want to do this?
   /*
   if(tt)
     {
      for (i=0; i<TT; i++)
       	{
	 if (tt[i])
	    free(tt[i]);
       	}
     }
     */



}


/*==============================================================================
 * create_hash
 *
 * Creates a hash value for the current state.  On the GUI side it's used to 
 * see if the state has changed recently.
 */
int create_hash(state *s)
{

   ull board_u, board_l;

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

   return( (board_u ^ board_l) % TT);
}


/*==============================================================================
 * game_over
 *
 * Checks to see if the game is over and generates a pop-up stating who the 
 * winner is.  Returns TRUE if the game is over.
 */
int game_over(move *movelist)
{
   state *s = states.s[states.current_state];
//   GtkWidget *auto_button, *force_button;

   if (children(s, movelist) == 0)
     {
      //printf("player %d wins!\n", s->turn^3);
      s->winner = s->turn^3;
      if (s->winner == BLACK)
	 gnome_ok_dialog("White wins!");
      else
	 gnome_ok_dialog("Black wins!");

      bstate_set_just_finished(GAME_OVER);

      /*
      auto_button = (GtkWidget *) lookup_widget(main_window, "BT_AUTOFINISH");
      force_button = (GtkWidget *) lookup_widget(main_window, "BT_FORCEMOVE");
      gtk_widget_set_sensitive (auto_button, FALSE);
      gtk_widget_set_sensitive (force_button, FALSE);
      */

      return TRUE;
     }
   else
      return FALSE;

}

/*==============================================================================
 * update_status_bar
 *
 * Updates the status bar based on the current value of what_next
 */
update_status_bar()
{
   GtkStatusbar *status = (GtkStatusbar *) lookup_widget(main_window, "statusbar1");
   guint context_id = bstate_get_what_next();

   gtk_statusbar_pop(status, context_id);

   switch (bstate_get_what_next()) 
     {
       case FIRE_ARROW:
	   gtk_statusbar_push(status, context_id, "Fire Arrow");
	   break;
       case MOVE_BLACK_QUEEN:
	   gtk_statusbar_push(status, context_id, "Move Black Amazon");
	   break;
       case MOVE_WHITE_QUEEN:
	   gtk_statusbar_push(status, context_id, "Move White Amazon");
	   break;
       case WAIT_FOR_AI:
	   gtk_statusbar_push(status, context_id, "AI is thinking...");
	   break;
       case NEW_GAME:
	   gtk_statusbar_push(status, context_id, "Select Game->New to start game");
	   break;
       default:
	   gtk_statusbar_push(status, context_id, "I have no idea what to do next!");

     }

}

/*==============================================================================
 * print_board
 *
 * prints out an ascii version of the board, useful for ensuring the board shows
 * what it should show.
 */
void print_board()
{
   int i,j;

   for (i=0; i<BOARD_SIZE; i++)
     {
      for (j=0; j<BOARD_SIZE; j++)
	{
	 if (board->squares[i][j] == 0)
	    printf(" 0");
	 if (board->squares[i][j] == 1)
	    printf(" B");
	 if (board->squares[i][j] == 2)
	    printf(" W");
	 if (board->squares[i][j] == 3)
	    printf(" x");
	}
      printf("\n");
     }
}

/*==============================================================================
 * destroy_board
 *
 * Destroys the main board canvas group which contains all the square and piece
 * images, and takes them with it.  Once done, it creates a new group that 
 * draw_board() can take advantage of.
 */
void destroy_board()
{
   int i;
   GtkWidget *CNVS_GAMEBOARD, *w, *scrolledwindow4, *table1;


#ifdef DEBUG
   printf("Destroying board now\n");
#endif


   gtk_object_destroy(GTK_OBJECT(board->root));
   board->root = GNOME_CANVAS_GROUP(gnome_canvas_item_new(gnome_canvas_root(board->canvas),
	       gnome_canvas_group_get_type(),
	       NULL));
}

/*==============================================================================
 * print_move_in_text_window
 *
 * Prints the given move in official amazon notation.  The move struct doesn't
 * contain 'from' information, so that must be retrieved from the previous state
 */
void print_move_in_text_window(move *m)
{
   GtkTextView *view; 
   GtkTextBuffer *buffer;
   GtkTextIter *iter = (GtkTextIter *) malloc(sizeof(GtkTextIter));
   char string_buf[32];
   GtkScrolledWindow *w;
   GtkAdjustment *adj;

   view = (GtkTextView *) lookup_widget(main_window, "textview1");
   buffer = gtk_text_view_get_buffer (view);
   gtk_text_buffer_get_end_iter(buffer, iter);

   get_move_str(m, string_buf);

#ifdef DEBUG
   printf("%s", string_buf);
#endif
   gtk_text_buffer_insert(buffer, iter, string_buf, -1);

   w = (GtkScrolledWindow *) lookup_widget(main_window, "scrolledwindow6");
   adj = gtk_scrolled_window_get_vadjustment(w);
   gtk_adjustment_set_value(adj, adj->upper);
   gtk_scrolled_window_set_vadjustment(w, adj);
   

   free (iter);
}

/*==============================================================================
 * get_move_str
 *
 * Creates a move string from a move struct
 */
void get_move_str(move *m, char move_str[])
{
   Square to_sq, from_sq, arrow_sq;
   int to_num, from_num, arrow_num;
   char to_alpha, from_alpha, arrow_alpha;
   int state_i = states.current_state;
   int turn;

   //Determine which side just moved:
   turn = states.s[state_i]->turn^3;
   if (turn == WHITE_PLAYER)
     {
      from_sq = get_square_from_engine(states.s[state_i-1]->white_q_x[m->queen],
	      				states.s[state_i-1]->white_q_y[m->queen]);
     }
   else
     {
      from_sq = get_square_from_engine(states.s[state_i-1]->black_q_x[m->queen],
	      				states.s[state_i-1]->black_q_y[m->queen]);
     }
   to_sq = get_square_from_engine(m->tocol, m->torow);
   arrow_sq = get_square_from_engine(m->wallcol, m->wallrow);



   from_alpha = get_grid_alpha_from_square(from_sq);
   from_num = get_grid_num_from_square(from_sq);

   to_alpha = get_grid_alpha_from_square(to_sq);
   to_num = get_grid_num_from_square(to_sq);
   
   arrow_alpha = get_grid_alpha_from_square(arrow_sq);
   arrow_num = get_grid_num_from_square(arrow_sq);
   
   sprintf(move_str, "%d. %c%d-%c%d, %c%d\n", state_i, from_alpha, from_num,
	   to_alpha, to_num, arrow_alpha, arrow_num);
}

   

/*==============================================================================
 * bstate_set_just_finished
 *
 * tells the internal state machine what state was just finished.  It then 
 * figures out from that what the next state should be.  This is designed to 
 * eliminate the redundant code scattered all around that tries to figure
 * this out.
 */
int bstate_set_just_finished(int finished)
{
   GtkWidget *auto_button, *force_button, *undo_button, *settings_menu;

   auto_button = (GtkWidget *) lookup_widget(main_window, "BT_AUTOFINISH");
   force_button = (GtkWidget *) lookup_widget(main_window, "BT_FORCEMOVE");
   undo_button = (GtkWidget *) lookup_widget(main_window, "BT_UNDO");
   settings_menu = (GtkWidget *) lookup_widget(main_window, "Settings");

   switch(finished)
     {
       case FIRE_ARROW:
	   if (bstate.turn == BLACK_PLAYER)
	     {
	      if (options.white_player == AI)
		{
		 bstate.what_next = WAIT_FOR_AI;
		 bstate.moving_ai = TRUE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, FALSE);
		 gtk_widget_set_sensitive (force_button, TRUE);
		}
	      else
		{
		 bstate.what_next = MOVE_WHITE_QUEEN;
		 bstate.moving_ai = FALSE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, TRUE);
		 gtk_widget_set_sensitive (force_button, FALSE);
		}
	      bstate.turn = WHITE_PLAYER;
	     }
	   else
	     {
	      if (options.black_player == AI)
		{
		 bstate.what_next = WAIT_FOR_AI;
		 bstate.moving_ai = TRUE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, FALSE);
		 gtk_widget_set_sensitive (force_button, TRUE);
		}
	      else
		{
		 bstate.what_next = MOVE_BLACK_QUEEN;
		 bstate.moving_ai = FALSE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, TRUE);
		 gtk_widget_set_sensitive (force_button, FALSE);
		}
	      bstate.turn = BLACK_PLAYER;
	     }
	   gtk_widget_set_sensitive (settings_menu, TRUE);
	   break;
       case MOVE_BLACK_QUEEN:
	   bstate.what_next = FIRE_ARROW;
	   gtk_widget_set_sensitive (undo_button, TRUE);
	   gtk_widget_set_sensitive (auto_button, FALSE);
	   gtk_widget_set_sensitive (settings_menu, FALSE);
	   break;
       case MOVE_WHITE_QUEEN:
	   bstate.what_next = FIRE_ARROW;
	   gtk_widget_set_sensitive (undo_button, TRUE);
	   gtk_widget_set_sensitive (auto_button, FALSE);
	   gtk_widget_set_sensitive (settings_menu, FALSE);
	   break;
       case WAIT_FOR_AI:
	   if (bstate.turn == BLACK_PLAYER)
	     {
	      if (options.white_player == AI)
		{
		 bstate.what_next = WAIT_FOR_AI;
		 bstate.moving_ai = TRUE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, FALSE);
		 gtk_widget_set_sensitive (force_button, TRUE);
		}
	      else
		{
		 bstate.what_next = MOVE_WHITE_QUEEN;
		 bstate.moving_ai = FALSE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, TRUE);
		 gtk_widget_set_sensitive (force_button, FALSE);
		}
	      bstate.turn = WHITE_PLAYER;
	     }
	   else
	     {
	      if (options.black_player == AI)
		{
		 bstate.what_next = WAIT_FOR_AI;
		 bstate.moving_ai = TRUE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, FALSE);
		 gtk_widget_set_sensitive (force_button, TRUE);
		}
	      else
		{
		 bstate.what_next = MOVE_BLACK_QUEEN;
		 bstate.moving_ai = FALSE;

		 gtk_widget_set_sensitive (undo_button, FALSE);
		 gtk_widget_set_sensitive (auto_button, TRUE);
		 gtk_widget_set_sensitive (force_button, FALSE);
		}
	      bstate.turn = BLACK_PLAYER;
	     }
	   break;
       case UNDO:
	   if (bstate.turn == BLACK_PLAYER)
	     {
	      bstate.what_next = MOVE_BLACK_QUEEN;
	     }
	   else
	     {
	      bstate.what_next = MOVE_WHITE_QUEEN;
	     }
	   gtk_widget_set_sensitive (settings_menu, TRUE);
	   gtk_widget_set_sensitive (undo_button, FALSE);
	   gtk_widget_set_sensitive (auto_button, TRUE);
	   break;
       case AUTO_FINISH:
	   bstate.what_next = WAIT_FOR_AI;
	   gtk_widget_set_sensitive (settings_menu, FALSE);
	   gtk_widget_set_sensitive (undo_button, FALSE);
	   gtk_widget_set_sensitive (auto_button, FALSE);
	   break;
       case FORCE_MOVE:
	   gtk_widget_set_sensitive (force_button, FALSE);
	   break;
       case START_GAME:
	   if (options.white_player == AI)
	     {
	      bstate.what_next = NEW_GAME;
	      gtk_widget_set_sensitive (undo_button, FALSE);
	      gtk_widget_set_sensitive (auto_button, FALSE);
	      gtk_widget_set_sensitive (force_button, FALSE);
	     }
	   else
	     {
	      bstate.what_next = MOVE_WHITE_QUEEN;
	      gtk_widget_set_sensitive (undo_button, FALSE);
	      gtk_widget_set_sensitive (auto_button, TRUE);
	      gtk_widget_set_sensitive (force_button, FALSE);
	     }
	   gtk_widget_set_sensitive (settings_menu, TRUE);
	   bstate.turn = WHITE_PLAYER;
	   bstate.from = INVALID_SQUARE_VALUE;
	   bstate.to = INVALID_SQUARE_VALUE;
	   bstate.last_arrow = INVALID_SQUARE_VALUE;
	   bstate.moving_ai = FALSE;
	   bstate.open_dialog = FALSE;
	   bstate.new_game = FALSE;
	   bstate.quit_game = FALSE;
	   break;
       case NEW_GAME:
	   if (bstate.moving_ai) //in the middle of an AI move
	      bstate.new_game = TRUE;
	   else
	      bstate.new_game = FALSE;

	   if (bstate.moving_piece)
	      bstate.stop_moving = TRUE;

	   if (options.white_player == AI)
	     {
	      bstate.what_next = WAIT_FOR_AI;
	      bstate.moving_ai = TRUE;
	      gtk_widget_set_sensitive (undo_button, FALSE);
	      gtk_widget_set_sensitive (auto_button, FALSE);
	      gtk_widget_set_sensitive (force_button, TRUE);
	     }
	   else
	     {
	      bstate.what_next = MOVE_WHITE_QUEEN;
	      bstate.moving_ai = FALSE;
	      gtk_widget_set_sensitive (undo_button, FALSE);
	      gtk_widget_set_sensitive (auto_button, TRUE);
	      gtk_widget_set_sensitive (force_button, FALSE);
	     }
	   gtk_widget_set_sensitive (settings_menu, TRUE);
	   bstate.turn = WHITE_PLAYER;
	   bstate.from = INVALID_SQUARE_VALUE;
	   bstate.to = INVALID_SQUARE_VALUE;
	   bstate.last_arrow = INVALID_SQUARE_VALUE;
	   bstate.quit_game = FALSE;

	   break;

       case LOAD_GAME:
	   break;
       case GAME_OVER:
	   gtk_widget_set_sensitive (undo_button, FALSE);
	   gtk_widget_set_sensitive (auto_button, FALSE);
	   gtk_widget_set_sensitive (force_button, FALSE);
	   gtk_widget_set_sensitive (settings_menu, TRUE);
	   bstate.what_next = NEW_GAME;
	   break;

       case QUIT_GAME:
	   bstate.quit_game = TRUE;
	   break;
       default:
	   bstate.what_next = CONFUSED;
     }
   update_status_bar();
#ifdef DEBUG
   print_bstate();
#endif
   return bstate.what_next;

}

/*==============================================================================
 * bstate_store_what_next
 *
 * This initializes the internal board state machine.  Use of this is discouraged
 * and should instead use bstate_set_just_finished.
void bstate_store_what_next(int next)
{
   switch(next)
     {
       case FIRE_ARROW:
	   bstate.what_next = FIRE_ARROW;
	   break;
       case MOVE_BLACK_QUEEN:
	   if (options.black_player == AI)
	      bstate.what_next = WAIT_FOR_AI;
	   else
	      bstate.what_next = MOVE_BLACK_QUEEN;
	   bstate.turn = BLACK_PLAYER;
	   break;
       case MOVE_WHITE_QUEEN:
	   if (options.white_player == AI)
	      bstate.what_next = WAIT_FOR_AI;
	   else
	      bstate.what_next = MOVE_WHITE_QUEEN;
	   bstate.turn = WHITE_PLAYER;
	   break;
       case WAIT_FOR_AI:
	   bstate.what_next = WAIT_FOR_AI;
	   break;
       default:
	   bstate.what_next = CONFUSED;
     }
   update_status_bar();
}
 */

/*==============================================================================
 * bstate_get_what_next
 *
 * This is the method for code throughout the program to find out what input
 * is expected next.
 */
int bstate_get_what_next()
{
   return bstate.what_next;
}

/*==============================================================================
 * bstate_set_move_from
 *
 * This lets the internal board state know that a queen has just been moved from
 * a given square.
 */
void bstate_set_move_from(Square from)
{
   bstate.from = from;
}

/*==============================================================================
 * bstate_set_move_from
 *
 * This lets the internal board state know that a queen has just been moved to
 * a given square.
 */
void bstate_set_move_to(Square to)
{
   bstate.to = to;
}

/*==============================================================================
 * bstate_get_move_from
 *
 * This lets the internal board state know that a queen has just been moved from
 * a given square.
 */
Square bstate_get_move_from()
{
   return bstate.from;
}

/*==============================================================================
 * bstate_get_move_from
 *
 * This lets the internal board state know that a queen has just been moved to
 * a given square.
 */
Square bstate_get_move_to()
{
   return bstate.to;
}

int bstate_get_moving_ai()
{
   return bstate.moving_ai;
}
/*
void bstate_set_moving_ai(int moving)
{
   bstate.moving_ai = moving;
}
*/
int bstate_get_new_game()
{
   return bstate.new_game;
}
void bstate_set_new_game(int new_game)
{
    bstate.new_game = new_game;
}

void bstate_set_moving_piece(int moving)
{
   bstate.moving_piece = moving;
}
int bstate_get_moving_piece()
{
   return bstate.moving_piece;
}

int bstate_get_turn()
{
   return bstate.turn;
}

int bstate_get_open_dialog()
{
   return bstate.open_dialog;
}

void bstate_set_open_dialog(int dialog)
{
   bstate.open_dialog = dialog;
}

void bstate_update_player_settings()
{
   if (bstate.turn == WHITE_PLAYER && options.white_player == HUMAN)
      bstate.what_next = MOVE_WHITE_QUEEN;
   if (bstate.turn == BLACK_PLAYER && options.black_player == HUMAN)
      bstate.what_next = MOVE_BLACK_QUEEN;

   if (bstate.what_next == NEW_GAME)
      return;
   
   if (bstate.turn == WHITE_PLAYER && options.white_player == AI)
      bstate.what_next = WAIT_FOR_AI;
   if (bstate.turn == BLACK_PLAYER && options.black_player == AI)
      bstate.what_next = WAIT_FOR_AI;
   update_status_bar();

}

int bstate_get_quit_game()
{
   return bstate.quit_game;
}

int bstate_get_stop_moving()
{
   return bstate.stop_moving;
}

void bstate_set_stop_moving(int stop_moving)
{
   bstate.stop_moving = stop_moving;
}


void print_bstate()
{
   printf("turn = %d\n", bstate.turn);
   printf("what_next = %d\n", bstate.what_next);
   printf("moving_ai = %d\n", bstate.moving_ai);
   printf("new_game = %d\n", bstate.new_game);
}



int read_in_moves(FILE *history_fd)
{
   char *buffer=NULL;
   size_t buf_size = 30;

   printf("History contents:\n");
   while (getline(&buffer, &buf_size, history_fd) != -1)
     {
      if (buffer != NULL)
	 printf("%s", buffer);
      free(buffer);
      buffer = NULL;
     }
   

   return TRUE;

}

