个人作品

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下

扫雷(by wysaid)

经典的扫雷游戏。

以下是该游戏运行抓图:

由于项目包含很多图片和音乐,因此这里给出整个项目的压缩包:【点击下载】

以下是项目的完整源代码:

文件 3-1,mine.cpp:

/*

 * author      wysaid
 * E-mail      admin@bnicer.com  OR  wysaid@gmail.com
 * date        20120214

*/

#include "wysaid.h"
#include <conio.h>
BlockType MARK;
MineArray g_mineArray;
HWND g_hwnd;
int g_scrWidth = DEFAULT_MINE_WIDTH * IMG_SIZE, g_scrHeight = DEFAULT_MINE_HEIGHT * IMG_SIZE;
int g_minNum = 50;

void startFrame()
{
	mciSendString("seek startAudio to 0", NULL, 0, NULL);
	mciSendString("play startAudio", NULL, 0, NULL);
	setcolor(YELLOW);
	setfont(22,11, "楷体");
	for(int i = 0; i < g_scrWidth; i += 35)
	{
		for(int j = 0; j < g_scrHeight; j += 35)
		{
			putimage(i, j, Block::imgBlock);
		}
	}

	RECT rect;
	rect.left = rect.top = 0;
	rect.right = g_scrWidth;
	rect.bottom = g_scrHeight;
	drawtext("点击任意方格以开始游戏! \n 注意:\n游戏开始后按住ESC点击或者移动鼠标可退出,\n按住space键点击或者移动鼠标可以激活输入窗口自由设定雷区大小\n和雷数! \n 按住Enter键点击或者移动鼠标可以重新开始\n扫雷游戏的规则请自行百度.\n提示:右键插旗,左右双键可以探测快速扫雷。\n第一次点击以后初始化,肯定不会踩到雷", &rect, DT_LEFT);
}

inline Message translateMsg(MOUSEMSG& msg)
{
	static bool isSearching = false;
	switch(msg.uMsg)
	{
	case WM_LBUTTONDOWN: 
		if(msg.mkRButton)
		{
			isSearching = true;
			return msgSEARCH;
		}
//		else return msgKEYDOWN;
		break;
	case WM_RBUTTONDOWN:
		if(msg.mkLButton)
		{
			isSearching = true;
			return msgSEARCH;
		}
		else return msgGUESS;
	case WM_LBUTTONUP:
		isSearching = false;
		if(msg.mkRButton) return msgENDSEARCH;
 		if(isSearching)
 		{
 			isSearching = false;
 			return msgMOVE;
 		}
		return msgSWEEP;
	case WM_RBUTTONUP:
		if(msg.mkLButton) return msgENDSEARCH;
		isSearching = false;
//		return msgKEYUP;
	default:;
	}
	return msgMOVE;
}

// inline void dealMsg(Message& click)
// {
// 	
// }

inline void keyDownFrame(int x, int y)
{
	putimage(x / IMG_SIZE * IMG_SIZE, y / IMG_SIZE * IMG_SIZE, Block::imgSpace);
}

