diff --git a/README.md b/README.md
index fc0affd..c11fba9 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,13 @@
本次更新在015_testinput3目录下,只有一个TestInput3.java文件,这是个临时测试类,用穷举法来测试一个如果有三个视觉输入细胞、一个执行细胞的情况下能不能实现所有正常模式识别,即输入有2的7次方=128种组合,输出有0/1两种信号。实测发现这128种情况下有31种输入是无法通过调整权重来实现输出逻辑的,也就是说31种情况下是无解的。类似地,如果有4个输入,在32768组合中有29987种情况是无解的。所以如果输入信号大于两个时,必须改进结构,增加层数或在水平方向平铺增加输入输出细胞。
目前有两个问题:一是用甜激素增加所有最近活跃的正权重、苦激素增加所有最近活跃的负权重这种方式能不能完全代替穷举法找到所有解;二是有没有办法只使用浅层神经网络实现模式识别?(人脑的皮层占了很大比重,顾名思义,皮层可能就是浅层的,而不是象深度学习一样是极深层的神经网络),这个模式识别不需要很精准,能达到约15x15的分辨率就可以接近人脑的模式识别功能了,因为人脑还会结合动眼和变焦两个功能来缩小需要进行模式识别信号的像素。这两个问题目前深度学习可能能找到答案,但我不知道有没有人采用这种正负权重双通道输入的结构,这种双通道输入结构实际上才是实际生物的神经网络构成。
+2024-02-29 还是单点信号输入
+这个更新在history\016a_OneInput目录下,实现当只有一个视信号输入时,咬细胞随食物出现激活,食物消失停止激活,这是个最简单的逻辑。这个实现还是使用连线算法来模拟触突,因为细胞少时,连线算法编程更方便一点,连线算法是以连线的绝对坐标来定位,分裂算法是以相对每个细胞的相对坐标来定位。本次更新中,有一个视细胞,一个甜味感觉细胞,一个苦味感觉细胞(咬错时激活),一个活动细胞(始终激活),和几个空白细胞。随机连线的参数是在常量随机数组上随机截取一段,这次引入了分组功能,把每种连线给一个编号,每个编号相同的连线拥有相同起始位置的一串固定参数,固定参数是指一旦生成就不再改变的参数。可变参数如权重等需要在运行期为每个连线上的参数分配一个内存。固定参数不管有多少,每个连线只需要给一个编号即可,可以节约内存。这个类似生物脑,可变参数不在基因里保存,因为可变,出生时是空白的,也就不需要占用基因位来存贮。一串固定参数可以简化成一个编号,然后编号们又由分裂算法来控制,海量的细胞可以用很少的字节数来控制,这就是为什么人类有100亿个不同位置和功能的脑细胞但基因信息量却只有850MB的原因。
+下一步计划是2点、3点、4点线性信号模式识别,2x2、3x3二维信号模式识别, 一点一点向上实现,大的图像将引入动眼和变焦细胞。
+从2点开始,可能引入饥饿细胞,在饥饿状态下,青蛙会有更多随机试咬动作,以增加形成正确条件反射的机率。当然以后随着模式识别复杂化,就算青蛙都饿死也很难触发正确的随机动作,就要考虑引入人为的训练信号了。
+
+
+
## 运行方式 | Run
运行core或history各个子目录下的run.bat批处理文件即可启动运行,history下有多个子目录,按版本号顺序排列,存放着这个项目演化过程中的主要历史版本供演示。
diff --git a/core/pom.xml b/core/pom.xml
index 0dfce8f..002d2e9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -2,12 +2,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
com.gitee.drinkjava2
- frog015
+ frog016b
jar
- 15.0
+ 16b.0
frog
- 当前目标是用分裂算法来实现第一个具备模式识别功能的神经网络
+ 当前目标是用分裂算法来实现模式识别,当前小目标是实现两点输入的模式识别
https://gitee.com/drinkjava2/frog
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/Animal.java b/core/src/main/java/com/gitee/drinkjava2/frog/Animal.java
index 9e9ab92..3fc589d 100644
--- a/core/src/main/java/com/gitee/drinkjava2/frog/Animal.java
+++ b/core/src/main/java/com/gitee/drinkjava2/frog/Animal.java
@@ -12,6 +12,7 @@ package com.gitee.drinkjava2.frog;
import static com.gitee.drinkjava2.frog.brain.Genes.GENE_NUMBERS;
+import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
@@ -20,8 +21,8 @@ import java.util.ArrayList;
import javax.imageio.ImageIO;
-import com.gitee.drinkjava2.frog.brain.Consts;
import com.gitee.drinkjava2.frog.brain.Genes;
+import com.gitee.drinkjava2.frog.brain.Line;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.objects.Material;
import com.gitee.drinkjava2.frog.util.GeneUtils;
@@ -50,7 +51,10 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public ArrayList> genes = new ArrayList<>(); // 基因是多个数列,有点象多条染色体。每个数列都代表一个基因的分裂次序(8叉/4叉/2叉)。
- public int[] consts = new int[Consts.CountsQTY]; //常量基因,用来存放不参与分裂算法的全局常量,这些常量也参与遗传算法筛选,规则是有大概率小变异,小概率大变异,见constGenesMutation方法
+ public static int CountsQTY = 100; //常量总数多少
+ public float[] consts = new float[CountsQTY]; // 常量,范围0~1之间,这些常量并不常,会参与遗传算法筛选,规则是有大概率小变异,小概率大变异
+
+ public ArrayList lines = new ArrayList<>();
/** brain cells,每个细胞对应一个神经元。long是64位,所以目前一个细胞只能允许最多64个基因,64个基因有些是8叉分裂,有些是4叉分裂
* 如果今后要扩充到超过64个基因限制,可以定义多个三维数组,同一个细胞由多个三维数组相同坐标位置的基因共同表达
@@ -59,27 +63,27 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public float[][][] energys = new float[Env.BRAIN_SIZE][Env.BRAIN_SIZE][Env.BRAIN_SIZE]; //每个细胞的能量值,细胞能量不参与打分。打分是由fat变量承担
- public int[][][][] holes = new int[Env.BRAIN_SIZE][Env.BRAIN_SIZE][Env.BRAIN_SIZE][]; //每个细胞的洞(相当于触突)
-
public int xPos; // animal在Env中的x坐标
public int yPos; // animal在Env中的y坐标
public long fat = 1000000000; // 青蛙的肥胖度, 只有胖的青蛙才允许下蛋, 以前版本这个变量名为energy,为了不和脑细胞的能量重名,从这个版本起改名为fat
public boolean alive = true; // 设为false表示青蛙死掉了,将不参与计算和显示,以节省时间
public int ateFood = 0; // 青蛙曾吃过的食物总数
public int ateWrong = 0; // 青蛙咬了个空气的次数
+ public int ateMiss = 0; // 该咬却没咬下去的次数
public int no; // 青蛙在Env.animals中的序号,从1开始, 会在运行期写到当前brick的最低位,可利用Env.animals.get(no-1)快速定位青蛙
public int animalMaterial;
public Image animalImage;
- public Animal(Egg egg) {// x, y 是虑拟环境的坐标
- System.arraycopy(egg.constGenes, 0, this.consts, 0, consts.length);//从蛋中拷一份全局参数
+ public Animal(Egg egg) {//构造方法,Animal从蛋中诞生
+ System.arraycopy(egg.consts, 0, this.consts, 0, consts.length);//从蛋中拷一份全局参数
for (int i = 0; i < GENE_NUMBERS; i++) {
genes.add(new ArrayList<>());
}
int i = 0;
for (ArrayList gene : egg.genes)//动物的基因是蛋的基因的拷贝
genes.get(i++).addAll(gene);
+ lines.addAll(egg.lines); //复制蛋的所有线条
i = 0;
if (Env.BORN_AT_RANDOM_PLACE) { //是否随机出生在地图上?
xPos = RandomUtils.nextInt(Env.ENV_WIDTH);
@@ -99,11 +103,15 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
}
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步,这个方法是在当前屏animal生成之后调用,比方说有一千个青蛙分为500屏测试,每屏只生成2个青蛙的脑细胞,可以节约内存
- GeneUtils.geneMutation(this); //有小概率基因突变
- Consts.constMutation(this);//常量基因突变
- if (RandomUtils.percent(40))
+ constMutate();//常量基因突变, 线条的参数都在常量里
+ Line.randomAddorRemoveLine(this);// //Line的随机增删变异
+
+ GeneUtils.geneMutation(this); //分裂算法控制的基因突变
+ if (RandomUtils.percent(5))
for (ArrayList gene : genes) //基因多也要适当小扣点分,防止基因无限增长
fat -= gene.size();
+ if (RandomUtils.percent(3)) //线条多也小扣点分,防止线条无限增长
+ fat -= lines.size() / 10;
GeneUtils.createCellsFromGene(this); //根据基因,分裂生成脑细胞
}
@@ -116,12 +124,27 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
kill();
return false;
}
-
- holesReduce(); //所有细胞上的洞都随时间消逝,即信息的遗忘,旧的不去新的不来
+ this.setEng(Genes.ACT_POS, 1f); //ACT这个细胞就象太阳永远保持激活,某些情况下当无外界信号时,它是驱动系统运行的能量来源
Genes.active(this, step); //调用每个细胞的活动,重要!
+ Line.active(this, step); //调用每个连线(触突)的活动,重要!
return alive;
}
+ public void constMutate() { // 全局参数变异, 这一个方法此动物个体的所有常量
+ if (RandomUtils.percent(30)) //这个30%机率的变异方法让所有常量都有3%的机率随机在0~1之间重新取值
+ for (int i = 0; i < CountsQTY; i++) {
+ if (RandomUtils.percent(3))
+ consts[i] = RandomUtils.nextFloat(); //debug
+ }
+
+ if (RandomUtils.percent(10)) //这个10%机率的变异方法让所有常量都有5%的机率随机在原基础上变异,即大概率有小变异,小概率有大变异
+ for (int i = 0; i < CountsQTY; i++) {
+ if (RandomUtils.percent(5))
+ consts[i] = RandomUtils.vary(consts[i]);
+ }
+
+ }
+
private static final int MIN_FAT_LIMIT = Integer.MIN_VALUE + 5000;
private static final int MAX_FAT_LIMIT = Integer.MAX_VALUE - 5000;
@@ -147,10 +170,18 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public void kill() { this.alive = false; changeFat(-5000000); Env.clearMaterial(xPos, yPos, animalMaterial); } //kill是最大的惩罚
//@formatter:on
- public void show(Graphics g) {// 显示当前动物
+ public void showInEnv(Graphics g) {// 在虚拟环境显示当前动物,这个方法直接调用Env的Graphics对象
+ if (g != null) //这个版本借用环境区测试模式功能,不需要显示青蛙,所以直接跳出
+ return;
+ if (no == (Env.current_screen * Env.FROG_PER_SCREEN + 1)) { //如果是当前第一个青蛙,给它画个红圈
+ Color c = g.getColor();
+ g.setColor(Color.red);
+ g.drawArc(xPos - 15, yPos - 15, 30, 30, 0, 360);
+ g.setColor(c);
+ }
if (!alive)
return;
- //g.drawImage(animalImage, xPos - 8, yPos - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
+ g.drawImage(animalImage, xPos - 8, yPos - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
}
/** Check if x,y,z out of animal's brain range */
@@ -166,25 +197,25 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
return cells[x][y][z] > 0;
}
- public void setEng1(int x, int y, int z) { //打开指定的xyz坐标对应的cell能量值为极大
- energys[x][y][z] = 1;
+ public void setEng(int x, int y, int z, float e) { //打开指定的xyz坐标对应的cell能量值为极大
+ if (e > 1)
+ e = 1;
+ if (e < 0)
+ e = 0;
+ energys[x][y][z] = e;
}
- public void setEng1(int[] a) { //打开指定的a坐标对应的cell能量值为极大
- energys[a[0]][a[1]][a[2]] =1;
- }
-
- public void setEng0(int x, int y, int z) { //关闭指定的xyz坐标对应的cell能量值为0
- energys[x][y][z] = 0;
- }
-
- public void setEng0(int[] a) {//关闭指定的a坐标对应的cell能量值为0
- energys[a[0]][a[1]][a[2]] = 0;
+ public void setEng(int[] a, float e) { //打开指定的xyz坐标对应的cell能量值为极大
+ if (e > 1)
+ e = 1;
+ if (e < 0)
+ e = 0;
+ energys[a[0]][a[1]][a[2]] = e;
}
public void addEng(int[] a, float e) {//指定的a坐标对应的cell能量值加e
addEng(a[0], a[1], a[2], e);
- }
+ }
public void addEng(int x, int y, int z, float e) {//指定的a坐标对应的cell能量值加e
if (cells[x][y][z] == 0)
@@ -192,117 +223,17 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
float eng = energys[x][y][z] + e;
if (eng > 1) //如果饱和,不再增加,通过这个方法可以实现异或逻辑或更复杂的模式识别,详见TestInput3测试
eng = 1;
- if (eng < 0) //回到传统方式,细胞不允许出现负能量。(但是权值,即树突的正负两个通道中的负通道上,可以出现负信号,这个与实际细胞的抑制信号相似)
+ if (eng < 0) //回到传统方式,细胞不允许出现负能量。(但是能量可以出现负值,这个与实际细胞的抑制信号相似)
eng = 0;
energys[x][y][z] = eng;
- }
+ }
+
+ public float getEng(int[] a) {//返回指定的a坐标对应的cell能量值
+ return energys[a[0]][a[1]][a[2]];
+ }
public float getEng(int x, int y, int z) {//返回指定的a坐标对应的cell能量值
return energys[x][y][z];
}
- static final int HOLE_MAX_SIZE = 1000 * 1000;
-
- public void digHole(int[] srcPos, int[] targetPos, int holeSize, int fresh) {
- digHole(srcPos[0], srcPos[1], srcPos[2], targetPos[0], targetPos[1], targetPos[2], holeSize, fresh);
- }
-
- public void digHole(int sX, int sY, int sZ, int[] targetPos, int holeSize, int fresh) {
- digHole(sX, sY, sZ, targetPos[0], targetPos[1], targetPos[2], holeSize, fresh);
- }
-
- public static final int HOLE_ARR_SIZE = 5; //洞由几个参数构成
-
-
-
- //TODO: =================以下这些方法太复杂,删除除或重新整理=================
- public void digHole(int sX, int sY, int sZ, int tX, int tY, int tZ, int size, int fresh) {//在t细胞上挖洞,将洞的方向链接到源s,如果洞已存在,扩大洞, 新洞大小为1,洞最大不超过100
- if (!hasGene(tX, tY, tZ))
- return;
- if (!Env.insideBrain(sX, sY, sZ))
- return;
- if (!Env.insideBrain(tX, tY, tZ))
- return;
- if (getEng(tX, tY, tZ) < 1) //要调整
- addEng(tX, tY, tZ, 1); //要调整
-
- int[] cellHoles = holes[tX][tY][tZ];
- if (cellHoles == null) { //洞不存在,新建一个, 洞参数是一个一维数组,分别为源坐标X,Y,Z, 洞的大小,洞的新鲜度
- holes[tX][tY][tZ] = new int[]{sX, sY, sZ, size, fresh}; //
- return;
- } else {
- int emptyPos = -1; //找指定源坐标已存在的洞,如果不存在,如发现空洞也可以占用
- for (int i = 0; i < cellHoles.length / HOLE_ARR_SIZE; i++) {
- int n = i * HOLE_ARR_SIZE;
- if (cellHoles[n] == sX && cellHoles[n + 1] == sY && cellHoles[n + 2] == sZ) {//找到已有的洞了
- if (cellHoles[n + 3] < 1000) //要改成由基因调整
- cellHoles[n + 3] += size;
- if (cellHoles[n + 4] < 1000) //要改成由基因调整
- cellHoles[n + 4] += fresh;
- return;
- }
- if (emptyPos == -1 && cellHoles[n + 3] <= 1)//如发现空洞也可以,先记下它的位置
- emptyPos = n;
- }
-
- if (emptyPos > -1) { //找到一个空洞
- cellHoles[emptyPos] = sX;
- cellHoles[emptyPos + 1] = sY;
- cellHoles[emptyPos + 2] = sZ;
- if (cellHoles[emptyPos + 3] < 1000) //要改成由基因调整
- cellHoles[emptyPos + 3] += size;
- if (cellHoles[emptyPos + 4] < 1000) //要改成由基因调整
- cellHoles[emptyPos + 4] += fresh;
- return;
- }
-
- int length = cellHoles.length; //没找到已有的洞,也没找到空洞,新建一个并追加到原洞数组未尾
- int[] newHoles = new int[length + HOLE_ARR_SIZE];
- System.arraycopy(cellHoles, 0, newHoles, 0, length);
- newHoles[length] = sX;
- newHoles[length + 1] = sY;
- newHoles[length + 2] = sZ;
- newHoles[length + 3] = size; //要改成由基因调整
- newHoles[length + 4] = fresh; //要改成由基因调整
- holes[tX][tY][tZ] = newHoles;
- return;
- }
- }
-
- public void holeSendEngery(int[] pos, float e) {//在当前细胞所有洞上反向发送能量(光子),le是向左边的细胞发, re是向右边的细胞发
- holeSendEngery(pos[0], pos[1], pos[2], e);
- }
-
- public void holeSendEngery(int x, int y, int z, float e) {//在当前细胞所有洞上反向发送能量(光子),le是向左边的细胞发, re是向右边的细胞发
- int[] cellHoles = holes[x][y][z]; //cellHoles是单个细胞的所有洞(触突),4个一组,前三个是洞的坐标,后一个是洞的大小
- if (cellHoles == null) //如洞不存在,不发送能量
- return;
- for (int i = 0; i < cellHoles.length / HOLE_ARR_SIZE; i++) {
- int n = i * HOLE_ARR_SIZE;
- float size = cellHoles[n + 3];
- if (size > 1) {
- addEng(cellHoles[n], cellHoles[n + 1], cellHoles[n + 2], e + cellHoles[n + 3] + cellHoles[n + 4]); //向源细胞反向发送常量大小的能量
- }
- }
- }
-
- public void holesReduce() {//所有hole大小都会慢慢减小,模拟触突连接随时间消失,即细胞的遗忘机制,这保证了系统不会被信息撑爆
- for (int x = 0; x < Env.BRAIN_SIZE - 1; x++)
- for (int y = 0; y < Env.BRAIN_SIZE - 1; y++)
- for (int z = 0; z < Env.BRAIN_SIZE - 1; z++) {
- int[] cellHoles = holes[x][y][z];
- if (cellHoles != null)
- for (int i = 0; i < cellHoles.length / HOLE_ARR_SIZE; i++) {
- int n = i * HOLE_ARR_SIZE;
- int size = cellHoles[n + 3];
- if (size > 0)
- cellHoles[n + 3] = (int) (size * 0.9);//要改成由基因调整
- int fresh = cellHoles[n + 4];
- if (fresh > 0)
- cellHoles[n + 4] -= Consts.HOLE_REDUCE;//要改成由基因调整
-
- }
- }
- }
-
}
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/Application.java b/core/src/main/java/com/gitee/drinkjava2/frog/Application.java
index 886ab80..f9e1622 100644
--- a/core/src/main/java/com/gitee/drinkjava2/frog/Application.java
+++ b/core/src/main/java/com/gitee/drinkjava2/frog/Application.java
@@ -18,6 +18,18 @@ import com.gitee.drinkjava2.frog.brain.Genes;
/**
* Application's main method start the program
+ * Application是程序入口
+ *
+ * 关于本项目代码格式化工具的约定:
+ * 1.不使用tab,而是使用空白符
+ * 2.源码采用UTF-8编码
+ * 3.源码换行设定为UNIX风格单个LF字符结尾。 git里设定git config --global core.autocrlf input,即提交时把CRLF改成单个LF字符,签出时不改
+ * 4.所有注释内容不允许被格式化,即:
+ * Never join lines 设为true,不允许自动合并注释行
+ * Enable Javadoc comment formatting 设为false
+ * Enable block comment formatting 设为false
+ * Enable line comment formatting 设为false
+ * 5.其他人提交时,只能修改自已修改的部分,不要随便使用代码格式化工具。如果要使用代码格式化工具,也必须参照以上内容设置成不能变动未修改的其它行。
*
* @author Yong Zhu
* @since 1.0
@@ -70,7 +82,7 @@ public class Application {
button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight);
ActionListener al = new ActionListener() {
@Override
- public void actionPerformed(ActionEvent arg0) {//显示或隐藏脑图
+ public void actionPerformed(ActionEvent arg0) {// 显示或隐藏脑图
Env.SHOW_FIRST_ANIMAL_BRAIN = !Env.SHOW_FIRST_ANIMAL_BRAIN;
checkIfShowBrainPicture(button);
}
@@ -112,7 +124,7 @@ public class Application {
label.setBounds(buttonXpos - 90, stopButton.getY() + 23, 100, buttonHeight);
mainFrame.add(label);
- //是否把egg文件存盘
+ // 是否把egg文件存盘
JCheckBox saveFileCheckBox = new JCheckBox("Save egg file");
saveFileCheckBox.setBounds(buttonXpos, Env.ENV_HEIGHT + 80, 120, 22);
ActionListener saveAction = new ActionListener() {
@@ -126,7 +138,7 @@ public class Application {
saveFileCheckBox.addActionListener(saveAction);
mainFrame.add(saveFileCheckBox);
- //基因维数显示控制
+ // 基因维数显示控制
for (int i = 0; i < Genes.GENE_NUMBERS; i++) {
JRadioButton geneRadio = new JRadioButton();
geneRadio.setBounds(buttonXpos + 300 + i * 16, Env.ENV_HEIGHT + 8, 20, 22);
@@ -145,7 +157,7 @@ public class Application {
mainFrame.add(geneRadio);
}
- //是否显示分裂过程
+ // 是否显示分裂过程
JCheckBox showSplitDetailCheckBox = new JCheckBox("Show split detail");
showSplitDetailCheckBox.setBounds(buttonXpos + 300, Env.ENV_HEIGHT + 40, 120, 22);
ActionListener detailAction = new ActionListener() {
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/Env.java b/core/src/main/java/com/gitee/drinkjava2/frog/Env.java
index 3de24af..7d442fc 100644
--- a/core/src/main/java/com/gitee/drinkjava2/frog/Env.java
+++ b/core/src/main/java/com/gitee/drinkjava2/frog/Env.java
@@ -5,8 +5,6 @@ import java.awt.Graphics;
import java.awt.Image;
import java.text.NumberFormat;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
import javax.swing.JPanel;
@@ -15,7 +13,7 @@ import com.gitee.drinkjava2.frog.egg.FrogEggTool;
import com.gitee.drinkjava2.frog.objects.EnvObject;
import com.gitee.drinkjava2.frog.objects.Food;
import com.gitee.drinkjava2.frog.objects.Material;
-import com.gitee.drinkjava2.frog.objects.OneDotEye;
+import com.gitee.drinkjava2.frog.objects.OneInputJudge;
import com.gitee.drinkjava2.frog.util.Logger;
import com.gitee.drinkjava2.frog.util.RandomUtils;
@@ -32,11 +30,11 @@ public class Env extends JPanel {
/** Speed of test */
public static int SHOW_SPEED = 1000; // 测试速度,-1000~1000,可调, 数值越小,速度越慢
- public static final int FROG_EGG_QTY = 300; // 每轮下n个青蛙蛋,可调,只有最优秀的前n个青蛙们才允许下蛋
+ public static final int FROG_EGG_QTY = 1000; // 每轮下n个青蛙蛋,可调,只有最优秀的前n个青蛙们才允许下蛋
- public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
+ public static final int FROG_PER_EGG = 6; // 每个青蛙蛋可以孵出几个青蛙
- public static final int SCREEN = 4; // 分几屏测完
+ public static final int SCREEN = 3; // 分几屏测完
/** Delete eggs at beginning of each run */
public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除以前保存的青蛙蛋文件,如果为false将加载旧蛋文件继续运行
@@ -46,7 +44,7 @@ public class Env extends JPanel {
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出青蛙落在地图上随机位置,而不是在蛋所在地
/** Frog's brain size */ // 脑细胞位于脑范围内,是个三维结构,在animal中用三维数组来表示
- public static final int BRAIN_SIZE =4; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
+ public static final int BRAIN_SIZE = 4; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
/** SHOW first animal's brain structure */
public static boolean SHOW_FIRST_ANIMAL_BRAIN = true; // 是否显示脑图在Env区的右侧
@@ -64,7 +62,7 @@ public class Env extends JPanel {
public static final int FROG_BRAIN_DISP_WIDTH = 400; // Frog的脑图在屏幕上的显示大小,可调
/** Steps of one test round */
- public static final int STEPS_PER_ROUND = 800;// 每轮测试步数,可调
+ public static final int STEPS_PER_ROUND = 200;// 每轮测试步数,可调
public static int step;// 当前测试步数
public static final int FOOD_QTY = 3000; // 食物数量, 可调
@@ -80,11 +78,11 @@ public class Env extends JPanel {
public static int[][] bricks = new int[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,见Material.java
- public static List frogs = new ArrayList<>(); // 这里存放所有待测的青蛙,可能分几次测完,由FROG_PER_SCREEN大小来决定
+ public static ArrayList frogs = new ArrayList<>(); // 这里存放所有待测的青蛙,可能分几次测完,由FROG_PER_SCREEN大小来决定
- public static List frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙,
+ public static ArrayList frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙,
- public static EnvObject[] things = new EnvObject[]{new OneDotEye()};// 所有外界物体,如食物、字母测试工具都放在这个things里面
+ public static EnvObject[] things = new EnvObject[] { new OneInputJudge() };// 所有外界物体,如食物、测试工具都放在这个things里面
public static boolean show_split_detail = false; //是否显示脑分裂的细节过程,即从一个细胞开始分裂分裂,而不是只显示分裂的最终结果
@@ -200,8 +198,7 @@ public class Env extends JPanel {
for (Frog f : frogs)
if (f.ateFood > maxFound)
maxFound = f.ateFood;
- return new StringBuilder("吃食率:").append(format100.format(Food.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Food.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound)
- .toString();
+ return new StringBuilder("吃食率:").append(format100.format(Food.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Food.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString();
}
public static void checkIfPause(int step) {
@@ -221,32 +218,39 @@ public class Env extends JPanel {
}
}
- public static Animal getShowAnimal() {
+ public static Animal getShowAnimal() { //取当前屏第一个青蛙
return frogs.get(current_screen * FROG_PER_SCREEN);
}
+ public static int round = 1;
public void run() {
- FrogEggTool.loadFrogEggs(); // 从磁盘加载蛙egg,或新建一批egg
+ FrogEggTool.loadFrogEggs(); // 首次运行时,从磁盘加载蛙egg,如加载失败就新建一批egg
Image buffImg = createImage(this.getWidth(), this.getHeight());
Graphics g = buffImg.getGraphics();
long time0;// 计时用
- int round = 1;
+ round = 1;
do {
rebuildFrogs(); // 根据蛙蛋重新孵化出蛙,注意基因变异有可能在孵化过程中发生
for (current_screen = 0; current_screen < SCREEN; current_screen++) {// 分屏测试,每屏FROG_PER_SCREEN个蛙
time0 = System.currentTimeMillis();
+
+ g.setColor(Color.white);
+ g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境
+ g.setColor(Color.BLACK);
for (EnvObject thing : things) // 创建食物、陷阱等物体
- thing.build();
+ thing.build(g);
+
boolean allDead = false;
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
f.initAnimal(); // 初始化器官延迟到这一步,是因为脑细胞太占内存,而且当前屏测完后会清空
}
+
for (step = 0; step < STEPS_PER_ROUND; step++) {
- for (EnvObject thing : things)// 调用食物、陷阱等物体的动作
- thing.active(current_screen, step);
if (allDead)
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
+ for (EnvObject thing : things)// 调用食物、陷阱等物体的动作
+ thing.active(current_screen, step, g);
allDead = true;
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
@@ -255,28 +259,18 @@ public class Env extends JPanel {
}
if (SHOW_SPEED == 1) // 如果speed为1,人为加入延迟
- sleep((100));
+ sleep(400);
else if (step % SHOW_SPEED != 0)// 用是否跳帧画图的方式来控制速度
continue;
- // 开始画虚拟环境和青蛙
- g.setColor(Color.white);
- g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境
- g.setColor(Color.BLACK);
- drawWorld(g);// 画整个虚拟环境
+ // 开始画things和青蛙
+ drawWorld(g);// 画整个虚拟环境中的material
+
for (int j = 0; j < FROG_PER_SCREEN; j++) { // 显示青蛙
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
- f.show(g);
+ f.showInEnv(g);
}
- if (SHOW_FIRST_ANIMAL_BRAIN) {// 在showAnimal上画一个红圈
- Animal showAnimal = getShowAnimal();
- if (showAnimal != null) {
- g.setColor(Color.red);
- g.drawArc(showAnimal.xPos - 15, showAnimal.yPos - 15, 30, 30, 0, 360);
- g.setColor(Color.BLACK);
- }
- }
if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0) //显示脑图是耗时操作,这个开关可以跳过一些脑图显示
Application.brainPic.drawBrainPicture(step);
if (SHOW_SPEED == 1 && SHOW_FIRST_ANIMAL_BRAIN) //如果速度为1,强制每步都显示脑图
@@ -287,17 +281,14 @@ public class Env extends JPanel {
if (SHOW_FIRST_ANIMAL_BRAIN) //一轮结束后再强制再显示脑图一次
Application.brainPic.drawBrainPicture(step);
checkIfPause(step);
- for (int j = 0; j < FROG_PER_SCREEN; j++) {
- Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
- }
+
StringBuilder sb = new StringBuilder("Round: ");
- sb.append(round).append(", screen:").append(current_screen).append(", speed:").append(Env.SHOW_SPEED).append(", ").append(", 用时: ").append(System.currentTimeMillis() - time0)
- .append("ms, ");
+ sb.append(round).append(", screen:").append(current_screen).append(", speed:").append(Env.SHOW_SPEED).append(", ").append(", 用时: ").append(System.currentTimeMillis() - time0).append("ms, ");
sb.append(foodAtedCount());
Application.mainFrame.setTitle(sb.toString());
for (EnvObject thing : things)// 去除食物、陷阱等物体
- thing.destory();
+ thing.destory(g);
}
round++;
FrogEggTool.layEggs(); //能量高的青蛙才有权下蛋
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java b/core/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java
index 316a1b0..1c27f3f 100644
--- a/core/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java
+++ b/core/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java
@@ -35,445 +35,462 @@ import com.gitee.drinkjava2.frog.util.Tree8Util;
*/
@SuppressWarnings("all")
public class BrainPicture extends JPanel {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L;
- private static final float D90 = (float) (Math.PI / 2);
+ private static final float D90 = (float) (Math.PI / 2);
- Color picColor = RED;
- int brainDispWidth; // screen display piexls width
- float scale; // brain scale
- int xOffset = 0; // brain display x offset compare to screen
- int yOffset = 0; // brain display y offset compare to screen
- float xAngle = D90 * .8f; // brain rotate on x axis
- float yAngle = D90 / 4; // brain rotate on y axis
- float zAngle = 0;// brain rotate on z axis
- int xMask = -1;// x Mask
- int yMask = -1;// y Mask
- BufferedImage buffImg;
- Graphics g;
- String note;
- public KeyAdapter keyAdapter;
+ Color picColor = RED;
+ int brainDispWidth; // screen display piexls width
+ float scale; // brain scale
+ int xOffset = 0; // brain display x offset compare to screen
+ int yOffset = 0; // brain display y offset compare to screen
+ float xAngle = D90 * .8f; // brain rotate on x axis
+ float yAngle = D90 / 4; // brain rotate on y axis
+ float zAngle = 0;// brain rotate on z axis
+ int xMask = -1;// x Mask
+ int yMask = -1;// y Mask
+ BufferedImage buffImg;
+ Graphics g;
+ String note;
+ public KeyAdapter keyAdapter;
- public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) {
- super();
- this.setLayout(null);// 空布局
- this.brainDispWidth = brainDispWidth;
- scale = 0.5f * brainDispWidth / brainWidth;
- this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1);
- buffImg = new BufferedImage(Env.FROG_BRAIN_DISP_WIDTH, Env.FROG_BRAIN_DISP_WIDTH, BufferedImage.TYPE_INT_RGB);
- g = buffImg.getGraphics();
- MouseAction act = new MouseAction(this);
- this.addMouseListener(act); // 添加鼠标动作监听
- this.addMouseWheelListener(act);// 添加鼠标滚轮动作监听
- this.addMouseMotionListener(act);// 添加鼠标移动动作监听
+ public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) {
+ super();
+ this.setLayout(null);// 空布局
+ this.brainDispWidth = brainDispWidth;
+ scale = 0.5f * brainDispWidth / brainWidth;
+ this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1);
+ buffImg = new BufferedImage(Env.FROG_BRAIN_DISP_WIDTH, Env.FROG_BRAIN_DISP_WIDTH, BufferedImage.TYPE_INT_RGB);
+ g = buffImg.getGraphics();
+ MouseAction act = new MouseAction(this);
+ this.addMouseListener(act); // 添加鼠标动作监听
+ this.addMouseWheelListener(act);// 添加鼠标滚轮动作监听
+ this.addMouseMotionListener(act);// 添加鼠标移动动作监听
- keyAdapter = new KeyAdapter() {// 处理t,f,l,r,x键盘命令
- @Override
- public void keyPressed(KeyEvent e) {
- switch (e.getKeyCode()){
- case KeyEvent.VK_UP:// Y切面向上
- yMask++;
- if (yMask > Env.BRAIN_SIZE)
- yMask = Env.BRAIN_SIZE;
- break;
- case KeyEvent.VK_DOWN:// Y切面向下
- yMask--;
- if (yMask < 0)
- yMask = 0;
- break;
- case KeyEvent.VK_LEFT:// x切面向左
- xMask--;
- if (xMask < 0)
- xMask = 0;
- break;
- case KeyEvent.VK_RIGHT:// x切面向右
- xMask++;
- if (xMask > Env.BRAIN_SIZE)
- xMask = Env.BRAIN_SIZE;
- break;
- case ' ':// 暂停及继续
- Application.pauseAction.actionPerformed(null);
- break;
- case 'T':// 顶视
- xAngle = 0;
- yAngle = 0;
- zAngle = 0;
- break;
- case 'F':// 前视
- xAngle = D90;
- yAngle = 0;
- zAngle = 0;
- break;
- case 'L':// 左视
- xAngle = D90;
- yAngle = D90;
- zAngle = 0;
- break;
- case 'R':// 右视
- xAngle = D90;
- yAngle = -D90;
- zAngle = 0;
- break;
- case 'X':// 斜视
- xAngle = D90 * .8f;
- yAngle = D90 / 4;
- zAngle = 0;
- break;
- default:
- }
- }
- };
- addKeyListener(keyAdapter);
- this.setFocusable(true);
- }
+ keyAdapter = new KeyAdapter() {// 处理t,f,l,r,x键盘命令
+ @Override
+ public void keyPressed(KeyEvent e) {
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_UP:// Y切面向上
+ yMask++;
+ if (yMask > Env.BRAIN_SIZE)
+ yMask = Env.BRAIN_SIZE;
+ break;
+ case KeyEvent.VK_DOWN:// Y切面向下
+ yMask--;
+ if (yMask < 0)
+ yMask = 0;
+ break;
+ case KeyEvent.VK_LEFT:// x切面向左
+ xMask--;
+ if (xMask < 0)
+ xMask = 0;
+ break;
+ case KeyEvent.VK_RIGHT:// x切面向右
+ xMask++;
+ if (xMask > Env.BRAIN_SIZE)
+ xMask = Env.BRAIN_SIZE;
+ break;
+ case ' ':// 暂停及继续
+ Application.pauseAction.actionPerformed(null);
+ break;
+ case 'T':// 顶视
+ xAngle = 0;
+ yAngle = 0;
+ zAngle = 0;
+ break;
+ case 'F':// 前视
+ xAngle = D90;
+ yAngle = 0;
+ zAngle = 0;
+ break;
+ case 'L':// 左视
+ xAngle = D90;
+ yAngle = D90;
+ zAngle = 0;
+ break;
+ case 'R':// 右视
+ xAngle = D90;
+ yAngle = -D90;
+ zAngle = 0;
+ break;
+ case 'X':// 斜视
+ xAngle = D90 * .8f;
+ yAngle = D90 / 4;
+ zAngle = 0;
+ break;
+ default:
+ }
+ }
+ };
+ addKeyListener(keyAdapter);
+ this.setFocusable(true);
+ }
- public void drawCuboid(float x, float y, float z, float xe, float ye, float ze) {// 在脑图上画一个长立方体框架,视角是TopView
- drawLine(x, y, z, x + xe, y, z);// 画立方体的下面边
- drawLine(x + xe, y, z, x + xe, y + ye, z);
- drawLine(x + xe, y + ye, z, x, y + ye, z);
- drawLine(x, y + ye, z, x, y, z);
+ public void drawCuboid(float x, float y, float z, float xe, float ye, float ze) {// 在脑图上画一个长立方体框架,视角是TopView
+ drawLine(x, y, z, x + xe, y, z);// 画立方体的下面边
+ drawLine(x + xe, y, z, x + xe, y + ye, z);
+ drawLine(x + xe, y + ye, z, x, y + ye, z);
+ drawLine(x, y + ye, z, x, y, z);
- drawLine(x, y, z, x, y, z + ze);// 画立方体的中间边
- drawLine(x + xe, y, z, x + xe, y, z + ze);
- drawLine(x + xe, y + ye, z, x + xe, y + ye, z + ze);
- drawLine(x, y + ye, z, x, y + ye, z + ze);
+ drawLine(x, y, z, x, y, z + ze);// 画立方体的中间边
+ drawLine(x + xe, y, z, x + xe, y, z + ze);
+ drawLine(x + xe, y + ye, z, x + xe, y + ye, z + ze);
+ drawLine(x, y + ye, z, x, y + ye, z + ze);
- drawLine(x, y, z + ze, x + xe, y, z + ze);// 画立方体的上面边
- drawLine(x + xe, y, z + ze, x + xe, y + ye, z + ze);
- drawLine(x + xe, y + ye, z + ze, x, y + ye, z + ze);
- drawLine(x, y + ye, z + ze, x, y, z + ze);
- }
+ drawLine(x, y, z + ze, x + xe, y, z + ze);// 画立方体的上面边
+ drawLine(x + xe, y, z + ze, x + xe, y + ye, z + ze);
+ drawLine(x + xe, y + ye, z + ze, x, y + ye, z + ze);
+ drawLine(x, y + ye, z + ze, x, y, z + ze);
+ }
- public void drawCentLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {//从细胞中点之间画一条线
- drawLine(px1 + 0.5f, py1 + 0.5f, pz1 + 0.5f, px2 + 0.5f, py2 + 0.5f, pz2 + 0.5f);
- }
+ public void drawCentLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {// 从细胞中点之间画一条线
+ drawLine(px1 + 0.5f, py1 + 0.5f, pz1 + 0.5f, px2 + 0.5f, py2 + 0.5f, pz2 + 0.5f);
+ }
- /*-
- 画线,固定以top视角的角度,所以只需要从x1,y1画一条到x2,y2的直线
- 绕 x 轴旋转 θ
- x, y.cosθ-zsinθ, y.sinθ+z.cosθ
-
- 绕 y 轴旋转 θ
- z.sinθ+x.cosθ, y, z.cosθ-x.sinθ
-
- 绕 z 轴旋转 θ
- x.cosθ-y.sinθ, x.sinθ+y.consθ, z
- -*/
- public void drawLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {
- double x1 = px1 - Env.BRAIN_SIZE / 2;
- double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
- double z1 = pz1 - Env.BRAIN_SIZE / 2;
- double x2 = px2 - Env.BRAIN_SIZE / 2;
- double y2 = -py2 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
- double z2 = pz2 - Env.BRAIN_SIZE / 2;
- x1 = x1 * scale;
- y1 = y1 * scale;
- z1 = z1 * scale;
- x2 = x2 * scale;
- y2 = y2 * scale;
- z2 = z2 * scale;
- double x, y, z;
- y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
- z = y1 * sin(xAngle) + z1 * cos(xAngle);
- y1 = y;
- z1 = z;
+ /*-
+ 画线,固定以top视角的角度,所以只需要从x1,y1画一条到x2,y2的直线
+ 绕 x 轴旋转 θ
+ x, y.cosθ-zsinθ, y.sinθ+z.cosθ
+
+ 绕 y 轴旋转 θ
+ z.sinθ+x.cosθ, y, z.cosθ-x.sinθ
+
+ 绕 z 轴旋转 θ
+ x.cosθ-y.sinθ, x.sinθ+y.consθ, z
+ -*/
+ public void drawLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {
+ double x1 = px1 - Env.BRAIN_SIZE / 2;
+ double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
+ double z1 = pz1 - Env.BRAIN_SIZE / 2;
+ double x2 = px2 - Env.BRAIN_SIZE / 2;
+ double y2 = -py2 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
+ double z2 = pz2 - Env.BRAIN_SIZE / 2;
+ x1 = x1 * scale;
+ y1 = y1 * scale;
+ z1 = z1 * scale;
+ x2 = x2 * scale;
+ y2 = y2 * scale;
+ z2 = z2 * scale;
+ double x, y, z;
+ y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
+ z = y1 * sin(xAngle) + z1 * cos(xAngle);
+ y1 = y;
+ z1 = z;
- x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
- // z = z1 * cos(yAngle) - x1 * sin(yAngle);
- x1 = x;
- // z1 = z;
+ x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
+ // z = z1 * cos(yAngle) - x1 * sin(yAngle);
+ x1 = x;
+ // z1 = z;
- x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
- y = x1 * sin(zAngle) + y1 * cos(zAngle);
- x1 = x;
- y1 = y;
+ x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
+ y = x1 * sin(zAngle) + y1 * cos(zAngle);
+ x1 = x;
+ y1 = y;
- y = y2 * cos(xAngle) - z2 * sin(xAngle);// 绕x轴转
- z = y2 * sin(xAngle) + z2 * cos(xAngle);
- y2 = y;
- z2 = z;
+ y = y2 * cos(xAngle) - z2 * sin(xAngle);// 绕x轴转
+ z = y2 * sin(xAngle) + z2 * cos(xAngle);
+ y2 = y;
+ z2 = z;
- x = z2 * sin(yAngle) + x2 * cos(yAngle);// 绕y轴转
- // z = z2 * cos(yAngle) - x2 * sin(yAngle);
- x2 = x;
- // z2 = z;
+ x = z2 * sin(yAngle) + x2 * cos(yAngle);// 绕y轴转
+ // z = z2 * cos(yAngle) - x2 * sin(yAngle);
+ x2 = x;
+ // z2 = z;
- x = x2 * cos(zAngle) - y2 * sin(zAngle);// 绕z轴转
- y = x2 * sin(zAngle) + y2 * cos(zAngle);
- x2 = x;
- y2 = y;
+ x = x2 * cos(zAngle) - y2 * sin(zAngle);// 绕z轴转
+ y = x2 * sin(zAngle) + y2 * cos(zAngle);
+ x2 = x;
+ y2 = y;
- g.setColor(picColor);
- g.drawLine((int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset, (int) round(x2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset,
- (int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
- }
+ g.setColor(picColor);
+ g.drawLine((int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset,
+ (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset,
+ (int) round(x2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset,
+ (int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
+ }
- /** 画点,固定以top视角的角度,所以只需要在x1,y1位置画一个点 */
- public void drawPoint(float px1, float py1, float pz1, float r) {
- double x1 = px1 - Env.BRAIN_SIZE / 2;
- double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
- double z1 = pz1 - Env.BRAIN_SIZE / 2;
- x1 = x1 * scale;
- y1 = y1 * scale;
- z1 = z1 * scale;
- double x, y, z;
- y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
- z = y1 * sin(xAngle) + z1 * cos(xAngle);
- y1 = y;
- z1 = z;
+ public void drawPointCent(float px1, float py1, float pz1, float r) {
+ drawPoint(px1+0.5f, py1+0.5f, pz1+0.5f, r);
+ }
+
+ /** 画点,固定以top视角的角度,所以只需要在x1,y1位置画一个点 */
+ public void drawPoint(float px1, float py1, float pz1, float r) {
+ double x1 = px1 - Env.BRAIN_SIZE / 2;
+ double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
+ double z1 = pz1 - Env.BRAIN_SIZE / 2;
+ x1 = x1 * scale;
+ y1 = y1 * scale;
+ z1 = z1 * scale;
+ double x, y, z;
+ y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
+ z = y1 * sin(xAngle) + z1 * cos(xAngle);
+ y1 = y;
+ z1 = z;
- x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
- // z = z1 * cos(yAngle) - x1 * sin(yAngle);
- x1 = x;
- // z1 = z;
+ x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
+ // z = z1 * cos(yAngle) - x1 * sin(yAngle);
+ x1 = x;
+ // z1 = z;
- x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
- y = x1 * sin(zAngle) + y1 * cos(zAngle);
- x1 = x;
- y1 = y;
+ x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
+ y = x1 * sin(zAngle) + y1 * cos(zAngle);
+ x1 = x;
+ y1 = y;
- g.setColor(picColor);
- g.fillOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
- round(r * scale));
- }
+ g.setColor(picColor);
+ g.fillOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f),
+ round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
+ round(r * scale));
+ }
- /** 画一个圆 */
- public void drawCircle(float px1, float py1, float pz1, float r) {//这个方法实际和上面的一样的,只是改成了drawOval
- double x1 = px1 - Env.BRAIN_SIZE / 2;
- double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
- double z1 = pz1 - Env.BRAIN_SIZE / 2;
- x1 = x1 * scale;
- y1 = y1 * scale;
- z1 = z1 * scale;
- double x, y, z;
- y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
- z = y1 * sin(xAngle) + z1 * cos(xAngle);
- y1 = y;
- z1 = z;
+ /** 画一个圆 */
+ public void drawCircle(float px1, float py1, float pz1, float r) {// 这个方法实际和上面的一样的,只是改成了drawOval
+ double x1 = px1 - Env.BRAIN_SIZE / 2;
+ double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
+ double z1 = pz1 - Env.BRAIN_SIZE / 2;
+ x1 = x1 * scale;
+ y1 = y1 * scale;
+ z1 = z1 * scale;
+ double x, y, z;
+ y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
+ z = y1 * sin(xAngle) + z1 * cos(xAngle);
+ y1 = y;
+ z1 = z;
- x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
- // z = z1 * cos(yAngle) - x1 * sin(yAngle);
- x1 = x;
- // z1 = z;
+ x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
+ // z = z1 * cos(yAngle) - x1 * sin(yAngle);
+ x1 = x;
+ // z1 = z;
- x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
- y = x1 * sin(zAngle) + y1 * cos(zAngle);
- x1 = x;
- y1 = y;
+ x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
+ y = x1 * sin(zAngle) + y1 * cos(zAngle);
+ x1 = x;
+ y1 = y;
- g.setColor(picColor);
- g.drawOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
- round(r * scale));
- }
+ g.setColor(picColor);
+ g.drawOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f),
+ round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
+ round(r * scale));
+ }
- public void drawText(float px1, float py1, float pz1, String text, float textSize) {
- double x1 = px1 - Env.BRAIN_SIZE / 2;
- double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
- double z1 = pz1 - Env.BRAIN_SIZE / 2;
- x1 = x1 * scale;
- y1 = y1 * scale;
- z1 = z1 * scale;
- double x, y, z;
- y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
- z = y1 * sin(xAngle) + z1 * cos(xAngle);
- y1 = y;
- z1 = z;
+ public void drawTextCenter(float px1, float py1, float pz1, String text, float textSize) {
+ drawText(px1 + 0.5f, py1 + 0.5f, pz1 + 0.5f, text, textSize);
+ }
- x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
- // z = z1 * cos(yAngle) - x1 * sin(yAngle);
- x1 = x;
- // z1 = z;
+ public void drawText(float px1, float py1, float pz1, String text, float textSize) {
+ double x1 = px1 - Env.BRAIN_SIZE / 2;
+ double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
+ double z1 = pz1 - Env.BRAIN_SIZE / 2;
+ x1 = x1 * scale;
+ y1 = y1 * scale;
+ z1 = z1 * scale;
+ double x, y, z;
+ y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
+ z = y1 * sin(xAngle) + z1 * cos(xAngle);
+ y1 = y;
+ z1 = z;
- x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
- y = x1 * sin(zAngle) + y1 * cos(zAngle);
- x1 = x;
- y1 = y;
+ x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
+ // z = z1 * cos(yAngle) - x1 * sin(yAngle);
+ x1 = x;
+ // z1 = z;
- g.setColor(picColor);
- g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) round(textSize * scale)));
- g.drawString(text, (int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
+ x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
+ y = x1 * sin(zAngle) + y1 * cos(zAngle);
+ x1 = x;
+ y1 = y;
- }
+ g.setColor(picColor);
+ g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) round(textSize * scale)));
+ g.drawString(text, (int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset,
+ (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
- public void drawBrainPicture(int step) {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
- if (!Env.SHOW_FIRST_ANIMAL_BRAIN)
- return;
- if (Env.show_split_detail)
- drawSplitDetail();
- else
- drawBrainStructure(step);
- }
+ }
- public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚,即从一个细胞开始分裂成最终脑结构的每一步
- Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
+ public void drawBrainPicture(int step) {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
+ if (!Env.SHOW_FIRST_ANIMAL_BRAIN)
+ return;
+ if (Env.show_split_detail)
+ drawSplitDetail();
+ else
+ drawBrainStructure(step);
+ }
- for (int i = Env.BRAIN_SIZE; i >= 1; i /= 2) {
- g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中
- g.fillRect(0, 0, brainDispWidth, brainDispWidth);
- g.setColor(BLACK); // 画边框
- g.drawRect(0, 0, brainDispWidth, brainDispWidth);
+ public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚,即从一个细胞开始分裂成最终脑结构的每一步
+ Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
- for (int geneIndex = 0; geneIndex < Genes.GENE_NUMBERS; geneIndex++) {
- ArrayList gene = a.genes.get(geneIndex);
- Tree8Util.knockNodesByGene(gene);
- for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
- if (Tree8Util.keep[j] > 0) {
- int[] node = Tree8Util.TREE8[j];
- int size = node[0];
- if (size == i && Genes.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
- setPicColor(ColorUtils.colorByCode(geneIndex));
- drawPoint(node[1] + size / 2, node[2] + size / 2, node[3] + size / 2, size * (0.5f - geneIndex * 0.05f));
- }
- }
- }
- }
- g.setColor(BLACK);
- drawCuboid(0, 0, 0, Env.BRAIN_SIZE, Env.BRAIN_SIZE, Env.BRAIN_SIZE);// 把脑的框架画出来
- this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
- if (!Env.show_split_detail)
- return;
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- }
- }
- }
+ for (int i = Env.BRAIN_SIZE; i >= 1; i /= 2) {
+ g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中
+ g.fillRect(0, 0, brainDispWidth, brainDispWidth);
+ g.setColor(BLACK); // 画边框
+ g.drawRect(0, 0, brainDispWidth, brainDispWidth);
- public void drawBrainStructure(int step) {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
- Animal a = Env.getShowAnimal(); // 显示第一个青蛙或蛇
- if (a == null || !a.alive)
- return;
- g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中
- g.fillRect(0, 0, brainDispWidth, brainDispWidth);
- g.setColor(BLACK); // 画边框
- g.drawRect(0, 0, brainDispWidth, brainDispWidth);
+ for (int geneIndex = 0; geneIndex < Genes.GENE_NUMBERS; geneIndex++) {
+ ArrayList gene = a.genes.get(geneIndex);
+ Tree8Util.knockNodesByGene(gene);
+ for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
+ if (Tree8Util.keep[j] > 0) {
+ int[] node = Tree8Util.TREE8[j];
+ int size = node[0];
+ if (size == i && Genes.display_gene[geneIndex]) {// 如果允许显示的话, 显示当前层级的节点
+ setPicColor(ColorUtils.colorByCode(geneIndex));
+ drawPoint(node[1] + size / 2, node[2] + size / 2, node[3] + size / 2,
+ size * (0.5f - geneIndex * 0.05f));
+ }
+ }
+ }
+ }
+ g.setColor(BLACK);
+ drawCuboid(0, 0, 0, Env.BRAIN_SIZE, Env.BRAIN_SIZE, Env.BRAIN_SIZE);// 把脑的框架画出来
+ this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
+ if (!Env.show_split_detail)
+ return;
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
- for (int z = 0; z < Env.BRAIN_SIZE; z++) {
- for (int y = Env.BRAIN_SIZE - 1; y >= 0; y--) {
- for (int x = Env.BRAIN_SIZE - 1; x >= 0; x--) {
- long cell = a.cells[x][y][z];
- // if (cell == 0) //只显示有效的细胞点
- // continue;
+ public void drawBrainStructure(int step) {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
+ Animal a = Env.getShowAnimal(); // 显示第一个青蛙或蛇
+ if (a == null || !a.alive)
+ return;
+ g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中
+ g.fillRect(0, 0, brainDispWidth, brainDispWidth);
+ g.setColor(BLACK); // 画边框
+ g.drawRect(0, 0, brainDispWidth, brainDispWidth);
- int[] holes = a.holes[x][y][z];
- if (holes != null) {
- setPicColor(Color.GRAY);
- for (int i = 0; i < holes.length / Animal.HOLE_ARR_SIZE; i++) {//这里画出hole连线
- int n = i * Animal.HOLE_ARR_SIZE;
- drawCentLine(x, y, z, holes[n], holes[n + 1], holes[n + 2]);
- }
- }
+ for (int z = 0; z < Env.BRAIN_SIZE; z++) {// 画它所有的脑细胞位置和颜色
+ for (int y = Env.BRAIN_SIZE - 1; y >= 0; y--) {
+ for (int x = Env.BRAIN_SIZE - 1; x >= 0; x--) {
+ setPicColor(BLACK); // 画边框
+ drawPointCent(x, y, z, 0.03f); //画每个细胞小点
+
+ long cell = a.cells[x][y][z];
+ // if (cell == 0) //只显示有效的细胞点
+ // continue;
- if (x >= xMask && y >= yMask && cell != 0)//画出细胞每个基因存在的细胞格子
- for (int geneIndex = 0; geneIndex < Genes.GENE_NUMBERS; geneIndex++) {
- if ((cell & (1 << geneIndex)) != 0 && Genes.display_gene[geneIndex]) {
- setPicColor(ColorUtils.colorByCode(geneIndex)); //开始画出对应的细胞基因参数,用不同颜色直径圆表示
- //setPicColor(Color.RED);
- //drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, geneIndex == 0 ? 0.8f : 0.5f - geneIndex * 0.05f);
- drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, 0.6f);
- }
- }
- float e = a.energys[x][y][z];
- if (e > 1f || e < -1f) {
- setPicColor(e > 0 ? Color.RED : Color.BLUE); //用红色小圆表示正能量,蓝色表示负能量
- drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, 0.2f);
- float size = (float) (0.5f + 0.4 * Math.log10(Math.abs(e)));//再用不同大小圆形表示不同能量值
- drawCircle(x + 0.5f, y + 0.5f, z + 0.5f, size);
- }
+ if (x >= xMask && y >= yMask && cell != 0)// 画出细胞每个基因存在的细胞格子
+ for (int geneIndex = 0; geneIndex < Genes.GENE_NUMBERS; geneIndex++) {
+ if ((cell & (1 << geneIndex)) != 0 && Genes.display_gene[geneIndex]) {
+ setPicColor(ColorUtils.colorByCode(geneIndex)); // 开始画出对应的细胞基因参数,用不同颜色圆表示
+ drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, 0.3f);
+ }
+ }
+ float e = a.energys[x][y][z];
+ if (e > 0.03f || e < -0.03f) {
+ setPicColor(e > 0 ? Color.red : Color.BLUE); // 用红色小圆表示正能量,蓝色表示负能量
+ float size = Math.abs(e);// 再用不同大小圆形表示不同能量值
+ if (size > 1)
+ size = 1;
+ drawCircle(x + 0.5f, y + 0.5f, z + 0.5f, size);
+ }
- }
- }
- }
+ }
+ }
+ }
- setPicColor(Color.BLACK);
- drawCuboid(0, 0, 0, Env.BRAIN_SIZE, Env.BRAIN_SIZE, Env.BRAIN_SIZE);// 把脑的框架画出来
+ setPicColor(Color.BLACK); //画出 a.lines里所有线条
+ Line.drawOnBrainPicture(a, this);
- setPicColor(BLACK); //把x,y,z坐标画出来
- drawText(Env.BRAIN_SIZE, 0, 0, "x", Env.BRAIN_SIZE * 0.2f);
- drawText(0, Env.BRAIN_SIZE, 0, "y", Env.BRAIN_SIZE * 0.2f);
- drawText(0, 0, Env.BRAIN_SIZE, "z", Env.BRAIN_SIZE * 0.2f);
- setPicColor(RED);
- drawLine(0, 0, 0, Env.BRAIN_SIZE, 0, 0);
- drawLine(0, 0, 0, 0, Env.BRAIN_SIZE, 0);
- drawLine(0, 0, 0, 0, 0, Env.BRAIN_SIZE);
+ for (Object[] o : Genes.dots) { // 画出所有登记的点的名字
+ String name = (String) o[0];
+ int x = (int) o[1];
+ int y = (int) o[2];
+ int z = (int) o[3];
+ drawTextCenter(x, y, z, name, 0.3f);
+ }
- g.setColor(Color.black);
- if (note != null) {// 全局注释
- g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
- g.drawString(note, 10, 20);
- }
+ drawCuboid(0, 0, 0, Env.BRAIN_SIZE, Env.BRAIN_SIZE, Env.BRAIN_SIZE);// 把脑的框架画出来
- g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
- g.drawString("step:" + step + ", ate:" + a.ateFood + ", wrong:" + a.ateWrong, 10, 15);
+ setPicColor(BLACK); // 把x,y,z坐标画出来
+ drawText(Env.BRAIN_SIZE, 0, 0, "x", Env.BRAIN_SIZE * 0.2f);
+ drawText(0, Env.BRAIN_SIZE, 0, "y", Env.BRAIN_SIZE * 0.2f);
+ drawText(0, 0, Env.BRAIN_SIZE, "z", Env.BRAIN_SIZE * 0.2f);
+ setPicColor(RED);
+ drawLine(0, 0, 0, Env.BRAIN_SIZE, 0, 0);
+ drawLine(0, 0, 0, 0, Env.BRAIN_SIZE, 0);
+ drawLine(0, 0, 0, 0, 0, Env.BRAIN_SIZE);
- // for (int y = 0; y < ColorUtils.rainbow.length; y += 1) {//调试彩虹色
- // g.setColor(ColorUtils.rainbow[y]);
- // for (int i = 0; i < 9; i++)
- // g.drawLine(0, y * 9 + i, 50, y * 9 + i);
- // }
+ g.setColor(Color.black);
+ if (note != null) {// 全局注释
+ g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
+ g.drawString(note, 10, 20);
+ }
- this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
- }
+ g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
+ g.drawString("step:" + step + ", ate:" + a.ateFood + ", wrong:" + a.ateWrong+", miss:" + a.ateMiss+", fat="+a.fat, 10, 15);
- public static void setNote(String note) {
- Application.brainPic.note = note;
- }
+ // for (int y = 0; y < ColorUtils.rainbow.length; y += 1) {//调试彩虹色
+ // g.setColor(ColorUtils.rainbow[y]);
+ // for (int i = 0; i < 9; i++)
+ // g.drawLine(0, y * 9 + i, 50, y * 9 + i);
+ // }
- // getters & setters
- public float getScale() {
- return scale;
- }
+ this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
+ }
- public void setScale(float scale) {
- this.scale = scale;
- }
+ public static void setNote(String note) {
+ Application.brainPic.note = note;
+ }
- public float getxAngle() {
- return xAngle;
- }
+ // getters & setters
+ public float getScale() {
+ return scale;
+ }
- public void setxAngle(float xAngle) {
- this.xAngle = xAngle;
- }
+ public void setScale(float scale) {
+ this.scale = scale;
+ }
- public float getyAngle() {
- return yAngle;
- }
+ public float getxAngle() {
+ return xAngle;
+ }
- public void setyAngle(float yAngle) {
- this.yAngle = yAngle;
- }
+ public void setxAngle(float xAngle) {
+ this.xAngle = xAngle;
+ }
- public float getzAngle() {
- return zAngle;
- }
+ public float getyAngle() {
+ return yAngle;
+ }
- public void setzAngle(float zAngle) {
- this.zAngle = zAngle;
- }
+ public void setyAngle(float yAngle) {
+ this.yAngle = yAngle;
+ }
- public void setPicColor(Color color) {
- this.picColor = color;
- }
+ public float getzAngle() {
+ return zAngle;
+ }
- public Color getPicColor() {
- return picColor;
- }
+ public void setzAngle(float zAngle) {
+ this.zAngle = zAngle;
+ }
- public int getxOffset() {
- return xOffset;
- }
+ public void setPicColor(Color color) {
+ this.picColor = color;
+ }
- public void setxOffset(int xOffset) {
- this.xOffset = xOffset;
- }
+ public Color getPicColor() {
+ return picColor;
+ }
- public int getyOffset() {
- return yOffset;
- }
+ public int getxOffset() {
+ return xOffset;
+ }
- public void setyOffset(int yOffset) {
- this.yOffset = yOffset;
- }
+ public void setxOffset(int xOffset) {
+ this.xOffset = xOffset;
+ }
+
+ public int getyOffset() {
+ return yOffset;
+ }
+
+ public void setyOffset(int yOffset) {
+ this.yOffset = yOffset;
+ }
}
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java b/core/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java
new file mode 100644
index 0000000..464dc11
--- /dev/null
+++ b/core/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 the original author or authors.
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ */
+package com.gitee.drinkjava2.frog.brain;
+
+/**
+ * Cell is a basic node of brain 3d array
+ *
+ * 从效率的角度出发,Line、Cell这两个对象将来可能都不实际创建,因为Java中对象的操作比数组更占用内存和影响速度,
+ * 所以Cell和Line里尽量只放一些文档、静态方法,以便以后采用数组来代替Cell对象或Line对象,尤其是Line可能用计算机模拟根本不需要分配内存,是个虚对象。
+ *
+ *
+ * 关于Cell的特性:
+ * 1.Cell相当于一个脑神经元细胞的细胞主体部分,能量只保存在主体上,只存贮正值, 在0~1之间,传入的多余的能量将削除
+ * 2.Cell如果有能量,能量会随时间消逝,随时间消逝的能量曲线是个属性,不同种类的Cell这个属性是不同的
+ * 3.Cell激活后,给每个树突轴突(Line)发送等同自身能量的能量,注意不是均分,而是每个都拷贝一份等量的能量。(此处能量不守恒,由它的上层计算机系统注入能量即熵)。
+ * 4.Cell一直给Line发送能量,但是否能量被传送、能量传送后是否扣除影响细胞主体能量?这些都不由Cell考虑,而是由Line的属性和行为来决定,Line是复杂的。
+ * 同一个Line接收激活的Cell能量,有一个再次传送给间隔时间, 这是由这个Line的阀值特性、Cell的能量下降曲线、Line的能量扣除值来决定的。
+ *
+ * Cell可以看出来非常简单,比树突、轴突要简单的多,就是一个能量暂存、放大(拷贝)、消逝、分发节点。而树突、轴突(统一用Line来表示)有复杂的行为,但原则上不保存能量。Cell和Line分工
+ * 协作,一个保存能量,一个传输能量。 Line的种类有很多,今后分裂算法的主要任务就是进行Line种类的空间分配。
+ *
+ * ======== Line可以是个虚对象! =========
+ * 为什么Line不保存能量?因为如果不保存能量,Line就是无状态的,甚至可以不创建Line实体或数组,不需要给Line分配内存,将Line作为Cell的一个行为即可,能量到了Cell后,根据它有
+ * 多少个和多少种Line属性,进行相应的能量分发行为,影响周围或近或远的Cell能量。
+ * 打个比方比如
+ * "6叉Line属性"会对四周的细胞发送能量,“特长上Line属性”会对上方100个细胞间隔的细胞发送能量,这个行为实际上并不需要创建Line对象或给它分配内存,所以Line可以
+ * 是一种虚对象, 作为Cell的一种属性存在(即在表示Cell的长整数中占据一个字节的标志位,而这个标志位又由分裂算法的基因决定)。
+ * 世上的道理是相通的,如果一个数据结据在电脑里能简化编程,实际生物细胞也可能采用同样的方案。
+ *
+ * 总体来说,脑是简单的,决定它结构的熵并不多(一颗人类受精卵约包含750MB的信息),所以受精卵里并不记录每个细胞、每个连线的位置,而是大致决定有多少种类细胞(每类细胞上有相似的连线),然后交给分裂算法来
+ * 生成海量的细胞,但是这个脑的复杂性与细胞数量无关,这个复杂性即熵量仅仅是由这750MB还要去除与脑结构不相关的其它部分的信息来决定的,脑本身的复杂度可能定义为"约50MB信息控制的100亿细胞的分形结构"。
+ *
+ * @author Yong Zhu
+ * @since 1.0
+ */
+public class Cell {
+}
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/brain/Consts.java b/core/src/main/java/com/gitee/drinkjava2/frog/brain/Consts.java
deleted file mode 100644
index 9a9647b..0000000
--- a/core/src/main/java/com/gitee/drinkjava2/frog/brain/Consts.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
- * applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
- * OF ANY KIND, either express or implied. See the License for the specific
- * language governing permissions and limitations under the License.
- */
-package com.gitee.drinkjava2.frog.brain;
-
-import static com.gitee.drinkjava2.frog.util.RandomUtils.percent;
-
-import java.lang.reflect.Field;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import com.gitee.drinkjava2.frog.Animal;
-import com.gitee.drinkjava2.frog.util.Logger;
-import com.gitee.drinkjava2.frog.util.RandomUtils;
-
-/**
- * Here store counts
- *
- * 这个类存放脑常量定义、变异、日志打印相关的方法。
- * 神经网络中有一些全局常量,与结构生成无关,这时可以把所有常量定义到animal和egg的constGenes常量数组中,用统一的随机方法来变异这些常量
- *
- * @author Yong Zhu
- * @since 15.0
- */
-@SuppressWarnings("all")
-public class Consts {
- public static int CountsQTY; //总常量数量
-
- private static int index_ = 0;
-
- private static int index() {
- return index_++;
- }
-
- public static final int ADD_EYE = index(); //用index()这种编程技巧而不是直接给定数值是为了增删常量定义时比较方便,不会影响其它行
- public static final int ADD_BITE = index();
- public static final int REDUCE_BITE = index();
- public static final int HOLE_FRESH = index();
- public static final int HOLE_REDUCE = index();
-
- private static Map values = new LinkedHashMap();
-
- static {
- try {
- Class c = Consts.class;
- Field[] fs = c.getDeclaredFields();
- for (Field f : fs) { // 用反射来获取常量的名称并保存下来,将来在printLog中要按顺序打印出所有常量名
- if (int.class.equals(f.getType()) && !"LENGTH".equals(f.getName()) && !"index_".equals(f.getName())) {
- values.put(f.getName(), f.getInt(null));
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(-1);
- }
- CountsQTY = values.size();
- }
-
- public static boolean[] exist = new boolean[CountsQTY]; //不是每个常量组数都用到,只有被用字母代表的才会用到并在这里标记,这种方法比MAP要快
-
- static StringBuilder sb = new StringBuilder();
-
- public static void printLog(Animal a) {
- sb.setLength(0);
- int i = 0;
- for (Entry e : values.entrySet()) {
- sb.append(e.getKey()).append("=").append(a.consts[e.getValue()]).append("\t\t");
- if (i++ % 6 == 5)
- sb.append("\n");
- }
- Logger.debug(sb.toString());
- }
-
- public static void constMutation(Animal a) { //全局参数变异, 这一个方法变异动物的所有常量
- for (int i = 0; i < CountsQTY; i++) {
- if (percent(20))
- a.consts[i] = RandomUtils.vary(a.consts[i]);
- }
- }
-
-}
diff --git a/core/src/main/java/com/gitee/drinkjava2/frog/brain/Genes.java b/core/src/main/java/com/gitee/drinkjava2/frog/brain/Genes.java
index 1f9bc7b..0432bd2 100644
--- a/core/src/main/java/com/gitee/drinkjava2/frog/brain/Genes.java
+++ b/core/src/main/java/com/gitee/drinkjava2/frog/brain/Genes.java
@@ -10,18 +10,15 @@
*/
package com.gitee.drinkjava2.frog.brain;
-import static com.gitee.drinkjava2.frog.brain.Consts.ADD_BITE;
-import static com.gitee.drinkjava2.frog.brain.Consts.REDUCE_BITE;
+import java.util.ArrayList;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
-import com.gitee.drinkjava2.frog.objects.OneDotEye;
-import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Genes代表不同的脑细胞参数,对应每个参数,用8叉/4叉/2叉树算法给每个细胞添加细胞参数和行为。
- * 每个脑细胞用一个long来存储,所以目前最多允许64个基因位, 多字节参数可以由多个基因位决定。每个基因位都由一个单独的阴阳8/4/2叉树控制,多个基因就组成了一个8/4/2叉树阵列
- * 基因+分裂算法=结构
+ * 每个脑细胞用一个long来存储,所以目前最多允许64个基因位,
+ * 多字节参数可以由多个基因位决定。每个基因位都由一个单独的阴阳8/4/2叉树控制,多个基因就组成了一个8/4/2叉树阵列 基因+分裂算法=结构
* 基因+分裂算法+遗传算法=结构的进化
*
* 这个类里定义每个基因位的掩码以及对应基因的细胞行为, 脑结构的所有参数,都要用基因来控制。开始时可以有常量、魔数,但以后都放到基因里去自动进化。
@@ -30,31 +27,50 @@ import com.gitee.drinkjava2.frog.util.RandomUtils;
* @since 10.0
*/
@SuppressWarnings("all")
-public class Genes { //Genes登记所有的基因, 指定每个基因允许分布的空间范围。注意登录完后还要并针对每个基因在active方法里写出它对应的细胞行为
- public static int GENE_MAX = 64; //目前最多允许64个基因
+public class Genes { // Genes登记所有的基因, 指定每个基因允许分布的空间范围。注意登录完后还要并针对每个基因在active方法里写出它对应的细胞行为
+ public static int GENE_MAX = 64; // 目前最多允许64个基因
- public static int GENE_NUMBERS = 0; //这里统计定义了多少个基因
- private static int zeros = 0; //当前基因位掩码0个数
+ public static int GENE_NUMBERS = 0; // 这里统计定义了多少个基因
+ private static int zeros = 0; // 当前基因位掩码0个数
- public static boolean[] display_gene = new boolean[GENE_MAX]; //如果这个参数为真,此基因显示在脑图上
- public static boolean[] fill_gene = new boolean[GENE_MAX]; //如果这个参数为真,此基因填充指定的区域,而不是由分裂算法随机生成
+ public static boolean[] display_gene = new boolean[GENE_MAX]; // 如果这个参数为真,此基因显示在脑图上
+ public static boolean[] fill_gene = new boolean[GENE_MAX]; // 如果这个参数为真,此基因填充指定的区域,而不是由分裂算法随机生成
- public static int[] xLimit = new int[GENE_MAX]; //用来手工限定基因分布范围,详见register方法
+ public static int[] xLimit = new int[GENE_MAX]; // 用来手工限定基因分布范围,详见register方法
public static int[] yLimit = new int[GENE_MAX];
public static int[] zLimit = new int[GENE_MAX];
+ public static ArrayList