掃雷--C語言實現

Nemo丶發表於2018-05-28

  在學習過二維陣列 簡單的遞迴呼叫 ,之後很容易寫一個掃雷小遊戲。


主函式:

主函式所寫的是玩家玩遊戲的大致步驟。  

所其中包括遊戲選單,遊戲選項 ,遊戲 ,輸贏結果的判斷及顯示 ,while或do...while迴圈實現遊戲迴圈

#include "gmine.h"

void menu()
{
	printf("************  掃雷  ************\n");
	printf("********>   1.  play   <********\n");
	printf("********>   0.  exit   <********\n");
	printf("********************************\n");
}

void game()
{
	srand((unsigned)time(NULL));
	printf("設定雷的個數: ");
	int num;
	scanf("%d", &num);
	char panel[ROW][COL];                //有記錄雷的介面
	char panel2[ROW][COL];               //對玩家顯示介面
	int row = 0, col = 0, flag = 0;
	InitBoard(num, panel, panel2);     //初始化panel,panel2
	FillNum(panel);                //填充雷周圍的數字
	//ShowBoard(panel); 
	ShowBoard(panel2);                 
	int i = 0;
	int step = 0;
	for (i = 0; i < num; i++)
	{
		printf("請輸入座標並標記是否是雷(1代表是,0代表不是):");
		scanf("%d%d%d", &row, &col, &flag);
		int mine = Find(panel, panel2, row - 1, col - 1, flag);
		//如果踩到雷
		if (mine == 2)
		{
			//第一次就踩雷,將雷挪走
			if (step == 0)
			{
				mine = MoveMine(panel, panel2,row - 1,col - 1 );
			}
			else
			    break;
		}
		//如果找到雷
		else if (mine)
		{
			ShowBoard(panel2);
			continue;
		}
		step = 1;
		i--;
		ShowBoard(panel2);                  //顯示盤
	}
	if (i < num)
	{
		printf(" 遺憾 > < 遊戲結束. \n");
	}
	else
	{
		printf("!!恭喜,玩家勝利 !!\n");
	}
 
}

int main() 
{
	int input = 0;
	
		menu();
		printf("請輸入:> ");
		scanf("%d", &input);
	do 
	{	switch (input)
		{
		case 1: game(); break;
		case 0: exit(0); break;
		default: printf("輸入錯誤,請輸入0 or 1\n"); break;
		}
	printf("再來一局??(1: 繼續  0: 退出 ) ");
	int again = 0;
	scanf("%d", &again);
	if (again == 1)
	{
		input = 1;
	}
	else if (again == 0)
	{
		input = 0;
	}
	else
	{
	
	printf("輸入錯誤\n");
	}
	} while (input);
	return 0;
}


掃雷的具體實現:

寫這一模組時應該注重梳理,應該一步步寫,如:繪製介面 --> 顯示介面 --> 初始化盤 --> 檢測雷周圍的數字 --> 列印數字(0或其他)--> 標記雷 --> 擴充套件功能

#include "gmine.h"


//輸出橫向座標
void PrintX() {
	int row = 0;
	printf("  ");
	for (row = 0; row < ROW; row++) 
	{
		printf("%4d", row + 1);
	}
	printf("\n");
}

//輸出橫向框
void PrintH() {
	int col = 0;
	printf("   +");
	for (col = 0; col < COL *2; col++) 
	{
		if (!((col + 1) % 2)){
			printf("+");
		}
		else {
			printf("---");
		}
	}
	printf("\n");
}


//顯示盤
void ShowBoard(char panel[ROW][COL])
{
	int row = 0, col = 0;
	PrintX();
	PrintH();
	for (row = 0; row < ROW; row++) 
	{
		printf("%2d ", row + 1); //輸出豎向座標
		printf("| ");
		for (col = 0; col < COL; col++)
		{
			printf("%c ", panel[row][col]);
			printf("| ");
		}
		printf("%d\n", row +1); //輸出豎向座標
		PrintH();   //橫向框
	}
	PrintX();
}

//初始化盤
void InitBoard(int num, char panel[ROW][COL], char panel2[ROW][COL])
{
	int i = 0;
	int row = 0;
	int col = 0;
	for (row = 0; row < ROW; row++) 
	{
		for (col = 0; col < COL; col++) 
		{
			panel[row][col] = ' ';
			panel2[row][col] = ' ';
		}
	}
	for (i = 0; i < num; i++) 
	{
		row = rand() % ROW;
		col = rand() % COL;
		if (panel[row][col] == '*') 
		{
			i--;
		}
		else 
		{
			panel[row][col] = '*';
		}
	}
}

//根據佈置好的雷計算雷周圍的數字
void FillNum(char panel[][COL]) 
{ 
	//填充數字
	int row = 0, col = 0;
	for (row = 0; row < ROW; row++) 
	{
		for (col = 0; col < COL; col++) 
		{
			int count = 0;
			//如果是雷,則不需要計算該位置周圍的雷數
			if (panel[row][col] == '*')
				continue;
			if ((row - 1) >= 0 && (col - 1) >= 0)
			{
				//檢測左上角是否在盤內
				if (panel[row - 1][col - 1] == '*') 
					count++;                           //檢測到雷,則count加1
			}

			if ((row + 1) < ROW && (col - 1) >= 0)
			{
				//左下角
				if (panel[row + 1][col - 1] == '*')
					count++;
			}

			if ((row - 1) >= 0 && (col + 1) < COL)
			{
				//右上角
				if (panel[row - 1][col + 1] == '*')
					count++;
			}

			if ((row + 1) < ROW && (col + 1) < COL)
			{
				//右下角
				if (panel[row + 1][col + 1] == '*')
					count++;
			}

			if ((row - 1) >= 0) 
			{
				//正上方
				if (panel[row - 1][col] == '*') 
					count++;
			}

			if ((row + 1) < ROW)
			{
				//正下方
				if (panel[row + 1][col] == '*')
					count++;
			}

			if ((col - 1) >= 0)
			{
				//左邊
				if (panel[row][col - 1] == '*')
					count++;
			}

			if ((col + 1) < COL)
			{
				//右邊
				if (panel[row][col + 1] == '*')
					count++;
			}

			panel[row][col] = '0' + count;                     //將計算出的周圍的雷數整型轉換成字元型
		}
	}
}


