LoginSignup
0
0

More than 3 years have passed since last update.

5目並べを作成しました

Last updated at Posted at 2020-05-16

C++で簡単な五目並べをプログラムを作成してみました。

C++初心者です。C++で何かプログラムを作りたかったので、五目並べを作ってみました。
至らぬ点ばかりだとは思いますが、何卒ご容赦お願いします。
以下がソースコードです。
あくまで大まかな流れをとりあえず作りたかったので、入力チェックなどはまだ不十分です。今後改善予定です。

main.cpp
#include <iostream>
#include <string>

#include "Board.h"
#include "CommonData.h"
int main(void)
{
    Board board;
    CommonData::PlayerKind nowPlayer = CommonData::PlayerKind::Black;

    while (true)
    {
        bool isPutSucceed = false;
        std::string dispStr;

        while (!isPutSucceed)
        {
            // 盤面の描画
            board.Draw();

            // 勝敗判定
            CommonData::PlayerKind winPlayer = board.Judge();
            if (winPlayer != CommonData::PlayerKind::None)
            {
                if (winPlayer == CommonData::PlayerKind::Black) {
                    dispStr = "黒";
                }
                else {
                    dispStr = "白";
                }

                // ゲーム終了
                std::cout << dispStr << "の勝ち!やったね!!!";
                std::rewind(stdin);
                std::getchar();
                return 0;
            }

            if (nowPlayer == CommonData::PlayerKind::Black) {
                dispStr = "黒";
            }
            else {
                dispStr = "白";
            }

            // 置く石の位置の入力
            std::cout << dispStr << "の手番です。横・縦の順に入力してください。" << std::endl;
            int x, y;
            std::cout << "横:";
            std::cin >> x;
            std::cout << "縦:";
            std::cin >> y;

            isPutSucceed = board.PutStone(nowPlayer, x, y);
            if(!isPutSucceed)
            {
                std::cout << "正しい場所に置いてください!" << std::endl;
                std::rewind(stdin);
                std::getchar();
                std::system("cls");
            }
        }

        // 番の変更
        if (nowPlayer == CommonData::PlayerKind::Black) {
            nowPlayer = CommonData::PlayerKind::White;
        }else {
            nowPlayer = CommonData::PlayerKind::Black;
        }
        std::system("cls");
    }
    return 0;
}
Board.h
#pragma once
#include <array>

#include "CommonData.h"

class Board
{
    enum JudegeKind
    {
        Tete,
        Yoko,
        Naname1,
        Naname2,
    };

public:
    Board();
    ~Board();

    void Draw(void);

    bool PutStone(CommonData::PlayerKind player, int x, int y);
    CommonData::PlayerKind Judge(void);

private:
    std::array<std::array<CommonData::PlayerKind, CommonData::BoardSizeY>, CommonData::BoardSizeX> m_boardData;

    CommonData::PlayerKind JudgeBaseStone(JudegeKind judgeKind, int x, int y);

    bool IsRangeOk(int x, int y);
    bool IsPutOk(int x, int y);

};
Board.cpp
#include <string>
#include <iostream>

#include "Board.h"


