Add history\010_tree_grow

This commit is contained in:
yong 2022-07-22 02:37:51 -06:00
parent 837740d78d
commit 42c389f4e4
46 changed files with 3382 additions and 193 deletions

View File

@ -177,6 +177,14 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
位于history\009c目录下采用了阴阳(黑白)节点算法阴节点基因会删除节点下所有节点是自顶向下的减材加工阳节点基因会保留节点下所有节点是自底向上的增材加工。利用遗传算法的大样本筛选把自顶向下和自底向上两个进化方向结合起来这样基本能解决误删分支后缺色不能补回这个问题。而且对于奖罚不再象以前一样要设成差距很大的值animal.java中awardAAAA()原来要设成8000, 现在设成20也不会产生缺色现象。这个版本是研究技术细节问题看不懂的同学们可以跳过。
考虑到这个算法的特点我给它起名“阴阳无极八卦阵算法“阴阳是指它有阴阳两种节点无极是指它的分裂阶数没有限制八卦阵是指它采用了多个8叉树结构每一维细胞参数都对应一个8叉树。
2022-07-22 树的生长演示
位于history\010目录演示一个树的生长。因为以前小鱼是手工指定一个三维像素点阵模板有点作弊的嫌疑所以这次演示是基于规则而不是模板来生成一棵树这棵树的形状仅由以下规则决定
1.树根位于底部中心
2.树的每个细胞水平方向四周不能有其它细胞
3.树的每个细胞正下方不能有细胞,但必须在斜下方至少有一个细胞
基于这三条规则,利用阴阳无极八卦阵分裂算法,树能够自动进化出来,但要耐心等一会儿。这个演示的意义是表示形状可以由规则来决定,不同的规则能进化出不同的形状,生物会通过改变自己的形状来适应环境规则。
这个项目下一个任务就要基于形状由规则决定这个原理制定模式识别奖惩规则然后利用分裂算法让细胞自动在空间上排布出不同细胞参数从而进化出具有初步模式识别功能的神经网络比方说识别出012 ,3数字。大自然生物的模式识别不是通过人为设计算法而就是这样无脑随机分裂细胞进化出来的。
![result17](result17_tree_grow.gif)
## 运行方式 | Run
运行core或history各个子目录下的run.bat批处理文件即可启动运行history下有多个子目录按版本号顺序排列存放着这个项目演化过程中的主要历史版本供演示。

View File

@ -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;
}
//TODO1.视觉光子产生如果位于眼睛处有细胞产生光子
//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
//TODO5.如果青蛙与有毒食物位置重合在所有痛觉细胞处产生光子,即惩罚信号的发生痛觉细胞的位置和数量不是指定的而是进化出来的
//===============================================================================================
//现在的分水岭是以光子为循环主体还是以细胞作为循环主体??? 前者的话细胞是光子的中转站后者的话细胞之间互相用光子挖洞可以不把光子模拟出来
//===============================================================================================
//依次激活每个细胞模拟并行激活这个是依次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);
}
}
}
}
}

View File

@ -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;

View 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(); //能量高的青蛙才有权下蛋

View File

@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

@ -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");

View File

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

View File

@ -0,0 +1,7 @@
## 2022-07-22 树的生长演示
位于history\010目录演示一个树的生长。因为以前小鱼是手工指定一个三维像素点阵模板有点作弊的嫌疑所以这次演示是基于规则而不是模板来生成一棵树这棵树的形状仅由以下规则决定
1.树根位于底部中心
2.树的每个细胞水平方向四周不能有其它细胞
3.树的每个细胞正下方不能有细胞,但必须在斜下方至少有一个细胞
基于这三条规则,利用阴阳无极八卦阵分裂算法,树能够自动进化出来,但要耐心等一会儿。这个演示的意义是表示形状可以由规则来决定,不同的规则能进化出不同的形状,生物会通过改变自己的形状来适应环境规则。
这个项目下一个任务就要基于形状由规则决定这个原理制定模式识别奖惩规则然后利用分裂算法让细胞自动在空间上排布出不同细胞参数从而进化出具有初步模式识别功能的神经网络比方说识别出012 ,3数字。大自然生物的模式识别不是通过人为设计算法而就是这样无脑随机分裂细胞进化出来的。

View File

@ -0,0 +1 @@
mvn clean

View File

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

View File

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

View File

@ -0,0 +1,102 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.drinkjava2</groupId>
<artifactId>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>

