C語言實現六邊形掃雷遊戲的示例代碼

程序簡介

六邊形掃雷,尋寶模式,稍稍介紹一下。

他也是要把所有安全的地方點出來。

他沒有掃雷模式的消零算法。每一個安全的點都需要單獨挖出來,一次顯示一個格子。

添加瞭生命值的概念,也就是說存在一定的容錯。

顯示的數字有別於掃雷模式。點擊寶藏點,會顯示周圍寶藏點數量,綠色;點擊地雷,會顯示周圍地雷數量,黑色。註意,這個數字不包括自己,顯示的范圍自然就是 0~6 瞭。點擊地雷會減生命值,生命值歸零則結束。

所以雷和寶藏都是有價值的,都是能給準確信息的。

我能給一個參考難度:占總格子數 40%的地雷,占總地雷數 50 %的生命值。

程序運行展示

完整源代碼

 
// 程序:六邊形掃雷:尋寶模式
// 編譯環境:Visual C++ 2010,EasyX_20211109
// 更多好玩的遊戲源碼加我Q群:724050348
 
# include <math.h>
# include <graphics.h>
# include <string>
# include <time.h>
 
static double pi = acos (-1.0);			// 圓周率 π
static HWND hOut;						// 畫佈
 
// 定義一個結構體,按鈕
struct Node1
{
	int posx1, posy1, posx2, posy2;		// 坐標
	LPTSTR text;						// 文字
	int mod;							// 狀態
};
 
// 定義一個結構體,六邊形格子
struct Node2
{
	int i, j, k;						// 特征值
	int mod_life;						// 翻開
	int mod_mine;						// 雷
	int mod_flag;						// 標記
	int posx, posy;						// 坐標
	int num_mine;						// 周圍雷數
	int num_peace;						// 周圍空地塊
};
 
// 定義一個類
class Gary
{
public:
	void carry ();						// 主進程
	void initialization ();				// 初始化
	void draw_scene ();					// 繪制界面函數
	void draw_box (int num_box);		// 繪制格子
	void draw_flag (int num_box);		// 繪制標記
	void draw_num (int num_box, int num);	// 繪制數字
	void move ();						// 窗口主視角
	void create ();						// 地雷生成
	void check_over ();					// 結束判定
 
	int num_button;						// 按鈕數量參數
	int exit_carry;						// 主循函數控制參數
	int exit_move;						// 開始界面控制參數
	int exit_game;						// 遊戲進行控制參數
	int num_life;						// 生命值
	int num_size;						// 邊長
	int num_mine;						// 總雷數
	int num_box;						// 總地塊數
	int num_flag;						// 標記數
	COLORREF color_text[2];				// 按鈕繪制填充
	Node1 boxm[30];						// 按鈕,預制 30 個
	Node2 box[1000];					// 地塊
};
 
// 標記繪制函數
void Gary::draw_flag (int num_box)
{
	setlinestyle (PS_SOLID, 1);
	setlinecolor (BLACK);
	line (box[num_box].posx + 2, box[num_box].posy + 7, box[num_box].posx + 2, box[num_box].posy - 7);
	setfillcolor (LIGHTRED);
	setlinecolor (LIGHTRED);
	fillrectangle (box[num_box].posx - 7 + 2, box[num_box].posy - 7, box[num_box].posx + 2, box[num_box].posy - 1);
}
 
// 數字繪制函數
void Gary::draw_num (int num_box, int num)
{
	int i;
	// 畫六邊形,格子處於點擊後狀態
	setfillcolor (RGB (170, 170, 170));
	setlinecolor (RGB (85, 85, 85));
	POINT pts[6];
	setlinestyle (PS_SOLID, 1);
	for (i = 0; i < 6; i++)
	{
		pts[i].x = long(box[num_box].posx + 14.0 * cos (60.0 * double (i) * pi / 180.0));
		pts[i].y = long(box[num_box].posy + 14.0 * sin (60.0 * double (i) * pi / 180.0));
	}
	fillpolygon (pts, 6);
 
	// 數字繪制
	TCHAR s[15];
	settextstyle (20, 0, _T ("Consolas"));
	_stprintf_s (s, _T ("%0.1d"), num);
	outtextxy (box[num_box].posx - 5, box[num_box].posy - 10, s);
}
 
