add history folder

pull/1/head
drinkjava2 5 years ago
parent e26ce04039
commit ce65e3da5f

@ -91,7 +91,9 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
![result6](https://gitee.com/drinkjava2/frog/raw/master/result6_letter.gif)
2019-11-26 优化了一下程序用8个汉字来进行模式识别原理演示但容错性依然没有变形、变位后的文字识别率很差。以后要考虑借签算法中的侧抑制、卷积、分层等原理来提高它的容错性这方面算法已经很成熟了目前只需要拿来主义用图形化模拟的方式来实现。但总体上算法和图形化模拟是两条路算法通常可以用模拟的方式来表达但不是所有模拟都可以归纳成算法因为模拟(或者说软件本身)有时会非常复杂,不容易总结出规律。也就是说模拟的表现力比算法更强,但模拟的缺点是资源消耗大。
注意如果想要运行这个项目的以前码云版本可以结合gitk命令和参考"版本提交记录.md"的介绍用git reset命令回复到以前任一个版本例如用:
## 运行方式 | Run
运行core或history各个子目录下的run.bat批处理文件即可启动运行history下有多个子目录按时间顺序按列存放着这个项目演化过程中的主要历史版本供演示。
另外如果想要研究这个项目的任一旧版本可以结合gitk命令和参考"版本提交记录.md"的介绍用git reset命令回复到以前任一个版本例如用:
git reset --hard ae34b07e 可以转回到以前一个分组测试的找食版本。
## 重要参数 | Parameters

@ -4,7 +4,7 @@
<groupId>com.gitee.drinkjava2</groupId>
<artifactId>frog</artifactId>
<packaging>jar</packaging>
<version>2.0.1</version>
<version>1.0</version>
<name>frog</name>
<description>An artificial life test project</description>
@ -99,4 +99,4 @@
<profiles>
</profiles>
</project>
</project>

@ -16,19 +16,36 @@ import com.github.drinkjava2.frog.brain.BrainPicture;
* @since 1.0
*/
public class Application {
/** SHOW first frog's brain structure */
public static boolean SHOW_FIRST_FROG_BRAIN = false;
public static final String CLASSPATH;
static {
String classpath = new File("").getAbsolutePath();
int core = classpath.indexOf("core");
CLASSPATH = classpath.substring(0, core);
int core = classpath.indexOf("\\frog\\");
if (core > 0)
CLASSPATH = classpath.substring(0, core) + "\\frog\\";
else
CLASSPATH = classpath.substring(0, core) + "/frog/"; // UNIX
}
public static JFrame mainFrame = new JFrame();
public static Env env = new Env();
public static BrainPicture brainPic = new BrainPicture(Env.ENV_WIDTH + 5, 0, Env.FROG_BRAIN_WIDTH,
public static BrainPicture brainPic = new BrainPicture(Env.ENV_WIDTH + 5, 0, Env.FROG_BRAIN_XSIZE,
Env.FROG_BRAIN_DISP_WIDTH);
public static ActionListener pauseAction;
static private void checkIfShowBrainPicture(JButton button) {
if (Env.SHOW_FIRST_FROG_BRAIN) {
button.setText("Hide brain");
int y = Env.ENV_HEIGHT + 100;
if (Env.FROG_BRAIN_DISP_WIDTH + 41 > y)
y = Env.FROG_BRAIN_DISP_WIDTH + 41;
mainFrame.setSize(Env.ENV_WIDTH + Env.FROG_BRAIN_DISP_WIDTH + 25, y);
brainPic.requestFocus();
} else {
button.setText("Show brain");
mainFrame.setSize(Env.ENV_WIDTH + 20, Env.ENV_HEIGHT + 100);
}
}
public static void main(String[] args) throws InterruptedException {
mainFrame.setLayout(null);
@ -38,33 +55,27 @@ public class Application {
mainFrame.add(brainPic);
JButton button = new JButton("Show first frog's brain");
int buttonWidth = 180;
JButton button = new JButton("Show brain");
int buttonWidth = 100;
int buttonHeight = 22;
int buttonXpos = Env.ENV_WIDTH / 2 - buttonWidth / 2;
button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight);
ActionListener al = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
SHOW_FIRST_FROG_BRAIN = !SHOW_FIRST_FROG_BRAIN;
if (SHOW_FIRST_FROG_BRAIN) {
button.setText("Hide first frog's brain");
int y = Env.ENV_HEIGHT + 100;
if (Env.FROG_BRAIN_DISP_WIDTH + 41 > y)
y = Env.FROG_BRAIN_DISP_WIDTH + 41;
mainFrame.setSize(Env.ENV_WIDTH + Env.FROG_BRAIN_DISP_WIDTH + 25, y);
} else {
button.setText("Show first frog's brain");
mainFrame.setSize(Env.ENV_WIDTH + 20, Env.ENV_HEIGHT + 100);
}
Env.SHOW_FIRST_FROG_BRAIN = !Env.SHOW_FIRST_FROG_BRAIN;
checkIfShowBrainPicture(button);
}
};
checkIfShowBrainPicture(button);
button.addActionListener(al);
mainFrame.add(button);
JButton stopButton = new JButton("Pause");
stopButton.setBounds(buttonXpos, Env.ENV_HEIGHT + 35, buttonWidth, buttonHeight);
ActionListener a2 = new ActionListener() {
pauseAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Env.pause = !Env.pause;
@ -72,10 +83,11 @@ public class Application {
stopButton.setText("Resume");
} else {
stopButton.setText("Pause");
brainPic.requestFocus();
}
}
};
stopButton.addActionListener(a2);
stopButton.addActionListener(pauseAction);
mainFrame.add(stopButton);
mainFrame.setVisible(true);

@ -9,13 +9,11 @@ import java.util.List;
import javax.swing.JPanel;
import com.github.drinkjava2.frog.brain.group.RandomConnectGroup;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.egg.EggTool;
import com.github.drinkjava2.frog.objects.Food;
import com.github.drinkjava2.frog.objects.LetterTester;
import com.github.drinkjava2.frog.objects.EnvObject;
import com.github.drinkjava2.frog.objects.Material;
import com.github.drinkjava2.frog.objects.Object;
import com.github.drinkjava2.frog.objects.SeeSaw;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -27,21 +25,29 @@ import com.github.drinkjava2.frog.util.RandomUtils;
@SuppressWarnings("all")
public class Env extends JPanel {
/** Speed of test */
public static final int SHOW_SPEED = 500; // 测试速度,-1000~1000,可调, 数值越小,速度越慢
public static final int SHOW_SPEED = 1; // 测试速度,-1000~1000,可调, 数值越小,速度越慢
/** Delete eggs at beginning of each run */
public static final boolean DELETE_EGGS = false;// 每次运行是否先删除保存的蛋
public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的蛋
public static final int EGG_QTY = 25; // 每轮下n个蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int EGG_QTY = 10; // 每轮下n个蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 4; // 每个蛋可以孵出几个青蛙
public static final int SCREEN = 100; // 分几屏测完
public static final int SCREEN = 1; // 分几屏测完
public static final int FROG_PER_SCREEN = EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙,这个数值由上面三个参数计算得来
/** Frog's brain size is a 3D array of Cell */ // 脑空间是个三维Cell数组为节约内存仅在用到数组元素时才去初始化这维按需分配内存
public static final int FROG_BRAIN_XSIZE = 30; // frog的脑在X方向长度
public static final int FROG_BRAIN_YSIZE = 20; // frog的脑在Y方向长度
public static final int FROG_BRAIN_ZSIZE = 20; // frog的脑在Z方向长度
/** SHOW first frog's brain structure */
public static boolean SHOW_FIRST_FROG_BRAIN = true; // 是否显示脑图在Env区的右侧
/** Draw first frog's brain after some steps */
public static int DRAW_BRAIN_AFTER_STEPS = 50; // 以此值为间隔动态画出脑图设为0则关闭这个动态脑图功能只显示一个静态、不闪烁的脑图
public static int DRAW_BRAIN_AFTER_STEPS = 1; // 以此值为间隔动态画出脑图设为0则关闭这个动态脑图功能只显示一个静态、不闪烁的脑图
/** Environment x width, unit: pixels */
public static final int ENV_WIDTH = 400; // 虚拟环境的宽度, 可调
@ -50,30 +56,31 @@ public class Env extends JPanel {
public static final int ENV_HEIGHT = ENV_WIDTH; // 虚拟环境高度, 可调,通常取正方形
/** Frog's brain display width on screen, not important */
public static final int FROG_BRAIN_DISP_WIDTH = 400; // Frog的脑图在屏幕上的显示大小,可调
public static final int FROG_BRAIN_DISP_WIDTH = 600; // Frog的脑图在屏幕上的显示大小,可调
/** Steps of one test round */
public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调
/** Frog's brain width, fixed to 1000 unit */
public static final float FROG_BRAIN_WIDTH = 1000; // frog的脑宽度固定为1000,不要随便调整,因为器官的相对位置和大小是按脑大小设定的
public static final int STEPS_PER_ROUND = LetterTester.STR.length() * 2 * LetterTester.TIME;// 每轮测试步数,可调
public static int step;// 当前测试步数
public static final int FOOD_QTY = 1500; // 食物数量, 可调
public static final int FOOD_QTY = 100; // 食物数量, 可调
// 以下是程序内部变量,不要手工修改它们
public static boolean pause = false; // 暂停按钮按下将暂停测试
public static byte[][] bricks = new byte[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,0=无, 1=食, 其它=其它...
public static byte[][] bricks = new byte[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,见Material.java
public static List<Frog> frogs = new ArrayList<>(); // 这里存放所有待测的青蛙可能分几次测完由FROG_PER_SCREEN大小来决定
public static List<Egg> eggs = new ArrayList<>(); // 这里存放从磁盘载入或上轮下的蛋每个蛋可能生成1~n个青蛙,
public static List<Egg> eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙,
public static Object[] things = new Object[] { new SeeSaw() };
public static EnvObject[] things = new EnvObject[] {};// 所有外界物体如食物、字母测试工具都放在这个things里面
static {
System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒见码云issue#IW4H8
System.out.println("脑图快捷键: T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移");
if (DELETE_EGGS)
EggTool.deleteEggs();
}
public Env() {
@ -148,7 +155,7 @@ public class Env extends JPanel {
int leftfood = 0;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++)
if (bricks[x][y] == 1)
if (bricks[x][y] == Material.FOOD)
leftfood++;
return FOOD_QTY - leftfood;
}
@ -163,7 +170,18 @@ public class Env extends JPanel {
.append(foodFound * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString();
}
private static void sleep(long millis) {
public static void checkIfPause(Frog f) {
if (pause)
do {
if (f != null) {
Application.brainPic.drawBrainPicture(f);
Application.brainPic.requestFocus();
}
sleep(100);
} while (pause);
}
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
@ -181,16 +199,18 @@ public class Env extends JPanel {
rebuildFrogs();
for (int screen = 0; screen < SCREEN; screen++) {// 分屏测试每屏FROG_PER_SCREEN个蛙
time0 = System.currentTimeMillis();
if (pause)
do {
sleep(300);
} while (pause);
for (Object thing : things) // 创建食物、陷阱等物体
for (EnvObject thing : things) // 创建食物、陷阱等物体
thing.build();
boolean allDead = false;
Frog firstFrog = frogs.get(screen * FROG_PER_SCREEN);
for (int i = 0; i < STEPS_PER_ROUND; i++) {
for (Object thing : things)// 调用食物、陷阱等物体的动作
checkIfPause(firstFrog);
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
f.initFrog(); // 初始化器官延迟到这一步,是因为脑细胞太占内存,而且当前屏测完后会清空
}
for (step = 0; step < STEPS_PER_ROUND; step++) {
for (EnvObject thing : things)// 调用食物、陷阱等物体的动作
thing.active(screen);
if (allDead)
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
@ -199,14 +219,9 @@ public class Env extends JPanel {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
if (f.active(this))
allDead = false;
if (f.alive && RandomUtils.percent(0.5f)) {// 有很小的机率在青蛙活着时就创建新的器官
RandomConnectGroup newConGrp = new RandomConnectGroup();
newConGrp.initFrog(f);
f.organs.add(newConGrp);
}
}
if (SHOW_SPEED > 0 && i % SHOW_SPEED != 0) // 用画青蛙的方式来拖慢速度
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用画青蛙的方式来拖慢速度
continue;
if (SHOW_SPEED < 0) // 如果speed小于0人为加入延迟
@ -223,23 +238,26 @@ public class Env extends JPanel {
}
if (firstFrog.alive) { // 开始显示第一个Frog的动态脑图
if (Application.SHOW_FIRST_FROG_BRAIN) {
if (SHOW_FIRST_FROG_BRAIN) {
g.setColor(Color.red);
g.drawArc(firstFrog.x - 15, firstFrog.y - 15, 30, 30, 0, 360);
g.setColor(Color.BLACK);
}
if (DRAW_BRAIN_AFTER_STEPS > 0 && i % DRAW_BRAIN_AFTER_STEPS == 0)
if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0)
Application.brainPic.drawBrainPicture(firstFrog);
}
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
}
Application.brainPic.drawBrainPicture(firstFrog);
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
f.cells = null; // 清空frog脑细胞所占用的内存
}
Application.mainFrame.setTitle(new StringBuilder("Round: ").append(round).append(", screen:")
.append(screen).append(", ").append(foodFoundCountText()).append(", 用时: ")
.append(System.currentTimeMillis() - time0).append("ms").append(", energy:")
.append(firstFrog.energy).toString());
for (Object thing : things)// 去除食物、陷阱等物体
.append(System.currentTimeMillis() - time0).append("ms").toString());
for (EnvObject thing : things)// 去除食物、陷阱等物体
thing.destory();
}
round++;

@ -19,29 +19,35 @@ import java.util.List;
import javax.imageio.ImageIO;
import com.github.drinkjava2.frog.brain.Cell;
import com.github.drinkjava2.frog.brain.CellActions;
import com.github.drinkjava2.frog.brain.Cuboid;
import com.github.drinkjava2.frog.brain.Hole;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.Photon;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.objects.Material;
/**
* Frog = organs + brain cells
* Frog = cells <br/>
* cells = actions + photons <br/>
*
* Group
* Frog's name is Sam.
*
* cellscell
*
* @author Yong Zhu
* @since 1.0
*/
public class Frog {
public class Frog {// 这个程序大量用到public变量而不是getter/setter主要是为了编程方便和简洁但缺点是编程者需要小心维护各个变量
/** brain cells */
public List<Cell> cells = new ArrayList<>();
public Cell[][][] cells;// 一开始不要初始化只在调用getOrCreateCell方法时才初始化相关维以节约内存
/** organs */
public List<Organ> organs = new ArrayList<>();
public int x; // frog在Env中的x坐标
public int y; // frog在Env中的y坐标
public long energy = 100000; // 青蛙的能量为0则死掉
public long energy = 10000000; // 青蛙的能量为0则死掉
public boolean alive = true; // 设为false表示青蛙死掉了将不参与计算和显示以节省时间
public int ateFood = 0;
@ -54,25 +60,73 @@ public class Frog {
}
}
public Frog(int x, int y, Egg egg) {
public Frog(int x, int y, Egg egg) {// x, y 是虑拟环境的坐标
this.x = x;
this.y = y;
for (Organ org : egg.organs) {
for (Organ org : egg.organs)
organs.add(org);
org.initFrog(this);// 每个新器官初始化如果是Group类它们会生成许多脑细胞
}
public void initFrog() {// 仅在测试之前调用这个方法初始化frog以节约内存测试完成后要清空units释放内存
try {
cells = new Cell[Env.FROG_BRAIN_XSIZE][][]; // 为了节约内存先只初始化三维数组的x维另两维用到时再分配
} catch (OutOfMemoryError e) {
System.out.println("OutOfMemoryError found for frog, force it die.");
this.alive = false;
return;
}
for (int orgNo = 0; orgNo < organs.size(); orgNo++) {
organs.get(orgNo).init(this, orgNo);
}
}
public boolean active(Env v) {
// 如果能量小于0则死、出界、与非食物的点重合则判死
/** Find a organ in frog by organ's name */
@SuppressWarnings("unchecked")
public <T extends Organ> T findOrganByName(String organName) {// 根据器官名寻找器官,但不是每个器官都有名字
for (Organ o : organs)
if (o.organName != null && organName.equalsIgnoreCase(o.organName))
return (T) o;
return null;
}
/** Set with given activeValue */
public void setCuboidVales(Cuboid o, boolean active) {// 激活长方体区域内的所有脑区
if (!alive)
return;
for (int x = o.x; x < o.x + o.xe; x++)
if (cells[x] != null)
for (int y = o.y; y < o.y + o.ye; y++)
if (cells[x][y] != null)
for (int z = o.z; z < o.z + o.ze; z++)
if (cells[x][y][z] != null)
getOrCreateCell(x, y, z).hasInput = active;
}
private int activeNo = 0;// 每一帧光子只能走一步,用这个来作标记
public boolean active(Env v) {// 这个active方法在每一步循环都会被调用是脑思考的最小帧
activeNo++;
// 如果能量小于0、出界、与非食物的点重合则判死
if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILLFROG) {
energy -= 100; // 死掉的青蛙也要消耗能量,确保淘汰出局
alive = false;
return false;
}
energy -= 20;
for (Organ o : organs) {
o.active(this);
for (Organ o : organs)
o.active(this); // 调用每个器官的active方法 通常只用于执行器官的外界信息输入、动作输出,脑细胞的遍历不是在这一步
// 这里是最关键的脑细胞主循环,脑细胞负责捕获和发送光子,光子则沿它的矢量方向每次自动走一格,如果下一格是真空(即cell未初始化会继续走下去并衰减直到为0(为减少运算)
for (int i = 0; i < Env.FROG_BRAIN_XSIZE; i++) {
Env.checkIfPause(this);
if (cells[i] != null)
for (int j = 0; j < Env.FROG_BRAIN_YSIZE; j++)
if (cells[i][j] != null)
for (int k = 0; k < Env.FROG_BRAIN_ZSIZE; k++) {
Cell cell = cells[i][j][k];
if (cell != null)
CellActions.act(this, activeNo, cell); // 调用每个细胞的act方法
}
}
return alive;
}
@ -83,4 +137,86 @@ public class Frog {
g.drawImage(frogImg, x - 8, y - 8, 16, 16, null);
}
/** Check if cell exist */
public Cell getCell(int x, int y, int z) {// 返回指定脑ssf坐标的cell 如果不存在返回null
if (cells[x] == null || cells[x][y] == null)
return null;
return cells[x][y][z];
}
/** Get a cell in position (x,y,z), if not exist, create a new one */
public Cell getOrCreateCell(int x, int y, int z) {// 获取指定坐标的Cell如果为空则在指定位置新建Cell
if (outBrainBound(x, y, z))
return null;
if (cells[x] == null)
cells[x] = new Cell[Env.FROG_BRAIN_YSIZE][];
if (cells[x][y] == null)
cells[x][y] = new Cell[Env.FROG_BRAIN_ZSIZE];
Cell cell = cells[x][y][z];
if (cell == null) {
cell = new Cell(x, y, z);
cells[x][y][z] = cell;
}
return cell;
}
/** Check if x,y,z out of frog's brain bound */
public static boolean outBrainBound(int x, int y, int z) {// 检查指定坐标是否超出frog脑空间界限
return x < 0 || x >= Env.FROG_BRAIN_XSIZE || y < 0 || y >= Env.FROG_BRAIN_YSIZE || z < 0
|| z >= Env.FROG_BRAIN_ZSIZE;
}
/** Photon always walk */
public void addAndWalk(Photon p) { // 添加光子的同时让它沿光子方向自动走一格
p.x += p.mx;
p.y += p.my;
p.z += p.mz;
int rx = Math.round(p.x);
int ry = Math.round(p.y);
int rz = Math.round(p.z);
if (Frog.outBrainBound(rx, ry, rz))
return;// 出界直接扔掉
Cell cell = getCell(rx, ry, rz);
if (cell != null)
cell.addPhoton(p);
}
/** Photon always walk */
public void addAndWalkAndDig(Photon p) { // 添加光子的同时让它沿光子方向自动走一格
p.x += p.mx;
p.y += p.my;
p.z += p.mz;
int rx = Math.round(p.x);
int ry = Math.round(p.y);
int rz = Math.round(p.z);
if (Frog.outBrainBound(rx, ry, rz))
return;// 出界直接扔掉
Cell cell = getCell(rx, ry, rz);
if (cell != null) {
cell.addPhoton(p);
cell.digHole(p);
}
}
// for test purpose, reset some values for prepare next training.
public void prepareNewTraining() {
for (int i = 0; i < Env.FROG_BRAIN_XSIZE; i++) {
if (cells[i] != null)
for (int j = 0; j < Env.FROG_BRAIN_YSIZE; j++)
if (cells[i][j] != null)
for (int k = 0; k < Env.FROG_BRAIN_ZSIZE; k++) {
Cell cell = cells[i][j][k];
if (cell != null) {
cell.deleteAllPhotons();
cell.hasInput = false;
cell.photonSum = 0;
if (cell.holes != null)
for (Hole h : cell.holes) {
h.age += 100;// 强迫洞的年龄增加,用这个方法来区分开不同批次的训练
}
}
}
}
}
}

@ -10,25 +10,179 @@
*/
package com.github.drinkjava2.frog.brain;
import java.util.Arrays;
import com.github.drinkjava2.frog.util.ColorUtils;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Cell is the basic unit of frog's brain
* Cell is the smallest unit of brain space, a Cell can have many actions and
* photons and holes and relations
*
* Cell(organs)(Photon)Hole)(Relation)frogcells
*
*
* CellCellActionsCell
*
* JellyMoveJelly,hole)
* ()(线)
* 沿线,
* hebb
*
*
* @author Yong Zhu
* @since 1.0
*/
public class Cell {
public static final float MAX_ENERGY_LIMIT = 100.0f;
public int x;
public int y;
public int z;
public Cell(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
/** Active of current cell */
public boolean hasInput = false; // 这个细胞是否有外界信号(如光、声音)输入
public int[] organs = null; //// 每个Cell可以被多个Organ登记这里保存organ在蛋里的序号
public Photon[] photons = null;// 光子
public Hole[] holes = null;// 洞(即动态突触),洞由光子产生,洞由时间抹平
public Relation[] relations = null;// 洞的关联关系
public int color;// Cell的颜色取最后一次被添加的光子的颜色颜色不重要但能方便观察
public int photonQty = 0; // 这个细胞里当前包含的光子总数
public int photonSum = 0; // 这个细胞里曾经收到的光子总数
public void regOrgan(int orgNo) {// 每个Cell可以被多个Organ登记通常只在青蛙初始化器官时调用这个方法
if (organs == null)
organs = new int[] {};
organs = Arrays.copyOf(organs, organs.length + 1);
organs[organs.length - 1] = orgNo;
}
public void addPhoton(Photon p) {// 每个cell可以存在多个光子
if (p == null)
return;
photonQty++;
photonSum++;
color = p.color; // Cell的颜色取最后一次被添加的光子的颜色
if (photons == null) {
photons = new Photon[] { p };// 创建数组
return;
} else
for (int i = 0; i < photons.length; i++) { // 找空位插入,尽量重复利用内存
if (photons[i] == null) {
photons[i] = p;
return; // 如找到就插入,返回
}
}
photons = Arrays.copyOf(photons, photons.length + 1);// 否则追加新光子到未尾
photons[photons.length - 1] = p;
}
public void digHole(Photon p) {// 根据光子来把洞挖大一点,同时,如果有洞和它年龄相近,将把它们绑定起来,如果已有绑定的洞,有可能在绑定的洞里撞出光子来
if (p == null || p.isBackway())// 反向的光子不参与挖坑
return;
if (holes == null) {// 如果没有坑,就新挖一个
holes = new Hole[] { new Hole(p) }; // 新挖的坑不参与绑定
return;
}
if (RandomUtils.percent(10)) // 这个机率纯粹是为了减少光子数,增加运行速度
for (int i = 0; i < holes.length; i++) { // 这部分很关键,光子如果与坑同向或角度相近,会在与坑绑定的坑上撞出新的光子反向飞回,注意只针对绑定的坑
Hole h = holes[i];
if (h != null) {
float r = h.angleCompare(p);
if (r < 0.05) {
if (RandomUtils.percent(h.size))
createBackPhoton(h); // 产生光子的机率与洞的大小有关
} else if (r > 0.1 && r < 0.5) { // 这个叫侧抑制,角度不等但相近的光子射过来会使洞变小
h.size -= 10;
if (h.size < 10)
h.size = 10;
}
}
}
Hole found = null;
for (int i = 0; i < holes.length; i++) { // 先看看已存在的洞是不是与光子同向,是的话就把洞挖大一点
Hole h = holes[i];
if (h != null && h.ifSimilarWay(p)) { // 找到了与入射光子同向的洞,实际上就是同一个波源发来的
found = h;
h.size += 10;
h.age = 0; // 为0表示这个洞被重新激活可以参与绑定
if (h.size > 100)
h.size = 100;
break;
}
}
if (found != null) { // 如果第二次扩洞,且光子和洞不是同一个器官产生的,这时可以把这个洞和其它洞关联起来了
for (Hole hole : holes) {
if (hole != found && found.organNo != hole.organNo && (Math.abs(found.age - hole.age) < 80)) {// TODO:不应用固定值
bind(found, hole);
}
}
}
if (found == null) {// 如果还没有找到旧坑,只好挖一个新坑到未尾
holes = Arrays.copyOf(holes, holes.length + 1);
holes[holes.length - 1] = new Hole(p);
}
}
// this cell belong to frog's which organ
public Organ organ;
private void createBackPhoton(Hole h) { // 根据给定的洞,把所有与它绑定的洞上撞出光子来
if (relations == null)
return;
for (Relation r : relations) {
Hole f = null;
if (h.equals(r.h1))
f = r.h2;// h2与h是一对绑定的
else if (h.equals(r.h2))
f = r.h1; // h1与h是一对绑定的
if (f != null) {
Photon back = new Photon(-1, ColorUtils.RED, f.x, f.y, f.z, -f.mx, -f.my, -f.mz);// 生成反向的光子
addPhoton(back);
// energy -= 90;
}
}
}
// inputs of cell
public Input[] inputs; // 每个细胞有一组输入触突
public void bind(Hole a, Hole b) {// 将两个坑绑定,以后只要有一个坑激活,另一个坑也会产生出光子
if (relations == null) {
relations = new Relation[] { new Relation(a, b) };
return;
}
for (Relation r : relations) {// 先看看是不是已绑过,绑过就把强度乘1.5
if ((r.h1 == a && r.h2 == b) || (r.h2 == a && r.h1 == b)) {
r.strength *= 1.5;
if (r.strength > 100000) // TODO: strength要有遗忘机制
r.strength = 100000;
return;
}
}
relations = Arrays.copyOf(relations, relations.length + 1);
relations[relations.length - 1] = new Relation(a, b);
}
// outputs of cell
public Output[] outputs; // 每个细胞有一组输出触突
public void removePhoton(int i) {// 删第几个光子
if (photons[i] != null) {
photons[i] = null;
photonQty--;
}
}
// energy of cell, energy got from food
public float energy; // 每个细胞当前的能量值
public void deleteAllPhotons() {
photons = null;
photonQty = 0;
}
}

@ -29,14 +29,16 @@ public class CellActions {
*
* act
* )
* action,organs
*
*
*
* 穿穿()
* 穿穿
*
* 线()(沿线)
* +
*
*
*
*/
public static void act(Frog frog, int activeNo, Cell c) {
if (c.holes != null)
@ -62,7 +64,7 @@ public class CellActions {
continue;
p.activeNo = activeNo;
c.removePhoton(ii);
frog.addAndWalk(p); // 让光子自已往下走,并且还挖洞
frog.addAndWalk(p); // 让光子自已往下走,走到哪就停到哪个细胞里
}
}
break;
@ -81,15 +83,15 @@ public class CellActions {
continue;
p.activeNo = activeNo;
c.removePhoton(ii);
frog.addAndWalkAndDig(p); // 让光子自已往下走,并且还挖洞
frog.addAndWalkAndDig(p); // 让光子自已往下走,走到哪就停到哪个细胞里,并且还在细胞上挖洞
}
}
break;
case Organ.EYE: // 如果是视网膜细胞,它的行为是只要Cell有输入信号就产生向右的多个光子发散出去模拟波源
case Organ.EYE: // 如果是视网膜细胞,它的行为是只要Cell有输入信号就产生向右的多个光子发散出去模拟波源
if (c.hasInput && RandomUtils.percent(40)) {// 随机数的作用是减少光子数,加快速度
for (float yy = -0.1f; yy <= 0.1f; yy += 0.03) {// 形成一个扇面向右发送
for (float zz = -0.1f; zz <= 0.1f; zz += 0.03) {
Photon p = new Photon(orgNo, o.color, c.x, c.y, c.z, 1.0f, yy, zz, 100f);
Photon p = new Photon(orgNo, o.color, c.x, c.y, c.z, 1.0f, yy, zz);
p.activeNo = activeNo; // 用这个activeNo防止一直被赶着走
frog.addAndWalk(p);// 光子不是直接添加,而是走一格后添加在相邻的细胞上
}
@ -100,7 +102,7 @@ public class CellActions {
if (c.hasInput && RandomUtils.percent(40)) {// 随机数的作用是减少光子数,加快速度
for (float xx = -0.3f; xx <= 0.3f; xx += 0.15) {// 形成一个扇面向下发送
for (float yy = -1f; yy <= 1f; yy += 0.06) {
Photon p = new Photon(o.organNo, o.color, c.x, c.y, c.z, xx, yy, -1, 100f);
Photon p = new Photon(o.organNo, o.color, c.x, c.y, c.z, xx, yy, -1);
p.activeNo = activeNo;
frog.addAndWalk(p);// 光子不是直接添加,而是走一格后添加在相邻的细胞上
}

@ -11,7 +11,7 @@
package com.github.drinkjava2.frog.brain;
/**
* Hole can be input, output, side synapse
* Hole is a hole on jelly cell, it works like synapse on nerve cell
*
*
*
@ -25,8 +25,8 @@ public class Hole {
public float mx; // mx,my,mz分别是光子砸出这个洞时的光子每单元移动方向在三个轴上的投影
public float my;
public float mz;
public float size = 1;// 洞的大小,同一个方向砸来的光子越多, 洞就越大
public int age;// 洞的年龄,一直在增长,但当洞光子砸进来或被激活产生光子时洞的年龄就归0
public int size = 50;// 洞的大小1~100这个size会按记忆曲线慢慢回复到0接近0后这个洞就被删除回收内存
public int age;// 洞的年龄,一直在增长,但一个洞有完全同向的光子再次砸进来洞的年龄就归0
public int organNo;// 这里记录第一个撞出来这个洞的产子是由哪个器官产生出来的
public Hole(Photon p) {

@ -9,7 +9,7 @@ import java.awt.event.MouseWheelListener;
/**
* MouseAction
*
*
* BrainPicture
*
* @author Yong Zhu
* @since 2.0.2

@ -11,84 +11,166 @@
package com.github.drinkjava2.frog.brain;
import java.awt.Color;
import java.io.Serializable;
import com.github.drinkjava2.frog.Application;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Organ is a part of frog, organ can be saved in egg
* Organ is a cone-cylinder shape zone inside of brain,, organ can be saved in
* egg organ will create cells in brain. Most organ's size, angle, location and
* cell parameters are randomly created
*
*
*
*
*
* ,
*
*
*
*
*
*
* )
*
* Cell,
* Cell
*
*
* ;
*
* ,线()
*
* <br/>
* 线cell
*
*
* @author Yong Zhu
* @since 1.0.4
*/
public class Organ extends Zone {
public class Organ implements Serializable, Cloneable {// 因为要保存在蛋文件里,所以必须支持串行化
private static final long serialVersionUID = 1L;
public String name; // 显示在脑图上的器官名称,可选
public long fat = 0; // 如果活跃多fat值高则保留及变异的可能性大反之则很可能丢弃掉
// public float organWasteEnergy = 0.05f; //
// 器官在每个测试循环中需要消耗青蛙多少能量,可以通过调节这个参数抑制器官数量无限增长
public float organActiveEnergy = 1; // 输出器官激活需要消耗每个脑细胞多少能量
public float organOutputEnergy = 2; // 感觉器官激活会给每个脑细胞增加多少能量
public boolean initilized; // 通过这个标记判断是否需要手工给定它的参数初值
public boolean allowBorrow() { // 是否允许在精子中将这个器官借出
return false;
// 以下是各种器官类型每个神经元都属于一个器官每个器官都有一个type类型参数
public static final int EMPTY = 0;// 空细胞,不处理光子
public static final int MOVE = 1;// 会让光子沿直线走一格
public static final int MOVE_JELLY = 2;// 会让光子沿直线走一格,并在下一个细胞上打洞
public static final int EYE = 3;// 眼细胞会根据cell激活度产生发散到各个方向的光子
public static final int EAR = 4;// 耳细胞,类似眼细胞,不同点是为了简化脑内听觉区和输入区混用一个区所以它也可吸收光子倒过来激活cell
public static final int JELLY = 5; // 光子在当前细胞上可以打出洞来
public static final int STATIC = 6; // 只有静态洞的细胞,它忽略动态洞参数
public static final int MIX = 7; // 同时具有静态和动态洞的细胞
public static final int TYPE_QTY = 8;// 所有的type都是预先写好在这里的自动生成的type也只能在写好的type里选一个
private static int organNoIndex = 1;
public int organNo = organNoIndex++; // 每个器官都有一个唯一的编号,作用是同一个编号的光子间将不产生绑定
public int color = 1;// 这个不重要表示它生成的光子的显示在脑图中的颜色号见ColorUtils
public float fat = 0;// 细胞活跃多则fat值大如果fat值很低则这个器官被丢弃的可能性加大这个值很重要它使得孤岛器官被淘汰
public boolean allowVary;// 是否允许变异,有一些器官是手工创建的,在项目初级阶段禁止它们参与变异和生存竟争。
public boolean allowBorrow;// 是否允许在精子中将这个器官借出,有一些器官是手工创建的,在项目初级阶段禁止它们借出
public String organName;// 器官的名字通常只有手工创建的器官才有名字可以用frog.findOrganByName来查找到这个器官
// ======= 本行以下是一些假设的参数,受变异和生存竟争影响 ,并通过大样本数、随机变异、生存竟争来进行多参数的优化选择 ========
public int type; // 器官类型,见上面的常量定义,这个字段通常很稳定。一旦变异,将从根本上改变器官的播种行为和神经元的行为
public Shape shape; // 器官的形状,不同的形状要写出不同的播种行为
public float cellDistance; // 细胞播种间隔每隔多少个cell进行器官行为的播种
public float centerDensityRate; // 中心相对于边沿的播种密度比为1时为均匀分布
public int holeLimit;// 细胞允许创建动态洞的数量上限详见Cell类的holes.字段
public float energyLimit;// 细胞能量上限,当能量超过能存贮的上限,多余的光子能量将不被细胞吸收,直接煙灭或以光子的形式转发出去
public float outputRate;// 细胞激活后,一次脉冲会释放出细胞存贮的能量比率(或释放出一个固定值) 根据能量守恒这个值通常小于1
public float outputDoor;// 输出阀值,细胞当前能量小于这个阀值时,细胞不会产生输出
public float inputRate;// 能量接收率,细胞存贮的能量占输入能量的比率(或吸收一个固定值) 根据能量守恒这个值通常小于1
public float inputDoor;// 接收阀值,接收的能量小于这个阀值时,细胞不会吸收这份能量,直接煙灭或以光子的形式转发出去
public float radius;// 细胞即使没有洞也可以处理光子这个radius是细胞的管辖半径但处理信号角度只限于穿透和反射或6个正方向
public float dropRate;// 是一个介于0~1的值反映了细胞存贮能量的下降速率在每一步长中细胞能量都以这个速率损失可以参考遗忘曲线
// =====注意以下三个字段可以让细胞具备一些固定角度的洞这个不占内存但缺点是不灵活不智能详见与Cell类中动态洞的对比 =====
public Hole[] holes; // 输出洞
public Organ() {// 缺省构造器,生成具有缺省参数但没有形状的器官
allowVary = true;
allowBorrow = true;
type = 0;
cellDistance = 1;
centerDensityRate = 1;
holeLimit = 10;
energyLimit = 100;
outputRate = 30;
outputDoor = 30;
inputRate = 100;
inputDoor = 5;
radius = 1;
dropRate = 95;
holes = null;
}
/** Each loop step call active method, Child class can override this method */
public void active(Frog f) { // 每一步都会调用器官的active方法 ,缺省啥也不干
/** Only call once after organ be created */
public Organ[] vary(Frog f) { // 器官变异仅会在青蛙下蛋时即new Egg(frog)中被调用一次,返回本身或变异后的一个或一组类似器官返回
if (!allowVary)
return new Organ[] { this };// 如果不允许变异,器官就把自身返回,存放在蛋里
// 各参数 随机有大概率小变异,小概率大变异,极小概率极大变异
type = RandomUtils.vary(type, 10);// 这个type通常不允许变所以只给它10%的机率去变, 也就是说在正常变异概率上再乘以10%的变异可能性
shape = RandomUtils.vary(shape);
cellDistance = RandomUtils.vary(cellDistance);
centerDensityRate = RandomUtils.vary(centerDensityRate);
holeLimit = RandomUtils.vary(holeLimit);
energyLimit = RandomUtils.vary(energyLimit);
outputRate = RandomUtils.vary(outputRate);
outputDoor = RandomUtils.vary(outputDoor);
inputRate = RandomUtils.vary(inputRate);
inputDoor = RandomUtils.vary(inputDoor);
radius = RandomUtils.vary(radius);
dropRate = RandomUtils.vary(dropRate);
holes = RandomUtils.vary(holes);
return new Organ[] { this };
}
/** If active in this organ's zone? */
public boolean outputActive(Frog f) { // 如果一个细胞能量>10,且它的输出触突位于这个器官内,则器官被激活
for (Cell cell : f.cells) {
if (cell.energy > organActiveEnergy)
for (Output output : cell.outputs) { //
if (this.nearby(output)) {
cell.organ.fat++;
cell.energy -= 30;//
return true;
}
}
}
return false;
/** Only call once when frog created , Child class can override this method */
public void init(Frog f, int orgNo) { // 在青蛙生成时会调用这个方法,进行一些初始化,通常是根据参数来播种脑细胞
// 里是器官播种脑细胞的具体代码,对于手工生成的器官也可以重写这个方法对于自动生成的器官必须根据type和shape等来播种要写死在这里
if (shape != null)
shape.createCellsRegOrgan(f, orgNo); // 先均匀播种脑细胞试试
}
/** Set X, Y, Radius, name of current Organ */
public Organ setXYRN(float x, float y, float r, String name) {
this.setXYR(x, y, r);
this.name = name;
return this;
/** each step will call Organ's active methodd */
public void active(Frog f) { // 每一步测试都会调用active方法通常用于手动生成的器官自动生成的器官其行为仅由脑细胞来决定
// do nothing
}
/** Child class can override this method to drawing picture */
public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来,子类可以重写这个方法
if (!Application.SHOW_FIRST_FROG_BRAIN)
public void drawOnBrainPicture(Frog f, BrainPicture pic) { // 把器官的轮廓显示在脑图上
if (shape == null)
return;// 如果没有形状,就不画
if (!Env.SHOW_FIRST_FROG_BRAIN || !f.alive) // 如果不允许画或青蛙死了,就直接返回
return;
pic.setColor(Color.BLACK); // 缺省是黑色
pic.drawZone(this);
if (this.name != null)
pic.drawText(this, String.valueOf(this.name));
pic.setPicColor(Color.LIGHT_GRAY); // 缺省是灰色
shape.drawOnBrainPicture(pic);
}
/** Only call once when frog created , Child class can override this method */
public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次缺省啥也不干通常用于Group子类的初始化
public static Organ randomCuboidOrgan() {
Organ o = new Organ();
o.shape = RandomUtils.randomCuboid();
return o;
}
/** Only call once after organ be created by new() method */
public Organ[] vary() { // 在下蛋时每个器官会调用这个方法,缺省返回一个类似自已的副本,子类通常要覆盖这个方法
Organ newOrgan = null;
try {
newOrgan = this.getClass().newInstance();
} catch (Exception e) {
throw new UnknownError("Can not make new Organ copy for " + this);
}
copyXYR(this, newOrgan);
newOrgan.name = this.name;
newOrgan.fat = this.fat;
return new Organ[] { newOrgan };
public static Organ randomConeOrgan() {
Organ o = new Organ();
o.shape = RandomUtils.randomCone();
return o;
}
}

@ -31,11 +31,12 @@ public class Photon {
public int organNo;// 每个光子是由哪个器官产生的,为-1表示它不是器官产生而是由细胞动态生成的反向光子信号
public int color;// 每个光子都有自已的颜色,由产生光子的器官的颜色来决定,颜色不重要,但能方便观察
public int activeNo;// 每一轮循环都有一个编号,光子走一格后就加上这个编号,同一个循环如果遇到相同编号的光子就跳过,防止光子被一直赶着走
public int energy;
public Photon() { // 缺省构造器
}
public Photon(int organNo, int color, float x, float y, float z, float mx, float my, float mz, float energy) {
public Photon(int organNo, int color, float x, float y, float z, float mx, float my, float mz) {
this.x = x;
this.y = y;
this.z = z;

@ -10,129 +10,55 @@
*/
package com.github.drinkjava2.frog.brain.organ;
import com.github.drinkjava2.frog.Application;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.BrainPicture;
import com.github.drinkjava2.frog.brain.Cell;
import com.github.drinkjava2.frog.brain.Input;
import com.github.drinkjava2.frog.brain.Cuboid;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.Zone;
import com.github.drinkjava2.frog.util.RandomUtils;
import com.github.drinkjava2.frog.util.ColorUtils;
import com.github.drinkjava2.frog.util.PixelsUtils;
/**
* Eye can only see 4 direction
* Eye can only see env material
*
* @author Yong Zhu
* @since 1.0
*/
public class Eye extends Organ {// 这个Eye是老版的眼睛只能看到四个方向但它的调节距离会自动随机调整到一个最佳值这就是随机试错算法的一个应用
public class Eye extends Organ {// 眼睛是长方体
private static final long serialVersionUID = 1L;
public int seeDistance; // 眼睛能看到的距离
@Override
public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次
if (!initilized) {
initilized = true;
organOutputEnergy = 30;
seeDistance = 8;
}
public Eye() {
this.shape = new Cuboid(0, 3, 2, 1, 13, 13);
this.type = Organ.EYE;
this.organName = "Eye";
this.allowVary = false;// 不允许变异
this.allowBorrow = false;// 不允许借出
this.color = ColorUtils.GRAY;
}
@Override
public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来
if (!Application.SHOW_FIRST_FROG_BRAIN)
return;
super.drawOnBrainPicture(f, pic);
float qRadius = r / 4;
float q3Radius = (float) (r * .75);
Zone seeUp = new Zone(x, y + q3Radius, qRadius);
Zone seeDown = new Zone(x, y - q3Radius, qRadius);
Zone seeLeft = new Zone(x - q3Radius, y, qRadius);
Zone seeRight = new Zone(x + q3Radius, y, qRadius);
pic.drawZone(seeUp);
pic.drawZone(seeDown);
pic.drawZone(seeLeft);
pic.drawZone(seeRight);
}
@Override
public Organ[] vary() {
if (RandomUtils.percent(5)) { // 可视距离有5%的机率变异
seeDistance = seeDistance + 1 - 2 * RandomUtils.nextInt(2);
if (seeDistance < 1)
seeDistance = 1;
if (seeDistance > 50)
seeDistance = 50;
}
return new Organ[] { this };
/** Clear image on retina */
public void seeNothing(Frog f) {// 外界可以直接调用这个方法,清除视网膜图像
f.setCuboidVales((Cuboid) shape, false);
}
@Override
public void active(Frog f) {
// 第一个眼睛只能观察上、下、左、右四个方向有没有食物
float qRadius = r / 4;
float q3Radius = (float) (r * .75);
Zone seeUp = new Zone(x, y + q3Radius, qRadius);
Zone seeDown = new Zone(x, y - q3Radius, qRadius);
Zone seeLeft = new Zone(x - q3Radius, y, qRadius);
Zone seeRight = new Zone(x + q3Radius, y, qRadius);
boolean seeSomething = false;
boolean atUp = false;
boolean atDown = false;
boolean atLeft = false;
boolean atRight = false;
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x, f.y + i)) {
seeSomething = true;
atUp = true;
break;
}
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x, f.y - i)) {
seeSomething = true;
atDown = true;
break;
}
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x - i, f.y)) {
seeSomething = true;
atLeft = true;
break;
}
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x + i, f.y)) {
seeSomething = true;
atRight = true;
break;
}
if (seeSomething)
for (Cell cell : f.cells) {
if (cell.energy < 100)
for (Input input : cell.inputs) {
if (input.nearby(this)) {
if (atUp && input.nearby(seeUp)) {
input.cell.energy += organOutputEnergy;
}
if (atDown && input.nearby(seeDown)) {
input.cell.energy += organOutputEnergy;
}
if (atLeft && input.nearby(seeLeft)) {
input.cell.energy += organOutputEnergy;
}
if (atRight && input.nearby(seeRight)) {
input.cell.energy += organOutputEnergy;
}
}
}
}
/**
* Accept a byte[x][y] array, active tubes located on eye's retina
*
*
*/
public void seeImage(Frog f, byte[][] pixels) {// 外界可以直接调用这个方法,硬塞一个象素图到视网膜上
if (!f.alive)
return;
int w = pixels.length;
int h = pixels[0].length;
Cuboid c = (Cuboid) shape;
// 在视网膜上产生字母像素点阵即激活这个脑视网膜所在的cells区然后由器官播种出的脑细胞负责将激活能量转为光子输送、存贮到其它位置
for (int px = 0; px < w; px++)
for (int py = 0; py < h; py++)
if (pixels[px][py] > 0)
f.getOrCreateCell(0, c.y + c.ye - px - 1, c.z + py).hasInput = true;
}
public void seeImageWithOffset(Frog f, byte[][] pixels, int xOff, int yOff) {// 外界硬塞一个象素图到视网膜上,并给出偏移量
byte[][] newPixels = PixelsUtils.offset(pixels, xOff, yOff);
seeImage(f, newPixels);
}
}

@ -16,24 +16,14 @@ import java.util.List;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.group.Group;
import com.github.drinkjava2.frog.brain.organ.Active;
import com.github.drinkjava2.frog.brain.organ.Chance;
import com.github.drinkjava2.frog.brain.organ.Eat;
import com.github.drinkjava2.frog.brain.organ.Ear;
import com.github.drinkjava2.frog.brain.organ.Eye;
import com.github.drinkjava2.frog.brain.organ.Happy;
import com.github.drinkjava2.frog.brain.organ.Hungry;
import com.github.drinkjava2.frog.brain.organ.MoveDown;
import com.github.drinkjava2.frog.brain.organ.MoveLeft;
import com.github.drinkjava2.frog.brain.organ.MoveRight;
import com.github.drinkjava2.frog.brain.organ.MoveUp;
import com.github.drinkjava2.frog.brain.organ.NewEye;
import com.github.drinkjava2.frog.brain.organ.Pain;
import com.github.drinkjava2.frog.brain.organ.MoveJelly;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Egg is the static structure description of frog, can save as text file, to
* build a frog, first need build a egg.<br/>
* Egg is the static structure description of frog, can save as file, to build a
* frog, first need build a egg.<br/>
*
* Frog,FrogFrogFrog"永生"egg
*
@ -42,59 +32,51 @@ import com.github.drinkjava2.frog.util.RandomUtils;
* @since 1.0
*/
public class Egg implements Serializable {
// 为了缩短时间,这个程序随机生成的联结将只落在固定的器官上而不是漫天撒网(见4.12提交),这是程序的优化,实现的逻辑和随机漫天撒网定是相同的。
// 但是这个优化带来的问题是这是一个硬编码逻辑,不利于器官的优胜劣汰, 而且下面这个 FIXED_ORGAN_QTY必须每次手工设定以后需要重构这块的代码
public static int FIXED_ORGAN_QTY = 11;
private static final long serialVersionUID = 1L;
public List<Organ> organs = new ArrayList<>();
public List<Group> groups = new ArrayList<>();
public List<Organ> organs = new ArrayList<>();// NOSONAR
public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙
organs.add(new Happy().setXYRN(600, 700, 60, "Happy")); // Happy必须第一个加入
organs.add(new Hungry().setXYRN(300, 100, 60, "Hungry"));
organs.add(new MoveUp().setXYRN(800, 100, 60, "Up"));
organs.add(new MoveDown().setXYRN(800, 400, 60, "Down"));
organs.add(new MoveLeft().setXYRN(700, 250, 60, "Left"));
organs.add(new MoveRight().setXYRN(900, 250, 60, "Right"));
organs.add(new Eye().setXYRN(100, 300, 100, "Eye"));
organs.add(new NewEye().setXYRN(200, 700, 200, "NewEye"));
organs.add(new Pain().setXYRN(800, 700, 60, "Pain")); // 痛苦在靠近边界时触发
organs.add(new Active().setXYRN(500, 100, 60, "Active")); // 永远激活
organs.add(new Chance().setXYRN(650, 100, 60, "Chance")); // 永远激活
// 以上为11个, 就是FIXED_ORGAN_QTY值
organs.add(new Eat().setXYRN(0, 0, 0, "Eat")); // EAT不是感觉或输出器官没有位置和大小
organs.add(new MoveJelly()); // MoveJelly即移动光子也是果冻记忆细胞本来可以分成两个器官的图省事
organs.add(new Eye()); // 眼是手工创建的,必有
organs.add(new Ear()); // 耳是手工创建的这个是用来测试ABCD字母识别的
}
/** Create egg from frog */
public Egg(Frog frog) { // 青蛙下蛋每个青蛙的器官会创建自已的副本或变异可以是0或多个
for (Organ organ : frog.organs)
for (Organ newOrgan : organ.vary())
for (Organ newOrgan : organ.vary(frog))
organs.add(newOrgan);
}
/**
* Create a egg by join 2 eggs, x+y=zygote XY XY,
* 退,
*
*
* Create a egg by join 2 eggs, x+y=zygote XY
* XY
*/
public Egg(Egg x, Egg y) {
for (Organ organ : x.organs) {
if (!organ.allowVary || organ.fat != 0 || RandomUtils.percent(70)) // 如果器官没用到,fat为0增加丢弃它的机率
organs.add(organ);
}
// x里原来的organ
for (Organ organ : x.organs)
organs.add(organ);
// 从y里借一个organ
int yOrganSize = y.organs.size();
if (yOrganSize > 0) {
Organ o = y.organs.get(RandomUtils.nextInt(yOrganSize));
if (o.allowBorrow())
organs.add(o);
if (RandomUtils.percent(70)) // 70%的情况下不作为, x就是受精卵
return;
// 从y里借一个organ替换掉原来位置的organ相当于DNA级别的片段切换它要求一个随机位置的Organ都允许替换allowBorrow
// int yOrganSize = y.organs.size();
// if (yOrganSize > 0) {
// int i = RandomUtils.nextInt(yOrganSize);
// Organ o = y.organs.get(i);
// if (o.allowBorrow) {
// if (organs.size() > i && organs.get(i).allowBorrow)
// organs.set(i, o);// 用y里的organ替换掉x里的organ,模拟受精
// }
// }
// if (RandomUtils.percent(50))// 有50%的机率随机会产生新的器官
// organs.add(Organ.randomCuboidOrgan());
if (RandomUtils.percent(organs.size())) {// 器官会随机丢失,并且机率与器官数量成正比,防止器官无限增长
int i = RandomUtils.nextInt(organs.size());
if (organs.get(i).allowBorrow)
organs.remove(i);
}
}

@ -22,8 +22,6 @@ import java.util.List;
import com.github.drinkjava2.frog.Application;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.organ.Chance;
import com.github.drinkjava2.frog.brain.organ.Eye;
import com.github.drinkjava2.frog.util.FrogFileUtils;
/**
@ -54,10 +52,9 @@ public class EggTool {
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(Env.eggs);
so.close();
System.out.print("\r1st frog has " + first.organs.size() + " organs, energy=" + first.energy + ", seeDist="
+ ((Eye) first.organs.get(6)).seeDistance + ", chance=" + ((Chance) first.organs.get(10)).percent);
System.out.print("Fist frog has " + first.organs.size() + " organs, energy=" + first.energy);
System.out.println(", Last frog has " + last.organs.size() + " organs, energy=" + last.energy);
System.out.println("Saved "+Env.eggs.size() +" eggs to file '" + Application.CLASSPATH + "eggs.ser'");
System.out.println("Saved " + Env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser'");
} catch (IOException e) {
System.out.println(e);
}

@ -23,7 +23,7 @@ import com.github.drinkjava2.frog.util.RandomUtils;
* @author Yong Zhu
* @since 1.0
*/
public class Food implements Object {
public class Food implements EnvObject {
@Override
public void build() {

@ -26,7 +26,7 @@ import com.github.drinkjava2.frog.util.StringPixelUtils;
* @since 1.0
*/
public class LetterTester implements EnvObject {
public static final String STR = "对酒当歌人生几何";
public static final String STR = "一二三";
public static final int TIME = 120;
@Override
@ -54,7 +54,7 @@ public class LetterTester implements EnvObject {
} else {
int index2 = index % STR.length();
BrainPicture.setNote("第" + (index2 + 1) + "个字识别");
eye.seeImageWithOffset(frog, StringPixelUtils.getSanserif12Pixels(STR.substring(index2, index2 + 1)),0,0);
eye.seeImageWithOffset(frog, StringPixelUtils.getSanserif12Pixels(STR.substring(index2, index2 + 1)),1,1);
if (Env.step % TIME > (TIME - 2)) {
int result = ear.readcode(frog);
System.out.println("Max=" + result+", 即 '"+STR.substring(result, result+1)+"'");

@ -15,21 +15,22 @@ import java.awt.Color;
/**
* Object means some thing in Env
*
* 01020,
*
* @author Yong Zhu
* @since 1.0
*/
public class Material {
public static final byte VISIBLE = 10; // if>=10 will visible to frog
public static final byte KILLFROG = 20; // if>=20 will kill frog
public static final byte NO = 0;
public static final byte NO = 0; // nothing
public static final byte SEESAW_BASE = 1; // 1~9 is invisible to frog
public static final byte VISIBLE = 10; // if>=10 will visible to frog
public static final byte FOOD = VISIBLE + 1;
public static final byte SEESAW = VISIBLE + 2; // if <0 will not cause frog die
public static final byte SEESAW = VISIBLE + 2;
public static final byte BRICK = KILLFROG + 1;
public static final byte TRAP = KILLFROG + 2;
public static final byte KILLFROG = 20; // if>=20 will kill frog
public static final byte BRICK = KILLFROG + 1;// brick will kill frog
public static final byte TRAP = KILLFROG + 2; // trap will kill frog
public static Color color(byte material) {
if (material == TRAP)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save