View File

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

View File

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

View File

@ -0,0 +1,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.根据青蛙移动的矢量汇总出移动方向和步数实际移动青蛙
//TODO4.如果青蛙与食物位置重合在所有奖励细胞处产生光子,即奖励信号的发生奖励细胞的位置和数量不是指定的而是进化出来的
//TODO5.如果青蛙与有毒食物位置重合在所有痛觉细胞处产生光子,即惩罚信号的发生痛觉细胞的位置和数量不是指定的而是进化出来的
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);
}
}
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,29 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.objects.Material;
/**
* Frog is child class of Animal, Frog's name is Sam
* Frog是Animal的一个子类
*
* @since 1.0
*/
public class Frog extends Animal {
public Frog(Egg egg) {
super(egg);
animalMaterial = Material.FROG_TAG;
animalImage = Animal.FROG_IMAGE;
}
}

View File

@ -0,0 +1,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维结构进行有针对性的改进
* 可以用鼠标进行平移缩放旋转以及tflr,x五个键来选择顶视前视左视右视斜视这5个方向的视图以及空格暂停方向键调整切面
* 鼠标的动作定义在MouseAction类中
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class BrainPicture extends JPanel {
private static final long serialVersionUID = 1L;
private static final float D90 = (float) (Math.PI / 2);
Color picColor = RED;
int brainDispWidth; // screen display piexls width
float scale; // brain scale
int xOffset = 0; // brain display x offset compare to screen
int yOffset = 0; // brain display y offset compare to screen
float xAngle = D90 * .8f; // brain rotate on x axis
float yAngle = D90 / 4; // brain rotate on y axis
float zAngle = 0;// brain rotate on z axis
int xMask = -1;// x Mask
int yMask = -1;// y Mask
BufferedImage buffImg;
Graphics g;
String note;
public KeyAdapter keyAdapter;
public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) {
super();
this.setLayout(null);// 空布局
this.brainDispWidth = brainDispWidth;
scale = 0.5f * brainDispWidth / brainWidth;
this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1);
buffImg = new BufferedImage(Env.FROG_BRAIN_DISP_WIDTH, Env.FROG_BRAIN_DISP_WIDTH, BufferedImage.TYPE_INT_RGB);
g = buffImg.getGraphics();
MouseAction act = new MouseAction(this);
this.addMouseListener(act); // 添加鼠标动作监听
this.addMouseWheelListener(act);// 添加鼠标滚轮动作监听
this.addMouseMotionListener(act);// 添加鼠标移动动作监听
keyAdapter = new KeyAdapter() {// 处理t,f,l,rx键盘命令
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()){
case KeyEvent.VK_UP:// Y切面向上
yMask++;
if (yMask > Env.BRAIN_YSIZE)
yMask = Env.BRAIN_YSIZE;
break;
case KeyEvent.VK_DOWN:// Y切面向下
yMask--;
if (yMask < 0)
yMask = 0;
break;
case KeyEvent.VK_LEFT:// x切面向左
xMask--;
if (xMask < 0)
xMask = 0;
break;
case KeyEvent.VK_RIGHT:// x切面向右
xMask++;
if (xMask > Env.BRAIN_XSIZE)
xMask = Env.BRAIN_XSIZE;
break;
case ' ':// 暂停及继续
Application.pauseAction.actionPerformed(null);
break;
case 'T':// 顶视
xAngle = 0;
yAngle = 0;
zAngle = 0;
break;
case 'F':// 前视
xAngle = D90;
yAngle = 0;
zAngle = 0;
break;
case 'L':// 左视
xAngle = D90;
yAngle = D90;
zAngle = 0;
break;
case 'R':// 右视
xAngle = D90;
yAngle = -D90;
zAngle = 0;
break;
case 'X':// 斜视
xAngle = D90 * .8f;
yAngle = D90 / 4;
zAngle = 0;
break;
default:
}
}
};
addKeyListener(keyAdapter);
this.setFocusable(true);
}
public void drawCuboid(Cuboid c) {// 在脑图上画一个长立方体框架视角是TopView
drawCuboid(c.x, c.y, c.z, c.xe, c.ye, c.ze);
}
public void drawCuboid(float x, float y, float z, float xe, float ye, float ze) {// 在脑图上画一个长立方体框架视角是TopView
drawLine(x, y, z, x + xe, y, z);// 画立方体的下面边
drawLine(x + xe, y, z, x + xe, y + ye, z);
drawLine(x + xe, y + ye, z, x, y + ye, z);
drawLine(x, y + ye, z, x, y, z);
drawLine(x, y, z, x, y, z + ze);// 画立方体的中间边
drawLine(x + xe, y, z, x + xe, y, z + ze);
drawLine(x + xe, y + ye, z, x + xe, y + ye, z + ze);
drawLine(x, y + ye, z, x, y + ye, z + ze);
drawLine(x, y, z + ze, x + xe, y, z + ze);// 画立方体的上面边
drawLine(x + xe, y, z + ze, x + xe, y + ye, z + ze);
drawLine(x + xe, y + ye, z + ze, x, y + ye, z + ze);
drawLine(x, y + ye, z + ze, x, y, z + ze);
}
/*-
画线固定以top视角的角度所以只需要从x1,y1画一条到x2,y2的直线
x 轴旋转 θ
x, y.cosθ-zsinθ, y.sinθ+z.cosθ
y 轴旋转 θ
z.sinθ+x.cosθ, y, z.cosθ-x.sinθ
z 轴旋转 θ
x.cosθ-y.sinθ, x.sinθ+y.consθ, z
-*/
public void drawLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
double x2 = px2 - Env.BRAIN_XSIZE / 2;
double y2 = -py2 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z2 = pz2 - Env.BRAIN_ZSIZE / 2;
x1 = x1 * scale;
y1 = y1 * scale;
z1 = z1 * scale;
x2 = x2 * scale;
y2 = y2 * scale;
z2 = z2 * scale;
double x, y, z;
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
z = y1 * sin(xAngle) + z1 * cos(xAngle);
y1 = y;
z1 = z;
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
x1 = x;
// z1 = z;
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
y = x1 * sin(zAngle) + y1 * cos(zAngle);
x1 = x;
y1 = y;
y = y2 * cos(xAngle) - z2 * sin(xAngle);// 绕x轴转
z = y2 * sin(xAngle) + z2 * cos(xAngle);
y2 = y;
z2 = z;
x = z2 * sin(yAngle) + x2 * cos(yAngle);// 绕y轴转
// z = z2 * cos(yAngle) - x2 * sin(yAngle);
x2 = x;
// z2 = z;
x = x2 * cos(zAngle) - y2 * sin(zAngle);// 绕z轴转
y = x2 * sin(zAngle) + y2 * cos(zAngle);
x2 = x;
y2 = y;
g.setColor(picColor);
g.drawLine((int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset, (int) round(x2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset,
(int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
}
/** 画点固定以top视角的角度所以只需要在x1,y1位置画一个点 */
public void drawPoint(float px1, float py1, float pz1, float r) {
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
x1 = x1 * scale;
y1 = y1 * scale;
z1 = z1 * scale;
double x, y, z;
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
z = y1 * sin(xAngle) + z1 * cos(xAngle);
y1 = y;
z1 = z;
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
x1 = x;
// z1 = z;
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
y = x1 * sin(zAngle) + y1 * cos(zAngle);
x1 = x;
y1 = y;
g.setColor(picColor);
g.fillOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
round(r * scale));
}
/** 画一个圆 */
public void drawCircle(float px1, float py1, float pz1, float r) {//这个方法实际和上面的一样的只是改成了drawOval
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
x1 = x1 * scale;
y1 = y1 * scale;
z1 = z1 * scale;
double x, y, z;
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
z = y1 * sin(xAngle) + z1 * cos(xAngle);
y1 = y;
z1 = z;
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
x1 = x;
// z1 = z;
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
y = x1 * sin(zAngle) + y1 * cos(zAngle);
x1 = x;
y1 = y;
g.setColor(picColor);
g.drawOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
round(r * scale));
}
public void drawText(float px1, float py1, float pz1, String text, float textSize) {
double x1 = px1 - Env.BRAIN_XSIZE / 2;
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的显示时要正过来
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
x1 = x1 * scale;
y1 = y1 * scale;
z1 = z1 * scale;
double x, y, z;
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
z = y1 * sin(xAngle) + z1 * cos(xAngle);
y1 = y;
z1 = z;
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
x1 = x;
// z1 = z;
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
y = x1 * sin(zAngle) + y1 * cos(zAngle);
x1 = x;
y1 = y;
g.setColor(picColor);
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) round(textSize * scale)));
g.drawString(text, (int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
}
private static Cuboid brain = new Cuboid(0, 0, 0, Env.BRAIN_XSIZE, Env.BRAIN_YSIZE, Env.BRAIN_ZSIZE);
public void drawBrainPicture() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
if (!Env.SHOW_FIRST_ANIMAL_BRAIN)
return;
if (Env.show_split_detail)
drawSplitDetail();
else
drawBrainStructure();
}
public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚即从一个细胞开始分裂成最终脑结构的每一步
Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
for (int i = Env.BRAIN_CUBE_SIZE; i >= 1; i /= 2) {
g.setColor(WHITE);// 先清空旧图, g是buffImg绘在内存中
g.fillRect(0, 0, brainDispWidth, brainDispWidth);
g.setColor(BLACK); // 画边框
g.drawRect(0, 0, brainDispWidth, brainDispWidth);
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
ArrayList<Integer> gene = a.genes.get(geneIndex);
Tree8Util.knockNodesByGene(gene);
for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
if (Tree8Util.keep[j] >= 0) {
int[] node = Tree8Util.TREE8[j];
int size = node[0];
if (size == i && Env.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
setPicColor(ColorUtils.colorByCode(geneIndex));
drawPoint(node[1] + size / 2, node[2] + size / 2, node[3] + size / 2, size * (0.5f - geneIndex * 0.05f));
}
}
}
}
g.setColor(BLACK);
drawCuboid(brain);// 把脑的框架画出来
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁这里输出缓存图片
if (!Env.show_split_detail)
return;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
public void drawBrainStructure() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
Animal a = Env.getShowAnimal(); // 显示第一个青蛙或蛇
if (a == null || !a.alive)
return;
g.setColor(WHITE);// 先清空旧图, g是buffImg绘在内存中
g.fillRect(0, 0, brainDispWidth, brainDispWidth);
g.setColor(BLACK); // 画边框
g.drawRect(0, 0, brainDispWidth, brainDispWidth);
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--) {
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
if (x >= xMask && y >= yMask && a.cells[x][y][z] != 0)
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
if ((a.cells[x][y][z] & (1 << geneIndex)) != 0 && Env.display_gene[geneIndex]) {
setPicColor(ColorUtils.colorByCode(geneIndex)); //开始画出对应的细胞基因参数用不同颜色直径圆表示
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, geneIndex == 0 ? 0.8f : 0.5f - geneIndex * 0.05f);
}
}
}
}
}
setPicColor(Color.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;
}
}

