一点关于细胞自动机的见解
个人非常喜欢翁恺老师的网课。在学习细胞自动机之后产生了一点自己的想法。在这里写出来,本人现在的水平尚且达不到Java入门,一点愚昧见解还请大佬们海涵。
贴上源码
感谢@一条sin大佬贴出来的代码,原文链接https://blog.csdn.net/weixin_42546792/article/details/101168863
小弟在这里CTRL C+V一下。
package cellmachine;
import javax.swing.JFrame;
import cell.Cell;
import field.*;
public class CellMachine {
public static void main(String[] args) {
Field field=new Field(30,30);
for(int row=0;row<field.getHeight();row++) {
for(int col=0;col<field.getWidth();col++) {
field.place(row, col, new Cell());
}
}
for(int row=0;row<field.getHeight();row++) {
for(int col=0;col<field.getWidth();col++) {
Cell cell=field.get(row, col);
if(Math.random()<0.5) {
cell.reborn();
}
}
}
View view =new View(field);
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setTitle("Cells");
frame.add(view);
frame.pack();
frame.setVisible(true);
for(int i=0;i<1000;i++) {
for(int row=0;row<field.getHeight();row++) {
for(int col=0;col<field.getWidth();col++) {
Cell cell=field.get(row, col);
Cell[] neighbor=field.getNeighbor(row, col);
int numOfLive=0;
for(Cell c:neighbor) {
if(c.isAlive()) {
numOfLive++;
}
}
System.out.print("["+row+"]["+col+"]:");
System.out.print(cell.isAlive()?"live":"dead");
System.out.print(":"+numOfLive+"-->");
if(cell.isAlive()) {
if(numOfLive<2||numOfLive>3) {
cell.die();
System.out.print("die");
}
}else if(numOfLive==3) {
cell.reborn();
System.out.print("reborn");
}
System.out.println();
}
}
System.out.println("UPDATE");
frame.repaint();
try {
Thread.sleep(200);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
————————————————
版权声明:本文为CSDN博主「一条sin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42546792/article/details/101168863
package field;
import java.util.ArrayList;
import cell.Cell;
public class Field {
private int width;
private int height;
private Cell[][] field;
public Field (int width,int height) {
this.width=width;
this.height=height;
field=new Cell[height][width];
}
public int getWidth() {return width;}
public int getHeight() {return height;}
public Cell place(int row,int col,Cell o){
Cell ret=field[row][col];
field[row][col]=o;
return ret;
}
public Cell get(int row,int col) {
return field[row][col];
}
public Cell[] getNeighbor(int row,int col) {
ArrayList<Cell> list= new ArrayList<Cell>();
for(int i=-1;i<2;i++){
for(int j=-1;j<2;j++){
int r=row+i;
int c=col+j;
if ( r >-1 && r<height && c>-1 && c<width && !(r== row && c == col) ) {
list.add(field[r][c]);
}
}
}
return list.toArray(new Cell[list.size()]);
}
}
————————————————
版权声明:本文为CSDN博主「一条sin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42546792/article/details/101168863
package field;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
import cell.Cell;
public class View extends JPanel {
private static final long serialVersionUID=-5258995676212660595L;
private static final int GRID_SIZE=16;
private Field theField;
public View(Field field) {
theField=field;
}
@Override
public void paint(Graphics g) {
super.paint(g);
for(int row=0;row<theField.getHeight();row++) {
for(int col=0;col<theField.getWidth();col++) {
Cell cell=theField.get(row, col);
if(cell!=null) {
cell.draw(g, col*GRID_SIZE, row*GRID_SIZE, GRID_SIZE);
}
}
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(theField.getWidth()*GRID_SIZE+1,theField.getHeight()*GRID_SIZE+1);
}
}
————————————————
版权声明:本文为CSDN博主「一条sin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42546792/article/details/101168863
package cell;
import java.awt.*;
public class Cell {
private boolean alive=false;
public void reborn() {alive=true;}
public boolean isAlive() {
return alive;
}
public void die() {alive=false;}
public void draw(Graphics g,int x,int y,int size) {
g.drawRect(x, y, size, size);
if(alive) {
g.fillRect(x, y, size, size);
}
}
}
————————————————
版权声明:本文为CSDN博主「一条sin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42546792/article/details/101168863
我的思考
在源码中,首先生成网格以及初代细胞。在后续的更迭中,每次判断都是从 row=0 到 height-1;从col=0到 width-1。那我的理解就是如此行列递增的产生先后顺序对后面的细胞不公平。举个简单的例子:如下图所示:
假如循环是自左向右,自上向下扫描每一个细胞。我选取了一个孤立细胞团,就是除了这三个黑的,周围全都是白的。
对于上1(上面那排第一个,下同),周围俩活得,所以状态不变。
那么对于上2由于周围邻居达到三个,所以会重生,即在下一轮绘图时,格子会变成黑色。
但是!但是!但是!重点来了,在判断完上2之后,上3在扫描邻居状态的时候会判断定出邻居中有三个活着的细胞,那么复活,但是实际上目前他们呢周围只有中2和中3是活着的,不满足复活条件,按理说在一下轮应该状态不变。可是由于先判断了上2,上2 的状态变成了alive,所以他们靠着目前版图上还不存在上2获得了重生。
那么同理,中1判断周围俩(上2和中2)活得,那我也不死了。
中二,我周边四个活得(上2,上3,中1和中3),那我死了。
。。。。。。。。。
但是实际上呢,不应该仅仅是中2和下2重生,中1和中3死亡吗???
由于先判断了上面一排,改变了他们细胞的状态,就造成了下面两排的细胞不按剧本走。实际上这个状态是该细胞未来(下一轮)才会出现的结果。但是在代码里,判断的依据仅仅是isAlive。我个人觉得对后面的细胞不公平。判断不合理。
小小的修改
在实现业务逻辑的代码里,
for(Cell c:neighbor) {
if(c.isFill()) {
numOfLive++;//周围共计多少活细胞
}
}
邻居的数量不依赖isAlive,我用图片中是否被填充颜色判断,周围有几个填充色,就是几个活着的细胞。
在cell的代码中,
private boolean fullfill=false;
public boolean isFill() {
return fullfill;
}
public void draw(Graphics g,int x,int y,int size) {
g.drawRect(x, y, size, size);
if(alive) {
g.fillRect(x, y, size, size);
this.fullfill = true;
}
else
this.fullfill = false;
}
引入 isFill,来判断目前的窗口里的格子状态。
每一轮frame.repaint之后,更新每个cell的填充状态,以此来判断下一轮的生或死。
同样,主函数中的判断条件也要改变。
if(cell.isFill()) {
if(numOfLive<2||numOfLive>3) {
cell.die();
System.out.print("die");
}
}
else if(numOfLive==3) {
cell.reborn();
System.out.print("reborn");
}
就写这些吧,其实挺无聊的,就是脑子一抽,突然这么想了。改了几行代码而已。见笑了。
日敲代码三千行,不辞长作死肥宅。