康威生命游戏
简介
约翰·康威全名John Horton Conway,1937年12月26日出生于英国利物浦。他少时便对数学感兴趣,后来进入剑桥大学攻读数学专业,终于如愿以偿成了数学家。他活跃于有限群的研究、趣味数学、纽结理论、数论、组合博弈论和编码学等范畴。
约翰·康威最常被专业人士和大众拿来讨论的成果,就是他在1970年发明的生命游戏,Game of Life。它的意义在于验证了某些科学家的宇宙观,即最简单的逻辑规则能产生出复杂有趣的活动。
康威生命游戏是一个类似于模拟细胞存活的小游戏,规则虽然很简单,但它的魅力在于,不同的初始分布,最终会演化出许多有意思和意想不到的图案,其内涵无比的丰富。
规则
康威生命游戏在方格网上进行,有点像围棋。有填充的网格代表有生命,或理解成一个细胞。游戏规则只有四条:
- 当周围仅有1个或没有存活细胞时,原来的存活细胞进入死亡状态。(模拟生命数量稀少)
- 当周围有2个或3个存活细胞时, 网格保持原样。
- 当周围有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();
}