欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++實(shí)現(xiàn)掃雷小游戲(控制臺(tái)版)

 更新時(shí)間:2022年05月07日 11:42:49   作者:驚嘆號(hào)的云  
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)控制臺(tái)版的掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文為大家分享了C++實(shí)現(xiàn)掃雷小游戲的具體代碼,供大家參考,具體內(nèi)容如下

程序功能:

提供三種模式:初級(jí)、中級(jí)、高級(jí)

操作模式:wsad控制光標(biāo)移動(dòng),空格鍵打開(kāi)方塊

提供掃雷地圖的類

map.h

#ifndef MAP_H_
#define MAP_H_
 
#define MAX_LENGTH 32  //可以提供的地圖最大長(zhǎng)度
#define MAX_WIDTH 18  //可以提供的地圖最大寬度
#define UP_EDGE 1   //上邊界
#define DOWN_EDGE _wid  //下邊界
#define LEFT_EDGE 1  //左邊界
#define RIGHT_EDGE _lng //右邊界
 
void gotoxy(int, int);  //移動(dòng)光標(biāo)的接口函數(shù)
 
struct Position{ 
 int x;
 int y;
};
 
struct Info{
 int n;   //用于標(biāo)記雷、數(shù)字、空格的屬性
 bool flag;  //用于標(biāo)記是否要打開(kāi)方塊
};
 
class Map{
private:
 int _lng, _wid;     //長(zhǎng)和寬
 int _mines, _blanks;    //雷數(shù)、未開(kāi)啟空格數(shù)目
 Position _pos = {1, 1};   //光標(biāo)位置
 Info data[MAX_WIDTH][MAX_LENGTH]; //包含地圖信息的矩陣
public:
 void AcceptCond();   //選擇模式
 void InitMap();    //初始化地圖
 void SetMine();    //布置地雷
 void SetNumber();   //計(jì)算數(shù)字
 void SetPosition();   //移動(dòng)光標(biāo)至指示區(qū)域
 void ResetPosition();  //重置初始坐標(biāo)
 void ShowMap();    //顯示地圖
 void ShowAll();    //顯示全部地圖,游戲失敗時(shí)候調(diào)用
 void OpenBlock();   //打開(kāi)方塊,即將 flag 值設(shè)置為 true,在 ShowMap() 中將打開(kāi)方塊
 void FirstStep();   //預(yù)先處理游戲,防止第一步就觸雷導(dǎo)致失敗,這是無(wú)意義的
 bool PlayGame();    //提供的游戲操作接口
 bool Move(char);    //移動(dòng)光標(biāo),同時(shí)改變 _pos 的值用于指代目前要訪問(wèn)(打開(kāi))的方塊
 bool IfLose();    //游戲失敗,則返回真
 bool IfWin();    //游戲成功,則返回真
};
 
#endif

實(shí)現(xiàn)思路:

1.接收游戲模式參數(shù),確定地圖規(guī)模

2.初始化地圖,值全部設(shè)置為 0,flag 全部設(shè)置為 false,表示未曾打開(kāi)

3.根據(jù)用戶操作,確定要打開(kāi)的第一個(gè)空格的,然后再開(kāi)始布雷,避免開(kāi)局觸雷結(jié)束,這樣沒(méi)什么意義。

4.布雷采用生成隨機(jī)數(shù)的方法

5.根據(jù)地雷分布計(jì)算其他空格所對(duì)應(yīng)的數(shù)字

6.通過(guò)PlayGame() 接口進(jìn)行游戲操作

Map類的實(shí)現(xiàn)

#include <cstdlib>
#include <cstdio>
#include <ctime> //提供時(shí)間函數(shù)
#include <conio.h> //提供getch()
#include <windows.h>
#include <iostream>
#include "map.h"
 
#define GOTO(pos) gotoxy(2 * (pos.x) - 1, (pos.y) - 1) //定義用于移動(dòng)光標(biāo)的 宏
//由于一個(gè)方塊占 2 個(gè)格子,所以 pos.x 每加 1,則光標(biāo)要移動(dòng) 2 格
 
using std::cout;
using std::cin;
using std::endl;
 
