#include #include #define BOARD_SIZE 3 struct Board { GtkWidget *buttons[3][3]; enum { OK, CANCEL } player; }; static gchar *get_image_name( struct Board board, int row, int col ) { GList *child; GtkWidget *image; gchar *name; GtkIconSize size; if( row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE ) return ""; child = gtk_container_get_children( GTK_CONTAINER( board.buttons[row][col] ) ); image = (GtkWidget *) child->data; g_list_free( child ); gtk_image_get_stock( GTK_IMAGE( image ), &name, &size ); return name; return ""; } static gboolean is_current_player( struct Board board, int i, int j ) { gchar *name; name = get_image_name( board, i, j ); if( ( !strcmp( name, GTK_STOCK_OK ) && board.player == OK ) || ( !strcmp( name, GTK_STOCK_CANCEL ) && board.player == CANCEL ) ) { return TRUE; } return FALSE; } static gboolean rc_won( struct Board board ) { int r_sum, c_sum, i, j; for( i = 0; i < BOARD_SIZE; i++ ) { r_sum = c_sum = 0; for( j = 0; j < BOARD_SIZE; j++ ) { if( is_current_player( board, i, j ) == TRUE ) { r_sum++; } if( is_current_player( board, j, i ) == TRUE ) { c_sum++; } if( r_sum == BOARD_SIZE || c_sum == BOARD_SIZE ) { return TRUE; } } } return FALSE; } static gboolean d_won( struct Board board ) { int ld_sum, rd_sum, i; ld_sum = rd_sum = 0; for( i = 0; i < BOARD_SIZE; i++ ) { if( is_current_player( board, i, i ) == TRUE ) { ld_sum++; } if( is_current_player( board, i, BOARD_SIZE - 1 - i ) == TRUE ) { rd_sum++; } } if( ld_sum == BOARD_SIZE || rd_sum == BOARD_SIZE ) { return TRUE; } return FALSE; } static gboolean draw( struct Board board ) { int sum, i, j; sum = 0; for( i = 0; i < BOARD_SIZE; i++ ) { for( j = 0; j < BOARD_SIZE; j++ ) { if( strcmp( get_image_name( board, i, j ), GTK_STOCK_ADD ) ) { sum++; } } } if( sum == BOARD_SIZE * BOARD_SIZE ) { return TRUE; } return FALSE; } static void quit_message(GtkWindow *parent, gchar *stock_id, gchar *message) { GtkWidget *dialog, *box, *image, *label; dialog = gtk_dialog_new_with_buttons( "Result", parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL ); box = gtk_hbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( GTK_DIALOG( dialog )->vbox ), box ); image = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_BUTTON ); gtk_box_pack_start( GTK_BOX( box ), image, TRUE, FALSE, 3 ); label = gtk_label_new( message ); gtk_box_pack_start( GTK_BOX( box ), label, TRUE, FALSE, 3 ); g_signal_connect_swapped( dialog, "response", G_CALLBACK( gtk_widget_destroy ), parent); gtk_widget_show_all( dialog ); } static void destroy( GtkWidget *widget, gpointer data ) { gtk_main_quit(); } static void clicked( GtkWidget *widget, struct Board *board ) { int i, j; GList *child; GtkWidget *image; gchar *name; for( i = 0; i < BOARD_SIZE; i++ ) { for( j = 0; j < BOARD_SIZE; j++ ) { if( board->buttons[i][j] == widget ) { name = get_image_name( *board, i, j ); child = gtk_container_get_children( GTK_CONTAINER( board->buttons[i][j] ) ); image = (GtkWidget *) child->data; g_list_free( child ); } } } if( !strcmp( name, GTK_STOCK_ADD ) ) { gtk_widget_destroy( image ); switch( board->player ) { case OK: name = GTK_STOCK_OK; break; case CANCEL: name = GTK_STOCK_CANCEL; break; } image = gtk_image_new_from_stock( name, GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER( widget ), image ); gtk_widget_show( image ); } if( rc_won( *board ) == TRUE || d_won( *board ) == TRUE ) { quit_message( GTK_WINDOW( widget->parent->parent ), name, "Won!" ); } if( draw( *board ) == TRUE ) { quit_message( GTK_WINDOW( widget->parent->parent ), GTK_STOCK_ADD, "Draw!" ); } switch( board->player ) { case OK: board->player = CANCEL; break; case CANCEL: board->player = OK; break; } } int main( int argc, char *argv[] ) { GtkWidget *window, *table, *image; int i, j; struct Board board; board.player = OK; gtk_init( &argc, &argv ); window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_container_set_border_width( GTK_CONTAINER( window ), 10 ); gtk_window_set_title( GTK_WINDOW( window ), "Tic Tac Toe" ); g_signal_connect( G_OBJECT( window ), "destroy", G_CALLBACK( destroy ), NULL ); table = gtk_table_new( BOARD_SIZE, BOARD_SIZE, TRUE ); gtk_table_set_row_spacings( GTK_TABLE( table ), 3 ); gtk_table_set_col_spacings( GTK_TABLE( table ), 3 ); gtk_container_add( GTK_CONTAINER( window ), table ); for( i = 0; i < BOARD_SIZE; i++ ) { for( j = 0; j < BOARD_SIZE; j++ ) { board.buttons[i][j] = gtk_button_new(); g_signal_connect( G_OBJECT( board.buttons[i][j] ), "clicked", G_CALLBACK( clicked ), (gpointer) &board ); image = gtk_image_new_from_stock( GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER( board.buttons[i][j] ), image ); gtk_widget_show( image ); gtk_table_attach_defaults( GTK_TABLE( table ), board.buttons[i][j], i, i + 1, j, j + 1 ); gtk_widget_show( board.buttons[i][j] ); } } gtk_widget_show( table ); gtk_widget_show( window ); gtk_main(); return 0; }