// 場景繪制函數
void Gary::draw_scene ()
{
	TCHAR s[15];
	int i, j;
	setlinecolor (BLACK);
	setfillcolor (WHITE);
	setlinestyle (PS_SOLID, 1);
	// 主界面
	fillrectangle (401, 0, 650, 400);
	// 根據按鈕數量繪制	
	settextcolor (BLACK);
	for (i = 0; i < num_button; i++)
	{
		setfillcolor (color_text[boxm[i].mod]);
		setbkcolor (color_text[boxm[i].mod]);
		// 邊框
		fillrectangle (boxm[i].posx1, boxm[i].posy1, boxm[i].posx2, boxm[i].posy2);
		// 文字
		outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + 4, boxm[i].text);
	}
 
	// 設置參數
	setbkcolor (WHITE);
	settextcolor (BLACK);
	setlinecolor (BLACK);
 
	// 變量繪制
	j = 25;
	// 生命值
	i = 1;
	setbkcolor (color_text[boxm[i].mod]);
	_stprintf_s (s, _T ("%0.1d"), num_life);
	outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);
	// 邊長
	i = 2;
	setbkcolor (color_text[boxm[i].mod]);
	_stprintf_s (s, _T ("%0.1d"), num_size);
	outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);
	// 總地雷數
	i = 3;
	setbkcolor (color_text[boxm[i].mod]);
	_stprintf_s (s, _T ("%0.1d"), num_mine);
	outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);
	// 格子
	i = 4;
	setbkcolor (color_text[boxm[i].mod]);
	_stprintf_s (s, _T ("%0.1d"), num_box);
	outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);
	// 標記數
	i = 5;
	setbkcolor (color_text[boxm[i].mod]);
	_stprintf_s (s, _T ("%0.1d"), num_flag);
	outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);
 
	FlushBatchDraw ();
}
 
// 地雷生成函數
void Gary::create ()
{
	int i, j;
	// 設置雷
	for (i = 0; i < num_mine; i++)
	{
		// 隨機
		j = rand () % 1000;
		while (box[j].mod_mine == 1 || box[j].mod_life == 1)
		{
			// 隨機
			j = rand () % 1000;
		}
		// 是雷
		box[j].mod_mine = 1;
	}
	// 周邊雷數統計
	// 遍歷
	for (i = 0; i <= 888; i++)
	{
		if (box[i].mod_life == 0)
		{
			// 遍歷
			for (j = 0; j <= 999; j++)
			{
				// 排除自己
				if (j != i && box[j].mod_life == 0)
				{
					// 周圍六個
					if ((box[j].posx - box[i].posx) * (box[j].posx - box[i].posx) + (box[j].posy - box[i].posy) * (box[j].posy - box[i].posy) <= 900)
					{
						// 是雷
						if (box[j].mod_mine == 1)
						{
							// 周邊雷數參數加一
							box[i].num_mine++;
						}
						// 不是雷
						else if (box[j].mod_mine == 0)
						{
							// 周邊安全數參數加一
							box[i].num_peace++;
						}
					}
				}
			}
		}
	}
}
 
// 結束判斷函數
void Gary::check_over ()
{
	int i, k;
	k = 0;
	for (i = 0; i <= 888; i++)
	{
		// 每有一個翻開且不是雷的點,則加一
		if (box[i].mod_mine == 0 && box[i].mod_life == 1)
		{
			k++;
		}
	}
	// 全翻開則結束
	if (k == num_box - num_mine)
	{
		// 將所有未翻開雷做上標記
		for (i = 0; i <= 888; i++)
		{
			if (box[i].mod_mine == 1 && box[i].mod_life == 0)
			{
				draw_flag (i);
			}
		}
		// 勝利標志:笑臉
		setfillcolor (WHITE);
		setlinecolor (WHITE);
		fillrectangle (50, 20, 75, 45);
		settextstyle (30, 0, _T ("Wingdings"));
		setbkmode (TRANSPARENT);
		settextcolor (BLACK);
		outtextxy (50, 20, 0x4A);
		setbkmode (OPAQUE);
		settextstyle (20, 0, _T ("Consolas"));
		// 結束變化
		exit_game = 1;
		boxm[1].mod = 0;
		boxm[2].mod = 0;
		boxm[3].mod = 0;
		boxm[6].mod = 0;
		boxm[7].mod = 1;
		num_flag = 0;
		// 繪制
		draw_scene ();
	}
}
 
