元旦才刚放假,说实话,我很闲……
所以又写了个扫雷,这个扫雷程序其实真要算是“初学者”级的了……
里面就用到了一个比较像样的算法,…
就是点一个空的时候把邻近的所有连通的空格全部显出……
其实聪明人一下子就知道是搜索了,深搜广搜都可以了……我用的是深搜……
呵呵,程序很简单,但我还是写了这么长,不知怎么搞地……
可能很多地方还可以精简吧……我没刻意去怎么精简它……
因为反正是好玩呀……呵呵,关键的深搜算法写得好一点就差不多了……
正好温习一下落了些时日的算法了……
程序运行状态:
源程序:bomb.cc
/***************************************************************************
* bomb.cc
* 扫雷
* Mon Jan 1 15:29:38 2007
* Copyright 2007 HuYinLin
* Email huyinlin@126.com
****************************************************************************/
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <iostream>
using namespace std;
#define FrameW 3 //边框厚
#define BASE_W 20 //小方块大小
#define LINE 16 //行数
#define COL 30 //列数
#define BOMB_NUM 80 //雷数
#define UP 30 //上方还有的其它东东
#define HW FrameW*2+COL*BASE_W //屏幕宽
#define HH FrameW+LINE*BASE_W+UP //屏幕高
#define FontW 10 //字体高度和宽度
#define FontH 18
int bomb[LINE][COL] = { };
int temp[LINE][COL] = { };
int frame[8][2] = {
-1, 0, 1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, 1, 1, -1
};
int alive = 0, TIME;
SDL_Surface *screen, //屏幕
*nobomb, //没有雷的区域
*font, //字体
*dead, //雷
*flag, //旗帜
*error, //错误标志
*newgame, //新游戏
*back, //小背景
*cover; //默认的图
SDL_Surface *
LoadIMG (const char *name)
{
SDL_Surface *tmp, *final;
if ((tmp = IMG_Load (name)) == NULL)
fprintf (stderr, "load %s error\n", name);
final = SDL_DisplayFormat (tmp);
SDL_FreeSurface (tmp);
SDL_SetColorKey (final, SDL_SRCCOLORKEY | SDL_RLEACCEL,
*(Uint32 *) final->pixels);
return final;
}
void
LoadData ()
{
nobomb = LoadIMG ("nobomb.png");
font = LoadIMG ("font.gif");
dead = LoadIMG ("dead.png");
cover = LoadIMG ("cover.gif");
error = LoadIMG ("error.png");
flag = LoadIMG ("flag.png");
newgame = LoadIMG ("new.jpg");
back = LoadIMG ("back.png");
}
int
over (int x, int y) //测试是否超出边界
{
if (x < 0 || x >= LINE || y < 0 || y >= COL)
return 1;
else
return 0;
}
int
gameover ()
{
int flag = 1;
for (int i = 0; i < LINE; i++)
for (int j = 0; j < COL; j++)
if (bomb[i][j] == -1 && temp[i][j] != 1)
flag = 0;
return flag;
}
void
drawnum (int num) //显示时间
{
SDL_Rect dst, src;
dst.x = FrameW, dst.y = FrameW;
dst.w = FontW;
dst.h = FontH;
src.w = FontW;
src.h = FontH;
src.y = 0;
int s[3] = { }, i = 2;
while (num)
{
s[i--] = num % 10;
num /= 10;
}
for (i = 0; i < 3; i++)
{
src.x = s[i] * FontW;
SDL_BlitSurface (back, &src, screen, &dst);
SDL_BlitSurface (font, &src, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
dst.x += FontW;
}
}
void
creatbomb () //绘制雷区
{
TIME = 0;
drawnum (0);
alive = 1;
int i, j, x, y, num, k;
for (i = 0; i < LINE; i++)
for (j = 0; j < COL; j++)
{
bomb[i][j] = 0;
temp[i][j] = 0;
}
for (i = 0; i < BOMB_NUM; i++)
{
x = rand () % LINE;
y = rand () % COL;
bomb[x][y] = -1; //-1表示此地有雷
}
for (i = 0; i < LINE; i++) //填其它的数
for (j = 0; j < COL; j++)
if (bomb[i][j] != -1)
{
num = 0;
for (k = 0; k < 8; k++)
{
x = i + frame[k][0];
y = j + frame[k][1];
if (!over (x, y) && bomb[x][y] == -1)
num -= bomb[x][y];
}
bomb[i][j] = num;
}
}
void
initdraw () //初始时的画片
{
int i, j;
SDL_Rect src, dst;
src.x = src.y = 0;
src.w = back->w;
src.h = UP;
dst.y = dst.x = 0;
dst.w = back->w;
dst.h = UP;
for (i = FrameW; i < HW; i += back->w)
{
SDL_BlitSurface (back, &src, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
dst.x += back->w;
}
dst.x = (HW - newgame->w) / 2;
dst.y = (UP - newgame->h) / 2;
dst.w = newgame->w;
dst.h = newgame->h;
SDL_BlitSurface (newgame, NULL, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
dst.w = dst.h = BASE_W;
for (i = FrameW; i < HW - FrameW; i += BASE_W)
for (j = UP; j < HH - FrameW; j += BASE_W)
{
dst.x = i;
dst.y = j;
SDL_BlitSurface (cover, NULL, screen, &dst);
}
SDL_UpdateRect (screen, FrameW, UP, COL * BASE_W, LINE * BASE_W);
}
void
FreeData ()
{
SDL_FreeSurface (nobomb);
SDL_FreeSurface (font);
SDL_FreeSurface (dead);
SDL_FreeSurface (cover);
SDL_FreeSurface (flag);
SDL_FreeSurface (error);
SDL_FreeSurface (newgame);
SDL_FreeSurface (back);
}
void
init ()
{
if ((SDL_Init (SDL_INIT_AUDIO | SDL_INIT_VIDEO)) < 0)
fprintf (stderr, "init error\n");
if ((screen =
SDL_SetVideoMode (HW, HH, 32,
SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
fprintf (stderr, "set video mode error\n");
atexit (SDL_Quit);
SDL_WM_SetCaption ("hard bomble", "");
LoadData ();
initdraw ();
srand (time (NULL));
}
int
returnx (int a) //真实坐标到数组坐标
{
if (a < FrameW)
return -1;
return (a - FrameW) / BASE_W;
}
int
returny (int b)
{
if (b < UP)
return -1;
return (b - UP) / BASE_W;
}
void
drawsurface (SDL_Surface * img, int x, int y)
{
SDL_Rect dst;
dst.x = y * BASE_W + FrameW;
dst.y = x * BASE_W + UP;
dst.w = img->w;
dst.h = img->h;
SDL_BlitSurface (img, NULL, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
}
void
Bomb () //碰到雷了
{
int i, j;
alive = 0;
SDL_Rect dst;
dst.w = dst.h = BASE_W;
for (i = 0; i < LINE; i++)
for (j = 0; j < COL; j++)
{
if (temp[i][j] == 1 && bomb[i][j] != -1)
{
drawsurface (nobomb, i, j);
drawsurface (error, i, j);
}
if (bomb[i][j] == -1)
{
dst.x = j * BASE_W + FrameW;
dst.y = UP + i * BASE_W;
drawsurface (nobomb, i, j);
SDL_BlitSurface (dead, NULL, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
}
}
}
void
drawchar (int num, int x, int y) //在图片上画雷的个数
{
temp[x][y] = -1;
SDL_Rect src, dst;
src.w = FontW;
src.h = FontH;
src.x = num * FontW;
src.y = 0;
dst.w = FontW;
dst.h = FontH;
dst.x = y * BASE_W + FrameW + (BASE_W - FontW) / 2;
dst.y = UP + x * BASE_W + (BASE_W - FontH) / 2;
drawsurface (nobomb, x, y);
SDL_BlitSurface (font, &src, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
}
void
testvast (int x, int y) //对一个非雷区进行递归搜索
{
SDL_Rect dst;
int a, b, k;
dst.w = dst.h = BASE_W;
dst.x = y * BASE_W + FrameW;
dst.y = UP + x * BASE_W;
SDL_BlitSurface (nobomb, NULL, screen, &dst);
SDL_UpdateRects (screen, 1, &dst);
bomb[x][y] = 10;
for (k = 0; k < 4; k++)
{
a = x + frame[k][0];
b = y + frame[k][1];
if (!over (a, b) && temp[a][b] == 0)
{
if (bomb[a][b] == 0)
testvast (a, b);
else if (bomb[a][b] != -1)
drawchar (bomb[a][b], a, b);
}
}
}
/* type=-1 左键
type=0 中键
type=1 右键
*/
void
handleevent (int type, int x, int y)
{
if (alive)
{
switch (type)
{
case -1:
if (temp[x][y] == 0)
{
if (bomb[x][y] == -1)
Bomb ();
else if (bomb[x][y] != 0)
drawchar (bomb[x][y], x, y);
else if (bomb[x][y] == 0)
testvast (x, y);
}
break;
case 0:
if (bomb[x][y] != 0 && bomb[x][y] != -1
&& temp[x][y] == -1)
{
int k, num = 0, a, b;
for (k = 0; k < 8; k++)
{
a = x + frame[k][0];
b = y + frame[k][1];
if (!over (a, b) && temp[a][b] == 1)
num++;
}
if (num == bomb[x][y])
{
for (k = 0; k < 8; k++)
{
a = x + frame[k][0];
b = y + frame[k][1];
if (!over (a, b))
{
if (temp[a][b] != 1)
handleevent
(-1,
a,
b);
}
}
}
}
break;
case 1:
if (temp[x][y] == 1)
{
drawsurface (cover, x, y);
temp[x][y] = 0;
}
else if (temp[x][y] == 0)
{
drawsurface (flag, x, y);
temp[x][y] = 1;
if (gameover ())
{
alive = 0;
for (int i = 0; i < LINE; i++)
for (int j = 0; j < COL; j++)
{
if (bomb[i][j] == 0
&& temp[i][j] !=
10)
handleevent
(-1,
i,
j);
else if (bomb[i][j] !=
-1
&& temp[i][j]
!= -1)
drawchar (bomb
[i]
[j],
i,
j);
}
}
}
break;
};
}
}
int
pointatnew (int x, int y) //sdl坐标
{
if (x < (HW - newgame->w) / 2
|| x > (HW - newgame->w) / 2 + newgame->w
|| y < (UP - newgame->h) / 2
|| y > (UP - newgame->h) / 2 + newgame->h)
return 0;
else
return 1;
}
void
wait ()
{
SDL_Delay (50);
}
void
rungame ()
{
SDL_Event event;
int timeisok = 0;
Uint32 thistime, nexttime = 0;
int run = 1, x, y;
drawnum (0);
while (run)
{
wait ();
if (alive)
{
thistime = SDL_GetTicks ();
if (thistime >= nexttime)
{
timeisok = 1;
nexttime = thistime + 1000;
}
if (timeisok)
{
drawnum (TIME++);
timeisok = 0;
}
}
while (SDL_PollEvent (&event))
{
switch (event.type)
{
case SDL_QUIT:
run = 0;
break;
case SDL_MOUSEBUTTONDOWN:
x = returny (event.button.y);
y = returnx (event.button.x);
if (!over (x, y))
{
switch (event.button.button)
{
case SDL_BUTTON_LEFT:
handleevent (-1, x, y);
break;
case SDL_BUTTON_RIGHT:
handleevent (1, x, y);
break;
case SDL_BUTTON_MIDDLE:
handleevent (0, x, y);
break;
};
}
else if (pointatnew
(event.button.x, event.button.y))
{
creatbomb ();
initdraw ();
}
}
}
}
}
int
main ()
{
init ();
rungame ();
FreeData ();
}
评论