康威生命游戏

简介

约翰·康威全名John Horton Conway,1937年12月26日出生于英国利物浦。他少时便对数学感兴趣,后来进入剑桥大学攻读数学专业,终于如愿以偿成了数学家。他活跃于有限群的研究、趣味数学、纽结理论、数论、组合博弈论和编码学等范畴。

约翰·康威最常被专业人士和大众拿来讨论的成果,就是他在1970年发明的生命游戏,Game of Life。它的意义在于验证了某些科学家的宇宙观,即最简单的逻辑规则能产生出复杂有趣的活动。

康威生命游戏是一个类似于模拟细胞存活的小游戏,规则虽然很简单,但它的魅力在于,不同的初始分布,最终会演化出许多有意思和意想不到的图案,其内涵无比的丰富。

规则

康威生命游戏在方格网上进行,有点像围棋。有填充的网格代表有生命,或理解成一个细胞。游戏规则只有四条:

  1. 当周围仅有1个或没有存活细胞时,原来的存活细胞进入死亡状态。(模拟生命数量稀少)
  2. 当周围有2个或3个存活细胞时, 网格保持原样。
  3. 当周围有4个及以上存活细胞时,原来的存活细胞亦进入死亡状态。(模拟生命数量过多)
  4. 当周围有3个存活细胞时,空白网格变成存活细胞。(模拟繁殖)

康威生命游戏的四条规则一目了然地对应着宇宙中的生命规律,它是一种元胞自动机(cellular automaton),体现了冯·诺依曼(Von Neumann)关于机器自我进化的思想。

实现

本人基于QT的一个实现,项目地址如下:

https://gitee.com/HuangLiDi/live-game.git

其核心代码非常简单,请参考最后的附录

参考文章

其有趣玩法和规则可以参考以下这两篇文章:

https://zhuanlan.zhihu.com/p/144162012
https://zhuanlan.zhihu.com/p/45026142

附录:核心代码

class CellsItem : public QGraphicsItem
{
public:
    CellsItem();
    explicit CellsItem(QRectF rect);
    void SetRect(QRectF rect);
    void SetBrush(const QColor & color);
    void SetPen(const QPen & pen);
    bool IsLive();
    void setLive(bool live);
    void setNextLiveState(bool live);
    void Evolution();
protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;

private:
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual QRectF boundingRect() const override;

    QColor m_color;
    QPen   m_pen;
    QRectF m_rect;
    bool m_blLive = false;
    bool m_bl_next = false;
};


class LivePlay
{
public:
    static void play(int num, CellsItem *** cell_arry);
private:
    static bool ruleCheck(int row, int column,int limit, CellsItem *** cell_arry);
};

CellsItem::CellsItem()
{
    m_rect = QRectF(0,0,0,0);
    m_color = Qt::white;
    m_pen.setStyle(Qt::SolidLine);
    m_pen.setWidth(1);
    m_pen.setColor(Qt::lightGray);

    setFlags(ItemIsSelectable);
    setAcceptHoverEvents(true);
}

CellsItem::CellsItem(QRectF rect)
{
   m_rect = rect;

   m_color = Qt::black;
   m_pen.setStyle(Qt::SolidLine);
   m_pen.setWidth(1);
   m_pen.setColor(Qt::lightGray);

   setFlags(ItemIsSelectable);
   setAcceptHoverEvents(true);
}

void CellsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mousePressEvent(event);
    m_blLive = !m_blLive;
    update();
}

void CellsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseReleaseEvent(event);
    update();
}


void CellsItem::SetRect(QRectF rect)
{
   m_rect = rect;
}

void CellsItem::SetBrush(const QColor & color)
{
    m_color = color;
}

void CellsItem::SetPen(const QPen & pen)
{
    m_pen = pen;
}

bool CellsItem::IsLive()
{
    return m_blLive;
}

void CellsItem::setLive(bool live)
{
    m_blLive = live;
}

void CellsItem::setNextLiveState(bool live)
{
    m_bl_next = live;
}

void CellsItem::Evolution()
{
    if(m_blLive != m_bl_next)
    {
        m_blLive = m_bl_next;
        update();
    }
}

QRectF CellsItem::boundingRect() const
{
    return m_rect;
}


void CellsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(widget);

#if 0
    QColor fillColor = (option->state & QStyle::State_Selected) ?  m_color : Qt::white;
#else
    QColor fillColor = m_blLive ?  m_color : Qt::white;
#endif

//    if (option->state & QStyle::State_MouseOver)
//        fillColor = fillColor.light(125);

    painter->setPen(m_pen);
    painter->fillRect(m_rect.adjusted(1,1,-1,-1), fillColor);
    painter->drawRect(m_rect);
}

void LivePlay::play(int num, CellsItem *** cell_arry)
{
    QList<QPair<int,int>> lst_play;

    //细胞状态检查, 当前状态不变
    for (int i = 0; i < num; i++){
        for (int j = 0; j < num; j++){
           bool ret = ruleCheck(i, j, num, cell_arry);
           if (ret != cell_arry[i][j]->IsLive()){
               cell_arry[i][j]->setNextLiveState(ret);
               lst_play.append(qMakePair(i,j));
           }
        }
    }

    //进入细胞的下一个状态
    for(const QPair<int,int> & pair: lst_play)
    {
        cell_arry[pair.first][pair.second]->Evolution();
    }
}

bool LivePlay::ruleCheck(int row, int column, int limit, CellsItem *** cell_arry)
{
    if(nullptr == cell_arry[row][column]){
        return false;
    }

    CellsItem * p_Item = cell_arry[row][column];

    int count = 0;
    //检测周围一圈的细胞存活个数
    for (int i = -1; i <= 1; i++){
        for (int j = -1; j <= 1; j++) {
            if (i == 0 && j == 0){
                continue;
            }
            int r = row+i;
            int l = column+j;
            if (r >= 0 && r < limit
                    && l >= 0 && l < limit){
                if (cell_arry[r][l] && cell_arry[r][l]->IsLive())
                    count++;
            }
        }
    }


    if(p_Item->IsLive()){
        //规则:孤独会致命,拥挤也一样
        if (count <= 1 || count >= 4){
            return false;
        }
    }
    else {
        //规则2:三人行,繁殖的最佳环境
        if (count == 3){
            return true;
        }
    }

    return p_Item->IsLive();
}

posted @ 2024-04-12 15:32  HL棣  阅读(112)  评论(0编辑  收藏  举报