// 格子繪制函數
void Gary::draw_box (int num_box)
{
	int i;
	int posx, posy;
 
	// 六邊形繪制
	posx = box[num_box].posx;
	posy = box[num_box].posy;
 
	POINT pts[6];
	setlinestyle (PS_SOLID, 2);
	// 背景色
	setfillcolor (RGB (255, 255, 255));
	for (i = 0; i < 6; i++)
	{
		pts[i].x = long(posx + 14.0 * cos (60.0 * double (i) * pi / 180.0));
		pts[i].y = long(posy + 14.0 * sin (60.0 * double (i) * pi / 180.0));
	}
	solidpolygon (pts, 6);
	// 灰邊
	setlinecolor (RGB (85, 85, 85));
	line (pts[0].x, pts[0].y, pts[1].x, pts[1].y);
	line (pts[5].x, pts[5].y, pts[0].x, pts[0].y);
	line (pts[1].x, pts[1].y, pts[2].x, pts[2].y);
	// 前景色
	setfillcolor (RGB (170, 170, 170));
	for (i = 0; i < 6; i++)
	{
		pts[i].x = long(posx + 12.0 * cos (60.0 * double (i) * pi / 180.0));
		pts[i].y = long(posy + 12.0 * sin (60.0 * double (i) * pi / 180.0));
	}
	solidpolygon (pts, 6);
	FlushBatchDraw ();
}
 
// 初始化函數
void Gary::initialization ()
{
	int i, j, k, t;
	// 隨機初始化
	srand ((unsigned)time (NULL));
	// 顏色初始化
	color_text[0] = WHITE;
	color_text[1] = RGB (170, 170, 170);
 
	// 按鈕的初始化
	num_button = 10;
 
	// 坐標
	for (i = 0; i < 10; i++)
	{
		boxm[i].posx1 = 410 + 120 * (i % 2);
		boxm[i].posy1 = 25 + 75 * (i / 2);
		boxm[i].posx2 = 520 + 120 * (i % 2);
		boxm[i].posy2 = 75 + 75 * (i / 2);
	}
 
	// 內容
	boxm[0].text = _T ("尋寶模式");	boxm[1].text = _T ("生命值");
	boxm[2].text = _T ("地圖邊長");	boxm[3].text = _T ("總地雷數");
	boxm[4].text = _T ("總地塊數");	boxm[5].text = _T ("已標記數");
	boxm[6].text = _T ("開始");		boxm[7].text = _T ("重置");
	boxm[8].text = _T ("截圖");		boxm[9].text = _T ("退出");
 
	// 狀態
	boxm[0].mod = 1;
	boxm[1].mod = 1;
	boxm[2].mod = 1;
	boxm[3].mod = 1;
	boxm[4].mod = 1;
	boxm[5].mod = 1;
	boxm[6].mod = 1;
	boxm[7].mod = 0;
	boxm[8].mod = 0;
	boxm[9].mod = 0;
 
	num_box = 3 * num_size * (num_size - 1) + 1;
	num_flag = 0;
 
	// 繪制參數初始化
	setlinecolor (BLACK);
	setlinestyle (PS_SOLID, 1);
	settextstyle (20, 0, _T ("Consolas"));
	// 第一次繪制
	draw_scene ();
 
	// 重置
	setfillcolor (WHITE);
	fillrectangle (0, 0, 400, 400);
 
	// 平靜臉
	setfillcolor (WHITE);
	setlinecolor (WHITE);
	fillrectangle (50, 20, 75, 45);
	settextstyle (30, 0, _T ("Wingdings"));
	setbkmode (TRANSPARENT);
	settextcolor (BLACK);
	outtextxy (50, 20, 0x4B);
	setbkmode (OPAQUE);
	settextstyle (20, 0, _T ("Consolas"));
 
	// 格子初始化
	for (t = 0; t <= 999; t++)
	{
		// 已翻開
		box[t].mod_life = 1;
		// 城墻
		box[t].mod_mine = 2;
		// 坐標,點不到
		box[t].posx = -200;
		box[t].posy = -200;
	}
 
	// 初始化
	for (i = 0; i < num_size; i++)
	{
		for (j = 0; j < num_size; j++)
		{
			for (k = 0; k < num_size; k++)
			{
				// 特征值至少一個為零
				if (i == 0 || j == 0 || k == 0)
				{
					// 編號
					t = i * 100 + j * 10 + k;
					// 特征值
					box[t].i = i;
					box[t].j = j;
					box[t].k = k;
					// 未翻開
					box[t].mod_life = 0;
					// 不是雷
					box[t].mod_mine = 0;
					// 未標記
					box[t].mod_flag = 0;
					// 坐標
					box[t].posx = 200 + 22 * (j - k);
					box[t].posy = 200 - 25 * i + 13 * (j + k);
					// 周圍雷數初始化
					box[t].num_mine = 0;
					box[t].num_peace = 0;
					// 繪制地塊
					draw_box (t);
				}
			}
		}
	}
	// 地雷生成函數
	create ();
}
 
