昨天在网上乱转,在一个似乎是台湾人写的博客里面看到一个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;
}