一直說寫個幾百行的小專案,於是我寫了一個控制檯的掃雷,沒有想到精簡完了程式碼才200行左右,不過考慮到這是我精簡過後的,濃縮才是精華嘛,我就發出來大家一起學習啦,看到程式跑起來能玩,感覺還是蠻有成就感的~哈哈
掃雷應該屬於一款大眾遊戲,從我初中使用計算機開始,它就被整合到了windows系統中,雖然他是這麼經典,我還是要介紹一下他的玩法,然後再考慮在控制檯中怎麼實現它。
1、
遊戲的主介面,是一個一個小方格,
在小方格上單擊左鍵,可以翻開小方格看看後面有什麼
。
2、在這些小方格的背後隱藏著雷
,如果不幸點中了雷,那麼就GameOver了。
如果點中的不是一個雷,那麼就是一塊空地,這個時候會出現兩種情況:
1)
用滑鼠點中的空地周圍八個點內有雷,那麼就顯示雷的個數
2)
用滑鼠點中的空地周圍沒有雷,這個時候就將周圍的空地全部顯示出來,遇到該顯示數字的空地,就將數字顯示出來。(仔細觀察你會發現,數字會將空地圍起來,這是一句廢話,但是也值得想一想這是為什麼)
3、在小方格上,點選滑鼠的右鍵,可以將一個空地標記為雷,
當然這個功能只是為了方便你記憶你之前確定是雷的地方。(還有左右鍵都點,和點選右鍵出現?標記,這裡就不談啦)
4、
當空地上剩餘的格子數和雷的個數一樣多,那麼這個時候就應該算是勝利啦。
OK~遊戲流程說完了,這個時候該談談如何實現了。
1、
首先需要一張地圖,一般情況下我們都可以用一個二維陣列表示一個地圖,每一個元素代表著掃雷中的一個小方格。相應元素儲存0,那麼地圖上的這個位置就是空地,相應元素儲存1,那麼就代表這個位置就一顆雷。
2、
在控制檯上依照二維陣列長度和寬度,列印相應的小方塊。
3、
然後就用滑鼠點選那些小方塊,對於控制檯來講,在黑框框的區域中是有座標的,可以使用一些函式捕獲到你點選了螢幕的哪一個座標。
4、
對於控制檯來說,列印一個字元,有的字元橫向佔一個位置比如普通的字母數字,有的字元橫向佔兩個位置比如一些圖形字元: ①②③■◆等等,這點在控制檯程式設計的時候要注意。
5、
當點選螢幕的時候,獲取到點選的座標後,去二維陣列中檢視相應的位置是雷還是空地,從而做相應的處理。
1)
假如點選到了雷,那麼就控制遊戲結束
2)
假如點選到了空地有兩種情況
1。點選的空地周圍有雷,那麼就將雷的個數顯示出來
2。假如點選的空地周圍沒有雷,那麼就使用遞迴的方法去探測周圍的點,探測出與其相連的所有周圍有雷的點。
這個是我實現的效果,下面就是程式碼啦:
// saolei。cpp : 定義控制檯應用程式的入口點。
//
#include
“stdafx。h”
#include
#include
#include
#define Boom 10
int
a
[
10
][
10
]
=
{
0
};
COORD
TempPos
[
100
]
=
{
0
};
int
nSign
=
0
;
/************************************
函式名 : WriteWchar
函式作用: 在控制檯相應的座標上顯示一串字元
返回值 : void
引數 : int x 橫座標
引數 : int y 縱座標
引數 : char szString[] 要顯示的字串
說明 :
************************************/
void
WriteWchar
(
int
x
,
int
y
,
char
szString
[])
{
HANDLE
hOut
=
GetStdHandle
(
STD_OUTPUT_HANDLE
);
COORD
pos
=
{
x
*
2
,
y
};
SetConsoleCursorPosition
(
hOut
,
pos
);
printf
(
“%s”
,
szString
);
}
/************************************
函式名 : DrawNumber
函式作用: 在相應的座標上,根據傳入的數字,列印相應的數字字元
返回值 : void
引數 : COORD pos 要列印的位置
引數 : int nNumber 要列印的數字
說明 :
************************************/
void
DrawNumber
(
COORD
pos
,
int
nNumber
)
{
switch
(
nNumber
)
{
case
1
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“①”
);
break
;
case
2
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“②”
);
break
;
case
3
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“③”
);
break
;
case
4
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“④”
);
break
;
case
5
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“⑤”
);
break
;
case
6
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“⑥”
);
break
;
case
7
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“⑦”
);
break
;
case
8
:
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“⑧”
);
break
;
default
:
break
;
}
}
/************************************
函式名 : GetNumber
函式作用: 獲取一個點的四周有幾顆雷
返回值 : int
引數 : COORD pos 要探測的點的座標
說明 :
************************************/
int
GetNumber
(
COORD
pos
)
{
int
nCount
=
0
;
for
(
int
i
=
pos
。
X
-
1
;
i
<=
pos
。
X
+
1
;
i
++
)
for
(
int
j
=
pos
。
Y
-
1
;
j
<=
pos
。
Y
+
1
;
j
++
)
{
if
(
a
[
j
][
i
]
==
Boom
)
{
nCount
++
;
}
}
return
nCount
;
}
/************************************
函式名 : Drawmap
函式作用: 列印一下地圖
返回值 : void
說明 :
************************************/
void
Drawmap
()
{
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
for
(
int
j
=
0
;
j
<
10
;
j
++
)
{
WriteWchar
(
j
,
i
,
“■”
);
}
}
}
/************************************
函式名 : Init
函式作用: 隨機生成10個地雷,然後存到陣列中
返回值 : void
說明 :
************************************/
void
Init
()
{
srand
(
time
(
NULL
));
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
int
Temp_x
=
rand
()
%
10
;
int
Temp_y
=
rand
()
%
10
;
//判斷這個地方是不是已經生成一個雷了,如果沒有,賦值為雷
if
(
a
[
Temp_x
][
Temp_y
]
!=
Boom
)
{
a
[
Temp_x
][
Temp_y
]
=
Boom
;
}
//如果是雷,就相當於本次生成沒有發生過。。。。。
else
{
i
——
;
}
}
Drawmap
();
}
/************************************
函式名 : IsClose
函式作用: 判斷是不是已經探測過的點,由於使用的8方向遞迴的探測,這樣避免重複
返回值 : bool
引數 : COORD posTemp
說明 :
************************************/
bool
IsClose
(
COORD
posTemp
)
{
for
(
int
i
=
0
;
i
{
if
(
TempPos
[
i
]。
X
==
posTemp
。
X
&&
TempPos
[
i
]。
Y
==
posTemp
。
Y
)
return
true
;
}
return
false
;
}
/************************************
函式名 : IsKongdi
函式作用: 判斷一個點是空地,還是雷,如果是空地,需要做其他處理
返回值 : void
引數 : COORD pos
說明 :
************************************/
bool
IsKongdi
(
COORD
pos
)
{
int
nNumber
=
0
;
//1 如果是雷,就直接返回一個false說明要掛了
if
(
a
[
pos
。
Y
][
pos
。
X
]
==
Boom
)
{
return
false
;
}
//2 如果不是雷,那麼就做後續處理
else
{
//2。1先判斷一下週圍有幾顆雷
nNumber
=
GetNumber
(
pos
);
if
(
nNumber
!=
0
){
//有幾顆雷,就列印這個數字
DrawNumber
(
pos
,
nNumber
);
return
true
;
}
else
{
//如果沒有雷,那就先畫空地出來,然後向周圍擴散去探測其他點
WriteWchar
(
pos
。
X
,
pos
。
Y
,
“ ”
);
}
}
//2。2點到了空地,但是周圍沒有雷的情況的處理,繼續去探測周圍8個點
for
(
int
i
=
-
1
;
i
<=
1
;
i
++
)
for
(
int
j
=
-
1
;
j
<=
1
;
j
++
)
{
COORD
posTemp
=
{
pos
。
X
+
i
,
pos
。
Y
+
j
};
//是不是越界了
if
(
i
==
0
&&
j
==
0
||
posTemp
。
X
==-
1
||
posTemp
。
Y
==-
1
||
posTemp
。
X
==
10
||
posTemp
。
Y
==
10
)
continue
;
//這個點是不是已經探測過了
if
(
IsClose
(
posTemp
))
continue
;
//這個點沒有探測過,就將其加入到陣列中,然後使其在以後的探測中,存入
TempPos
[
nSign
++
]
=
posTemp
;
IsKongdi
(
posTemp
);
}
return
true
;
}
/************************************
函式名 : GetMousePosition
函式作用: 獲取滑鼠點選的位置,假如沒有獲取到,就返回(-1,-1)
返回值 : COORD 滑鼠點選的座標
說明 :
************************************/
COORD
GetMousePosition
()
{
HANDLE
hIn
=
GetStdHandle
(
STD_INPUT_HANDLE
);
INPUT_RECORD
stcInput
=
{
0
};
DWORD
buffer
;
COORD
pos
=
{
-
1
,
-
1
};
ReadConsoleInput
(
hIn
,
&
stcInput
,
1
,
&
buffer
);
if
(
stcInput
。
EventType
==
MOUSE_EVENT
)
{
MOUSE_EVENT_RECORD
stcMouseEnent
=
stcInput
。
Event
。
MouseEvent
;
if
(
stcMouseEnent
。
dwButtonState
==
FROM_LEFT_1ST_BUTTON_PRESSED
)
{
pos
=
stcMouseEnent
。
dwMousePosition
;
pos
。
X
/=
2
;
}
}
return
pos
;
}
int
_tmain
(
int
argc
,
_TCHAR
*
argv
[])
{
Init
();
COORD
pos
;
//開始遊戲
while
(
1
)
{
//獲取滑鼠點選位置
pos
=
GetMousePosition
();
if
(
pos
。
X
!=-
1
)
{
//如果滑鼠點選的位置被探測過了,就開始下一次迴圈
if
(
IsClose
(
pos
))
{
continue
;
}
TempPos
[
nSign
++
]
=
pos
;
bool
bIskongdi
=
IsKongdi
(
pos
);
//點到雷了,就直接退出遊戲了。
if
(
false
==
bIskongdi
)
{
system
(
“cls”
);
WriteWchar
(
20
,
10
,
“you lose”
);
getchar
();
break
;
}
//檢測是不是贏了,贏的條件就是沒有被探測的點的個數和雷的個數相等
if
(
nSign
==
90
)
{
system
(
“cls”
);
WriteWchar
(
20
,
10
,
“you win”
);
}
}
}
return
0
;
}
專案不是很長,但是註釋我寫的還算明白,估計大家都可以看得懂,希望對於新手們有一定的幫助,謝謝大家的支援!!!
看到這裡你是不是又學到了很多新知識呢~
如果你很想學程式設計,小編推薦我的C語言/C++程式設計學習基地【點選進入】!
都是學程式設計小夥伴們,帶你入個門還是簡簡單單啦,一起學習,一起加油~
還有許多學習資料和影片,相信你會喜歡的!
涉及:
遊戲開發、常用軟體開發、程式設計基礎知識、課程設計、駭客等等……