Work on add snake

This commit is contained in:
Yong Zhu 2020-06-03 07:59:07 -06:00
parent f67a1a0f5d
commit 830b83165b
32 changed files with 706 additions and 343 deletions

View File

@ -56,13 +56,13 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
## 目前进展和成绩
2019.03.11 虚拟环境已建好,可以模拟低等生命的遗传、繁殖、变异、进化现象,但只能往一个方向运动,相当于一个最简单的单细胞生物,还不具备视觉能力,不具备主动找食能力。
运行run.bat可以查看演示需要安装Java8和Maven
![result1](https://gitee.com/drinkjava2/frog/raw/master/result1.gif)
![result1](result1.gif)
另外每步演示的结果(egg)会存盘在根目根目录下名为egg.ser可以删除这个文件以从头开始新的测试。因为还没涉及脑模型的搭建可以看到有些青蛙跑得飞快这是自然选择的结果因为跑在最前面的吃得多。
一些重要的测试参数如显示区大小、是否每次测试要删除保存的蛋等请参见Env.java中开头的常量设定可以手工修改进行不同参数的测试。
2019.03.21 添加了脑图改进随机运动模式为Hungry区驱动。从脑图上可以直观地观察脑结构方便调试。
2019.04.01 改进脑图的显示bug, 每一次生成Frog时添加随机神经元并简单实现"卵+精子->受精卵"算法,以促进种群多样性。
2019-04-12 添加一个简单的眼睛(只有四个感光细胞),自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图:
![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif)
![resut2](result2.gif)
2019-06-13 做了一些重构清理加上了Happy和Pain两个器官分别对应进食奖励和痛苦感后者在靠近边界时激发。观查它的表现痛苦感生效了一些Frog跑到边界后就不再前进而是顺着边界溜下去了但是Happy器官没有生效这也很显然因为Happy属于复杂的进食条件反射链的一部分在没有记忆器官算法引入之前再怎么优胜劣汰也是没办法用上进食奖励信号的。见下图
![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif)
2019-06-26 找食效率太低又改回到4.12的用连接数量代替权值这个逻辑人为设计的算法居然比不过随机连接。Pain器官的加入没有提高找食效率必须与感光细胞合用才能知道是哪个边界急需引入记忆功能。
@ -71,11 +71,11 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
另外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)
![3d-model](3d-model.gif)
这个模型的最顶层表示眼睛的感光细胞(或任意输入输出细胞),同时也是思维区,红色表示一个长条的图形,兰色表示一个三角图形,如果这两个图形经常有规律地同时出现,就会把它们共有的节点撑大,见紫色的节点,当红色图形单独出现,就会强烈激活紫色节点,然后紫色节点的信号反向传播,就会激活三角图形,反之亦然。这就同时解释了模式识别和记忆(或者说回忆)功能的的原理。一个节点可以被多个感光细胞共享,所以它的存储能力是很强的。而且可能这个原理比较符合生物脑结构。当然,实际编程时,虚拟神经元不一定要排成正立方三角,而可能通过胡乱排放,大致上过得去就行了,也许能乱拳打死老师傅,最终要靠电脑自动随机的排放,然后用优胜劣汰来筛选。目前有个难点是这个记忆功能在思维区成像是如何有条不紊地大体上按串行进行工作的,这个问题先放一放。
2019-08-04 更新了一个分组测试功能,如果测试青蛙数量太多,可以分批来测试,每轮测试最少的青蛙数量可以少到只有一个,这是用时间来换空间。
2019-08-05 有了分组测试功能后,顺手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试大约跑90多轮半个小时(电脑慢)后,出现了下面的画面:
![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif)
![result5](result5_seesaw.gif)
这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,青蛙只会找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛)但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本今后这个项目将沉寂一段较长时间我将致力于将青蛙脑重构为3D金字塔形脑结构(见上文)因为这个项目的缺点已经很明显它不具备对2维图像的模式识别能力用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。
青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上器官的用进废退、奖励信号的利用都没反映但我认为这些还不关键目前最急迫的任务应该是先进行3D脑结构建模让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式完全不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。
2019-09-09 开始3D脑的构建任务又回到原点找食从静止的青蛙要能进化到吃光所有食物。目前只是搭建空的3D框架还未涉及3D脑模型编程。新的工作存放在core3d目录原有的旧core目录保留相应地批处理文件也分为普通版run.bat和3d版run3d.bat,蛋文件也分为普通版eggs.ser和3d版eggs3d.ser。
@ -88,7 +88,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
2019-11-16 模式识别功能更新
上次提交有个大bug有多个字母出现时将不能区分这次提交更正过来。到此为止基本完成了模式识别的原理验证过程即如果字母的象素点与训练图片的重点合越多则听力区收到的反向红色光子数就越多这是一个简单、直观的模式识别方法以后可以通过将声音分成多个小区编码并统计每个区收到多少反向的光子总数来判断是哪个字母图像输入。原理验证比较枯燥但这个模式识别功能是无法绕过去的一旦原理被证实以后就可以有意地引导或者说设计青蛙向这个方向进化而不是由手工来搭建包含模式识别功能的脑模型因为一来要减少手工的干预,硬编码越少越好,尽量利用随机变异、生存竟争这个电脑工具,二来这个原理不光是模式识别要用到,其它信号处理(如快感、痛觉信号与行为信号之间的关联)都要用到类似的细胞级逻辑,因为我一直在强调“任意两个时间上相关的信号,大脑总会将它们关联起来,这是条件反射行为建立的基础”。
另外,这次更新加强了暂停功能,可以在脑图任一时刻暂停,并加上了脑图的剖面显示。所有脑图快捷键有: T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标操作:缩放旋转平移
![result6](https://gitee.com/drinkjava2/frog/raw/master/result6_letter.gif)
![result6](result6_letter.gif)
2019-11-26 优化了一下程序,用"对酒当歌人生几何"8个汉字来进行模式识别原理演示但容错性依然没有变形、变位后的文字识别率很差。以后要考虑借签算法中的侧抑制、卷积、分层等原理来提高它的容错性用图形化模拟的方式来实现。总体上算法和图形化模拟是两条路算法通常可以用模拟的方式来表达但不是所有模拟都可以归纳成算法因为模拟(或者说软件本身)有时会非常复杂,不容易总结出规律。也就是说模拟的表现力比算法更强,但模拟的缺点是资源消耗大。
2019-12-27 开始设立history目录给主要的版本直接在history目录下创建副本以方便运行。在history\003a_legs目录下依然是2维脑)尝试给青蛙加两条腿看它能不能自动学会走路。一条腿位于下方负责左右移动一条腿位于右侧负责上下移动每条腿有抬腿、落腿、转动和相应的感觉细胞。只有当腿落下且转动而且另一条脚抬起来时青蛙才会位移具体什么时候抬腿、什么时候转动腿完全由随机数决定。经过一段时间的生存汰淘之后青蛙会进化出会利用两条腿走路了但需要的时间非常长约几个小时之后才达到最高吃食率50%左右,走路风格也比较诡异,是小碎步而不是大踏步。但至少这是青蛙第一次利用两条腿来走路,还是有点意义的,这证明生命进化中就算神经元随机排布,进化出眼睛和腿也是非常简单自然的事。
2020-05-04 在进行3维脑改造过程中发现找食率很低发现自己也看不懂以前的程序怎么编的了所以在history目录下又添加一个003b_simple目录把2维脑简化一下去掉不重要的器官好仔细分析它的逻辑。

