2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ゲームプログラミング:C++でマインスイーパを作ってみた

Posted at

概要

コンソールゲームプログラミングは5つ目!
2Dでフィールドが綺麗に用意されるタイプのゲームは、もう作り方が分かってきますね。
今回はマインスイーパです。
こちらは昔やったことあったなと思い出しましたが、当時は「地雷を爆破させたら勝ち」だと思っていました。
「どれだけ早く地雷を爆破するのか」競うゲームと解釈していて、なんかおもんないわと思っていました。
え?みなさんもそうですか?

いやー、推論を駆使して楽しむゲームだったとは・・・いいですね、面白い!!

以下を参考にしながらマインスイーパを作成しました。
僕個人が考慮した仕様で、フラグを立てた箇所の鉱石を取り除くことはできないようにしました。
館長、ありがとう!!!
 https://youtu.be/CHdkoeb-8oQ

とりあえずうまく動作していそうです。
スクリーンショット (99).png
お、ここは明らかに地雷!
スクリーンショット (100).png
じゃあここにフラグを立ててと・・・
スクリーンショット (101).png
楽勝楽勝~
スクリーンショット (102).png
ぎゃあああああああああああ!!

コード

せっかくなので、コードを公開します。
ご自由にお試し下さい。
ホントはコメントとかネーミングとかもうちょっと考えて、初学者の方が分かるようにしたいと思っていますが・・・

相変わらず不適切なコーディングがあるので、ちょこちょこ修正していこうと思います。
回帰テストせなアカンで!!!

※コードレビューコメント頂けますと幸いです

# include <iostream>
# include <stdlib.h>
# include <conio.h>
# include <time.h>

static const int FIELD_WIDTH = 9;
static const int FIELD_HEIGHT = 9;

static const int BOMB_COUNT = 10;

int cursorX;
int cursorY;

struct Cell
{
    bool isExistBomb;
    bool isHiddenByMine;
    bool isOnFlag;
};

Cell cells[FIELD_WIDTH][FIELD_HEIGHT];

int getAdjacentBombsCount(int x, int y);
void autoRemoveMines(int argX, int argY);

int main()
{
    // initialize. 
    srand(static_cast<unsigned int>(time(NULL)));
    {
        int count = 0;
        while(count < BOMB_COUNT)
        {
            int x = rand() % FIELD_WIDTH;
            int y = rand() % FIELD_HEIGHT;
            if (false == cells[x][y].isExistBomb)
            {
                cells[x][y].isExistBomb = true;
                ++count;
            }
        }
    }

    for (int y = 0; y < FIELD_HEIGHT; ++y)
    {
        for (int x = 0; x < FIELD_WIDTH; ++x)
        {
            cells[x][y].isHiddenByMine = true;
        }
    }

    bool isExplosion = false;
    bool isClear = false;

    while (1)
    {
        system("cls");
        for (int y = 0; y < FIELD_HEIGHT; ++y)
        {
            for (int x = 0; x < FIELD_WIDTH; ++x)
            {
                if ((cursorX == x) && (cursorY == y))
                {
                    if (true == isExplosion)
                    {
                        std::cout << "※";
                    }
                    else
                    {
                        std::cout << "◎";
                    }
                }
                else if (true == cells[x][y].isOnFlag)
                {
                    std::cout << "▲";
                }
                else if (true == cells[x][y].isHiddenByMine)
                {
                    std::cout << "■";
                }
                else if (true == cells[x][y].isExistBomb)
                {
                    std::cout << "●";
                }
                else
                {
                    int AdjacentBombs = getAdjacentBombsCount(x, y);
                    if (AdjacentBombs > 0)
                    {
                        char str[] = "0";
                        str[1] += AdjacentBombs;
                        std::cout << str;
                    }
                    else
                    {
                        std::cout << "・";
                    }
                }
            }
            std::cout << std::endl;
        }

        // Game Over. 
        if (true == isExplosion)
        {
            std::cout << "Game Over...";
            std::cout << "\a";
            _getch();
            break;
        }

        // Game Clear. 
        if (true == isClear)
        {
            std::cout << "Game Clear!";
            std::cout << "\a";
            _getch();
            break;
        }

        switch (_getch())
        {
        case 'w':
            --cursorY;
            break;
        case 's':
            ++cursorY;
            break;
        case 'a':
            --cursorX;
            break;
        case 'd':
            ++cursorX;
            break;
        /* DEBUG
        case 'b':
            cells[cursorX][cursorY].isExistBomb = !cells[cursorX][cursorY].isExistBomb;
            break;
        case 'm':
            cells[cursorX][cursorY].isHiddenByMine = !cells[cursorX][cursorY].isHiddenByMine;
            break;
        */
        case 'f':
            cells[cursorX][cursorY].isOnFlag = !cells[cursorX][cursorY].isOnFlag;
            break;
        default:
            // disable to remove mine. 
            if (true == cells[cursorX][cursorY].isOnFlag)
            {
                break;
            }
            cells[cursorX][cursorY].isHiddenByMine = false;

            // Judge Game Over. 
            if (true == cells[cursorX][cursorY].isExistBomb)
            {
                isExplosion = true;
                for (int y = 0; y < FIELD_HEIGHT; ++y)
                {
                    for (int x = 0; x < FIELD_WIDTH; ++x)
                    {
                        cells[x][y].isHiddenByMine = false;
                        cells[x][y].isOnFlag = false;
                    }
                }
                break;
            }

            // Judge Game Clear. 
            {
                isClear = true;
                for (int y = 0; y < FIELD_HEIGHT; ++y)
                {
                    for (int x = 0; x < FIELD_WIDTH; ++x)
                    {
                        if ((false == cells[x][y].isExistBomb) && (true == cells[x][y].isHiddenByMine))
                        {
                            isClear = false;
                        }
                    }
                }
            }

            // Remove Adjacent Mines Automatically. 
            for (int y = -1; y <= 1; ++y)
            {
                for (int x = -1; x <= 1; ++x)
                {
                    if ((0 == x) && (0 == y))
                    {
                        continue;
                    }

                    autoRemoveMines(cursorX + x, cursorY + y);
                }
            }
            break;
        }
    }
    return 0;
}

int getAdjacentBombsCount(int argX, int argY)
{
    int count = 0;

    for (int y = -1; y <= 1; ++y)
    {
        for (int x = -1; x <= 1; ++x)
        {
            if ((0 == x) && (0 == y))
            {
                continue;
            }
            if ((argX + x < 0) || (argX + x >= FIELD_WIDTH) || (argY + y < 0) || (argY + y >= FIELD_HEIGHT))
            {
                continue;
            }
            if (true == cells[argX + x][argY + y].isExistBomb)
            {
                ++count;
            }
        }
    }
    return count;
}

void autoRemoveMines(int argX, int argY)
{
    if ((true == cells[argX][argY].isExistBomb) 
        || (false == cells[argX][argY].isHiddenByMine)
        || (argX < 0) || (argX >= FIELD_WIDTH) || (argY < 0) || (argY >= FIELD_HEIGHT)
        || (getAdjacentBombsCount(argX, argY) > 0))
    {
        return;
    }

    cells[argX][argY].isHiddenByMine = false;

    for (int y = -1; y <= 1; ++y)
    {
        for (int x = -1; x <= 1; ++x)
        {
            if ((0 == x) && (0 == y))
            {
                continue;
            }
            autoRemoveMines(argX + x, argY + y);
        }
    }
}
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?