DIRECTIONS play()
{
	MOUSEMSG msg;
	Message click;
	int lastx, lasty;
	bool win = false;
	bool isKeyDown = false, isSearching = false;
	setcolor(BLACK);
	setfont(35, 35, "宋体");
	g_mineArray.render();
	FlushBatchDraw();
	if(g_mineArray.win())
		return dirWIN;
	for(;;FlushBatchDraw())
	{
		msg = GetMouseMsg();
		if(kbhit())
		{
			char ch = getch();
			if(ch == 27) return dirEXIT;
			else if(ch == 32) return dirSET;
			else if(ch == '\r') return dirREPLAY;
			while(kbhit()) getch();
			if(msg.x < 0 || msg.x > g_scrWidth || msg.y < 0 || msg.y > g_scrHeight)
			continue;
		}
 		if(msg.uMsg == WM_MOUSEMOVE && msg.x/IMG_SIZE == lastx/IMG_SIZE && msg.y/IMG_SIZE == lasty/IMG_SIZE)
 			continue;
		lastx = msg.x;
		lasty = msg.y;
		click = translateMsg(msg);
		switch(click)
		{
		case msgSWEEP:
//			isKeyDown = false;
			if(!g_mineArray.sweep(msg.x, msg.y))
			{
				PlaySound("bomb.wav", 0, SND_FILENAME | SND_ASYNC);
				return dirLOSE;
			}
			else 
			{
				PlaySound("click.wav", 0, SND_FILENAME | SND_ASYNC);
			}
			if(g_mineArray.win())
				return dirWIN;
			break;
		case msgGUESS:
			PlaySound("rightClick.wav", 0, SND_FILENAME | SND_ASYNC);
			g_mineArray.guess(msg.x, msg.y);
			break;
		case msgSEARCH:
			isSearching = true;
//			isKeyDown = false;
			break;
		case msgENDSEARCH:
			isSearching = false;
			if(!g_mineArray.search(msg.x, msg.y))
			{
				PlaySound("bomb.wav", 0, SND_FILENAME | SND_ASYNC);
				return dirLOSE;
			}
			else 
			{
				PlaySound("search.wav", 0, SND_FILENAME | SND_ASYNC);
			}
			if(g_mineArray.win())
				return dirWIN;
			break;

		default:;
		}
		cleardevice();
		g_mineArray.render();
		if(isSearching)
		{
			g_mineArray.searchFrame(msg.x, msg.y);
		}
		else if(msg.mkLButton)
		{
			keyDownFrame(msg.x, msg.y);
		}
		else if(click == msgMOVE)
		{
			g_mineArray.moveFrame(msg.x, msg.y);
		}
	}

	return dirWIN;
}

void replay()
{
	startFrame();
	FlushBatchDraw();
	MOUSEMSG msg;
	do
	{
		msg = GetMouseMsg();
	}while(msg.uMsg != WM_LBUTTONUP);
	int x = g_scrWidth / IMG_SIZE, y = g_scrHeight / IMG_SIZE;
	g_mineArray.reInit(x, y, msg.x, msg.y, g_minNum);
	g_mineArray.sweep(msg.x, msg.y);
	FlushMouseMsgBuffer();
	while(kbhit()) getch();
}

void set()
{
	char str[64];
	char *p = "请输入所需的列数(width)、行数(height)以及地雷数,用空格隔开";
	int w, h, n;
	for(bool b = false; !b; )
	{
		b = !!InputBox(str, 64, p, "准备初始化游戏", "20 15 50" , 1024);
		sscanf(str, "%d%d%d", &w, &h, &n);
		if(w < 1 || w > GetSystemMetrics(SM_CXSCREEN)/IMG_SIZE)
		{
			b = false;
			p = "输入的列数不合法!请重新输入!请输入所需的列数(width)、行数(height)以及地雷数,用空格隔开";
		}
		else if(h < 1 || h > GetSystemMetrics(SM_CYSCREEN)/IMG_SIZE)
		{
			p = "输入的行数不合法!请重新输入!请输入所需的列数(width)、行数(height)以及地雷数,用空格隔开";
			b = false;
		}
		else if(n >= w*h -1)
		{
			p = "输入的地雷数过多!请重新输入!请输入所需的列数(width)、行数(height)以及地雷数,用空格隔开";
			b = false;
		}
	}
	g_scrWidth = w * IMG_SIZE;
	g_scrHeight = h * IMG_SIZE;
	g_minNum = n;
	EndBatchDraw();
	closegraph();
	initgraph(g_scrWidth, g_scrHeight);
	BeginBatchDraw();
	setbkmode(TRANSPARENT);
	g_hwnd = GetHWnd();
	SetWindowText(g_hwnd, "扫雷 【学习版】 ——Made by wysaid");
	FlushMouseMsgBuffer();
	replay();
}

void youWin()
{
	g_mineArray.winFrame();
	cleardevice();
	setcolor(YELLOW);
	setfont(30,15,"宋体");
	outtextxy(20,g_scrHeight/2, "游戏将在2秒钟后初始化完毕并重新开始");
	FlushBatchDraw();
	FlushMouseMsgBuffer();
	Sleep(1500);
	replay();
}

void youLose()
{
	g_mineArray.loseFrame();
	cleardevice();
	setcolor(YELLOW);
	setfont(30,15,"宋体");
	outtextxy(20,g_scrHeight/2, "游戏将在2秒钟后初始化完毕并重新开始");
	FlushBatchDraw();
	FlushMouseMsgBuffer();
	Sleep(1500);
	replay();
}