View File

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

View File

@ -0,0 +1,55 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.brain;
/**
* Cuboid represents a rectangular prism 3d zone in brain
*
* Cuboid是一个长方体通常用来表示脑内器官的形状
*
* @author Yong Zhu
* @since 2.0.2
*/
@SuppressWarnings("all")
public class Cuboid {
private static final long serialVersionUID = 1L;
public float x;// x,y,z是长方体的左下角坐标
public float y;
public float z;
public float xe;// xe,ye,ze分别是长方体三边长
public float ye;
public float ze;
public Cuboid() {
// 空构造器不能省
}
public Cuboid(float x, float y, float z, float xe, float ye, float ze) {// 用x,y,z,r来构造
this.x = x;
this.y = y;
this.z = z;
this.xe = xe;
this.ye = ye;
this.ze = ze;
}
public Cuboid(Cuboid c) {// 用另一个Cuboid来构造
this.x = c.x;
this.y = c.y;
this.z = c.z;
this.xe = c.xe;
this.ye = c.ye;
this.ze = c.ze;
}
}

View File

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

View File

@ -0,0 +1,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 模拟XY 染色体合并两个蛋生成一个新的蛋
*/
public Egg(Egg a, Egg b) {//两个蛋的基因混合, 生成一个新蛋
x = a.x;
y = a.y;
genes.addAll(a.genes); //TODO: 两个蛋的基因混合
}
}

