Brain picture

pull/1/head
Yong Zhu 7 years ago
parent 2fac4ae408
commit 3e1eee2901

@ -66,7 +66,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
* EGG_QTY: 每次允许Frog下多少个蛋每个蛋可以孵出4个青蛙。通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一个蛋。
* FOOD_QTY食物的数量食物越多则Frog的生存率就越高能量排名靠前的一批Frog可以下蛋其余的被淘汰。
下面是这个测试的动画截图,有兴趣的可以试着自己运行一下:
![截图](https://gitee.com/drinkjava2/frog/raw/master/result.gif)
![截图](https://gitee.com/drinkjava2/frog/raw/master/result.gif)
另外每步演示的结果(egg)会存盘在根目根目录下名为egg.ser可以删除这个文件以从头开始新的测试。目前万里长征刚踏上第一步因为还没涉及脑模型的搭建。可以看到有些青蛙跑得飞快这是自然选择的结果因为跑在最前面的吃得多。以后会改正这个bug要让最聪明的、会抢食的Frog胜出而不是让跑得快的胜出。
## 版权 | License

@ -4,7 +4,7 @@
<groupId>com.gitee.drinkjava2</groupId>
<artifactId>frog</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<version>1.0.1</version>
<name>frog</name>
<description>An artificial life test project</description>

@ -39,28 +39,29 @@ import com.github.drinkjava2.frog.env.Env;
*/
public class Frog {
/** brain radius virtual unit */
public float brainRadius;
/** brain cells */
List<Cell> cells = new ArrayList<Cell>();
public List<Cell> cells = new ArrayList<Cell>();
/** 视觉细胞的输入区在脑中的坐标,随便取一个区就可以了,以后再考虑进化成两个眼睛 */
public Zone eye = new Zone(50, 250, 50);
/** 饥饿的感收区在脑中的坐标,先随便取就可以了,以后再考虑放到蛋里去进化 */
public Zone hungry = new Zone(200, 50, 50);
/** 视觉细胞的输入区在脑中的坐标,先随便取 在原点附件就可以了,以后再考虑放到蛋里去进化 */
public static Zone eye = new Zone(0, 0, 300);
/** 进食奖励的感收区在脑中的坐标,先随便取就可以了,以后再考虑放到蛋里去进化 */
public Zone happy = new Zone(200, 450, 50);
/** 运动细胞的输入区在脑中的坐标,先随便取就可以了,以后再考虑放到蛋里去进化 */
public static Zone moveUp = new Zone(500, 50, 10);
public static Zone moveDown = new Zone(500, 100, 10);
public static Zone moveLeft = new Zone(500, 150, 10);
public static Zone moveRight = new Zone(500, 200, 10);
public static Zone moveRandom = new Zone(500, 300, 10);
public Zone moveDown = new Zone(500, 100, 10); // 屏幕y坐标是向下的
public Zone moveUp = new Zone(500, 400, 10);
public Zone moveLeft = new Zone(400, 250, 10);
public Zone moveRight = new Zone(600, 250, 10);
public int x;
public int y;
public long energy = 10000;
public Egg egg;
public boolean alive = true; // if dead set to false
public int moveCount = 0; // how many times moved
public Egg egg; // 青蛙是从哪个egg孵出来的,如果青蛙生存下来将用这个egg来下蛋
public boolean alive = true; // 设为false表示青蛙死掉了将不参与任何计算以节省时间
static final Random r = new Random();
static Image frogImg;
@ -77,23 +78,24 @@ public class Frog {
this.y = y;
if (egg.cellgroups == null)
throw new IllegalArgumentException("Illegal egg cellgroups argument:" + egg.cellgroups);
this.brainRadius = egg.brainRadius;
for (int k = 0; k < egg.cellgroups.length; k++) {
CellGroup g = egg.cellgroups[k];
for (int i = 0; i < g.cellQty; i++) {// 开始根据蛋来创建脑细胞
Cell c = new Cell();
c.inputs = new Input[g.inputQtyPerCell];
for (int j = 0; j < g.inputQtyPerCell; j++) {
int cellQTY = Math.round(g.inputQtyPerCell);
c.inputs = new Input[cellQTY];
for (int j = 0; j < cellQTY; j++) {
c.inputs[j] = new Input();
c.inputs[j].cell = c;
Zone.copyXY(randomPosInZone(g.groupInputZone), c.inputs[j]);
c.inputs[j].radius = g.cellInputRadius;
}
c.outputs = new Output[g.outputQtyPerCell];
for (int j = 0; j < g.outputQtyPerCell; j++) {
cellQTY = Math.round(g.outputQtyPerCell);
c.outputs = new Output[cellQTY];
for (int j = 0; j < cellQTY; j++) {
c.outputs[j] = new Output();
c.outputs[j].cell = c;
Zone.copyXY(randomPosInZone(g.groupInputZone), c.outputs[j]);
Zone.copyXY(randomPosInZone(g.groupOutputZone), c.outputs[j]);
c.outputs[j].radius = g.cellOutputRadius;
}
cells.add(c);
@ -102,95 +104,73 @@ public class Frog {
this.egg = egg;// 保留一份蛋,如果没被淘汰掉,将来下蛋时要用这个蛋来下新蛋
}
private float goUp = 0;
private float goDown = 0;
private float goLeft = 0;
private float goRight = 0;
/** Active a frog, if frog is dead return false */
public boolean active(Env env) {
if (!alive)
return false;
if (x < 0 || x >= env.ENV_XSIZE || y < 0 || y >= env.ENV_YSIZE) {// 越界者死!
energy -= 100;
if (energy < 0) {
alive = false;
return false;
}
// move
for (Cell cell : cells) {
for (Output output : cell.outputs) {
if (moveUp.nearby(output))
moveUp(env);
goUp += 1;
if (moveDown.nearby(output))
moveDown(env);
goDown += 1;
if (moveLeft.nearby(output))
moveLeft(env);
goLeft += 1;
if (moveRight.nearby(output))
moveRight(env);
if (moveRandom.nearby(output))
moveRandom(env);
goRight += 1;
}
}
return true;
}
/** 如果青蛙位置与food重合吃掉它 */
private void checkFoodAndEat(Env env) {
boolean eatedFood = false;
if (x >= 0 && x < env.ENV_XSIZE && y > 0 && y < env.ENV_YSIZE)
if (env.foods[x][y] > 0) {
env.foods[x][y] = 0;
energy = energy + 1000;// 吃掉food能量境加
eatedFood = true;
}
// 奖励
if (eatedFood) {
moveAndEat(env);
}
return alive;
}
private void moveRandom(Env env) {
int ran = r.nextInt(4);
if (ran == 0)
moveUp(env);
if (ran == 1)
moveDown(env);
if (ran == 2)
moveLeft(env);
if (ran == 3)
moveRight(env);
}
private void moveUp(Env env) {
y += 1;
if (y < 0 || y >= env.ENV_YSIZE) {
alive = false;
/** 如果青蛙位置与food重合吃掉它 */
private void moveAndEat(Env env) {
if (!alive)
return;
}
checkFoodAndEat(env);
}
private void moveDown(Env env) {
y -= 1;
if (y < 0 || y >= env.ENV_YSIZE) {
// 限制一次最多只能走3个单元,所以即使进化出很多运动神经元在同一个位置也是无用功,防止青蛙越跑越快
if (goUp > 3)
goUp = 3;
if (goDown > 3)
goDown = 3;
if (goLeft > 3)
goLeft = 3;
if (goRight > 3)
goRight = 3;
x = x + Math.round(goRight - goLeft);
y = y + Math.round(goUp - goDown);
goUp = 0;// 方向重置
goDown = 0;
goLeft = 0;
goRight = 0;
if (x < 0 || x >= env.ENV_XSIZE || y < 0 || y >= env.ENV_YSIZE) {// 越界者死!
alive = false;
return;
}
checkFoodAndEat(env);
}
private void moveLeft(Env env) {
x -= 1;
if (x < 0 || x >= env.ENV_XSIZE) {
alive = false;
return;
boolean eatedFood = false;
if (env.foods[x][y] > 0) {
env.foods[x][y] = 0;
energy = energy + 1000;// 吃掉food能量境加
eatedFood = true;
}
checkFoodAndEat(env);
}
// 奖励
if (eatedFood) {
private void moveRight(Env env) {
x += 1;
if (x < 0 || x >= env.ENV_XSIZE) {
alive = false;
return;
}
checkFoodAndEat(env);
}
private boolean allowVariation = false;
@ -201,10 +181,10 @@ public class Frog {
return (float) (f * (0.99f + r.nextFloat() * 0.02));
}
private float percet5(float f) {
private float percet2(float f) {
if (!allowVariation)
return f;
return (float) (f * (0.95f + r.nextFloat() * 0.10));
return (float) (f * (0.98f + r.nextFloat() * 0.04));
}
private static Zone randomPosInZone(Zone z) {
@ -218,22 +198,21 @@ public class Frog {
else
allowVariation = true;
Egg newEgg = new Egg();
newEgg.brainRadius = percet5(egg.brainRadius);
CellGroup[] cellgroups = new CellGroup[egg.cellgroups.length];
newEgg.cellgroups = cellgroups;
for (int i = 0; i < cellgroups.length; i++) {
CellGroup cellGroup = new CellGroup();
cellgroups[i] = cellGroup;
CellGroup oldGp = egg.cellgroups[i];
cellGroup.groupInputZone = new Zone(percet5(oldGp.groupInputZone.x), percet5(oldGp.groupInputZone.y),
percet5(oldGp.groupInputZone.radius));
cellGroup.groupOutputZone = new Zone(percet5(oldGp.groupOutputZone.x), percet5(oldGp.groupOutputZone.y),
percet5(oldGp.groupOutputZone.radius));
cellGroup.cellQty = Math.round(percet5(oldGp.cellQty));
cellGroup.groupInputZone = new Zone(percet2(oldGp.groupInputZone.x), percet2(oldGp.groupInputZone.y),
percet2(oldGp.groupInputZone.radius));
cellGroup.groupOutputZone = new Zone(percet2(oldGp.groupOutputZone.x), percet2(oldGp.groupOutputZone.y),
percet2(oldGp.groupOutputZone.radius));
cellGroup.cellQty = Math.round(percet2(oldGp.cellQty));
cellGroup.cellInputRadius = percet1(oldGp.cellInputRadius);
cellGroup.cellOutputRadius = percet1(oldGp.cellOutputRadius);
cellGroup.inputQtyPerCell = Math.round(percet5(oldGp.inputQtyPerCell));
cellGroup.outputQtyPerCell = Math.round(percet5(oldGp.outputQtyPerCell));
cellGroup.inputQtyPerCell = Math.round(percet2(oldGp.inputQtyPerCell));
cellGroup.outputQtyPerCell = Math.round(percet2(oldGp.outputQtyPerCell));
}
return newEgg;
}

@ -33,8 +33,8 @@ public class CellGroup implements Serializable {
public float cellInputRadius; // input radius of each cell
public float cellOutputRadius; // output radius of each cell
public int cellQty; // how many nerve cells in this CellGroup
public float cellQty; // how many nerve cells in this CellGroup
public int inputQtyPerCell; // input qty per cell
public int outputQtyPerCell; // output qty per cell
public float inputQtyPerCell; // input qty per cell
public float outputQtyPerCell; // output qty per cell
}

@ -24,7 +24,7 @@ import java.util.Random;
public class Egg implements Serializable {
private static final long serialVersionUID = 2L;
public static final int CELL_GROUP_QTY = 30;
public float brainRadius = 1000;
public static final int BRAIN_WIDTH = 800;
public CellGroup[] cellgroups;
public static Egg createBrandNewEgg() {
@ -34,10 +34,10 @@ public class Egg implements Serializable {
for (int i = 0; i < CELL_GROUP_QTY; i++) {
CellGroup cellGroup = new CellGroup();
egg.cellgroups[i] = cellGroup;
cellGroup.groupInputZone = new Zone(r.nextFloat() * egg.brainRadius, r.nextFloat() * egg.brainRadius,
(float) (r.nextFloat() * egg.brainRadius * .01));
cellGroup.groupOutputZone = new Zone(r.nextFloat() * egg.brainRadius, r.nextFloat() * egg.brainRadius,
(float) (r.nextFloat() * egg.brainRadius * .01));
cellGroup.groupInputZone = new Zone(r.nextFloat() * BRAIN_WIDTH, r.nextFloat() * BRAIN_WIDTH,
(float) (r.nextFloat() * BRAIN_WIDTH * .01));
cellGroup.groupOutputZone = new Zone(r.nextFloat() * BRAIN_WIDTH, r.nextFloat() * BRAIN_WIDTH,
(float) (r.nextFloat() * BRAIN_WIDTH * .01));
cellGroup.cellQty = r.nextInt(10);
cellGroup.cellInputRadius = (float) (r.nextFloat() * 0.001);
cellGroup.cellOutputRadius = (float) (r.nextFloat() * 0.001);

@ -32,6 +32,14 @@ public class Zone implements Serializable {
this.x = x;
this.y = y;
this.radius = radius;
if (this.x < 0)
this.x = 0;
if (this.y < 0)
this.y = 0;
if (this.x > Egg.BRAIN_WIDTH)
this.x = Egg.BRAIN_WIDTH;
if (this.y > Egg.BRAIN_WIDTH)
this.y = Egg.BRAIN_WIDTH;
}
public boolean nearby(Zone z) {

@ -15,15 +15,19 @@ public class Application {
CLASSPATH = classpath.substring(0, core);
}
public static JFrame mainFrame = new JFrame();
public static Env env = new Env();
public static BrainStructure brainStructure = new BrainStructure();
public static void main(String[] args) throws InterruptedException {
mainFrame.setLayout(null);
mainFrame.setSize(520, 550); // 窗口大小
mainFrame.setSize(1320, 840); // 窗口大小
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭时退出程序
Env env = new Env();
mainFrame.add(env);
mainFrame.add(brainStructure);
mainFrame.setVisible(true);
env.run();
}

@ -0,0 +1,73 @@
package com.github.drinkjava2.frog.env;
import static java.lang.Math.round;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Cell;
import com.github.drinkjava2.frog.egg.CellGroup;
import com.github.drinkjava2.frog.egg.Zone;
/**
* Env is the living space of frog. draw it on JPanel
*/
@SuppressWarnings("serial")
public class BrainStructure extends JPanel {
public BrainStructure() {
super();
this.setLayout(null);// 空布局
this.setBounds(500, 0, 1000, 1000);
}
void drawZone(Graphics g, Zone z) {
g.drawRect(round(z.x - z.radius / 2), round(z.y - z.radius / 2), round(z.radius), round(z.radius));
}
void fillZone(Graphics g, Zone z) {
g.fillRect(round(z.x - z.radius / 2), round(z.y - z.radius / 2), round(z.radius), round(z.radius));
}
public void drawBrain(Frog frog) {
Graphics g = this.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 800);
g.setColor(Color.black);
g.drawRect(0, 0, 800, 800);
g.setColor(Color.red);
drawZone(g, frog.eye);
g.setColor(Color.green);
drawZone(g, frog.happy);
g.setColor(Color.yellow);
drawZone(g, frog.hungry);
g.setColor(Color.gray);
drawZone(g, frog.moveUp);
drawZone(g, frog.moveDown);
drawZone(g, frog.moveLeft);
drawZone(g, frog.moveRight);
g.setColor(Color.black);
int i = 1;
for (CellGroup group : frog.egg.cellgroups) {
g.setColor(new Color((i++) * 130 + i * 70000 + i * 3333333));// 取随机色
g.drawLine(round(group.groupInputZone.x), round(group.groupInputZone.y), round(group.groupOutputZone.x),
round(group.groupOutputZone.y));
drawZone(g, group.groupInputZone);
fillZone(g, group.groupOutputZone);
}
for (Cell iterable_element : frog.cells) {
}
}
}

@ -19,7 +19,7 @@ import com.github.drinkjava2.frog.util.EggTool;
@SuppressWarnings("serial")
public class Env extends JPanel {
/** Speed of test */
public static int SHOW_SPEED =1;
public static int SHOW_SPEED = 1;
/** Steps of one test round */
public static int STEPS_PER_ROUND = 3000;
@ -34,7 +34,7 @@ public class Env extends JPanel {
public int FOOD_QTY = 2000; // as name
public int EGG_QTY =80; // as name
public int EGG_QTY = 100; // as name
public List<Frog> frogs = new ArrayList<Frog>();
public List<Egg> eggs;
@ -58,7 +58,8 @@ public class Env extends JPanel {
frogs.add(new Frog(ENV_XSIZE / 2 + rand.nextInt(90), ENV_YSIZE / 2 + rand.nextInt(90), eggs.get(i)));
}
}
System.out.println("Created "+4*eggs.size() +" frogs");
System.out.println("Created " + 4 * eggs.size() + " frogs");
for (int i = 0; i < FOOD_QTY; i++)
foods[rand.nextInt(ENV_XSIZE - 3)][rand.nextInt(ENV_YSIZE - 3)] = 1;
}
@ -82,16 +83,14 @@ public class Env extends JPanel {
rebuildFrogAndFood();
boolean allDead = false;
for (int i = 0; i < STEPS_PER_ROUND; i++) {
if (allDead)
break;
if (allDead) {
System.out.println("All dead at round:" + i);
break; // 全死光了就直接跳到下一轮,以节省时间
}
allDead = true;
for (Frog frog : frogs) {
for (Frog frog : frogs)
if (frog.active(this))
allDead = false;
if (frog.alive && frog.moveCount == 0 && i > 100) {// 如果不移动就死!
frog.alive = false;
}
}
if (i % SHOW_SPEED != 0) // 画青蛙会拖慢速度
continue;
// 开始画青蛙
@ -104,9 +103,9 @@ public class Env extends JPanel {
drawFood(g);
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
Thread.sleep(10);
}
EggTool.layEggs(this);
Application.brainStructure.drawBrain(frogs.get(0));
t2 = System.currentTimeMillis();
Application.mainFrame.setTitle("Frog test round: " + round++ + ", time used: " + (t2 - t1) + " ms");
} while (true);

@ -42,10 +42,6 @@ public class EggTool {
sortFrogsOrderByEnergyDesc(env);
System.out.print("First frog energy=" + env.frogs.get(0).energy);
System.out.print(", Last frog energy=" + env.frogs.get(env.frogs.size() - 1).energy + ", ");
for (Frog frog : env.frogs) {
System.out.print(frog.energy + ",");
}
System.out.println();
try {
List<Egg> newEggs = new ArrayList<Egg>();
for (int i = 0; i < env.EGG_QTY; i++)
@ -109,7 +105,7 @@ public class EggTool {
"Loaded " + env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.ser" + "'.");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
errorfound = true;
}
}
if (errorfound) {

Binary file not shown.

@ -0,0 +1,12 @@
## 版本发布记录
### 2018-1-3
项目启动。
### 2019-3-11 1.0.0版Commit:Go frog go!)发布
开发环境完成演示第一个人工生命诞生。但是所有Frog脑部为空因为运动神经元被短路只能固定向一个方向运动。
### 2019-03-18 1.0.1版提交 (Commit:Brain picture)
添加了脑结构图形以更直观地观察Frog的脑结构但是运动神经元依然被短路只能固定向一个方向运动。
Loading…
Cancel
Save