日期:2014-05-17  浏览次数:20798 次

Windows扫雷的设计思路与实现

      最近花了个把星期左右把Windows xp的扫雷实现了一下,在这里写下设计思路与大概实现。这个是下载地址,

欢迎大家下载试玩,http://kuai.xunlei.com/d/LTACJFIRFVKB。其实其中还有有个隐藏的bug。看看你能不能发现,哈哈。源代码我以后会补上,暂时不能上传,请各位谅解!

     既然是游戏的话,只有会玩了才有可能知道是怎么实现的!数字n代表以它为中心3*3的方格范围内

有n个雷。主要就是根据这个来判断是否有雷。然后是空格子的话就代表它周围没有雷。然后就是鼠标的各种事件了。下面这个是一个列表。

之后主要是按照这个写的,也有些改动,但是不大。

1.左键按下
 1.1.右键按下
  3*3方格变形
 1.2.右键未被按下
  当前方格变形
LBtnDown = TRUE;
2.右键按下
 2.1.左键按下
  3*3方格变形
 2.1.左键未被按下
  当前方格变形
RBtnDown = TRUE;
3.左键弹起
 3.1.之前左右键按下
  3.1.1.该数字的雷被找到
   调用展开算法 右键弹起失效
   RBtnDown = FALSE;
  3.1.2.没找到
   3*3方格复原 右键弹起失效

   标记标多了也会调用展开算法
   RBtnDown = FALSE;  
 3.2.之前左键按下
  当前位置方格调用展开算法
LBtnDown = FALSE;
4.右键弹起
 4.1.之前左右键按下
  4.1.1.该数字的雷被找到
   调用展开算法 左键弹起失效
   LBtnDown = FALSE;
  4.1.2.没找到
   3*3方格复原 左键弹起失效

 标记标多了也会调用展开算法
   LBtnDown = FALSE;
RBtnDown = FALSE;
5.鼠标滚动
 5.1.左键按下
  5.1.1.右键按下
   3*3方格移动
  5.1.2.右键弹起
   一个方格移动

这个是雷区初始化的代码。主要就是先写边界,然后把前面n个元素改成雷,最后随机分布。

 

void CMineView::SetMine()
{
	int i, j, currenti, currentj, i1, i2, j1, j2;

	currenti = m_mine.minenumber % m_mine.width;
	if (currenti == 0) {//刚好除尽
		currenti = m_mine.minenumber/m_mine.width;
		currentj = m_mine.width;
		for (i = 1; i <= currenti; i++) {
			for (j = 1; j <= m_mine.width; j++) {
				m_mineMax[i][j] = -1;//初始化雷区
			}
		}
		currenti++;
		currentj = 1;
	} else {//除不尽
		currenti = (m_mine.minenumber/m_mine.width)+1;
		currentj = m_mine.minenumber%m_mine.width;
		for (i = 1; i < currenti; i++) {
			for (j = 1; j <= m_mine.width; j++) {
				m_mineMax[i][j] = -1;//初始化雷区
			}
		}
		for (j = 1; j <= currentj; j++) {
			m_mineMax[currenti][j] = -1;//初始化雷区
		}
		currentj++;
	}

	//初始化不是雷区的区域
	for (j = currentj; j <= m_mine.width; j++) {
		m_mineMax[currenti][j] = 0;
	}
	++currenti;
	for (i = currenti; i <= m_mine.height; i++) {
		for (j = 1; j <= m_mine.width; j++) {
			m_mineMax[i][j] = 0;
		}
	}

	srand(time(NULL));
	for (i = m_mine.height * m_mine.width - 1; i >= 2; --i) {//布雷
		currenti = rand() % i;//产生的随机位置
		if (i%m_mine.width == 0) {//除的尽
			i1 = i / m_mine.width;
			j1 = m_mine.width;
		} else {//除不尽
			i1 = (i / m_mine.width) + 1;
			j1 = i % m_mine.width;
		}

		if (currenti == 0) {//就是第一个
			i2 = 1;
			j2 = 1;
		} else {
			if (currenti%m_mine.width == 0) {//除的尽
				i2 = currenti / m_mine.width;
				j2 = m_mine.width;
			} else {//除不尽
				i2 = (currenti / m_mine.width) + 1;
				j2 = currenti % m_mine.width;
			}
		}
		Swap(&m_mineMax[i1][j1], &m_mineMax[i2][j2]);
	}
}


   展开算法的主要思路就是用一个大的数组(包括虚拟边界)保存该算法对每一个方格的访问次数的计数。

==1就不在访问,分8个方向递归探测。碰到雷或者边界就返回。具体代码如下:

 

//8个方向探测
void CMineView::StretchMine(int i, int j)
{
	if (m_mineVisit[i][j] ==  1) {//走过的路不