void init()
{
	initgraph(g_scrWidth, g_scrHeight);
	mciSendString("open start.mp3 alias startAudio", NULL, 0, NULL);
	mciSendString("open click.wav alias clickAudio", NULL, 0, NULL);
	mciSendString("open rightClick.wav alias rightclickAudio", NULL, 0, NULL);
	mciSendString("open search.wav alias searchAudio", NULL, 0, NULL);
	mciSendString("open win.mp3 alias winAudio", NULL, 0, NULL);
//	mciSendString("open move.wav alias moveAudio", NULL, 0, NULL);
	setbkmode(TRANSPARENT);
	g_hwnd = GetHWnd();
	SetWindowText(g_hwnd, "扫雷 【学习版】 ——Made by wysaid");
	if(!g_mineArray.loadResource())
	{
		MessageBox(g_hwnd, "读取资源失败,请确认本运行程序和资源文件在同一文件夹下", "程序初始化失败!", MB_OK);
		closegraph();
		exit(-1);
	}

	BeginBatchDraw();	
	startFrame();
	FlushBatchDraw();

	{
		MOUSEMSG msg;
		do
		{
			msg = GetMouseMsg();
		}while(msg.uMsg != WM_LBUTTONUP);
		g_mineArray.init(DEFAULT_MINE_WIDTH, DEFAULT_MINE_HEIGHT, msg.x, msg.y, g_minNum);
		g_mineArray.sweep(msg.x, msg.y);
	}
}

void release()
{
	EndBatchDraw();
	closegraph();
	mciSendString("close startAudio", NULL, 0, NULL);
	mciSendString("close clickAudio", NULL, 0, NULL);
	mciSendString("close rightclickAudio", NULL, 0, NULL);
	mciSendString("close searchAudio", NULL, 0, NULL);
	mciSendString("close winAudio", NULL, 0, NULL);
//	mciSendString("close moveAudio", NULL, 0, NULL);
}

int main()
{
	init();
	while(1)
	{
		PlaySound("click.wav", 0, SND_FILENAME | SND_ASYNC);
		switch(play())
		{
		case dirREPLAY: replay(); break;
		case dirSET: set(); break;
		case dirEXIT: 
			cleardevice();
			setcolor(RED);
			setfont(50,25,"宋体");
			outtextxy(50,g_scrHeight / 2, "wysaid: 欢迎使用,再见~~");
			outtextxy(50,g_scrHeight / 2 + 100, "程序将在五秒钟后安全退出~~~~");
			FlushBatchDraw();
			Sleep(5000);
			EndBatchDraw();
			closegraph();
			return 0;
		case dirWIN: youWin(); break;
		case dirLOSE: youLose(); break;
		default:;
		}
	}
	release();
	return 0;
}

文件 3-2,wysaid.cpp:

/*

 * author      wysaid
 * E-mail      admin@bnicer.com  OR  wysaid@gmail.com
 * date        20120208

*/

#include "wysaid.h"

extern BlockType MARK;
extern int g_scrWidth, g_scrHeight;

IMAGE *Block::imgBlock, *Block::imgMine, *Block::imgFlag, *Block::imgUnknown, *Block::imgSpace;
IMAGE *Mine::imgBlock, *Mine::imgMine, *Mine::imgFlag, *Mine::imgUnknown, *Mine::imgSpace;
int Mine::bomb = 0;

void Block::render()
{
	switch(m_type)
	{
	case NORMAL: putimage(m_x, m_y,imgBlock); break;
	case CHOSEN: putimage(m_x, m_y,imgBlock + 1); break;
	case FLAG: putimage(m_x, m_y,imgFlag); break;
	case FLAG_CHOSEN: putimage(m_x, m_y,imgFlag+1); break;
	case UNKNOWN: putimage(m_x, m_y,imgUnknown); break;
	case UNKNOWN_CHOSEN: putimage(m_x, m_y,imgUnknown +1); break;
//	case WRONGQMARK: imgUnknown[]
	case WRONGFLAG: putimage(m_x, m_y,imgMine + 8); break;
	case SPACE:
	case FOUND: 
		putimage(m_x, m_y, imgSpace); 
		if(m_num != 0)
		{
			char s[64];
			sprintf(s, "%d", m_num);
			outtextxy(m_x, m_y, s);
		}
		break;
	default:;
	}
}

