Skip to content

ライフゲーム

Reputeless edited this page Apr 30, 2017 · 4 revisions
ライフゲーム
# include <Siv3D.hpp>

template <class Type>
class CellularAutomaton
{
public:

    using type = Type;

    // 近傍と自身の情報
    struct Neighbors
    {
        Type tl, t, tr, l, c, r, bl, b, br;
    };

    // 自身と近傍の値から、次の世代の値を決める関数
    using RuleFuncType = std::function<Type(const Neighbors&)>;

    // セルの値を色に変換する関数
    using ColorFuncType = std::function<Color(const Type&)>;

    // width:   セルの個数(横)
    // height:  セルの個数(縦)
    // cellsize:    セルの大きさ(ピクセル)
    // rule:    セルの更新のルール
    // colorRule: 色の表現のルール
    CellularAutomaton(
        int32 width,
        int32 height,
        RuleFuncType rule,
        ColorFuncType colorRule
        )
        : m_image(width, height, Palette::Black)
        , m_texture(m_image)
        , m_data((width + 2)*(height + 2))
        , m_tmpData((width + 2)*(height + 2))
        , m_width(width)
        , m_height(height)
        , m_ruleFunction(rule)
        , m_colorFunction(colorRule) {}

    int32 width() const
    {
        return m_width;
    }

    int32 height() const
    {
        return m_height;
    }

    Type getPixel(int32 y, int32 x) const
    {
        return m_data[getStride()*(y + 1) + (x + 1)];
    }

    void setPixel(int32 y, int32 x, Type value)
    {
        m_data[getStride()*(y + 1) + (x + 1)] = value;
    }

    void setRule(RuleFuncType rule)
    {
        m_ruleFunction = rule;
    }

    void setColorRule(ColorFuncType rule)
    {
        m_colorFunction = rule;
    }

    void update()
    {
        // すべてのセルを更新
        for (auto y : step(m_height))
        {
            for (auto x : step(m_width))
            {
                Neighbors n;
                n.tl = getPixel(y - 1, x - 1);
                n.t = getPixel(y - 1, x);
                n.tr = getPixel(y - 1, x + 1);
                n.l = getPixel(y, x - 1);
                n.c = getPixel(y, x);
                n.r = getPixel(y, x + 1);
                n.bl = getPixel(y + 1, x - 1);
                n.b = getPixel(y + 1, x);
                n.br = getPixel(y + 1, x + 1);

                setPixelTemp(y, x, m_ruleFunction(n));
            }
        }

        m_data = m_tmpData;

        // Image を更新
        for (auto y : step(m_height))
        {
            for (auto x : step(m_width))
            {
                m_image[y][x] = m_colorFunction(getPixel(y, x));
            }
        }

        // 動的テクスチャをイメージで更新
        m_texture.fill(m_image);
    }

    const Texture& getTexture()
    {
        return m_texture;
    }

private:

    Image m_image;

    DynamicTexture m_texture;

    Array<Type> m_data, m_tmpData;

    int32 m_width, m_height;

    RuleFuncType m_ruleFunction;

    ColorFuncType m_colorFunction;

    int32 getStride() const
    {
        return m_width + 2;
    }

    void setPixelTemp(int32 y, int32 x, Type value)
    {
        m_tmpData[getStride()*(y + 1) + (x + 1)] = value;
    }
};

using Simulation = CellularAutomaton<int>;

// セルの状態をランダムに 0 か 1 にする
void Reset(Simulation& simulation)
{
    for (auto y : step(simulation.height()))
    {
        for (auto x : step(simulation.width()))
        {
            simulation.setPixel(y, x, Random(1));
        }
    }
}

void Main()
{
    //
    // 誕生: 死んでいるセル (0) の周囲に 3 つの生きているセル (1) があれば次の時間ステップでは生きる (1 になる)。
    // 維持: 生きているセル (1) の周囲に 2 つか 3 つの生きているセル (1) があれば次の世代でも生き残る (1 のままである)。
    // 死亡: 上以外の場合には次の世代では死ぬ (「0」になる)。
    // http://ja.wikipedia.org/wiki/セル・オートマトン より
    //
    const auto Rule = [](const Simulation::Neighbors& n)
    {
        const int32 sum = n.tl + n.t + n.tr + n.l + n.r + n.bl + n.b + n.br;

        if (n.c == 0 && sum == 3)
        {
            return 1;
        }
        else if (n.c == 1 && (sum == 2 || sum == 3))
        {
            return 1;
        }

        return 0;
    };

    // 1 なら緑、0 なら黒
    const auto ColorRule = [](Simulation::type v)
    {
        return v ? Palette::Lime : Palette::Black;
    };

    Simulation simulation{ 160, 120, Rule, ColorRule };

    Reset(simulation);

    Graphics2D::SetSamplerState(SamplerState::ClampPoint);

    while (System::Update())
    {
        if (Input::MouseL.clicked)
        {
            Reset(simulation);
        }

        if (System::FrameCount() % 5 == 0)
        {
            simulation.update();
        }

        simulation.getTexture().scale(4.0).draw();
    }
}

14行でライフゲーム

# include <Siv3D.hpp>

void Main()
{
    Graphics2D::SetSamplerState(SamplerState::ClampPoint);
    Image img(128, 96, [](auto) { return Color(Random(1), 0, 0); });
    DynamicTexture tex;

    while (System::Update())
    {
        for (auto b : step(img.size))
        {
            int32 s = 0;
            for (auto d : step({ -1, -1 }, { 3, 3 }))
                s += img.getPixel<ImageAddressMode::Wrap>(b + d).r;

            img[b].b = (s == 3) || (img[b].r && s == 4);
        }

        tex.fill(img.forEach([](Color& p) { p.g = (p.r = p.b) ? 255 : 0; }));

        tex.scale(5).draw();

        System::Sleep(0.1s);
    }
}

Siv3D について

  1. Siv3D の基本
  2. 図形を描く
  3. テクスチャを描く
  4. テキストを描く
  5. 文字列と数値の変換
  6. キーボード入力
  7. マウス入力
  8. サウンドの再生
  9. MIDI の再生
  10. ウィンドウと背景
  11. 図形のあたり判定
  12. 乱数
  13. ダイアログ
  14. ドラッグ & ドロップ
  15. アプリの状態
  16. テキストファイル
  17. INI, CSV, JSON
  18. バイナリファイル
  19. GUI
  20. アセット管理
  21. 画像編集
  22. Web カメラ
  23. マイク入力
  24. 経過時間の測定
  25. HSV カラー
  26. ファイルダウンロード
  27. 3D 描画
  28. 2D のレンダーステート
  29. 3D のレンダーステート
  30. パーティクル
  31. スクリーンショット
  32. アプリケーションの公開
  33. さらに学ぶには

表現テクニック集

入出力デバイス

開発のヒント

Clone this wiki locally