void gotoxy(int x, int y) {  //移動(dòng)光標(biāo)的接口
 COORD pos = { short(x), short(y) };
 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 SetConsoleCursorPosition(hOut, pos);
}
 
 
void Map::AcceptCond() {    //接收游戲模式參數(shù)
 cout << "Choose Mode" << endl;
 cout << "1 : Beginner" << endl;
 cout << "2 : Intermediate" << endl;
 cout << "3 : Expert" << endl << "Mode: ";
 char mode;
 cin >> mode;
 while (('1' != mode) && ('2' != mode) && ('3' != mode)) {  //僅僅接受 1, 2, 3,其他字符跳過(guò)
  cout << "Wrong Mode, Enter number again\n Mode: ";
  cin >> mode;
 }
 switch (mode) {
  case '1' : _lng = 8; _wid = 8; _mines = 10; break;
  case '2' : _lng = 16; _wid = 16; _mines = 40; break;
  default: _lng = 30; _wid = 16; _mines = 99;
 }
 _blanks = _lng * _wid - _mines;  //計(jì)算空格數(shù),用于判斷是否贏,_blanks = 0 時(shí)判定贏
}
 
 
void Map::InitMap() {  //初始化地圖,顯示的地圖下標(biāo)從 1 - wid, 1 - _lng, 邊界外面還有空格,用于計(jì)算空格對(duì)應(yīng)數(shù)字的,邊界相當(dāng)于0
 for (int i = 0; i < _wid + 2; i++) {
  for (int j = 0; j < _lng + 2; j++) {
   data[i][j].n = 0;
   data[i][j].flag = false;
  }
 }
}
 
 
void Map::SetMine() {
 int i, j;
 int m = _mines;
 srand(time(NULL));
 while (m)
 {
  i = rand() % _wid + 1;
  j = rand() % _lng + 1;
  if ((-1 != data[i][j].n) && (j != _pos.x && i != _pos.y)) { //后面的條件用于避免用戶第一個(gè)打開(kāi)的空格處布置地雷
   data[i][j].n = -1;
   m--;
  }
 }
}
 
 
void Map::SetNumber() {
 for (int i = 1; i <= _wid; i++) {
  for (int j = 1; j <= _lng; j++) { //依次檢查周圍的 8 個(gè)空格的雷數(shù)
   if (-1 == data[i][j].n) continue;
   if (-1 == data[i-1][j-1].n) data[i][j].n++;
   if (-1 == data[i][j-1].n) data[i][j].n++;
   if (-1 == data[i+1][j-1].n) data[i][j].n++;
   if (-1 == data[i-1][j].n) data[i][j].n++;
   if (-1 == data[i+1][j].n) data[i][j].n++;
   if (-1 == data[i-1][j+1].n) data[i][j].n++;
   if (-1 == data[i][j+1].n) data[i][j].n++;
   if (-1 == data[i+1][j+1].n) data[i][j].n++;
  }
 }
}
 
 
void Map::SetPosition() {
 GOTO(_pos);
}
 
 
void Map::ResetPosition() {
 _pos.x = _pos.y = 1;
}
 
 
void Map::ShowMap() {
 system("cls");   //清屏
 system("color 03");  //調(diào)整控制臺(tái)顯示顏色
 SetConsoleOutputCP(437); //使方塊能夠正常顯示
 for (int i = 1; i <= _wid; i++) {
  cout << '|';  //左邊界
  for (int j = 1; j <= _lng; j++) {
   if (data[i][j].flag) {
    switch (data[i][j].n) {
     case 0 : cout << " "; break; //由于方塊占兩個(gè)格子,因此其他的輸出,如空格、數(shù)字等也要占2個(gè)格子,對(duì)齊
     default: cout << data[i][j].n << ' ';
    }
   }
   else printf("%c", 219);
  }
  cout << '|' << endl; //右邊界
 }
 gotoxy(0, _wid+2); //在地圖下方輸出坐標(biāo)信息和空格數(shù)
 printf("Position : (%d, %d)\n Blanks : %d", _pos.x, _pos.y, _blanks);
 GOTO(_pos); //歸位到原先地圖坐標(biāo)對(duì)應(yīng)的位置
}
 
 
void Map::ShowAll() { //類似上面的ShowMap(),但在游戲失敗時(shí)調(diào)用
 system("cls");
 system("color 03");
 SetConsoleOutputCP(437);
 for (int i = 1; i <= _wid; i++) {
  cout << '|';
  for (int j = 1; j <= _lng; j++) {
   switch (data[i][j].n) {
    case 0 : printf("%c", 219); break;
    case -1: 
     if (i == _pos.y && j == _pos.x)
      cout << "X ";
     else
      cout << "* ";
     break;
    default: cout << data[i][j].n << ' ';
   }
  }
  cout << '|' << endl;
 }
}
 
#define SOLVE_IT(t) {stack[++top] = (t); data[(t).y][(t).x].flag = true; _blanks--;}
#define FALSE_FLAG(t) !data[(t).y][(t).x].flag
 
