Done yin yang algorithm, and copy to hsitory\009c

This commit is contained in:
yong 2022-01-15 21:28:19 -07:00
parent 02f450ed40
commit 35dc9d06c9
76 changed files with 5915 additions and 71 deletions

View File

@ -166,6 +166,17 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
这个动画的每一帧是细胞分裂到最小不可再分的最终结果而且是从400个青蛙中生存下来的最佳个体这就是遗传算法遗传算法就是穷举法。这个16x16x16的大立方体要理解成第一个细胞只是画的大了而已。以后等有时间可以做1个细胞分成8个8个变64个的动画能更好地演示分裂的中间过程。
细胞分裂研究到此结束下面要开始生成神经网络空间结构了。我的思路是脑结构也无非就是三维细胞的空间排布而已细胞有各种参数比如触突长度、方向、密度、信号收发阀值、信号强度、信号遗忘曲线等只要每个细胞不超过64个构造参数就可以用分裂算法来随机试错把神经网络的空间结构给试出来。分裂算法的优点是遵循从主干到细节的生成次序如果要完成的任务(即外界信号输入输出)也是从简单到复杂,就可能正好符合这个脑的空间结构生成顺序。
2022-01-03 多参数的细胞分裂的小改进
位于history\009b目录下与009a分支相比算法是相同的只是作了以下一些小改动
1.可增加颜色 2.添加存盘选择框,可以在运行期选择存盘 3.添加每维参数分别显示的选择框 4.将颜色参数与细胞位置参数产生关联 5.新增了上次提到的显示分裂过程动画图,见下图:
![result16](result16_cell_split.gif)
因为参数之间有关联,更容易发生缺色现象,这是因为进化过程中,主要参数(细胞位置)的进化会导致次要参数的分支被误删,然后就很难再补回来了。为了解决这个问题,下一个版本打算改进算法,采用黑白节点的方式,黑节点删除节点以下的细胞,白节点保留节点以下的细胞。
细胞分裂研究算法目前还不能结束(打脸自己),还要先解决这个缺色问题。多参数的进化,如果一旦某个参数被误删除就不能再进化回来,这种算法是不能接受的。
2022-01-15 多参数的细胞分裂继续改进:阴阳无极八卦阵算法
位于history\009c目录下采用了阴阳(黑白)节点算法阴节点基因会删除节点下所有节点是自顶向下的减材加工阳节点基因会保留节点下所有节点是自底向上的增材加工。利用遗传算法的大样本筛选把自顶向下和自底向上两个进化方向结合起来这样基本能解决误删分支后缺色不能补回这个问题。而且对于奖罚不再象以前一样要设成差距很大的值animal.java中awardAAAA()原来要设成8000, 现在设成20也不会产生缺色现象。这个版本是研究技术细节问题看不懂的同学们可以跳过。
考虑到这个算法的特点我给它起名“阴阳无极八卦阵算法“阴阳是指它有阴阳两种节点无极是指它的分裂阶数没有限制八卦阵是指它采用了多个8叉树结构每一维细胞参数都对应一个8叉树。
## 运行方式 | Run
运行core或history各个子目录下的run.bat批处理文件即可启动运行history下有多个子目录按版本号顺序排列存放着这个项目演化过程中的主要历史版本供演示。

View File

@ -1,6 +1,5 @@
## core目录简介
core目录是当前工作目录如果跑出什么结果就会拷贝一份放到history目录里存档。
原来core分为bottom_up和top_down两个目录从这版起还是恢复成一个目录以集中精力不管是手工算法试验还是用细胞分裂自动生成脑结构都放在core一个目录里切换时从history里拷贝一份来接着工作即可。
当前目标是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务
当前目标是大方向是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务。当前小目标是要利用阴阳无极八卦阵算法进化出第一个可以工作(向食物运动)的神经网络。

View File

@ -7,7 +7,7 @@
<version>10.0</version>
<name>frog</name>
<description>当前目标是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务</description>
<description>当前目标是大方向是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务</description>
<url>https://gitee.com/drinkjava2/jsqlbox/frog</url>
<issueManagement>

View File

@ -21,28 +21,26 @@ import java.util.ArrayList;
import javax.imageio.ImageIO;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.judge.BrainRainbowColorJudge;
import com.gitee.drinkjava2.frog.judge.BrainShapeJudge;
import com.gitee.drinkjava2.frog.judge.RainBowFishJudge;
import com.gitee.drinkjava2.frog.objects.Material;
import com.gitee.drinkjava2.frog.util.RandomUtils;
import com.gitee.drinkjava2.frog.util.Tree8Util;
/**
* Animal is all artificial lives' father class
*
* Animal是所有动物青蛙蛇等的父类, animal是由蛋孵出来的蛋里保存着脑细胞结构生成的基因
* genes是一个list<list>结构, 每一条list代表一条由深度树方式存储的基因树分表控制细胞的一个参数用cells长整的一位表示比如genes.get(0)是控制细胞的存在即cells三维数组的元素的最低位
* Animal only keep one copy of genes from egg, not store gene in cell
* Animal是所有动物青蛙蛇等的父类, animal是由蛋孵出来的蛋里保存着脑细胞结构生成的基因, Animal只保存一份基因而不是每个细胞都保存一份基因这是人工生命与实际生物的最大不同
* 基因是一个list<list>结构, 每一条list代表一条由深度树方式存储的基因树分表控制细胞的一个参数当cell用长整数表示时最多可以表达支持64个参数
*
*
* @author Yong Zhu
*
* @since 1.0
*/
public abstract class Animal {// 这个程序大量用到public变量而不是getter/setter主要是为了编程方便和简洁但缺点是编程者需要小心维护各个变量
public static BufferedImage FROG_IMAGE;
public static BufferedImage snakeImage;
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>(); // Animal的基因只保存一份这是人工生命与实际生物每个细胞都保留一份基因的最大不同
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>(); // 基因是多个数列有点象多条染色体
static {
try {
@ -58,7 +56,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public int x; // animal在Env中的x坐标
public int y; // animal在Env中的y坐标
public long energy = 100000; // 青蛙的能量为0则死掉
public long energy = 1000000000; // 青蛙的能量为0则死掉
public boolean alive = true; // 设为false表示青蛙死掉了将不参与计算和显示以节省时间
public int ateFood = 0; // 青蛙曾吃过的食物总数下蛋时如果两个青蛙能量相等可以比数量
public int no; // 青蛙在Env.animals中的序号从1开始 会在运行期写到当前brick的最低位可利用Env.animals.get(no-1)快速定位青蛙
@ -68,12 +66,12 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public Animal(Egg egg) {// x, y 是虑拟环境的坐标
for (int i = 0; i < GENE_NUMBERS; i++) {
ArrayList<Integer> gene = new ArrayList<>();
genes.add(gene);
genes.add(new ArrayList<>());
}
int i = 0;
for (ArrayList<Integer> gene : egg.genes) //动物的基因是蛋的基因的拷贝
for (ArrayList<Integer> gene : egg.genes)//动物的基因是蛋的基因的拷贝
genes.get(i++).addAll(gene);
i = 0;
if (Env.BORN_AT_RANDOM_PLACE) { //是否随机出生在地图上?
x = RandomUtils.nextInt(Env.ENV_WIDTH);
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
@ -93,9 +91,11 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步这个方法是在当前屏animal生成之后调用比方说有一千个青蛙分为500屏测试每屏只生成2个青蛙的脑细胞可以节约内存
geneMutation(); //有小概率基因突变
for (ArrayList<Integer> gene : genes) //基因多也要适当小扣点分防止基因无限增长
energy -= gene.size();
createCellsFromGene(); //运行基因语言生成脑细胞
BrainShapeJudge.judge(this); //外界判断对这个动物打分
BrainRainbowColorJudge.judge(this);
RainBowFishJudge.judge(this); //外界对是否长得象彩虹鱼打分
// FlowerJudge.judge(this);//外界对是否长得象小花儿打分
}
private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 5000;
@ -109,15 +109,16 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
if (energy < MIN_ENERGY_LIMIT)
energy = MIN_ENERGY_LIMIT;
}
public void awardAAAA() { changeEnergy(8000);}
public void awardAAA() { changeEnergy(1000);}
public void awardAA() { changeEnergy(100);} //TODO:如果改为20就可能出现缺色所以下面要用细胞8叉树从底向上扩张的算法把缺色补上
//如果改奖罚值就可能出现缺色这个要在基因变异算法从上到下从下到上和环境本身奖罚合理性上下功夫
public void awardAAAA() { changeEnergy(20);}
public void awardAAA() { changeEnergy(10);}
public void awardAA() { changeEnergy(5);}
public void awardA() { changeEnergy(2);}
public void penaltyAAAA() { changeEnergy(-8000);}
public void penaltyAAA() { changeEnergy(-1000);}
public void penaltyAA() { changeEnergy(-100);}
public void penaltyAAAA() { changeEnergy(-20);}
public void penaltyAAA() { changeEnergy(-10);}
public void penaltyAA() { changeEnergy(-5);}
public void penaltyA() { changeEnergy(-2);}
public void kill() { this.alive = false; changeEnergy(-5); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
//@formatter:on
@ -151,14 +152,33 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
}
public void geneMutation() { //基因变异,注意这一个算法同时变异所有条基因目前最多允许64条基因
for (int g = 0; g < GENE_NUMBERS; g++) {//依次对每条基因对应的参数在相应的细胞处把细胞参数位置1
if (RandomUtils.percent(10)) { //随机新增基因, 在基因里插入一个8叉树位置号,表示这个位置的8叉树整个节点会被敲除
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阴节点基因
if (RandomUtils.percent(10)) {
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记
int randomIndex = RandomUtils.nextInt(Tree8Util.ENABLE_NODE_QTY);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记下面的算法保证阴节点基因只添加阳节点上
int randomIndex = RandomUtils.nextInt(Tree8Util.keepNodeQTY);
int count = -1;
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {
if (Tree8Util.ENABLE[i]) {
if (Tree8Util.keep[i] >= 0) {
count++;
if (count >= randomIndex && !gene.contains(-i)) {
gene.add(-i);
break;
}
}
}
}
}
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阳节点基因
if (RandomUtils.percent(5)) {
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记下面的算法保证阳节点基因只添加在阴节点上
int yinNodeQTY = Tree8Util.NODE_QTY - Tree8Util.keepNodeQTY; //阴节点总数
int randomIndex = RandomUtils.nextInt(yinNodeQTY);
int count = -1;
for (int i = 0; i < yinNodeQTY; i++) {
if (Tree8Util.keep[i] < 0) {
count++;
if (count >= randomIndex && !gene.contains(i)) {
gene.add(i);
@ -169,8 +189,29 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
}
}
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因
if (RandomUtils.percent(3)) {
// for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异将阳节点向上提升一级相当于单个细胞的自底向上扩散式生长
// if (RandomUtils.percent(3)) {
// ArrayList<Integer> gene = genes.get(g);
// int randomIndex = RandomUtils.nextInt(gene.size());
// if (randomIndex > 0 && gene.get(randomIndex) > 0) {//如基因是阳基因且节点不是顶节点
// int size = Tree8Util.TREE8[randomIndex][0];
// gene.remove(randomIndex); //先删除底层这个阳基因
// for (int i = randomIndex - 1; i > 0; i--) {
// if (Tree8Util.TREE8[i][0] > size) { //深度树只要大于size就是它的父节点
// if (!gene.contains(i))
// gene.add(i);
// int x = gene.indexOf(-i);//如果有阴节点也删除
// if (x > 0)
// gene.remove(x);
// break;
// }
// }
// }
// }
// }
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因这样可以去除无用的拉圾基因防止基因无限增大
if (RandomUtils.percent(10)) {
ArrayList<Integer> gene = genes.get(g);
if (!gene.isEmpty())
gene.remove(RandomUtils.nextInt(gene.size()));
@ -180,14 +221,14 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
private void createCellsFromGene() {//根据基因生成细胞参数
long geneMask = 1;
for (int g = 0; g < GENE_NUMBERS; g++) {//依次对每条基因对应的参数在相应的细胞处把细胞参数位置1
for (int g = 0; g < GENE_NUMBERS; g++) {//动物有多条基因一条基因控制一维细胞参数最多有64维也就是最多有64条基因
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树最小节点标记细胞参数位
if (Tree8Util.ENABLE[i]) {
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树keep标记生成细胞参数
if (Tree8Util.keep[i] >= 0) {
int[] node = Tree8Util.TREE8[i];
if (node[0] == 1) {//如果node边长为1即不可以再分裂了就在三维空间对间数组的位置把当前基因geneMask置1
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask;
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask; //在相应的细胞处把细胞参数位置1
}
}
}

View File

@ -83,7 +83,7 @@ public class Env extends JPanel {
public static int food_ated = 0; // 用来统计总共多少个食物被青蛙吃掉
public static int frog_ated = 0; // 用来统计总共多少个食物被青蛙吃掉
public static int frog_ated = 0; // 用来统计总共多少个青蛙被蛇吃掉
public static boolean pause = false; // 暂停按钮按下将暂停测试

View File

@ -14,7 +14,7 @@ import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.objects.Material;
/**
* Frog is child class of Animal, Animal's name is Sam.
* Frog is child class of Animal, Frog's name is Sam
* Frog是Animal的一个子类
*
* @since 1.0

View File

@ -321,7 +321,7 @@ public class BrainPicture extends JPanel {
ArrayList<Integer> gene = a.genes.get(geneIndex);
Tree8Util.knockNodesByGene(gene);
for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
if (Tree8Util.ENABLE[j]) {
if (Tree8Util.keep[j]>=0) {
int[] node = Tree8Util.TREE8[j];
int size = node[0];
if (size == i && Env.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点

View File

@ -18,6 +18,6 @@ package com.gitee.drinkjava2.frog.brain;
*/
@SuppressWarnings("all")
public class Cells {
public static int GENE_NUMBERS = 5; //目前有多少条基因每个脑细胞用是一个long来存储所以最多允许64条基因每个基因控制一个细胞的参数
public static int GENE_NUMBERS = 4; //目前有多少条基因每个脑细胞用是一个long来存储所以最多允许64条基因每个基因控制一个细胞的参数
}

View File

@ -61,15 +61,15 @@ public class Egg implements Serializable {
x = a.x;
y = a.y;
genes.addAll(a.genes);
if (!genes.isEmpty() && b != null)
for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
if (RandomUtils.percent(10)) {
ArrayList<Integer> agene = a.genes.get(i);
ArrayList<Integer> bgene = b.genes.get(i);
if (!bgene.isEmpty())
agene.add(bgene.get(RandomUtils.nextInt(bgene.size())));
}
}
// if (!genes.isEmpty() && b != null)
// for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
// if (RandomUtils.percent(3)) {
// ArrayList<Integer> agene = a.genes.get(i);
// ArrayList<Integer> bgene = b.genes.get(i);
// if (!bgene.isEmpty())
// agene.add(bgene.get(RandomUtils.nextInt(bgene.size())));
// }
// }
}
}

View File

@ -43,11 +43,6 @@ public class FrogEggTool {
* 用能量的多少来简化生存竟争模拟每次下蛋数量固定为EGG_QTY个
*/
public static void layEggs() {
for (Frog frog : Env.frogs) {
for (ArrayList<Integer> gene : frog.genes) {//基因多的青蛙也要适当扣点分防止蛋文件太大
frog.energy-=gene.size();
}
}
sortFrogsOrderByEnergyDesc();
Frog first = Env.frogs.get(0);
Frog last = Env.frogs.get(Env.frogs.size() - 1);

View File

@ -0,0 +1,85 @@
package com.gitee.drinkjava2.frog.judge;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.StringPixelUtils;
/**
* judge method be called in animal's initAnimal method
*
* 这个类的judge方法在动物的初始化后被调用根据脑细胞群的三维结构和参数来对动物进行奖罚即加减它的能量值这是一个临时类只是用来检验细胞三维成形功能以后可能改名或删除
* 这个类的show方法在绘脑图时调用在脑图里显示脑细胞群的三维形状和参数用不同颜色直径的空心圆来表示不同参数judge方法就像是一个模子细胞长在这个模子里的有奖否则扣分
*/
public class FlowerJudge extends RainBowFishJudge {//NOSONAR
private static int[] C = new int[]{0, 0, Env.BRAIN_CUBE_SIZE / 2}; //C是中心点
private static boolean[][][] shape = new boolean[Env.BRAIN_XSIZE][Env.BRAIN_YSIZE][Env.BRAIN_ZSIZE];
private static List<int[]> pointList = new ArrayList<>(); //pointList存放上面shape的所有有效点用来加快显示循环而不用遍历三维数组
static {
putPixiel("🌸");
}
public static void putPixiel(String str) {
byte[][] c = StringPixelUtils.getStringPixels(Font.SANS_SERIF, Font.PLAIN, Env.BRAIN_CUBE_SIZE, str); //要把frog二维像素变成立体的三维点放到points里和pointsList里供使用
int w = c.length;
int h = c[0].length;
for (int z = 0; z < 5; z++) {
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][y] > 0) {
int[] p = new int[]{C[0] + x, C[1] + y + 2, C[2] + z};
if (!Animal.outBrainRange(p[0], p[1]-2, p[2])) {//减2是把花朵向下移两格
shape[p[0]][p[1]-2][p[2]] = true;
pointList.add(p);
}
}
}
}
}
}
private static void judgeShape(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++) {
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++) {
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
if ((animal.cells[x][y][z] & 1) != 0)
if (shape[x][y][z]) {
animal.awardAAAA();
} else {
animal.penaltyAAA();
}
}
}
}
}
public static void judgeColor(Animal animal) {//检查颜色与小鱼图像重合且呈斑马纹色彩分布是就加分否则扣分
int colorWidth = Env.BRAIN_CUBE_SIZE / Cells.GENE_NUMBERS; //每条彩带宽度
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++)
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++)
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++)
for (int i = 1; i <= Cells.GENE_NUMBERS; i++)
if ((animal.cells[x][y][z] & (1 << i)) != 0) { //如果色彩存在
if ((animal.cells[x][y][z] & 1) != 0 && y >= (i - 1) * colorWidth && y < (i * colorWidth))
animal.awardAA(); //如果细胞存在且颜色分布符合要求奖励
else
animal.penaltyA();//否则扣分
}
}
public static void judge(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
judgeShape(animal);
judgeColor(animal);
}
public static void show(BrainPicture pic) {// 在脑图上显示当前形状
for (int[] p : pointList)
pic.drawCircle(p[0] + 0.5f, p[1] + 0.5f, p[2] + 0.5f, 1);
}
}

View File

@ -0,0 +1,84 @@
package com.gitee.drinkjava2.frog.judge;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.StringPixelUtils;
/**
* judge method be called in animal's initAnimal method
*
* 这个类的judge方法在动物的初始化后被调用根据脑细胞群的三维结构和参数来对动物进行奖罚即加减它的能量值这是一个临时类只是用来检验细胞三维成形功能以后可能改名或删除
* 这个类的show方法在绘脑图时调用在脑图里显示脑细胞群的三维形状和参数用不同颜色直径的空心圆来表示不同参数judge方法就像是一个模子细胞长在这个模子里的有奖否则扣分
*/
public class RainBowFishJudge {//NOSONAR
private static int[] C = new int[]{0, 0, Env.BRAIN_CUBE_SIZE / 2}; //C是中心点
private static boolean[][][] shape = new boolean[Env.BRAIN_XSIZE][Env.BRAIN_YSIZE][Env.BRAIN_ZSIZE];
private static List<int[]> pointList = new ArrayList<>(); //pointList存放上面shape的所有有效点用来加快显示循环而不用遍历三维数组
static {
putPixiel("🐟");
}
public static void putPixiel(String str) {
byte[][] c = StringPixelUtils.getStringPixels(Font.SANS_SERIF, Font.PLAIN, Env.BRAIN_CUBE_SIZE, str); //要把frog二维像素变成立体的三维点放到points里和pointsList里供使用
int w = c.length;
int h = c[0].length;
for (int z = 0; z < 5; z++) {
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][y] > 0) {
int[] p = new int[]{C[0] + x, C[1] + y + 2, C[2] + z};
if (!Animal.outBrainRange(p[0], p[1], p[2])) {
shape[p[0]][p[1]][p[2]] = true;
pointList.add(p);
}
}
}
}
}
}
private static void judgeShape(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++) {
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++) {
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
if ((animal.cells[x][y][z] & 1) != 0)
if (shape[x][y][z]) {
animal.awardAAAA();
} else {
animal.penaltyAAA();
}
}
}
}
}
public static void judgeColor(Animal animal) {//检查颜色与小鱼图像重合且呈斑马纹色彩分布是就加分否则扣分
int colorWidth = Env.BRAIN_CUBE_SIZE / Cells.GENE_NUMBERS; //每条彩带宽度
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++)
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++)
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++)
for (int i = 1; i <= Cells.GENE_NUMBERS; i++)
if ((animal.cells[x][y][z] & (1 << i)) != 0) //如果色彩存
if ((animal.cells[x][y][z] & 1) != 0 && x >= (i - 1) * colorWidth && x < (i * colorWidth))
animal.awardAA();
else
animal.penaltyA();
}
public static void judge(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
judgeShape(animal);
judgeColor(animal);
}
public static void show(BrainPicture pic) {// 在脑图上显示当前形状
for (int[] p : pointList)
pic.drawCircle(p[0] + 0.5f, p[1] + 0.5f, p[2] + 0.5f, 1);
}
}

View File

@ -25,11 +25,18 @@ public class RandomUtils {
private static final Random rand = new Random();
public static int nextInt(int i) {
public static int nextInt(int i) {//返回随机整数最小为0最大为n-1
if(i==0)
return 0;
return rand.nextInt(i);
}
public static int nextNegOrPosInt(int n) {//返回随机整数最小为-(n-1)最大为n-1
int x = nextInt(n);
if (percent(50))
return x;
return -x;
}
public static float nextFloat() {
return rand.nextFloat();

View File

@ -29,9 +29,11 @@ public class Tree8Util {
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示第一维是深度树的行号第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
public static boolean[] ENABLE = new boolean[NODE_QTY]; //这里记录树的敲除记录被敲除的节点用false表示
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录大于等于0的值表示要keep, 负数节点表示要敲除
public static int ENABLE_NODE_QTY = NODE_QTY; //这里记录未被敲除的总节点数好用来下次继续敲除
private static byte[] KEEP = new byte[NODE_QTY]; //这里保存初值为0的数组常量可以用System.arraycopy(enable0, 0, enable, 0, NODE_QTY)快速清空enable数组
public static int keepNodeQTY = NODE_QTY; //这里临时记录需keep的节点总数好用来继续敲除初始值是全部节点
private static int index = 0;
static {
@ -60,22 +62,24 @@ public class Tree8Util {
tree8Split(x + half, y + half, z + half, half);
}
public static void knockNodesByGene(List<Integer> gene) {//根据基因把要敲除的8叉树节点作个标记0
for (int i = 0; i < Tree8Util.NODE_QTY; i++)
ENABLE[i] = true;
ENABLE_NODE_QTY = NODE_QTY;
for (int g : gene) {//g是要敲除的节点的行号
if (Tree8Util.ENABLE[g]) {
int gSize = Tree8Util.TREE8[g][0]; //gSize是节点对应的立方体边长
for (int i = g; i < Tree8Util.NODE_QTY; i++) {//从这个g节点开始往下找节点
int iSize = Tree8Util.TREE8[i][0];
if (i > g && iSize >= gSize) //如果除了第一个节点外边长与g相同或大于g的边长说明节点不是g的子节点退出
break;
else {//否则就是g的子节点需要敲除
if (Tree8Util.ENABLE[i]) { //如是还没敲除
ENABLE_NODE_QTY--; //有效节点数减1这个
Tree8Util.ENABLE[i] = false; //作敲除标记
}
public static void knockNodesByGene(List<Integer> gene) {//根据基因把要敲除的8叉树节点作敲除或保留标记
System.arraycopy(KEEP, 0, keep, 0, NODE_QTY);//清空keep数组
keepNodeQTY = NODE_QTY;
for (int g : gene) {//g基因用带符号的8叉数的行号表示负数表示阴节点要敲除0或正数表示是阳节点要保留
int gLine = Math.abs(g); //基因对应节点的行号
int size = Tree8Util.TREE8[gLine][0]; //size是基因对应节点的细胞立方体边长
for (int line = gLine; line < Tree8Util.NODE_QTY; line++) {//从这个g节点开始往下找节点
if (line > gLine && Tree8Util.TREE8[line][0] >= size) //如果除了第一个节点外边长大于等于size说明节点不是g的子节点退出
break;
else {//否则就是g的子节点
if (g < 0) { //g是阴节点
Tree8Util.keep[line]--;
if (Tree8Util.keep[line] == -1) //如果正好是-1表示这个节点从保留状态转为删除状态
keepNodeQTY--;
} else if (g > 0) { //g是阳节点
Tree8Util.keep[line]++;
if (Tree8Util.keep[line] == 0) //如果正好是0表示这个节点从删除状态又转回了保留状态
keepNodeQTY++;
}
}
}

201
history/009b_fish3d/LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@ -0,0 +1,9 @@
## 009b_fish3d 分支介绍
009b与009a分支相比算法是相同的只是作了以下一些小改动
1.增加了颜色数在Cells.GENE_NUMBERS中设定
2.增加了存盘到文件选择框,可以在运行期点击再存盘
3.增加了每维参数分别显示的选择框,每个参数可以单独显示进化过程和分裂过程
4.增加了显示分裂详细过程按钮
5.BrainRainbowColorJudge.java里将颜色参数与细胞位置参数产生关联也就是说参数之间有关联关系这种情况下更容易发生缺色现象出现这是因为进化过程中主要参数细胞位置的进化会导致个别次要参数的分支被误删然后就很难再补回来了。
为了解决这个缺色问题,,也就是分支一旦被误删就很难再补回来的问题,下一个版本打算改变算法,采用黑白节点的方式,白节点以下为无限分裂并生成细胞,黑节点依然是分裂但不生成实际细胞,除非碰到白节点为止。以前做法是只有根节点是白节点,以后改成在任意位置随机生成黑或白节点。这样变异就包括:黑白节点的生成、消失、上下左右漂移、黑白转换等。

View File

@ -0,0 +1 @@
mvn clean

View File

@ -0,0 +1 @@
mvn eclipse:clean

View File

@ -0,0 +1,2 @@
call mvn eclipse:eclipse
call pause

102
history/009b_fish3d/pom.xml Normal file
View File

@ -0,0 +1,102 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.drinkjava2</groupId>
<artifactId>frog009b</artifactId>
<packaging>jar</packaging>
<version>9.0</version>
<name>frog</name>
<description>当前目标是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务</description>
<url>https://gitee.com/drinkjava2/jsqlbox/frog</url>
<issueManagement>
<system>gitee Issue</system>
<url>https://gitee.com/drinkjava2/jsqlbox/frog/issues</url>
</issueManagement>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<name>Yong Zhu</name>
<email>yong9981@gmail.com</email>
<url>https://gitee.com/drinkjava2/</url>
</developer>
</developers>
<scm>
<connection>scm:git@gitee.com:drinkjava2/frog.git</connection>
<developerConnection>scm:git@gitee.com:drinkjava2/frog.git</developerConnection>
<url>git@gitee.com:drinkjava2/frog.git</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<!-- Release on Java8 -->
<version.java>1.8</version.java>
<version.javadoc>6</version.javadoc>
<version.compiler-plugin>3.3</version.compiler-plugin>
<version.war-plugin>2.6</version.war-plugin>
<version.clean-plugin>3.0.0</version.clean-plugin>
<version.resources-plugin>2.7</version.resources-plugin>
<version.surefire-plugin>2.19</version.surefire-plugin>
<version.jar-plugin>2.6</version.jar-plugin>
<version.source-plugin>2.4</version.source-plugin>
<version.javadoc-plugin>2.10.3</version.javadoc-plugin>
<version.gpg-plugin>1.6</version.gpg-plugin>
</properties>
<dependencies>
<!--dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${version.compiler-plugin}</version>
<configuration>
<source>${version.java}</source>
<target>${version.java}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<useUniqueVersions>false</useUniqueVersions>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.gitee.drinkjava2.frog.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
</profiles>
</project>

View File

@ -0,0 +1,3 @@
call mvn clean compile
cd target\classes
java -classpath ".;*" com.gitee.drinkjava2.frog.Application

View File

@ -0,0 +1,2 @@
mvn clean package
java -jar target/frog-*.jar

Binary file not shown.

View File

@ -0,0 +1,198 @@
/*
* 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;
import static com.gitee.drinkjava2.frog.brain.Cells.GENE_NUMBERS;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.judge.BrainRainbowColorJudge;
import com.gitee.drinkjava2.frog.judge.BrainShapeJudge;
import com.gitee.drinkjava2.frog.objects.Material;
import com.gitee.drinkjava2.frog.util.RandomUtils;
import com.gitee.drinkjava2.frog.util.Tree8Util;
/**
* Animal is all artificial lives' father class
*
* Animal是所有动物青蛙蛇等的父类, animal是由蛋孵出来的蛋里保存着脑细胞结构生成的基因
* genes是一个list<list>结构, 每一条list代表一条由深度树方式存储的基因树分表控制细胞的一个参数用cells长整的一位表示比如genes.get(0)是控制细胞的存在即cells三维数组的元素的最低位
*
*
* @author Yong Zhu
*
* @since 1.0
*/
public abstract class Animal {// 这个程序大量用到public变量而不是getter/setter主要是为了编程方便和简洁但缺点是编程者需要小心维护各个变量
public static BufferedImage FROG_IMAGE;
public static BufferedImage snakeImage;
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>(); // Animal的基因只保存一份这是人工生命与实际生物每个细胞都保留一份基因的最大不同
static {
try {
FROG_IMAGE = ImageIO.read(new FileInputStream(Application.CLASSPATH + "frog.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
/** brain cells */
public long[][][] cells = new long[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
public float[][][] energys = new float[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
public int x; // animal在Env中的x坐标
public int y; // animal在Env中的y坐标
public long energy = 100000; // 青蛙的能量为0则死掉
public boolean alive = true; // 设为false表示青蛙死掉了将不参与计算和显示以节省时间
public int ateFood = 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 是虑拟环境的坐标
for (int i = 0; i < GENE_NUMBERS; i++) {
ArrayList<Integer> gene = new ArrayList<>();
genes.add(gene);
}
int i = 0;
for (ArrayList<Integer> gene : egg.genes) //动物的基因是蛋的基因的拷贝
genes.get(i++).addAll(gene);
if (Env.BORN_AT_RANDOM_PLACE) { //是否随机出生在地图上?
x = RandomUtils.nextInt(Env.ENV_WIDTH);
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
} else {//否则出生成指定区域
this.x = egg.x + RandomUtils.nextInt(80) - 40;
this.y = egg.y + RandomUtils.nextInt(80) - 40;
if (this.x < 0)
this.x = 0;
if (this.y < 0)
this.y = 0;
if (this.x >= (Env.ENV_WIDTH - 1))
this.x = Env.ENV_WIDTH - 1;
if (this.y >= (Env.ENV_HEIGHT - 1))
this.y = Env.ENV_HEIGHT - 1;
}
}
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步这个方法是在当前屏animal生成之后调用比方说有一千个青蛙分为500屏测试每屏只生成2个青蛙的脑细胞可以节约内存
geneMutation(); //有小概率基因突变
createCellsFromGene(); //运行基因语言生成脑细胞
BrainShapeJudge.judge(this); //外界判断对这个动物打分
BrainRainbowColorJudge.judge(this);
}
private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 5000;
private static final int MAX_ENERGY_LIMIT = Integer.MAX_VALUE - 5000;
//@formatter:off 下面几行是重要的奖罚方法会经常调整或注释掉集中放在一起不要格式化为多行
public void changeEnergy(int energy_) {//正数为奖励负数为惩罚 energy大小是环境对animal唯一的奖罚也是animal唯一的下蛋竞争标准
energy += energy_;
if (energy > MAX_ENERGY_LIMIT)
energy = MAX_ENERGY_LIMIT;
if (energy < MIN_ENERGY_LIMIT)
energy = MIN_ENERGY_LIMIT;
}
public void awardAAAA() { changeEnergy(8000);}
public void awardAAA() { changeEnergy(1000);}
public void awardAA() { changeEnergy(100);} //TODO:如果改为20就可能出现缺色所以下面要用细胞8叉树从底向上扩张的算法把缺色补上
public void awardA() { changeEnergy(2);}
public void penaltyAAAA() { changeEnergy(-8000);}
public void penaltyAAA() { changeEnergy(-1000);}
public void penaltyAA() { changeEnergy(-100);}
public void penaltyA() { changeEnergy(-2);}
public void kill() { this.alive = false; changeEnergy(-5); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
//@formatter:on
public boolean active() {// 这个active方法在每一步循环都会被调用是脑思考的最小帧
// 如果能量小于0出界与非食物的点重合则判死
if (!alive) {
energy = MIN_ENERGY_LIMIT; // 死掉的青蛙确保淘汰出局
return false;
}
if (energy <= 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILL_ANIMAL) {
kill();
return false;
}
//energy -= 20;
// 依次调用每个cell的active方法
//for (Cell cell : cells)
// cell.organ.active(this, cell);
return alive;
}
public void show(Graphics g) {// 显示当前动物
if (!alive)
return;
// g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标保证嘴巴显示在当前x,y处
}
/** Check if x,y,z out of animal's brain range */
public static boolean outBrainRange(int x, int y, int z) {// 检查指定坐标是否超出animal脑空间界限
return x < 0 || x >= Env.BRAIN_XSIZE || y < 0 || y >= Env.BRAIN_YSIZE || z < 0 || z >= Env.BRAIN_ZSIZE;
}
public void geneMutation() { //基因变异,注意这一个算法同时变异所有条基因目前最多允许64条基因
for (int g = 0; g < GENE_NUMBERS; g++) {//依次对每条基因对应的参数在相应的细胞处把细胞参数位置1
if (RandomUtils.percent(10)) { //随机新增基因, 在基因里插入一个8叉树位置号,表示这个位置的8叉树整个节点会被敲除
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记
int randomIndex = RandomUtils.nextInt(Tree8Util.ENABLE_NODE_QTY);
int count = -1;
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {
if (Tree8Util.ENABLE[i]) {
count++;
if (count >= randomIndex && !gene.contains(i)) {
gene.add(i);
break;
}
}
}
}
}
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因
if (RandomUtils.percent(3)) {
ArrayList<Integer> gene = genes.get(g);
if (!gene.isEmpty())
gene.remove(RandomUtils.nextInt(gene.size()));
}
}
}
private void createCellsFromGene() {//根据基因生成细胞参数
long geneMask = 1;
for (int g = 0; g < GENE_NUMBERS; g++) {//依次对每条基因对应的参数在相应的细胞处把细胞参数位置1
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树最小节点标记细胞参数位
if (Tree8Util.ENABLE[i]) {
int[] node = Tree8Util.TREE8[i];
if (node[0] == 1) {//如果node边长为1即不可以再分裂了就在三维空间对间数组的位置把当前基因geneMask置1
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask;
}
}
}
geneMask <<= 1;
}
}
}

View File

@ -0,0 +1,169 @@
package com.gitee.drinkjava2.frog;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
/**
* Application's main method start the program
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class Application {
public static final String CLASSPATH;
static {
String classpath = new File("").getAbsolutePath();
int i = classpath.lastIndexOf("\\frog\\");
if (i > 0)
CLASSPATH = classpath.substring(0, i) + "\\frog\\";// windows
else
CLASSPATH = classpath + "/"; // 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.BRAIN_XSIZE, Env.FROG_BRAIN_DISP_WIDTH);
public static ActionListener pauseAction;
public static boolean selectFrog = true;
private static void checkIfShowBrainPicture(JButton button) {
int y = Env.ENV_HEIGHT + 150;
if (Env.SHOW_FIRST_ANIMAL_BRAIN) {
button.setText("Hide brain");
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, y);
}
}
public static void main(String[] args) {
mainFrame.setLayout(null);
mainFrame.setSize(Env.ENV_WIDTH + 200, Env.ENV_HEIGHT + 150); // 窗口大小
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭时退出程序
mainFrame.add(env); // 添加虚拟环境Panel
mainFrame.add(brainPic); // 添加脑图Panel
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) {//显示或隐藏脑图
Env.SHOW_FIRST_ANIMAL_BRAIN = !Env.SHOW_FIRST_ANIMAL_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);
pauseAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Env.pause = !Env.pause;
if (Env.pause) {
stopButton.setText("Resume");
} else {
stopButton.setText("Pause");
brainPic.requestFocus();
}
}
};
stopButton.addActionListener(pauseAction);
mainFrame.add(stopButton);
// 速度条
final JSlider speedSlider = new JSlider(1, 10, (int) Math.round(Math.pow(Env.SHOW_SPEED, 1.0/3)));
speedSlider.setBounds(buttonXpos - 50, stopButton.getY() + 25, buttonWidth + 100, buttonHeight);
ChangeListener slideAction = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
Env.SHOW_SPEED = speedSlider.getValue() * speedSlider.getValue() * speedSlider.getValue();
brainPic.requestFocus();
}
};
speedSlider.addChangeListener(slideAction);
mainFrame.add(speedSlider);
final JLabel label = new JLabel("Speed:");
label.setBounds(buttonXpos - 90, stopButton.getY() + 23, 100, buttonHeight);
mainFrame.add(label);
//是否把egg文件存盘
JCheckBox saveFileCheckBox = new JCheckBox("Save egg file");
saveFileCheckBox.setBounds(buttonXpos, Env.ENV_HEIGHT + 80, 120, 22);
ActionListener saveAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (saveFileCheckBox.isSelected())
Env.SAVE_EGGS_FILE = true;
else
Env.SAVE_EGGS_FILE = false;
}
};
saveFileCheckBox.addActionListener(saveAction);
mainFrame.add(saveFileCheckBox);
//基因维数显示控制
for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
JRadioButton geneRadio=new JRadioButton();
geneRadio.setBounds(buttonXpos+300+i*20, Env.ENV_HEIGHT + 8, 20, 22);
geneRadio.setSelected(true);
geneRadio.setName(""+i);
ActionListener geneRadioAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
int i= Integer.parseInt(geneRadio.getName());
if (geneRadio.isSelected())
Env.display_gene[i]=true;
else
Env.display_gene[i]=false;
}
};
geneRadio.addActionListener(geneRadioAction);
mainFrame.add(geneRadio);
}
//是否显示分裂过程
JCheckBox showSplitDetailCheckBox = new JCheckBox("Show split detail");
showSplitDetailCheckBox.setBounds(buttonXpos+300, Env.ENV_HEIGHT + 40, 120, 22);
ActionListener detailAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (showSplitDetailCheckBox.isSelected())
Env.show_split_detail = true;
else
Env.show_split_detail = false;
}
};
showSplitDetailCheckBox.addActionListener(detailAction);
mainFrame.add(showSplitDetailCheckBox);
mainFrame.setVisible(true);
env.run();
}
}

View File

@ -0,0 +1,325 @@
package com.gitee.drinkjava2.frog;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.egg.Egg;
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.util.Logger;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Env is the living space of frog. draw it on JPanel
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class Env extends JPanel {
private static final long serialVersionUID = 1L;
/** Speed of test */
public static int SHOW_SPEED = 1000; // 测试速度-1000~1000,可调, 数值越小速度越慢
public static final int FROG_EGG_QTY = 100; // 每轮下n个青蛙蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
public static final int SCREEN = 1; // 分几屏测完
/** Delete eggs at beginning of each run */
public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除以前保存的青蛙蛋文件如果为false将加载旧蛋文件继续运行
public static boolean SAVE_EGGS_FILE = false; //从2021-11-23起添加这个选项允许不输出蛋文件到磁盘上
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出动物落在地图上随机位置而不是在蛋所在地
/** Frog's brain size */ // 脑细胞位于脑范围内是个三维结构在animal中用一个List<Cell>来存贮表示的同时也用一个Cell3D动态数组来表示
public static final int BRAIN_CUBE_SIZE = 16; //脑立方边长大小必须是2的幂数如4,8,16...
public static final int BRAIN_XSIZE = BRAIN_CUBE_SIZE; // 脑在X方向长度取值最大为1000
public static final int BRAIN_YSIZE = BRAIN_CUBE_SIZE; // 脑在Y方向长度取值最大为1000
public static final int BRAIN_ZSIZE = BRAIN_CUBE_SIZE; // 脑在Z方向长度取值最大为1000
public static final int CELLS_MAX_QTY = 4000; //脑细胞总数不能超过这个值
/** SHOW first animal's brain structure */
public static boolean SHOW_FIRST_ANIMAL_BRAIN = true; // 是否显示脑图在Env区的右侧
/** Draw first frog's brain after some steps */
public static int DRAW_BRAIN_AFTER_STEPS = 0; // 以此值为间隔动态画出脑图设为0则关闭这个动态脑图功能只显示一个静态不闪烁的脑图
/** Environment x width, unit: pixels */
public static final int ENV_WIDTH = 400; // 虚拟环境的宽度, 可调
/** Environment y height, unit: pixels */
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的脑图在屏幕上的显示大小,可调
/** Steps of one test round */
public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调
public static int step;// 当前测试步数
public static final int FOOD_QTY = 1500; // 食物数量, 可调
// 以下是程序内部变量不要手工修改它们
public static final int TOTAL_FROG_QTY = FROG_EGG_QTY * FROG_PER_EGG; // 蛇的总数
public static final int FROG_PER_SCREEN = TOTAL_FROG_QTY / SCREEN; // 每屏显示几个青蛙这个数值由其它常量计算得来
public static int current_screen = 0;
public static int food_ated = 0; // 用来统计总共多少个食物被青蛙吃掉
public static int frog_ated = 0; // 用来统计总共多少个食物被青蛙吃掉
public static boolean pause = false; // 暂停按钮按下将暂停测试
public static int[][] bricks = new int[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料见Material.java
public static List<Frog> frogs = new ArrayList<>(); // 这里存放所有待测的青蛙可能分几次测完由FROG_PER_SCREEN大小来决定
public static List<Egg> frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋每个蛋可能生成几个青蛙
public static EnvObject[] things = new EnvObject[]{ };// 所有外界物体如食物字母测试工具都放在这个things里面
public static boolean show_split_detail=false; //是否显示脑分裂的细节过程即从一个细胞开始分裂分裂而不是只显示分裂的最终结果
public static boolean[] display_gene=new boolean[Cells.GENE_NUMBERS]; //脑最多有64个基因这里用来控制哪些基因需要显示在脑图上
static {
Logger.info("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒见码云issue#IW4H8
Logger.info("脑图快捷键: T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移");
if (DELETE_FROG_EGGS)
FrogEggTool.deleteEggs();
for (int i = 0; i < display_gene.length; i++)
display_gene[i]=true;
}
public Env() {
super();
this.setLayout(null);// 空布局
this.setBounds(1, 1, ENV_WIDTH, ENV_HEIGHT);
}
public static boolean insideEnv(int x, int y) {// 如果指定点在边界内
return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT);
}
public static boolean outsideEnv(int x, int y) {// 如果指定点超出边界
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT;
}
public static boolean closeToEdge(Animal a) {// 靠近边界? 离死不远了
return a.x < 20 || a.y < 20 || a.x > (Env.ENV_WIDTH - 20) || a.y > (Env.ENV_HEIGHT - 20);
}
public static boolean foundAnyThingOrOutEdge(int x, int y) {// 如果指定点看到任意东西或超出边界返回true
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] != 0;
}
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物将其清0返回true
if (insideEnv(x, y) && (Env.bricks[x][y] & Material.FOOD) > 0) {
Env.food_ated++;
clearMaterial(x, y, Material.FOOD);// 清空任意食物
return true;
}
return false;
}
public static boolean foundFrogOrOutEdge(int x, int y) {// 如果指定点看到青蛙或超出边界返回true
if (x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT)
return true;// 如果出界返回true
if ((Env.bricks[x][y] & Material.FROG_TAG) > 0)
return true;
else
return false;
}
public static void setMaterial(int x, int y, int material) {
if (Env.insideEnv(x, y))
Env.bricks[x][y] = Env.bricks[x][y] | material;
}
public static boolean hasMaterial(int x, int y, int material) {
if (!Env.insideEnv(x, y))
return false;
return (Env.bricks[x][y] & material) > 0;
}
public static void clearMaterial(int x, int y, int material) {
if (Env.insideEnv(x, y))
Env.bricks[x][y] = Env.bricks[x][y] & ~material;
}
private void rebuildFrogs() {// 根据蛙蛋重新孵化出蛙
frogs.clear();
for (int i = 0; i < frog_eggs.size(); i++) {// 创建青蛙每个蛋生成n个蛙并随机取一个别的蛋作为精子
int loop = FROG_PER_EGG;
if (frog_eggs.size() > 20) { // 如果数量多进行一些优化让排名靠前的Egg多孵出青蛙
if (i < FROG_PER_EGG)// 0,1,2,3
loop = FROG_PER_EGG + 1;
if (i >= (frog_eggs.size() - FROG_PER_EGG))
loop = FROG_PER_EGG - 1;
}
for (int j = 0; j < loop; j++) {
Egg zygote = new Egg(frog_eggs.get(i), frog_eggs.get(RandomUtils.nextInt(frog_eggs.size())));
Frog f = new Frog(zygote);
frogs.add(f);
f.no = frogs.size();
}
}
}
private void drawWorld(Graphics g) {
int brick;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++) {
brick = bricks[x][y];
if (brick != 0) {
g.setColor(Material.color(brick));
if ((brick & Material.FOOD) > 0) {
g.fillRoundRect(x, y, 4, 4, 2, 2); //食物只有一个点太小画大一点
} else
g.drawLine(x, y, x, y); // only 1 point
}
}
g.setColor(Color.BLACK);
}
static final NumberFormat format100 = NumberFormat.getPercentInstance();
static {
format100.setMaximumFractionDigits(2);
}
private String foodAtedCount() {// 统计吃食总数等
int maxFound = 0;
for (Frog f : frogs)
if (f.ateFood > maxFound)
maxFound = f.ateFood;
return new StringBuilder("吃食率:").append(format100.format(Env.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Env.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound)
.toString();
}
private String frogAtedCount() {// 统计食蛙总数
return new StringBuilder("吃蛙率:").append(format100.format(Env.frog_ated * 1.00 / TOTAL_FROG_QTY)).toString();
}
public static void checkIfPause() {
if (pause)
do {
Application.brainPic.drawBrainPicture();
Application.brainPic.requestFocus();
sleep(100);
} while (pause);
}
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static Animal getShowAnimal() {
return frogs.get(current_screen * FROG_PER_SCREEN);
}
public void run() {
FrogEggTool.loadFrogEggs(); // 从磁盘加载蛙egg或新建一批egg
Image buffImg = createImage(this.getWidth(), this.getHeight());
Graphics g = buffImg.getGraphics();
long time0;// 计时用
int round = 1;
do {
rebuildFrogs(); // 根据蛙蛋重新孵化出蛙注意基因变异有可能在孵化过程中发生
for (current_screen = 0; current_screen < SCREEN; current_screen++) {// 分屏测试每屏FROG_PER_SCREEN个蛙
Env.food_ated = 0; // 先清0吃食物数
Env.frog_ated = 0;// 先清0吃蛙数
time0 = System.currentTimeMillis();
for (EnvObject thing : things) // 创建食物陷阱等物体
thing.build();
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();
if (allDead)
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
allDead = true;
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
if (f.active())// 调用青蛙的Active方法并返回是否还活着
allDead = false;
}
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用是否跳帧画图的方式来控制速度
continue;
if (SHOW_SPEED < 0) // 如果speed小于0人为加入延迟
sleep(-SHOW_SPEED);
// 开始画虚拟环境和青蛙和蛇
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境
g.setColor(Color.BLACK);
drawWorld(g);// 画整个虚拟环境
for (int j = 0; j < FROG_PER_SCREEN; j++) { // 显示青蛙
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
f.show(g);
}
if (SHOW_FIRST_ANIMAL_BRAIN) {// 在showAnimal上画一个红圈
Animal showAnimal = getShowAnimal();
if (showAnimal != null) {
g.setColor(Color.red);
g.drawArc(showAnimal.x - 15, showAnimal.y - 15, 30, 30, 0, 360);
g.setColor(Color.BLACK);
}
}
if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0)
Application.brainPic.drawBrainPicture();
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
}
if (SHOW_FIRST_ANIMAL_BRAIN)
Application.brainPic.drawBrainPicture();
checkIfPause();
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(foodAtedCount());
Application.mainFrame.setTitle(sb.toString());
// for (EnvObject thing : things)// 去除食物陷阱等物体
// thing.destory();
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
bricks[i][j] = 0;
}
}
round++;
FrogEggTool.layEggs(); //能量高的青蛙才有权下蛋
} while (true);
}
}

View File

@ -0,0 +1,29 @@
/*
* 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;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.objects.Material;
/**
* Frog is child class of Animal, Animal's name is Sam.
* Frog是Animal的一个子类
*
* @since 1.0
*/
public class Frog extends Animal {
public Frog(Egg egg) {
super(egg);
animalMaterial = Material.FROG_TAG;
animalImage = Animal.FROG_IMAGE;
}
}

View File

@ -0,0 +1,450 @@
package com.gitee.drinkjava2.frog.brain;
import static java.awt.Color.BLACK;
import static java.awt.Color.RED;
import static java.awt.Color.WHITE;
import static java.lang.Math.cos;
import static java.lang.Math.round;
import static java.lang.Math.sin;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Application;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.util.ColorUtils;
import com.gitee.drinkjava2.frog.util.Tree8Util;
/**
* BrainPicture show first frog's brain structure, for debug purpose only
*
* 这个类用来画出脑图这不是一个关键类对脑的运行逻辑无影响但有了脑图后可以直观地看出脑的3维结构进行有针对性的改进
* 可以用鼠标进行平移缩放旋转以及tflr,x五个键来选择顶视前视左视右视斜视这5个方向的视图以及空格暂停方向键调整切面
* 鼠标的动作定义在MouseAction类中
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class BrainPicture extends JPanel {
private static final long serialVersionUID = 1L;
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;
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,rx键盘命令
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()){
case KeyEvent.VK_UP:// Y切面向上
yMask++;
if (yMask > Env.BRAIN_YSIZE)
yMask = Env.BRAIN_YSIZE;
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_XSIZE)
xMask = Env.BRAIN_XSIZE;
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(Cuboid c) {// 在脑图上画一个长立方体框架视角是TopView
drawCuboid(c.x, c.y, c.z, c.xe, c.ye, c.ze);
}
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 + 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);
}
/*-
画线固定以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_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
double x2 = px2 - Env.BRAIN_XSIZE / 2;
double y2 = -py2 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z2 = pz2 - Env.BRAIN_ZSIZE / 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 = 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;
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;
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_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 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 = 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));
}
/** 画一个圆 */
public void drawCircle(float px1, float py1, float pz1, float r) {//这个方法实际和上面的一样的只是改成了drawOval
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 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 = 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));
}
public void drawText(float px1, float py1, float pz1, String text, float textSize) {
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 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 = 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);
}
private static Cuboid brain = new Cuboid(0, 0, 0, Env.BRAIN_XSIZE, Env.BRAIN_YSIZE, Env.BRAIN_ZSIZE);
public void drawBrainPicture() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
if (!Env.SHOW_FIRST_ANIMAL_BRAIN)
return;
if(Env.show_split_detail)
drawSplitDetail();
else
drawBrainStructure();
}
public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚即从一个细胞开始分裂成最终脑结构的每一步
Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
for (int i = Env.BRAIN_CUBE_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);
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
ArrayList<Integer> gene = a.genes.get(geneIndex);
Tree8Util.knockNodesByGene(gene);
for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
if (Tree8Util.ENABLE[j]) {
int[] node = Tree8Util.TREE8[j];
int size = node[0];
if (size == i && Env.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(brain);// 把脑的框架画出来
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁这里输出缓存图片
if (!Env.show_split_detail)
return;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
public void drawBrainStructure() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
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 z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--) {
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
if (x >= xMask && y >= yMask && a.cells[x][y][z] != 0)
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
if ((a.cells[x][y][z] & (1 << geneIndex)) != 0 && Env.display_gene[geneIndex]) {
setPicColor(ColorUtils.colorByCode(geneIndex)); //开始画出对应的细胞基因参数用不同颜色直径圆表示
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, geneIndex == 0 ? 0.8f : 0.5f - geneIndex * 0.05f);
}
}
}
}
}
setPicColor(Color.BLACK);
//BrainShapeJudge.show(this);//这行显示目标形状这个模子
drawCuboid(brain);// 把脑的框架画出来
setPicColor(BLACK); //把x,y,z坐标画出来
drawText(Env.BRAIN_CUBE_SIZE, 0, 0, "x", 2);
drawText(0, Env.BRAIN_CUBE_SIZE, 0, "y", 2);
drawText(0, 0, Env.BRAIN_CUBE_SIZE, "z", 2);
setPicColor(RED);
drawLine(0, 0, 0, Env.BRAIN_CUBE_SIZE, 0, 0);
drawLine(0, 0, 0, 0, Env.BRAIN_CUBE_SIZE, 0);
drawLine(0, 0, 0, 0, 0, Env.BRAIN_CUBE_SIZE);
g.setColor(Color.black);
if (note != null) // 全局注释
g.drawString(note, 30, 55);
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁这里输出缓存图片
}
public static void setNote(String note) {
Application.brainPic.note = note;
}
// getters & setters
public float getScale() {
return scale;
}
public void setScale(float scale) {
this.scale = scale;
}
public float getxAngle() {
return xAngle;
}
public void setxAngle(float xAngle) {
this.xAngle = xAngle;
}
public float getyAngle() {
return yAngle;
}
public void setyAngle(float yAngle) {
this.yAngle = yAngle;
}
public float getzAngle() {
return zAngle;
}
public void setzAngle(float zAngle) {
this.zAngle = zAngle;
}
public void setPicColor(Color color) {
this.picColor = color;
}
public Color getPicColor() {
return picColor;
}
public int getxOffset() {
return xOffset;
}
public void setxOffset(int xOffset) {
this.xOffset = xOffset;
}
public int getyOffset() {
return yOffset;
}
public void setyOffset(int yOffset) {
this.yOffset = yOffset;
}
}

View File

@ -0,0 +1,23 @@
/*
* 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;
/**
* Cells代表不同的脑细胞参数对应每个参数细胞有不同的行为
*
* @author Yong Zhu
* @since 10.0
*/
@SuppressWarnings("all")
public class Cells {
public static int GENE_NUMBERS = 5; //目前有多少条基因每个脑细胞用是一个long来存储所以最多允许64条基因每个基因控制一个细胞的参数
}

View File

@ -0,0 +1,55 @@
/*
* 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;
/**
* Cuboid represents a rectangular prism 3d zone in brain
*
* Cuboid是一个长方体通常用来表示脑内器官的形状
*
* @author Yong Zhu
* @since 2.0.2
*/
@SuppressWarnings("all")
public class Cuboid {
private static final long serialVersionUID = 1L;
public float x;// x,y,z是长方体的左下角坐标
public float y;
public float z;
public float xe;// xe,ye,ze分别是长方体三边长
public float ye;
public float ze;
public Cuboid() {
// 空构造器不能省
}
public Cuboid(float x, float y, float z, float xe, float ye, float ze) {// 用x,y,z,r来构造
this.x = x;
this.y = y;
this.z = z;
this.xe = xe;
this.ye = ye;
this.ze = ze;
}
public Cuboid(Cuboid c) {// 用另一个Cuboid来构造
this.x = c.x;
this.y = c.y;
this.z = c.z;
this.xe = c.xe;
this.ye = c.ye;
this.ze = c.ze;
}
}

View File

@ -0,0 +1,107 @@
package com.gitee.drinkjava2.frog.brain;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
/**
* MouseAction
*
* 这个类用来处理脑图BrainPicture上的鼠标动作有平移旋转缩放三种
*
* @author Yong Zhu
* @since 2.0.2
*/
public class MouseAction implements MouseListener, MouseWheelListener, MouseMotionListener {
private BrainPicture brainPic;
private int buttonPressed = 0;
private int x;
private int y;
public MouseAction(BrainPicture brainPic) {
this.brainPic = brainPic;
}
@Override
public void mousePressed(MouseEvent e) {// 记录当前鼠标点
if (e.getButton() == 1)// 旋转
buttonPressed = 1;
else if (e.getButton() == 2)// 缩放
buttonPressed = 2;
else
buttonPressed = 0;
x = e.getPoint().x;
y = e.getPoint().y;
brainPic.requestFocus();
}
@Override
public void mouseReleased(MouseEvent e) {
buttonPressed = 0;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {// 缩放
if (e.getWheelRotation() < 0) {
brainPic.scale *= 1.1;
brainPic.xOffset *= 1.1;
brainPic.yOffset *= 1.1;
} else {
brainPic.scale /= 1.1;
brainPic.xOffset /= 1.1;
brainPic.yOffset /= 1.1;
}
}
@Override
public void mouseDragged(MouseEvent e) {// 旋转
if (buttonPressed == 1) {
if (e.getX() > x && e.getY() > y)
brainPic.zAngle -= .00f;
else if (e.getX() < x && e.getY() < y)
brainPic.zAngle += .00f;
else {
if (e.getX() > x)
brainPic.yAngle += .02f;
if (e.getX() < x)
brainPic.yAngle -= .02f;
if (e.getY() > y)
brainPic.xAngle -= .02f;
if (e.getY() < y)
brainPic.xAngle += .02f;
}
x = e.getX();
y = e.getY();
}
if (buttonPressed == 2) {// 平移
if (e.getX() > x)
brainPic.xOffset += 6;
if (e.getX() < x)
brainPic.xOffset -= 6;
if (e.getY() > y)
brainPic.yOffset += 6;
if (e.getY() < y)
brainPic.yOffset -= 6;
x = e.getX();
y = e.getY();
}
}
@Override
public void mouseClicked(MouseEvent e) {// do nothing
}
@Override
public void mouseEntered(MouseEvent e) {// do nothing
}
@Override
public void mouseExited(MouseEvent e) {// do nothing
}
@Override
public void mouseMoved(MouseEvent e) { // do nothing
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.egg;
import java.io.Serializable;
import java.util.ArrayList;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Egg is the static structure description of brain cells
*
* 蛋存在的目的是为了以最小的字节数串行化存储脑细胞,它是海量脑细胞的生成算法描述而不是脑细胞本身
* 蛋和基因的关系基因是一种语言相当于染色体不存在坐标位置蛋则是基因的载体有x,y坐标表示在虚拟环境中蛋存在的位置
*
* 另外青蛙本身也是基因的载体所以青蛙里有一个gene属性
*
* @author Yong Zhu
* @since 1.0
*/
public class Egg implements Serializable {
private static final long serialVersionUID = 1L;
public int x; // 蛋的x位置
public int y; // 蛋的y位置
// gene is a language similar like BASIC created by random
// 基因是随机生成的一种类似Basic语言的字符串符列保存在蛋中和实际生物每个细胞都要保存一份基因不同程序中每个细胞仅保存着基因的指针和当前细胞位于基因链中的行号并不需要保存基因的副本这样可以极大地减少内存占用
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>();
public Egg() {// 无中生有创建一个蛋先有蛋后有蛙d
x = RandomUtils.nextInt(Env.ENV_WIDTH);
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
}
/** Create egg from animal */
public Egg(Animal a) { // 下蛋每个器官会创建自已的副本或变异可以是0或多个
x = a.x;
y = a.y;
for (ArrayList<Integer> gene : a.genes) {//下蛋就是把动物的基因拷贝到新蛋里并有可能变异
ArrayList<Integer> g = new ArrayList<>();
g.addAll(gene);
genes.add(g);
}
}
/**
* Create a egg by join 2 eggs, x+y=zygote 模拟XY 染色体合并两个蛋生成一个新的蛋
*/
public Egg(Egg a, Egg b) {//两个蛋的基因混合, 生成一个新蛋
x = a.x;
y = a.y;
genes.addAll(a.genes);
if (!genes.isEmpty() && b != null)
for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
if (RandomUtils.percent(10)) {
ArrayList<Integer> agene = a.genes.get(i);
ArrayList<Integer> bgene = b.genes.get(i);
if (!bgene.isEmpty())
agene.add(bgene.get(RandomUtils.nextInt(bgene.size())));
}
}
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.egg;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Application;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.Frog;
import com.gitee.drinkjava2.frog.util.LocalFileUtils;
import com.gitee.drinkjava2.frog.util.Logger;
/**
* FrogEggTool save/load frog eggs to file
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class FrogEggTool {
/**
* Frogs which have higher energy lay eggs
*
* 利用Java串行机制存盘 能量多(也就是吃的更多)的Frog下蛋并存盘, 以进行下一轮测试能量少的Frog被淘汰没有下蛋的资格
* 用能量的多少来简化生存竟争模拟每次下蛋数量固定为EGG_QTY个
*/
public static void layEggs() {
for (Frog frog : Env.frogs) {
for (ArrayList<Integer> gene : frog.genes) {//基因多的青蛙也要适当扣点分防止蛋文件太大
frog.energy-=gene.size();
}
}
sortFrogsOrderByEnergyDesc();
Frog first = Env.frogs.get(0);
Frog last = Env.frogs.get(Env.frogs.size() - 1);
try {
Env.frog_eggs.clear();
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
Logger.info("Fist frog energy={}, Last frog energy={}", first.energy, last.energy);
if (Env.SAVE_EGGS_FILE) {
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(Env.frog_eggs);
so.close();
Logger.info(". Saved {} eggs to file '{}frog_eggs.ser'", Env.frog_eggs.size(), Application.CLASSPATH);
}
} catch (IOException e) {
Logger.error(e);
}
}
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
Collections.sort(Env.frogs, new Comparator<Animal>() {
public int compare(Animal a, Animal b) {
if (a.energy > b.energy)
return -1;
else if (a.energy == b.energy)
return 0;
else
return 1;
}
});
}
public static void deleteEggs() {
Logger.info("Delete exist egg file: '{}frog_eggs.ser'", Application.CLASSPATH);
LocalFileUtils.deleteFile(Application.CLASSPATH + "frog_eggs.ser");
}
/**
* 从磁盘读入一批frog Egg
*/
@SuppressWarnings("unchecked")
public static void loadFrogEggs() {
boolean errorfound = false;
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
Env.frog_eggs = (List<Egg>) eggsInputStream.readObject();
Logger.info("Loaded " + Env.frog_eggs.size() + " eggs from file '" + Application.CLASSPATH
+ "frog_eggs.ser" + "'.\n");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
}
if (errorfound) {
Env.frog_eggs.clear();
for (int j = 0; j < Env.FROG_EGG_QTY; j++) {
Egg egg = new Egg();
Env.frog_eggs.add(egg);
}
Logger.info("Fail to load frog egg file '" + Application.CLASSPATH + "frog_eggs.ser" + "', created "
+ Env.frog_eggs.size() + " eggs to do test.");
}
}
}

View File

@ -0,0 +1,26 @@
/* Copyright 2018-2020 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.objects;
/**
* EnvObject means some virtual object in Env
*
* @author Yong Zhu
* @since 1.0
*/
public interface EnvObject {
public void build(); // 在Env中创建本身物体指改变Env.bricks数组元素为本身物体的组成材料只在每屏测试前调用一次
public void destory();// 从Env中清除本身物体只在每屏测试完成后调用一次
public void active(); // 每个步长都会调用一次这个方法
}

View File

@ -0,0 +1,47 @@
/* Copyright 2018-2020 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.objects;
import static com.gitee.drinkjava2.frog.Env.ENV_HEIGHT;
import static com.gitee.drinkjava2.frog.Env.ENV_WIDTH;
import static com.gitee.drinkjava2.frog.Env.FOOD_QTY;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Food randomly scatter on Env
* 生成食物静态食物或苍蝇苍蝇如果Env中FOOD_CAN_MOVE=true,会向四个方向移动)
*
* @author Yong Zhu
* @since 1.0
*/
public class Food implements EnvObject {
@Override
public void build() {
for (int i = 0; i < FOOD_QTY; i++) // 生成食物
Env.setMaterial(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), Material.FOOD);
}
@Override
public void destory() {
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
Env.clearMaterial(i, j, Material.FOOD);
}
}
@Override
public void active() {
}
}

View File

@ -0,0 +1,50 @@
/* Copyright 2018-2020 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.objects;
import java.awt.Color;
/**
* Material store material types
*
* 虚拟环境中每个点由一个int代表多个材料可以同时出现在同一个点每种材料用int中的一个bit位来表示
* 小于等于16384的位数用来标记青蛙序号可利用Env.frogs.get(no-1)获取青蛙对象其它各种材料用整数中其它位来表示
*
* @author Yong Zhu
* @since 1.0
*/
public class Material {// NOSONAR
public static final int FROG_TAG = 0b11111111111111; // 16383 小于等于16384的位数用来标记青蛙序号可利用Env.frogs.get(no-1)快速定位青蛙
private static int material = FROG_TAG + 1; // 大于16384用来作为各种材料的标记
public static final int FOOD = nextMaterial();
public static final int SNAKE = nextMaterial(); // 蛇的图形
public static final int KILL_ANIMAL = nextMaterial(); // if>=KILLFROG will kill animal
public static final int BRICK = nextMaterial();// brick will kill frog
public static final int TRAP = nextMaterial(); // trap will kill frog
private static int nextMaterial() {// 每次将material左移1位
material = material << 1;
if (material < 0)
throw new IllegalArgumentException("Material out of maximum range");
return material;
}
public static Color color(int material) {
if ((material & TRAP) > 0)
return Color.LIGHT_GRAY;
else
return Color.BLACK;
}
}

View File

@ -0,0 +1,62 @@
/* Copyright 2018-2020 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.util;
import java.awt.Color;
/**
* Color Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class ColorUtils {
private static final Color[] rainbow = new Color[]{Color.GRAY, Color.GREEN, Color.RED, Color.BLUE, Color.YELLOW, Color.ORANGE, Color.MAGENTA, Color.CYAN};
private static int nextColor = 0;
private ColorUtils() {// default private constr
}
public static int nextColorCode() {
return nextColor++;
}
public static Color nextRainbowColor() {// 返回下一个彩虹色
if (nextColor == rainbow.length)
nextColor = 0;
return rainbow[nextColor++];
}
public static Color colorByCode(int i) {// 数值取模后返回一个固定彩虹色
return rainbow[i % rainbow.length];
}
public static Color rainbowColor(float i) { // 根据数值大小范围在8种彩虹色中取值
if (i <= 20)
return Color.GRAY;
if (i <= 30)
return Color.BLACK;
if (i <= 50)
return Color.RED;
return Color.MAGENTA;
}
public static Color grayColor(float f) { // 根据数值大小范围0~1000返回一个灰度色越大越黑
if (f > 1000)
f = 1000;
int i1 = 255 - (int) Math.round(f * .255);
int i2 = 200 - (int) Math.round(f * .200);
int i3 = 150 - (int) Math.round(f * .150);
return new Color(i1, i2, i3);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.util;
/**
* Cube has x,y,z value
*
* @author Yong Zhu
* @since 2021-11-07
*/
public class Cube {
public int x;//x,y,z是cube的左下前点坐标
public int y;
public int z;
public int size;//size是cube的边长
public Cube(int x, int y, int z, int size) {
this.x = x;
this.y = y;
this.z = z;
this.size = size;
}
}

View File

@ -0,0 +1,141 @@
/* Copyright 2018-2020 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.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Local File Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class LocalFileUtils {
private LocalFileUtils() {
// default constructor
}
public static boolean deleteFile(String fileFullPath) {
File file = new File(fileFullPath);
return file.delete(); // NOSONAR
}
public static void writeFile(String fileFullPath, byte[] byteArry) {
File file = new File(fileFullPath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(byteArry);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void writeFile(String fileFullPath, String text, String encoding) {
File file = new File(fileFullPath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
byte[] bytes;
bytes = text.getBytes(encoding);
fos.write(bytes);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String readFile(String fileFullPath, String encoding) {
InputStream inputStream;
try {
inputStream = new FileInputStream(new File(fileFullPath));
} catch (FileNotFoundException e1) {
return null;
}
try {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1)
result.write(buffer, 0, length);
String string = result.toString(encoding);
return string;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
public static void appendFile(String fileName, String content) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(fileName, true);
fos.write(content.getBytes());
fos.write("\r\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright 2021 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.util;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* Usually a logger tool is used like below:
* Logger log = LoggerFactory.getLogger(Xxxx.class);
* log.info("some msg");
*
* But to simplify, in this project directly use static method:
* Logger.info("some msg");
*
* @Description: 简版控制台日志打印从码云上合并来 https://gitee.com/drinkjava2/frog/pulls/4
* @author 栾成翔
* @Date: 2021/12/07
*/
@SuppressWarnings("all")
public class Logger {
private static final String LEV_EL = "debug";
private static final int LEVEL_INT;
private static final BlockingQueue<String> LOG_LIST = new ArrayBlockingQueue<>(256);
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
private static final OutputStream OUTPUT_STREAM = System.out;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String DELIM_STR = "{}";
private static final String TAB = "\tat";
private static final Map<String, Integer> LEVEL_MAP = new HashMap<>();
static {
LEVEL_MAP.put("DEBUG", 1);
LEVEL_MAP.put("INFO", 2);
LEVEL_MAP.put("WARN", 2);
LEVEL_MAP.put("ERROR", 2);
LEVEL_INT = LEVEL_MAP.get(LEV_EL.toUpperCase());
new Thread(() -> {
while (true) {
try {
outPutConsole(LOG_LIST.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
public static void debug(String msg) {
printLog(LEVEL_MAP.get("DEBUG"), msg);
}
public static void debug(String msg, Object params) {
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
}
public static void debug(String msg, Object... params) {
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
}
public static void info(String msg) {
printLog(LEVEL_MAP.get("INFO"), msg);
}
public static void info(String msg, Object params) {
printLog(LEVEL_MAP.get("INFO"), msg, params);
}
public static void info(String msg, Object... params) {
printLog(LEVEL_MAP.get("INFO"), msg, params);
}
public static void warn(String msg) {
printLog(LEVEL_MAP.get("WARN"), msg);
}
public static void warn(String msg, Object params) {
printLog(LEVEL_MAP.get("WARN"), msg, params);
}
public static void warn(String msg, Object... params) {
printLog(LEVEL_MAP.get("WARN"), msg, params);
}
public static void error(String msg) {
printLog(LEVEL_MAP.get("ERROR"), msg);
}
public static void error(String msg, Object params) {
printLog(LEVEL_MAP.get("ERROR"), msg, params);
}
public static void error(String msg, Object... params) {
printLog(LEVEL_MAP.get("ERROR"), msg, params);
}
public static void error(Object param) {
printLog(LEVEL_MAP.get("ERROR"), "", param);
}
private static void printLog(int levelInt, String msg, Object... params) {
try {
if (levelInt >= LEVEL_INT) {
LOG_LIST.put(generateMsg(getLevelStr(levelInt), msg, params));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static String generateMsg(String levelStr, String msg, Object... params) {
StackTraceElement stack = Thread.currentThread().getStackTrace()[4];
String s = "{} [{}][{}#{} {}] - " + msg + LINE_SEPARATOR;
Object[] args = new Object[5 + params.length];
args[0] = FORMAT.format(System.currentTimeMillis());
args[1] = levelStr;
args[2] = stack.getClassName();
args[3] = stack.getMethodName();
args[4] = stack.getLineNumber();
Throwable throwable = null;
if (params.length > 0) {
final Object lastEntry = params[params.length - 1];
if (lastEntry instanceof Throwable) {
throwable = (Throwable) lastEntry;
System.arraycopy(params, 0, args, 5, params.length - 1);
} else {
System.arraycopy(params, 0, args, 5, params.length);
}
}
return formatMsg(s, throwable, args);
}
private static String formatMsg(String msg, Throwable throwable, Object... params) {
StringBuilder sb = new StringBuilder();
int s;
int i = 0;
for (Object o : params) {
s = msg.indexOf(DELIM_STR, i);
if (s > -1) {
sb.append(msg, i, s).append(o);
i = s + 2;
}
}
sb.append(msg, i, msg.length());
if (null != throwable) {
sb.append(throwable).append(LINE_SEPARATOR);
StackTraceElement[] stack = throwable.getStackTrace();
for (StackTraceElement element : stack) {
sb.append(TAB).append(element).append(LINE_SEPARATOR);
}
}
return sb.toString();
}
private static void outPutConsole(String msg) {
try {
OUTPUT_STREAM.write(msg.getBytes(StandardCharsets.UTF_8));
OUTPUT_STREAM.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getLevelStr(int levelInt) {
switch (levelInt) {
case 1:
return "DEBUG";
case 2:
return "INFO";
case 3:
return "WARN";
case 4:
return "ERROR";
default:
throw new IllegalStateException("Level " + levelInt + " is unknown.");
}
}
}

View File

@ -0,0 +1,94 @@
/* Copyright 2018-2020 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.util;
import java.util.Random;
/**
* Random Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class RandomUtils {
private RandomUtils() {
}
private static final Random rand = new Random();
public static int nextInt(int i) {
if(i==0)
return 0;
return rand.nextInt(i);
}
public static float nextFloat() {
return rand.nextFloat();
}
public static boolean percent(float percent) {// 有百分这percent的机率为true
return rand.nextFloat() * 100 < percent;
}
public static int vary(int v, int percet) {
if (percent(percet))
return vary(v);
return v;
}
public static int vary(int v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
if (percent(10))
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
else if (percent(5))
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
else if (percent(2))
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
else if (percent(1f))
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
return v;
}
public static float vary(float v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
if (percent(10))
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
else if (percent(5))
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
else if (percent(2))
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
else if (percent(1f))
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
return v;
}
public static int varyInLimit(int v, int from, int to) {// 让返回值在from和to之间随机变异
int i = vary(v);
if (i < from)
i = from;
if (i > to)
i = to;
return i;
}
public static float varyInLimit(float v, float from, float to) {// 让返回值在from和to之间随机变异
float i = vary(v);
if (i < from)
i = from;
if (i > to)
i = to;
return i;
}
}

View File

@ -0,0 +1,105 @@
/* Copyright 2018-2020 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.util;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
/**
* StringPixelUtils used to get pixel array from a given string
*
* 根据给定的字体和字符串返回它的像素点阵lettersMap[0][0]是左下角素
*
* @author Yong Zhu
* @since 2.0.2
*/
public class StringPixelUtils {
private static final Map<String, byte[][]> lettersMap = new HashMap<>();//cache
public static byte[][] getSanserif10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 10, s);
}
public static byte[][] getSanserif12Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, s);
}
public static byte[][] getSanserifItalic10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.ITALIC, 10, s);
}
/* 在内存 BufferedImage里输出文本并获取它的像素点 */
public static byte[][] getStringPixels(String fontName, int fontStyle, int fontSize, String s) {
String key = new StringBuilder(fontName).append("_").append(fontStyle).append("_").append(fontSize).append("_")
.append(s).toString();
if (lettersMap.containsKey(key))
return lettersMap.get(key);
Font font = new Font(fontName, fontStyle, fontSize);
BufferedImage bi = new BufferedImage(fontSize * 10, fontSize * 50, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int strHeight = fm.getAscent() + fm.getDescent() - 1;
int strWidth = fm.stringWidth(s);
g2d.drawString(s, 0, fm.getAscent() - fm.getLeading() -1);
int ystart;//改进在命令行和eclipse下会有不同的空行所以要用ystart和yend来限定只获取有效象素行数
loop1: for (ystart = 0; ystart < strHeight; ystart++)
for (int x = 0; x < strWidth; x++) {
if (bi.getRGB(x, ystart) == -1)
break loop1;
}
int yend;
loop2: for (yend = strHeight; yend >= 0; yend--)
for (int x = 0; x < strWidth; x++) {
if (bi.getRGB(x, yend) == -1)
break loop2;
}
byte[][] b = new byte[strWidth][yend-ystart+1];
for (int y = ystart; y <= yend; y++)
for (int x = 0; x < strWidth; x++)
if (bi.getRGB(x, y ) == -1)
b[x][yend-y] = 1;
else
b[x][yend-y] = 0;
lettersMap.put(key, b);
return b;
}
/*- 这个是测试输出平时不需要用
public static void main(String[] args) {
System.out.println("===============");
byte[][] c = getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, "FROG");
int w = c.length;
int h = c[0].length;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][h - y - 1] > 0)
System.out.print("*");
else
System.out.print(" ");
}
System.out.println();
}
System.out.println("===============");
}
*/
}

View File

@ -0,0 +1,85 @@
/* Copyright 2018-2020 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.util;
import java.util.List;
import com.gitee.drinkjava2.frog.Env;
/**
* Tree8Util used to store a pre-order Traversal tree array to speed
*
* 这里缓存着一个前序排列的八叉树用来在细胞生成时加快速度和简化运算关于树结构可用深度树数组来表达的知识可以参见这里https://my.oschina.net/drinkjava2/blog/1818631
*
* @author Yong Zhu
* @since 1.0
*/
public class Tree8Util {
//EIGHT_TREE store a pre-order Traversal tree array
public static final int NODE_QTY = calculateNodeSize(Env.BRAIN_CUBE_SIZE);
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示第一维是深度树的行号第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
public static boolean[] ENABLE = new boolean[NODE_QTY]; //这里记录树的敲除记录被敲除的节点用false表示
public static int ENABLE_NODE_QTY = NODE_QTY; //这里记录未被敲除的总节点数好用来下次继续敲除
private static int index = 0;
static {
tree8Split(0, 0, 0, Env.BRAIN_CUBE_SIZE);
}
static int calculateNodeSize(int n) {//计算8叉树全展开的总节点数
if (n == 1)
return 1;
return n * n * n + calculateNodeSize(n / 2);
}
//if cube can split, then split it to 8 small cubes
private static void tree8Split(int x, int y, int z, int size) {//如立方体可分裂就继续递归分裂成8个
TREE8[index++] = new int[]{size, x, y, z}; //这里size类似于深度树中的level只不过是size从大到小level是从小到大原理一样
if (size == 1)
return;
int half = size / 2;//每个细胞可以分裂成8个size为原来1/2的小细胞
tree8Split(x, y, z, half);
tree8Split(x + half, y, z, half);
tree8Split(x, y + half, z, half);
tree8Split(x + half, y + half, z, half);
tree8Split(x, y, z + half, half);
tree8Split(x + half, y, z + half, half);
tree8Split(x, y + half, z + half, half);
tree8Split(x + half, y + half, z + half, half);
}
public static void knockNodesByGene(List<Integer> gene) {//根据基因把要敲除的8叉树节点作个标记0
for (int i = 0; i < Tree8Util.NODE_QTY; i++)
ENABLE[i] = true;
ENABLE_NODE_QTY = NODE_QTY;
for (int g : gene) {//g是要敲除的节点的行号
if (Tree8Util.ENABLE[g]) {
int gSize = Tree8Util.TREE8[g][0]; //gSize是节点对应的立方体边长
for (int i = g; i < Tree8Util.NODE_QTY; i++) {//从这个g节点开始往下找节点
int iSize = Tree8Util.TREE8[i][0];
if (i > g && iSize >= gSize) //如果除了第一个节点外边长与g相同或大于g的边长说明节点不是g的子节点退出
break;
else {//否则就是g的子节点需要敲除
if (Tree8Util.ENABLE[i]) { //如是还没敲除
ENABLE_NODE_QTY--; //有效节点数减1这个
Tree8Util.ENABLE[i] = false; //作敲除标记
}
}
}
}
}
}
}

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@ -0,0 +1,3 @@
## history\009c分支简介
本分支是在009b基础上的继续改进采用了阴阳(黑白)节点算法阴节点基因会删除节点下所有节点是自顶向下的减材加工阳节点基因会保留节点下所有节点是自底向上的增材加工。利用遗传算法的大样本筛选把自顶向下和自底向上两个进化方向结合起来这样基本能解决误删分支后缺色不能补回这个问题。而且对于奖罚不再象以前一样要设成差距很大的值animal.java中awardAAAA()原来要设成8000, 现在设成20也不会产生缺色现象。这个版本是研究技术细节问题看不懂的同学们可以跳过。
考虑到这个算法的特点我给它起名“阴阳无极八卦阵算法“阴阳是指它有阴阳两种节点无极是指它的分裂阶数没有限制八卦阵是指它采用了多个8叉树结构每一维细胞参数都对应一个8叉树。

View File

@ -0,0 +1 @@
mvn clean

View File

@ -0,0 +1 @@
mvn eclipse:clean

View File

@ -0,0 +1,2 @@
call mvn eclipse:eclipse
call pause

View File

@ -0,0 +1,102 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.drinkjava2</groupId>
<artifactId>frog009c</artifactId>
<packaging>jar</packaging>
<version>9.0</version>
<name>frog</name>
<description>当前目标是大方向是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务。当前小目标是要引入黑白节点算法</description>
<url>https://gitee.com/drinkjava2/jsqlbox/frog</url>
<issueManagement>
<system>gitee Issue</system>
<url>https://gitee.com/drinkjava2/jsqlbox/frog/issues</url>
</issueManagement>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<name>Yong Zhu</name>
<email>yong9981@gmail.com</email>
<url>https://gitee.com/drinkjava2/</url>
</developer>
</developers>
<scm>
<connection>scm:git@gitee.com:drinkjava2/frog.git</connection>
<developerConnection>scm:git@gitee.com:drinkjava2/frog.git</developerConnection>
<url>git@gitee.com:drinkjava2/frog.git</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<!-- Release on Java8 -->
<version.java>1.8</version.java>
<version.javadoc>6</version.javadoc>
<version.compiler-plugin>3.3</version.compiler-plugin>
<version.war-plugin>2.6</version.war-plugin>
<version.clean-plugin>3.0.0</version.clean-plugin>
<version.resources-plugin>2.7</version.resources-plugin>
<version.surefire-plugin>2.19</version.surefire-plugin>
<version.jar-plugin>2.6</version.jar-plugin>
<version.source-plugin>2.4</version.source-plugin>
<version.javadoc-plugin>2.10.3</version.javadoc-plugin>
<version.gpg-plugin>1.6</version.gpg-plugin>
</properties>
<dependencies>
<!--dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${version.compiler-plugin}</version>
<configuration>
<source>${version.java}</source>
<target>${version.java}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<useUniqueVersions>false</useUniqueVersions>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.gitee.drinkjava2.frog.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
</profiles>
</project>

View File

@ -0,0 +1,3 @@
call mvn clean compile
cd target\classes
java -classpath ".;*" com.gitee.drinkjava2.frog.Application

View File

@ -0,0 +1,2 @@
mvn clean package
java -jar target/frog-*.jar

View File

@ -0,0 +1,239 @@
/*
* 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;
import static com.gitee.drinkjava2.frog.brain.Cells.GENE_NUMBERS;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.judge.RainBowFishJudge;
import com.gitee.drinkjava2.frog.objects.Material;
import com.gitee.drinkjava2.frog.util.RandomUtils;
import com.gitee.drinkjava2.frog.util.Tree8Util;
/**
* Animal is all artificial lives' father class
* Animal only keep one copy of genes from egg, not store gene in cell
* Animal是所有动物青蛙蛇等的父类, animal是由蛋孵出来的蛋里保存着脑细胞结构生成的基因, Animal只保存一份基因而不是每个细胞都保存一份基因这是人工生命与实际生物的最大不同
* 基因是一个list<list>结构, 每一条list代表一条由深度树方式存储的基因树分表控制细胞的一个参数当cell用长整数表示时最多可以表达支持64个参数
*
*
* @author Yong Zhu
* @since 1.0
*/
public abstract class Animal {// 这个程序大量用到public变量而不是getter/setter主要是为了编程方便和简洁但缺点是编程者需要小心维护各个变量
public static BufferedImage FROG_IMAGE;
public static BufferedImage snakeImage;
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>(); // 基因是多个数列有点象多条染色体
static {
try {
FROG_IMAGE = ImageIO.read(new FileInputStream(Application.CLASSPATH + "frog.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
/** brain cells */
public long[][][] cells = new long[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
public float[][][] energys = new float[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
public int x; // animal在Env中的x坐标
public int y; // animal在Env中的y坐标
public long energy = 1000000000; // 青蛙的能量为0则死掉
public boolean alive = true; // 设为false表示青蛙死掉了将不参与计算和显示以节省时间
public int ateFood = 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 是虑拟环境的坐标
for (int i = 0; i < GENE_NUMBERS; i++) {
genes.add(new ArrayList<>());
}
int i = 0;
for (ArrayList<Integer> gene : egg.genes)//动物的基因是蛋的基因的拷贝
genes.get(i++).addAll(gene);
i = 0;
if (Env.BORN_AT_RANDOM_PLACE) { //是否随机出生在地图上?
x = RandomUtils.nextInt(Env.ENV_WIDTH);
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
} else {//否则出生成指定区域
this.x = egg.x + RandomUtils.nextInt(80) - 40;
this.y = egg.y + RandomUtils.nextInt(80) - 40;
if (this.x < 0)
this.x = 0;
if (this.y < 0)
this.y = 0;
if (this.x >= (Env.ENV_WIDTH - 1))
this.x = Env.ENV_WIDTH - 1;
if (this.y >= (Env.ENV_HEIGHT - 1))
this.y = Env.ENV_HEIGHT - 1;
}
}
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步这个方法是在当前屏animal生成之后调用比方说有一千个青蛙分为500屏测试每屏只生成2个青蛙的脑细胞可以节约内存
geneMutation(); //有小概率基因突变
for (ArrayList<Integer> gene : genes) //基因多也要适当小扣点分防止基因无限增长
energy -= gene.size();
createCellsFromGene(); //运行基因语言生成脑细胞
RainBowFishJudge.judge(this); //外界对是否长得象彩虹鱼打分
// FlowerJudge.judge(this);//外界对是否长得象小花儿打分
}
private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 5000;
private static final int MAX_ENERGY_LIMIT = Integer.MAX_VALUE - 5000;
//@formatter:off 下面几行是重要的奖罚方法会经常调整或注释掉集中放在一起不要格式化为多行
public void changeEnergy(int energy_) {//正数为奖励负数为惩罚 energy大小是环境对animal唯一的奖罚也是animal唯一的下蛋竞争标准
energy += energy_;
if (energy > MAX_ENERGY_LIMIT)
energy = MAX_ENERGY_LIMIT;
if (energy < MIN_ENERGY_LIMIT)
energy = MIN_ENERGY_LIMIT;
}
//如果改奖罚值就可能出现缺色这个要在基因变异算法从上到下从下到上和环境本身奖罚合理性上下功夫
public void awardAAAA() { changeEnergy(20);}
public void awardAAA() { changeEnergy(10);}
public void awardAA() { changeEnergy(5);}
public void awardA() { changeEnergy(2);}
public void penaltyAAAA() { changeEnergy(-20);}
public void penaltyAAA() { changeEnergy(-10);}
public void penaltyAA() { changeEnergy(-5);}
public void penaltyA() { changeEnergy(-2);}
public void kill() { this.alive = false; changeEnergy(-5); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
//@formatter:on
public boolean active() {// 这个active方法在每一步循环都会被调用是脑思考的最小帧
// 如果能量小于0出界与非食物的点重合则判死
if (!alive) {
energy = MIN_ENERGY_LIMIT; // 死掉的青蛙确保淘汰出局
return false;
}
if (energy <= 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILL_ANIMAL) {
kill();
return false;
}
//energy -= 20;
// 依次调用每个cell的active方法
//for (Cell cell : cells)
// cell.organ.active(this, cell);
return alive;
}
public void show(Graphics g) {// 显示当前动物
if (!alive)
return;
// g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标保证嘴巴显示在当前x,y处
}
/** Check if x,y,z out of animal's brain range */
public static boolean outBrainRange(int x, int y, int z) {// 检查指定坐标是否超出animal脑空间界限
return x < 0 || x >= Env.BRAIN_XSIZE || y < 0 || y >= Env.BRAIN_YSIZE || z < 0 || z >= Env.BRAIN_ZSIZE;
}
public void geneMutation() { //基因变异,注意这一个算法同时变异所有条基因目前最多允许64条基因
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阴节点基因
if (RandomUtils.percent(10)) {
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记下面的算法保证阴节点基因只添加阳节点上
int randomIndex = RandomUtils.nextInt(Tree8Util.keepNodeQTY);
int count = -1;
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {
if (Tree8Util.keep[i] >= 0) {
count++;
if (count >= randomIndex && !gene.contains(-i)) {
gene.add(-i);
break;
}
}
}
}
}
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阳节点基因
if (RandomUtils.percent(5)) {
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记下面的算法保证阳节点基因只添加在阴节点上
int yinNodeQTY = Tree8Util.NODE_QTY - Tree8Util.keepNodeQTY; //阴节点总数
int randomIndex = RandomUtils.nextInt(yinNodeQTY);
int count = -1;
for (int i = 0; i < yinNodeQTY; i++) {
if (Tree8Util.keep[i] < 0) {
count++;
if (count >= randomIndex && !gene.contains(i)) {
gene.add(i);
break;
}
}
}
}
}
// for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异将阳节点向上提升一级相当于单个细胞的自底向上扩散式生长
// if (RandomUtils.percent(3)) {
// ArrayList<Integer> gene = genes.get(g);
// int randomIndex = RandomUtils.nextInt(gene.size());
// if (randomIndex > 0 && gene.get(randomIndex) > 0) {//如基因是阳基因且节点不是顶节点
// int size = Tree8Util.TREE8[randomIndex][0];
// gene.remove(randomIndex); //先删除底层这个阳基因
// for (int i = randomIndex - 1; i > 0; i--) {
// if (Tree8Util.TREE8[i][0] > size) { //深度树只要大于size就是它的父节点
// if (!gene.contains(i))
// gene.add(i);
// int x = gene.indexOf(-i);//如果有阴节点也删除
// if (x > 0)
// gene.remove(x);
// break;
// }
// }
// }
// }
// }
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因这样可以去除无用的拉圾基因防止基因无限增大
if (RandomUtils.percent(10)) {
ArrayList<Integer> gene = genes.get(g);
if (!gene.isEmpty())
gene.remove(RandomUtils.nextInt(gene.size()));
}
}
}
private void createCellsFromGene() {//根据基因生成细胞参数
long geneMask = 1;
for (int g = 0; g < GENE_NUMBERS; g++) {//动物有多条基因一条基因控制一维细胞参数最多有64维也就是最多有64条基因
ArrayList<Integer> gene = genes.get(g);
Tree8Util.knockNodesByGene(gene);//根据基因把要敲除的8叉树节点作个标记
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树keep标记生成细胞参数
if (Tree8Util.keep[i] >= 0) {
int[] node = Tree8Util.TREE8[i];
if (node[0] == 1) {//如果node边长为1即不可以再分裂了就在三维空间对间数组的位置把当前基因geneMask置1
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask; //在相应的细胞处把细胞参数位置1
}
}
}
geneMask <<= 1;
}
}
}

View File

@ -0,0 +1,169 @@
package com.gitee.drinkjava2.frog;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
/**
* Application's main method start the program
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class Application {
public static final String CLASSPATH;
static {
String classpath = new File("").getAbsolutePath();
int i = classpath.lastIndexOf("\\frog\\");
if (i > 0)
CLASSPATH = classpath.substring(0, i) + "\\frog\\";// windows
else
CLASSPATH = classpath + "/"; // 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.BRAIN_XSIZE, Env.FROG_BRAIN_DISP_WIDTH);
public static ActionListener pauseAction;
public static boolean selectFrog = true;
private static void checkIfShowBrainPicture(JButton button) {
int y = Env.ENV_HEIGHT + 150;
if (Env.SHOW_FIRST_ANIMAL_BRAIN) {
button.setText("Hide brain");
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, y);
}
}
public static void main(String[] args) {
mainFrame.setLayout(null);
mainFrame.setSize(Env.ENV_WIDTH + 200, Env.ENV_HEIGHT + 150); // 窗口大小
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭时退出程序
mainFrame.add(env); // 添加虚拟环境Panel
mainFrame.add(brainPic); // 添加脑图Panel
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) {//显示或隐藏脑图
Env.SHOW_FIRST_ANIMAL_BRAIN = !Env.SHOW_FIRST_ANIMAL_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);
pauseAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Env.pause = !Env.pause;
if (Env.pause) {
stopButton.setText("Resume");
} else {
stopButton.setText("Pause");
brainPic.requestFocus();
}
}
};
stopButton.addActionListener(pauseAction);
mainFrame.add(stopButton);
// 速度条
final JSlider speedSlider = new JSlider(1, 10, (int) Math.round(Math.pow(Env.SHOW_SPEED, 1.0/3)));
speedSlider.setBounds(buttonXpos - 50, stopButton.getY() + 25, buttonWidth + 100, buttonHeight);
ChangeListener slideAction = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
Env.SHOW_SPEED = speedSlider.getValue() * speedSlider.getValue() * speedSlider.getValue();
brainPic.requestFocus();
}
};
speedSlider.addChangeListener(slideAction);
mainFrame.add(speedSlider);
final JLabel label = new JLabel("Speed:");
label.setBounds(buttonXpos - 90, stopButton.getY() + 23, 100, buttonHeight);
mainFrame.add(label);
//是否把egg文件存盘
JCheckBox saveFileCheckBox = new JCheckBox("Save egg file");
saveFileCheckBox.setBounds(buttonXpos, Env.ENV_HEIGHT + 80, 120, 22);
ActionListener saveAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (saveFileCheckBox.isSelected())
Env.SAVE_EGGS_FILE = true;
else
Env.SAVE_EGGS_FILE = false;
}
};
saveFileCheckBox.addActionListener(saveAction);
mainFrame.add(saveFileCheckBox);
//基因维数显示控制
for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
JRadioButton geneRadio=new JRadioButton();
geneRadio.setBounds(buttonXpos+300+i*20, Env.ENV_HEIGHT + 8, 20, 22);
geneRadio.setSelected(true);
geneRadio.setName(""+i);
ActionListener geneRadioAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
int i= Integer.parseInt(geneRadio.getName());
if (geneRadio.isSelected())
Env.display_gene[i]=true;
else
Env.display_gene[i]=false;
}
};
geneRadio.addActionListener(geneRadioAction);
mainFrame.add(geneRadio);
}
//是否显示分裂过程
JCheckBox showSplitDetailCheckBox = new JCheckBox("Show split detail");
showSplitDetailCheckBox.setBounds(buttonXpos+300, Env.ENV_HEIGHT + 40, 120, 22);
ActionListener detailAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (showSplitDetailCheckBox.isSelected())
Env.show_split_detail = true;
else
Env.show_split_detail = false;
}
};
showSplitDetailCheckBox.addActionListener(detailAction);
mainFrame.add(showSplitDetailCheckBox);
mainFrame.setVisible(true);
env.run();
}
}

View File

@ -0,0 +1,325 @@
package com.gitee.drinkjava2.frog;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.egg.Egg;
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.util.Logger;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Env is the living space of frog. draw it on JPanel
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class Env extends JPanel {
private static final long serialVersionUID = 1L;
/** Speed of test */
public static int SHOW_SPEED = 1000; // 测试速度-1000~1000,可调, 数值越小速度越慢
public static final int FROG_EGG_QTY = 100; // 每轮下n个青蛙蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
public static final int SCREEN = 1; // 分几屏测完
/** Delete eggs at beginning of each run */
public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除以前保存的青蛙蛋文件如果为false将加载旧蛋文件继续运行
public static boolean SAVE_EGGS_FILE = false; //从2021-11-23起添加这个选项允许不输出蛋文件到磁盘上
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出动物落在地图上随机位置而不是在蛋所在地
/** Frog's brain size */ // 脑细胞位于脑范围内是个三维结构在animal中用一个List<Cell>来存贮表示的同时也用一个Cell3D动态数组来表示
public static final int BRAIN_CUBE_SIZE = 16; //脑立方边长大小必须是2的幂数如4,8,16...
public static final int BRAIN_XSIZE = BRAIN_CUBE_SIZE; // 脑在X方向长度取值最大为1000
public static final int BRAIN_YSIZE = BRAIN_CUBE_SIZE; // 脑在Y方向长度取值最大为1000
public static final int BRAIN_ZSIZE = BRAIN_CUBE_SIZE; // 脑在Z方向长度取值最大为1000
public static final int CELLS_MAX_QTY = 4000; //脑细胞总数不能超过这个值
/** SHOW first animal's brain structure */
public static boolean SHOW_FIRST_ANIMAL_BRAIN = true; // 是否显示脑图在Env区的右侧
/** Draw first frog's brain after some steps */
public static int DRAW_BRAIN_AFTER_STEPS = 0; // 以此值为间隔动态画出脑图设为0则关闭这个动态脑图功能只显示一个静态不闪烁的脑图
/** Environment x width, unit: pixels */
public static final int ENV_WIDTH = 400; // 虚拟环境的宽度, 可调
/** Environment y height, unit: pixels */
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的脑图在屏幕上的显示大小,可调
/** Steps of one test round */
public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调
public static int step;// 当前测试步数
public static final int FOOD_QTY = 1500; // 食物数量, 可调
// 以下是程序内部变量不要手工修改它们
public static final int TOTAL_FROG_QTY = FROG_EGG_QTY * FROG_PER_EGG; // 蛇的总数
public static final int FROG_PER_SCREEN = TOTAL_FROG_QTY / SCREEN; // 每屏显示几个青蛙这个数值由其它常量计算得来
public static int current_screen = 0;
public static int food_ated = 0; // 用来统计总共多少个食物被青蛙吃掉
public static int frog_ated = 0; // 用来统计总共多少个青蛙被蛇吃掉
public static boolean pause = false; // 暂停按钮按下将暂停测试
public static int[][] bricks = new int[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料见Material.java
public static List<Frog> frogs = new ArrayList<>(); // 这里存放所有待测的青蛙可能分几次测完由FROG_PER_SCREEN大小来决定
public static List<Egg> frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋每个蛋可能生成几个青蛙
public static EnvObject[] things = new EnvObject[]{ };// 所有外界物体如食物字母测试工具都放在这个things里面
public static boolean show_split_detail=false; //是否显示脑分裂的细节过程即从一个细胞开始分裂分裂而不是只显示分裂的最终结果
public static boolean[] display_gene=new boolean[Cells.GENE_NUMBERS]; //脑最多有64个基因这里用来控制哪些基因需要显示在脑图上
static {
Logger.info("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒见码云issue#IW4H8
Logger.info("脑图快捷键: T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移");
if (DELETE_FROG_EGGS)
FrogEggTool.deleteEggs();
for (int i = 0; i < display_gene.length; i++)
display_gene[i]=true;
}
public Env() {
super();
this.setLayout(null);// 空布局
this.setBounds(1, 1, ENV_WIDTH, ENV_HEIGHT);
}
public static boolean insideEnv(int x, int y) {// 如果指定点在边界内
return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT);
}
public static boolean outsideEnv(int x, int y) {// 如果指定点超出边界
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT;
}
public static boolean closeToEdge(Animal a) {// 靠近边界? 离死不远了
return a.x < 20 || a.y < 20 || a.x > (Env.ENV_WIDTH - 20) || a.y > (Env.ENV_HEIGHT - 20);
}
public static boolean foundAnyThingOrOutEdge(int x, int y) {// 如果指定点看到任意东西或超出边界返回true
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] != 0;
}
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物将其清0返回true
if (insideEnv(x, y) && (Env.bricks[x][y] & Material.FOOD) > 0) {
Env.food_ated++;
clearMaterial(x, y, Material.FOOD);// 清空任意食物
return true;
}
return false;
}
public static boolean foundFrogOrOutEdge(int x, int y) {// 如果指定点看到青蛙或超出边界返回true
if (x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT)
return true;// 如果出界返回true
if ((Env.bricks[x][y] & Material.FROG_TAG) > 0)
return true;
else
return false;
}
public static void setMaterial(int x, int y, int material) {
if (Env.insideEnv(x, y))
Env.bricks[x][y] = Env.bricks[x][y] | material;
}
public static boolean hasMaterial(int x, int y, int material) {
if (!Env.insideEnv(x, y))
return false;
return (Env.bricks[x][y] & material) > 0;
}
public static void clearMaterial(int x, int y, int material) {
if (Env.insideEnv(x, y))
Env.bricks[x][y] = Env.bricks[x][y] & ~material;
}
private void rebuildFrogs() {// 根据蛙蛋重新孵化出蛙
frogs.clear();
for (int i = 0; i < frog_eggs.size(); i++) {// 创建青蛙每个蛋生成n个蛙并随机取一个别的蛋作为精子
int loop = FROG_PER_EGG;
if (frog_eggs.size() > 20) { // 如果数量多进行一些优化让排名靠前的Egg多孵出青蛙
if (i < FROG_PER_EGG)// 0,1,2,3
loop = FROG_PER_EGG + 1;
if (i >= (frog_eggs.size() - FROG_PER_EGG))
loop = FROG_PER_EGG - 1;
}
for (int j = 0; j < loop; j++) {
Egg zygote = new Egg(frog_eggs.get(i), frog_eggs.get(RandomUtils.nextInt(frog_eggs.size())));
Frog f = new Frog(zygote);
frogs.add(f);
f.no = frogs.size();
}
}
}
private void drawWorld(Graphics g) {
int brick;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++) {
brick = bricks[x][y];
if (brick != 0) {
g.setColor(Material.color(brick));
if ((brick & Material.FOOD) > 0) {
g.fillRoundRect(x, y, 4, 4, 2, 2); //食物只有一个点太小画大一点
} else
g.drawLine(x, y, x, y); // only 1 point
}
}
g.setColor(Color.BLACK);
}
static final NumberFormat format100 = NumberFormat.getPercentInstance();
static {
format100.setMaximumFractionDigits(2);
}
private String foodAtedCount() {// 统计吃食总数等
int maxFound = 0;
for (Frog f : frogs)
if (f.ateFood > maxFound)
maxFound = f.ateFood;
return new StringBuilder("吃食率:").append(format100.format(Env.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Env.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound)
.toString();
}
private String frogAtedCount() {// 统计食蛙总数
return new StringBuilder("吃蛙率:").append(format100.format(Env.frog_ated * 1.00 / TOTAL_FROG_QTY)).toString();
}
public static void checkIfPause() {
if (pause)
do {
Application.brainPic.drawBrainPicture();
Application.brainPic.requestFocus();
sleep(100);
} while (pause);
}
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static Animal getShowAnimal() {
return frogs.get(current_screen * FROG_PER_SCREEN);
}
public void run() {
FrogEggTool.loadFrogEggs(); // 从磁盘加载蛙egg或新建一批egg
Image buffImg = createImage(this.getWidth(), this.getHeight());
Graphics g = buffImg.getGraphics();
long time0;// 计时用
int round = 1;
do {
rebuildFrogs(); // 根据蛙蛋重新孵化出蛙注意基因变异有可能在孵化过程中发生
for (current_screen = 0; current_screen < SCREEN; current_screen++) {// 分屏测试每屏FROG_PER_SCREEN个蛙
Env.food_ated = 0; // 先清0吃食物数
Env.frog_ated = 0;// 先清0吃蛙数
time0 = System.currentTimeMillis();
for (EnvObject thing : things) // 创建食物陷阱等物体
thing.build();
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();
if (allDead)
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
allDead = true;
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
if (f.active())// 调用青蛙的Active方法并返回是否还活着
allDead = false;
}
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用是否跳帧画图的方式来控制速度
continue;
if (SHOW_SPEED < 0) // 如果speed小于0人为加入延迟
sleep(-SHOW_SPEED);
// 开始画虚拟环境和青蛙和蛇
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境
g.setColor(Color.BLACK);
drawWorld(g);// 画整个虚拟环境
for (int j = 0; j < FROG_PER_SCREEN; j++) { // 显示青蛙
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
f.show(g);
}
if (SHOW_FIRST_ANIMAL_BRAIN) {// 在showAnimal上画一个红圈
Animal showAnimal = getShowAnimal();
if (showAnimal != null) {
g.setColor(Color.red);
g.drawArc(showAnimal.x - 15, showAnimal.y - 15, 30, 30, 0, 360);
g.setColor(Color.BLACK);
}
}
if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0)
Application.brainPic.drawBrainPicture();
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
}
if (SHOW_FIRST_ANIMAL_BRAIN)
Application.brainPic.drawBrainPicture();
checkIfPause();
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(foodAtedCount());
Application.mainFrame.setTitle(sb.toString());
// for (EnvObject thing : things)// 去除食物陷阱等物体
// thing.destory();
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
bricks[i][j] = 0;
}
}
round++;
FrogEggTool.layEggs(); //能量高的青蛙才有权下蛋
} while (true);
}
}

View File

@ -0,0 +1,29 @@
/*
* 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;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.objects.Material;
/**
* Frog is child class of Animal, Frog's name is Sam
* Frog是Animal的一个子类
*
* @since 1.0
*/
public class Frog extends Animal {
public Frog(Egg egg) {
super(egg);
animalMaterial = Material.FROG_TAG;
animalImage = Animal.FROG_IMAGE;
}
}

View File

@ -0,0 +1,450 @@
package com.gitee.drinkjava2.frog.brain;
import static java.awt.Color.BLACK;
import static java.awt.Color.RED;
import static java.awt.Color.WHITE;
import static java.lang.Math.cos;
import static java.lang.Math.round;
import static java.lang.Math.sin;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Application;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.util.ColorUtils;
import com.gitee.drinkjava2.frog.util.Tree8Util;
/**
* BrainPicture show first frog's brain structure, for debug purpose only
*
* 这个类用来画出脑图这不是一个关键类对脑的运行逻辑无影响但有了脑图后可以直观地看出脑的3维结构进行有针对性的改进
* 可以用鼠标进行平移缩放旋转以及tflr,x五个键来选择顶视前视左视右视斜视这5个方向的视图以及空格暂停方向键调整切面
* 鼠标的动作定义在MouseAction类中
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class BrainPicture extends JPanel {
private static final long serialVersionUID = 1L;
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;
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,rx键盘命令
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()){
case KeyEvent.VK_UP:// Y切面向上
yMask++;
if (yMask > Env.BRAIN_YSIZE)
yMask = Env.BRAIN_YSIZE;
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_XSIZE)
xMask = Env.BRAIN_XSIZE;
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(Cuboid c) {// 在脑图上画一个长立方体框架视角是TopView
drawCuboid(c.x, c.y, c.z, c.xe, c.ye, c.ze);
}
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 + 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);
}
/*-
画线固定以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_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
double x2 = px2 - Env.BRAIN_XSIZE / 2;
double y2 = -py2 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z2 = pz2 - Env.BRAIN_ZSIZE / 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 = 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;
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;
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_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 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 = 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));
}
/** 画一个圆 */
public void drawCircle(float px1, float py1, float pz1, float r) {//这个方法实际和上面的一样的只是改成了drawOval
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 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 = 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));
}
public void drawText(float px1, float py1, float pz1, String text, float textSize) {
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 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 = 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);
}
private static Cuboid brain = new Cuboid(0, 0, 0, Env.BRAIN_XSIZE, Env.BRAIN_YSIZE, Env.BRAIN_ZSIZE);
public void drawBrainPicture() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
if (!Env.SHOW_FIRST_ANIMAL_BRAIN)
return;
if(Env.show_split_detail)
drawSplitDetail();
else
drawBrainStructure();
}
public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚即从一个细胞开始分裂成最终脑结构的每一步
Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
for (int i = Env.BRAIN_CUBE_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);
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
ArrayList<Integer> 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 && Env.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(brain);// 把脑的框架画出来
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁这里输出缓存图片
if (!Env.show_split_detail)
return;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
public void drawBrainStructure() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
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 z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--) {
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
if (x >= xMask && y >= yMask && a.cells[x][y][z] != 0)
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
if ((a.cells[x][y][z] & (1 << geneIndex)) != 0 && Env.display_gene[geneIndex]) {
setPicColor(ColorUtils.colorByCode(geneIndex)); //开始画出对应的细胞基因参数用不同颜色直径圆表示
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, geneIndex == 0 ? 0.8f : 0.5f - geneIndex * 0.05f);
}
}
}
}
}
setPicColor(Color.BLACK);
//BrainShapeJudge.show(this);//这行显示目标形状这个模子
drawCuboid(brain);// 把脑的框架画出来
setPicColor(BLACK); //把x,y,z坐标画出来
drawText(Env.BRAIN_CUBE_SIZE, 0, 0, "x", 2);
drawText(0, Env.BRAIN_CUBE_SIZE, 0, "y", 2);
drawText(0, 0, Env.BRAIN_CUBE_SIZE, "z", 2);
setPicColor(RED);
drawLine(0, 0, 0, Env.BRAIN_CUBE_SIZE, 0, 0);
drawLine(0, 0, 0, 0, Env.BRAIN_CUBE_SIZE, 0);
drawLine(0, 0, 0, 0, 0, Env.BRAIN_CUBE_SIZE);
g.setColor(Color.black);
if (note != null) // 全局注释
g.drawString(note, 30, 55);
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁这里输出缓存图片
}
public static void setNote(String note) {
Application.brainPic.note = note;
}
// getters & setters
public float getScale() {
return scale;
}
public void setScale(float scale) {
this.scale = scale;
}
public float getxAngle() {
return xAngle;
}
public void setxAngle(float xAngle) {
this.xAngle = xAngle;
}
public float getyAngle() {
return yAngle;
}
public void setyAngle(float yAngle) {
this.yAngle = yAngle;
}
public float getzAngle() {
return zAngle;
}
public void setzAngle(float zAngle) {
this.zAngle = zAngle;
}
public void setPicColor(Color color) {
this.picColor = color;
}
public Color getPicColor() {
return picColor;
}
public int getxOffset() {
return xOffset;
}
public void setxOffset(int xOffset) {
this.xOffset = xOffset;
}
public int getyOffset() {
return yOffset;
}
public void setyOffset(int yOffset) {
this.yOffset = yOffset;
}
}

View File

@ -0,0 +1,23 @@
/*
* 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;
/**
* Cells代表不同的脑细胞参数对应每个参数细胞有不同的行为
*
* @author Yong Zhu
* @since 10.0
*/
@SuppressWarnings("all")
public class Cells {
public static int GENE_NUMBERS = 4; //目前有多少条基因每个脑细胞用是一个long来存储所以最多允许64条基因每个基因控制一个细胞的参数
}

View File

@ -0,0 +1,55 @@
/*
* 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;
/**
* Cuboid represents a rectangular prism 3d zone in brain
*
* Cuboid是一个长方体通常用来表示脑内器官的形状
*
* @author Yong Zhu
* @since 2.0.2
*/
@SuppressWarnings("all")
public class Cuboid {
private static final long serialVersionUID = 1L;
public float x;// x,y,z是长方体的左下角坐标
public float y;
public float z;
public float xe;// xe,ye,ze分别是长方体三边长
public float ye;
public float ze;
public Cuboid() {
// 空构造器不能省
}
public Cuboid(float x, float y, float z, float xe, float ye, float ze) {// 用x,y,z,r来构造
this.x = x;
this.y = y;
this.z = z;
this.xe = xe;
this.ye = ye;
this.ze = ze;
}
public Cuboid(Cuboid c) {// 用另一个Cuboid来构造
this.x = c.x;
this.y = c.y;
this.z = c.z;
this.xe = c.xe;
this.ye = c.ye;
this.ze = c.ze;
}
}

View File

@ -0,0 +1,107 @@
package com.gitee.drinkjava2.frog.brain;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
/**
* MouseAction
*
* 这个类用来处理脑图BrainPicture上的鼠标动作有平移旋转缩放三种
*
* @author Yong Zhu
* @since 2.0.2
*/
public class MouseAction implements MouseListener, MouseWheelListener, MouseMotionListener {
private BrainPicture brainPic;
private int buttonPressed = 0;
private int x;
private int y;
public MouseAction(BrainPicture brainPic) {
this.brainPic = brainPic;
}
@Override
public void mousePressed(MouseEvent e) {// 记录当前鼠标点
if (e.getButton() == 1)// 旋转
buttonPressed = 1;
else if (e.getButton() == 2)// 缩放
buttonPressed = 2;
else
buttonPressed = 0;
x = e.getPoint().x;
y = e.getPoint().y;
brainPic.requestFocus();
}
@Override
public void mouseReleased(MouseEvent e) {
buttonPressed = 0;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {// 缩放
if (e.getWheelRotation() < 0) {
brainPic.scale *= 1.1;
brainPic.xOffset *= 1.1;
brainPic.yOffset *= 1.1;
} else {
brainPic.scale /= 1.1;
brainPic.xOffset /= 1.1;
brainPic.yOffset /= 1.1;
}
}
@Override
public void mouseDragged(MouseEvent e) {// 旋转
if (buttonPressed == 1) {
if (e.getX() > x && e.getY() > y)
brainPic.zAngle -= .00f;
else if (e.getX() < x && e.getY() < y)
brainPic.zAngle += .00f;
else {
if (e.getX() > x)
brainPic.yAngle += .02f;
if (e.getX() < x)
brainPic.yAngle -= .02f;
if (e.getY() > y)
brainPic.xAngle -= .02f;
if (e.getY() < y)
brainPic.xAngle += .02f;
}
x = e.getX();
y = e.getY();
}
if (buttonPressed == 2) {// 平移
if (e.getX() > x)
brainPic.xOffset += 6;
if (e.getX() < x)
brainPic.xOffset -= 6;
if (e.getY() > y)
brainPic.yOffset += 6;
if (e.getY() < y)
brainPic.yOffset -= 6;
x = e.getX();
y = e.getY();
}
}
@Override
public void mouseClicked(MouseEvent e) {// do nothing
}
@Override
public void mouseEntered(MouseEvent e) {// do nothing
}
@Override
public void mouseExited(MouseEvent e) {// do nothing
}
@Override
public void mouseMoved(MouseEvent e) { // do nothing
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.egg;
import java.io.Serializable;
import java.util.ArrayList;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Egg is the static structure description of brain cells
*
* 蛋存在的目的是为了以最小的字节数串行化存储脑细胞,它是海量脑细胞的生成算法描述而不是脑细胞本身
* 蛋和基因的关系基因是一种语言相当于染色体不存在坐标位置蛋则是基因的载体有x,y坐标表示在虚拟环境中蛋存在的位置
*
* 另外青蛙本身也是基因的载体所以青蛙里有一个gene属性
*
* @author Yong Zhu
* @since 1.0
*/
public class Egg implements Serializable {
private static final long serialVersionUID = 1L;
public int x; // 蛋的x位置
public int y; // 蛋的y位置
// gene is a language similar like BASIC created by random
// 基因是随机生成的一种类似Basic语言的字符串符列保存在蛋中和实际生物每个细胞都要保存一份基因不同程序中每个细胞仅保存着基因的指针和当前细胞位于基因链中的行号并不需要保存基因的副本这样可以极大地减少内存占用
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>();
public Egg() {// 无中生有创建一个蛋先有蛋后有蛙d
x = RandomUtils.nextInt(Env.ENV_WIDTH);
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
}
/** Create egg from animal */
public Egg(Animal a) { // 下蛋每个器官会创建自已的副本或变异可以是0或多个
x = a.x;
y = a.y;
for (ArrayList<Integer> gene : a.genes) {//下蛋就是把动物的基因拷贝到新蛋里并有可能变异
ArrayList<Integer> g = new ArrayList<>();
g.addAll(gene);
genes.add(g);
}
}
/**
* Create a egg by join 2 eggs, x+y=zygote 模拟XY 染色体合并两个蛋生成一个新的蛋
*/
public Egg(Egg a, Egg b) {//两个蛋的基因混合, 生成一个新蛋
x = a.x;
y = a.y;
genes.addAll(a.genes);
// if (!genes.isEmpty() && b != null)
// for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
// if (RandomUtils.percent(3)) {
// ArrayList<Integer> agene = a.genes.get(i);
// ArrayList<Integer> bgene = b.genes.get(i);
// if (!bgene.isEmpty())
// agene.add(bgene.get(RandomUtils.nextInt(bgene.size())));
// }
// }
}
}

View File

@ -0,0 +1,112 @@
/*
* 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.egg;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Application;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.Frog;
import com.gitee.drinkjava2.frog.util.LocalFileUtils;
import com.gitee.drinkjava2.frog.util.Logger;
/**
* FrogEggTool save/load frog eggs to file
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class FrogEggTool {
/**
* Frogs which have higher energy lay eggs
*
* 利用Java串行机制存盘 能量多(也就是吃的更多)的Frog下蛋并存盘, 以进行下一轮测试能量少的Frog被淘汰没有下蛋的资格
* 用能量的多少来简化生存竟争模拟每次下蛋数量固定为EGG_QTY个
*/
public static void layEggs() {
sortFrogsOrderByEnergyDesc();
Frog first = Env.frogs.get(0);
Frog last = Env.frogs.get(Env.frogs.size() - 1);
try {
Env.frog_eggs.clear();
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
Logger.info("Fist frog energy={}, Last frog energy={}", first.energy, last.energy);
if (Env.SAVE_EGGS_FILE) {
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(Env.frog_eggs);
so.close();
Logger.info(". Saved {} eggs to file '{}frog_eggs.ser'", Env.frog_eggs.size(), Application.CLASSPATH);
}
} catch (IOException e) {
Logger.error(e);
}
}
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
Collections.sort(Env.frogs, new Comparator<Animal>() {
public int compare(Animal a, Animal b) {
if (a.energy > b.energy)
return -1;
else if (a.energy == b.energy)
return 0;
else
return 1;
}
});
}
public static void deleteEggs() {
Logger.info("Delete exist egg file: '{}frog_eggs.ser'", Application.CLASSPATH);
LocalFileUtils.deleteFile(Application.CLASSPATH + "frog_eggs.ser");
}
/**
* 从磁盘读入一批frog Egg
*/
@SuppressWarnings("unchecked")
public static void loadFrogEggs() {
boolean errorfound = false;
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
Env.frog_eggs = (List<Egg>) eggsInputStream.readObject();
Logger.info("Loaded " + Env.frog_eggs.size() + " eggs from file '" + Application.CLASSPATH
+ "frog_eggs.ser" + "'.\n");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
}
if (errorfound) {
Env.frog_eggs.clear();
for (int j = 0; j < Env.FROG_EGG_QTY; j++) {
Egg egg = new Egg();
Env.frog_eggs.add(egg);
}
Logger.info("Fail to load frog egg file '" + Application.CLASSPATH + "frog_eggs.ser" + "', created "
+ Env.frog_eggs.size() + " eggs to do test.");
}
}
}

View File

@ -0,0 +1,85 @@
package com.gitee.drinkjava2.frog.judge;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.StringPixelUtils;
/**
* judge method be called in animal's initAnimal method
*
* 这个类的judge方法在动物的初始化后被调用根据脑细胞群的三维结构和参数来对动物进行奖罚即加减它的能量值这是一个临时类只是用来检验细胞三维成形功能以后可能改名或删除
* 这个类的show方法在绘脑图时调用在脑图里显示脑细胞群的三维形状和参数用不同颜色直径的空心圆来表示不同参数judge方法就像是一个模子细胞长在这个模子里的有奖否则扣分
*/
public class FlowerJudge extends RainBowFishJudge {//NOSONAR
private static int[] C = new int[]{0, 0, Env.BRAIN_CUBE_SIZE / 2}; //C是中心点
private static boolean[][][] shape = new boolean[Env.BRAIN_XSIZE][Env.BRAIN_YSIZE][Env.BRAIN_ZSIZE];
private static List<int[]> pointList = new ArrayList<>(); //pointList存放上面shape的所有有效点用来加快显示循环而不用遍历三维数组
static {
putPixiel("🌸");
}
public static void putPixiel(String str) {
byte[][] c = StringPixelUtils.getStringPixels(Font.SANS_SERIF, Font.PLAIN, Env.BRAIN_CUBE_SIZE, str); //要把frog二维像素变成立体的三维点放到points里和pointsList里供使用
int w = c.length;
int h = c[0].length;
for (int z = 0; z < 5; z++) {
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][y] > 0) {
int[] p = new int[]{C[0] + x, C[1] + y + 2, C[2] + z};
if (!Animal.outBrainRange(p[0], p[1]-2, p[2])) {//减2是把花朵向下移两格
shape[p[0]][p[1]-2][p[2]] = true;
pointList.add(p);
}
}
}
}
}
}
private static void judgeShape(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++) {
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++) {
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
if ((animal.cells[x][y][z] & 1) != 0)
if (shape[x][y][z]) {
animal.awardAAAA();
} else {
animal.penaltyAAA();
}
}
}
}
}
public static void judgeColor(Animal animal) {//检查颜色与小鱼图像重合且呈斑马纹色彩分布是就加分否则扣分
int colorWidth = Env.BRAIN_CUBE_SIZE / Cells.GENE_NUMBERS; //每条彩带宽度
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++)
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++)
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++)
for (int i = 1; i <= Cells.GENE_NUMBERS; i++)
if ((animal.cells[x][y][z] & (1 << i)) != 0) { //如果色彩存在
if ((animal.cells[x][y][z] & 1) != 0 && y >= (i - 1) * colorWidth && y < (i * colorWidth))
animal.awardAA(); //如果细胞存在且颜色分布符合要求奖励
else
animal.penaltyA();//否则扣分
}
}
public static void judge(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
judgeShape(animal);
judgeColor(animal);
}
public static void show(BrainPicture pic) {// 在脑图上显示当前形状
for (int[] p : pointList)
pic.drawCircle(p[0] + 0.5f, p[1] + 0.5f, p[2] + 0.5f, 1);
}
}

View File

@ -0,0 +1,84 @@
package com.gitee.drinkjava2.frog.judge;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.StringPixelUtils;
/**
* judge method be called in animal's initAnimal method
*
* 这个类的judge方法在动物的初始化后被调用根据脑细胞群的三维结构和参数来对动物进行奖罚即加减它的能量值这是一个临时类只是用来检验细胞三维成形功能以后可能改名或删除
* 这个类的show方法在绘脑图时调用在脑图里显示脑细胞群的三维形状和参数用不同颜色直径的空心圆来表示不同参数judge方法就像是一个模子细胞长在这个模子里的有奖否则扣分
*/
public class RainBowFishJudge {//NOSONAR
private static int[] C = new int[]{0, 0, Env.BRAIN_CUBE_SIZE / 2}; //C是中心点
private static boolean[][][] shape = new boolean[Env.BRAIN_XSIZE][Env.BRAIN_YSIZE][Env.BRAIN_ZSIZE];
private static List<int[]> pointList = new ArrayList<>(); //pointList存放上面shape的所有有效点用来加快显示循环而不用遍历三维数组
static {
putPixiel("🐟");
}
public static void putPixiel(String str) {
byte[][] c = StringPixelUtils.getStringPixels(Font.SANS_SERIF, Font.PLAIN, Env.BRAIN_CUBE_SIZE, str); //要把frog二维像素变成立体的三维点放到points里和pointsList里供使用
int w = c.length;
int h = c[0].length;
for (int z = 0; z < 5; z++) {
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][y] > 0) {
int[] p = new int[]{C[0] + x, C[1] + y + 2, C[2] + z};
if (!Animal.outBrainRange(p[0], p[1], p[2])) {
shape[p[0]][p[1]][p[2]] = true;
pointList.add(p);
}
}
}
}
}
}
private static void judgeShape(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++) {
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++) {
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
if ((animal.cells[x][y][z] & 1) != 0)
if (shape[x][y][z]) {
animal.awardAAAA();
} else {
animal.penaltyAAA();
}
}
}
}
}
public static void judgeColor(Animal animal) {//检查颜色与小鱼图像重合且呈斑马纹色彩分布是就加分否则扣分
int colorWidth = Env.BRAIN_CUBE_SIZE / Cells.GENE_NUMBERS; //每条彩带宽度
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++)
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++)
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++)
for (int i = 1; i <= Cells.GENE_NUMBERS; i++)
if ((animal.cells[x][y][z] & (1 << i)) != 0) //如果色彩存
if ((animal.cells[x][y][z] & 1) != 0 && x >= (i - 1) * colorWidth && x < (i * colorWidth))
animal.awardAA();
else
animal.penaltyA();
}
public static void judge(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
judgeShape(animal);
judgeColor(animal);
}
public static void show(BrainPicture pic) {// 在脑图上显示当前形状
for (int[] p : pointList)
pic.drawCircle(p[0] + 0.5f, p[1] + 0.5f, p[2] + 0.5f, 1);
}
}

View File

@ -0,0 +1,26 @@
/* Copyright 2018-2020 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.objects;
/**
* EnvObject means some virtual object in Env
*
* @author Yong Zhu
* @since 1.0
*/
public interface EnvObject {
public void build(); // 在Env中创建本身物体指改变Env.bricks数组元素为本身物体的组成材料只在每屏测试前调用一次
public void destory();// 从Env中清除本身物体只在每屏测试完成后调用一次
public void active(); // 每个步长都会调用一次这个方法
}

View File

@ -0,0 +1,47 @@
/* Copyright 2018-2020 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.objects;
import static com.gitee.drinkjava2.frog.Env.ENV_HEIGHT;
import static com.gitee.drinkjava2.frog.Env.ENV_WIDTH;
import static com.gitee.drinkjava2.frog.Env.FOOD_QTY;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Food randomly scatter on Env
* 生成食物静态食物或苍蝇苍蝇如果Env中FOOD_CAN_MOVE=true,会向四个方向移动)
*
* @author Yong Zhu
* @since 1.0
*/
public class Food implements EnvObject {
@Override
public void build() {
for (int i = 0; i < FOOD_QTY; i++) // 生成食物
Env.setMaterial(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), Material.FOOD);
}
@Override
public void destory() {
for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物
for (int j = 0; j < ENV_HEIGHT; j++)
Env.clearMaterial(i, j, Material.FOOD);
}
}
@Override
public void active() {
}
}

View File

@ -0,0 +1,50 @@
/* Copyright 2018-2020 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.objects;
import java.awt.Color;
/**
* Material store material types
*
* 虚拟环境中每个点由一个int代表多个材料可以同时出现在同一个点每种材料用int中的一个bit位来表示
* 小于等于16384的位数用来标记青蛙序号可利用Env.frogs.get(no-1)获取青蛙对象其它各种材料用整数中其它位来表示
*
* @author Yong Zhu
* @since 1.0
*/
public class Material {// NOSONAR
public static final int FROG_TAG = 0b11111111111111; // 16383 小于等于16384的位数用来标记青蛙序号可利用Env.frogs.get(no-1)快速定位青蛙
private static int material = FROG_TAG + 1; // 大于16384用来作为各种材料的标记
public static final int FOOD = nextMaterial();
public static final int SNAKE = nextMaterial(); // 蛇的图形
public static final int KILL_ANIMAL = nextMaterial(); // if>=KILLFROG will kill animal
public static final int BRICK = nextMaterial();// brick will kill frog
public static final int TRAP = nextMaterial(); // trap will kill frog
private static int nextMaterial() {// 每次将material左移1位
material = material << 1;
if (material < 0)
throw new IllegalArgumentException("Material out of maximum range");
return material;
}
public static Color color(int material) {
if ((material & TRAP) > 0)
return Color.LIGHT_GRAY;
else
return Color.BLACK;
}
}

View File

@ -0,0 +1,62 @@
/* Copyright 2018-2020 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.util;
import java.awt.Color;
/**
* Color Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class ColorUtils {
private static final Color[] rainbow = new Color[]{Color.GRAY, Color.GREEN, Color.RED, Color.BLUE, Color.YELLOW, Color.ORANGE, Color.MAGENTA, Color.CYAN};
private static int nextColor = 0;
private ColorUtils() {// default private constr
}
public static int nextColorCode() {
return nextColor++;
}
public static Color nextRainbowColor() {// 返回下一个彩虹色
if (nextColor == rainbow.length)
nextColor = 0;
return rainbow[nextColor++];
}
public static Color colorByCode(int i) {// 数值取模后返回一个固定彩虹色
return rainbow[i % rainbow.length];
}
public static Color rainbowColor(float i) { // 根据数值大小范围在8种彩虹色中取值
if (i <= 20)
return Color.GRAY;
if (i <= 30)
return Color.BLACK;
if (i <= 50)
return Color.RED;
return Color.MAGENTA;
}
public static Color grayColor(float f) { // 根据数值大小范围0~1000返回一个灰度色越大越黑
if (f > 1000)
f = 1000;
int i1 = 255 - (int) Math.round(f * .255);
int i2 = 200 - (int) Math.round(f * .200);
int i3 = 150 - (int) Math.round(f * .150);
return new Color(i1, i2, i3);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.util;
/**
* Cube has x,y,z value
*
* @author Yong Zhu
* @since 2021-11-07
*/
public class Cube {
public int x;//x,y,z是cube的左下前点坐标
public int y;
public int z;
public int size;//size是cube的边长
public Cube(int x, int y, int z, int size) {
this.x = x;
this.y = y;
this.z = z;
this.size = size;
}
}

View File

@ -0,0 +1,141 @@
/* Copyright 2018-2020 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.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Local File Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class LocalFileUtils {
private LocalFileUtils() {
// default constructor
}
public static boolean deleteFile(String fileFullPath) {
File file = new File(fileFullPath);
return file.delete(); // NOSONAR
}
public static void writeFile(String fileFullPath, byte[] byteArry) {
File file = new File(fileFullPath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(byteArry);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void writeFile(String fileFullPath, String text, String encoding) {
File file = new File(fileFullPath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
byte[] bytes;
bytes = text.getBytes(encoding);
fos.write(bytes);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String readFile(String fileFullPath, String encoding) {
InputStream inputStream;
try {
inputStream = new FileInputStream(new File(fileFullPath));
} catch (FileNotFoundException e1) {
return null;
}
try {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1)
result.write(buffer, 0, length);
String string = result.toString(encoding);
return string;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
public static void appendFile(String fileName, String content) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(fileName, true);
fos.write(content.getBytes());
fos.write("\r\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright 2021 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.util;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* Usually a logger tool is used like below:
* Logger log = LoggerFactory.getLogger(Xxxx.class);
* log.info("some msg");
*
* But to simplify, in this project directly use static method:
* Logger.info("some msg");
*
* @Description: 简版控制台日志打印从码云上合并来 https://gitee.com/drinkjava2/frog/pulls/4
* @author 栾成翔
* @Date: 2021/12/07
*/
@SuppressWarnings("all")
public class Logger {
private static final String LEV_EL = "debug";
private static final int LEVEL_INT;
private static final BlockingQueue<String> LOG_LIST = new ArrayBlockingQueue<>(256);
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
private static final OutputStream OUTPUT_STREAM = System.out;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String DELIM_STR = "{}";
private static final String TAB = "\tat";
private static final Map<String, Integer> LEVEL_MAP = new HashMap<>();
static {
LEVEL_MAP.put("DEBUG", 1);
LEVEL_MAP.put("INFO", 2);
LEVEL_MAP.put("WARN", 2);
LEVEL_MAP.put("ERROR", 2);
LEVEL_INT = LEVEL_MAP.get(LEV_EL.toUpperCase());
new Thread(() -> {
while (true) {
try {
outPutConsole(LOG_LIST.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
public static void debug(String msg) {
printLog(LEVEL_MAP.get("DEBUG"), msg);
}
public static void debug(String msg, Object params) {
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
}
public static void debug(String msg, Object... params) {
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
}
public static void info(String msg) {
printLog(LEVEL_MAP.get("INFO"), msg);
}
public static void info(String msg, Object params) {
printLog(LEVEL_MAP.get("INFO"), msg, params);
}
public static void info(String msg, Object... params) {
printLog(LEVEL_MAP.get("INFO"), msg, params);
}
public static void warn(String msg) {
printLog(LEVEL_MAP.get("WARN"), msg);
}
public static void warn(String msg, Object params) {
printLog(LEVEL_MAP.get("WARN"), msg, params);
}
public static void warn(String msg, Object... params) {
printLog(LEVEL_MAP.get("WARN"), msg, params);
}
public static void error(String msg) {
printLog(LEVEL_MAP.get("ERROR"), msg);
}
public static void error(String msg, Object params) {
printLog(LEVEL_MAP.get("ERROR"), msg, params);
}
public static void error(String msg, Object... params) {
printLog(LEVEL_MAP.get("ERROR"), msg, params);
}
public static void error(Object param) {
printLog(LEVEL_MAP.get("ERROR"), "", param);
}
private static void printLog(int levelInt, String msg, Object... params) {
try {
if (levelInt >= LEVEL_INT) {
LOG_LIST.put(generateMsg(getLevelStr(levelInt), msg, params));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static String generateMsg(String levelStr, String msg, Object... params) {
StackTraceElement stack = Thread.currentThread().getStackTrace()[4];
String s = "{} [{}][{}#{} {}] - " + msg + LINE_SEPARATOR;
Object[] args = new Object[5 + params.length];
args[0] = FORMAT.format(System.currentTimeMillis());
args[1] = levelStr;
args[2] = stack.getClassName();
args[3] = stack.getMethodName();
args[4] = stack.getLineNumber();
Throwable throwable = null;
if (params.length > 0) {
final Object lastEntry = params[params.length - 1];
if (lastEntry instanceof Throwable) {
throwable = (Throwable) lastEntry;
System.arraycopy(params, 0, args, 5, params.length - 1);
} else {
System.arraycopy(params, 0, args, 5, params.length);
}
}
return formatMsg(s, throwable, args);
}
private static String formatMsg(String msg, Throwable throwable, Object... params) {
StringBuilder sb = new StringBuilder();
int s;
int i = 0;
for (Object o : params) {
s = msg.indexOf(DELIM_STR, i);
if (s > -1) {
sb.append(msg, i, s).append(o);
i = s + 2;
}
}
sb.append(msg, i, msg.length());
if (null != throwable) {
sb.append(throwable).append(LINE_SEPARATOR);
StackTraceElement[] stack = throwable.getStackTrace();
for (StackTraceElement element : stack) {
sb.append(TAB).append(element).append(LINE_SEPARATOR);
}
}
return sb.toString();
}
private static void outPutConsole(String msg) {
try {
OUTPUT_STREAM.write(msg.getBytes(StandardCharsets.UTF_8));
OUTPUT_STREAM.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getLevelStr(int levelInt) {
switch (levelInt) {
case 1:
return "DEBUG";
case 2:
return "INFO";
case 3:
return "WARN";
case 4:
return "ERROR";
default:
throw new IllegalStateException("Level " + levelInt + " is unknown.");
}
}
}

View File

@ -0,0 +1,101 @@
/* Copyright 2018-2020 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.util;
import java.util.Random;
/**
* Random Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class RandomUtils {
private RandomUtils() {
}
private static final Random rand = new Random();
public static int nextInt(int i) {//返回随机整数最小为0最大为n-1
if(i==0)
return 0;
return rand.nextInt(i);
}
public static int nextNegOrPosInt(int n) {//返回随机整数最小为-(n-1)最大为n-1
int x = nextInt(n);
if (percent(50))
return x;
return -x;
}
public static float nextFloat() {
return rand.nextFloat();
}
public static boolean percent(float percent) {// 有百分这percent的机率为true
return rand.nextFloat() * 100 < percent;
}
public static int vary(int v, int percet) {
if (percent(percet))
return vary(v);
return v;
}
public static int vary(int v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
if (percent(10))
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
else if (percent(5))
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
else if (percent(2))
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
else if (percent(1f))
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
return v;
}
public static float vary(float v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
if (percent(10))
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
else if (percent(5))
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
else if (percent(2))
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
else if (percent(1f))
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
return v;
}
public static int varyInLimit(int v, int from, int to) {// 让返回值在from和to之间随机变异
int i = vary(v);
if (i < from)
i = from;
if (i > to)
i = to;
return i;
}
public static float varyInLimit(float v, float from, float to) {// 让返回值在from和to之间随机变异
float i = vary(v);
if (i < from)
i = from;
if (i > to)
i = to;
return i;
}
}

View File

@ -0,0 +1,105 @@
/* Copyright 2018-2020 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.util;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
/**
* StringPixelUtils used to get pixel array from a given string
*
* 根据给定的字体和字符串返回它的像素点阵lettersMap[0][0]是左下角素
*
* @author Yong Zhu
* @since 2.0.2
*/
public class StringPixelUtils {
private static final Map<String, byte[][]> lettersMap = new HashMap<>();//cache
public static byte[][] getSanserif10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 10, s);
}
public static byte[][] getSanserif12Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, s);
}
public static byte[][] getSanserifItalic10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.ITALIC, 10, s);
}
/* 在内存 BufferedImage里输出文本并获取它的像素点 */
public static byte[][] getStringPixels(String fontName, int fontStyle, int fontSize, String s) {
String key = new StringBuilder(fontName).append("_").append(fontStyle).append("_").append(fontSize).append("_")
.append(s).toString();
if (lettersMap.containsKey(key))
return lettersMap.get(key);
Font font = new Font(fontName, fontStyle, fontSize);
BufferedImage bi = new BufferedImage(fontSize * 10, fontSize * 50, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int strHeight = fm.getAscent() + fm.getDescent() - 1;
int strWidth = fm.stringWidth(s);
g2d.drawString(s, 0, fm.getAscent() - fm.getLeading() -1);
int ystart;//改进在命令行和eclipse下会有不同的空行所以要用ystart和yend来限定只获取有效象素行数
loop1: for (ystart = 0; ystart < strHeight; ystart++)
for (int x = 0; x < strWidth; x++) {
if (bi.getRGB(x, ystart) == -1)
break loop1;
}
int yend;
loop2: for (yend = strHeight; yend >= 0; yend--)
for (int x = 0; x < strWidth; x++) {
if (bi.getRGB(x, yend) == -1)
break loop2;
}
byte[][] b = new byte[strWidth][yend-ystart+1];
for (int y = ystart; y <= yend; y++)
for (int x = 0; x < strWidth; x++)
if (bi.getRGB(x, y ) == -1)
b[x][yend-y] = 1;
else
b[x][yend-y] = 0;
lettersMap.put(key, b);
return b;
}
/*- 这个是测试输出平时不需要用
public static void main(String[] args) {
System.out.println("===============");
byte[][] c = getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, "FROG");
int w = c.length;
int h = c[0].length;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][h - y - 1] > 0)
System.out.print("*");
else
System.out.print(" ");
}
System.out.println();
}
System.out.println("===============");
}
*/
}

View File

@ -0,0 +1,89 @@
/* Copyright 2018-2020 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.util;
import java.util.List;
import com.gitee.drinkjava2.frog.Env;
/**
* Tree8Util used to store a pre-order Traversal tree array to speed
*
* 这里缓存着一个前序排列的八叉树用来在细胞生成时加快速度和简化运算关于树结构可用深度树数组来表达的知识可以参见这里https://my.oschina.net/drinkjava2/blog/1818631
*
* @author Yong Zhu
* @since 1.0
*/
public class Tree8Util {
//EIGHT_TREE store a pre-order Traversal tree array
public static final int NODE_QTY = calculateNodeSize(Env.BRAIN_CUBE_SIZE);
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示第一维是深度树的行号第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录大于等于0的值表示要keep, 负数节点表示要敲除
private static byte[] KEEP = new byte[NODE_QTY]; //这里保存初值为0的数组常量可以用System.arraycopy(enable0, 0, enable, 0, NODE_QTY)快速清空enable数组
public static int keepNodeQTY = NODE_QTY; //这里临时记录需keep的节点总数好用来继续敲除初始值是全部节点
private static int index = 0;
static {
tree8Split(0, 0, 0, Env.BRAIN_CUBE_SIZE);
}
static int calculateNodeSize(int n) {//计算8叉树全展开的总节点数
if (n == 1)
return 1;
return n * n * n + calculateNodeSize(n / 2);
}
//if cube can split, then split it to 8 small cubes
private static void tree8Split(int x, int y, int z, int size) {//如立方体可分裂就继续递归分裂成8个
TREE8[index++] = new int[]{size, x, y, z}; //这里size类似于深度树中的level只不过是size从大到小level是从小到大原理一样
if (size == 1)
return;
int half = size / 2;//每个细胞可以分裂成8个size为原来1/2的小细胞
tree8Split(x, y, z, half);
tree8Split(x + half, y, z, half);
tree8Split(x, y + half, z, half);
tree8Split(x + half, y + half, z, half);
tree8Split(x, y, z + half, half);
tree8Split(x + half, y, z + half, half);
tree8Split(x, y + half, z + half, half);
tree8Split(x + half, y + half, z + half, half);
}
public static void knockNodesByGene(List<Integer> gene) {//根据基因把要敲除的8叉树节点作敲除或保留标记
System.arraycopy(KEEP, 0, keep, 0, NODE_QTY);//清空keep数组
keepNodeQTY = NODE_QTY;
for (int g : gene) {//g基因用带符号的8叉数的行号表示负数表示阴节点要敲除0或正数表示是阳节点要保留
int gLine = Math.abs(g); //基因对应节点的行号
int size = Tree8Util.TREE8[gLine][0]; //size是基因对应节点的细胞立方体边长
for (int line = gLine; line < Tree8Util.NODE_QTY; line++) {//从这个g节点开始往下找节点
if (line > gLine && Tree8Util.TREE8[line][0] >= size) //如果除了第一个节点外边长大于等于size说明节点不是g的子节点退出
break;
else {//否则就是g的子节点
if (g < 0) { //g是阴节点
Tree8Util.keep[line]--;
if (Tree8Util.keep[line] == -1) //如果正好是-1表示这个节点从保留状态转为删除状态
keepNodeQTY--;
} else if (g > 0) { //g是阳节点
Tree8Util.keep[line]++;
if (Tree8Util.keep[line] == 0) //如果正好是0表示这个节点从删除状态又转回了保留状态
keepNodeQTY++;
}
}
}
}
}
}

BIN
result16_cell_split.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB