翁恺老师的细胞自动机

大家可能看完翁恺老师的课程会对于细胞自动机想要真正的源代码,现在就展示各个类的源代码。

cellmachine/CellMachine.java

package cellmachine;

import javax.swing.JFrame;

import cell.Cell;
import field.View;
import field.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.2 ) {
					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[] neighbour = field.getNeighbour(row, col);
					int numOfLive = 0;
					for( Cell c : neighbour ) {
						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.print("UPDATE");
			frame.repaint();
			try {
				Thread.sleep(200);
			}catch( InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

cell/Cell.java

package cell;

import java.awt.Graphics;

public class Cell {
	private boolean alive = false;
	
	public void die() { alive = false; }
	public void reborn() { alive = true; }
	public boolean isAlive() { return alive; }

	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);
		}
	}

}

field/View.java

package field;

import java.awt.Dimension;

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);
	}
	
	public static void main(String[] args) {
		Field field = new Field(10,10);
		for( int row = 0; row<field.getHeight(); row++ ) {
			for( int col = 0; col<field.getWidth(); col++ ) {
				field.place(row, col, new Cell());
			}
		}
		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);
	}

}

field/Field.java

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 getHeight() { return height; }
	
	public int getWidth() { return width; }
	
	public Cell place(int row, int col, Cell o) {
		Cell ret = field[row][col];
		field[row][col] = o;
		return ret;
	}

	public Cell[] getNeighbour(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()]);
	}

	public Cell get(int row, int col) {
		return field[row][col];
	}

	public void clear() {
		for( int i = 0; i<height; i++ ) {
			for( int j = 0; j<width; j++ ) {
				field[i][j] = null;
			}
		}
	}

}

老师在最后还说到了几个点:
数据与表现分离
程序业务逻辑与表现无关
表现可以是图形的也可以是文本的
表现可以是当地的也可以是远程的

View和Field的关系
表现与数据的关系
View只管根据Field画出图形
Field只管数据的存放
一旦数据更新以后,通知View重新画出整个画面
不去精心设计哪个局部需要更新
这样简化了程序逻辑
是在计算机运算速度提高的基础上实现的

责任驱动的设计
将程序要实现的功能分配到合适的类/对象中去是设计中非常重要的一环

网格化
图形界面本身有更多的解析度
但是将画面格式化以后,数据就更容易处理了

同时,也提出了几个问题:
问题0
为什么不是在Cell中提供setAlive(boolean)函数?
卫视采用复杂的die()、reborn()两个函数?

问题1
为什么Field.getNeighbour()不直接看Cell。isAlive来返回一个数字,而是要返回一个数组让外面来数数?

问题2
为什么不是由Cell自己判断自己的邻居的情况来决定自己是否应该被die或reborn?

本人现在还是没有弄清这几个问题的解,还希望各位知道的小伙伴们能够在评论区中指点迷津。

  • 16
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值