void Map::OpenBlock() {      //用棧來(lái)將連著的空格區(qū)域遍歷一遍,并將其 flag 值置為 true
 if (data[_pos.y][_pos.x].flag) return; //如果已經(jīng)打開(kāi)過(guò)就不需要再次打開(kāi),否則 _blanks--; 會(huì)多次執(zhí)行,無(wú)法判斷贏
 Position stack[_lng * _wid << 1];
 Position t;
 int top = 0;
 
 stack[top] = _pos;
 data[_pos.y][_pos.x].flag = true;
 _blanks--;
 while (top != -1) {
  t = stack[top--];
  if (0 == data[t.y][t.x].n) { //如果該位置為 0 ,那么它周圍的格子都要打開(kāi)
   t.y--; //判斷上方三個(gè)格子
   if (t.y >= UP_EDGE) { //如果上方三個(gè)格子 y 不越界
    if (FALSE_FLAG(t)) SOLVE_IT(t)
    t.x--;
    if (t.x >= LEFT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t)
    t.x += 2;
    if (t.x <= RIGHT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t)
    t.x--;
   }
    
   t.y++; t.x--;//判斷左右兩個(gè)格子, 此時(shí) t.y 復(fù)原
   if (t.x >= LEFT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t)
   t.x += 2;
   if (t.x <= RIGHT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t)
 
   t.y++; //下方三個(gè)格子, 此時(shí) t.x 是最右邊的格子
   if (t.y <= DOWN_EDGE) { //如果下方三個(gè)格子 y 不越界, 與上面判斷基本相同
    if (t.x <= RIGHT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t)
    t.x--;
    if (FALSE_FLAG(t)) SOLVE_IT(t)
    t.x--;
    if (t.x >= LEFT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t)
   }
  }
 }
}
 
 
void Map::FirstStep() { //函數(shù)結(jié)束后將改變 _pos,就是我們用的預(yù)先處理函數(shù),防止第一步就觸雷的
 char op;
 do {
  op = getch();
  while ((op != 'a') && (op != 's') && (op != 'd') && (op != 'w') && (op !=' '))
   op = getch();
 } while (Move(op));
}
 
 
bool Map::Move(char op) {
 switch (op) { //通過(guò)不同的操作,改變坐標(biāo),然后再通過(guò) GOTO宏 移動(dòng)到該位置上
  case ' ':
   return false;
  case 'w':
   if (UP_EDGE != _pos.y) _pos.y--;
   break;
  case 'a':
   if (LEFT_EDGE != _pos.x) _pos.x--;
   break;
  case 's':
   if (DOWN_EDGE != _pos.y) _pos.y++;
   break;
  default:
   if (RIGHT_EDGE != _pos.x) _pos.x++;
 }
 gotoxy(0, _wid + 2);
 printf("Position : (%d, %d)\n Blanks : %d", _pos.x, _pos.y, _blanks);
 GOTO(_pos);
 return true;
}
 
 
bool Map::IfLose() {
 return -1 == data[_pos.y][_pos.x].n;
}
 
 
bool Map::IfWin() {
 return 0 == _blanks;
}
 
 
bool Map::PlayGame() {
 char op;
 float start, end;
 while (!IfWin()) {
  do {
   op = getch();
   while ((op != 'a') && (op != 's') && (op != 'd') && (op != 'w') && (op !=' '))
    op = getch();
  } while (Move(op));
 
  if (IfLose()) { //觸雷
   ShowAll(); gotoxy (0, _wid + 3);
   return false;
  }
  else {
   OpenBlock();   //打開(kāi)方塊,實(shí)質(zhì)上時(shí)將 flag 的值置為 true,接著 ShowMap()將可以顯示該方塊信息
   ShowMap();
   GOTO(_pos);
  }
 }
 gotoxy(0, _wid + 3);
 return true;
}

主程序

mineweeper.cpp

#include <iostream>
#include <cstdlib>
#include <conio.h>
#include <ctime>
#include "map.h"
 
using namespace std;
 
int main() {
 Map game;
 float start, end;
 char ch;
 while (1) {
  game.AcceptCond();  //選擇模式
  game.InitMap();  //初始化
  game.ShowMap();  //顯示地圖。 注:此時(shí)地圖未生成完畢
  game.FirstStep();  //預(yù)處理,防止第一步就觸雷結(jié)束
  game.SetMine();  //設(shè)置地雷
  game.SetNumber();  //根據(jù)地雷分布計(jì)算數(shù)字
  game.OpenBlock();  //打開(kāi)開(kāi)局預(yù)先想要打開(kāi)的第一個(gè)空
  start = clock();
  game.ShowMap();
  if (game.PlayGame()) { //根據(jù)PlayGame()接口的返回值判定輸贏
   cout << endl << "~ Congratulation ~\n ~ You Win ~" << endl;
  }
  else {
   cout << endl << "BOOM!!! ~ Game Over ~\n" << endl;
  }
  end = clock();
  printf("\nTime : %.2f\n", (end - start) / CLK_TCK); //輸出游戲所用時(shí)間
  cout << endl << "Please enter 'q' to quit, or any other keys to continue" << endl;
  game.SetPosition(); //用于觸雷失敗時(shí),將光標(biāo)返回到觸雷的位置,提示哪一步失敗,同時(shí)觸碰的雷也將顯示為 ‘X'
  ch = getch();
  if ('q' == ch) { // q 用于退出游戲
   system("cls");
   cout << "~ Bye ~" << endl;
   break;
  }
  else {
   game.ResetPosition();
   system("cls");
  }
 }
 system("pause");
 return 0;
}