namespace
{
    const char* NumberStr[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9" };
}


Board::Board()
{
    // 配列の初期化
    for (int y = 0; y < CommonData::BoardSizeY; y++)
    {
        for (int x = 0; x < CommonData::BoardSizeX; x++)
        {
            m_boardData[y][x] = CommonData::PlayerKind::None;
        }
    }
}

Board::~Board()
{
}


// 盤の描画
void Board::Draw()
{
    // 一番上
    std::string drawStr = " ";
    for (int i = 0; i < CommonData::BoardSizeX; i++)
    {
        drawStr = drawStr + NumberStr[i];
    }
    std::cout << drawStr << std::endl;

    for (int y = 0; y < CommonData::BoardSizeY; y++)
    {
        drawStr = NumberStr[y];
        for (int x = 0; x < CommonData::BoardSizeX; x++)
        {
            switch (m_boardData[y][x])
            {
            case CommonData::PlayerKind::None:
                drawStr = drawStr + "・";
                break;

            case CommonData::PlayerKind::White:
                drawStr = drawStr + "●";
                break;

            case CommonData::PlayerKind::Black:
                drawStr = drawStr + "○";
                break;
            }
        }
        std::cout << drawStr << std::endl;
    }

}


// 石を置く
bool Board::PutStone(CommonData::PlayerKind player, int x, int y)
{
    if (IsPutOk(x, y))
    {
        m_boardData[y - 1][x - 1] = player;
        return true;
    }
    else {
        return false;
    }
}



// 勝敗の判定
CommonData::PlayerKind Board::Judge(void)
{
    // すべてのマスごとに、5つ並んでいるか判定を行う
    for (int y = 0; y < CommonData::BoardSizeY; y++)
    {
        for (int x = 0; x < CommonData::BoardSizeX; x++)
        {
            CommonData::PlayerKind playerResult;

            // 縦の判定
            playerResult = JudgeBaseStone(JudegeKind::Tete, x, y);
            if (playerResult != CommonData::PlayerKind::None) {
                return playerResult;
            }

            // 横の判定
            playerResult = JudgeBaseStone(JudegeKind::Yoko, x, y);
            if (playerResult != CommonData::PlayerKind::None) {
                return playerResult;
            }

            // 斜めの判定(左上→右下)
            playerResult = JudgeBaseStone(JudegeKind::Naname1, x, y);
            if (playerResult != CommonData::PlayerKind::None) {
                return playerResult;
            }

            // 斜めの判定(右上→左下)
            playerResult = JudgeBaseStone(JudegeKind::Naname2, x, y);
            if (playerResult != CommonData::PlayerKind::None) {
                return playerResult;
            }
        }
    }

    return CommonData::PlayerKind::None;
}

// 基点となる石から5つならんでいるか判定する
CommonData::PlayerKind Board::JudgeBaseStone(JudegeKind judgeKind, int x, int y)
{
    CommonData::PlayerKind basePlayerKind;

    // 5回ループ
    for (int i = 0; i < 5; i++)
    {
        // 基点の色を保存しておく
        if (i == 0) {
            basePlayerKind = m_boardData[y][x];
        }

        int searchX;
        int searchY;
        switch (judgeKind)
        {
        case JudegeKind::Tete:
            searchX = x;
            searchY = y + i;
            break;

        case JudegeKind::Yoko:
            searchX = x + i;
            searchY = y;
            break;

        case JudegeKind::Naname1:
            searchX = x + i;
            searchY = y + i;
            break;

        case JudegeKind::Naname2:
            searchX = x - i;
            searchY = y + i;
            break;
        }


        if (IsRangeOk(searchX, searchY))
        {
            if (m_boardData[searchY][searchX] != basePlayerKind)
            {
                // 5つ並んでいない
                return CommonData::PlayerKind::None;
            }
        }
        else
        {
            // 範囲外のときはNG
            return CommonData::PlayerKind::None;
        }
    }

    // 5つならんだ駒を返す
    return basePlayerKind;
}



// 盤の範囲内か判定を行う
bool Board::IsRangeOk(int x, int y)
{
    if (x >= 0 && x < CommonData::BoardSizeX &&
        y >= 0 && y < CommonData::BoardSizeX)
    {
        return true;
    }
    return false;
}

// 盤に駒が置けるかの判定を行う
bool Board::IsPutOk(int x, int y)
{
    if (!IsRangeOk(x-1, y-1)) {
        return false;
    }

    if (m_boardData[y-1][x-1] != CommonData::PlayerKind::None) {
        return false;
    }

    return true;
}
CommonData.h
#pragma once

namespace CommonData
{
    const int BoardSizeX = 9;
    const int BoardSizeY = 9;

    enum PlayerKind
    {
        None,
        White,
        Black,
    };
}

実際の画面

新しいビットマップ イメージ.jpg
上記のような画面が表示されます
○ … 黒
● … 白 です(コンソールだと色が反転するので…)
横・縦の順に入力します。
縦・横・斜めのどれかに5つ揃えると、終わりです。

それだけです。

開発環境

  • Visual Studio 2017
  • Windows 7

意識したポイント

  • なるべくマジックナンバーを使わない。
    • 描画する"○""●"やJudgeBaseStone関数のfor文の中の5(5個分石が並んでいるか判定の意味)などは、多分変更が無いのと、1箇所だけなので、とりあえず直接書いています。
  • なるべくC++っぽく書く。
    • 配列などは、 std::array を使うことにした。(std::vectorとどちらを使うか悩んだが、可変長である必要がないのでarrayにしました)
    • #defineは使用せず、constやenumを使用する

今後改善したい点

  • 5個並べる判定の部分は現在かなりゴミ宜しくないので、アルゴリズム改善したい。
  • Player vs Player しかできない為、Comとの対戦できるようにしたい。
0
0
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
0
0