diff --git a/README.md b/README.md index fb664e5..e2a0a32 100644 --- a/README.md +++ b/README.md @@ -67,28 +67,42 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) 2019-06-26 找食效率太低,又改回到4.12的用连接数量代替权值这个逻辑,人为设计的算法居然比不过随机连接。Pain器官的加入没有提高找食效率,必须与感光细胞合用才能知道是哪个边界,急需引入记忆功能。 2019-06-28 为了让青蛙看到边界,又加了个新的眼睛,它是一个可自进化的nxn点阵的眼睛,将来会取代只有四个象素点(但能看得远)的老眼睛。到目前为止,依然还没有进行模式识别和记忆功能开发。另外脑图可以动态显示了,用一个红圈标记出被动态跟踪显示的青蛙。 -2019-07-28 -有以下改动:1.在Env区中间加了一个陷阱区Trap,以增加趣味性,自然选择的结果是青蛙会自动绕开陷阱区。2.增加一个Active器官,它的作用是一直保持激活,发现比Hungry器官驱动更能提高找食效率。3.增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。目前进食奖励信号没用到,白白浪费了。 +2019-07-28 有以下改动: 1.在Env区中间加了一个陷阱区Trap,以增加趣味性,自然选择的结果是青蛙会自动绕开陷阱区。2.增加一个Active器官,它的作用是一直保持激活,发现比Hungry器官驱动更能提高找食效率。3.增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。目前进食奖励信号没用到,白白浪费了。 另外Chance和Eye类里也再次运用了随机试错原理去确定关键参数,效果还不错,有兴趣的可以看一看源码。 ![resut4](https://gitee.com/drinkjava2/frog/raw/master/result4.gif) - 另外发现青蛙其实是有记忆能力的,因为连接本身就是一种记忆,只不过它没有复杂的模式识别能力,例如给个蛇的图片它就认不出来。以后的工作将以模式识别为重点(当然随机连接看起来很有用,以后还可能保留),基本原理是见note中提到的仿照波传播及全息存储原理,在思维区逆向成像。而且脑可能改成三维结构,并根据逆向成像原理,要将所有输入输出器官全移到三维结构的同一侧(即思维区)。这将会是一个非常大的改动,下面我简单画了一个3D示意图来说明我想象中的这个模式识别和记忆的原理,至于对不对还需要实验来验证: ![3d-model](https://gitee.com/drinkjava2/frog/raw/master/3d-model.gif) 这个模型的最顶层表示眼睛的感光细胞(或任意输入输出细胞),同时也是思维区,红色表示一个长条的图形,兰色表示一个三角图形,如果这两个图形经常有规律地同时出现,就会把它们共有的节点撑大,见紫色的节点,当红色图形单独出现,就会强烈激活紫色节点,然后紫色节点的信号反向传播,就会激活三角图形,反之亦然。这就同时解释了模式识别和记忆(或者说回忆)功能的的原理。一个节点可以被多个感光细胞共享,所以它的存储能力是很强的。而且可能这个原理比较符合生物脑结构。当然,实际编程时,虚拟神经元不一定要排成正立方三角,而可能通过胡乱排放,大致上过得去就行了,也许能乱拳打死老师傅,最终要靠电脑自动随机的排放,然后用优胜劣汰来筛选。目前有个难点是这个记忆功能在思维区成像是如何有条不紊地大体上按串行进行工作的,这个问题先放一放。 2019-08-04 更新了一个分组测试功能,如果测试青蛙数量太多,可以分批来测试,每轮测试最少的青蛙数量可以少到只有一个,这是用时间来换空间。 +2019-08-05 有了分组测试功能后,顺手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试,大约跑90多轮半个小时(电脑慢)后,出现了下面的画面: +![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif) +这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,青蛙只会找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛),但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本,今后这个项目将沉寂一段较长时间,我将致力于将青蛙脑重构为3D金字塔形脑结构(见上文),因为这个项目的缺点已经很明显,它不具备对2维图像的模式识别能力,用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。 +青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上,器官的用进废退、奖励信号的利用都没反映,但我认为这些还不关键,目前最急迫的任务应该是先进行3D脑结构建模,让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式完全不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。 + +如果想要运行这个项目的以前版本,可以结合gitk命令和参考"版本提交记录.md"的介绍,用git reset命令回复到以前任一个版本,例如用: +git reset --hard ae34b07e 可以转回到上一个分组测试的找食版本。 +## 重要参数 | Parameters +在Env.java类中以下有以下可调整参数,请手工修改这些参数进行不同的测试,前5个参数很重要: +``` +SHOW_SPEED: 调整实验的速度(1~1000),值越小则越慢。 +DELETE_EGGS: 每次运行是否先删除保存的蛋,如果设为false,将不删除保存的蛋,会接着上次的测试结果续继运行。 +EGG_QTY: 每次允许Frog下多少个蛋,通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一批蛋。 +FROG_PER_EGG: 每个蛋可以孵出多少个青蛙。 +SCREEN: 分屏测试,一轮测试可以分为多个批次进行,这里是屏数。每轮总的青蛙数量=EGG_QTY * FROG_PER_EGG, 每屏青蛙数=总数/SCREEN +ENV_WIDTH: 虚拟环境的宽度大小,通常取值100~1000左右 +ENV_HEIGHT: 虚拟环境高度大小,通常取值100~1000左右 +FROG_BRAIN_DISP_WIDTH: Frog的脑图在屏幕上的显示大小,通常取值100~1000左右 +STEPS_PER_ROUND: 每轮测试步数, 每一步相当于脑思考的一桢,所有青蛙的脑神经元被遍历一次。 +FOOD_QTY:食物的数量,食物越多,则Frog的生存率就越高,能量排名靠前的一批Frog可以下蛋,其余的被淘汰。 +``` + ## 版权 | License [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) ## 期望 | Futures -欢迎发issue、私信等方式提出建议或加入开发组。 -另外本项目开启了哭穷模式,比提交一个pull request还能帮助这个项目开发的,莫过于提交一个红包了,金钱就是时间,您的捐助将只会用于回馈本项目的实际参与开发者。 - -## 作者其它开源项目 | Other Projects -- [Java持久层工具 jSqlBox](https://gitee.com/drinkjava2/jSqlBox) -- [微型IOC/AOP工具 jBeanBox](https://gitee.com/drinkjava2/jBeanBox) -- [前端写SQL工具 GoSqlGo](https://gitee.com/drinkjava2/gosqlgo) -- [MyBatis增强插件 MyFatFat](https://gitee.com/drinkjava2/myfatfat) +欢迎发issue、评论等方式提出建议或加入开发组。 +另外本项目开启了哭穷模式,比提交一个pull request还能帮助这个项目开发的,莫过于提交一个红包了,金钱就是时间,您的捐助会用于回馈本项目的参与开发者或用于发布开发任务。 ## 关注我 | About Me [Github](https://github.com/drinkjava2) diff --git a/core/src/main/java/com/github/drinkjava2/frog/Env.java b/core/src/main/java/com/github/drinkjava2/frog/Env.java index 8cdca51..e741a5f 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Env.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Env.java @@ -6,13 +6,16 @@ import java.awt.Image; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; -import java.util.Random; import javax.swing.JPanel; import com.github.drinkjava2.frog.brain.group.RandomConnectGroup; import com.github.drinkjava2.frog.egg.Egg; import com.github.drinkjava2.frog.egg.EggTool; +import com.github.drinkjava2.frog.objects.Food; +import com.github.drinkjava2.frog.objects.Material; +import com.github.drinkjava2.frog.objects.Object; +import com.github.drinkjava2.frog.objects.SeeSaw; import com.github.drinkjava2.frog.util.RandomUtils; /** @@ -24,22 +27,19 @@ import com.github.drinkjava2.frog.util.RandomUtils; @SuppressWarnings("all") public class Env extends JPanel { /** Speed of test */ - public static final int SHOW_SPEED = 300; // 测试速度,-1000~1000,可调, 数值越小,速度越慢 + public static final int SHOW_SPEED = 1; // 测试速度,-1000~1000,可调, 数值越小,速度越慢 /** Delete eggs at beginning of each run */ - public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的蛋 + public static final boolean DELETE_EGGS = false;// 每次运行是否先删除保存的蛋 - public static final int EGG_QTY = 30; // 每轮下n个蛋,可调,只有最优秀的前n个青蛙们才允许下蛋 + public static final int EGG_QTY = 25; // 每轮下n个蛋,可调,只有最优秀的前n个青蛙们才允许下蛋 - public static final int FROG_PER_EGG = 3; // 每个蛋可以孵出几个青蛙 + public static final int FROG_PER_EGG = 4; // 每个蛋可以孵出几个青蛙 - public static final int SCREEN = 3; // 分几屏测完, 所以每轮待测青蛙总数=EGG_QTY*FROG_PER_EGG*SCREEN + public static final int SCREEN = 100; // 分几屏测完 public static final int FROG_PER_SCREEN = EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙,这个数值由上面三个参数计算得来 - /** Debug mode will print more debug info */ - public static final boolean DEBUG_MODE = false; // Debug 模式下会打印出更多的调试信息 - /** Draw first frog's brain after some steps */ public static int DRAW_BRAIN_AFTER_STEPS = 50; // 以此值为间隔动态画出脑图,设为0则关闭这个动态脑图功能,只显示一个静态、不闪烁的脑图 @@ -60,20 +60,16 @@ public class Env extends JPanel { public static final int FOOD_QTY = 1500; // 食物数量, 可调 - private static final Random r = new Random(); // 随机数发生器 - public static boolean pause = false; // 暂停按钮按下将暂停测试 - private static final boolean[][] foods = new boolean[ENV_WIDTH][ENV_HEIGHT];// 食物数组定义 - - private static final int TRAP_WIDTH = 350; // 陷阱高, 0~200 - - private static final int TRAP_HEIGHT = 10; // 陷阱宽, 0~200 + public static byte[][] bricks = new byte[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,0=无, 1=食, 其它=其它... public static List frogs = new ArrayList<>(); // 这里存放所有待测的青蛙,可能分几次测完,由FROG_PER_SCREEN大小来决定 public static List eggs = new ArrayList<>(); // 这里存放从磁盘载入或上轮下的蛋,每个蛋可能生成1~n个青蛙, + public static Object[] things = new Object[] { new SeeSaw() }; + static { System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒,见码云issue#IW4H8 if (DELETE_EGGS) @@ -94,40 +90,22 @@ public class Env extends JPanel { return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT; } - public static boolean foundFood(int x, int y) {// 如果指定点看到食物 - return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT) && Env.foods[x][y]; - } - public static boolean closeToEdge(Frog f) {// 青蛙靠近边界? 离死不远了 return f.x < 20 || f.y < 20 || f.x > (Env.ENV_WIDTH - 20) || f.y > (Env.ENV_HEIGHT - 20); } - public static boolean inTrap(int x, int y) {// 如果指定点看到食物 - return x >= ENV_WIDTH / 2 - TRAP_WIDTH / 2 && x <= ENV_WIDTH / 2 + TRAP_WIDTH / 2 - && y >= ENV_HEIGHT / 2 - TRAP_HEIGHT / 2 && y <= ENV_HEIGHT / 2 + TRAP_HEIGHT / 2; - } - - public static boolean foundAnyThing(int x, int y) {// 如果指定点看到食物或超出边界 - return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.foods[x][y] || inTrap(x, y); + public static boolean foundAnyThing(int x, int y) {// 如果指定点看到任意东西或超出边界 + return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] >= Material.VISIBLE; } - public static boolean foundAndDeleteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true - if (foundFood(x, y)) { - foods[x][y] = false; + public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true + if (insideEnv(x, y) && Env.bricks[x][y] == Material.FOOD) { + bricks[x][y] = 0; return true; } return false; } - private void rebuildFood() { - for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物 - for (int j = 0; j < ENV_HEIGHT; j++) - foods[i][j] = false; - } - for (int i = 0; i < Env.FOOD_QTY; i++) // 生成食物 - foods[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = true; - } - private void rebuildFrogs() { frogs.clear(); for (int i = 0; i < eggs.size(); i++) {// 创建青蛙,每个蛋生成n个蛙,并随机取一个别的蛋作为精子 @@ -139,26 +117,26 @@ public class Env extends JPanel { loop = FROG_PER_EGG - 1; } for (int j = 0; j < loop; j++) { - Egg zygote = new Egg(eggs.get(i), eggs.get(r.nextInt(eggs.size()))); + Egg zygote = new Egg(eggs.get(i), eggs.get(RandomUtils.nextInt(eggs.size()))); frogs.add(new Frog(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote)); } } } - private void drawFood(Graphics g) { + private void drawWorld(Graphics g) { + byte brick; for (int x = 0; x < ENV_WIDTH; x++) - for (int y = 0; y < ENV_HEIGHT; y++) - if (foods[x][y]) { - g.fillOval(x, y, 4, 4); + for (int y = 0; y < ENV_HEIGHT; y++) { + brick = bricks[x][y]; + if (brick != 0) { + g.setColor(Material.color(brick)); + if (brick == Material.FOOD) + g.fillRoundRect(x, y, 4, 4, 2, 2); // show food bigger + else + g.drawLine(x, y, x, y); // only 1 point } - } - - private void drawTrap(Graphics g) {// 所有走到陷阱边沿上的的青蛙都死掉 - g.fillRect(ENV_HEIGHT / 2 - TRAP_WIDTH / 2, ENV_HEIGHT / 2 - TRAP_HEIGHT / 2, TRAP_WIDTH, TRAP_HEIGHT); - g.setColor(Color.white); - g.fillRect(ENV_HEIGHT / 2 - TRAP_WIDTH / 2 + 3, ENV_HEIGHT / 2 - TRAP_HEIGHT / 2 + 3, TRAP_WIDTH - 6, - TRAP_HEIGHT - 6); - g.setColor(Color.black); + } + g.setColor(Color.BLACK); } static final NumberFormat format100 = NumberFormat.getPercentInstance(); @@ -170,7 +148,7 @@ public class Env extends JPanel { int leftfood = 0; for (int x = 0; x < ENV_WIDTH; x++) for (int y = 0; y < ENV_HEIGHT; y++) - if (foods[x][y]) + if (bricks[x][y] == 1) leftfood++; return FOOD_QTY - leftfood; } @@ -182,7 +160,7 @@ public class Env extends JPanel { if (f.ateFood > maxFound) maxFound = f.ateFood; return new StringBuilder("找食率:").append(format100.format(foodFound * 1.00 / FOOD_QTY)).append(", 平均: ") - .append(foodFound * 1.0f / (EGG_QTY * FROG_PER_EGG)).append(",最多:").append(maxFound).toString(); + .append(foodFound * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString(); } private static void sleep(long millis) { @@ -207,19 +185,21 @@ public class Env extends JPanel { do { sleep(300); } while (pause); - rebuildFood(); + for (Object thing : things) // 创建食物、陷阱等物体 + thing.build(); boolean allDead = false; Frog firstFrog = frogs.get(screen * FROG_PER_SCREEN); for (int i = 0; i < STEPS_PER_ROUND; i++) { + for (Object thing : things)// 调用食物、陷阱等物体的动作 + thing.active(screen); if (allDead) break; // 青蛙全死光了就直接跳到下一轮,以节省时间 - allDead = true; for (int j = 0; j < FROG_PER_SCREEN; j++) { Frog f = frogs.get(screen * FROG_PER_SCREEN + j); if (f.active(this)) allDead = false; - if (f.alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官 + if (f.alive && RandomUtils.percent(0.5f)) {// 有很小的机率在青蛙活着时就创建新的器官 RandomConnectGroup newConGrp = new RandomConnectGroup(); newConGrp.initFrog(f); f.organs.add(newConGrp); @@ -236,6 +216,7 @@ public class Env extends JPanel { 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(screen * FROG_PER_SCREEN + j); f.show(g); @@ -250,16 +231,16 @@ public class Env extends JPanel { if (DRAW_BRAIN_AFTER_STEPS > 0 && i % DRAW_BRAIN_AFTER_STEPS == 0) Application.brainPic.drawBrainPicture(firstFrog); } - drawTrap(g); - drawFood(g); Graphics g2 = this.getGraphics(); g2.drawImage(buffImg, 0, 0, this); - } Application.brainPic.drawBrainPicture(firstFrog); Application.mainFrame.setTitle(new StringBuilder("Round: ").append(round).append(", screen:") .append(screen).append(", ").append(foodFoundCountText()).append(", 用时: ") - .append(System.currentTimeMillis() - time0).append("ms").toString()); + .append(System.currentTimeMillis() - time0).append("ms").append(", energy:") + .append(firstFrog.energy).toString()); + for (Object thing : things)// 去除食物、陷阱等物体 + thing.destory(); } round++; EggTool.layEggs(); diff --git a/core/src/main/java/com/github/drinkjava2/frog/Frog.java b/core/src/main/java/com/github/drinkjava2/frog/Frog.java index f9d91f3..5f1af0c 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Frog.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Frog.java @@ -21,6 +21,7 @@ import javax.imageio.ImageIO; import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.brain.Organ; import com.github.drinkjava2.frog.egg.Egg; +import com.github.drinkjava2.frog.objects.Material; /** * Frog = organs + brain cells @@ -63,14 +64,16 @@ public class Frog { } public boolean active(Env v) { - if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.inTrap(x, y)) {// 如果能量小于0则死 - energy -= 100; // 死掉的青蛙也要消耗能量,保证淘汰出局 + // 如果能量小于0则死、出界、与非食物的点重合则判死 + if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILLFROG) { + energy -= 100; // 死掉的青蛙也要消耗能量,确保淘汰出局 alive = false; return false; } energy -= 20; - for (Organ o : organs) + for (Organ o : organs) { o.active(this); + } return alive; } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java b/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java index ed223df..3bd760d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java @@ -52,7 +52,7 @@ public class RandomConnectGroup extends Group { x = Env.FROG_BRAIN_WIDTH / 2; y = Env.FROG_BRAIN_WIDTH / 2; r = Env.FROG_BRAIN_WIDTH / 2; - inputZone = RandomUtils.randomPosInAnyFrogOrgan(f); + inputZone = RandomUtils.randomPosMostInNewEye(f); outputZone = RandomUtils.randomPosInAnyFrogOrgan(f); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java index cf97cec..3b097d8 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java @@ -22,7 +22,7 @@ public class Eat extends Organ {// Eat这个类将食物转化为能量,能量 @Override public void active(Frog f) { - if (Env.foundAndDeleteFood(f.x, f.y)) { + if (Env.foundAndAteFood(f.x, f.y)) { f.ateFood++; // 所有的硬编码都是bug,包括这个1000 f.energy += 1000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java index 43c8645..29d9686 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java @@ -58,7 +58,7 @@ public class Eye extends Organ {// 这个Eye是老版的眼睛,只能看到四 @Override public Organ[] vary() { - if (RandomUtils.percent(5)) { + if (RandomUtils.percent(5)) { // 可视距离有5%的机率变异 seeDistance = seeDistance + 1 - 2 * RandomUtils.nextInt(2); if (seeDistance < 1) seeDistance = 1; @@ -78,55 +78,55 @@ public class Eye extends Organ {// 这个Eye是老版的眼睛,只能看到四 Zone seeLeft = new Zone(x - q3Radius, y, qRadius); Zone seeRight = new Zone(x + q3Radius, y, qRadius); - boolean seeFood = false; - boolean foodAtUp = false; - boolean foodAtDown = false; - boolean foodAtLeft = false; - boolean foodAtRight = false; + boolean seeSomething = false; + boolean atUp = false; + boolean atDown = false; + boolean atLeft = false; + boolean atRight = false; for (int i = 1; i < seeDistance; i++) - if (Env.foundFood(f.x, f.y + i)) { - seeFood = true; - foodAtUp = true; + if (Env.foundAnyThing(f.x, f.y + i)) { + seeSomething = true; + atUp = true; break; } for (int i = 1; i < seeDistance; i++) - if (Env.foundFood(f.x, f.y - i)) { - seeFood = true; - foodAtDown = true; + if (Env.foundAnyThing(f.x, f.y - i)) { + seeSomething = true; + atDown = true; break; } for (int i = 1; i < seeDistance; i++) - if (Env.foundFood(f.x - i, f.y)) { - seeFood = true; - foodAtLeft = true; + if (Env.foundAnyThing(f.x - i, f.y)) { + seeSomething = true; + atLeft = true; break; } for (int i = 1; i < seeDistance; i++) - if (Env.foundFood(f.x + i, f.y)) { - seeFood = true; - foodAtRight = true; + if (Env.foundAnyThing(f.x + i, f.y)) { + seeSomething = true; + atRight = true; break; } - if (seeFood) + if (seeSomething) for (Cell cell : f.cells) { if (cell.energy < 100) for (Input input : cell.inputs) { if (input.nearby(this)) { - if (foodAtUp && input.nearby(seeUp)) { + if (atUp && input.nearby(seeUp)) { input.cell.energy += organOutputEnergy; } - if (foodAtDown && input.nearby(seeDown)) { + if (atDown && input.nearby(seeDown)) { input.cell.energy += organOutputEnergy; } - if (foodAtLeft && input.nearby(seeLeft)) { + if (atLeft && input.nearby(seeLeft)) { input.cell.energy += organOutputEnergy; } - if (foodAtRight && input.nearby(seeRight)) { + if (atRight && input.nearby(seeRight)) { input.cell.energy += organOutputEnergy; } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java index d9459ed..cdff767 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java @@ -18,7 +18,6 @@ import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; import com.github.drinkjava2.frog.brain.Zone; -import com.github.drinkjava2.frog.util.RandomUtils; /** * Eye is an organ can see environment, and active brain cells which inputs are @@ -29,7 +28,7 @@ import com.github.drinkjava2.frog.util.RandomUtils; */ public class NewEye extends Organ {// 这个新版的眼睛有nxn个感光细胞,可以看到青蛙周围nxn网络内有没有食物 private static final long serialVersionUID = 1L; - public int n = 3; // 眼睛有n x n个感光细胞, 用随机试错算法自动变异(加1或减1,最小是3x3) + public int n = 13; // 眼睛有n x n个感光细胞, 用随机试错算法自动变异(加1或减1,最小是3x3) @Override public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次,缺省啥也不干,通常用于Organ类的初始化 @@ -60,13 +59,13 @@ public class NewEye extends Organ {// 这个新版的眼睛有nxn个感光细胞 @Override public Organ[] vary() { - if (RandomUtils.percent(50)) { - n = n + 1 - 2 * RandomUtils.nextInt(2); - if (n < 3) - n = 3; - if (n > 12) - n = 12; - } +// if (RandomUtils.percent(50)) { +// n = n + 1 - 2 * RandomUtils.nextInt(2); +// if (n < 3) +// n = 3; +// if (n > 12) +// n = 12; +// } return new Organ[] { this }; } diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java b/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java index d384f0d..4e36670 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java +++ b/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java @@ -22,7 +22,6 @@ import java.util.List; import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; -import com.github.drinkjava2.frog.brain.Organ; import com.github.drinkjava2.frog.brain.organ.Chance; import com.github.drinkjava2.frog.brain.organ.Eye; import com.github.drinkjava2.frog.util.FrogFileUtils; @@ -47,13 +46,6 @@ public class EggTool { Frog first = Env.frogs.get(0); Frog last = Env.frogs.get(Env.frogs.size() - 1); - if (Env.DEBUG_MODE) - for (int i = 0; i < first.organs.size(); i++) { - Organ org = first.organs.get(i); - System.out.println("Organ(" + i + ")=" + org + ", fat=" + org.fat + ", organWasteEnergy=" - + org.organActiveEnergy + ", outputEnergy=" + org.organOutputEnergy); - } - try { Env.eggs.clear(); for (int i = 0; i < Env.EGG_QTY; i++) @@ -65,7 +57,7 @@ public class EggTool { System.out.print("\r1st frog has " + first.organs.size() + " organs, energy=" + first.energy + ", seeDist=" + ((Eye) first.organs.get(6)).seeDistance + ", chance=" + ((Chance) first.organs.get(10)).percent); System.out.println(", Last frog has " + last.organs.size() + " organs, energy=" + last.energy); - System.out.println("Saved 1 group eggs to file '" + Application.CLASSPATH + "eggs.ser'"); + System.out.println("Saved "+Env.eggs.size() +" eggs to file '" + Application.CLASSPATH + "eggs.ser'"); } catch (IOException e) { System.out.println(e); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java new file mode 100644 index 0000000..ea03051 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java @@ -0,0 +1,48 @@ +/* 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.github.drinkjava2.frog.objects; + +import static com.github.drinkjava2.frog.Env.ENV_HEIGHT; +import static com.github.drinkjava2.frog.Env.ENV_WIDTH; +import static com.github.drinkjava2.frog.Env.FOOD_QTY; +import static com.github.drinkjava2.frog.Env.bricks; + +import com.github.drinkjava2.frog.util.RandomUtils; + +/** + * Food randomly scatter on Env + * + * @author Yong Zhu + * @since 1.0 + */ +public class Food implements Object { + + @Override + public void build() { + for (int i = 0; i < FOOD_QTY; i++) // 生成食物 + bricks[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++) + if (bricks[i][j] == Material.FOOD) + bricks[i][j] = 0; + } + } + + @Override + public void active(int screen) { + // Food do not have any active + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java new file mode 100644 index 0000000..ca66cc7 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java @@ -0,0 +1,40 @@ +/* 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.github.drinkjava2.frog.objects; + +import java.awt.Color; + +/** + * Object means some thing in Env + * + * @author Yong Zhu + * @since 1.0 + */ +public class Material { + public static final byte VISIBLE = 10; // if>=10 will visible to frog + public static final byte KILLFROG = 20; // if>=20 will kill frog + + public static final byte NO = 0; + public static final byte SEESAW_BASE = 1; // 1~9 is invisible to frog + + public static final byte FOOD = VISIBLE + 1; + public static final byte SEESAW = VISIBLE + 2; // if <0 will not cause frog die + + public static final byte BRICK = KILLFROG + 1; + public static final byte TRAP = KILLFROG + 2; + + public static Color color(byte material) { + if (material == TRAP) + return Color.LIGHT_GRAY; + else + return Color.BLACK; + } +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Object.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Object.java new file mode 100644 index 0000000..daa3160 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/Object.java @@ -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.github.drinkjava2.frog.objects; + +/** + * Object means some thing in Env + * + * @author Yong Zhu + * @since 1.0 + */ +public interface Object { + + public void build(); + + public void destory(); + + public void active(int screen); +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java b/core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java new file mode 100644 index 0000000..5f220ae --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java @@ -0,0 +1,93 @@ +/* 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.github.drinkjava2.frog.objects; + +import static com.github.drinkjava2.frog.Env.ENV_HEIGHT; +import static com.github.drinkjava2.frog.Env.ENV_WIDTH; +import static com.github.drinkjava2.frog.Env.bricks; + +import com.github.drinkjava2.frog.Env; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.util.RandomUtils; + +/** + * This is a seesaw to train frog's balance + * + * @author Yong Zhu + * @since 2.0.1 + */ +public class SeeSaw implements Object { + private static final int LEGNTH = 300; + private static final int CENTER_X = Env.ENV_WIDTH / 2; + private static final int CENTER_Y = Env.ENV_HEIGHT / 2; + + private double angle = 0;// -PI/4 to PI/4 + private double leftWeight = 0; + private double rightWeight = 0; + + @Override + public void build() { + angle = 0; + } + + @Override + public void destory() { + + } + + @Override + public void active(int screen) { + for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物 + for (int j = 0; j < ENV_HEIGHT; j++) + if (bricks[i][j] == Material.SEESAW) + bricks[i][j] = 0; + } + + if (RandomUtils.percent(2)) + leftWeight = RandomUtils.nextFloat() * 3; + if (RandomUtils.percent(2)) + rightWeight = RandomUtils.nextFloat() * 3; + Frog f = Env.frogs.get(screen); + + if (f.x < (CENTER_X - LEGNTH / 2) || f.x > (CENTER_X + LEGNTH / 2)) + f.energy -= 100000; // 如果走出跷跷板外则扣分,出局 + double left = leftWeight - (f.x - CENTER_X); + double right = rightWeight + (f.x - CENTER_X); + // right - left need in -100 to +100 + angle = angle + (right - left) * Math.PI * .000001; + if (angle > Math.PI / 6) { + angle = Math.PI / 6; + f.energy -= 200; + } + if (angle < -Math.PI / 6) { + angle = -Math.PI / 6; + f.energy -= 200; + } + f.y = CENTER_Y + (int) Math.round((f.x - CENTER_X) * Math.tan(angle)); + f.energy -= Math.abs(angle) * 180; // 角度越大,扣分越多 + int x; + int y; + for (int l = -LEGNTH / 2; l <= LEGNTH / 2; l++) { + x = (int) Math.round(l * Math.cos(angle)); + y = (int) Math.round(l * Math.sin(angle)); + Env.bricks[CENTER_X + x][CENTER_Y + y] = Material.SEESAW; + } + + // 画底座 + for (int i = 1; i < 10; i++) { + Env.bricks[CENTER_X - i][CENTER_Y + i] = Material.SEESAW_BASE; + Env.bricks[CENTER_X + i][CENTER_Y + i] = Material.SEESAW_BASE; + } + for (int i = -10; i < 10; i++) + Env.bricks[CENTER_X + i][CENTER_Y + 10] = Material.SEESAW_BASE; + + } +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java new file mode 100644 index 0000000..0b7fc68 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java @@ -0,0 +1,56 @@ +/* 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.github.drinkjava2.frog.objects; + +import static com.github.drinkjava2.frog.Env.ENV_HEIGHT; +import static com.github.drinkjava2.frog.Env.ENV_WIDTH; +import static com.github.drinkjava2.frog.Env.bricks; + +import com.github.drinkjava2.frog.Frog; + +/** + * Trap will kill all frogs inside of it, if frog's position has material and + * it's not food, frog will die + * + * @author Yong Zhu + * @since 2019-08-05 + */ +@SuppressWarnings("all") +public class Trap implements Object { + private static final int X1 = ENV_WIDTH / 2 - 350 / 2; // 陷阱左上角 + private static final int Y1 = ENV_HEIGHT / 2 - 20 / 2; // 陷阱左上角 + private static final int X2 = ENV_WIDTH / 2 + 350 / 2; // 陷阱右下角 + private static final int Y2 = ENV_HEIGHT / 2 + 20 / 2; // 陷阱右下角 + + @Override + public void build() { + for (int x = X1; x <= X2; x++) + for (int y = Y1; y <= Y2; y++) + bricks[x][y] = Material.TRAP; + } + + @Override + public void destory() { + for (int x = X1; x <= X2; x++) + for (int y = Y1; y <= Y2; y++) + bricks[x][y] = 0; + } + + @Override + public void active(int screen) { + + } + + public static boolean inTrap(Frog f) { + return f.x >= X1 && f.x <= X2 && f.y >= Y1 && f.y <= Y2; + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java b/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java index 60ecdd5..b7827bc 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java +++ b/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java @@ -46,64 +46,70 @@ public class RandomUtils { return randomZoneInZone(f.organs.get(RandomUtils.nextInt(Egg.FIXED_ORGAN_QTY))); } + /** Return a random zone inside of frog's random organ */ + public static Zone randomPosMostInNewEye(Frog f) { + if (f.organs == null || f.organs.size() == 0) + throw new IllegalArgumentException("Can not call randomPosInRandomOrgan method when frog has no organ"); + if (RandomUtils.percent(95)) + return randomZoneInZone(f.organs.get(7));// 这是一个硬编码,大部分新联接建立在newEye中 + return randomZoneInZone(f.organs.get(RandomUtils.nextInt(Egg.FIXED_ORGAN_QTY))); + } public static boolean percent(float percent) { return rand.nextFloat() * 100 < percent; } - - -// /** vary a zone position, size a little bit */ -// public static void varyZone(Zone z) { -// int i = rand.nextInt(100); -// if (i < 95) // 有95的机率不变异 -// return; -// z.x = varyByRate(z.x, 0.01f); -// z.y = varyByRate(z.y, 0.01f); -// z.r = varyByRate(z.r, 0.03f); -// } - -// public static float varyByRate(float f, float rate) { // 用指定的机率变异 -// boolean bigger = rand.nextInt(2) > 0; -// if (bigger) -// f = f + f * rate * rand.nextFloat() + .001f; -// else -// f = f - f * rate * rand.nextFloat() - .001f; -// if (Float.isNaN(f)) -// f = 0f; -// if (f > 1000000f) -// f = 1000000f; -// else if (f < -1000000f) -// f = -1000000f; -// return f; -// } + // /** vary a zone position, size a little bit */ + // public static void varyZone(Zone z) { + // int i = rand.nextInt(100); + // if (i < 95) // 有95的机率不变异 + // return; + // z.x = varyByRate(z.x, 0.01f); + // z.y = varyByRate(z.y, 0.01f); + // z.r = varyByRate(z.r, 0.03f); + // } + + // public static float varyByRate(float f, float rate) { // 用指定的机率变异 + // boolean bigger = rand.nextInt(2) > 0; + // if (bigger) + // f = f + f * rate * rand.nextFloat() + .001f; + // else + // f = f - f * rate * rand.nextFloat() - .001f; + // if (Float.isNaN(f)) + // f = 0f; + // if (f > 1000000f) + // f = 1000000f; + // else if (f < -1000000f) + // f = -1000000f; + // return f; + // } -// public static float vary(float f) { // 大部分时候不变,有极小机会变异,有极极小机会大变异,有极极极小机会大大大变异 -// int i = rand.nextInt(100); -// if (i < 50) // 有50的机率不变异 -// return f; -// float rate = 0.2f; // 50%机率在0.2倍范围变异 -// if (i > 80) -// rate = 1f; // 有20%的机率在1倍的范围变异 -// if (i > 90) -// rate = 10f; // 有10%的机率在10倍的范围变异 -// if (i > 95) -// rate = 100f; // 有5%的机率在100倍的范围变异 -// if (i > 98) -// rate = 1000f; // 有1%的机率在1000倍的范围变异 -// -// boolean bigger = rand.nextInt(2) > 0; -// if (bigger) -// f = f + f * rate * rand.nextFloat() + .001f; -// else -// f = f - f * rate * rand.nextFloat() - .001f; -// if (Float.isNaN(f)) -// f = 0f; -// if (f > 1000000f) -// f = 1000000f; -// else if (f < -1000000f) -// f = -1000000f; -// return f; -// } + // public static float vary(float f) { // 大部分时候不变,有极小机会变异,有极极小机会大变异,有极极极小机会大大大变异 + // int i = rand.nextInt(100); + // if (i < 50) // 有50的机率不变异 + // return f; + // float rate = 0.2f; // 50%机率在0.2倍范围变异 + // if (i > 80) + // rate = 1f; // 有20%的机率在1倍的范围变异 + // if (i > 90) + // rate = 10f; // 有10%的机率在10倍的范围变异 + // if (i > 95) + // rate = 100f; // 有5%的机率在100倍的范围变异 + // if (i > 98) + // rate = 1000f; // 有1%的机率在1000倍的范围变异 + // + // boolean bigger = rand.nextInt(2) > 0; + // if (bigger) + // f = f + f * rate * rand.nextFloat() + .001f; + // else + // f = f - f * rate * rand.nextFloat() - .001f; + // if (Float.isNaN(f)) + // f = 0f; + // if (f > 1000000f) + // f = 1000000f; + // else if (f < -1000000f) + // f = -1000000f; + // return f; + // } } diff --git a/eggs.ser b/eggs.ser new file mode 100644 index 0000000..3e1b613 Binary files /dev/null and b/eggs.ser differ diff --git a/result5_seesaw.gif b/result5_seesaw.gif new file mode 100644 index 0000000..f7df4a0 Binary files /dev/null and b/result5_seesaw.gif differ diff --git a/初学者入门介绍.md b/初学者入门介绍.md index cc6dc20..5dd0a64 100644 --- a/初学者入门介绍.md +++ b/初学者入门介绍.md @@ -40,19 +40,18 @@ Frog #### Envģ Env.javaģģһòͬ״ͼεģʳСϰ壬ռɳԱȫȨƺƣFrogԽϱԽԽӣͨΪƵһһܵĽ -Env.javaеĿɵ˵: +Env.javaеĿɵ˵(ֹ޸ЩвͬIJԣǰ5Ҫ): ``` SHOW_SPEED ʵٶ(1~1000)ֵԽСԽ +DELETE_EGGS: ÿǷɾĵ,ΪfalseɾĵϴεIJԽС +EGG_QTY: ÿFrog¶ٸͨµȡֵ10~1000֮䡣DzԵĽʵĿǻһ +FROG_PER_EGG ÿԷٸܡ +SCREEN ԣһֲԿԷΪνУÿܵ=EGG_QTY * FROG_PER_EGG, ÿ=/SCREEN ENV_WIDTH: ⻷ĿȴСͨȡֵ100~1000 ENV_HEIGHT: ⻷߶ȴСͨȡֵ100~1000 FROG_BRAIN_DISP_WIDTH: FrogͼĻϵʾС,ͨȡֵ100~1000 -STEPS_PER_ROUND: ÿֲԲ, ÿһ൱˼һ壬ܵԪһΡ -EGG_QTY: ÿFrog¶ٸͨµȡֵ10~1000֮䡣DzԵĽʵĿǻһ -FROG_PER_EGG ÿԷٸܡ -SCREEN ԣһֲԿԷΪνУÿܵ=EGG_QTY * FROG_PER_EGG * SCREEN +STEPS_PER_ROUND: ÿֲԲ, ÿһ൱˼һ壬ܵԪһΡ FOOD_QTYʳʳԽ࣬FrogʾԽߣǰһFrogµı̭ -DELETE_EGGS: ÿǷɾĵ,ΪfalseɾĵϴεIJԽС -DEBUG_MODE: ģʽأ翪ӡĵϢ ``` #### Frogģ Frog.java, ˹壬Ŀǰ(Frog)ʵʲôһFrogȫģ⣬ҪģԽṹ͹ܣҪ߱Թص٣ @@ -70,3 +69,4 @@ Group.java Group.javaDrawOnBrainPictureҪдÿGroupʵͼϵʾơ ĿǰԻû㷨䡢ģʽʶ),Ҳ˵ܵĿ𲽽׶ΣԵĽṹdzԱҪ⣬ҲҪȡĿꡣģ͵ɵʤ̭ѭɣģ͵Ľ̻DZɳԱƿأһ̽ +ĿҪеı룬Ҫ˼·ԴеıֻʱģʱܱƷ \ No newline at end of file diff --git a/版本提交记录.md b/版本提交记录.md index d0ed2d2..db14865 100644 --- a/版本提交记录.md +++ b/版本提交记录.md @@ -1,11 +1,16 @@ ## 版本提交记录 +如果想要运行这个项目的以前版本,可以结合gitk命令和参考"版本提交记录.md"的介绍,用git reset命令回复到以前任一个版本,例如用: +git reset --hard ae34b07e 可以转回到2019-08-04提交的分组测试的找食版本。 + + ### 2018-1-3 项目启动,主要是文字方面的一些构想。 ### 2019-3-11 1.0.0版, Commit:Go frog go! 开发环境完成,演示第一个人工生命诞生。但是所有Frog脑部为空,因为运动神经元被短路,只能固定向一个方向运动。 -这是第一个发布版,演示了生命的随机进化和优胜劣汰。 +这是第一个发布版,演示了生命的随机进化和优胜劣汰。 +![result1](https://gitee.com/drinkjava2/frog/raw/master/result1.gif) ### 2019-3-18, Commit:Brain picture! 添加了脑结构图形,用于调试用,可以显示第一个胜出的Frog的脑结构,但是运动神经元依然被短路,只能固定向一个方向运动。 @@ -37,14 +42,16 @@ 下面要考虑逻辑了,也就是思考判断能力(后天条件反射的建立)。 ### 2019-04-12, Commit:Random frog -没做大改动,只是将青蛙改成按整个地图随机分布,看起来眼睛的作用就比较明显了,比起随机运动,明显食物被吃掉更多。 +没做大改动,只是将青蛙改成按整个地图随机分布,看起来眼睛的作用就比较明显了,比起随机运动,明显食物被吃掉更多。 +![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) ### 2019-05-23, Commit:2 eyes no helps 没做大改动,只是演示添加两个眼睛后,对它的进化没有帮助,到此为此,逐渐看出问题了,没有记忆能力和模式识别能力。目前存在两个比较大的硬编码,导致它不能进一步进化:1.用CellGroup这种硬编码方式,导致在Frog的生存期不能产生记忆功能,而需要多次淘汰,这不符合现实中青蛙从小学到大这样的实际过程,它不需要死很多次。另一个问题是眼睛部分存在硬编码,因此只能起到感光作用,但是不具备根据外在图像进行模式识别能力。所以下面要开始进行非常大的结构改进,。将把CellGroup作为器官引入,但是它的内部细胞是动态生成的,而且不是随机生成的,而是任两个细胞在它的区内活跃就生成新的细胞(将来也可以参与新建细胞)。CellGroup的数量、大小、网格密度(直接影响到神经元生成多少和算法快慢)会参与遗传和进化,快乐和痛苦器官会对新细胞生成的类型有影响。fat参数用来指示它的肥胖度。Fat高的遗传时会保留,并可能变大、变小、内部允行连接数更多、分化成更多CellGroup,但是它的内部连接(新建的细胞)不会参与遗传,这样每个个体都出生时都是一张白纸,虽然也许CellGroup已经进化得很多层很复杂。同一个位置可以存在多个CellGroup,这样由多层大小、位置不同的Layer就同时具备了模式识别和记忆功能,而且这个算法比较简单,很好理解。大范围的Cellgroup可以解释条件反射的形成(两件不相干的事之间形成联系),小范围的Cellgroup可以解释模式识别(相邻感光细胞同时激活,经过层层处理后,汇总到最上层的某个Cellgroup的激活)。而所有这些CellGroup的形成(结构和层级)都可以用非常简单的"用进废退"规则(Fat值控制遗传、随机变异和适者生存来探索最优解)来最终进化出来。 ### 2019-06-13, Commit: Happy & Pain 主要做了一些清理,将所有器官移到单独的类里,删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是比较大的一个重构,最大的进步是将算法当成一个器官引入,当然,这个版本只存在一个随机连接两端的算法,以后会扩充。 -另外,顺手加上了Happy和Pain两个器官,分别对应进食愉快感和痛苦感,后者在靠近边界时激发。观查它的表现,果然不出所料,痛苦感立即生效,有一些Frog移动到边界后就不再前进,而是顺着边界溜下去了,不傻,但是Happy器官没有生效,这也很显然,因为Happy属于进食反射链的一部分,在没有记忆器官(算法)引入之前,是没有途径使用上进食奖励信号的。 +另外,顺手加上了Happy和Pain两个器官,分别对应进食愉快感和痛苦感,后者在靠近边界时激发。观查它的表现,果然不出所料,痛苦感立即生效,有一些Frog移动到边界后就不再前进,而是顺着边界溜下去了,不傻,但是Happy器官没有生效,这也很显然,因为Happy属于进食反射链的一部分,在没有记忆器官(算法)引入之前,是没有途径使用上进食奖励信号的。 +![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) ### 2019-06-26, Commit: Back to many connections 找食效率太低,又改回到4.12的用连接数量代替权值这个逻辑,权值这种人为设计的算法居然比不过随机试错,失败。先暂时去掉Pain器官,Pain的加入并没有提高找食效率,必须与感光细胞合用才能知道是哪个方向的边界,下个版本急需引入记忆功能,也就是说要将感光细胞的活跃和痛苦器官的活跃关联起来。 @@ -57,6 +64,14 @@ 2. 青蛙增加一个Active器官,它的作用是一直保持激活,如果有神经元触突位于这个区就会驱动神经元兴奋,这个器官经实践证明比Hungry器官驱动更能提高找食效率。 3. 青蛙增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。 从当前这个版本可以看出,实际上青蛙是有一定的记忆能力的,连接就=记忆,只不过没有模式识别能力,以后的工作将以模式识别为重点,基本原理是见note中提到的仿照全息存储原理,在思维区逆向成像。因为逆向成像的限制,以后的版本,所有的器官会被移到脑图的同一侧,不再是随意分布在脑图上了,这将是一个比较明显的改动。当然随机连接这个算法看起来比较有用,以后还是可能保留的。 +以下为运行图像: +![resut4](https://gitee.com/drinkjava2/frog/raw/master/result4.gif) + +### 2019-08-04, Commit: Screen group test +引入分屏测试功能,如果青蛙数量多,可以分屏来测试,每屏青蛙的数量可以少到只有1只。 -### 2019-08-04, Commit: Screen group test -引入分屏测试功能,如果青蛙数量多,可以分屏来测试,每屏青蛙的数量可以少到只有1只。 \ No newline at end of file +2019-08-05 commit: Seesaw +有了分屏测试功能后,顺便随手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试,大约跑90多轮半个小时(电脑慢)后,出现了下面的画面: +![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif) +这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,只会让青蛙找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛),但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本,今后这个项目将沉寂一段较长时间,今后将致力于将青蛙脑重构为3D金字塔形脑结构(见上文),因为这个项目的缺点已经很明显,它不具备对2维图像的模式识别能力,用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。 +青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上,但我认为这不重要,目前最高优先级是先进行3D脑结构建模,让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。 \ No newline at end of file