/* * ataxx.c - gameplay code for gataxx * Written by Chris Rogers (gandalf@pobox.com) * Based on iagno code written by Ian Peters (itp@gnu.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For more details see the file COPYING. */ #include "config.h" #include #include #include "ataxx.h" #include "gataxx.h" #include guint flip_final_id = 0; gboolean flip_final; extern guint black_computer_level; extern guint white_computer_level; extern gint animate; extern guint whose_turn; extern guint game_in_progress; extern gint8 pixmaps[7][7]; extern gint8 board[7][7]; extern MoveHistory * game; extern gint bcount; extern gint wcount; extern gint timer_valid; extern GtkWidget *time_display; extern guint tiles_to_flip; /* Wrapper for is_valid_move_board, to maintain API for CORBA stuff */ gint is_valid_piece(guint x, guint y, guint me) { return is_valid_piece_board (board, x, y, me); } gint is_valid_piece_board (gint8 board[7][7], guint x, guint y, guint me) { if (board[x][y] == me) return TRUE; return FALSE; } gint is_valid_move (guint x, guint y, guint selected_x, guint selected_y, guint me) { return is_valid_move_board (board, x, y, selected_x, selected_y, me); } /* Check if a given square is a valid move for one of the players */ gint is_valid_move_board (gint8 board[7][7], guint x, guint y, guint selected_x, guint selected_y, guint me) { guint not_me; not_me = (me == WHITE_TURN) ? BLACK_TURN : WHITE_TURN; if (board[x][y] != 0) return (FALSE); /*basically make sure that the current and selected positions are no more than 2 spaces away*/ if ((abs(y-selected_y) <= 1) && (abs(x-selected_x) <= 1)) return 1; if ((abs(y-selected_y) <= 2) && (abs(x-selected_x) <= 2)) return 2; return (FALSE); } /* Wrapper for move_board, to maintain API for CORBA stuff */ gint move (guint x, guint y, guint selected_x, guint selected_y, guint me) { int retval; retval = move_board (board, x, y, selected_x, selected_y, me, 1); check_valid_moves (); check_computer_players (); return retval; } gint move_board (gint8 board[7][7], guint x, guint y, guint selected_x, guint selected_y, guint me, gint real) { guint not_me; gint count = 1; gint take_count = 0; MoveHistory * newentry; /* Stuff to do if this is a ``real'' move */ not_me = (me == WHITE_TURN) ? BLACK_TURN : WHITE_TURN; if (real) { /* Copy the old board and move info to the undo buffer */ memcpy (game->board, board, sizeof (gint8) * 7 * 7); game->x = x; game->y = y; game->me = me; newentry = g_malloc (sizeof (MoveHistory)); newentry->prev = game; game = newentry; if (whose_turn == WHITE_TURN) { whose_turn = BLACK_TURN; gui_message(_("Dark's move")); if (!white_computer_level) { games_clock_stop (GAMES_CLOCK (time_display)); } } else { whose_turn = WHITE_TURN; gui_message(_("Light's move")); if (!black_computer_level) { games_clock_stop (GAMES_CLOCK (time_display)); } } if (!((abs (y-selected_y) <= 1) && (abs (x-selected_x) <= 1))) { pixmaps[selected_x][selected_y] = 0; gui_draw_pixmap (0, selected_x, selected_y); } pixmaps[x][y] = me; gui_draw_pixmap (me, x, y); } board[x][y] = me; if (!((abs (y-selected_y) <= 1) && (abs (x-selected_x) <= 1))) { board[selected_x][selected_y] = 0; count--; } if (((gint) x - 1 >= 0) && (board[x-1][y] == not_me)) { board[x-1][y] = me; take_count++;} if ((x + 1 <= 6) && (board[x+1][y] == not_me)) { board[x+1][y] = me; take_count++; } if (((gint)y - 1 >= 0) && (board[x][y-1] == not_me)) {board[x][y-1] = me; take_count++; } if ((y + 1 <= 6) && (board[x][y+1] == not_me)) {board[x][y+1] = me; take_count++; } if ((x + 1 <= 6) && (y + 1 <= 6) && (board[x+1][y+1] == not_me)) {board[x+1][y+1] = me;take_count++; } if ((x + 1 <= 6) && ((gint)y - 1 >= 0) && (board[x+1][y-1] == not_me)) {board[x+1][y-1] = me;take_count++; } if (((gint)x - 1 >= 0) && (y + 1 <= 6) && (board[x-1][y+1] == not_me)) {board[x-1][y+1] = me;take_count++; } if (((gint)x - 1 >= 0) && (((gint)y - 1) >= 0) && (board[x-1][y-1] == not_me)) {board[x-1][y-1] = me;take_count++; } /* More stuff for a ``real'' move */ if (real) { /* Update the statusbar counters */ if (me == BLACK_TURN) { bcount = bcount + count + take_count; wcount -= take_count; } else { wcount += count + take_count; bcount -= take_count; } gui_status(); if (not_me == BLACK_TURN && !black_computer_level && timer_valid) { games_clock_start (GAMES_CLOCK (time_display)); } if (not_me == WHITE_TURN && !white_computer_level && timer_valid) { games_clock_start (GAMES_CLOCK (time_display)); } tiles_to_flip = 1; } return (FALSE); } gint computer_move_3 (guint me) { guint xs[320], ys[320], xss[320], yss[320]; guint weights[320]; gint num_maxes = 0; gint maxpieces = -1; gint tmp; guint num_moves = 0; guint i, j, k, l; gint8 tboard[7][7]; gint * tmplist; for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, me)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,me)){ memcpy (tboard, board, sizeof (gint8) * 7 * 7); move_board (tboard, k, l, i, j, me, FALSE); tmp = count_pieces (tboard,me); if (tmp == maxpieces) { xss[num_moves] = i; yss[num_moves] = j; xs[num_moves] = k; ys[num_moves] = l; weights[num_moves] = tmp; num_maxes++; num_moves++; } else if (tmp > maxpieces) { xss[num_moves] = i; yss[num_moves] = j; xs[num_moves] = k; ys[num_moves] = l; weights[num_moves] = tmp; maxpieces = tmp; num_maxes = 1; num_moves++; } } if (num_moves) { tmplist = g_malloc (sizeof (gint) * num_maxes); j = 0; for (i = 0; i < num_moves; i++) if (weights[i] == maxpieces) { tmplist[j++] = i; } j = (rand ()>>3) % num_maxes; i = tmplist[j]; move (xs[i], ys[i], xss[i], yss[i], me); g_free (tmplist); } return (FALSE); } gint computer_move_2(guint me) { guint xs[1000], ys[1000], xss[1000], yss[1000]; /*another canidate for linked lists*/ gint weights[1000]; gint maxpieces = 0; gint maxwhite = 0; gint maxwhite2 = -50; gint tmp, tmp2, tmp3; guint num_moves = 0; guint i, j, k, l; guint i2,j2,k2,l2; gint8 tboard[7][7], t2board[7][7]; guint not_me; gint * tmplist; gint num_maxes = 0; not_me = (me == WHITE_TURN) ? BLACK_TURN : WHITE_TURN; for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, me)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,me)){ maxpieces = 0; memcpy (tboard, board, sizeof (gint8) * 7 * 7); move_board (tboard, k, l, i, j, me, FALSE); maxwhite = 0; for (i2 = 0; i2 < 7; i2++) for (j2 = 0; j2 < 7; j2++) if (is_valid_piece (i2, j2, not_me)) for (k2 = 0; k2 < 7; k2++) for (l2 = 0; l2 < 7; l2++) if (is_valid_move (k2,l2,i2,j2,not_me)){ memcpy (t2board, tboard, sizeof (gint8) * 7 * 7); move_board (t2board, k2, l2, i2, j2, not_me, FALSE); tmp = count_pieces (t2board,not_me); tmp3 = count_pieces (t2board, me); /* g_print("maxblack:%d maxwhite:%d\n",tmp,tmp3); */ if (tmp > maxpieces) { maxwhite = tmp3; maxpieces = tmp; } else if ((tmp == maxpieces) && (tmp3 < maxwhite)) maxwhite = tmp3; } tmp2 = (maxwhite); /* g_print("weight:%d\n",tmp2); */ if ( tmp2 == maxwhite2) { xss[num_moves] = i; yss[num_moves] = j; xs[num_moves] = k; ys[num_moves] = l; weights[num_moves] = maxwhite2; num_maxes++; num_moves++; /* g_print("num_moves:%d weight:%d\n",num_moves,maxwhite2);*/ } else if (tmp2 > maxwhite2){ xss[num_moves] = i; yss[num_moves] = j; xs[num_moves] = k; ys[num_moves] = l; maxwhite2 = tmp2; weights[num_moves] = maxwhite2; num_maxes = 1; num_moves++; /* g_print("num_moves:%d weight:%d\n",num_moves,maxwhite2);*/ } } if (num_moves) { tmplist = g_malloc (sizeof (gint) * num_maxes); /* g_print("num_maxes:%d\n",num_maxes); */ j = 0; for (i = 0; i < num_moves; i++) { /* g_print("weight:%d, max:%d\n",weights[i],maxwhite2); */ if (weights[i] == maxwhite2) { tmplist[j++] = i; } } /* g_print("maxes assigned:%d\n",j); */ j = (rand ()>>3) % num_maxes; /* g_print("index into tmplist:%d\n",j); */ i = tmplist[j]; /* g_print("i:%d\n",i); */ move (xs[i], ys[i], xss[i], yss[i], me); g_free (tmplist); } return (FALSE); } gint computer_move_1 (guint me) { guint xs[1000], ys[1000], xss[1000], yss[1000]; /*another canidate for linked lists*/ gint weights[1000]; gint maxpieces = 0; gint maxwhite = 0; gint maxwhite2 = -50; gint tmp, tmp2, tmp3; guint num_moves = 0; guint i, j, k, l; guint i2,j2,k2,l2; gint8 tboard[7][7], t2board[7][7]; guint not_me; gint * tmplist; gint num_maxes = 0; not_me = (me == WHITE_TURN) ? BLACK_TURN : WHITE_TURN; for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, me)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,me)){ maxpieces = 0; memcpy (tboard, board, sizeof (gint8) * 7 * 7); move_board (tboard, k, l, i, j, me, FALSE); maxwhite = 0; for (i2 = 0; i2 < 7; i2++) for (j2 = 0; j2 < 7; j2++) if (is_valid_piece (i2, j2, not_me)) for (k2 = 0; k2 < 7; k2++) for (l2 = 0; l2 < 7; l2++) if (is_valid_move (k2,l2,i2,j2,not_me)){ memcpy (t2board, tboard, sizeof (gint8) * 7 * 7); move_board (t2board, k2, l2, i2, j2, not_me, FALSE); tmp = count_pieces (t2board,not_me); tmp3 = count_pieces (t2board, me); /* g_print("maxblack:%d maxwhite:%d\n",tmp,tmp3); */ if (tmp > maxpieces) { maxwhite = tmp3; maxpieces = tmp; } else if ((tmp == maxpieces) && (tmp3 < maxwhite)) maxwhite = tmp3; } tmp2 = (maxwhite - maxpieces); /* g_print("weight:%d\n",tmp2); */ if ( tmp2 == maxwhite2) { xss[num_moves] = i; yss[num_moves] = j; xs[num_moves] = k; ys[num_moves] = l; weights[num_moves] = maxwhite2; num_maxes++; num_moves++; /* g_print("num_moves:%d weight:%d\n",num_moves,maxwhite2); */ } else if (tmp2> maxwhite2){ xss[num_moves] = i; yss[num_moves] = j; xs[num_moves] = k; ys[num_moves] = l; maxwhite2 = tmp2; weights[num_moves] = maxwhite2; num_maxes = 1; num_moves++; /* g_print("num_moves:%d weight:%d\n",num_moves,maxwhite2); */ } } if (num_moves) { tmplist = g_malloc (sizeof (gint) * num_maxes); /* g_print("num_maxes:%d\n",num_maxes); */ j = 0; for (i = 0; i < num_moves; i++) { /* g_print("weight:%d, max:%d\n",weights[i],maxwhite2); */ if (weights[i] == maxwhite2) { tmplist[j++] = i; } } /* g_print("maxes assigned:%d\n",j); */ j = (rand ()>>3) % num_maxes; /* g_print("index into tmplist:%d\n",j); */ i = tmplist[j]; /* g_print("i:%d\n",i); */ move (xs[i], ys[i], xss[i], yss[i], me); g_free (tmplist); } return (FALSE); } gint count_pieces (gint8 board[7][7], gint me) { guint tmp = 0; guint i, j; for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (board[i][j] == me) tmp++; return(tmp); } static gboolean flip_final_results (gpointer data) { guint i; guint white_pieces; guint black_pieces; guint adder = 0; white_pieces = count_pieces (board, WHITE_TURN); black_pieces = count_pieces (board, BLACK_TURN); for (i = 0; i < black_pieces; i++) { board[i % 7][i / 7] = BLACK_TURN; if (pixmaps[i % 7][i / 7] < 1) pixmaps[i % 7][i / 7] = WHITE_TURN; if (pixmaps[i % 7][i / 7] == WHITE_TURN) { pixmaps[i % 7][i / 7] += adder; } } for (i = black_pieces; i < 49 - white_pieces; i++) { board[i % 7][i / 7] = 0; pixmaps[i % 7][i / 7] = 100; } for (i = 49 - white_pieces; i < 49; i++) { board[i % 7][i / 7] = WHITE_TURN; if (pixmaps[i % 7][i / 7] == 0) pixmaps[i % 7][i / 7] = BLACK_TURN; if (pixmaps[i % 7][i / 7] == BLACK_TURN) { pixmaps[i % 7][i / 7] -= adder; } } tiles_to_flip = 1; return (FALSE); } gint check_valid_moves (void) { guint i, j, k, l; guint white_moves = 0; guint black_moves = 0; if (!game_in_progress) return (TRUE); switch(whose_turn) { case WHITE_TURN: for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, WHITE_TURN)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,WHITE_TURN)) return (TRUE); break; case BLACK_TURN: for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, BLACK_TURN)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,BLACK_TURN)) return (TRUE); break; } switch(whose_turn) { case WHITE_TURN: for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, BLACK_TURN)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,BLACK_TURN)) black_moves++; break; case BLACK_TURN: for (i = 0; i < 7; i++) for (j = 0; j < 7; j++) if (is_valid_piece (i, j, WHITE_TURN)) for (k = 0; k < 7; k++) for (l = 0; l < 7; l++) if (is_valid_move (k,l,i,j,WHITE_TURN)) white_moves++; break; } if (!white_moves || !black_moves) { games_clock_stop (GAMES_CLOCK (time_display)); white_moves = count_pieces (board, WHITE_TURN); black_moves = count_pieces (board, BLACK_TURN); if (white_moves > black_moves) gui_message(_("Light player wins!")); if (black_moves > white_moves) gui_message(_("Dark player wins!")); if (white_moves == black_moves) gui_message(_("The game was a draw.")); whose_turn = 0; game_in_progress = 0; if (flip_final) flip_final_id = g_timeout_add (3000, flip_final_results, NULL); return (TRUE); } if (whose_turn == WHITE_TURN) { gui_message (_("Light must pass, Dark's move")); whose_turn = BLACK_TURN; if (white_computer_level ^ black_computer_level) { if (!black_computer_level && timer_valid) games_clock_start (GAMES_CLOCK (time_display)); else games_clock_stop (GAMES_CLOCK (time_display)); } return (TRUE); } if (whose_turn == BLACK_TURN) { gui_message (_("Dark must pass, Light's move")); whose_turn = WHITE_TURN; if (white_computer_level ^ black_computer_level) { if (!white_computer_level && timer_valid) games_clock_start (GAMES_CLOCK (time_display)); else games_clock_stop (GAMES_CLOCK (time_display)); } return (TRUE); } return (TRUE); }