Import upstream Source
[gamazons.git] / src / board.c
blob365aa20a7515ccd97782e4a62d680665a5738940
1 #include <time.h>
2 #include <assert.h>
3 #include <gnome.h>
5 #include "amazons.h"
6 #include "board.h"
7 #include "bstate.h"
8 #include "callbacks.h"
10 /* local Prototypes */
13 static void fill_a_square(GnomeCanvasGroup *group,
14 double x1, double y1, double x2, double y2, char *color);
15 static void get_square_color(int square, char *color);
16 static void draw_a_line(GnomeCanvasGroup *group,
17 int x1, int y1, int x2, int y2, char *color);
18 static void draw_grid();
21 /* Globals */
22 extern Board *board;
23 extern struct options options;
24 extern struct game_states states;
25 extern int ok;
26 extern time_t start;
27 extern GtkWidget *main_window;
28 Square legal_moves[100];
29 int state_hash;
32 void init_game_board(GtkWidget *GamazonsMain)
34 int i,j;
35 char color[256];
36 GtkWidget *w = (GtkWidget *) lookup_widget(GamazonsMain, BOARD_NAME);
37 GtkWidget *force_button, *undo_button;
38 GtkTextView *view;
39 GtkTextBuffer *buffer;
40 GtkWidget *speed, *delay;
41 static int first_run = TRUE;
43 if (w == NULL)
44 printf("Couldn't find board!!!!!!!!\n");
46 board = (Board *) malloc(sizeof(Board));
47 board->canvas = GNOME_CANVAS(w);
48 board->root = GNOME_CANVAS_GROUP(gnome_canvas_item_new(gnome_canvas_root(board->canvas),
49 gnome_canvas_group_get_type(),
50 NULL));
52 gnome_canvas_set_scroll_region(board->canvas, 0.0, 0.0,
53 400.0,
54 400.0);
57 /* initialize pieces */
58 for (i=0; i<BOARD_SIZE; i++)
60 for (j=0; j<BOARD_SIZE; j++)
62 board->squares[i][j] = NOTHING;
65 gtk_signal_connect(GTK_OBJECT(board->canvas), "event",
66 GTK_SIGNAL_FUNC(arrow_fire_cb), NULL);
68 //Place amazon queens on the board
69 board->squares[9][3] = WHITE;
70 board->squares[9][6] = WHITE;
71 board->squares[6][0] = WHITE;
72 board->squares[6][9] = WHITE;
74 board->squares[0][3] = BLACK;
75 board->squares[0][6] = BLACK;
76 board->squares[3][0] = BLACK;
77 board->squares[3][9] = BLACK;
79 board->square_to_wh_queen_map[0] = 96;
80 board->square_to_wh_queen_map[1] = 93;
81 board->square_to_wh_queen_map[2] = 60;
82 board->square_to_wh_queen_map[3] = 69;
84 board->square_to_bl_queen_map[0] = 3;
85 board->square_to_bl_queen_map[1] = 6;
86 board->square_to_bl_queen_map[2] = 30;
87 board->square_to_bl_queen_map[3] = 39;
89 //Set up move history window
90 view = (GtkTextView *) lookup_widget(main_window, "textview1");
91 buffer = gtk_text_buffer_new(NULL);
92 gtk_text_view_set_buffer(view, buffer);
94 //Initialize buttons
95 force_button = (GtkWidget *)lookup_widget(main_window, "BT_FORCEMOVE");
96 gtk_widget_set_sensitive (force_button, FALSE);
97 undo_button = (GtkWidget *)lookup_widget(main_window, "BT_UNDO");
98 gtk_widget_set_sensitive (undo_button, FALSE);
101 draw_board();
102 if (first_run)
104 //Set spinner values
105 delay = (GtkWidget *)lookup_widget(main_window, "ReplayDelaySpinner");
106 gtk_spin_button_set_value((GtkSpinButton *)delay, options.replay_delay);
107 speed = (GtkWidget *)lookup_widget(main_window, "MovementSpeedSpinner");
108 gtk_spin_button_set_value((GtkSpinButton *)speed, options.movement_speed);
110 first_run = FALSE;
111 bstate_set_just_finished(START_GAME);
117 void fill_a_square(GnomeCanvasGroup *group,
118 double x1, double y1, double x2, double y2, char *color)
120 /* draw a box*/
121 gnome_canvas_item_new(group,
122 gnome_canvas_rect_get_type(),
123 "x1", x1,
124 "y1", y1,
125 "x2", x2,
126 "y2", y2,
127 "outline_color", "black",
128 "fill_color", color,
129 "width_pixels", (double)THICKNESS,
130 NULL, NULL);
134 static void get_square_color(int square, char *color)
136 if ((square % 2) == 0)
137 strcpy(color, SQUARE_COLOR_1);
138 else
139 strcpy(color, SQUARE_COLOR_2);
143 static void draw_grid()
145 int x,y;
147 for (x=0; x<=10; x++)
149 for (y=0; y<=10; y++)
151 //draw horiz
152 draw_a_line(board->root, //gnome_canvas_root(board->canvas),
153 0, y*CELL_SIZE, BOARD_SIZE*CELL_SIZE, y*CELL_SIZE, "black");
155 //draw vert
156 draw_a_line(board->root, //gnome_canvas_root(board->canvas),
157 x*CELL_SIZE, 0, x*CELL_SIZE, BOARD_SIZE*CELL_SIZE, "black");
164 static void draw_a_line(GnomeCanvasGroup *group,
165 int x1, int y1, int x2, int y2, char *color)
167 GnomeCanvasPoints *points;
169 /* allocate a new points array */
170 points = gnome_canvas_points_new (2);
172 /* fill out the points */
173 points->coords[0] = x1;
174 points->coords[1] = y1;
175 points->coords[2] = x2;
176 points->coords[3] = y2;
177 /* draw the line */
178 gnome_canvas_item_new(group,
179 gnome_canvas_line_get_type(),
180 "points", points,
181 "fill_color", color,
182 "width_units", (double)THICKNESS,
183 NULL);
185 /* free the points array */
186 gnome_canvas_points_free(points);
189 void draw_board()
191 int i,j,k;
192 int black_i = 0;
193 GdkPixbuf *white_pb, *black_pb;
194 GdkPixbuf *white_sq, *grey_sq, *arrow_sq;
195 char color[256];
196 GnomeCanvasItem *image;
197 GnomeCanvasGroup *root = GNOME_CANVAS_GROUP(gnome_canvas_root (GNOME_CANVAS (board->canvas)));
198 static int first_game = 1;
202 /* Find images */
203 white_pb = gdk_pixbuf_new_from_file(options.images.white_piece, NULL);
204 if (white_pb == NULL)
206 fprintf(stderr, "Cannot find white piece image: %s\n", options.images.white_piece);
207 exit(1);
210 black_pb = gdk_pixbuf_new_from_file(options.images.black_piece, NULL);
211 if (black_pb == NULL)
213 fprintf(stderr, "Cannot find black piece image: %s\n", options.images.black_piece);
214 exit(1);
217 white_sq = gdk_pixbuf_new_from_file(options.images.white_sq, NULL);
218 if (white_sq == NULL)
220 fprintf(stderr, "Cannot find white square image: %s\n", options.images.white_sq);
221 exit(1);
224 grey_sq = gdk_pixbuf_new_from_file(options.images.grey_sq, NULL);
225 if (grey_sq == NULL)
227 fprintf(stderr, "Cannot find grey square image: %s\n", options.images.grey_sq);
228 exit(1);
230 arrow_sq = gdk_pixbuf_new_from_file(options.images.arrow_sq, NULL);
231 if (arrow_sq == NULL)
233 fprintf(stderr, "Cannot find arrow square image: %s\n", options.images.arrow_sq);
234 exit(1);
239 /* fill alternate squares */
240 for(j=0;j<BOARD_SIZE;j++)
242 for(i=0;i<BOARD_SIZE;i++)
244 board->square_items[j*10+i] = NULL;
245 if ((i + j) % 2)
247 board->square_items[j*10+i] = gnome_canvas_item_new (board->root,
248 gnome_canvas_pixbuf_get_type (),
249 "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
250 "width", CELL_SIZE, "height", CELL_SIZE,
251 "width_set", TRUE, "height_set", TRUE,
252 "pixbuf", grey_sq,
253 NULL);
255 else
257 board->square_items[j*10+i] = gnome_canvas_item_new (board->root,
258 gnome_canvas_pixbuf_get_type (),
259 "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
260 "width", CELL_SIZE, "height", CELL_SIZE,
261 "width_set", TRUE, "height_set", TRUE,
262 "pixbuf", white_sq,
263 NULL);
268 //Place the queen images on the board in the right order
269 if (board->squares[j][i] == WHITE)
271 #ifdef DEBUG
272 printf("Square %c%c contains a white queen\n",i+'a',10-j+'0');
273 #endif
274 image = gnome_canvas_item_new (board->root,
275 gnome_canvas_pixbuf_get_type (),
276 "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
277 "width", CELL_SIZE, "height", CELL_SIZE,
278 "width_set", TRUE, "height_set", TRUE,
279 "pixbuf", white_pb,
280 NULL);
281 //We need to do some funky checking to make sure board->white_queens[] matches
282 //up exactly with state->white_q_x[], state->white_q_y[]
283 for (k=0; k<4; k++)
285 if(j*10 +i == board->square_to_wh_queen_map[k])
287 board->white_queens[k] = image;
288 #ifdef DEBUG
289 printf("registering queen %d\n", k);
290 #endif
291 break;
295 #ifdef DEBUG
296 printf("connecting signal to queen\n");
297 #endif
298 gtk_signal_connect(GTK_OBJECT(image), "event",
299 GTK_SIGNAL_FUNC(board_press_cb), NULL);
301 else if (board->squares[j][i] == BLACK)
303 #ifdef DEBUG
304 printf("Square %c%c contains a black queen\n",i+'a',10-j+'0');
305 #endif
306 image = gnome_canvas_item_new (board->root,
307 gnome_canvas_pixbuf_get_type (),
308 "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
309 "width", CELL_SIZE, "height", CELL_SIZE,
310 "width_set", TRUE, "height_set", TRUE,
311 "pixbuf", black_pb,
312 NULL);
313 for (k=0; k<4; k++)
315 if(j*10 +i == board->square_to_bl_queen_map[k])
317 board->black_queens[k] = image;
318 #ifdef DEBUG
319 printf("registering queen %d\n", k);
320 #endif
321 break;
325 #ifdef DEBUG
326 printf("connecting signal to queen\n");
327 #endif
328 gtk_signal_connect(GTK_OBJECT(image), "event",
329 GTK_SIGNAL_FUNC(board_press_cb), NULL);
331 else if (board->squares[j][i] == ARROW)
333 image = gnome_canvas_item_new (board->root,
334 gnome_canvas_pixbuf_get_type (),
335 "x", i*CELL_SIZE+QUEEN_OFFSET, "y", j*CELL_SIZE+QUEEN_OFFSET,
336 "width", CELL_SIZE, "height", CELL_SIZE,
337 "width_set", TRUE, "height_set", TRUE,
338 "pixbuf", arrow_sq,
339 NULL);
346 if (options.images.grid == TRUE)
347 draw_grid();
350 image = gnome_canvas_item_new (root,
351 gnome_canvas_pixbuf_get_type (),
352 "x", 10.0, "y", 10.0,
353 "width", 40.0, "height", 40.0,
354 "width_set", TRUE, "height_set", TRUE,
355 "pixbuf", white_pb,
356 NULL);
360 gtk_widget_show_now(main_window);
361 gtk_widget_queue_draw ((GtkWidget *) board->canvas);
362 gtk_widget_show_now((GtkWidget *) board->canvas);
367 void mark_square (GnomeCanvasItem *square)
369 gnome_canvas_item_set (square, "outline_color", "red", NULL);
372 Square get_square (double x, double y)
374 Square from;
375 int x_square;
376 int y_square;
379 x -= (BOARD_BORDER - CELL_PAD);
380 y -= (BOARD_BORDER - CELL_PAD);
383 if (x < 0)
384 x = 0.0;
385 else if (x > ((BOARD_SIZE-1) * CELL_SIZE))
386 x = (BOARD_SIZE-1) * CELL_SIZE;
387 if (y < 0)
388 y = 0.0;
389 else if (y > ((BOARD_SIZE-1) * CELL_SIZE))
390 y = (BOARD_SIZE-1) * CELL_SIZE;
392 x_square = x / CELL_SIZE;
393 y_square = y / CELL_SIZE;
395 #ifdef DEBUG
396 printf("x coord = %f y coord = %f\n", x, y);
397 printf("x coord = %d y coord = %d\n", x_square, y_square);
398 #endif
400 from = x_square + y_square * 10;
402 return from;
405 void clear_square (GnomeCanvasItem **square)
407 gnome_canvas_item_set (*square, "outline_color", NULL, NULL);
408 *square = NULL;
411 /*==============================================================================
412 * move_piece_to
414 * This moves the given piece to the given square. This is a very tricky function
415 * because the user can do many things to upset the state of the board while a
416 * piece is sliding, so various checks must take place throughout the movement
417 * process to make sure the board still exists as it thinks it does.
419 * The piece can also move at different speeds. Originally, it moved one pixel at
420 * a time, but it now gets its value from the MovementSpeedSpinner widget. This
421 * makes it so the pieces can move at acceptable speeds on slower computers, but
422 * adds more complexity in trying to calculate the distance a piece should move.
424 void move_piece_to(Square to, GnomeCanvasItem *item)
426 double Lx, Uy, Rx, By;
427 double to_Lx, to_Uy;
428 int x, y;
429 int i,j;
430 int game_life;
431 GtkWidget *speed = (GtkWidget *)lookup_widget(main_window, "MovementSpeedSpinner");
432 int inc = gtk_spin_button_get_value_as_int((GtkSpinButton *)speed);
433 int count = 0;
435 game_life = bstate_get_game_life();
436 to_Lx = get_x_from_square(to);
437 to_Uy = get_y_from_square(to);
439 #ifdef DEBUG
440 printf("We want the queen at coords %f, %f\n", to_Lx, to_Uy);
441 #endif
442 gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
443 #ifdef DEBUG
444 printf("The queen is at coords %f, %f\n", Lx, Uy);
445 #endif
446 if (bstate_get_dont_slide())
448 gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
449 gnome_canvas_item_move (item,
450 get_x_from_square(to) - Lx,
451 get_y_from_square(to) - Uy);
452 gnome_canvas_item_raise_to_top (item);
454 else
456 while (Lx != to_Lx || Uy != to_Uy)
458 #ifdef DEBUG
459 if (count++ < 20)
460 printf("Lx = %g; to_Lx = %g; Uy = %g; to_Uy = %g\n", Lx, to_Lx, Uy, to_Uy);
461 #endif
462 bstate_set_moving_piece(TRUE);
463 if ((int)Lx == (int)to_Lx)
464 x = 0;
465 else if (Lx < to_Lx && (to_Lx - Lx) >= inc)
466 x = inc;
467 else if (Lx < to_Lx && (to_Lx - Lx) <= inc)
468 x = to_Lx - Lx;
469 else if (Lx > to_Lx && (Lx - to_Lx) >= inc)
470 x = -inc;
471 else if (Lx > to_Lx && (Lx - to_Lx) <= inc)
472 x = to_Lx - Lx;
474 if ((int)Uy == (int)to_Uy)
475 y = 0;
476 else if (Uy < to_Uy && (to_Uy - Uy) >= inc)
477 y = inc;
478 else if (Uy < to_Uy && (to_Uy - Uy) <= inc)
479 y = to_Uy - Uy;
480 else if (Uy > to_Uy && (Uy - to_Uy) >= inc)
481 y = -inc;
482 else if (Uy > to_Uy && (Uy - to_Uy) <= inc)
483 y = to_Uy - Uy;
485 #ifdef DEBUG
486 if (count < 20)
487 printf("x = %d, y = %d\n", x, y);
488 #endif
490 if (bstate_get_game_life() != game_life)
492 bstate_set_moving_piece(FALSE);
493 return;
495 gnome_canvas_item_move (item, (double)x, (double)y);
496 gnome_canvas_item_raise_to_top (item);
498 //update the board
499 while (gtk_events_pending())
500 gtk_main_iteration();
502 if (bstate_get_quit_game())
503 exit(0);
504 if (bstate_get_game_life() != game_life)
506 bstate_set_moving_piece(FALSE);
507 return;
509 gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
513 if (bstate_get_game_life() != game_life)
515 bstate_set_moving_piece(FALSE);
516 return;
518 gnome_canvas_item_raise_to_top (item);
519 bstate_set_moving_piece(FALSE);
520 //see where it landed
521 gnome_canvas_item_get_bounds(item, &Lx, &Uy, &Rx, &By);
522 #ifdef DEBUG
523 printf("The queen landed at coords %f, %f\n", Lx, Uy);
524 printf("this time the queen is on square %d\n", to);
525 #endif
531 double get_x_from_square(int sq)
533 double x;
535 x = (double) ((sq % 10) * CELL_SIZE+QUEEN_OFFSET);
537 return x;
541 double get_y_from_square(int sq)
543 double y;
545 y = (double) ((sq / 10) * CELL_SIZE+QUEEN_OFFSET);
547 return y;
552 int get_x_int_from_square(int sq)
554 return(sq % 10);
557 int get_y_int_from_square(int sq)
559 return(sq / 10);
562 int get_grid_num_from_square(int sq)
564 return(10 - sq/10);
567 char get_grid_alpha_from_square(int sq)
569 return('a' + sq % 10);
572 int engine_x_to_board_x(int eng_x)
574 return(eng_x);//hey, these are the same, no conversion necessary
577 int engine_y_to_board_y(int eng_y)
579 return(9 - eng_y);
582 int board_x_to_engine_x(int brd_x)
584 return(brd_x);
587 int board_y_to_engine_y(int brd_y)
589 return(9 - brd_y);
592 int get_square_from_engine(int x, int y)
594 return((9 - y) * 10 + x);
598 void fire_arrow(Square sq)
600 int x,y;
601 GdkPixbuf *arrow_sq;
602 GnomeCanvasItem *image;
603 GnomeCanvasGroup *root = GNOME_CANVAS_GROUP(gnome_canvas_root (GNOME_CANVAS (board->canvas)));
605 x = sq % 10;
606 y = sq / 10;
608 board->squares[y][x] = ARROW;
610 arrow_sq = gdk_pixbuf_new_from_file(options.images.arrow_sq, NULL);
611 if (arrow_sq == NULL)
613 fprintf(stderr, "Cannot find arrow image: %s\n", options.images.arrow_sq);
614 exit(1);
617 image = gnome_canvas_item_new (board->root,
618 gnome_canvas_pixbuf_get_type (),
619 "x", x*CELL_SIZE+QUEEN_OFFSET, "y", y*CELL_SIZE+QUEEN_OFFSET,
620 "width", CELL_SIZE, "height", CELL_SIZE,
621 "width_set", TRUE, "height_set", TRUE,
622 "pixbuf", arrow_sq,
623 NULL);
627 void square_contains(Square sq)
629 int row, col;
631 col = get_x_int_from_square(sq);
632 row = get_y_int_from_square(sq);
634 if (board->squares[row][col] == NOTHING)
635 printf("Nothing is found at square %d\n", sq);
636 else if (board->squares[row][col] == WHITE)
637 printf("A White Queen is found at square %d\n", sq);
638 else if (board->squares[row][col] == BLACK)
639 printf("A Black Queen is found at square %d\n", sq);
640 else if (board->squares[row][col] == ARROW)
641 printf("An arrow is found at square %d\n", sq);
642 else
643 printf("Whoa, I don't know _what_ is on square %d\n", sq);
647 /*==============================================================================
648 * move_ai
650 * Checks to see if an AI oppenent is next to move. If it is, it starts the
651 * move process, and checks for a win afterwards. If not, it just checks for
652 * the win. Returns TRUE if an AI opponent moves next. False if human.
654 * NOTE: If you have 2 AI players, this function would just keep thinking and
655 * never let the board update or respond. So there are several checks to see
656 * if any new events occured that should be handled, or critical changes have
657 * been made (like starting a new game, etc..). If something critical has changed
658 * the function will exit after learning about it.
660 int move_ai()
662 state *s = states.s[states.current_state];
663 move temp;
664 int ai = FALSE;
665 int current_hash;
666 int game_life = bstate_get_game_life();
667 //GtkWidget *auto_button, *force_button;
669 current_hash = state_hash = create_hash(s);
671 //quit this function if a 'New Game' option was selected since this
672 //function was started.
674 if (bstate_get_new_game())
676 bstate_set_new_game(FALSE);
677 return FALSE;
680 ok = 1;
681 ai = TRUE;
682 start = time(NULL);
683 temp = isearch(s, NOTHINK);
684 if (s->winner) //XXX does this if statement do any good? I thot winner was handled elsewhere
685 return FALSE;
686 makemove(s,temp);
688 //update the board before drawing the new move
689 //the program would segfault if you closed it while it was thinking
690 while (gtk_events_pending())
691 gtk_main_iteration();
692 if (current_hash != state_hash)
693 return FALSE;
696 if (bstate_get_new_game())
698 bstate_set_new_game(FALSE);
699 return FALSE;
703 if (bstate_get_quit_game())
704 exit(0);
706 if (bstate_get_game_life() != game_life)
707 return FALSE;
710 //register move on graphical board
711 move_piece(temp);
712 if (bstate_get_game_life() != game_life)
713 return FALSE;
714 print_move_in_text_window(&temp);
715 dup_state(s, states.s[++(states.current_state)]);
716 bstate_set_just_finished(WAIT_FOR_AI);
719 #ifdef DEBUG
720 if (options.white_player == AI)
721 printf("White is AI\n");
722 if (options.black_player == AI)
723 printf("Black is AI\n");
724 printf("Turn is %d\n", states.s[states.current_state]->turn );
725 #endif
727 if (game_over())
729 //XXX should I set ai = FALSE?
730 ai = FALSE;
731 return (ai);
734 return ai;
737 /*==============================================================================
738 * move_piece
740 * Takes a move struct generated by the engine, and extracts the necessary info
741 * to update the GUI data structs and have the GUI reflect the move.
743 void move_piece(move m)
745 GnomeCanvasItem *item;
746 int from_row, from_col;
747 int to_row, to_col;
748 int game_life = bstate_get_game_life();
750 bstate_set_move_to(get_square_from_engine(m.tocol, m.torow));
751 to_col = get_x_int_from_square(bstate_get_move_to());
752 to_row = get_y_int_from_square(bstate_get_move_to());
753 //Note: by the time the state gets here, it's signaled the other player's turn
754 //so if it says it's white's turn, black just moved and we need to move black's
755 //piece.
756 if (states.s[states.current_state]->turn == WHITE_PLAYER)
758 bstate_set_move_from(get_square_from_engine(states.s[states.current_state -1]->black_q_x[m.queen],
759 states.s[states.current_state -1]->black_q_y[m.queen]));
761 board->squares[to_row][to_col] = BLACK;
762 #ifdef DEBUG
763 printf("Moving black queen\n");
764 #endif
765 item = board->black_queens[m.queen];
766 board->square_to_bl_queen_map[m.queen] = to_row*10 +to_col;
768 else
770 bstate_set_move_from(get_square_from_engine(states.s[states.current_state -1]->white_q_x[m.queen],
771 states.s[states.current_state -1]->white_q_y[m.queen]));
772 board->squares[to_row][to_col] = WHITE;
773 #ifdef DEBUG
774 printf("Moving white queen\n");
775 #endif
776 item = board->white_queens[m.queen];
777 board->square_to_wh_queen_map[m.queen] = to_row*10 +to_col;
781 from_col = get_x_int_from_square(bstate_get_move_from());
782 from_row = get_y_int_from_square(bstate_get_move_from());
783 board->squares[from_row][from_col] = NOTHING;
785 move_piece_to(bstate_get_move_to(), item);
786 #ifdef DEBUG
787 printf("Engine coords for arrow: %d, %d\n", m.wallcol, m.wallrow);
788 #endif
789 if (game_life != bstate_get_game_life())
790 return;
791 fire_arrow(get_square_from_engine(m.wallcol, m.wallrow));
792 #ifdef DEBUG
793 printf("fired arrow to square %d\n", get_square_from_engine(m.wallcol, m.wallrow));
794 pmove(m);
795 #endif
798 /*==============================================================================
799 * register_move_with_engine
801 * Fills out a move struct with the human's move and calls makemove() to update
802 * the state struct, so the AI engine knows what happened.
804 void register_move_with_engine(Square arrow_sq)
806 state *s = states.s[states.current_state];
807 move m;
808 move movelist[3000];
809 int move_count;
810 int i;
811 int tocol, torow;
812 int found = FALSE;
813 char move_str[32];
814 char err_msg[256];
816 //find out the index of the queen that was just moved.
817 //weird things will happen if it's not found.
818 for (i=0; i<4; i++)
820 if (board->selected_queen == board->white_queens[i] ||
821 board->selected_queen == board->black_queens[i])
823 found = TRUE;
824 break;
828 if (!found)
829 fprintf(stderr, "Error registering move w/ AI engine! Game play will now be weird.\n");
831 m.queen = i;
832 m.torow = board_y_to_engine_y(get_y_int_from_square(bstate_get_move_to()));
833 m.tocol = board_x_to_engine_x(get_x_int_from_square(bstate_get_move_to()));
835 m.wallrow = board_y_to_engine_y(get_y_int_from_square(arrow_sq));
836 m.wallcol = board_x_to_engine_x(get_x_int_from_square(arrow_sq));
838 //make sure it's a valid move
839 move_count = children(s, movelist);
840 if (move_count == 0)
842 gnome_error_dialog("The AI engine thinks the game is over. Please use the menu item Game->New to start a new game");
843 return;
845 if (!move_lookup(&m, movelist, move_count))
847 get_move_str(&m, move_str);
848 strcpy(err_msg, "You've hit a bug. The following illegal move was just attempted: ");
849 strcat(err_msg, move_str);
850 gnome_error_dialog(err_msg);
851 return;
854 makemove(s, m);
855 print_move_in_text_window(&m);
859 /*==============================================================================
860 * is_queen_square
862 * Compares the given square with the information stored in board->squares[][]
863 * to see if a queen is there.
865 int is_queen_square(Square sq)
867 int row, col;
869 col = get_x_int_from_square(sq);
870 row = get_y_int_from_square(sq);
872 if ((board->squares[row][col] == BLACK) ||
873 (board->squares[row][col] == WHITE))
874 return TRUE;
875 else
876 return FALSE;
880 /*==============================================================================
881 * gen_legal_moves
883 * Given a square, this generates an array of all legal moves that can be made
884 * from it. This works for both queen movement, as well as firing an arrow,
885 * since both move the same way.
887 * The array terminator is 100
889 void gen_legal_moves(Square sq)
891 int arr_i = 0;
892 int i;
893 int row, col, sq_row, sq_col;
894 int scanning;
896 sq_col = get_x_int_from_square(sq);
897 sq_row = get_y_int_from_square(sq);
899 //make sure the player can drop the piece on the same square if he changes
900 //his mind
901 legal_moves[arr_i++] = sq;
903 //get vertical moves
904 row = sq_row + 1;
905 col = sq_col;
906 while (board->squares[row][col] == NOTHING && row < 10)
908 legal_moves[arr_i++] = (row*10) + col;
909 row++;
912 row = sq_row - 1;
913 while (board->squares[row][col] == NOTHING && row >= 0)
915 legal_moves[arr_i++] = (row*10) + col;
916 row--;
919 //get horizontal moves
920 row = sq_row;
921 col = sq_col + 1;
922 while (board->squares[row][col] == NOTHING && col < 10)
924 legal_moves[arr_i++] = (row*10) + col;
925 col++;
928 col = sq_col - 1;
929 while (board->squares[row][col] == NOTHING && col >= 0)
931 legal_moves[arr_i++] = (row*10) + col;
932 col--;
935 //get forward diagonal moves
936 row = sq_row + 1;
937 col = sq_col + 1;
938 while (board->squares[row][col] == NOTHING && col < 10 && row < 10)
940 legal_moves[arr_i++] = (row*10) + col;
941 col++;
942 row++;
945 row = sq_row - 1;
946 col = sq_col - 1;
947 while (board->squares[row][col] == NOTHING && col >= 0 && row >= 0)
949 legal_moves[arr_i++] = (row*10) + col;
950 col--;
951 row--;
954 //get backward diagonal moves
955 row = sq_row + 1;
956 col = sq_col - 1;
957 while (board->squares[row][col] == NOTHING && col >= 0 && row < 10)
959 legal_moves[arr_i++] = (row*10) + col;
960 col--;
961 row++;
964 row = sq_row - 1;
965 col = sq_col + 1;
966 while (board->squares[row][col] == NOTHING && col < 10 && row >= 0)
968 legal_moves[arr_i++] = (row*10) + col;
969 col++;
970 row--;
974 legal_moves[arr_i] = 100;
975 #ifdef DEBUG
976 printf("legal move list for %d of length %d: \n", sq, arr_i);
977 i = 0;
978 while (legal_moves[i] < 100)
979 printf(" %d", legal_moves[i++]);
980 printf("\n");
981 #endif
985 /*==============================================================================
986 * is_move_legal
988 * Looks up the given square in the current legal_moves array. If it doesn't
989 * exist, it's not a legal move and returns FALSE. Returns TRUE if it is there.
991 int is_move_legal(Square sq)
993 int i=0;
995 #ifdef DEBUG
996 printf("checking to see if a move is legal\n");
997 #endif
998 while (legal_moves[i] < 100)
1000 if (sq == legal_moves[i++])
1002 #ifdef DEBUG
1003 printf("%d is a legal move\n", sq);
1004 #endif
1005 return TRUE;
1009 #ifdef DEBUG
1010 printf("Can't move to square. Legal moves are: %d\n", sq);
1011 i=0;
1012 while (legal_moves[i] < 100)
1013 printf(" %d", legal_moves[i++]);
1014 printf("\n");
1015 #endif
1016 return FALSE;
1019 /*==============================================================================
1020 * count_queens
1022 * DEBUG - counts the number of queens on the GUI representation and prints
1023 * out a bunch of XXXX's whenever there are not 4 of both kinds.
1025 void count_queens()
1027 int black=0, white=0;
1028 int i,j;
1030 for(i=0; i<10; i++)
1032 for(j=0; j<10; j++)
1034 if (board->squares[i][j] == WHITE)
1035 white++;
1036 if (board->squares[i][j] == BLACK)
1037 black++;
1040 if (black > 4)
1041 printf("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY Gained a black queen\n");
1042 if (white > 4)
1043 printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Gained a white queen\n");
1044 if (black < 4)
1045 printf("XYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXXYXYX Lost a black queen\n");
1046 if (white < 4)
1047 printf("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ Lost a white queen\n");
1052 /*==============================================================================
1053 * free_all_memory
1055 * When a new game is started, we want to free all the memory we've allocated
1056 * so we can start all over without leaking all the memory.
1058 void free_all_memory()
1060 int i;
1062 //free states
1063 for (i=0; i< states.max_state; i++)
1064 free (states.s[i]);
1066 //Oh, this is ugly! Do I really want to do this?
1068 if(tt)
1070 for (i=0; i<TT; i++)
1072 if (tt[i])
1073 free(tt[i]);
1083 /*==============================================================================
1084 * create_hash
1086 * Creates a hash value for the current state. On the GUI side it's used to
1087 * see if the state has changed recently.
1089 int create_hash(state *s)
1092 ull board_u, board_l;
1094 board_u = s->white_bd[1] | s->black_bd[1] | s->blocks_bd[1];
1095 board_l = s->white_bd[0] | s->black_bd[0] | s->blocks_bd[0];
1097 return( (board_u ^ board_l) % TT);
1101 /*==============================================================================
1102 * game_over
1104 * Checks to see if the game is over and generates a pop-up stating who the
1105 * winner is. Returns TRUE if the game is over.
1107 int game_over()
1109 state *s = states.s[states.current_state];
1110 move movelist[3000];
1111 // GtkWidget *auto_button, *force_button;
1113 if (children(s, movelist) == 0)
1115 //printf("player %d wins!\n", s->turn^3);
1116 s->winner = s->turn^3;
1117 if (s->winner == BLACK)
1118 gnome_ok_dialog("White wins!");
1119 else
1120 gnome_ok_dialog("Black wins!");
1122 bstate_set_just_finished(GAME_OVER);
1125 auto_button = (GtkWidget *) lookup_widget(main_window, "BT_AUTOFINISH");
1126 force_button = (GtkWidget *) lookup_widget(main_window, "BT_FORCEMOVE");
1127 gtk_widget_set_sensitive (auto_button, FALSE);
1128 gtk_widget_set_sensitive (force_button, FALSE);
1131 return TRUE;
1133 else
1134 return FALSE;
1138 /*==============================================================================
1139 * update_status_bar
1141 * Updates the status bar based on the current value of what_next
1143 update_status_bar()
1145 GtkStatusbar *status = (GtkStatusbar *) lookup_widget(main_window, "statusbar1");
1146 guint context_id = bstate_get_what_next();
1148 gtk_statusbar_pop(status, context_id);
1150 //printf("Updating status bar for state %d\n", bstate_get_what_next());
1151 switch (bstate_get_what_next())
1153 case FIRE_ARROW:
1154 gtk_statusbar_push(status, context_id, "Fire Arrow");
1155 break;
1156 case MOVE_BLACK_QUEEN:
1157 gtk_statusbar_push(status, context_id, "Move Black Amazon");
1158 break;
1159 case MOVE_WHITE_QUEEN:
1160 gtk_statusbar_push(status, context_id, "Move White Amazon");
1161 break;
1162 case WAIT_FOR_AI:
1163 gtk_statusbar_push(status, context_id, "AI is thinking...");
1164 break;
1165 case NEW_GAME:
1166 gtk_statusbar_push(status, context_id, "Select Game->New to start game");
1167 break;
1168 case STOP_REPLAY:
1169 gtk_statusbar_push(status, context_id, "Replaying a game...");
1170 break;
1172 default:
1173 gtk_statusbar_push(status, context_id, "I have no idea what to do next!");
1179 /*==============================================================================
1180 * print_board
1182 * prints out an ascii version of the board, useful for ensuring the board shows
1183 * what it should show.
1185 void print_board()
1187 int i,j;
1189 for (i=0; i<BOARD_SIZE; i++)
1191 for (j=0; j<BOARD_SIZE; j++)
1193 if (board->squares[i][j] == 0)
1194 printf(" 0");
1195 if (board->squares[i][j] == 1)
1196 printf(" B");
1197 if (board->squares[i][j] == 2)
1198 printf(" W");
1199 if (board->squares[i][j] == 3)
1200 printf(" x");
1202 printf("\n");
1206 /*==============================================================================
1207 * destroy_board
1209 * Destroys the main board canvas group which contains all the square and piece
1210 * images, and takes them with it. Once done, it creates a new group that
1211 * draw_board() can take advantage of.
1213 void destroy_board()
1215 int i;
1216 GtkWidget *CNVS_GAMEBOARD, *w, *scrolledwindow4, *table1;
1219 #ifdef DEBUG
1220 printf("Destroying board now\n");
1221 #endif
1224 gtk_object_destroy(GTK_OBJECT(board->root));
1225 board->root = GNOME_CANVAS_GROUP(gnome_canvas_item_new(gnome_canvas_root(board->canvas),
1226 gnome_canvas_group_get_type(),
1227 NULL));
1230 /*==============================================================================
1231 * print_move_in_text_window
1233 * Prints the given move in official amazon notation. The move struct doesn't
1234 * contain 'from' information, so that must be retrieved from the previous state
1236 void print_move_in_text_window(move *m)
1238 GtkTextView *view;
1239 GtkTextBuffer *buffer;
1240 GtkTextIter *iter = (GtkTextIter *) malloc(sizeof(GtkTextIter));
1241 char string_buf[32];
1242 GtkScrolledWindow *w;
1243 GtkAdjustment *adj;
1245 view = (GtkTextView *) lookup_widget(main_window, "textview1");
1246 buffer = gtk_text_view_get_buffer (view);
1247 gtk_text_buffer_get_end_iter(buffer, iter);
1249 get_move_str(m, string_buf);
1251 #ifdef DEBUG
1252 printf("%s", string_buf);
1253 #endif
1254 gtk_text_buffer_insert(buffer, iter, string_buf, -1);
1256 w = (GtkScrolledWindow *) lookup_widget(main_window, "scrolledwindow6");
1257 adj = gtk_scrolled_window_get_vadjustment(w);
1258 gtk_adjustment_set_value(adj, adj->upper);
1259 gtk_scrolled_window_set_vadjustment(w, adj);
1262 free (iter);
1265 /*==============================================================================
1266 * get_move_str
1268 * Creates a move string from a move struct
1270 void get_move_str(move *m, char move_str[])
1272 Square to_sq, from_sq, arrow_sq;
1273 int to_num, from_num, arrow_num;
1274 char to_alpha, from_alpha, arrow_alpha;
1275 int state_i = states.current_state;
1276 int turn;
1278 //Determine which side just moved:
1279 turn = states.s[state_i]->turn^3;
1280 if (turn == WHITE_PLAYER)
1282 from_sq = get_square_from_engine(states.s[state_i-1]->white_q_x[m->queen],
1283 states.s[state_i-1]->white_q_y[m->queen]);
1285 else
1287 from_sq = get_square_from_engine(states.s[state_i-1]->black_q_x[m->queen],
1288 states.s[state_i-1]->black_q_y[m->queen]);
1290 to_sq = get_square_from_engine(m->tocol, m->torow);
1291 arrow_sq = get_square_from_engine(m->wallcol, m->wallrow);
1295 from_alpha = get_grid_alpha_from_square(from_sq);
1296 from_num = get_grid_num_from_square(from_sq);
1298 to_alpha = get_grid_alpha_from_square(to_sq);
1299 to_num = get_grid_num_from_square(to_sq);
1301 arrow_alpha = get_grid_alpha_from_square(arrow_sq);
1302 arrow_num = get_grid_num_from_square(arrow_sq);
1304 sprintf(move_str, "%d. %c%d-%c%d, %c%d\n", state_i, from_alpha, from_num,
1305 to_alpha, to_num, arrow_alpha, arrow_num);
1308 /*==============================================================================
1309 * get_move_from_str
1311 * This generates a move struct from a move string of the format 1. a4-a6, b6
1312 * If the string is not in a valid format, the return value will be FALSE to
1313 * inform the calling routine that the returned move struct does not contain
1314 * valid information. If everything goes well, TRUE will be returned.
1316 int get_move_from_str(move *m, char move_str[])
1318 int i=0, j;
1319 int from_row, from_col;
1320 int to_row, to_col;
1321 int arrow_row, arrow_col;
1322 Square queen_sq;
1323 int queen_i = -1;
1325 //Ignore move number
1326 while (move_str[i++] != ' ')
1328 if (i > 4)
1330 fprintf(stderr, "Space is in wrong place: %d\n", i);
1331 return FALSE; //Ack! this can't be right!
1334 from_col = move_str[i++] - 'a';
1335 from_row = move_str[i++] - '1';
1336 if (move_str[i] == '0')
1338 from_row = 9;
1339 i++;
1342 if (move_str[i++] != '-')
1344 fprintf(stderr, "Expected a hyphen at index %d\n", i);
1345 return FALSE; //Ack!! I expected a '-' here, this is not a valid move string
1348 to_col = move_str[i++] - 'a';
1349 to_row = move_str[i++] - '1';
1350 if (move_str[i] == '0')
1352 to_row = 9;
1353 i++;
1356 if (move_str[i++] != ',')
1358 fprintf(stderr, "Expected a comma at index %d\n", i);
1359 return FALSE; //Ack!! I expected a ',' here, this is not a valid move string
1361 if (move_str[i++] != ' ')
1363 fprintf(stderr, "Expected a space at index %d\n", i);
1364 return FALSE; //Ack!! I expected a ' ' here, this is not a valid move string
1367 arrow_col = move_str[i++] - 'a';
1368 arrow_row = move_str[i++] - '1';
1369 if (move_str[i++] == '0')
1370 arrow_row = 9;
1372 //Find the index to the appropriate queen
1373 queen_sq = get_square_from_engine(from_col, from_row);
1374 for(j=0; j<4; j++)
1376 if (queen_sq == board->square_to_wh_queen_map[j])
1378 queen_i = j;
1379 //printf("found move for white queen\n");
1381 if (queen_sq == board->square_to_bl_queen_map[j])
1383 queen_i = j;
1384 //printf("found move for black queen\n");
1387 if (queen_i == -1)
1389 fprintf(stderr, "Couldn't find a queen at square %d\n", queen_sq);
1390 return FALSE; //Couldn't find queen index!
1393 m->queen = queen_i;
1394 m->tocol = to_col;
1395 m->torow = to_row;
1396 m->wallcol = arrow_col;
1397 m->wallrow = arrow_row;
1399 return TRUE;
1404 int read_in_moves(FILE *history_fd)
1406 char *buffer=NULL;
1407 size_t buf_size = 30;
1409 state *s;
1410 move m;
1411 int replay_mode = bstate_get_replay_mode();
1412 int replay_delay = 0;
1413 int game_life = bstate_get_game_life();
1414 GtkWidget *delay;
1416 if (replay_mode)
1418 delay = (GtkWidget *)lookup_widget(main_window, "ReplayDelaySpinner");
1420 else
1422 bstate_set_dont_slide(TRUE);
1424 //printf("History contents:\n");
1425 while (getline(&buffer, &buf_size, history_fd) != -1)
1427 if (replay_mode && !bstate_get_replay_mode()) //If not in replay mode anymore, drop out
1428 return FALSE;
1429 s = states.s[states.current_state];
1431 if (buffer != NULL)
1432 printf("%s", buffer);
1434 if (get_move_from_str(&m, buffer))
1436 makemove(s,m); //register w/ engine
1437 move_piece(m); //register w/ board
1438 if (game_life != bstate_get_game_life())
1439 return FALSE;
1440 print_move_in_text_window(&m);
1441 dup_state(s, states.s[++(states.current_state)]);
1443 else
1445 fprintf(stderr, "Move string is invalid\n");
1446 bstate_set_dont_slide(FALSE);
1447 return FALSE;
1449 free(buffer);
1450 buffer = NULL;
1452 if (replay_mode) //Delay for appropriate amount of time
1454 replay_delay = gtk_spin_button_get_value_as_int((GtkSpinButton *)delay);
1455 rest(replay_delay);
1456 if (game_life != bstate_get_game_life())
1457 return FALSE;
1462 bstate_set_dont_slide(FALSE);
1463 return TRUE;
1467 void rest(int duration)
1469 time_t start = time(NULL);
1470 time_t end = start + duration;
1472 while (time(NULL) < end)
1474 usleep(10000);
1475 while (gtk_events_pending())
1476 gtk_main_iteration();