View File

@ -0,0 +1,112 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.egg;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Application;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.Frog;
import com.gitee.drinkjava2.frog.util.LocalFileUtils;
import com.gitee.drinkjava2.frog.util.Logger;
/**
* FrogEggTool save/load frog eggs to file
*
* @author Yong Zhu
* @since 1.0
*/
@SuppressWarnings("all")
public class FrogEggTool {
/**
* Frogs which have higher energy lay eggs
*
* 利用Java串行机制存盘 能量多(也就是吃的更多)的Frog下蛋并存盘, 以进行下一轮测试能量少的Frog被淘汰没有下蛋的资格
* 用能量的多少来简化生存竟争模拟每次下蛋数量固定为EGG_QTY个
*/
public static void layEggs() {
sortFrogsOrderByEnergyDesc();
Frog first = Env.frogs.get(0);
Frog last = Env.frogs.get(Env.frogs.size() - 1);
try {
Env.frog_eggs.clear();
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
Logger.info("Fist frog energy={}, Last frog energy={}", first.energy, last.energy);
if (Env.SAVE_EGGS_FILE) {
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(Env.frog_eggs);
so.close();
Logger.info(". Saved {} eggs to file '{}frog_eggs.ser'", Env.frog_eggs.size(), Application.CLASSPATH);
}
} catch (IOException e) {
Logger.error(e);
}
}
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
Collections.sort(Env.frogs, new Comparator<Animal>() {
public int compare(Animal a, Animal b) {
if (a.energy > b.energy)
return -1;
else if (a.energy == b.energy)
return 0;
else
return 1;
}
});
}
public static void deleteEggs() {
Logger.info("Delete exist egg file: '{}frog_eggs.ser'", Application.CLASSPATH);
LocalFileUtils.deleteFile(Application.CLASSPATH + "frog_eggs.ser");
}
/**
* 从磁盘读入一批frog Egg
*/
@SuppressWarnings("unchecked")
public static void loadFrogEggs() {
boolean errorfound = false;
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
Env.frog_eggs = (List<Egg>) eggsInputStream.readObject();
Logger.info("Loaded " + Env.frog_eggs.size() + " eggs from file '" + Application.CLASSPATH
+ "frog_eggs.ser" + "'.\n");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
}
if (errorfound) {
Env.frog_eggs.clear();
for (int j = 0; j < Env.FROG_EGG_QTY; j++) {
Egg egg = new Egg();
Env.frog_eggs.add(egg);
}
Logger.info("Fail to load frog egg file '" + Application.CLASSPATH + "frog_eggs.ser" + "', created "
+ Env.frog_eggs.size() + " eggs to do test.");
}
}
}