Mine::Mine(int x, int y) : Block(x, y), m_frame(0), m_f(0)
{
	m_dx = RANDF;
	m_dy = RANDF;
	m_mx = m_x;
	m_my = m_y;
}

void Mine::m_frameUpdate()
{
	if(m_frame >= 7)
		setType(MINE);
	if(++m_f > DELAY_FPS)
	{
		++m_frame %= 8;
		m_f = 0;
	}
}

void Mine::m_go()
{
	m_mx += m_dx;
	m_my += m_dy;
	m_x = m_mx;
	m_y = m_my;
	if(m_mx < 0 || m_mx > g_scrWidth-10)
	{
		m_dx = -m_dx;
		m_x += m_dx;
	}
	if(m_my < 0 || m_my > g_scrHeight-10)
	{
		m_dy = -m_dy;
		m_y += m_dy;
	}
}

void Mine::setFire()
{
// 	m_dx = (randomf() + 0.4) * pow(-1, random(10));
// 	m_dy = (randomf() + 0.4) * pow(-1, random(10));
}

void Mine::render()
{
	switch(m_type)
	{
	case NORMAL: putimage(m_x, m_y,imgBlock); break;
	case CHOSEN: putimage(m_x, m_y,imgBlock); break;
	case FLAG: putimage(m_x, m_y,imgFlag); break;
	case FLAG_CHOSEN: putimage(m_x, m_y,imgFlag); break;
	case UNKNOWN: putimage(m_x, m_y,imgUnknown); break;
	case UNKNOWN_CHOSEN: putimage(m_x, m_y,imgUnknown); break;
	case FLAG_MINE: putimage(m_x, m_y,imgFlag); break;
	case UNKNOWN_MINE: putimage(m_x, m_y,imgUnknown); break;
	case SPACE: putimage(m_x, m_y,imgSpace); break;
	case MARKEDMINE:
		putimage(m_x, m_y,imgMine); break;
		break;
	case MINE: 
		m_go();
		/*imgMine[7].putimage(m_mx, m_my); */
		break;
	case ONFIRE: 
		{
			putimage(m_x, m_y,imgMine+m_frame);
			m_frameUpdate(); 
		}
		break;
	default:;
	}
}

bool MineArray::reInit(int width, int height, int x, int y, int num)
{
	for(int a = 0; a != m_width; ++a)
	{
		for(int b = 0; b != m_height; ++b)
		{
			delete m_block[a][b];
		}
		delete[] m_block[a];
	}
	delete[] m_block;
	
	return init(width, height, x, y, num);
}

bool MineArray::init(int width, int height, int x, int y, int num)
{
	x /= IMG_SIZE;
	y /= IMG_SIZE;
	m_width = width;
	m_height = height;
	m_blockNum = width * height - num;
	if(num >= width * height) return false;
	int i;
	bool** mark = new bool*[width];
	for(i = 0; i != width; ++i)
	{
		mark[i] = new bool[height];
		memset(mark[i], 0, height * sizeof bool);
	}
	m_randomize(mark, width, height, num, x, y);
	
	m_block = new Block**[width];
	for(i = 0; i != width; ++i)
	{
		m_block[i] = new Block*[height];
	}
	
	for(int a = 0; a != width; ++a)
	{	for(int b = 0; b != height; ++b)
		{
			if(mark[a][b]) 
				m_block[a][b] = new Mine(a * IMG_SIZE, b * IMG_SIZE);
			else 
				m_block[a][b] = new Block(a * IMG_SIZE, b * IMG_SIZE);
		}
	}
	m_initBlocks(mark);
	for(i = 0; i != width; ++i)
	{
		delete[] mark[i];
	}
	delete[] mark;
	
	return true;
}

void MineArray::m_initBlocks(bool** mark)
{
	for(int a = 0; a != m_width; ++a)
	{
		for(int b = 0; b != m_height; ++b)
		{
			if(mark[a][b])
			{
				if(a-1 >= 0) m_block[a-1][b]->addMine();				
				if(b-1 >= 0) m_block[a][b-1]->addMine();
				if(a-1 >= 0 && b-1 >= 0) m_block[a-1][b-1]->addMine();
				if(a+1 < m_width) m_block[a+1][b]->addMine();
				if(b+1 < m_height) m_block[a][b+1]->addMine();
				if(a+1 < m_width && b+1 < m_height) m_block[a+1][b+1]->addMine();
				if(a-1 >=0 && b+1 < m_height) m_block[a-1][b+1]->addMine();
				if(a+1 < m_width && b-1 >= 0) m_block[a+1][b-1]->addMine();
			}
		}
	}
}

