正文

SDL版本的扫雷程序2007-01-01 23:53:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/tonyhu/22160.html

分享到:

元旦才刚放假,说实话,我很闲……
所以又写了个扫雷,这个扫雷程序其实真要算是“初学者”级的了……
里面就用到了一个比较像样的算法,…
就是点一个空的时候把邻近的所有连通的空格全部显出……
其实聪明人一下子就知道是搜索了,深搜广搜都可以了……我用的是深搜……
呵呵,程序很简单,但我还是写了这么长,不知怎么搞地……
可能很多地方还可以精简吧……我没刻意去怎么精简它……
因为反正是好玩呀……呵呵,关键的深搜算法写得好一点就差不多了……
正好温习一下落了些时日的算法了……

程序运行状态:


源程序: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 ();
}

阅读(5968) | 评论(3)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册