code2012

加油,坚持,努力,自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

GTK的扫雷程序 转

Posted on 2011-10-26 10:53  code2012  阅读(435)  评论(0编辑  收藏  举报

    昨天在网上乱转,在一个似乎是台湾人写的博客里面看到一个GTK的扫雷程序,因为我是个扫雷迷,平时没事就点扫雷(

见笑了)。就下下来看了看,发现其功能有些不太完善,于是改了改,加了复位功能和完善了其它一些小的设计,不过因为还有MATLAB的作业程序要写,扫雷英雄榜,规模的选择就没有加。还有就是忙了一下午也没搞明白到底button上label的颜色怎么设置,这样就可以将不同雷数的数字用不同的颜色显示,更像大家平时玩的扫雷一样,有谁懂的一定要告诉我啊,谢谢你们了~~
                
                
                
                
                #include gtk/gtk.h>
struct block
{
    gint       count;  //表示一个点周围有多少个雷
    gboolean   mine;  //这个点是否藏有雷
    gboolean   marked; //是否被标记有雷
    gboolean   opened; //是否被掀开
    GtkWidget *button;
};
static struct block *map; //整个地雷区图
static gint width=10;     //雷区的宽度
static gint height=10;    //雷区的高度
static gint mines=10;     //总共的地雷数量
static GtkWidget *window;
static GtkWidget *mine_label; //显示剩余的地雷数
static GtkWidget *time_label; //显示剩余的地雷时间
static GtkWidget *reset;   //用于游戏结束后的重新复位
static gint button_size=25;   //每个按钮的大小
static gint opened_count;  //已掀开了多少个格子
static gint marked_count;  //已经标记了多少个格子
static gboolean game_over; //游戏是否结束的标志
static gint game_time;//游戏时间的记录
static gint i=0, j,index;
static gint size;//整个地图区的大小
static gboolean mark;//用于标记是否按了复位键
static gboolean clicked;//用于表示是否按下掀开键
//游戏结束时调用的函数
void gameover(gboolean won)
  {
     GtkWidget *dialog;
        gchar buf[4];
     gchar msg[100];
        game_over=TRUE;
        if(won==TRUE)//扫雷成功的提示信息
          {
        g_snprintf(msg, 100, "哇!你这么牛,用时 %3d 秒。", game_time);
      }
        else//踩到地雷的情况
          { 
         g_snprintf(msg, 100, "太有才了!这么快就玩完了~~");
      }
        for(i=0, index=0; iheight; i++)//游戏结束后让所有格子都打开
          {
              for(j=0; jwidth; j++)
                {
                     if(map[index].opened==FALSE)
                     {
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(map[index].button),TRUE);
                        gtk_button_set_label(GTK_BUTTON(map[index].button), " ");
                         if(map[index].mine==FALSE) 
                          {
                             if(map[index].count==0) gtk_button_set_label(GTK_BUTTON(map[index].button), "");
                             else
                                {
                                  g_snprintf(buf, 4, "%d", map[index].count);
                                  gtk_button_set_label(GTK_BUTTON(map[index].button), buf);
                                 }
                           }
                        else gtk_button_set_label(GTK_BUTTON(map[index].button), "*");
                       }
                  index++;
               }
         }
    //弹出窗口显示提示信息
    dialog=gtk_message_dialog_new(GTK_WINDOW(window), 0,GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msg);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
  }