View File

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

View File

@ -4,9 +4,12 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.ButtonGroup;
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;
@ -37,6 +40,7 @@ public class Application {
public static BrainPicture brainPic = new BrainPicture(Env.ENV_WIDTH + 5, 0, Env.FROG_BRAIN_XSIZE,
Env.FROG_BRAIN_DISP_WIDTH);
public static ActionListener pauseAction;
public static boolean selectFrog = true;
static private void checkIfShowBrainPicture(JButton button) {
if (Env.SHOW_FIRST_FROG_BRAIN) {
@ -63,13 +67,26 @@ public class Application {
int buttonWidth = 100;
int buttonHeight = 22;
int buttonXpos = Env.ENV_WIDTH / 2 - buttonWidth / 2;
button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight);
// select frog or snake 显示青蛙或蛇的脑图
JRadioButton radioFrog = new JRadioButton("Frog");
radioFrog.setBounds(buttonXpos + buttonWidth + 10, Env.ENV_HEIGHT + 8, 50, buttonHeight);
radioFrog.addActionListener(e -> selectFrog = radioFrog.isSelected());
JRadioButton radioSnake = new JRadioButton("Snake");
button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight);
ActionListener al = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Env.SHOW_FIRST_FROG_BRAIN = !Env.SHOW_FIRST_FROG_BRAIN;
checkIfShowBrainPicture(button);
if (Env.SHOW_FIRST_FROG_BRAIN && Env.SNAKE_MODE) {
radioFrog.setVisible(true);
radioSnake.setVisible(true);
} else {
radioFrog.setVisible(false);
radioSnake.setVisible(false);
}
}
};
@ -77,6 +94,15 @@ public class Application {
button.addActionListener(al);
mainFrame.add(button);
radioSnake.setBounds(buttonXpos + buttonWidth + 60, Env.ENV_HEIGHT + 8, 80, buttonHeight);
radioSnake.addActionListener(e -> selectFrog = radioFrog.isSelected());
ButtonGroup btnGroup = new ButtonGroup();
btnGroup.add(radioFrog);
btnGroup.add(radioSnake);
radioFrog.setSelected(true);
mainFrame.add(radioFrog);
mainFrame.add(radioSnake);
JButton stopButton = new JButton("Pause");// 按钮暂停或继续
stopButton.setBounds(buttonXpos, Env.ENV_HEIGHT + 35, buttonWidth, buttonHeight);
pauseAction = new ActionListener() {
@ -109,6 +135,21 @@ public class Application {
label.setBounds(buttonXpos - 90, stopButton.getY() + 23, 100, buttonHeight);
mainFrame.add(label);
JCheckBox snakeModeCkBox = new JCheckBox("Snake Mode");
snakeModeCkBox.setBounds(buttonXpos, speedSlider.getY() + 25, 120, buttonHeight);
snakeModeCkBox.addActionListener(e -> {
Env.SNAKE_MODE = snakeModeCkBox.isSelected();
if (Env.SHOW_FIRST_FROG_BRAIN && Env.SNAKE_MODE) {
radioFrog.setVisible(true);
radioSnake.setVisible(true);
} else {
radioFrog.setVisible(false);
radioSnake.setVisible(false);
}
});
snakeModeCkBox.setSelected(true);
mainFrame.add(snakeModeCkBox);
mainFrame.setVisible(true);
env.run();
}

View File

@ -10,10 +10,12 @@ import java.util.List;
import javax.swing.JPanel;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.egg.EggTool;
import com.github.drinkjava2.frog.egg.FrogEggTool;
import com.github.drinkjava2.frog.egg.SnakeEggTool;
import com.github.drinkjava2.frog.objects.EnvObject;
import com.github.drinkjava2.frog.objects.Food;
import com.github.drinkjava2.frog.objects.Material;
import com.github.drinkjava2.frog.snake.Snake;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -28,15 +30,15 @@ public class Env extends JPanel {
public static int SHOW_SPEED = 10; // 测试速度-1000~1000,可调, 数值越小速度越慢
/** Delete eggs at beginning of each run */
public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的
public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除保存的青蛙
public static final int EGG_QTY = 25; // 每轮下n个可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_EGG_QTY = 25; // 每轮下n个青蛙可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 4; // 每个蛋可以孵出几个青蛙
public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
public static final int SCREEN = 1; // 分几屏测完
public static final int FROG_PER_SCREEN = EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙这个数值由上面三个参数计算得来
public static final int FROG_PER_SCREEN = FROG_EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙这个数值由上面三个参数计算得来
/** Frog's brain size is a 3D array of Cell */ // 脑空间是个三维Cell数组为节约内存仅在用到数组元素时才去初始化这维按需分配内存
public static final int FROG_BRAIN_XSIZE = 1000; // frog的脑在X方向长度
@ -63,24 +65,42 @@ public class Env extends JPanel {
public static int step;// 当前测试步数
public static final int FOOD_QTY = 1500; // 食物数量, 可调
public static boolean FOOD_CAN_MOVE = false; // 食物是否可以移动眼花
// 以下是程序内部变量不要手工修改它们
public static boolean pause = false; // 暂停按钮按下将暂停测试
public static byte[][] bricks = new byte[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料见Material.java
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> eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋每个蛋可能生成几个青蛙
public static List<Egg> frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋每个蛋可能生成几个青蛙
public static EnvObject[] things = new EnvObject[] { new Food() };// 所有外界物体如食物字母测试工具都放在这个things里面
// =========以下是与蛇相关的常量和变量===========
public static final boolean DELETE_SNAKE_EGGS = true;// 每次运行是否先删除保存的蛇蛋
public static boolean SNAKE_MODE = true; // 是否加小蛇加进来吃青蛙?
public static final int SNAKE_EGG_QTY = 10; // 每轮下n个蛇蛋可调只有最优秀的前n个蛇们才允许下蛋
public static final int SNAKE_PER_EGG = 4; // 每个蛇蛋可以孵出几个蛇
public static final int SNAKE_PER_SCREEN = SNAKE_EGG_QTY * SNAKE_PER_EGG / SCREEN; // 每屏上显示几个蛇这个数值由上面参数计算得来
public static List<Snake> snakes = new ArrayList<>(); // 这里存放所有待测的蛇可能分几次测完由FROG_PER_SCREEN大小来决定
public static List<Egg> snake_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋每个蛋可能生成几个蛇
static {
System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒见码云issue#IW4H8
System.out.println("脑图快捷键: T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移");
if (DELETE_EGGS)
EggTool.deleteEggs();
if (DELETE_FROG_EGGS)
FrogEggTool.deleteEggs();
if (DELETE_SNAKE_EGGS)
SnakeEggTool.deleteEggs();
}
public Env() {
@ -105,41 +125,79 @@ public class Env extends JPanel {
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] >= Material.VISIBLE;
}
public static boolean foundFrog(int x, int y) {// TODO:优化寻找青蛙的速度不要用循环 如果指定点看到青蛙或超出边界返回true
if (x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT)
return true;
for (Frog f : frogs)
if (f.alive && f.x == x && f.y == y) {
return true;
}
return false;
}
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物将其清0返回true
if (insideEnv(x, y) && Env.bricks[x][y] == Material.FOOD) {
if (insideEnv(x, y) && Env.bricks[x][y] >= Material.FOOD && Env.bricks[x][y] <= Material.FLY4) {
Food.food_ated++;
bricks[x][y] = 0;
return true;
}
return false;
}
private void rebuildFrogs() {
public static boolean foundAndAteFrog(int x, int y) {// TODO:优化寻找青蛙的速度不要用循环 如果x,y有青蛙将其杀死返回true
for (Frog f : frogs)
if (f.alive && f.x == x && f.y == y) {
f.alive = false;
return true;
}
return false;
}
private void rebuildFrogs() {// 根据蛙蛋重新孵化出蛙
frogs.clear();
for (int i = 0; i < eggs.size(); i++) {// 创建青蛙每个蛋生成n个蛙并随机取一个别的蛋作为精子
for (int i = 0; i < frog_eggs.size(); i++) {// 创建青蛙每个蛋生成n个蛙并随机取一个别的蛋作为精子
int loop = FROG_PER_EGG;
if (eggs.size() > 20) { // 如果数量多进行一些优化让排名靠前的Egg多孵出青蛙
if (frog_eggs.size() > 20) { // 如果数量多进行一些优化让排名靠前的Egg多孵出青蛙
if (i < FROG_PER_EGG)// 0,1,2,3
loop = FROG_PER_EGG + 1;
if (i >= (eggs.size() - FROG_PER_EGG))
if (i >= (frog_eggs.size() - FROG_PER_EGG))
loop = FROG_PER_EGG - 1;
}
for (int j = 0; j < loop; j++) {
Egg zygote = new Egg(eggs.get(i), eggs.get(RandomUtils.nextInt(eggs.size())));
Egg zygote = new Egg(frog_eggs.get(i), frog_eggs.get(RandomUtils.nextInt(frog_eggs.size())));
frogs.add(new Frog(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote));
}
}
}
private void rebuildSnakes() {// 根据蛇蛋重新孵化出蛇
snakes.clear();
for (int i = 0; i < snake_eggs.size(); i++) {// 创建蛇每个蛋生成n个蛇并随机取一个别的蛋作为精子
int loop = SNAKE_PER_EGG;
if (snake_eggs.size() > 20) { // 如果数量多进行一些优化让排名靠前的Egg多孵出青蛙
if (i < SNAKE_PER_EGG)// 0,1,2,3
loop = SNAKE_PER_EGG + 1;
if (i >= (snake_eggs.size() - SNAKE_PER_EGG))
loop = SNAKE_PER_EGG - 1;
}
for (int j = 0; j < loop; j++) {
Egg zygote = new Egg(snake_eggs.get(i), snake_eggs.get(RandomUtils.nextInt(snake_eggs.size())));
snakes.add(new Snake(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote));
}
}
}
private void drawWorld(Graphics g) {
byte brick;
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)
g.fillRoundRect(x, y, 4, 4, 2, 2); // show food bigger
else
if (brick >= Material.FOOD && brick <= Material.FLY4) {
g.fillRoundRect(x, y, 4, 4, 2, 2); // 点模式 食物只有一个点太小画大一点
// g.drawString(String.valueOf(brick - Material.FOOD), x, y); // 数字雨模式
} else
g.drawLine(x, y, x, y); // only 1 point
}
}
@ -151,23 +209,13 @@ public class Env extends JPanel {
format100.setMaximumFractionDigits(2);
}
private static int foodFoundAmount() {// 统计找食数等
int leftfood = 0;
for (int x = 0; x < ENV_WIDTH; x++)
for (int y = 0; y < ENV_HEIGHT; y++)
if (bricks[x][y] == Material.FOOD)
leftfood++;
return FOOD_QTY - leftfood;
}
private String foodFoundCountText() {// 统计找食数等
int foodFound = foodFoundAmount();
int maxFound = 0;
for (Frog f : frogs)
if (f.ateFood > maxFound)
maxFound = f.ateFood;
return new StringBuilder("找食率:").append(format100.format(foodFound * 1.00 / FOOD_QTY)).append(", 平均: ")
.append(foodFound * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString();
return new StringBuilder("找食率:").append(format100.format(Food.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ")
.append(Food.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString();
}
public static void checkIfPause(Frog f) {
@ -190,24 +238,37 @@ public class Env extends JPanel {
}
public void run() {
EggTool.loadEggs(); // 从磁盘加载egg或新建一批egg
FrogEggTool.loadFrogEggs(); // 从磁盘加载蛙egg或新建一批egg
if (SNAKE_MODE)
SnakeEggTool.loadSnakeEggs(); // 从磁盘加载蛇egg或新建一批egg
Image buffImg = createImage(this.getWidth(), this.getHeight());
Graphics g = buffImg.getGraphics();
long time0;// 计时用
int round = 1;
do {
rebuildFrogs();
if (SNAKE_MODE)
rebuildSnakes();
for (int screen = 0; screen < SCREEN; screen++) {// 分屏测试每屏FROG_PER_SCREEN个蛙
time0 = System.currentTimeMillis();
for (EnvObject thing : things) // 创建食物陷阱等物体
thing.build();
boolean allDead = false;
Frog firstFrog = frogs.get(screen * FROG_PER_SCREEN);
Snake firstSnake = null;
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
f.initFrog(); // 初始化器官延迟到这一步是因为脑细胞太占内存而且当前屏测完后会清空
}
if (SNAKE_MODE && !snakes.isEmpty()) {
firstSnake = snakes.get(screen * SNAKE_PER_SCREEN);
for (int j = 0; j < SNAKE_PER_SCREEN; j++) {
Snake s = snakes.get(screen * SNAKE_PER_SCREEN + j);
s.initFrog(); // 初始化器官延迟到这一步是因为脑细胞太占内存而且当前屏测完后会清空
}
}
Frog showFrog = Application.selectFrog ? firstFrog : firstSnake;
for (step = 0; step < STEPS_PER_ROUND; step++) {
for (EnvObject thing : things)// 调用食物陷阱等物体的动作
thing.active(screen);
@ -219,36 +280,46 @@ public class Env extends JPanel {
if (f.active(this))// 调用青蛙的Active方法并返回是否还活着
allDead = false;
}
if (SNAKE_MODE && !snakes.isEmpty())
for (int j = 0; j < SNAKE_PER_SCREEN; j++) {
Snake s = snakes.get(screen * SNAKE_PER_SCREEN + j);
s.active(this);// snake唯一作用就是吃小蛇
}
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用画青蛙的方式来拖慢速度
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 是否跳帧画图的方式来控制速度
continue;
if (SHOW_SPEED < 0) // 如果speed小于0人为加入延迟
sleep(-SHOW_SPEED);
// 开始画青蛙
// 开始画虚拟环境和青蛙和蛇
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境
g.setColor(Color.BLACK);
drawWorld(g);
for (int j = 0; j < FROG_PER_SCREEN; j++) {
drawWorld(g);// 画整个虚拟环境
for (int j = 0; j < FROG_PER_SCREEN; j++) { // 显示青蛙
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
f.show(g);
}
if (firstFrog.alive) { // 开始显示第一个Frog的动态脑图
if (SHOW_FIRST_FROG_BRAIN) {
g.setColor(Color.red);
g.drawArc(firstFrog.x - 15, firstFrog.y - 15, 30, 30, 0, 360);
g.setColor(Color.BLACK);
if (SNAKE_MODE && !snakes.isEmpty())
for (int j = 0; j < SNAKE_PER_SCREEN; j++) { // 显示蛇
Snake s = snakes.get(screen * SNAKE_PER_SCREEN + j);
s.show(g);
}
if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0)
Application.brainPic.drawBrainPicture(firstFrog);
if (SHOW_FIRST_FROG_BRAIN && showFrog != null) {
g.setColor(Color.red);
g.drawArc(showFrog.x - 15, showFrog.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(showFrog);
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
}
Application.brainPic.drawBrainPicture(firstFrog);
// System.out.println(showFrog.debugInfo());// 打印输出Frog调试内容
if (SHOW_FIRST_FROG_BRAIN)
Application.brainPic.drawBrainPicture(showFrog);
checkIfPause(firstFrog);
for (int j = 0; j < FROG_PER_SCREEN; j++) {
Frog f = frogs.get(screen * FROG_PER_SCREEN + j);
@ -262,7 +333,13 @@ public class Env extends JPanel {
thing.destory();
}
round++;
EggTool.layEggs();
FrogEggTool.layEggs();
if (SNAKE_MODE) {
if (snakes.isEmpty())
SnakeEggTool.loadSnakeEggs();
else
SnakeEggTool.layEggs();
}
} while (true);
}

View File

@ -74,8 +74,9 @@ public class Frog {// 这个程序大量用到public变量而不是getter/setter
public void addRandomLines() {// 有一定机率在器官间生成随机的神经连线
if (alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官
Line line = new Line();
organs.add(line);
line.initilized = false;
line.initFrog(this);
organs.add(line);
}
}
@ -93,7 +94,7 @@ public class Frog {// 这个程序大量用到public变量而不是getter/setter
// 依次调用每个cell的active方法这是写在organ类里的方法因为同一个器官的cell具有相同的行为
for (Cell cell : cells)
cell.organ.active(this, cell);
addRandomLines();
addRandomLines(); // 随机添加神经连线, 这是一个硬编码, 目前一个连线对应一个器官待改进
return alive;
}
@ -117,4 +118,21 @@ public class Frog {// 这个程序大量用到public变量而不是getter/setter
|| z >= Env.FROG_BRAIN_ZSIZE;
}
/** Print debug info */
public String debugInfo() {// 输出Frog调试内容
StringBuilder sb = new StringBuilder();
for (int i = 0; i < organs.size(); i++) {
Organ o = organs.get(i);
if (o != null) {
sb.append("organ(" + i + ")=" + o.getClass()).append("\r");
if (Line.class.equals(o.getClass())) {
Line l = (Line) o;
sb.append(l.inputZone.debugInfo()).append("\r");
sb.append(l.outputZone.debugInfo()).append("\r");
}
}
}
return sb.toString();
}
}

View File

@ -313,10 +313,8 @@ public class BrainPicture extends JPanel {
private static Cuboid brain = new Cuboid(0, 0, 0, Env.FROG_BRAIN_XSIZE, Env.FROG_BRAIN_YSIZE, Env.FROG_BRAIN_ZSIZE);
public void drawBrainPicture(Frog f) {// 在这个方法里进行青蛙三维脑结构的绘制
if (!f.alive)
return;
if (!Env.SHOW_FIRST_FROG_BRAIN)
public void drawBrainPicture(Frog f) {// 在这个方法里进行青蛙或蛇的三维脑结构的绘制,蛇是青蛙的子类所以也可以当参数传进来
if (!Env.SHOW_FIRST_FROG_BRAIN || f == null || !f.alive)
return;
g.setColor(WHITE);// 先清空旧图
g.fillRect(0, 0, brainDispWidth, brainDispWidth);

View File

@ -94,7 +94,7 @@ public class Organ extends Zone {
try {
newOrgan = this.getClass().newInstance();
} catch (Exception e) {
throw new UnknownError("Can not make new Organ copy for " + this);
throw new UnknownError("Can not make new organ copy for " + this);
}
copyXYZR(this, newOrgan);
newOrgan.name = this.name;

View File

@ -58,6 +58,13 @@ public class Zone implements Serializable { // zone 代表脑空间中的一块
this.r = z.r;
}
public Zone(Zone a, Zone b) {// 用两个Zone来构造新的zone位于两个zone的中间
this.x = (a.x + b.x) / 2;
this.y = (a.y + b.y) / 2;
this.z = (a.z + b.z) / 2 ;
this.r = (a.r + b.r) / 2;
}
public boolean nearby(Zone o) {
if (o == null)
return false;
@ -97,4 +104,8 @@ public class Zone implements Serializable { // zone 代表脑空间中的一块
this.r = r;
}
public String debugInfo() {
return new StringBuilder().append("zone x=").append(x).append(", y=").append(y).append(", z=").append(z)
.append(", r=").append(r).toString();
}
}

View File

@ -22,16 +22,17 @@ import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Line
*
* 这是一个随机方式连接两端的Organ它是从旧版的RandomConnectGroup改造过来这是一种最简单的神经元排列方式
* 这是一个随机方式连接两端的Organ它是从旧版的RandomConnectGroup改造过来这是一种最简单的神经元排列方式
*
* @author Yong Zhu
* @since 1.0
*/
public class Line extends Organ {
public class Line extends Organ {
private static final long serialVersionUID = 1L;
public Zone inputZone; // 输入触突区
public Zone outputZone; // 输出触突区
public Zone bodyZone; // 输出触突区
@Override
public boolean allowBorrow() { // 是否允许在精子中将这个器官借出
@ -41,18 +42,38 @@ public class Line extends Organ {
@Override
public void initFrog(Frog f) {
if (!initilized) {
initilized = true;
inputZone= RandomUtils.randomZoneInOrgans(f);
initilized = true;
inputZone = RandomUtils.randomZoneInOrgans(f);
outputZone = RandomUtils.randomZoneInOrgans(f);
}
bodyZone = new Zone(inputZone, outputZone);
}
this.fat = 0;// 每次fat清0因为遗传下来的fat不为0
Cell c=new Cell();
c.input= inputZone;
c.output=outputZone;
c.organ=this;
Cell c = new Cell();
c.input = inputZone;
c.output = outputZone;
c.body = bodyZone;
c.organ = this;
f.cells.add(c);
}
/** Line如果input是另一个line的body吸收能量 Line如果output是另一个line的body,放出能量 */
public void active(Frog f, Cell c) {
if (RandomUtils.percent(95)) //这个会严重影响速度所以降低它的机率
return;
for (Cell cell : f.cells) {
if (cell.energy > organActiveEnergy)
if (c.input.nearby(cell.body)) {
c.organ.fat++;
cell.energy -= organActiveEnergy;
c.energy += organActiveEnergy;
}
if (c.energy >= organOutputEnergy && c.output.nearby(cell.body)) {
c.energy -= organOutputEnergy;
cell.energy += organOutputEnergy;
}
}
}
@Override
public Organ[] vary() {
organOutputEnergy = RandomUtils.varyInLimit(organOutputEnergy, -3, 3);
@ -71,9 +92,10 @@ public class Line extends Organ {
else if (organOutputEnergy <= 0)
pic.setPicColor(Color.BLUE);
else
pic.setPicColor(Color.red); // 用到了?红色
pic.drawLine(inputZone, outputZone);
pic.drawZone(this);
pic.setPicColor(Color.red); // 用到了?红色
pic.drawLine(inputZone, bodyZone);
pic.drawLine(bodyZone, outputZone);
pic.drawZone(bodyZone);
pic.setPicColor(Color.red);
}

View File

@ -15,9 +15,9 @@ import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
/**
* Eat food at current x, y position
* Mouth eat food at current x, y position
*/
public class Eat extends Organ {// Eat这个类将食物转化为能量能量小于0则青蛙死掉
public class Mouth extends Organ {// Mouth这个类将食物转化为能量能量小于0则青蛙死掉
private static final long serialVersionUID = 1L;
@Override

View File

@ -16,16 +16,6 @@ import java.util.List;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.organ.Active;
import com.github.drinkjava2.frog.brain.organ.Eat;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeDown;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeLeft;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeRight;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeUp;
import com.github.drinkjava2.frog.brain.organ.MoveDown;
import com.github.drinkjava2.frog.brain.organ.MoveLeft;
import com.github.drinkjava2.frog.brain.organ.MoveRight;
import com.github.drinkjava2.frog.brain.organ.MoveUp;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -41,24 +31,9 @@ import com.github.drinkjava2.frog.util.RandomUtils;
public class Egg implements Serializable {
private static final long serialVersionUID = 1L;
public static int FIXED_ORGAN_QTY = 9;
public List<Organ> organs = new ArrayList<>();// NOSONAR
public Egg() {// 无中生有创建一个蛋先有蛋后有蛙
organs.add(new MoveUp().setXYZRN(800, 100, 500, 60, "Up"));
organs.add(new MoveDown().setXYZRN(800, 400, 500, 60, "Down"));
organs.add(new MoveLeft().setXYZRN(700, 250, 500, 60, "Left"));
organs.add(new MoveRight().setXYZRN(900, 250, 500, 60, "Right"));
organs.add(new SeeUp().setXYZRN(200, 300 + 90, 500, 40, "SeeUp"));
organs.add(new SeeDown().setXYZRN(200, 300 - 90, 500, 40, "SeeDown"));
organs.add(new SeeLeft().setXYZRN(200 - 90, 300, 500, 40, "SeeLeft"));
organs.add(new SeeRight().setXYZRN(200 + 90, 300, 500, 40, "SeeRight"));
organs.add(new Active().setXYZRN(500, 600, 500, 40, "Active")); // 永远激活
// 以上数量就是FIXED_ORGAN_QTY值
organs.add(new Eat().setXYZRN(0, 0, 0, 0, null)); // EAT不是感觉或输出器官没有位置和大小
public Egg() {// 无中生有创建一个蛋先有蛋后有蛙
}
/** Create egg from frog */

View File

@ -22,7 +22,17 @@ 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.util.FrogFileUtils;
import com.github.drinkjava2.frog.brain.organ.Active;
import com.github.drinkjava2.frog.brain.organ.Mouth;
import com.github.drinkjava2.frog.brain.organ.MoveDown;
import com.github.drinkjava2.frog.brain.organ.MoveLeft;
import com.github.drinkjava2.frog.brain.organ.MoveRight;
import com.github.drinkjava2.frog.brain.organ.MoveUp;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeDown;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeLeft;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeRight;
import com.github.drinkjava2.frog.brain.organ.Eyes.SeeUp;
import com.github.drinkjava2.frog.util.LocalFileUtils;
/**
* EggTool save eggs to disk
@ -30,7 +40,7 @@ import com.github.drinkjava2.frog.util.FrogFileUtils;
* @author Yong Zhu
* @since 1.0
*/
public class EggTool {
public class FrogEggTool {
/**
* Frogs which have higher energy lay eggs
@ -39,25 +49,22 @@ public class EggTool {
* 用能量的多少来简化生存竟争模拟每次下蛋数量固定为EGG_QTY个
*/
public static void layEggs() {
sortFrogsOrderByEnergyDesc();
// for (Frog frog : Env.frogs) {
// Lines LINES=(Lines) frog.organs.get(10);
// System.out.println(frog.energy+":"+LINES.lines[0]);
// }
Frog first = Env.frogs.get(0);
Frog last = Env.frogs.get(Env.frogs.size() - 1);
try {
Env.eggs.clear();
for (int i = 0; i < Env.EGG_QTY; i++)
Env.eggs.add(new Egg(Env.frogs.get(i)));
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser");
Env.frog_eggs.clear();
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(Env.eggs);
so.writeObject(Env.frog_eggs);
so.close();
System.out.print("Fist frog has " + first.organs.size() + " organs, energy=" + first.energy);
System.out.println(", Last frog has " + last.organs.size() + " organs, energy=" + last.energy);
System.out.println("Saved " + Env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser'");
System.out.println(
"Saved " + Env.frog_eggs.size() + " eggs to file '" + Application.CLASSPATH + "frog_eggs.ser'");
} catch (IOException e) {
System.out.println(e);
}
@ -77,32 +84,45 @@ public class EggTool {
}
public static void deleteEggs() {
System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "eggs.ser'");
FrogFileUtils.deleteFile(Application.CLASSPATH + "eggs.ser");
System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "frog_eggs.ser'");
LocalFileUtils.deleteFile(Application.CLASSPATH + "frog_eggs.ser");
}
/**
* 从磁盘读入一批Egg
* 从磁盘读入一批frog Egg
*/
@SuppressWarnings("unchecked")
public static void loadEggs() {
public static void loadFrogEggs() {
boolean errorfound = false;
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "eggs.ser");
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "frog_eggs.ser");
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
Env.eggs = (List<Egg>) eggsInputStream.readObject();
System.out.println(
"Loaded " + Env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.ser" + "'.\n");
Env.frog_eggs = (List<Egg>) eggsInputStream.readObject();
System.out.println("Loaded " + Env.frog_eggs.size() + " eggs from file '" + Application.CLASSPATH
+ "frog_eggs.ser" + "'.\n");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
}
if (errorfound) {
Env.eggs.clear();
for (int j = 0; j < Env.EGG_QTY; j++)
Env.eggs.add(new Egg());
System.out.println("Fail to load egg file at path '" + Application.CLASSPATH + "', created "
+ Env.eggs.size() + " eggs to do test.\n");
Env.frog_eggs.clear();
for (int j = 0; j < Env.FROG_EGG_QTY; j++) {
Egg egg = new Egg();
float r = 40;
egg.organs.add(new Mouth().setXYZRN(0, 0, 0, 0, "Eat")); // Mouth不是感觉或输出器官没有位置和大小
egg.organs.add(new Active().setXYZRN(500, 600, 500, r, "Active")); // 永远激活
egg.organs.add(new MoveUp().setXYZRN(800, 100, 500, r, "Up"));
egg.organs.add(new MoveDown().setXYZRN(800, 400, 500, r, "Down"));
egg.organs.add(new MoveLeft().setXYZRN(700, 250, 500, r, "Left"));
egg.organs.add(new MoveRight().setXYZRN(900, 250, 500, r, "Right"));
egg.organs.add(new SeeUp().setXYZRN(200, 300 + 90, 500, r, "SeeUp"));
egg.organs.add(new SeeDown().setXYZRN(200, 300 - 90, 500, r, "SeeDown"));
egg.organs.add(new SeeLeft().setXYZRN(200 - 90, 300, 500, r, "SeeLeft"));
egg.organs.add(new SeeRight().setXYZRN(200 + 90, 300, 500, r, "SeeRight"));
Env.frog_eggs.add(egg);
}
System.out.println("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,128 @@
/*
* 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.github.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.Collections;
import java.util.Comparator;
import java.util.List;
import com.github.drinkjava2.frog.Application;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.brain.organ.Active;
import com.github.drinkjava2.frog.brain.organ.MoveDown;
import com.github.drinkjava2.frog.brain.organ.MoveLeft;
import com.github.drinkjava2.frog.brain.organ.MoveRight;
import com.github.drinkjava2.frog.brain.organ.MoveUp;
import com.github.drinkjava2.frog.snake.Snake;
import com.github.drinkjava2.frog.snake.brain.organ.SnakeEyes;
import com.github.drinkjava2.frog.snake.brain.organ.SnakeMouth;
import com.github.drinkjava2.frog.util.LocalFileUtils;
/**
* EggTool save eggs to disk
*
* @author Yong Zhu
* @since 1.0
*/
public class SnakeEggTool {
/**
* Snakes which have higher energy lay eggs
*
* 利用Java串行机制存盘 能量多(也就是吃的更多)的Snake下蛋并存盘, 以进行下一轮测试能量少的Snake被淘汰没有下蛋的资格
* 用能量的多少来简化生存竟争模拟每次下蛋数量固定为EGG_QTY个
*/
public static void layEggs() {
if (!Env.SNAKE_MODE)
return;
sortSnakesOrderByEnergyDesc();
Snake first = Env.snakes.get(0);
Snake last = Env.snakes.get(Env.snakes.size() - 1);
try {
Env.snake_eggs.clear();
for (int i = 0; i < Env.SNAKE_EGG_QTY; i++)
Env.snake_eggs.add(new Egg(Env.snakes.get(i)));
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "snake_eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(Env.snake_eggs);
so.close();
System.out.print("Fist snake has " + first.organs.size() + " organs, energy=" + first.energy);
System.out.println(", Last snake has " + last.organs.size() + " organs, energy=" + last.energy);
System.out.println(
"Saved " + Env.snake_eggs.size() + " eggs to file '" + Application.CLASSPATH + "snake_eggs.ser'");
} catch (IOException e) {
System.out.println(e);
}
}
private static void sortSnakesOrderByEnergyDesc() {// 按能量多少给青蛙排序
Collections.sort(Env.snakes, new Comparator<Snake>() {
public int compare(Snake a, Snake b) {
if (a.energy > b.energy)
return -1;
else if (a.energy == b.energy)
return 0;
else
return 1;
}
});
}
public static void deleteEggs() {
System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "snake_eggs.ser'");
LocalFileUtils.deleteFile(Application.CLASSPATH + "snake_eggs.ser");
}
/**
* 从磁盘读入一批snake Egg
*/
@SuppressWarnings("unchecked")
public static void loadSnakeEggs() {
boolean errorfound = false;
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "snake_eggs.ser");
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
Env.snake_eggs = (List<Egg>) eggsInputStream.readObject();
System.out.println("Loaded " + Env.snake_eggs.size() + " eggs from file '" + Application.CLASSPATH
+ "snake_eggs.ser" + "'.\n");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
}
if (errorfound) {
Env.snake_eggs.clear();
for (int j = 0; j < Env.SNAKE_EGG_QTY; j++) {
Egg egg = new Egg();
float r = 40;
egg.organs.add(new SnakeMouth().setXYZRN(0, 0, 0, 0, "Eat")); // SnakeMouth不是感觉或输出器官没有位置和大小
egg.organs.add(new Active().setXYZRN(500, 600, 500, 5, "Active")); // 永远激活
egg.organs.add(new MoveUp().setXYZRN(800, 100, 500, r, "Up"));
egg.organs.add(new MoveDown().setXYZRN(800, 400, 500, r, "Down"));
egg.organs.add(new MoveLeft().setXYZRN(700, 250, 500, r, "Left"));
egg.organs.add(new MoveRight().setXYZRN(900, 250, 500, r, "Right"));
egg.organs.add(new SnakeEyes.SeeUp().setXYZRN(200, 300 + 90, 500, r, "SeeUp"));
egg.organs.add(new SnakeEyes.SeeDown().setXYZRN(200, 300 - 90, 500, r, "SeeDown"));
egg.organs.add(new SnakeEyes.SeeLeft().setXYZRN(200 - 90, 300, 500, r, "SeeLeft"));
egg.organs.add(new SnakeEyes.SeeRight().setXYZRN(200 + 90, 300, 500, r, "SeeRight"));
Env.snake_eggs.add(egg);
}
System.out.println("Fail to load snake egg file '" + Application.CLASSPATH + "snake_eggs.ser"
+ "', created " + Env.snake_eggs.size() + " eggs to do test.");
}
}
}

View File

@ -15,6 +15,7 @@ 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.Env;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -24,25 +25,73 @@ import com.github.drinkjava2.frog.util.RandomUtils;
* @since 1.0
*/
public class Food implements EnvObject {
public static int food_ated = 0;
@Override
public void build() {
for (int i = 0; i < FOOD_QTY; i++) // 生成食物
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FOOD;
food_ated = 0;
if (!Env.FOOD_CAN_MOVE) {
for (int i = 0; i < FOOD_QTY; i++) // 生成食物
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FOOD;
return;
}
for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇1
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY1;
for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇2
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY2;
for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇3
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY3;
for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇4
bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY4;
}
@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)
if (bricks[i][j] >= Material.FOOD && bricks[i][j] <= Material.FLY4)
bricks[i][j] = 0;
}
}
@Override
public void active(int screen) {
// Food do not have any active
if (RandomUtils.percent(96))
return;
for (int i = 1; i < ENV_WIDTH; i++) {// 水平移动FLY
for (int j = 1; j < ENV_HEIGHT; j++) {
if (bricks[i][j] == Material.FLY1) {
bricks[i - 1][j] = Material.FLY1;
bricks[i][j] = 0;
}
if (bricks[i][j] == Material.FLY2) {
bricks[i][j - 1] = Material.FLY2;
bricks[i][j] = 0;
}
}
}
for (int i = ENV_WIDTH - 2; i > 0; i--) {// 上下移动FLY
for (int j = ENV_HEIGHT - 2; j > 0; j--) {
if (bricks[i][j] == Material.FLY3) {
bricks[i + 1][j] = Material.FLY3;
bricks[i][j] = 0;
}
if (bricks[i][j] == Material.FLY4) {
bricks[i][j + 1] = Material.FLY4;
bricks[i][j] = 0;
}
}
}
for (int i = 0; i < ENV_WIDTH; i++) {
bricks[i][0] = 0;
bricks[i][ENV_HEIGHT - 1] = 0;
}
for (int i = 0; i < ENV_HEIGHT; i++) {
bricks[0][i] = 0;
bricks[ENV_WIDTH - 1][i] = 0;
}
}
}

View File

@ -15,24 +15,35 @@ import java.awt.Color;
/**
* Material store material types
*
* 用不同的数字常量代表虚拟环境中不同的组成材料0为空小于10的不可见大于20的将杀死在同一位置出现的青蛙,例如砖头和青蛙不可以重叠出现在同一位置
* 用不同的数字常量代表虚拟环境中不同的材料0为空每个材料用整数中的一位表示, 所以一个整数中可以表达15种不同的材料并且这些材料可以同时出现
*
* @author Yong Zhu
* @since 1.0
*/
public class Material {
public static final byte NO = 0; // nothing
public static final byte SEESAW_BASE = 1; // 1~9 is invisible to frog
private static int origin = 1;
public static final byte VISIBLE = 10; // if>=10 will visible to frog
public static final byte FOOD = VISIBLE + 1;
public static final byte SEESAW = VISIBLE + 2;
private static int next() {// 每次将origin左移1位
origin = origin << 1;
if (origin < 0)
throw new RuntimeException("");
return origin;
}
public static final byte KILLFROG = 20; // if>=20 will kill frog
public static final byte BRICK = KILLFROG + 1;// brick will kill frog
public static final byte TRAP = KILLFROG + 2; // trap will kill frog
public static final int NO = 0; // nothing
public static final int VISIBLE = next(); // if visible to frog
public static final int SEESAW = next();
public static final int FOOD = next();
public static final int FLY1 = next();// FLY1苍蝇是一种会移动的Food
public static final int FLY2 = next();// FLY2苍蝇是一种会移动的Food
public static final int FLY3 = next();// FLY3苍蝇是一种会移动的Food
public static final int FLY4 = next();// FLY4苍蝇是一种会移动的Food
public static Color color(byte material) {
public static final int KILLFROG = next(); // if>=KILLFROG will kill frog
public static final int BRICK = next();// brick will kill frog
public static final int TRAP = next(); // trap will kill frog
public static Color color(int material) {
if (material == TRAP)
return Color.LIGHT_GRAY;
else

View File

@ -1,93 +0,0 @@
/* 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 EnvObject {
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() {
// do nothing
}
@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;
}
}

View File

@ -1,52 +0,0 @@
/* 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 trap, frog will die
*
* @author Yong Zhu
* @since 2019-08-05
*/
@SuppressWarnings("all")
public class Trap implements EnvObject {
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) {
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.github.drinkjava2.frog.snake;
import java.awt.Graphics;
import java.awt.Image;
import java.io.FileInputStream;
import javax.imageio.ImageIO;
import com.github.drinkjava2.frog.Application;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.egg.Egg;
/**
* Snake has similar brain like Frog, snake eat frog <br>
* 蛇是青蛙的子类区别是 蛇只能看到青蛙并将其当作一个单个象素点的食物 青蛙能看到真的食物(Food)和蛇
*
* @since 1.0
*/
public class Snake extends Frog {
static Image snakeImg;
static {
try {
snakeImg = ImageIO.read(new FileInputStream(Application.CLASSPATH + "snake.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
public Snake(int x, int y, Egg egg) {
super(x, y, egg);
}
@Override
public void show(Graphics g) {// 显示蛇的图象
if (!alive)
return;
g.drawImage(snakeImg, x - 16, y - 5, 18, 18, null);// 减去坐标保证蛇嘴巴显示在当前x,y处
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.github.drinkjava2.frog.snake.brain.organ;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* SnakeEyes can only see 4 direction's frog
*
* 蛇的眼睛看不到food, 只能看到青蛙也就是说它把青蛙当成食物
*
* @author Yong Zhu
* @since 1.0
*/
public class SnakeEyes {
public static class SeeUp extends Organ {// 只能看到上方青蛙
private static final long serialVersionUID = 1L;
public int seeDistance; // 眼睛能看到的距离
@Override
public void initFrog(Frog f) { // 仅在Snake生成时这个方法会调用一次
if (!initilized) {
initilized = true;
seeDistance = 8;
}
}
@Override
public Organ[] vary() {
seeDistance = RandomUtils.varyInLimit(seeDistance, 5, 20);
if (RandomUtils.percent(5)) { // 可视距离有5%的机率变异
seeDistance = seeDistance + 1 - 2 * RandomUtils.nextInt(2);
if (seeDistance < 1)
seeDistance = 1;
if (seeDistance > 50)
seeDistance = 50;
}
return new Organ[] { this };
}
@Override
public void active(Frog f) {
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x, f.y + i)) {
activeInput(f, 30);
return;
}
}
}
public static class SeeDown extends SeeUp {// 只能看到下方青蛙
private static final long serialVersionUID = 1L;
@Override
public void active(Frog f) {
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x, f.y - i)) {
activeInput(f, 30);
return;
}
}
}
public static class SeeLeft extends SeeUp {// 只能看到左方青蛙
private static final long serialVersionUID = 1L;
@Override
public void active(Frog f) {
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x - i, f.y)) {
activeInput(f, 30);
return;
}
}
}
public static class SeeRight extends SeeUp {// 只能看到右方青蛙
private static final long serialVersionUID = 1L;
@Override
public void active(Frog f) {
for (int i = 1; i < seeDistance; i++)
if (Env.foundAnyThing(f.x + i, f.y)) {
activeInput(f, 30);
return;
}
}
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.github.drinkjava2.frog.snake.brain.organ;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
/**
* SnakeMouth eat frog at current x, y position (snake's mouth postion)
*/
public class SnakeMouth extends Organ {// SnakeMouth这个类将青蛙作为食物转化为能量能量小于0则蛇死掉
private static final long serialVersionUID = 1L;
@Override
public void active(Frog f) {
if (Env.foundAndAteFrog(f.x, f.y)) {
f.ateFood++;
f.energy += 1000;// 如果蛇的坐标与青蛙重合吃掉food能量境加
}
}
}

View File

@ -19,14 +19,14 @@ import java.io.IOException;
import java.io.InputStream;
/**
* File Utilities used in this project
* Local File Utilities used in this project
*
* @author Yong Zhu
* @since 1.0
*/
public class FrogFileUtils {
public class LocalFileUtils {
private FrogFileUtils() {
private LocalFileUtils() {
// default constructor
}

View File

@ -10,16 +10,12 @@
*/
package com.github.drinkjava2.frog.util;
import static com.github.drinkjava2.frog.Env.FROG_BRAIN_XSIZE;
import static com.github.drinkjava2.frog.Env.FROG_BRAIN_YSIZE;
import static com.github.drinkjava2.frog.Env.FROG_BRAIN_ZSIZE;
import java.util.Random;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Cuboid;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.Zone;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.brain.organ.Line;
/**
* Random Utilities used in this project
@ -48,38 +44,19 @@ public class RandomUtils {
public static Zone randomZoneInZone(Zone o) { // 在一个区内随机取一个小小区
return new Zone(o.x - o.r + o.r * 2 * rand.nextFloat(), o.y - o.r + o.r * 2 * rand.nextFloat(),
o.z - o.r + o.r * 2 * rand.nextFloat(), o.r * rand.nextFloat() * .04f);
o.z /*- o.r + o.r * 2 * rand.nextFloat()*/, o.r * rand.nextFloat() * .04f);
}
/** Return a random zone inside of frog's random organ */
public static Zone randomZoneInOrgans(Frog f) {
if (f.organs == null || f.organs.size() == 0)
throw new IllegalArgumentException("Can not call randomPosInRandomOrgan method when frog has no organ");
return randomZoneInZone(f.organs.get(RandomUtils.nextInt(Egg.FIXED_ORGAN_QTY)));
}
/** Randomly create a Cuboid inside of brain space */
public static Cuboid randomCuboid() {// 随机生成一个位于脑空间内的立方体
Cuboid c = new Cuboid();
c.x = nextInt(FROG_BRAIN_XSIZE) - FROG_BRAIN_XSIZE / 4;// 为了多产生贴边的立方体超出边界的被裁切
if (c.x < 0)
c.x = 0;
c.y = nextInt(FROG_BRAIN_YSIZE) - FROG_BRAIN_YSIZE / 4;
if (c.y < 0)
c.y = 0;
c.z = nextInt(FROG_BRAIN_ZSIZE) - FROG_BRAIN_ZSIZE / 4;
if (c.z < 0)
c.z = 0;
c.xe = 1 + nextInt(FROG_BRAIN_XSIZE); // 立方体任一个边长至少是1
if (c.xe > (FROG_BRAIN_XSIZE - c.x))// 超出边界的被裁切
c.xe = FROG_BRAIN_XSIZE - c.x;
c.ye = 1 + nextInt(FROG_BRAIN_YSIZE);
if (c.ye > (FROG_BRAIN_YSIZE - c.y))
c.ye = FROG_BRAIN_YSIZE - c.y;
c.ze = 1 + nextInt(FROG_BRAIN_ZSIZE);
if (c.ze > (FROG_BRAIN_ZSIZE - c.z))
c.ze = FROG_BRAIN_ZSIZE - c.z;
return c;
throw new IllegalArgumentException("Can not call randomPosInRandomOrgan method when has no organ");
Organ o = f.organs.get(1 + RandomUtils.nextInt(f.organs.size() - 1)); // 跳过第一个器官
if (o instanceof Line) {
return randomZoneInZone(((Line) o).bodyZone);
} else {
return randomZoneInZone(o);
}
}
public static int vary(int v, int percet) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
snake.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 B

View File

@ -1,6 +1,6 @@
这个项目的捐款将用于项目本身,如发布开发任务等。设这个捐款记录的目的是为了让收支透明化,万一项目做大了,收到码云平台外的捐款也可以在这里记录下来。本记录按时间顺序记录捐款人和当前总额,不记具体数额,这样即体现了不鼓励金额攀比、自愿随意的原则,也能通过历史记录查询出每笔的具体数额。在此衷心地感谢每一位捐款、点赞、及关注这个项目的同学!
捐款(按时间顺序):
捐款(按时间顺序):
wangtao
dotao
LongFer
@ -16,10 +16,14 @@ Ad
张四峰
这家伙太懒了
miazzy
目前收入总额:309.57元
半城言沙
sunne
CV远程移动师
目前收入总额:339.57元
支出(按时间顺序)
目前支出总额:0元
目前余额309.57元
目前余额339.57元

View File

@ -192,4 +192,7 @@ T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:
重整理了一下目录将当前工作版本放在core目录下, 比较重大的历史版本放在history目录下以方便初学者直接运行各个历史版本而不需要使用git reset命令去手工回到以前的历史版本。同时如果有未完成的子功能研究如模式识别见005_letter_test目录)也可以开一个子目录在history里以后有时间再去慢慢研究这个子功能。
### 2019-12-27 在history\003a_legs目录下尝试给青蛙加两条腿看它能不能自动学会走路。一条腿位于下方一条腿位于右侧每条腿有位置感觉细胞、抬腿、落腿运动和感觉细胞转动腿运动细胞。只有当腿落下且转动时青蛙才会位移。经过一段时间的生存汰淘之后青蛙自动进化出会利用腿走路了但效果不太理想找食效率不高往往只能朝一个方向利用单条腿前进但至少这是青蛙第一次利用腿来走路有兴趣的可以运行试试看。
### 2020-06-03 加入小蛇Snake进来吃青蛙未完成
基本思路是小蛇是有形状的,青蛙要能进化到看到小蛇就跑开,这样就开始正式引入了模式识别