Задача: создать игру Пятнашки; Перемещение элементов ("квадратиков") осуществляется при нажатии на них левой кнопкой мыши. Производится проверка на наличие 0 в окрестности элемента в матрице (сверху, снизу, слева и справа) и затем, если 0 найден, осуществляется перемещение элемента в данном направлении. При нажатии на клавишу 'r' (маленькая, английская), производится случайная перестановка элементов и перерисовка состояния. После использования рекомендуется проверить состояние, чтобы убедиться, что данная перестановка элементов имеет решение. При нажатии на клавишу 'c' (маленькая, английская), производится проверка состояния. Возможные состояния: Проверка состояния осуществляется с помощью подсчета инверсий (элементы матрицы a, такие что ai > aj, но i < j). Затем, количество инверсий суммируется с номером строки в которой стоит 0 (пустой элемент), четность этой суммы и свидетельствует о решаемости данной перестановки: /* Подключаемые модули */ #pragma comment(lib,"gthread-2.0.lib") #pragma comment(lib,"gtk-win32-2.0.lib") #pragma comment(lib,"glib-2.0.lib") #pragma comment(lib,"gobject-2.0.lib") #pragma comment(lib,"gdk-win32-2.0.lib") #pragma comment(lib,"gdk_pixbuf-2.0.lib") #pragma comment(lib,"pango-1.0.lib") #pragma comment(lib,"pangowin32-1.0.lib") #pragma comment(lib,"intl.lib") /* Подключаемые библиотеки; WIDTH - ширина создаваемого окна; HEIGHT - высота создаваемого окна; N - разрядность матрицы ||NxN||; R - длина стороны квадратика; shadow - сдвиг, чтобы из квадрата, радиуса R, получить квадрат радиуса чуть меньше; */ #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> #include <stdlib.h> #include <time.h> #define WIDTH N*R #define HEIGHT N*R #define N 4 #define R 100 #define shadow 5 int X1,Y1,Y2,X2,x1,x2,y1,y2,I,J,vector; int a[N][N],lent; char *text; GdkColor fclrb,fclrw,fclrg,fclrr,fclrp; GdkGC *gc; GtkWidget *window; GdkDrawable *w; double x_mouse, y_mouse; gboolean boolstart(GtkWidget *widget, int XX1, int YY1, int XX2, int YY2); // перерисовка состояния пятнашек. gboolean mousemove(GtkWidget *w, GdkEvent *e,gpointer data); // отслеживание перемещение мышки gboolean on_click(GtkWidget *Window, GdkEventButton *event, gpointer data); //функция, обрабатывает событие click gboolean on_draw(GtkWidget *widget, GdkEventExpose *event, gpointer data); // задает исходное состояние, и цвета. gboolean destroy(GtkWidget *widget); gboolean keypress(GtkWidget *widget, GdkEventKey *e,gpointer data); // обработка нажатия клавиш на клавиатуре. gint delete_event(GtkWidget *widget); void gettext(char*,int, int*); // получение строки выводимого текста. gboolean time_wind(GtkWidget *widget); // перемещение квадратика void draw_text_in_center(gchar * text, GtkWidget *w, GdkGC *gc, gint xc, gint yc, unsigned t); // вывод текста /* получение строки выводимого текста, преобразуем целое число в стоку символов: */ void gettext(char *t,int a, int* lt) { if(a > 9) { *lt = 2; t[1] = a%10 + '0'; a = a/10; t[0] = a%10 + '0'; } else { *lt = 1; t[0] = a%10 + '0'; } } /* Вывод текста на экран */ void draw_text_in_center(gchar * text, GtkWidget *w, GdkGC *gc, gint xc, gint yc, unsigned t = lent) { PangoContext *context=gtk_widget_create_pango_context(w); PangoLayout *layout= pango_layout_new(context); gint width,height; pango_layout_set_text(layout,text,t); pango_layout_get_pixel_size(layout,&width,&height); gdk_draw_layout (w->window,gc,xc-width/2,yc-height/2,layout); g_object_unref(context); g_object_unref(layout); } /* отслеживание перемещений мышки */ gboolean mousemove(GtkWidget *w, GdkEvent *e,gpointer data) { double a,b; gdk_event_get_coords(e,&a,&b); x_mouse=a; y_mouse=b; return FALSE; } /* обработка нажатия клавиш на клавиатуре */ gboolean keypress(GtkWidget *widget, GdkEventKey *e,gpointer data) { int st[N*N - 1],i,k,j,s,zero,t1,rdt,t2,tt1,tt2; switch(e->keyval) { case (GDK_c): // если нажали английскую 'c', проверяем состояние; { for(i=0,k=0; i<N; i++) // переписываем элементы в строчку, исключая 0 { for(j=0; j<N; j++) { if(a[i][j] != 0) { st[k] = a[i][j]; k++; } else { zero = i + 1; } } } s = 1; k = 0; while(s) // подсчет инверсий { i = 0; s = 0; while(i < N*N - 2) { if(st[i] > st[i+1]) { k++; // +1 инверсия s = 1; j = st[i]; st[i] = st[i+1]; st[i+1] = j; } i++; } } if(k == 0 && a[N-1][N-1] == 0) // готово { gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,5,HEIGHT,WIDTH-10,15); gdk_gc_set_rgb_fg_color(gc,&fclrp); draw_text_in_center("State: Done",widget,gc,WIDTH/11,HEIGHT + 5,13); } else { k = k + zero; if(k%2 == 0) // решаемая ситуация { gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,5,HEIGHT,WIDTH-10,15); gdk_gc_set_rgb_fg_color(gc,&fclrg); draw_text_in_center("State: Normal",widget,gc,WIDTH/10,HEIGHT + 5,13); } else // не решаемая ситуация { gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,5,HEIGHT,WIDTH-10,15); gdk_gc_set_rgb_fg_color(gc,&fclrr); draw_text_in_center("State: Error!!",widget,gc,WIDTH/10,HEIGHT + 5,14); } } break; } case (GDK_r): // если нажали английскую 'r', делаем перестановку элементов; { rdt = rand()%100 + 20; for(i=0; i<rdt; i++) { t1 = rand()%N; t2 = rand()%N; tt1 = rand()%(N/2); tt2 = rand()%(N/2) + N/2; j = a[tt1][t1]; a[tt1][t1] = a[tt2][t2]; a[tt2][t2] = j; } boolstart(window,0,0,WIDTH,HEIGHT); // перерисовываем состояние пятнашек, после перемещения элементов матрицы. break; } } return TRUE; } int main(int arge, char **argv) { int i,j,k; GdkColor clr; gtk_init(&arge,&argv); k = 0; for(i=0;i<N;i++) // создание начальной матрицы { for(j=0;j<N;j++) { k++; if(i == N-1 && j == N-1) a[i][j] = 0; else a[i][j] = k; } } text = (char*)malloc(sizeof(char)*2); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(window,WIDTH,HEIGHT + 50); gtk_widget_add_events(window,GDK_POINTER_MOTION_MASK); gtk_widget_add_events(window,GDK_BUTTON_PRESS_MASK); gtk_widget_add_events(window,GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(window),"motion-notify-event",G_CALLBACK(mousemove),NULL); g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(destroy),NULL); g_signal_connect(G_OBJECT(window),"delete_event",G_CALLBACK(delete_event),NULL); g_signal_connect(G_OBJECT(window),"button-press-event",G_CALLBACK(on_click),NULL); g_signal_connect(G_OBJECT(window),"key-press-event",G_CALLBACK(keypress),NULL); gdk_color_parse("white",&clr); gtk_widget_modify_bg(window,GTK_STATE_NORMAL,&clr); g_signal_connect(G_OBJECT(window),"expose_event",G_CALLBACK(on_draw),NULL); gtk_widget_show_all(window); gtk_main(); return 0; } gboolean destroy(GtkWidget *widget) { return FALSE; } gint delete_event(GtkWidget *widget) { gtk_main_quit(); return 1; } /* при нажатии на левую кнопку мыши, проверяем, можем ли мы сдвинуться в каком-либо направлении (т.е. есть ли в окрестности 0) vector: 1 - влево 2 - вверх 3 - вправо 4 - вниз */ gboolean on_click(GtkWidget *Window, GdkEventButton *event, gpointer data) { int i,j; for(i=0; i<N; i++) { for(j=0; j<N; j++) { if(x_mouse > j*R && x_mouse < (j+1)*R && y_mouse > i*R && y_mouse < (i+1)*R) { x1 = j*R; y1 = i*R; I = i; J = j; } } } vector = 0; if(I == 0 || J == 0 || I == N-1 || J == N-1) { if(I == 0 && J == 0) { if(a[I][J+1] == 0) vector = 3; if(a[I+1][J] == 0) vector = 4; } else if(I == 0 && J == N-1) { if(a[I][J-1] == 0) vector = 1; if(a[I+1][J] == 0) vector = 4; } else if(I == N-1 && J == 0) { if(a[I-1][J] == 0) vector = 2; if(a[I][J+1] == 0) vector = 3; } else if(I == N-1 && J == N-1) { if(a[I-1][J] == 0) vector = 2; if(a[I][J-1] == 0) vector = 1; } else if(I == 0) { if(a[I][J-1] == 0) vector = 1; if(a[I+1][J] == 0) vector = 4; if(a[I][J+1] == 0) vector = 3; } else if(I == N-1) { if(a[I-1][J] == 0) vector = 2; if(a[I][J-1] == 0) vector = 1; if(a[I][J+1] == 0) vector = 3; } else if(J == 0) { if(a[I+1][J] == 0) vector = 4; if(a[I-1][J] == 0) vector = 2; if(a[I][J+1] == 0) vector = 3; } else if(J == N-1) { if(a[I-1][J] == 0) vector = 2; if(a[I+1][J] == 0) vector = 4; if(a[I][J-1] == 0) vector = 1; } } else { if(a[I][J-1] == 0) vector = 1; if(a[I-1][J] == 0) vector = 2; if(a[I][J+1] == 0) vector = 3; if(a[I+1][J] == 0) vector = 4; } g_timeout_add(20,(GSourceFunc)time_wind,(gpointer)window); return TRUE; } /* После того, как мы сделали случайную перестановку элементов (при нажатии клавишы 'r', нам нужно вывести на экран результат) */ gboolean boolstart(GtkWidget *widget, int XX1, int YY1, int XX2, int YY2) { int i,j; gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,0,0,XX2,YY2); for(i=0; i<N; i++) { Y1 = i*R; for(j=0; j<N; j++) { X1 = j*R; if(a[i][j] != 0) { gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,X1,Y1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,X1+shadow,Y1+shadow,R-2*shadow,R-2*shadow); gdk_gc_set_rgb_fg_color(gc,&fclrb); gettext(text,a[i][j],&lent); draw_text_in_center(text,widget,gc,X1+R/2,Y1+R/2); } } } gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,5,HEIGHT,WIDTH-10,15); gdk_gc_set_rgb_fg_color(gc,&fclrr); draw_text_in_center("State: Random",widget,gc,WIDTH/9,HEIGHT + 5,13); gdk_gc_set_rgb_fg_color(gc,&fclrb); return TRUE; } /* Создаем изображение начального состояния и задаем начальные элементы (цвета, надписи и т.п.) */ gboolean on_draw(GtkWidget *widget,GdkEventExpose *event, gpointer data) { int i, j, XX1, YY1, XX2, YY2; XX1 = YY1 = 0; XX2 = WIDTH; YY2 = HEIGHT; gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)]; w = widget->window; fclrb.pixel = 0; fclrb.red = 0x6d00; fclrb.green = 0xcf00; fclrb.blue = 0xf600; fclrw.pixel = 0; fclrw.red = 0xFFFF; fclrw.green = 0xFFFF; fclrw.blue = 0xFFFF; fclrg.pixel = 0; fclrg.red = 0; fclrg.green = 0xFFFF; fclrg.blue = 0; fclrr.pixel = 0; fclrr.red = 0xFFFF; fclrr.green = 0; fclrr.blue = 0; fclrp.pixel = 0; fclrp.red = 0xFFFF; fclrp.green = 0; fclrp.blue = 0xFFFF; gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,0,0,XX2,YY2); for(i=0; i<N; i++) { Y1 = i*R; for(j=0; j<N; j++) { X1 = j*R; if(i != N-1 || j != N-1) { gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,X1,Y1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,X1+shadow,Y1+shadow,R-2*shadow,R-2*shadow); gdk_gc_set_rgb_fg_color(gc,&fclrb); gettext(text,a[i][j],&lent); draw_text_in_center(text,widget,gc,X1+R/2,Y1+R/2); } } } gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,5,HEIGHT,WIDTH-10,45); gdk_gc_set_rgb_fg_color(gc,&fclrp); draw_text_in_center("State: Done",widget,gc,WIDTH/11,HEIGHT + 5,13); gdk_gc_set_rgb_fg_color(gc,&fclrb); draw_text_in_center("Plz press 'c' to check the state",widget,gc,WIDTH/5,HEIGHT + 20,32); draw_text_in_center("Plz press 'r', for on randomizer",widget,gc,WIDTH/5,HEIGHT + 35,32); return TRUE; } /* Перемещение квадратика в направлении найденного вектора (после обработки события: click) */ gboolean time_wind(GtkWidget *widget) { int xx1,yy1; if(vector == 1) { xx1 = x1 - R; yy1 = y1; gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,x1,y1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,xx1,yy1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,xx1+shadow,yy1+shadow,R-2*shadow,R-2*shadow); gdk_gc_set_rgb_fg_color(gc,&fclrb); gettext(text,a[I][J],&lent); draw_text_in_center(text,widget,gc,xx1+R/2,yy1+R/2); a[I][J-1] = a[I][J]; a[I][J] = 0; } else if(vector == 2) { xx1 = x1; yy1 = y1 - R; gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,x1,y1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,xx1,yy1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,xx1+shadow,yy1+shadow,R-2*shadow,R-2*shadow); gdk_gc_set_rgb_fg_color(gc,&fclrb); gettext(text,a[I][J],&lent); draw_text_in_center(text,widget,gc,xx1+R/2,yy1+R/2); a[I-1][J] = a[I][J]; a[I][J] = 0; } else if(vector == 3) { xx1 = x1 + R; yy1 = y1; gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,x1,y1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,xx1,yy1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,xx1+shadow,yy1+shadow,R-2*shadow,R-2*shadow); gdk_gc_set_rgb_fg_color(gc,&fclrb); gettext(text,a[I][J],&lent); draw_text_in_center(text,widget,gc,xx1+R/2,yy1+R/2); a[I][J+1] = a[I][J]; a[I][J] = 0; } else if(vector == 4) { xx1 = x1; yy1 = y1 + R; gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,x1,y1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrb); gdk_draw_rectangle(w,gc,TRUE,xx1,yy1,R,R); gdk_gc_set_rgb_fg_color(gc,&fclrw); gdk_draw_rectangle(w,gc,TRUE,xx1+shadow,yy1+shadow,R-2*shadow,R-2*shadow); gdk_gc_set_rgb_fg_color(gc,&fclrb); gettext(text,a[I][J],&lent); draw_text_in_center(text,widget,gc,xx1+R/2,yy1+R/2); a[I+1][J] = a[I][J]; a[I][J] = 0; } return FALSE; }
Ключевые слова:
Игра, пятнашки
|
|||||||