//布雷函数
void put_mines()
{
   while(imines)
   {
        gint index;
    gint row, col;
    index=g_random_int_range(0, size);
    if(map[index].mine==TRUE)//如果此点有雷则跳过
        continue;
    map[index].mine=TRUE;
    row=index/width;
    col=index%width; 
    //周围格子的count加1 
    if(row>0)
           {
              if(col>0) map[index-width-1].count++;
              map[index-width].count++;
              if(colwidth-1) map[index-width+1].count++;
           }
         if(col>0) map[index-1].count++;
         if(colwidth-1) map[index+1].count++;
     if(rowheight-1)
           {
               if(col>0) map[index+width-1].count++;
               map[index+width].count++;
               if(colwidth-1) map[index+width+1].count++;
       }
          i++;
    }
}
//打开某一个格子对应的函数
void open_block(gint x, gint y)
{
     gint index;
     GtkWidget *button;
     index=x+y*width;
     if(game_over==TRUE || map[index].marked==TRUE) 
        return; //游戏结束或防止某家对已标记的盒子打开
     button=map[index].button;
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),TRUE);//改变状态为按下
     clicked=TRUE;//表示有敲击
     if(map[index].opened==TRUE) //防止打开已经打开的盒子
        return;
     map[index].opened=TRUE; //打开盒子
     if(map[index].mine==TRUE)//如果此盒子下有雷
        {
        gtk_button_set_label(GTK_BUTTON(button), "*");
        gameover(FALSE); //踩到地雷游戏结束
        return;
    }
     if(map[index].count>0)//若周围有雷
        {
        gchar buf[2];
        g_snprintf(buf, 2, "%d", map[index].count);
        gtk_button_set_label(GTK_BUTTON(button), buf);
    }
       opened_count++; //增加一个已掀开的格子数
     if(opened_count+mines==width*height)//获胜的标志
        {
        gameover(TRUE); 
        return;
    }
      if(map[index].count==0)//若周围没有雷则掀开周围的格子
        { 
       if(y>0)
             {
        if(x>0) open_block(x-1, y-1);
        open_block(x, y-1);
        if(xwidth-1) open_block(x+1, y-1);
         }
        if(x>0) open_block(x-1, y);
        if(xwidth-1) open_block(x+1, y);
        if(yheight-1)
                   {
              if(x>0) open_block(x-1, y+1);
              open_block(x, y+1);
              if(xwidth-1) open_block(x+1, y+1);
           }
    }
}
//复位
void g_reset(GtkWidget *widget,gpointer *data)
{
    opened_count=0;
    marked_count=0;
    game_over=FALSE;
    mark=TRUE;
    clicked=FALSE;
    gtk_label_set_text(GTK_LABEL(mine_label), "10");
    for(i=0, index=0; iheight; i++)
      {
         for(j=0; jwidth; j++)
          {
            map[index].mine=FALSE;
            map[index].count=0;
            map[index].marked=FALSE;
            map[index].opened=FALSE;
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(map[index].button),FALSE);
            gtk_button_set_label(GTK_BUTTON(map[index].button), " ");
            index++;
           }
       }
   i=0;
   put_mines();
}
//计时器
gboolean tick(gpointer data)
{
     gchar buf[8];
     if(game_over==FALSE)//计时
         {
           if(mark==TRUE) game_time=0,mark=FALSE;//得位标记mark为TRUE,则时间刷新为0
           if(clicked==TRUE)//如果有掀雷,则开始计时
             {
           game_time++;//增加游戏时间
           g_snprintf(buf, 8, "%d", game_time);
             }
           else g_snprintf(buf,2,"%d",game_time);//没有敲击时一直显示为0
           gtk_label_set_text(GTK_LABEL(time_label), buf);//刷新时间显示
          } 
  return TRUE;//返回TRUE继续计时
}
//键盘敲击时的敲击
gboolean on_mouse_click(GtkWidget *widget,GdkEventButton *event,gpointer data)
  {
     gint index;
     gint row, col;
     gchar buf[4];
     if(game_over==TRUE) return TRUE; //游戏结束时按键失去作用
     index=(gint)data;
     switch(event->button)
      {
    case 1://左键
        row=index/width;
        col=index%width;
        open_block(col, row);
        break;
    case 2: //中键
        break;
    case 3: //右键
        if(map[index].opened==TRUE)//已掀开的不作记号
            break;
        //没有记号的加上,有的去掉
        if(map[index].marked!=TRUE)
                   {
            map[index].marked=TRUE;
            gtk_button_set_label(
            GTK_BUTTON(widget), "!");
            marked_count++;
           }
                else
                  {
            map[index].marked=FALSE;
            gtk_button_set_label(
            GTK_BUTTON(widget), "");
            marked_count--;
         }
        //显示新的地雷数
        g_snprintf(buf, 4, "%d",mines-marked_count);
        gtk_label_set_text(GTK_LABEL(mine_label), buf);
    }
    return TRUE;
}
gint main(gint argc,gchar **argv)
{
   size=width*height;
   map=(struct block *)g_malloc0(sizeof(struct block)*width*height);//分配内容为‘0’的的内存空间
   put_mines();
  GtkWidget *vbox;
  GtkWidget *hbox;
  GtkWidget *label;
  gtk_init(&argc,&argv);
  window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
  g_signal_connect(G_OBJECT(window), "delete_event",gtk_main_quit, NULL);
  reset=gtk_button_new_with_label("重开");
  gtk_widget_set_usize(reset,100,28);
  vbox=gtk_vbox_new(FALSE, 0);
  hbox=gtk_hbox_new(FALSE, 0);
  label=gtk_label_new("Mines:");
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 6);
  mine_label=gtk_label_new("10");
  gtk_box_pack_start(GTK_BOX(hbox), mine_label,FALSE, FALSE, 3);
  gtk_box_pack_start(GTK_BOX(hbox),reset,FALSE,TRUE,6);
  label=gtk_label_new("Time:");
  gtk_box_pack_start(GTK_BOX(hbox), label,FALSE, FALSE, 6);
  time_label=gtk_label_new("0");
  gtk_box_pack_start(GTK_BOX(hbox), time_label,TRUE, FALSE, 0);
  gtk_widget_show_all(hbox);
  gtk_box_pack_start(GTK_BOX(vbox), hbox,FALSE, FALSE, 0);
  for(i=0, index=0; iheight; i++)//所有格子的初始化
     {
    gint j;
    hbox=gtk_hbox_new(FALSE, 0);
    for(j=0; jwidth; j++)
              {
        GtkWidget *button;
        button=gtk_toggle_button_new();
        gtk_widget_set_usize(button,
        button_size, button_size);
        g_object_set(G_OBJECT(button),"can-focus", FALSE, NULL);
        gtk_box_pack_start(GTK_BOX(hbox),button, FALSE, FALSE, 0);
        gtk_widget_show(button);
        g_signal_connect(G_OBJECT(button),"button-press-event",
        G_CALLBACK(on_mouse_click),(gpointer)index);
            map[index].button=button;
        index++;
        }
        gtk_box_pack_start(GTK_BOX(vbox), hbox,FALSE, FALSE, 0);
        gtk_widget_show(hbox);
    }
   gtk_container_add(GTK_CONTAINER(window), vbox);
   gtk_widget_show(vbox);
   gtk_widget_show(window);
   g_timeout_add(1000, (GSourceFunc)tick, NULL);//计时器启动
   g_signal_connect(GTK_OBJECT(reset),"clicked",GTK_SIGNAL_FUNC(g_reset),NULL);
  
    gtk_main();
    return 0;
}