//點到0,顯示多個數字
void ShowNum(char panel[][COL], int row, int col, char panel2[][COL])
{
	panel2[row][col] = panel[row][col];        //顯示數字

	//檢測相鄰點是否超出棋盤 若相鄰點為0且沒有雷則以該點為中心繼續顯示

	//正上方
	if ((row - 1) >= 0) 
	{
		if (panel[row - 1][col] == '0' && panel2[row - 1][col] == ' ')
			ShowNum(panel, row - 1, col, panel2);
		else 
			panel2[row - 1][col] = panel[row - 1][col];
	}

	//正下方
	if ((row + 1) < ROW)
	{
		if (panel[row + 1][col] == '0' && panel2[row + 1][col] == ' ')
			ShowNum(panel, row + 1, col, panel2);
		else 
			panel2[row + 1][col] = panel[row + 1][col];
	}

	//左邊
	if ((col - 1) >= 0)
	{
		if (panel[row][col - 1] == '0' && panel2[row][col - 1] == ' ')
			ShowNum(panel, row, col - 1, panel2);
		else 
			panel2[row][col - 1] = panel[row][col - 1];
	}

	//右邊
	if ((col + 1) < COL)
	{
		if (panel[row][col + 1] == '0' && panel2[row][col + 1])
			ShowNum(panel, row, col + 1, panel2);
		else panel2[row][col + 1] = panel[row][col + 1];
	}

	//左上角
	if ((row - 1) >= 0 && (col - 1) >= 0)
	{
		if (panel[row - 1][col - 1] == '0' && panel2[row - 1][col - 1] == ' ')
			ShowNum(panel, row - 1, col - 1, panel2);
		else
			panel2[row - 1][col - 1] = panel[row - 1][col - 1];
	}
	
	//左下角
	if ((row + 1) < ROW && (col - 1) >= 0)
	{	
		if (panel[row + 1][col - 1] == '0' && panel2[row + 1][col - 1] == ' ')
			ShowNum(panel, row + 1, col - 1, panel2);
		else panel2[row + 1][col - 1] = panel[row + 1][col - 1];

	}

	//右上角
	if ((row - 1) >= 0 && (col + 1) < COL)
	{
		if (panel[row - 1][col + 1] == '0' && panel2[row - 1][col + 1] == ' ')
			ShowNum(panel, row - 1, col + 1, panel2);
		else panel2[row - 1][col + 1] = panel[row - 1][col + 1];
	}	

	//右下角
	if ((row + 1) < ROW && (col + 1) < ROW) 
	{
		if (panel[row + 1][col + 1] == '0' && panel2[row + 1][col + 1] == ' ')
			ShowNum(panel, row + 1, col + 1, panel2);
		else
			panel2[row + 1][col + 1] = panel[row + 1][col + 1];
	}
}


//找雷
int Find(char panel[][COL],  char panel2[][COL],int row, int col, int flag) 
{
	if (flag == 1) 
	{ 
		//標記可能是雷的位置 
		//是雷返回 1 不是返回 0
		panel2[row][col] = 'F';       //如果是雷標記‘F' 
		if (panel[row][col] == '*') 
		{
			return 1;
		}
		else 
		{
			return 0;
		}
	}
	else
	{
		//猜測不是雷
		if (panel[row][col] == '*') 
		{ 
			//點到雷,遊戲失敗
			return 2;
		}
		else if (panel[row][col] == '0') 
		{ 
			//點選到0,顯示多個數字
			ShowNum(panel, row, col, panel2);
			return 0;
		}
		else 
		{
			panel2[row][col] = panel[row][col];      //顯示數字
			return 0;
		}
	}
}

//防止第一次踩雷
int MoveMine(char panel[][COL], char panel2[][COL], int row, int col)
{

	int row2 = 0;
	int col2 = 0;
	//找到沒有雷的位置與輸入位置交換
	for (row2 = 0; row2 < ROW; row++)
	{
		for (col2 = 0; col2 < COL; col++)
		{
			int tmp = 0;
			if (panel[row2][col2] == '*')
				continue;
			else
			{
				//將雷移走
				tmp = panel[row][col];
				panel[row][col] = panel[row2][col2];
				panel[row2][col2] = tmp;
				//更新
				FillNum(panel);
				//ShowBoard(panel);
                panel2[row][col] = panel[row][col];     
				return panel2[row][col];
			}
		}

	}

}


標頭檔案:

#ifndef _GAME_H_
#define _GAME_H_
 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 10
#define COL 10

void ShowaBoard (char panel[ROW][COL]);
void InitBoard (int num, char panel[ROW][COL], char panel2[ROW][COL]);
void FillNumber(char panel[][COL]);
void ShowNum(char panel[][COL], int row, int col, char panel2[][COL]);
int Find(char panel[][COL], char panel2[][COL], int row, int col, int flag);
int MoveMine(char panel[][COL], char panel2[][COL],int row,int col);

#endif //_GAME_H_

由於多次修改過,可能程式碼有很多地方很亂,而且應該有許多地方寫的比較挫,然後功能比較簡單,之後希望能有好的建議。

  

相關文章