View File

@ -0,0 +1,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();
}
}
}
}

View File

@ -0,0 +1,84 @@
package com.gitee.drinkjava2.frog.judge;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.BrainPicture;
import com.gitee.drinkjava2.frog.brain.Cells;
import com.gitee.drinkjava2.frog.util.StringPixelUtils;
/**
* 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);
}
}

View File

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

View File

@ -0,0 +1,26 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.objects;
/**
* EnvObject means some virtual object in Env
*
* @author Yong Zhu
* @since 1.0
*/
public interface EnvObject {
public void build(); // 在Env中创建本身物体指改变Env.bricks数组元素为本身物体的组成材料只在每屏测试前调用一次
public void destory();// 从Env中清除本身物体只在每屏测试完成后调用一次
public void active(); // 每个步长都会调用一次这个方法
}

View File

@ -0,0 +1,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;
}
}

View File

@ -0,0 +1,50 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.objects;
import java.awt.Color;
/**
* Material store material types
*
* 虚拟环境中每个点由一个int代表多个材料可以同时出现在同一个点每种材料用int中的一个bit位来表示
* 小于等于16384的位数用来标记青蛙序号可利用Env.frogs.get(no-1)获取青蛙对象其它各种材料用整数中其它位来表示
*
* @author Yong Zhu
* @since 1.0
*/
public class Material {// NOSONAR
public static final int FROG_TAG = 0b11111111111111; // 16383 小于等于16384的位数用来标记青蛙序号可利用Env.frogs.get(no-1)快速定位青蛙
private static int material = FROG_TAG + 1; // 大于16384用来作为各种材料的标记
public static final int FOOD = nextMaterial();
public static final int SNAKE = nextMaterial(); // 蛇的图形
public static final int KILL_ANIMAL = nextMaterial(); // if>=KILLFROG will kill animal
public static final int BRICK = nextMaterial();// brick will kill frog
public static final int TRAP = nextMaterial(); // trap will kill frog
private static int nextMaterial() {// 每次将material左移1位
material = material << 1;
if (material < 0)
throw new IllegalArgumentException("Material out of maximum range");
return material;
}
public static Color color(int material) {
if ((material & TRAP) > 0)
return Color.LIGHT_GRAY;
else
return Color.BLACK;
}
}

View File

@ -0,0 +1,62 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
import java.awt.Color;
/**
* Color Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class ColorUtils {
private static final Color[] rainbow = new Color[]{Color.GRAY, Color.GREEN, Color.RED, Color.BLUE, Color.YELLOW, Color.ORANGE, Color.MAGENTA, Color.CYAN};
private static int nextColor = 0;
private ColorUtils() {// default private constr
}
public static int nextColorCode() {
return nextColor++;
}
public static Color nextRainbowColor() {// 返回下一个彩虹色
if (nextColor == rainbow.length)
nextColor = 0;
return rainbow[nextColor++];
}
public static Color colorByCode(int i) {// 数值取模后返回一个固定彩虹色
return rainbow[i % rainbow.length];
}
public static Color rainbowColor(float i) { // 根据数值大小范围在8种彩虹色中取值
if (i <= 20)
return Color.GRAY;
if (i <= 30)
return Color.BLACK;
if (i <= 50)
return Color.RED;
return Color.MAGENTA;
}
public static Color grayColor(float f) { // 根据数值大小范围0~1000返回一个灰度色越大越黑
if (f > 1000)
f = 1000;
int i1 = 255 - (int) Math.round(f * .255);
int i2 = 200 - (int) Math.round(f * .200);
int i3 = 150 - (int) Math.round(f * .150);
return new Color(i1, i2, i3);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
/**
* Cube has x,y,z value
*
* @author Yong Zhu
* @since 2021-11-07
*/
public class Cube {
public int x;//x,y,z是cube的左下前点坐标
public int y;
public int z;
public int size;//size是cube的边长
public Cube(int x, int y, int z, int size) {
this.x = x;
this.y = y;
this.z = z;
this.size = size;
}
}

View File

@ -0,0 +1,141 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Local File Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class LocalFileUtils {
private LocalFileUtils() {
// default constructor
}
public static boolean deleteFile(String fileFullPath) {
File file = new File(fileFullPath);
return file.delete(); // NOSONAR
}
public static void writeFile(String fileFullPath, byte[] byteArry) {
File file = new File(fileFullPath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(byteArry);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void writeFile(String fileFullPath, String text, String encoding) {
File file = new File(fileFullPath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
byte[] bytes;
bytes = text.getBytes(encoding);
fos.write(bytes);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String readFile(String fileFullPath, String encoding) {
InputStream inputStream;
try {
inputStream = new FileInputStream(new File(fileFullPath));
} catch (FileNotFoundException e1) {
return null;
}
try {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1)
result.write(buffer, 0, length);
String string = result.toString(encoding);
return string;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
public static void appendFile(String fileName, String content) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(fileName, true);
fos.write(content.getBytes());
fos.write("\r\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
try {
fos.flush();
} catch (Exception e) {
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright 2021 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* Usually a logger tool is used like below:
* Logger log = LoggerFactory.getLogger(Xxxx.class);
* log.info("some msg");
*
* But to simplify, in this project directly use static method:
* Logger.info("some msg");
*
* @Description: 简版控制台日志打印从码云上合并来 https://gitee.com/drinkjava2/frog/pulls/4
* @author 栾成翔
* @Date: 2021/12/07
*/
@SuppressWarnings("all")
public class Logger {
private static final String LEV_EL = "debug";
private static final int LEVEL_INT;
private static final BlockingQueue<String> LOG_LIST = new ArrayBlockingQueue<>(256);
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
private static final OutputStream OUTPUT_STREAM = System.out;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String DELIM_STR = "{}";
private static final String TAB = "\tat";
private static final Map<String, Integer> LEVEL_MAP = new HashMap<>();
static {
LEVEL_MAP.put("DEBUG", 1);
LEVEL_MAP.put("INFO", 2);
LEVEL_MAP.put("WARN", 2);
LEVEL_MAP.put("ERROR", 2);
LEVEL_INT = LEVEL_MAP.get(LEV_EL.toUpperCase());
new Thread(() -> {
while (true) {
try {
outPutConsole(LOG_LIST.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
public static void debug(String msg) {
printLog(LEVEL_MAP.get("DEBUG"), msg);
}
public static void debug(String msg, Object params) {
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
}
public static void debug(String msg, Object... params) {
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
}
public static void info(String msg) {
printLog(LEVEL_MAP.get("INFO"), msg);
}
public static void info(String msg, Object params) {
printLog(LEVEL_MAP.get("INFO"), msg, params);
}
public static void info(String msg, Object... params) {
printLog(LEVEL_MAP.get("INFO"), msg, params);
}
public static void warn(String msg) {
printLog(LEVEL_MAP.get("WARN"), msg);
}
public static void warn(String msg, Object params) {
printLog(LEVEL_MAP.get("WARN"), msg, params);
}
public static void warn(String msg, Object... params) {
printLog(LEVEL_MAP.get("WARN"), msg, params);
}
public static void error(String msg) {
printLog(LEVEL_MAP.get("ERROR"), msg);
}
public static void error(String msg, Object params) {
printLog(LEVEL_MAP.get("ERROR"), msg, params);
}
public static void error(String msg, Object... params) {
printLog(LEVEL_MAP.get("ERROR"), msg, params);
}
public static void error(Object param) {
printLog(LEVEL_MAP.get("ERROR"), "", param);
}
private static void printLog(int levelInt, String msg, Object... params) {
try {
if (levelInt >= LEVEL_INT) {
LOG_LIST.put(generateMsg(getLevelStr(levelInt), msg, params));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static String generateMsg(String levelStr, String msg, Object... params) {
StackTraceElement stack = Thread.currentThread().getStackTrace()[4];
String s = "{} [{}][{}#{} {}] - " + msg + LINE_SEPARATOR;
Object[] args = new Object[5 + params.length];
args[0] = FORMAT.format(System.currentTimeMillis());
args[1] = levelStr;
args[2] = stack.getClassName();
args[3] = stack.getMethodName();
args[4] = stack.getLineNumber();
Throwable throwable = null;
if (params.length > 0) {
final Object lastEntry = params[params.length - 1];
if (lastEntry instanceof Throwable) {
throwable = (Throwable) lastEntry;
System.arraycopy(params, 0, args, 5, params.length - 1);
} else {
System.arraycopy(params, 0, args, 5, params.length);
}
}
return formatMsg(s, throwable, args);
}
private static String formatMsg(String msg, Throwable throwable, Object... params) {
StringBuilder sb = new StringBuilder();
int s;
int i = 0;
for (Object o : params) {
s = msg.indexOf(DELIM_STR, i);
if (s > -1) {
sb.append(msg, i, s).append(o);
i = s + 2;
}
}
sb.append(msg, i, msg.length());
if (null != throwable) {
sb.append(throwable).append(LINE_SEPARATOR);
StackTraceElement[] stack = throwable.getStackTrace();
for (StackTraceElement element : stack) {
sb.append(TAB).append(element).append(LINE_SEPARATOR);
}
}
return sb.toString();
}
private static void outPutConsole(String msg) {
try {
OUTPUT_STREAM.write(msg.getBytes(StandardCharsets.UTF_8));
OUTPUT_STREAM.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getLevelStr(int levelInt) {
switch (levelInt) {
case 1:
return "DEBUG";
case 2:
return "INFO";
case 3:
return "WARN";
case 4:
return "ERROR";
default:
throw new IllegalStateException("Level " + levelInt + " is unknown.");
}
}
}

View File

@ -0,0 +1,101 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
import java.util.Random;
/**
* Random Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class RandomUtils {
private RandomUtils() {
}
private static final Random rand = new Random();
public static int nextInt(int i) {//返回随机整数最小为0最大为n-1
if(i==0)
return 0;
return rand.nextInt(i);
}
public static int nextNegOrPosInt(int n) {//返回随机整数最小为-(n-1)最大为n-1
int x = nextInt(n);
if (percent(50))
return x;
return -x;
}
public static float nextFloat() {
return rand.nextFloat();
}
public static boolean percent(float percent) {// 有百分这percent的机率为true
return rand.nextFloat() * 100 < percent;
}
public static int vary(int v, int percet) {
if (percent(percet))
return vary(v);
return v;
}
public static int vary(int v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
if (percent(10))
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
else if (percent(5))
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
else if (percent(2))
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
else if (percent(1f))
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
return v;
}
public static float vary(float v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
if (percent(10))
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
else if (percent(5))
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
else if (percent(2))
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
else if (percent(1f))
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
return v;
}
public static int varyInLimit(int v, int from, int to) {// 让返回值在from和to之间随机变异
int i = vary(v);
if (i < from)
i = from;
if (i > to)
i = to;
return i;
}
public static float varyInLimit(float v, float from, float to) {// 让返回值在from和to之间随机变异
float i = vary(v);
if (i < from)
i = from;
if (i > to)
i = to;
return i;
}
}

View File

@ -0,0 +1,105 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
/**
* StringPixelUtils used to get pixel array from a given string
*
* 根据给定的字体和字符串返回它的像素点阵lettersMap[0][0]是左下角素
*
* @author Yong Zhu
* @since 2.0.2
*/
public class StringPixelUtils {
private static final Map<String, byte[][]> lettersMap = new HashMap<>();//cache
public static byte[][] getSanserif10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 10, s);
}
public static byte[][] getSanserif12Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, s);
}
public static byte[][] getSanserifItalic10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.ITALIC, 10, s);
}
/* 在内存 BufferedImage里输出文本并获取它的像素点 */
public static byte[][] getStringPixels(String fontName, int fontStyle, int fontSize, String s) {
String key = new StringBuilder(fontName).append("_").append(fontStyle).append("_").append(fontSize).append("_")
.append(s).toString();
if (lettersMap.containsKey(key))
return lettersMap.get(key);
Font font = new Font(fontName, fontStyle, fontSize);
BufferedImage bi = new BufferedImage(fontSize * 10, fontSize * 50, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int strHeight = fm.getAscent() + fm.getDescent() - 1;
int strWidth = fm.stringWidth(s);
g2d.drawString(s, 0, fm.getAscent() - fm.getLeading() -1);
int ystart;//改进在命令行和eclipse下会有不同的空行所以要用ystart和yend来限定只获取有效象素行数
loop1: for (ystart = 0; ystart < strHeight; ystart++)
for (int x = 0; x < strWidth; x++) {
if (bi.getRGB(x, ystart) == -1)
break loop1;
}
int yend;
loop2: for (yend = strHeight; yend >= 0; yend--)
for (int x = 0; x < strWidth; x++) {
if (bi.getRGB(x, yend) == -1)
break loop2;
}
byte[][] b = new byte[strWidth][yend-ystart+1];
for (int y = ystart; y <= yend; y++)
for (int x = 0; x < strWidth; x++)
if (bi.getRGB(x, y ) == -1)
b[x][yend-y] = 1;
else
b[x][yend-y] = 0;
lettersMap.put(key, b);
return b;
}
/*- 这个是测试输出平时不需要用
public static void main(String[] args) {
System.out.println("===============");
byte[][] c = getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, "FROG");
int w = c.length;
int h = c[0].length;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (c[x][h - y - 1] > 0)
System.out.print("*");
else
System.out.print(" ");
}
System.out.println();
}
System.out.println("===============");
}
*/
}

View File

@ -0,0 +1,89 @@
/* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.util;
import java.util.List;
import com.gitee.drinkjava2.frog.Env;
/**
* Tree8Util used to store a pre-order Traversal tree array to speed
*
* 这里缓存着一个前序排列的八叉树用来在细胞生成时加快速度和简化运算关于树结构可用深度树数组来表达的知识可以参见这里https://my.oschina.net/drinkjava2/blog/1818631
*
* @author Yong Zhu
* @since 1.0
*/
public class Tree8Util {
//EIGHT_TREE store a pre-order Traversal tree array
public static final int NODE_QTY = calculateNodeSize(Env.BRAIN_CUBE_SIZE);
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示第一维是深度树的行号第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录大于等于0的值表示要keep, 负数节点表示要敲除
private static byte[] KEEP = new byte[NODE_QTY]; //这里保存初值为0的数组常量可以用System.arraycopy(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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -1,5 +1,6 @@
## 初学者入门介绍
注意这个介绍只是针对码云"人工生命"以后简称Frog)这个项目本身,并不是神经网络知识入门介绍。
注意这个介绍只是针对码云"人工生命"以后简称Frog)这个项目本身,并不是神经网络知识入门介绍。
下面的介绍仅针对早期版本因时间关系没有继续更新后来陆续更新了好多版后按时间顺序放在history目录下。大家可以参数Readme中的介绍一个目录一个目录地看如果想研究源码的建议看懂003b_simple目录。但是总的来说源码并不重要关键是思路。
### 项目的运行环境
Frog项目需要安装JDK8、Maven、GIT客户端如果已经在本机上安装过的请跳过这一节

View File

@ -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元