MineArray::	~MineArray()
{
	for(int a = 0; a != m_width; ++a)
	{
		for(int b = 0; b != m_height; ++b)
		{
			delete m_block[a][b];
		}
		delete[] m_block[a];
	}
	delete[] m_block;

	delete[] m_imgBlock;
	delete[] m_imgMine;
	delete[] m_imgFlag;
	delete[] m_imgUnknown;
	delete[] m_imgSpace;
}

void MineArray::m_randomize(bool** b, int width, int height, int num, int x, int y)
{
	int rndx, rndy, cnt = 0, length = width * height, firstclick = x*width + height;
//	bool* tmpb = (bool*)b;
	srand(unsigned(time(NULL)));
	while(num > 0)
	{
		rndx = rand() % width;
		rndy = rand() % height;
		if(rndx == x && rndy == y) continue;
		if(b[rndx][rndy])
		{
			if(++cnt > 10)
			{
				int i;
				for(i = 0; i != length; ++i)
				{
					if(!b[i/width][i%height] && i != firstclick)
					{
						b[i/width][i%height] = true;
						cnt = 0;
						break;
					}
				}
				if(i == length) return;
			}
		}
		else
		{
			b[rndx][rndy] = true;
			--num;
			cnt = 0;
		}
	}
}

bool MineArray::loadResource()
{
	int test = 0;
	m_imgBlock = new IMAGE[2];
	m_imgMine = new IMAGE[9];
	m_imgFlag = new IMAGE[3];
	m_imgUnknown = new IMAGE[3];
	m_imgSpace = new IMAGE[1];
	
	loadimage(m_imgBlock,"block_normal.bmp");
 	loadimage(m_imgBlock+1,"block_chosen.bmp");
	
	for(int i=0; i != 9; ++i)
	{
		char buf[256];
		sprintf(buf, "mine_%d.bmp", i);
		loadimage(m_imgMine+i,buf);
	}

	loadimage(m_imgFlag,"flag.bmp");
	loadimage(m_imgFlag+1,"flag_chosen.bmp");
	loadimage(m_imgFlag+2,"flag_mine.bmp");

	loadimage(m_imgUnknown, "quote.bmp");
	loadimage(m_imgUnknown+1, "quote_chosen.bmp");
	loadimage(m_imgUnknown+2, "quote_mine.bmp");

	loadimage(m_imgSpace,"space.bmp");

	if(test) return false;

	Block::imgBlock = m_imgBlock;
	Block::imgMine = m_imgMine;
	Block::imgFlag = m_imgFlag;
	Block::imgUnknown = m_imgUnknown;
	Block::imgSpace = m_imgSpace;

	Mine::imgBlock = m_imgBlock;
	Mine::imgMine = m_imgMine;
	Mine::imgFlag = m_imgFlag;
	Mine::imgUnknown = m_imgUnknown;
	Mine::imgSpace = m_imgSpace;

	return true;
}

void MineArray::render()
{
	for(int i=0; i < m_width; ++i)
	{
		for(int j=0; j < m_height; ++j)
			m_block[i][j]->render();
	}
}

// void MineArray::frameUpdate()
// {
// 	for(int i=0; i < g_scrWidth; i += IMG_SIZE);
// 	{
// 		for(int j=0; j < g_scrHeight; j += IMG_SIZE);
// 			m_block[i][j]->frameUpdate();
// 	}
// }

void MineArray::searchFrame(int x, int y)
{
	PIXEL2BLOCK(x,y);
	for(int i = x - 1; i <= x + 1; ++i)
		for(int j = y- 1; j <= y + 1; ++j)
		{
			if(i >= 0 && i < m_width && j >= 0 && j < m_height && m_block[i][j]->canBeSearched())
			{
				putimage(i * IMG_SIZE, j * IMG_SIZE, m_imgSpace);
			}
		}
}

void MineArray::m_findMore(int x, int y)
{
	if(x < 0 || x >= m_width || y < 0 || y >= m_height)
		return;
	BlockType tp = m_block[x][y]->getType();
	if(m_block[x][y]->getNum() == 0 && tp == NORMAL)
	{
		m_block[x][y]->setType(FOUND);
		--m_blockNum;
		m_findMore(x-1,y);
		m_findMore(x,y-1);
		m_findMore(x-1, y-1);
		m_findMore(x+1,y);
		m_findMore(x+1, y-1);
		m_findMore(x,y+1);
		m_findMore(x-1, y+1);
		m_findMore(x+1, y+1);
	}
	else if(m_block[x][y]->getNum() > 0 && tp != FOUND)
	{
		m_block[x][y]->setType(FOUND);
		--m_blockNum;
	}
}

bool MineArray::sweep(int x, int y)
{
	PIXEL2BLOCK(x, y);

	if(m_block[x][y]->isMine() && m_block[x][y]->getType() != FLAG)
	{
		m_firedX = x;
		m_firedY = y;
		return false;
	}
	
	switch(m_block[x][y]->getType())
	{
	case NORMAL:
	case CHOSEN:
	case UNKNOWN:
	case UNKNOWN_CHOSEN:
		m_findMore(x, y);
	default:;
	}

	return true;
}

void MineArray::keyDown(int x, int y)
{
// 	static int lastx, lasty;
// 	if(m_keyCtrl)
// 	{
// 		if(m_block[x][y]->getType() == CHOSEN && lastx != x && lasty != y)
// 		{
// 			m_block[x][y]->setType(SPACE);
// 			m_block[lastx][lasty]->setType(NORMAL);
// 		}
// 	}
// 	else
// 	{
// 		lastx = x;
// 		lasty = y;
// 		if(m_block[x][y]->getType() == CHOSEN)
// 			m_block[x][y]->setType(SPACE);
// 	}
// 	m_keyCtrl = KEYDOWN;
}

void MineArray::guess(int x, int y)
{
	PIXEL2BLOCK(x,y);
	switch(m_block[x][y]->getType())
	{
	case NORMAL:
	case CHOSEN:
		m_block[x][y]->setType(FLAG);
		break;
	case FLAG:
	case FLAG_CHOSEN:
		m_block[x][y]->setType(UNKNOWN);
		break;
	case UNKNOWN:
	case UNKNOWN_CHOSEN:
		m_block[x][y]->setType(NORMAL);
		break;
	default:;
	}
}

void MineArray::moveFrame(int x, int y)
{
	PIXEL2BLOCK(x, y);
	int a = x * IMG_SIZE, b = y * IMG_SIZE;
	switch(m_block[x][y]->getType())
	{
	case NORMAL:
		putimage(a, b, m_imgBlock + 1); break;
	case FLAG:
		putimage(a, b, m_imgFlag + 1); break;
	case UNKNOWN:
		putimage(a, b, m_imgUnknown + 1); break;
	default:;
	}

}


// 
// void MineArray::move(int x, int y)
// {
// 	static int lastx, lasty;
// 	switch(m_block[x][y]->getType())
// 	{
// 	case NORMAL: 
// // 		if(lastx == x && lasty == y)
// // 			m_block[lastx][lasty]->setType(NORMAL);
// 		m_block[x][y]->setType(CHOSEN); 
// 		break;
// 	case FLAG: 
// 
// 		m_block[x][y]->setType(FLAG_CHOSEN); 
// 		break;
// 	case UNKNOWN: 
// 
// 		m_block[x][y]->setType(UNKNOWN_CHOSEN); 
// 		break;
// 	default:;
// 	}
// }

bool MineArray::search(int x, int y)
{
	PIXEL2BLOCK(x,y);
	if(m_block[x][y]->getType() != FOUND)
		return true;
	
	int cnt = 0, tmp = 0, arrX[9], arrY[9];
	bool bombExist = false;
	for(int i = x - 1; i <= x + 1; ++i)
		for(int j = y- 1; j <= y + 1; ++j)
		{
			if(i >= 0 && i < m_width && j >= 0 && j < m_height)
			{
				if(m_block[i][j]->getType() == FLAG)
				{
					++cnt;
				}
				else if(m_block[i][j]->getType() == NORMAL)
				{
					arrX[tmp] = i * IMG_SIZE;
					arrY[tmp] = j * IMG_SIZE;
					++tmp;
				}
				else if(m_block[i][j]->getType() == UNKNOWN)
					return true;
			}
		}
	if(cnt == m_block[x][y]->getNum())
	{
		for(int n = 0; n != tmp; ++n)
		{
			if(!sweep(arrX[n], arrY[n]))
			{
				bombExist = true;
			}
		}
	}

	return !bombExist;
}

void MineArray::winFrame()
{
	float x = g_scrWidth / 2, y = g_scrHeight / 2;	
	cleardevice();
	while(kbhit()) getch();
	mciSendString("seek winAudio to 0", NULL, 0, NULL);
	mciSendString("play winAudio", NULL, 0, NULL);
	for(float dx = RANDF, dy = RANDF;; x += dx, y += dy)
	{
		if(x < 0 || x > g_scrWidth)
			dx = -dx;
		if(y < 0 || y > g_scrHeight)
			dy = -dy;
		cleardevice();
		setcolor(BLACK);
		setfont(35, 35, "宋体");
		render();

		setfont(40,20,"宋体");
		setcolor(RED);
		outtextxy(x, y-50, "You Win!");
		outtextxy(x-100, y+50, "Press anykey to continue!");

		FlushBatchDraw();
		Sleep(10);
		if(kbhit())
		{
			Sleep(100);
			while(kbhit()) getch();
			break;
		}
	}		
}


void MineArray::m_markAll()
{
	for(int i=0; i != m_width; ++i)
		for(int j=0; j != m_height; ++j)
		{
			switch(m_block[i][j]->getType())
			{
			case NORMAL:
				if(m_block[i][j]->isMine())
					m_block[i][j]->setType(MARKEDMINE);
				break;
			case FLAG:
				if(m_block[i][j]->isMine()) m_block[i][j]->setType(FLAG_MINE);
				else m_block[i][j]->setType(WRONGFLAG);
				break;
			case UNKNOWN:
				if(m_block[i][j]->isMine()) m_block[i][j]->setType(UNKNOWN_MINE);
//				else m_block[i][j]->setType(WRONGQMARK);
				break;
			default:;
			}
		}
}

void play(void* arg)
{
	static int i = 0;
	char s[64];
	sprintf(s, "open bomb.wav alias bombAudio%d", i);
	mciSendString(s, NULL, 0, NULL);
	sprintf(s, "play bombAudio%d", i);
	mciSendString(s, NULL, 0, NULL);
	++i;
	if(i >= 100)
	{
		for(int n=0; n != 100; ++n)
		{
			sprintf(s, "close bombAudio%d", n);
			mciSendString(s, NULL, 0, NULL);
		}
		i = 0;
	}
}

void MineArray::loseFrame()
{

	using std::vector;
	vector<Block*> vec;
	vec.push_back(m_block[m_firedX][m_firedY]);
	m_markAll();
	m_block[m_firedX][m_firedY]->setType(ONFIRE);
	m_block[m_firedX][m_firedY]->setFire();
	while(kbhit()) getch();
 	for(int x, y; ; Sleep(10))
 	{
		cleardevice();
		render();
		for(size_t i = 0; i != vec.size(); ++i)
		{
			if(vec[i]->getType() == MINE)
			{
				vec[i]->getPos(x, y);
				putimage(x, y, Mine::imgMine + 7);
				PIXEL2BLOCK(x,y);
				if(m_block[x][y]->isMine() && m_block[x][y]->getType() == MARKEDMINE)
				{
					m_block[x][y]->setType(ONFIRE);
					vec.push_back(m_block[x][y]);
					/*PlaySound("bomb.wav", NULL, SND_FILENAME | SND_ASYNC);*/
					_beginthread(play, 0, NULL);
				}
			}
		}

		setfont(40,20,"宋体");
		setcolor(YELLOW);

		outtextxy(200,200, "You Lose!");
		outtextxy(50,400, "Press anykey to continue!");
 		FlushBatchDraw();
		if(kbhit())
		{
			Sleep(100);
			while(kbhit()) getch();
			break;
		}
		setcolor(BLACK);
		setfont(35, 35, "宋体");
 	}
}

文件 3-3,wysaid.h:

/*

 * author      wysaid
 * E-mail      admin@bnicer.com  OR  wysaid@gmail.com
 * date        20120208

*/

#ifndef _WYSAID_H_
#define _WYSAID_H_

#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <graphics.h>
#include <conio.h>
#include <vector>
#include <cmath>
#include <process.h>

#pragma comment(lib, "Winmm.lib")


#define IMG_SIZE			35
#define DEFAULT_MINE_WIDTH	20
#define DEFAULT_MINE_HEIGHT	15

#define PIXEL2MAP(x,y) x = x / IMG_SIZE * IMG_SIZE; y = y / IMG_SIZE * IMG_SIZE
#define PIXEL2BLOCK(x, y) x /= IMG_SIZE; y /= IMG_SIZE
#define DELAY_FPS			(60/7)

#define RANDF	((rand() % 1000 / 1000.0 + 0.2) * pow(-1.0f,rand()%10))

enum BlockType{NORMAL, CHOSEN, FLAG, FLAG_CHOSEN, FLAG_MINE, WRONGFLAG, UNKNOWN, UNKNOWN_CHOSEN, WRONGQMARK,SPACE, UNKNOWN_MINE, ONFIRE, FOUND, MARKEDMINE, MINE};
enum Message{msgSWEEP, msgGUESS, msgSEARCH, msgENDSEARCH, msgKEYDOWN, msgKEYUP, msgMOVE};
enum DIRECTIONS {dirREPLAY, dirSET, dirEXIT, dirWIN, dirLOSE};

class Block
{
public:
	Block() : m_x(0), m_y(0), m_type(NORMAL), m_num(0)/*, isSwept(false)*/ {}
	Block(int x, int y) : m_x(x), m_y(y), m_type(NORMAL), m_num(0) {}
	virtual void render();
	virtual bool isMine() { return false; }
	virtual void addMine() { ++m_num; }
	virtual int getNum() { return m_num; }
	virtual void setFire() {}
	void getPos(int &x, int &y) { x = m_x; y = m_y; }
	BlockType getType() { return m_type; }
	void setType(BlockType type) { m_type = type; }
	bool canBeSearched() { return m_type == FOUND || m_type == FLAG ? false : true; }
	static IMAGE *imgBlock, *imgMine, *imgFlag, *imgUnknown, *imgSpace;
protected:
	int m_x, m_y;
	BlockType m_type;
private:
	int m_num;
//	bool isSwept;
};

class Mine : public Block
{
public:
	Mine() : m_frame(0), m_f(0), m_dx(0.0f), m_dy(0.0f), m_mx(0.0f), m_my(0.0f) {}
	Mine(int x, int y);
	void render();
	bool isMine() { return true; }
	void addMine() {}
	void setFire();
	int getNum() { return -1; }
	static IMAGE *imgBlock, *imgMine, *imgFlag, *imgUnknown, *imgSpace;
	static int bomb;
private:
	void m_frameUpdate();
	void m_go();
	float m_dx, m_dy;
	float m_mx, m_my;
	int m_frame, m_f;
};

class MineArray
{
public:
	MineArray(): m_width(0), m_height(0), m_firedX(0), m_firedY(0), m_keyCtrl(KEYFREE), m_block(NULL), m_imgBlock(NULL)
	, m_imgMine(NULL), m_imgFlag(NULL), m_imgUnknown(NULL), m_imgSpace(NULL), m_blockNum(0) {}


	enum KeyState{ KEYDOWN, KEYFREE, SEARCHING };

	bool loadResource();
	bool init(int width, int height, int x, int y, int num);
	bool reInit(int width, int height, int x, int y, int num);
	bool win() { return m_blockNum <= 0; }
	bool sweep(int x, int y);
	void keyDown(int, int);
	void guess(int, int);
	void moveFrame(int, int);
	void searchFrame(int x, int y);
	bool search(int, int);
	void render();
//	void frameUpdate();
	void winFrame();
	void loseFrame();
	~MineArray();
private:
	void m_randomize(bool** b, int width, int height, int num, int , int);
	void m_initBlocks(bool**);
	void m_findMore(int, int);
	void m_markAll();
	int m_width, m_height;
	int m_firedX, m_firedY;
	int m_blockNum;
	KeyState m_keyCtrl;
	Block*** m_block;
	IMAGE *m_imgBlock, *m_imgMine, *m_imgFlag, *m_imgUnknown, *m_imgSpace;
};

#endif
作者:wysaid
邮箱:wysaid@gmail.com
分享到