游戲截圖

更多精彩游戲小代碼,請(qǐng)點(diǎn)擊《游戲?qū)n}》閱讀

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解c++中的類型識(shí)別

    詳解c++中的類型識(shí)別

    這篇文章主要介紹了 詳解c++中的類型識(shí)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Qt編寫(xiě)地圖實(shí)現(xiàn)實(shí)時(shí)動(dòng)態(tài)軌跡效果

    Qt編寫(xiě)地圖實(shí)現(xiàn)實(shí)時(shí)動(dòng)態(tài)軌跡效果

    實(shí)時(shí)動(dòng)態(tài)軌跡主要是需要在地圖上動(dòng)態(tài)顯示GPS的運(yùn)動(dòng)軌跡,也是編寫(xiě)地圖時(shí)一個(gè)重要的功能。本文將利用Qt實(shí)現(xiàn)這一功能,需要的可以參考一下
    2022-02-02
  • C++非繼承時(shí)函數(shù)成員訪問(wèn)屬性和類繼承過(guò)程中的訪問(wèn)控制

    C++非繼承時(shí)函數(shù)成員訪問(wèn)屬性和類繼承過(guò)程中的訪問(wèn)控制

    這篇文章主要介紹了C++非繼承時(shí)函數(shù)成員訪問(wèn)屬性和類繼承過(guò)程中的訪問(wèn)控制,非繼承時(shí),protected成員和private成員沒(méi)有任何區(qū)別,都是類內(nèi)部可以直接訪問(wèn)它們、類外部的類對(duì)象不可訪問(wèn)它們、類內(nèi)部的類對(duì)象可以訪問(wèn)它們,更多詳細(xì)內(nèi)容請(qǐng)參考下面相關(guān)資料
    2022-03-03
  • C語(yǔ)言選擇排序算法及實(shí)例代碼

    C語(yǔ)言選擇排序算法及實(shí)例代碼

    本篇文章主要介紹了 C語(yǔ)言選擇排序算法,這里提供代碼實(shí)例以便大家理解,通過(guò)本文,更好的理解排序算法
    2016-07-07
  • C++ 標(biāo)準(zhǔn)模板庫(kù) STL 順序容器詳解

    C++ 標(biāo)準(zhǔn)模板庫(kù) STL 順序容器詳解

    這篇文章主要介紹了C++ 標(biāo)準(zhǔn)模板庫(kù) STL 順序容器詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • string與char*轉(zhuǎn)換的使用詳解

    string與char*轉(zhuǎn)換的使用詳解

    本篇文章對(duì)string與char*的轉(zhuǎn)換進(jìn)行的介紹。需要的朋友參考下
    2013-05-05
  • 簡(jiǎn)單掌握C++中的函數(shù)模板

    簡(jiǎn)單掌握C++中的函數(shù)模板

    這篇文章主要介紹了C++中的函數(shù)模板,包括函數(shù)模板的聲明和生成以及異常處理等基本知識(shí),需要的朋友可以參考下
    2016-04-04
  • 深入C++浮點(diǎn)數(shù)無(wú)效值定義與判定的解決辦法

    深入C++浮點(diǎn)數(shù)無(wú)效值定義與判定的解決辦法

    本篇文章是對(duì)C++中浮點(diǎn)數(shù)無(wú)效值定義與判定進(jìn)行了介紹,需要的朋友參考下
    2013-05-05
  • C++枚舉類型用法總結(jié)(枚舉字符常量代替常量)

    C++枚舉類型用法總結(jié)(枚舉字符常量代替常量)

    這篇文章主要介紹了C++枚舉類型用法總結(jié)(枚舉字符常量代替常量),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • QT6安裝圖文教程(兼容QT5、QT4)

    QT6安裝圖文教程(兼容QT5、QT4)

    本文主要介紹了QT6安裝圖文教程(兼容QT5、QT4),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評(píng)論