// 窗口主視角函數,獲取用戶操作
void Gary::move ()
{
	// 鼠標定義
	ExMessage m;
	TCHAR ss[15];
	int i, t;
	exit_move = 0;
	exit_game = 0;
	while (exit_move == 0)
	{
		// 鼠標信息
		if (peekmessage (&m, EM_MOUSE | EM_KEY))
		{
			// 左鍵單擊判斷
			if (m.message == WM_LBUTTONDOWN)
			{
				// 判斷是否點擊瞭格子
				if (m.x > 0 && m.y > 0 && m.x < 400 && m.y < 400 && exit_game == 0)
				{
					for (t = 0; t <= 888; t++)
					{
						// 成功點擊未標記的空格子
						if ((m.x - box[t].posx) * (m.x - box[t].posx) + (m.y - box[t].posy) * (m.y - box[t].posy) <= 144 && box[t].mod_life == 0 && box[t].mod_flag == 0)
						{
							// 點擊的格子不是雷
							if (box[t].mod_mine == 0)
							{
								// 綠色,安全,繪制
								settextcolor (LIGHTGREEN);
								draw_num (t, box[t].num_peace);
								// 改為翻開
								box[t].mod_life = 1;
							}
							// 點擊的格子雷
							else if (box[t].mod_mine == 1)
							{
								// 扣除生命值
								num_life--;
								// 黑色,危險,繪制
								settextcolor (BLACK);
								draw_num (t, box[t].num_mine);
								// 改為翻開
								box[t].mod_life = 1;
								// 生命值減為零
								if (num_life <= 0)
								{
									// 失敗標志:哭臉
									setfillcolor (WHITE);
									setlinecolor (WHITE);
									fillrectangle (50, 20, 75, 45);
									settextstyle (30, 0, _T ("Wingdings"));
									setbkmode (TRANSPARENT);
									settextcolor (BLACK);
									outtextxy (50, 20, 0x4C);
									setbkmode (OPAQUE);
									settextstyle (20, 0, _T ("Consolas"));
									// 失敗
									exit_game = 1;
									boxm[1].mod = 0;
									boxm[2].mod = 0;
									boxm[3].mod = 0;
									boxm[6].mod = 0;
									boxm[7].mod = 1;
									num_flag = 0;
								}
								// 繪制
								draw_scene ();
							}
							// 成功結束判斷
							check_over ();
							break;
						}
					}
				}
 
				// 判斷是否點擊瞭可點擊按鈕
				for (i = 0; i < num_button; i++)
				{
					if (m.x > boxm[i].posx1 && m.y > boxm[i].posy1 && m.x < boxm[i].posx2 && m.y < boxm[i].posy2 && boxm[i].mod == 0)
					{
						break;
					}
				}
 
				// 點擊矩形按鈕
				switch (i)
				{
				// 生命值:num_life
				case 1:
				{
					// 輸入
					InputBox (ss, 10, _T ("輸入生命值(1 ~ 999)"));
					_stscanf_s (ss, _T ("%d"), &i);
					if (i > 0 && i <= 999)
					{
						num_life = i;
					}
					else { MessageBox (hOut, _T ("輸入錯誤,不在范圍內"), _T ("來自小豆子的提醒"), MB_OK); }
					// 繪制
					draw_scene ();
					break;
				}
				// 地圖邊長:num_size
				case 2:
				{
					// 輸入
					InputBox (ss, 10, _T ("輸入邊長(2 ~ 8)"));
					_stscanf_s (ss, _T ("%d"), &i);
					if (i > 1 && i <= 8)
					{
						num_size = i;
						num_box = 3 * num_size * (num_size - 1) + 1;
					}
					else { MessageBox (hOut, _T ("輸入錯誤,不在范圍內"), _T ("來自小豆子的提醒"), MB_OK); }
					// 繪制
					draw_scene ();
					break;
				}
				// 總地雷數:num_mine
				case 3:
				{
					InputBox (ss, 10, _T ("輸入地雷數(1 ~ 總格子數)"));
					_stscanf_s (ss, _T ("%d"), &i);
					if (i > 0 && i < num_box)
					{
						num_mine = i;
					}
					else { MessageBox (hOut, _T ("輸入錯誤,不在范圍內"), _T ("來自小豆子的提醒"), MB_OK); }
					// 繪制
					draw_scene ();
					break;
				}
				// 開始
				case 6:
				{
					num_box = 3 * num_size * (num_size - 1) + 1;
					if (num_mine < num_box && num_life > 0)
					{
						exit_game = 0;
						// 初始化
						initialization ();
					}
					else
					{
						MessageBox (hOut, _T ("請將雷數修改為小於格子數或將生命值修改為大於零"), _T ("來自小豆子的提醒"), MB_OK);
					}
					break;
				}
				// 重置
				case 7:
				{
					// 結束遊戲進程,進入準備階段
					if (exit_game == 0)
					{
						exit_game = 1;
						boxm[1].mod = 0;
						boxm[2].mod = 0;
						boxm[3].mod = 0;
						boxm[6].mod = 0;
						boxm[7].mod = 1;
						num_flag = 0;
						// 繪制
						draw_scene ();
					}
					break;
				}
				// 截圖
				case 8:
				{
					saveimage (_T ("image.png"));
					break;
				}
				// 退出
				case 9:
				{
					exit_game = 1;
					exit_move = 1;
					exit_carry = 1;
					break;
				}
				default:break;
				}
			}
			// 右鍵,且處於遊戲進行狀態
			else if (m.message == WM_RBUTTONDOWN && exit_game == 0)
			{
				for (t = 0; t <= 888; t++)
				{
					// 成功點擊空格子
					if ((m.x - box[t].posx) * (m.x - box[t].posx) + (m.y - box[t].posy) * (m.y - box[t].posy) <= 144 && box[t].mod_life == 0)
					{
						// 標記狀態轉換
						box[t].mod_flag = (box[t].mod_flag == 0 ? 1 : 0);
						// 繪制
						draw_box (t);
						// 畫小旗子
						if (box[t].mod_flag == 1)
						{
							draw_flag (t);
							num_flag++;
						}
						else
						{
							num_flag--;
						}
						// 繪制
						draw_scene ();
					}
				}
			}
		}
	}
}
 
// 主進程
void Gary::carry ()
{
	// 窗口定義
	hOut = initgraph (651, 401);
	SetWindowText (hOut, _T ("六邊形掃雷:掃雷模式"));
	// 參數初始化
	num_size = 5;
	num_mine = 10;
	num_life = 3;
	// 背景繪制
	setbkcolor (WHITE);
	cleardevice ();
	// 進程控制
	exit_carry = 0;
	while (exit_carry == 0)
	{
		initialization ();
		move ();
	}
	closegraph ();
}
 
// 主函數
int main (void)
{
	Gary G;
	G.carry ();
	return 0;
}

到此這篇關於C語言實現六邊形掃雷遊戲的示例代碼的文章就介紹到這瞭,更多相關C語言六邊形掃雷遊戲內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: