mirror of
https://gitee.com/drinkjava2/frog.git
synced 2024-11-25 16:04:06 +08:00
Add history\010_tree_grow
This commit is contained in:
parent
837740d78d
commit
42c389f4e4
@ -177,6 +177,14 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
|
||||
位于history\009c目录下,采用了阴阳(黑白)节点算法,阴节点基因会删除节点下所有节点,是自顶向下的减材加工,阳节点基因会保留节点下所有节点,是自底向上的增材加工。利用遗传算法的大样本筛选,把自顶向下和自底向上两个进化方向结合起来,这样基本能解决误删分支后缺色不能补回这个问题。而且对于奖罚不再象以前一样要设成差距很大的值,animal.java中awardAAAA()原来要设成8000, 现在设成20也不会产生缺色现象。这个版本是研究技术细节问题,看不懂的同学们可以跳过。
|
||||
考虑到这个算法的特点,我给它起名“阴阳无极八卦阵算法“,阴阳是指它有阴阳两种节点,无极是指它的分裂阶数没有限制,八卦阵是指它采用了多个8叉树结构,每一维细胞参数都对应一个8叉树。
|
||||
|
||||
2022-07-22 树的生长演示
|
||||
位于history\010目录,演示一个树的生长。因为以前小鱼是手工指定一个三维像素点阵模板,有点作弊的嫌疑,所以这次演示是基于规则而不是模板来生成一棵树,这棵树的形状仅由以下规则决定:
|
||||
1.树根位于底部中心
|
||||
2.树的每个细胞水平方向四周不能有其它细胞
|
||||
3.树的每个细胞正下方不能有细胞,但必须在斜下方至少有一个细胞
|
||||
基于这三条规则,利用阴阳无极八卦阵分裂算法,树能够自动进化出来,但要耐心等一会儿。这个演示的意义是表示形状可以由规则来决定,不同的规则能进化出不同的形状,生物会通过改变自己的形状来适应环境规则。
|
||||
这个项目下一个任务就要基于形状由规则决定这个原理,制定模式识别奖惩规则,然后利用分裂算法,让细胞自动在空间上排布出不同细胞参数,从而进化出具有初步模式识别功能的神经网络,比方说,识别出0,1,2 ,3数字。大自然生物的模式识别不是通过人为设计算法,而就是这样无脑随机分裂细胞进化出来的。
|
||||
![result17](result17_tree_grow.gif)
|
||||
|
||||
## 运行方式 | Run
|
||||
运行core或history各个子目录下的run.bat批处理文件即可启动运行,history下有多个子目录,按版本号顺序排列,存放着这个项目演化过程中的主要历史版本供演示。
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import static com.gitee.drinkjava2.frog.brain.Cells.*;
|
||||
import static com.gitee.drinkjava2.frog.brain.Cells.GENE_NUMBERS;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
@ -22,7 +22,8 @@ import java.util.List;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.gitee.drinkjava2.frog.egg.Egg;
|
||||
import com.gitee.drinkjava2.frog.judge.RainBowFishJudge;
|
||||
import com.gitee.drinkjava2.frog.judge.TreeShapeJudge;
|
||||
import com.gitee.drinkjava2.frog.objects.Food;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
import com.gitee.drinkjava2.frog.util.Tree8Util;
|
||||
@ -55,9 +56,9 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
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 List<byte[]> photons = new ArrayList<>(); //每个光子是由一个byte数组表示,依次是x,y,z坐标、dx,dy,dz坐标余数(即小数后256分之几),mz,my,mz运动方向矢量,能量值,速度
|
||||
public List<float[]> photons = new ArrayList<>(); //每个光子是由一个float数组表示,依次是x,y,z坐标, mz,my,mz运动方向矢量,能量值,速度
|
||||
|
||||
public List<byte[]> photons2 = new ArrayList<>();// photons2是个临时空间,用来中转存放一下每遍光子运算后的结果,用双鬼拍门来替代单个链表的增删,每个list只增不减以优化速度
|
||||
public List<float[]> photons2 = new ArrayList<>();// photons2是个临时空间,用来中转存放一下每遍光子运算后的结果,用双鬼拍门来替代单个链表的增删,每个list只增不减以优化速度
|
||||
|
||||
public int x; // animal在Env中的x坐标
|
||||
public int y; // animal在Env中的y坐标
|
||||
@ -99,7 +100,9 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
for (ArrayList<Integer> gene : genes) //基因多也要适当小扣点分,防止基因无限增长
|
||||
energy -= gene.size();
|
||||
createCellsFromGene(); //根据基因分裂生成脑细胞
|
||||
RainBowFishJudge.judge(this); //外界对是否长得象彩虹鱼打分
|
||||
//RainBowFishJudge.judge(this); //外界对是否长得象彩虹鱼打分
|
||||
//MoveCellLocationJudge.judge(this);
|
||||
TreeShapeJudge.judge(this);
|
||||
}
|
||||
|
||||
private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 5000;
|
||||
@ -115,13 +118,13 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
|
||||
//如果改奖罚值,就可能出现缺色,这个要在基因变异算法(从上到下,从下到上)和环境本身奖罚合理性上下功夫
|
||||
public void awardAAAA() { changeEnergy(20);}
|
||||
public void awardAAA() { changeEnergy(10);}
|
||||
public void awardAAAA() { changeEnergy(2000);}
|
||||
public void awardAAA() { changeEnergy(200);}
|
||||
public void awardAA() { changeEnergy(5);}
|
||||
public void awardA() { changeEnergy(2);}
|
||||
|
||||
public void penaltyAAAA() { changeEnergy(-20);}
|
||||
public void penaltyAAA() { changeEnergy(-10);}
|
||||
public void penaltyAAAA() { changeEnergy(-2000);}
|
||||
public void penaltyAAA() { changeEnergy(-200);}
|
||||
public void penaltyAA() { changeEnergy(-5);}
|
||||
public void penaltyA() { changeEnergy(-2);}
|
||||
public void kill() { this.alive = false; changeEnergy(-500000); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
|
||||
@ -130,7 +133,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
public void show(Graphics g) {// 显示当前动物
|
||||
if (!alive)
|
||||
return;
|
||||
//g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
|
||||
g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
|
||||
}
|
||||
|
||||
/** Check if x,y,z out of animal's brain range */
|
||||
@ -214,9 +217,33 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO:1.视觉光子产生,如果位于眼睛处有细胞,产生光子
|
||||
//1.将外界食物信号投放到视网膜上产生光子
|
||||
seeFood();
|
||||
|
||||
//TODO:2.光子循环,每个光子行走一步, 直到光子消失,如果光子落在移动细胞上将消失,并会移动
|
||||
//2.光子主循环,每个光子行走一步, 直到光子消失,如果光子落在移动细胞上将消失,并会移动。这里有个编程技巧是用另一个list来累加新的光子,不对原list作删增,以加快速度
|
||||
// photons2.clear();
|
||||
// for (float[] p : photons) {
|
||||
// float[] p2 = movePhoton(p);
|
||||
// if (p2 != null) {
|
||||
// int xx = (int) p2[X];
|
||||
// int yy = (int) p2[Y];
|
||||
// int zz = (int) p2[Z];
|
||||
// if ((cells[xx][yy][zz] & 1) > 0)
|
||||
// y++;
|
||||
// if ((cells[xx][yy][zz] & 2) > 0)
|
||||
// y--;
|
||||
// if ((cells[xx][yy][zz] & 4) > 0)
|
||||
// x--;
|
||||
// if ((cells[xx][yy][zz] & 8) > 0)
|
||||
// x++;
|
||||
// photons2.add(p2);
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (Food.foundAndAteFood(x, y)) {
|
||||
// this.ateFood++;
|
||||
// this.awardAA();
|
||||
// }
|
||||
|
||||
//TODO:3.根据青蛙移动的矢量汇总出移动方向和步数,实际移动青蛙
|
||||
|
||||
@ -224,65 +251,50 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
|
||||
//TODO:5.如果青蛙与有毒食物位置重合,在所有痛觉细胞处产生光子,即惩罚信号的发生,痛觉细胞的位置和数量不是指定的,而是进化出来的
|
||||
|
||||
//===============================================================================================
|
||||
//现在的分水岭是以光子为循环主体,还是以细胞作为循环主体??? 前者的话,细胞是光子的中转站,后者的话,细胞之间互相用光子挖洞,可以不把光子模拟出来
|
||||
//===============================================================================================
|
||||
|
||||
//依次激活每个细胞,模拟并行激活,这个是依次x,y,z方向激活,可能会产会顺序驱逐信号的bug,以后要考虑改成随机或跳行次序激活
|
||||
// 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++) {
|
||||
// long c = cells[x][y][z];
|
||||
// float energy = energys[x][y][z];
|
||||
// float wasteEnergy = 0; //细胞会增加或消耗的总量
|
||||
// long pos = 1;
|
||||
//
|
||||
// if (energy < 0) //如细胞能量小于0,表示过分消耗了,需时间来慢慢回填
|
||||
// energy += 0.1;
|
||||
//
|
||||
// if (z == Z_TOP && (c & pos) > 0) {//感光细胞,将光信号能量存贮到细胞里, 感光细胞只能出现在最上层
|
||||
// if (Env.foundAnyThingOrOutEdge(this.x + x - XY_CENTER, this.y + y - XY_CENTER)) {
|
||||
// energys[x][y][z] = 100;
|
||||
// } else {
|
||||
// energys[x][y][z] = 0;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pos <<= 1;
|
||||
// if (z == 0 && (c & pos) > 0) {//向上运动细胞,只能出现在底层,任意位置都可
|
||||
// wasteEnergy++;
|
||||
// this.y++;
|
||||
// }
|
||||
//
|
||||
// pos <<= 1;
|
||||
// if (z == 0 && (c & pos) > 0) {//向下运动细胞,只能出现在底层,任意位置都可
|
||||
// wasteEnergy++;
|
||||
// this.y--;
|
||||
// }
|
||||
//
|
||||
// pos <<= 1;
|
||||
// if (z == 0 && (c & pos) > 0) {//向左运动细胞,只能出现在底层,任意位置都可
|
||||
// wasteEnergy++;
|
||||
// this.x--;
|
||||
// }
|
||||
//
|
||||
// pos <<= 1;
|
||||
// if (z == 0 && (c & pos) > 0) {//向右运动细胞,只能出现在底层,任意位置都可
|
||||
// wasteEnergy++;
|
||||
// this.x++;
|
||||
// }
|
||||
//
|
||||
// for (int i = 0; i < 3; i++)
|
||||
// for (int j = 0; j < 3; j++) {
|
||||
// pos <<= 1;
|
||||
// if (energy > 0 && (c & pos) > 0) {//一类固定角度的传输型参数,即能量以指定角度传送到它的相邻细胞
|
||||
// //TODO
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// energys[x][y][z] -= wasteEnergy;
|
||||
// }
|
||||
List<float[]> temp = photons;
|
||||
photons = photons2; //互换,让photons指向新的结果
|
||||
photons2 = temp; //让photons2指向原来的photons,以免创建新对象
|
||||
return alive;
|
||||
}
|
||||
|
||||
public static final int X = 0;
|
||||
public static final int Y = 1;
|
||||
public static final int Z = 2;
|
||||
public static final int MX = 3;
|
||||
public static final int MY = 4;
|
||||
public static final int MZ = 5;
|
||||
public static final int ENERGY = 6;
|
||||
public static final int SPEED = 7;
|
||||
|
||||
private void createPhoton(float x, float y, float z, float mx, float my, float mz, float energy, float speed) {//在脑空间产生光子
|
||||
photons.add(new float[]{x, y, z, mx, my, mz, energy, speed});
|
||||
}
|
||||
|
||||
private float[] movePhoton(float[] p) {//光子沿移动方向走一格,能量减少为95%
|
||||
p[ENERGY] *= .99f;
|
||||
if (p[ENERGY] < 0.01)
|
||||
return null;
|
||||
if (p[SPEED] < 0.01)
|
||||
return p;
|
||||
p[X] += p[MX];
|
||||
p[Y] += p[MY];
|
||||
p[Z] += p[MZ];
|
||||
if (Env.insideBrain(p[X], p[Y], p[Z]))
|
||||
return p;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void seeFood() {
|
||||
if (Food.smell[x][y] > 0) { //这是程序优化,如果闻到香味,说明食物在附近,才允许开启眼睛在香味范围内看图像
|
||||
for (int xx = -Food.SMELL_RANGE; xx <= Food.SMELL_RANGE; xx++)
|
||||
for (int yy = -Food.SMELL_RANGE; yy <= Food.SMELL_RANGE; yy++) {
|
||||
if (Env.insideBrain(xx + BRAIN_CENTER, yy + BRAIN_CENTER) && Env.foundAnyThingOrOutEdge(x + xx, y + yy)) { //如看到任何东西或看到出界
|
||||
for (float xxx = -0.1f; xxx <= 0.1f; xxx += 0.05)
|
||||
for (float yyy = -0.1f; yyy <= 0.1f; yyy += 0.05) // 形成一个扇面向下发送光子
|
||||
createPhoton(xx + BRAIN_CENTER, yy + BRAIN_CENTER, BRAIN_TOP, xxx, yyy, -1f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
|
@ -31,7 +31,7 @@ public class Env extends JPanel {
|
||||
/** 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_EGG_QTY = 25; // 每轮下n个青蛙蛋,可调,只有最优秀的前n个青蛙们才允许下蛋
|
||||
|
||||
public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
|
||||
|
||||
@ -42,16 +42,14 @@ public class Env extends JPanel {
|
||||
|
||||
public static boolean SAVE_EGGS_FILE = false; //从2021-11-23起,添加这个选项,允许不输出蛋文件到磁盘上
|
||||
|
||||
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出动物落在地图上随机位置,而不是在蛋所在地
|
||||
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出青蛙落在地图上随机位置,而不是在蛋所在地
|
||||
|
||||
/** Frog's brain size */ // 脑细胞位于脑范围内,是个三维结构,在animal中用一个List<Cell>来存贮表示的同时,也用一个Cell3D动态数组来表示
|
||||
/** Frog's brain size */ // 脑细胞位于脑范围内,是个三维结构,在animal中用三维数组来表示
|
||||
public static final int BRAIN_CUBE_SIZE = 16; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
|
||||
|
||||
public static final int BRAIN_CUBE_SIZE = 8; //脑立方边长大小,必须是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; //脑细胞总数不能超过这个值
|
||||
public static final int BRAIN_XSIZE = BRAIN_CUBE_SIZE; // 脑在X方向长度
|
||||
public static final int BRAIN_YSIZE = BRAIN_CUBE_SIZE; // 脑在Y方向长度
|
||||
public static final int BRAIN_ZSIZE = BRAIN_CUBE_SIZE; // 脑在Z方向长度
|
||||
|
||||
/** SHOW first animal's brain structure */
|
||||
public static boolean SHOW_FIRST_ANIMAL_BRAIN = true; // 是否显示脑图在Env区的右侧
|
||||
@ -70,21 +68,18 @@ public class Env extends JPanel {
|
||||
|
||||
/** Steps of one test round */
|
||||
public static final int STEPS_PER_ROUND = 20;// 每轮测试步数,可调
|
||||
public static int step;// 当前测试步数
|
||||
|
||||
public static final int FOOD_QTY = 1500; // 食物数量, 可调
|
||||
public static final int FOOD_QTY = 3500; // 食物数量, 可调
|
||||
|
||||
// 以下是程序内部变量,不要手工修改它们
|
||||
public static int step; // 当前测试步数
|
||||
|
||||
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
|
||||
@ -93,19 +88,19 @@ public class Env extends JPanel {
|
||||
|
||||
public static List<Egg> frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙,
|
||||
|
||||
public static EnvObject[] things = new EnvObject[]{new Food() };// 所有外界物体,如食物、字母测试工具都放在这个things里面
|
||||
|
||||
public static boolean show_split_detail=false; //是否显示脑分裂的细节过程,即从一个细胞开始分裂分裂,而不是只显示分裂的最终结果
|
||||
|
||||
public static boolean[] display_gene=new boolean[Cells.GENE_NUMBERS]; //脑最多有64个基因,这里用来控制哪些基因需要显示在脑图上
|
||||
|
||||
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;
|
||||
for (int i = 0; i < display_gene.length; i++)
|
||||
display_gene[i] = true;
|
||||
}
|
||||
|
||||
public Env() {
|
||||
@ -114,6 +109,18 @@ public class Env extends JPanel {
|
||||
this.setBounds(1, 1, ENV_WIDTH, ENV_HEIGHT);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(int x, int y) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(int x, int y, int z) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || z <= 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE || z >= BRAIN_ZSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(float x, float y, float z) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || z <= 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE || z >= BRAIN_ZSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideEnv(int x, int y) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT);
|
||||
}
|
||||
@ -130,15 +137,6 @@ public class Env extends JPanel {
|
||||
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
|
||||
@ -209,14 +207,10 @@ public class Env extends JPanel {
|
||||
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)
|
||||
return new StringBuilder("吃食率:").append(format100.format(Food.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Food.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound)
|
||||
.toString();
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -247,8 +241,6 @@ public class Env extends JPanel {
|
||||
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();
|
||||
@ -272,8 +264,7 @@ public class Env extends JPanel {
|
||||
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用是否跳帧画图的方式来控制速度
|
||||
continue;
|
||||
|
||||
if (SHOW_SPEED < 0) // 如果speed小于0,人为加入延迟
|
||||
sleep(-SHOW_SPEED);
|
||||
sleep(100);
|
||||
|
||||
// 开始画虚拟环境和青蛙和蛇
|
||||
g.setColor(Color.white);
|
||||
@ -310,12 +301,8 @@ public class Env extends JPanel {
|
||||
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;
|
||||
}
|
||||
for (EnvObject thing : things)// 去除食物、陷阱等物体
|
||||
thing.destory();
|
||||
}
|
||||
round++;
|
||||
FrogEggTool.layEggs(); //能量高的青蛙才有权下蛋
|
||||
|
@ -297,17 +297,15 @@ public class BrainPicture extends JPanel {
|
||||
|
||||
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)
|
||||
if (Env.show_split_detail)
|
||||
drawSplitDetail();
|
||||
else
|
||||
else
|
||||
drawBrainStructure();
|
||||
}
|
||||
|
||||
|
||||
public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚,即从一个细胞开始分裂成最终脑结构的每一步
|
||||
Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
|
||||
|
||||
@ -321,7 +319,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.keep[j]>=0) {
|
||||
if (Tree8Util.keep[j] >= 0) {
|
||||
int[] node = Tree8Util.TREE8[j];
|
||||
int size = node[0];
|
||||
if (size == i && Env.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
|
||||
@ -342,7 +340,7 @@ public class BrainPicture extends JPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void drawBrainStructure() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
|
||||
Animal a = Env.getShowAnimal(); // 显示第一个青蛙或蛇
|
||||
if (a == null || !a.alive)
|
||||
@ -366,6 +364,10 @@ public class BrainPicture extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
setPicColor(Color.ORANGE); //开始画出光子
|
||||
for (float[] p : a.photons)
|
||||
drawPoint(p[0]+0.5f, (int)p[1]+0.5f, (int)p[2]+0.5f, 0.2f);
|
||||
|
||||
setPicColor(Color.BLACK);
|
||||
//BrainShapeJudge.show(this);//这行显示目标形状这个模子
|
||||
|
||||
@ -384,6 +386,10 @@ public class BrainPicture extends JPanel {
|
||||
if (note != null) // 全局注释
|
||||
g.drawString(note, 30, 55);
|
||||
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setNote(String note) {
|
||||
|
@ -18,41 +18,46 @@ package com.gitee.drinkjava2.frog.brain;
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Cells {
|
||||
public static long[] masks = new long[64];
|
||||
public static long[] GENES = new long[64];
|
||||
|
||||
public static int GENE_NUMBERS = 0; //目前有多少条基因,每个脑细胞用是一个long来存储,所以最多允许64条基因,每个基因控制一个细胞的参数
|
||||
private static long mask = 1L;
|
||||
private static long gene = 1L;
|
||||
|
||||
public static final long EYE = nextMask(); //光线感觉细胞,即视网膜
|
||||
public static final long FELL_HAPPY = nextMask(); //快乐感觉细胞,通常吃食后激活
|
||||
public static final long FELL_PAIN = nextMask(); //痛苦感觉细胞,受伤害后激活
|
||||
|
||||
public static final long MOVE_UP = nextMask(); //细胞如激活,青蛙向上运动
|
||||
public static final long MOVE_DOWN = nextMask();//细胞如激活,青蛙向下运动
|
||||
public static final long MOVE_LEFT = nextMask(); //细胞如激活,青蛙向左运动
|
||||
public static final long MOVE_RIGHT = nextMask(); //细胞如激活,青蛙向右运动
|
||||
|
||||
public static final long PHOTON_DELETE = nextMask(); // 删除光子
|
||||
public static final long PHOTON_ABSORB = nextMask(); // 删除并吸收光子能量
|
||||
public static final long PHOTON_FIX = nextMask(); //固定光子,使光子不能移动
|
||||
public static final long PHOTON_ENHENCE = nextMask(); // 提高光子能量
|
||||
public static final long PHOTON_WEAKEN = nextMask(); //减弱光子能量
|
||||
public static final long PHOTON_SEND = nextMask(); //如细胞有能量,发送光子
|
||||
public static final long PHOTON_SEND_NEG = nextMask(); //如细胞有能量,发送负能量光子
|
||||
|
||||
public static final long PHOTON_LIMIT_UP = nextMask(); //光子只能向上扇面发送
|
||||
public static final long PHOTON_LIMIT_DOWN = nextMask(); //光子只能向下扇面发送
|
||||
public static final long PHOTON_LIMIT_LEFT = nextMask(); //光子只能向左扇面发送
|
||||
public static final long PHOTON_LIMIT_RIGHT = nextMask(); //光子只能向右扇面发送
|
||||
public static final long PHOTON_LIMIT_FRONT = nextMask(); //光子只能向前扇面发送
|
||||
public static final long PHOTON_LIMIT_BACK = nextMask(); //光子只能向后扇面发送
|
||||
public static final long TREE_CELL = nextMask(); //细胞如激活,青蛙向上运动
|
||||
|
||||
//public static final long EYE = nextMask(); //光线感觉细胞,即视网膜
|
||||
// public static final long FELL_HAPPY = nextMask(); //快乐感觉细胞,通常吃食后激活
|
||||
// public static final long FELL_PAIN = nextMask(); //痛苦感觉细胞,受伤害后激活
|
||||
//
|
||||
// public static final long MOVE_UP = nextMask(); //细胞如激活,青蛙向上运动
|
||||
// public static final long MOVE_DOWN = nextMask();//细胞如激活,青蛙向下运动
|
||||
// public static final long MOVE_LEFT = nextMask(); //细胞如激活,青蛙向左运动
|
||||
// public static final long MOVE_RIGHT = nextMask(); //细胞如激活,青蛙向右运动
|
||||
// public static final long MOVE_ANY = MOVE_UP | MOVE_DOWN | MOVE_LEFT | MOVE_RIGHT; //任意移动,是上面四个bit位的合并
|
||||
|
||||
//
|
||||
// public static final long PHOTON_DELETE = nextMask(); // 删除光子
|
||||
// public static final long PHOTON_ABSORB = nextMask(); // 删除并吸收光子能量
|
||||
// public static final long PHOTON_FIX = nextMask(); //固定光子,使光子不能移动
|
||||
// public static final long PHOTON_ENHENCE = nextMask(); // 提高光子能量
|
||||
// public static final long PHOTON_WEAKEN = nextMask(); //减弱光子能量
|
||||
// public static final long PHOTON_SEND = nextMask(); //如细胞有能量,发送光子
|
||||
// public static final long PHOTON_SEND_NEG = nextMask(); //如细胞有能量,发送负能量光子
|
||||
//
|
||||
// public static final long PHOTON_LIMIT_UP = nextMask(); //光子只能向上扇面发送
|
||||
// public static final long PHOTON_LIMIT_DOWN = nextMask(); //光子只能向下扇面发送
|
||||
// public static final long PHOTON_LIMIT_LEFT = nextMask(); //光子只能向左扇面发送
|
||||
// public static final long PHOTON_LIMIT_RIGHT = nextMask(); //光子只能向右扇面发送
|
||||
// public static final long PHOTON_LIMIT_FRONT = nextMask(); //光子只能向前扇面发送
|
||||
// public static final long PHOTON_LIMIT_BACK = nextMask(); //光子只能向后扇面发送
|
||||
|
||||
private static long nextMask() {// 每次将Code左移1位
|
||||
long result = mask;
|
||||
long result = gene;
|
||||
if (result < 0)
|
||||
throw new IllegalArgumentException("Mask out of maximum long integer range");
|
||||
masks[GENE_NUMBERS++] = mask;
|
||||
mask = mask << 1;
|
||||
GENES[GENE_NUMBERS++] = gene;
|
||||
gene = gene << 1; //这个gene占用long的一位,将来判断一个细胞是否包含此基因只要与它做“与”运算
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package com.gitee.drinkjava2.frog.judge;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
|
||||
/**
|
||||
* MoveCellLocationJudge determine move cells can only be on bottom layer of brain
|
||||
*
|
||||
* 运动细胞只允许出现在脑的最底层,否则扣分
|
||||
*/
|
||||
public class MoveCellLocationJudge {//NOSONAR
|
||||
|
||||
public static void judge(Animal animal) {////检查animal的脑细胞分布和参数是否符合要求并加减分
|
||||
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++) {
|
||||
long cell = animal.cells[x][y][z];
|
||||
if (z >= 1) {
|
||||
if ((cell & 1) > 0) //注意四个条件要分别判断和扣分,不能合并放在同一个if条件里,否则互相干扰,进化不出结果
|
||||
animal.penaltyAAAA();
|
||||
if ((cell & 2) > 0)
|
||||
animal.penaltyAAAA();
|
||||
if ((cell & 4) > 0)
|
||||
animal.penaltyAAAA();
|
||||
if ((cell & 8) > 0)
|
||||
animal.penaltyAAAA();
|
||||
}
|
||||
if (z == 0) {
|
||||
if ((cell & 1) > 0) //注意四个条件要分别判断和扣分,不能合并放在同一个if条件里,否则互相干扰,进化不出结果
|
||||
animal.awardAAAA();
|
||||
if ((cell & 2) > 0)
|
||||
animal.awardAAAA();
|
||||
if ((cell & 4) > 0)
|
||||
animal.awardAAAA();
|
||||
if ((cell & 8) > 0)
|
||||
animal.awardAAAA();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.gitee.drinkjava2.frog.judge;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
|
||||
/**
|
||||
* TreeShapeJudge to create a tree
|
||||
*/
|
||||
public class TreeShapeJudge {//NOSONAR
|
||||
|
||||
private static boolean hasCell(long[][][] cells, int x, int y, int z) { //检查指定位置是否有TREE_CELL
|
||||
if (Animal.outBrainRange(x, y, z))
|
||||
return false;
|
||||
return (cells[x][y][z] & Cells.TREE_CELL) > 0;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
private static boolean hasCellAround(long[][][] cells, int x, int y, int z) {//检查四周是否有TREE_CELL
|
||||
if (hasCell(cells, x + 1, y, z))return true;
|
||||
if (hasCell(cells, x - 1, y, z))return true;
|
||||
if (hasCell(cells, x + 1, y+1, z))return true;
|
||||
if (hasCell(cells, x - 1, y+1, z))return true;
|
||||
if (hasCell(cells, x + 1, y-1, z))return true;
|
||||
if (hasCell(cells, x - 1, y-1, z))return true;
|
||||
if (hasCell(cells, x, y+1, z))return true;
|
||||
if (hasCell(cells, x, y-1, z))return true;
|
||||
return false;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
public static void judge(Animal animal) {
|
||||
long[][][] cells = animal.cells;
|
||||
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 - 2; z++) {
|
||||
long cell = cells[x][y][z];
|
||||
if ((cell & Cells.TREE_CELL) > 0) {
|
||||
if ((z == 0 && x == Env.BRAIN_XSIZE / 2 && y == Env.BRAIN_YSIZE / 2) //如果在底部中心
|
||||
|| //或
|
||||
(!hasCell(cells, x, y, z - 1) // 正下方没有cell
|
||||
&& !hasCellAround(cells, x, y, z) //且周围没有cell
|
||||
&& hasCellAround(cells, x, y, z - 1) //且下方周围有cell
|
||||
))
|
||||
animal.awardAA();
|
||||
else
|
||||
animal.penaltyAA();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -19,29 +19,63 @@ 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 {
|
||||
public enum Food implements EnvObject {
|
||||
FOOD; //FOOD是一个枚举型单例,整个环境只允许有一个FOOD实例
|
||||
|
||||
public static final int SMELL_RANGE = 3;
|
||||
|
||||
public static int food_ated=0;
|
||||
|
||||
public static int[][] smell = new int[ENV_WIDTH][ENV_HEIGHT];//食物的香味, 这个香味是为了优化速度,和算法无关。有香味,说明食物在附近,程序才会启动眼睛,在视网膜产生光子,没有香味就不启动眼睛以加快速度
|
||||
|
||||
@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);
|
||||
food_ated=0;
|
||||
for (int i = 0; i < FOOD_QTY; i++) { // 随机位置生成食物
|
||||
int x = RandomUtils.nextInt(ENV_WIDTH);
|
||||
int y = RandomUtils.nextInt(ENV_HEIGHT);
|
||||
if (!Env.hasMaterial(x, y, Material.FOOD)) {
|
||||
Env.setMaterial(x, y, Material.FOOD); //在环境里标记上FOOD
|
||||
changeSmell(x, y, 1); //产生此食物的香气
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destory() {
|
||||
food_ated=0;
|
||||
for (int x = 0; x < ENV_WIDTH; x++) // 清除食物
|
||||
for (int y = 0; y < ENV_HEIGHT; y++) {
|
||||
Env.clearMaterial(x, y, Material.FOOD);
|
||||
smell[x][y] = 0; //清除所有香气
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void active() {
|
||||
//食物除了被吃,它自己没有什么活动
|
||||
}
|
||||
|
||||
private static void changeSmell(int x, int y, int value) { //在食物的附近增加或减少它的香味
|
||||
for (int xx = x - SMELL_RANGE; xx <= x + SMELL_RANGE; xx++)
|
||||
for (int yy = y - SMELL_RANGE; yy <= y + SMELL_RANGE; yy++)
|
||||
if (Env.insideEnv(xx, yy))
|
||||
smell[xx][yy] += value;
|
||||
}
|
||||
|
||||
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true
|
||||
if (Env.hasMaterial(x, y, Material.FOOD)) {
|
||||
food_ated++;
|
||||
Env.clearMaterial(x, y, Material.FOOD);//在环境里清除FOOD
|
||||
changeSmell(x, y, -1); //仅清除此食物产生的香气
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,14 +57,7 @@
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- For JSON translate -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.54</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
@ -20,8 +20,6 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.github.drinkjava2.frog.Frog;
|
||||
import com.github.drinkjava2.frog.egg.Egg;
|
||||
import com.github.drinkjava2.frog.env.Application;
|
||||
@ -52,8 +50,8 @@ public class EggTool {
|
||||
newEggs.add(env.frogs.get(i).layEgg());
|
||||
|
||||
if (JSON_FILE_FORMAT) {
|
||||
String newEggsString = JSON.toJSONString(newEggs);
|
||||
FrogFileUtils.writeFile(Application.CLASSPATH + "eggs.json", newEggsString, "utf-8");
|
||||
// String newEggsString = JSON.toJSONString(newEggs);
|
||||
// FrogFileUtils.writeFile(Application.CLASSPATH + "eggs.json", newEggsString, "utf-8");
|
||||
} else {
|
||||
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser");
|
||||
ObjectOutputStream so = new ObjectOutputStream(fo);
|
||||
@ -88,18 +86,18 @@ public class EggTool {
|
||||
public static void loadEggs(Env env) {
|
||||
boolean errorfound = false;
|
||||
if (JSON_FILE_FORMAT) {
|
||||
String eggsString = FrogFileUtils.readFile(Application.CLASSPATH + "eggs.json", "utf-8");
|
||||
if (eggsString != null) {
|
||||
List<JSONObject> jsonEggs = (List<JSONObject>) JSON.parse(eggsString);
|
||||
env.eggs = new ArrayList<Egg>();
|
||||
for (JSONObject json : jsonEggs) {
|
||||
Egg egg = json.toJavaObject(Egg.class);
|
||||
env.eggs.add(egg);
|
||||
}
|
||||
System.out.println(
|
||||
"Loaded " + env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.json" + "'.");
|
||||
} else
|
||||
errorfound = true;
|
||||
// String eggsString = FrogFileUtils.readFile(Application.CLASSPATH + "eggs.json", "utf-8");
|
||||
// if (eggsString != null) {
|
||||
// List<JSONObject> jsonEggs = (List<JSONObject>) JSON.parse(eggsString);
|
||||
// env.eggs = new ArrayList<Egg>();
|
||||
// for (JSONObject json : jsonEggs) {
|
||||
// Egg egg = json.toJavaObject(Egg.class);
|
||||
// env.eggs.add(egg);
|
||||
// }
|
||||
// System.out.println(
|
||||
// "Loaded " + env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.json" + "'.");
|
||||
// } else
|
||||
// errorfound = true;
|
||||
} else {
|
||||
try {
|
||||
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "eggs.ser");
|
||||
|
201
history/010_tree_grow/LICENSE
Normal file
201
history/010_tree_grow/LICENSE
Normal 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.
|
7
history/010_tree_grow/README.md
Normal file
7
history/010_tree_grow/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
## 2022-07-22 树的生长演示
|
||||
位于history\010目录,演示一个树的生长。因为以前小鱼是手工指定一个三维像素点阵模板,有点作弊的嫌疑,所以这次演示是基于规则而不是模板来生成一棵树,这棵树的形状仅由以下规则决定:
|
||||
1.树根位于底部中心
|
||||
2.树的每个细胞水平方向四周不能有其它细胞
|
||||
3.树的每个细胞正下方不能有细胞,但必须在斜下方至少有一个细胞
|
||||
基于这三条规则,利用阴阳无极八卦阵分裂算法,树能够自动进化出来,但要耐心等一会儿。这个演示的意义是表示形状可以由规则来决定,不同的规则能进化出不同的形状,生物会通过改变自己的形状来适应环境规则。
|
||||
这个项目下一个任务就要基于形状由规则决定这个原理,制定模式识别奖惩规则,然后利用分裂算法,让细胞自动在空间上排布出不同细胞参数,从而进化出具有初步模式识别功能的神经网络,比方说,识别出0,1,2 ,3数字。大自然生物的模式识别不是通过人为设计算法,而就是这样无脑随机分裂细胞进化出来的。
|
1
history/010_tree_grow/maven_clean.bat
Normal file
1
history/010_tree_grow/maven_clean.bat
Normal file
@ -0,0 +1 @@
|
||||
mvn clean
|
1
history/010_tree_grow/maven_eclipse_clean.bat
Normal file
1
history/010_tree_grow/maven_eclipse_clean.bat
Normal file
@ -0,0 +1 @@
|
||||
mvn eclipse:clean
|
2
history/010_tree_grow/maven_eclipse_eclipse.bat
Normal file
2
history/010_tree_grow/maven_eclipse_eclipse.bat
Normal file
@ -0,0 +1,2 @@
|
||||
call mvn eclipse:eclipse
|
||||
call pause
|
102
history/010_tree_grow/pom.xml
Normal file
102
history/010_tree_grow/pom.xml
Normal 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>frog010</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>10.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>
|
3
history/010_tree_grow/run.bat
Normal file
3
history/010_tree_grow/run.bat
Normal file
@ -0,0 +1,3 @@
|
||||
call mvn clean compile
|
||||
cd target\classes
|
||||
java -classpath ".;*" com.gitee.drinkjava2.frog.Application
|
2
history/010_tree_grow/run.sh
Normal file
2
history/010_tree_grow/run.sh
Normal file
@ -0,0 +1,2 @@
|
||||
mvn clean package
|
||||
java -jar target/frog-*.jar
|
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.gitee.drinkjava2.frog.egg.Egg;
|
||||
import com.gitee.drinkjava2.frog.judge.TreeShapeJudge;
|
||||
import com.gitee.drinkjava2.frog.objects.Food;
|
||||
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 List<float[]> photons = new ArrayList<>(); //每个光子是由一个float数组表示,依次是x,y,z坐标, mz,my,mz运动方向矢量,能量值,速度
|
||||
|
||||
public List<float[]> photons2 = new ArrayList<>();// photons2是个临时空间,用来中转存放一下每遍光子运算后的结果,用双鬼拍门来替代单个链表的增删,每个list只增不减以优化速度
|
||||
|
||||
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); //外界对是否长得象彩虹鱼打分
|
||||
//MoveCellLocationJudge.judge(this);
|
||||
TreeShapeJudge.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(2000);}
|
||||
public void awardAAA() { changeEnergy(200);}
|
||||
public void awardAA() { changeEnergy(5);}
|
||||
public void awardA() { changeEnergy(2);}
|
||||
|
||||
public void penaltyAAAA() { changeEnergy(-2000);}
|
||||
public void penaltyAAA() { changeEnergy(-200);}
|
||||
public void penaltyAA() { changeEnergy(-5);}
|
||||
public void penaltyA() { changeEnergy(-2);}
|
||||
public void kill() { this.alive = false; changeEnergy(-500000); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
|
||||
//@formatter:on
|
||||
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int BRAIN_CENTER = Env.BRAIN_CUBE_SIZE / 2;
|
||||
private static final int BRAIN_TOP = Env.BRAIN_CUBE_SIZE - 1;
|
||||
|
||||
public boolean active() {// 这个active方法在每一步循环都会被调用,是脑思考的最小帧,最复杂的这个方法写在最下面
|
||||
// 如果能量小于0、出界、与非食物的点重合则判死
|
||||
if (!alive)
|
||||
return false;
|
||||
if (energy <= 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILL_ANIMAL) {
|
||||
kill();
|
||||
return false;
|
||||
}
|
||||
|
||||
//1.将外界食物信号投放到视网膜上产生光子
|
||||
seeFood();
|
||||
|
||||
//2.光子主循环,每个光子行走一步, 直到光子消失,如果光子落在移动细胞上将消失,并会移动。这里有个编程技巧是用另一个list来累加新的光子,不对原list作删增,以加快速度
|
||||
// photons2.clear();
|
||||
// for (float[] p : photons) {
|
||||
// float[] p2 = movePhoton(p);
|
||||
// if (p2 != null) {
|
||||
// int xx = (int) p2[X];
|
||||
// int yy = (int) p2[Y];
|
||||
// int zz = (int) p2[Z];
|
||||
// if ((cells[xx][yy][zz] & 1) > 0)
|
||||
// y++;
|
||||
// if ((cells[xx][yy][zz] & 2) > 0)
|
||||
// y--;
|
||||
// if ((cells[xx][yy][zz] & 4) > 0)
|
||||
// x--;
|
||||
// if ((cells[xx][yy][zz] & 8) > 0)
|
||||
// x++;
|
||||
// photons2.add(p2);
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (Food.foundAndAteFood(x, y)) {
|
||||
// this.ateFood++;
|
||||
// this.awardAA();
|
||||
// }
|
||||
|
||||
//TODO:3.根据青蛙移动的矢量汇总出移动方向和步数,实际移动青蛙
|
||||
|
||||
//TODO:4.如果青蛙与食物位置重合,在所有奖励细胞处产生光子,即奖励信号的发生,奖励细胞的位置和数量不是指定的,而是进化出来的
|
||||
|
||||
//TODO:5.如果青蛙与有毒食物位置重合,在所有痛觉细胞处产生光子,即惩罚信号的发生,痛觉细胞的位置和数量不是指定的,而是进化出来的
|
||||
|
||||
List<float[]> temp = photons;
|
||||
photons = photons2; //互换,让photons指向新的结果
|
||||
photons2 = temp; //让photons2指向原来的photons,以免创建新对象
|
||||
return alive;
|
||||
}
|
||||
|
||||
public static final int X = 0;
|
||||
public static final int Y = 1;
|
||||
public static final int Z = 2;
|
||||
public static final int MX = 3;
|
||||
public static final int MY = 4;
|
||||
public static final int MZ = 5;
|
||||
public static final int ENERGY = 6;
|
||||
public static final int SPEED = 7;
|
||||
|
||||
private void createPhoton(float x, float y, float z, float mx, float my, float mz, float energy, float speed) {//在脑空间产生光子
|
||||
photons.add(new float[]{x, y, z, mx, my, mz, energy, speed});
|
||||
}
|
||||
|
||||
private float[] movePhoton(float[] p) {//光子沿移动方向走一格,能量减少为95%
|
||||
p[ENERGY] *= .99f;
|
||||
if (p[ENERGY] < 0.01)
|
||||
return null;
|
||||
if (p[SPEED] < 0.01)
|
||||
return p;
|
||||
p[X] += p[MX];
|
||||
p[Y] += p[MY];
|
||||
p[Z] += p[MZ];
|
||||
if (Env.insideBrain(p[X], p[Y], p[Z]))
|
||||
return p;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void seeFood() {
|
||||
if (Food.smell[x][y] > 0) { //这是程序优化,如果闻到香味,说明食物在附近,才允许开启眼睛在香味范围内看图像
|
||||
for (int xx = -Food.SMELL_RANGE; xx <= Food.SMELL_RANGE; xx++)
|
||||
for (int yy = -Food.SMELL_RANGE; yy <= Food.SMELL_RANGE; yy++) {
|
||||
if (Env.insideBrain(xx + BRAIN_CENTER, yy + BRAIN_CENTER) && Env.foundAnyThingOrOutEdge(x + xx, y + yy)) { //如看到任何东西或看到出界
|
||||
for (float xxx = -0.1f; xxx <= 0.1f; xxx += 0.05)
|
||||
for (float yyy = -0.1f; yyy <= 0.1f; yyy += 0.05) // 形成一个扇面向下发送光子
|
||||
createPhoton(xx + BRAIN_CENTER, yy + BRAIN_CENTER, BRAIN_TOP, xxx, yyy, -1f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
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*16, 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();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
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 = 25; // 每轮下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中用三维数组来表示
|
||||
public static final int BRAIN_CUBE_SIZE = 16; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
|
||||
|
||||
public static final int BRAIN_XSIZE = BRAIN_CUBE_SIZE; // 脑在X方向长度
|
||||
public static final int BRAIN_YSIZE = BRAIN_CUBE_SIZE; // 脑在Y方向长度
|
||||
public static final int BRAIN_ZSIZE = BRAIN_CUBE_SIZE; // 脑在Z方向长度
|
||||
|
||||
/** 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 = 20;// 每轮测试步数,可调
|
||||
|
||||
public static final int FOOD_QTY = 3500; // 食物数量, 可调
|
||||
|
||||
// 以下是程序内部变量,不要手工修改它们
|
||||
public static int step; // 当前测试步数
|
||||
|
||||
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 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 insideBrain(int x, int y) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(int x, int y, int z) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || z <= 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE || z >= BRAIN_ZSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(float x, float y, float z) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || z <= 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE || z >= BRAIN_ZSIZE);
|
||||
}
|
||||
|
||||
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 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(Food.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Food.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static void checkIfPause() {
|
||||
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个蛙
|
||||
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;
|
||||
|
||||
sleep(100);
|
||||
|
||||
// 开始画虚拟环境和青蛙和蛇
|
||||
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();
|
||||
}
|
||||
round++;
|
||||
FrogEggTool.layEggs(); //能量高的青蛙才有权下蛋
|
||||
} while (true);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,456 @@
|
||||
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维结构,进行有针对性的改进
|
||||
* 可以用鼠标进行平移、缩放、旋转,以及t、f、l、r,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,r,x键盘命令
|
||||
@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.ORANGE); //开始画出光子
|
||||
for (float[] p : a.photons)
|
||||
drawPoint(p[0]+0.5f, (int)p[1]+0.5f, (int)p[2]+0.5f, 0.2f);
|
||||
|
||||
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);// 利用缓存避免画面闪烁,这里输出缓存图片
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 long[] GENES = new long[64];
|
||||
|
||||
public static int GENE_NUMBERS = 0; //目前有多少条基因,每个脑细胞用是一个long来存储,所以最多允许64条基因,每个基因控制一个细胞的参数
|
||||
private static long gene = 1L;
|
||||
|
||||
public static final long TREE_CELL = nextMask(); //细胞如激活,青蛙向上运动
|
||||
|
||||
//public static final long EYE = nextMask(); //光线感觉细胞,即视网膜
|
||||
// public static final long FELL_HAPPY = nextMask(); //快乐感觉细胞,通常吃食后激活
|
||||
// public static final long FELL_PAIN = nextMask(); //痛苦感觉细胞,受伤害后激活
|
||||
//
|
||||
// public static final long MOVE_UP = nextMask(); //细胞如激活,青蛙向上运动
|
||||
// public static final long MOVE_DOWN = nextMask();//细胞如激活,青蛙向下运动
|
||||
// public static final long MOVE_LEFT = nextMask(); //细胞如激活,青蛙向左运动
|
||||
// public static final long MOVE_RIGHT = nextMask(); //细胞如激活,青蛙向右运动
|
||||
// public static final long MOVE_ANY = MOVE_UP | MOVE_DOWN | MOVE_LEFT | MOVE_RIGHT; //任意移动,是上面四个bit位的合并
|
||||
|
||||
//
|
||||
// public static final long PHOTON_DELETE = nextMask(); // 删除光子
|
||||
// public static final long PHOTON_ABSORB = nextMask(); // 删除并吸收光子能量
|
||||
// public static final long PHOTON_FIX = nextMask(); //固定光子,使光子不能移动
|
||||
// public static final long PHOTON_ENHENCE = nextMask(); // 提高光子能量
|
||||
// public static final long PHOTON_WEAKEN = nextMask(); //减弱光子能量
|
||||
// public static final long PHOTON_SEND = nextMask(); //如细胞有能量,发送光子
|
||||
// public static final long PHOTON_SEND_NEG = nextMask(); //如细胞有能量,发送负能量光子
|
||||
//
|
||||
// public static final long PHOTON_LIMIT_UP = nextMask(); //光子只能向上扇面发送
|
||||
// public static final long PHOTON_LIMIT_DOWN = nextMask(); //光子只能向下扇面发送
|
||||
// public static final long PHOTON_LIMIT_LEFT = nextMask(); //光子只能向左扇面发送
|
||||
// public static final long PHOTON_LIMIT_RIGHT = nextMask(); //光子只能向右扇面发送
|
||||
// public static final long PHOTON_LIMIT_FRONT = nextMask(); //光子只能向前扇面发送
|
||||
// public static final long PHOTON_LIMIT_BACK = nextMask(); //光子只能向后扇面发送
|
||||
|
||||
private static long nextMask() {// 每次将Code左移1位
|
||||
long result = gene;
|
||||
if (result < 0)
|
||||
throw new IllegalArgumentException("Mask out of maximum long integer range");
|
||||
GENES[GENE_NUMBERS++] = gene;
|
||||
gene = gene << 1; //这个gene占用long的一位,将来判断一个细胞是否包含此基因只要与它做“与”运算
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.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 record the 8-tree structure of brain cells
|
||||
// 基因是随机生成的8叉树数据结构,和实际生物每个细胞都要保存一份基因不同,程序中每个脑细胞并不需要保存基因的副本,这样可以极大地减少内存占用
|
||||
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>();
|
||||
|
||||
public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙
|
||||
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 模拟X、Y 染色体合并,两个蛋生成一个新的蛋
|
||||
*/
|
||||
public Egg(Egg a, Egg b) {//两个蛋的基因混合, 生成一个新蛋
|
||||
x = a.x;
|
||||
y = a.y;
|
||||
genes.addAll(a.genes); //TODO: 两个蛋的基因混合
|
||||
}
|
||||
|
||||
}
|
@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.gitee.drinkjava2.frog.judge;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
|
||||
/**
|
||||
* MoveCellLocationJudge determine move cells can only be on bottom layer of brain
|
||||
*
|
||||
* 运动细胞只允许出现在脑的最底层,否则扣分
|
||||
*/
|
||||
public class MoveCellLocationJudge {//NOSONAR
|
||||
|
||||
public static void judge(Animal animal) {////检查animal的脑细胞分布和参数是否符合要求并加减分
|
||||
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++) {
|
||||
long cell = animal.cells[x][y][z];
|
||||
if (z >= 1) {
|
||||
if ((cell & 1) > 0) //注意四个条件要分别判断和扣分,不能合并放在同一个if条件里,否则互相干扰,进化不出结果
|
||||
animal.penaltyAAAA();
|
||||
if ((cell & 2) > 0)
|
||||
animal.penaltyAAAA();
|
||||
if ((cell & 4) > 0)
|
||||
animal.penaltyAAAA();
|
||||
if ((cell & 8) > 0)
|
||||
animal.penaltyAAAA();
|
||||
}
|
||||
if (z == 0) {
|
||||
if ((cell & 1) > 0) //注意四个条件要分别判断和扣分,不能合并放在同一个if条件里,否则互相干扰,进化不出结果
|
||||
animal.awardAAAA();
|
||||
if ((cell & 2) > 0)
|
||||
animal.awardAAAA();
|
||||
if ((cell & 4) > 0)
|
||||
animal.awardAAAA();
|
||||
if ((cell & 8) > 0)
|
||||
animal.awardAAAA();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
/**
|
||||
* RainBowFishJudge to judge if is a rainbow fish, 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) {//检查颜色与小鱼图像重合,且呈斑马纹色彩分布,是就加分,否则扣分
|
||||
float colorWidth = 1.0f * 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的脑细胞分布和参数是否符合要求并加减分
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.gitee.drinkjava2.frog.judge;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
|
||||
/**
|
||||
* TreeShapeJudge to create a tree
|
||||
*/
|
||||
public class TreeShapeJudge {//NOSONAR
|
||||
|
||||
private static boolean hasCell(long[][][] cells, int x, int y, int z) { //检查指定位置是否有TREE_CELL
|
||||
if (Animal.outBrainRange(x, y, z))
|
||||
return false;
|
||||
return (cells[x][y][z] & Cells.TREE_CELL) > 0;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
private static boolean hasCellAround(long[][][] cells, int x, int y, int z) {//检查四周是否有TREE_CELL
|
||||
if (hasCell(cells, x + 1, y, z))return true;
|
||||
if (hasCell(cells, x - 1, y, z))return true;
|
||||
if (hasCell(cells, x + 1, y+1, z))return true;
|
||||
if (hasCell(cells, x - 1, y+1, z))return true;
|
||||
if (hasCell(cells, x + 1, y-1, z))return true;
|
||||
if (hasCell(cells, x - 1, y-1, z))return true;
|
||||
if (hasCell(cells, x, y+1, z))return true;
|
||||
if (hasCell(cells, x, y-1, z))return true;
|
||||
return false;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
public static void judge(Animal animal) {
|
||||
long[][][] cells = animal.cells;
|
||||
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 - 2; z++) {
|
||||
long cell = cells[x][y][z];
|
||||
if ((cell & Cells.TREE_CELL) > 0) {
|
||||
if ((z == 0 && x == Env.BRAIN_XSIZE / 2 && y == Env.BRAIN_YSIZE / 2) //如果在底部中心
|
||||
|| //或
|
||||
(!hasCell(cells, x, y, z - 1) // 正下方没有cell
|
||||
&& !hasCellAround(cells, x, y, z) //且周围没有cell
|
||||
&& hasCellAround(cells, x, y, z - 1) //且下方周围有cell
|
||||
))
|
||||
animal.awardAA();
|
||||
else
|
||||
animal.penaltyAA();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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(); // 每个步长都会调用一次这个方法
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/* 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
|
||||
* 食物
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public enum Food implements EnvObject {
|
||||
FOOD; //FOOD是一个枚举型单例,整个环境只允许有一个FOOD实例
|
||||
|
||||
public static final int SMELL_RANGE = 3;
|
||||
|
||||
public static int food_ated=0;
|
||||
|
||||
public static int[][] smell = new int[ENV_WIDTH][ENV_HEIGHT];//食物的香味, 这个香味是为了优化速度,和算法无关。有香味,说明食物在附近,程序才会启动眼睛,在视网膜产生光子,没有香味就不启动眼睛以加快速度
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
food_ated=0;
|
||||
for (int i = 0; i < FOOD_QTY; i++) { // 随机位置生成食物
|
||||
int x = RandomUtils.nextInt(ENV_WIDTH);
|
||||
int y = RandomUtils.nextInt(ENV_HEIGHT);
|
||||
if (!Env.hasMaterial(x, y, Material.FOOD)) {
|
||||
Env.setMaterial(x, y, Material.FOOD); //在环境里标记上FOOD
|
||||
changeSmell(x, y, 1); //产生此食物的香气
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destory() {
|
||||
food_ated=0;
|
||||
for (int x = 0; x < ENV_WIDTH; x++) // 清除食物
|
||||
for (int y = 0; y < ENV_HEIGHT; y++) {
|
||||
Env.clearMaterial(x, y, Material.FOOD);
|
||||
smell[x][y] = 0; //清除所有香气
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void active() {
|
||||
//食物除了被吃,它自己没有什么活动
|
||||
}
|
||||
|
||||
private static void changeSmell(int x, int y, int value) { //在食物的附近增加或减少它的香味
|
||||
for (int xx = x - SMELL_RANGE; xx <= x + SMELL_RANGE; xx++)
|
||||
for (int yy = y - SMELL_RANGE; yy <= y + SMELL_RANGE; yy++)
|
||||
if (Env.insideEnv(xx, yy))
|
||||
smell[xx][yy] += value;
|
||||
}
|
||||
|
||||
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true
|
||||
if (Env.hasMaterial(x, y, Material.FOOD)) {
|
||||
food_ated++;
|
||||
Env.clearMaterial(x, y, Material.FOOD);//在环境里清除FOOD
|
||||
changeSmell(x, y, -1); //仅清除此食物产生的香气
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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("===============");
|
||||
}
|
||||
*/
|
||||
}
|
@ -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(KEEP, 0, keep, 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
result17_tree_grow.gif
Normal file
BIN
result17_tree_grow.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
result3.gif
BIN
result3.gif
Binary file not shown.
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 84 KiB |
@ -1,5 +1,6 @@
|
||||
## 初学者入门介绍
|
||||
注意这个介绍只是针对码云"人工生命"(以后简称Frog)这个项目本身,并不是神经网络知识入门介绍。
|
||||
注意这个介绍只是针对码云"人工生命"(以后简称Frog)这个项目本身,并不是神经网络知识入门介绍。
|
||||
下面的介绍仅针对早期版本,因时间关系没有继续更新,后来陆续更新了好多版后,按时间顺序放在history目录下。大家可以参数Readme中的介绍一个目录一个目录地看,如果想研究源码的,建议看懂003b_simple目录。但是总的来说,源码并不重要,关键是思路。
|
||||
|
||||
### 项目的运行环境
|
||||
Frog项目需要安装JDK8、Maven、GIT客户端,如果已经在本机上安装过的请跳过这一节:
|
||||
|
12
捐款记录.md
12
捐款记录.md
@ -1,4 +1,4 @@
|
||||
这个项目的捐款将用于项目本身,如发布开发任务等。设这个捐款记录的目的是为了让收支透明化,如需捐赠请西联汇款"加拿大朱勇"收。本记录按时间顺序记录捐款人和当前总额,不记具体数额,这样即体现了不鼓励金额攀比、自愿随意的原则,也能通过历史记录查询出每笔的具体数额。在此衷心地感谢每一位捐款、点赞、及关注这个项目的同学!
|
||||
这个项目的捐款将用于项目本身,如发布开发任务等。设这个捐款记录的目的是为了让收支透明化,如用西联汇款请写"Canada"、"Zhu, Yong"收。本记录按时间顺序记录捐款人和当前总额,不记具体数额,这样即体现了自愿随意的原则,也能通过历史记录查询出每笔的具体数额。在此衷心地感谢每一位捐款、点赞、及关注这个项目的同学!
|
||||
|
||||
捐款(按时间顺序):
|
||||
wangtao
|
||||
@ -30,11 +30,17 @@ cctbby
|
||||
seanhuqi
|
||||
万码牛叔叔
|
||||
波斯家
|
||||
目前收入总额:663.77元
|
||||
QuietPear
|
||||
忨岩
|
||||
陈抟老祖
|
||||
TommyLemon
|
||||
老v表
|
||||
|
||||
目前收入总额:884.77元
|
||||
|
||||
支出(按时间顺序):
|
||||
细胞分裂演示(pama_1234):500元
|
||||
|
||||
目前支出总额:500元
|
||||
|
||||
目前余额:163.77元
|
||||
目前余额:384.77元
|
Loading…
Reference in New Issue
Block a user