Go one way

This commit is contained in:
Yong Zhu 2019-03-09 07:05:49 -07:00
parent 0d112e2256
commit 1d9dd6ebd9
12 changed files with 151 additions and 149 deletions

View File

@ -27,12 +27,10 @@ import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.egg.Zone;
import com.github.drinkjava2.frog.env.Application;
import com.github.drinkjava2.frog.env.Env;
import com.github.drinkjava2.frog.env.Food;
/**
* Frog = brain + body(mouth, eye, leg), but now let's focus on brain, ignore
* body
*
* 为了简化模型这个类里出现多个固定数值的编码以后要改进成可以可以放在蛋里遗传进化的动态数值先让生命延生是第一步优化是以后的事
* Frog = brain + body(mouth, eye, leg)
*
* @author Yong Zhu
* @since 1.0.0
@ -45,8 +43,8 @@ public class Frog {
/** brain cells */
List<Cell> cells = new ArrayList<Cell>();
/** 视觉细胞的输入区在脑中的坐标,先随便取 在原点附件就可以了,分瓣率为60x60, 以后再考虑放到蛋里去进化 */
public static int eyeRadius = Math.round(30);
/** 视觉细胞的输入区在脑中的坐标,先随便取 在原点附件就可以了,以后再考虑放到蛋里去进化 */
public static Zone eye = new Zone(0, 0, 300);
/** 运动细胞的输入区在脑中的坐标,先随便取就可以了,以后再考虑放到蛋里去进化 */
public static Zone moveUp = new Zone(500, 100, 10);
@ -56,7 +54,7 @@ public class Frog {
public int x;
public int y;
public long energy = Env.STEPS_PER_ROUND;
public long energy = 10000;
public Egg egg;
static final Random r = new Random();
@ -82,14 +80,12 @@ public class Frog {
c.inputs = new Input[g.inputQtyPerCell];
for (int j = 0; j < g.inputQtyPerCell; 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++) {
c.outputs[j] = new Output();
c.outputs[j].cell = c;
Zone.copyXY(randomPosInZone(g.groupInputZone), c.outputs[j]);
c.outputs[j].radius = g.cellOutputRadius;
}
@ -100,64 +96,43 @@ public class Frog {
}
public void active(Env env) {
// 每个step即使啥都不干也要消耗能量
energy--;
// 如果青蛙位置与food重合吃掉它
// this.x = this.x - 1 + r.nextInt(3);
// this.y = this.y - 1 + r.nextInt(3);
// eat food
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能量境加
int j = env.foods.size() - 1;
for (int i = j; i >= 0; i--) {
Food food = env.foods.get(i);
if (x == food.x && y == food.y) {
energy = energy + food.energy;
env.foods.remove(i);
eatedFood = true;
break;
}
}
// 吃掉food有奖励
// 奖励
if (eatedFood) {
}
// move
for (Cell cell : cells) {
// // 输入部分
// for (Input input : cell.inputs) {
// // 如果食物出现在视觉区激活对应frog视觉区的输入触突
// if (input.x > (-eyeRadius) && input.y > (-eyeRadius) && input.x < eyeRadius && input.y < eyeRadius) {
// int xx = x + input.roundX();
// int yy = y + input.roundY();
// if (xx > 0 && xx < env.ENV_XSIZE && yy > 0 && yy < env.ENV_YSIZE && env.foods[xx][yy] > 0)
// input.energy += 500;
// }
//
// // 如果任意输入触突激活增加对应细胞的输出区激活
// if (input.energy > 50)
// cell.activateOutputs();
//
// // 即使什么也不干input的能量总在以95%的速度下降
// input.energy *= .95;
// }
// 如果输出触突位于运动区且兴奋则frog移动一个单位
for (Output output : cell.outputs) {
// if (output.energy < 30)
// continue;
if (moveUp.nearby(output)) {
if (Zone.nearby(moveUp, output)) {
y += 1;
}
if (moveDown.nearby(output)) {
break;
} else if (Zone.nearby(moveDown, output)) {
y -= 1;
}
if (moveLeft.nearby(output)) {
break;
} else if (Zone.nearby(moveLeft, output)) {
x -= 1;
}
if (moveRight.nearby(output)) {
break;
} else if (Zone.nearby(moveRight, output)) {
x += 1;
break;
}
// 即使什么也不干output的能量总在以95%的速度下降
output.energy *= 0.95;
}
}
}
@ -181,7 +156,7 @@ public class Frog {
}
public Egg layEgg() {
if (r.nextInt(100) > 75) // 变异率先固定在75%
if (r.nextInt(100) > 25) // 变异率先固定在25%
allowVariation = false;// 如果不允许变异下的蛋就相当于克隆原来的蛋
else
allowVariation = true;

View File

@ -18,13 +18,17 @@ package com.github.drinkjava2.frog.brain;
*/
public class Cell {
public int group; // this cell belong to which group?
public Input[] inputs; // inputs of cell
public Output[] outputs; // outputs of cell
public Input[] inputs; // inputs of cell, float array format like {x1,y1, x2, y2...}
public Output[] outputs; // outputs of cell, float array format like {x1,y1, x2, y2...}
public boolean used = false;
public void activateOutputs() {
for (Output output : outputs)
output.energy += 55;
}
public void activate() {
used = true;
for (Input xy : inputs) {
}
}
}

View File

@ -20,5 +20,4 @@ import com.github.drinkjava2.frog.egg.Zone;
*/
public class Input extends Zone{
public float energy;
public Cell cell;
}

View File

@ -20,5 +20,4 @@ import com.github.drinkjava2.frog.egg.Zone;
*/
public class Output extends Zone {
public float energy;
public Cell cell;
}

View File

@ -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 = 100;
public float brainRadius = 1000;
public CellGroup[] cellgroups;
public static Egg createBrandNewEgg() {
@ -38,9 +38,9 @@ public class Egg implements Serializable {
(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.cellQty = r.nextInt(30);
cellGroup.cellInputRadius = (float) (r.nextFloat());
cellGroup.cellOutputRadius = (float) (r.nextFloat() );
cellGroup.cellQty = r.nextInt(10);
cellGroup.cellInputRadius = (float) (r.nextFloat() * 0.001);
cellGroup.cellOutputRadius = (float) (r.nextFloat() * 0.001);
cellGroup.inputQtyPerCell = r.nextInt(10);
cellGroup.outputQtyPerCell = r.nextInt(5);
}

View File

@ -34,21 +34,13 @@ public class Zone implements Serializable {
this.radius = radius;
}
public boolean nearby(Zone z) {
float dist = radius + z.radius;
if (Math.abs(x - z.x) < dist && Math.abs(y - z.y) < dist)
public static boolean nearby(Zone z1, Zone z2) {
float dist = z1.radius + z2.radius;
if (Math.abs(z1.x - z2.x) < dist && Math.abs(z1.y - z2.y) < dist)
return true;
return false;
}
public int roundX() {
return Math.round(x);
}
public int roundY() {
return Math.round(y);
}
public static void copyXY(Zone from, Zone to) {
to.x = from.x;
to.y = from.y;

View File

@ -18,7 +18,7 @@ import com.github.drinkjava2.frog.util.EggTool;
@SuppressWarnings("serial")
public class Env extends JPanel {
/** Speed of test */
public static int SHOW_SPEED = 100;
public static int SHOW_SPEED = 10;
/** Steps of one test round */
public static int STEPS_PER_ROUND = 1000;
@ -29,13 +29,12 @@ public class Env extends JPanel {
/** Virtual environment y size is 500 pixels */
public int ENV_YSIZE = 300;
public byte[][] foods = new byte[ENV_XSIZE][ENV_YSIZE];
public int FOOD_QTY = 2500; // as name
public int FOOD_QTY =6000; // as name
public int EGG_QTY = 2; // as name
public int EGG_QTY = 10; // as name
public List<Frog> frogs = new ArrayList<Frog>();
public List<Food> foods = new ArrayList<Food>();
public List<Egg> eggs;
public Env() {
@ -46,27 +45,16 @@ public class Env extends JPanel {
private void rebuildFrogAndFood() {
frogs.clear();
for (int i = 0; i < ENV_XSIZE; i++) {
for (int j = 0; j < ENV_YSIZE; j++) {
foods[i][j] = 0;
}
}
foods.clear();
Random rand = new Random();
for (int i = 0; i < eggs.size(); i++) { // 1个Egg生出10个Frog
for (int j = 0; j < 10; j++) {
frogs.add(new Frog(rand.nextInt(ENV_XSIZE - 3), rand.nextInt(ENV_YSIZE - 3), eggs.get(i)));
}
for (int i = 0; i < eggs.size(); i++) { // 1个Egg生出4个Frog
frogs.add(new Frog(rand.nextInt(ENV_XSIZE - 3), rand.nextInt(ENV_YSIZE - 3), eggs.get(i)));
frogs.add(new Frog(rand.nextInt(ENV_XSIZE - 3), rand.nextInt(ENV_YSIZE - 3), eggs.get(i)));
frogs.add(new Frog(rand.nextInt(ENV_XSIZE - 3), rand.nextInt(ENV_YSIZE - 3), eggs.get(i)));
frogs.add(new Frog(rand.nextInt(ENV_XSIZE - 3), rand.nextInt(ENV_YSIZE - 3), eggs.get(i)));
}
for (int i = 0; i < FOOD_QTY; i++)
foods[rand.nextInt(ENV_XSIZE - 3)][rand.nextInt(ENV_YSIZE - 3)] = 1;
}
private void drawFood(Graphics g) {
for (int x = 0; x < ENV_XSIZE; x++)
for (int y = 0; y < ENV_YSIZE; y++)
if (foods[x][y] > 0) {
g.fillOval(x, y, 4, 4);
}
foods.add(new Food(rand.nextInt(ENV_XSIZE - 3), rand.nextInt(ENV_YSIZE - 3)));
}
public void run() throws InterruptedException {
@ -84,8 +72,8 @@ public class Env extends JPanel {
Graphics g = buffImg.getGraphics();
for (Frog frog : frogs)
frog.show(g);
drawFood(g);
for (Food food : foods)
food.show(g);
Graphics g2 = this.getGraphics();
g2.drawImage(buffImg, 0, 0, this);
Thread.sleep(10);

View File

@ -0,0 +1,23 @@
package com.github.drinkjava2.frog.env;
import java.awt.Graphics;
/**
* Food is food for frogs, one food = 500 unit energy
*/
public class Food {
public int energy = 500;
public int x;
public int y;
public Food(int x, int y) {
this.x = x;
this.y = y;
}
public void show(Graphics g) {
g.fillOval(x, y, 4, 4);
}
}

View File

@ -35,31 +35,35 @@ public class EggTool {
public static final boolean JSON_FILE_FORMAT = false; // JSON is slow but easier to debug
public static void layEggs(Env env) {
if (JSON_FILE_FORMAT)
layJsonEggs(env);
else
laySerializedEggs(env);
}
public static void loadEggs(Env env) {
if (JSON_FILE_FORMAT)
loadJsonEggs(env);
else
loadSerializedEggs(env);
}
/**
* 利用Java串行机制存盘 能量多(也就是吃的更多更fat)的Frog下蛋并存盘, 以进行下一伦测试能量少的Frog被淘汰没有下蛋的资格
*/
public static void layEggs(Env env) {
public static void laySerializedEggs(Env env) {
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.frogs.size() / 10; i++)
for (int i = 0; i < env.frogs.size() / 4; i++)
newEggs.add(env.frogs.get(i).layEgg());
if (JSON_FILE_FORMAT) {
String newEggsString = JSON.toJSONString(newEggs);
FrogFileUtils.writeFile(Application.CLASSPATH + "eggs.json", newEggsString, "utf-8");
} else {
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(newEggs);
so.close();
}
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(newEggs);
so.close();
env.eggs = newEggs;
System.out
.println("Saved " + env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser" + "'");
@ -68,11 +72,27 @@ public class EggTool {
}
}
/** 类似laySerializedEggs方法但是存为JSON格式 ,以方便调试 */
public static void layJsonEggs(Env env) {
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 + ", ");
List<Egg> newEggs = new ArrayList<Egg>();
for (int i = 0; i < env.frogs.size() / 4; i++)
newEggs.add(env.frogs.get(i).layEgg());
String newEggsString = JSON.toJSONString(newEggs);
FrogFileUtils.writeFile(Application.CLASSPATH + "eggs.json", newEggsString, "utf-8");
env.eggs = newEggs;
System.out.println("Saved " + env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.json" + "'");
}
private static void sortFrogsOrderByEnergyDesc(Env env) {
Collections.sort(env.frogs, new Comparator<Frog>() {
public int compare(Frog a, Frog b) {
if (a.energy >= b.energy)
if (a.energy > b.energy)
return -1;
else if (a.energy == b.energy)
return 0;
else
return 1;
}
@ -83,41 +103,44 @@ public class EggTool {
* 从磁盘读入一批Egg
*/
@SuppressWarnings("unchecked")
public static void loadEggs(Env env) {
boolean errorfound = false;
if (JSON_FILE_FORMAT) {
String eggsString = FrogFileUtils.readFile(Application.CLASSPATH + "eggs.json", "utf-8");
if (eggsString != null) {
List<JSONObject> jsonEggs = (List<JSONObject>) JSON.parse(eggsString);
env.eggs = new ArrayList<Egg>();
for (JSONObject json : jsonEggs) {
Egg egg = json.toJavaObject(Egg.class);
env.eggs.add(egg);
}
System.out.println(
"Loaded " + env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.json" + "'.");
} else
errorfound = true;
} else {
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "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" + "'.");
eggsInputStream.close();
} catch (Exception e) {
errorfound = true;
e.printStackTrace();
}
}
if (errorfound) {
System.out.println("No eggs files ' " + Application.CLASSPATH + " found, created " + env.EGG_QTY
+ " new eggs to do test.");
public static void loadSerializedEggs(Env env) {
try {
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "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" + "'.");
eggsInputStream.close();
} catch (Exception e) {
System.out.println("No eggs files ' " + Application.CLASSPATH + "eggs.ser" + "' found, created "
+ env.EGG_QTY + " new eggs to do test.");
env.eggs = new ArrayList<Egg>();
for (int i = 0; i < env.EGG_QTY; i++)
env.eggs.add(Egg.createBrandNewEgg());
}
}
/** 类似loadSerializedEggs方法但是读取的是JSON格式以方便调试 */
@SuppressWarnings("unchecked")
public static void loadJsonEggs(Env env) {
String eggsString = FrogFileUtils.readFile(Application.CLASSPATH + "eggs.json", "utf-8");
if (eggsString != null) {
List<JSONObject> jsonEggs = (List<JSONObject>) JSON.parse(eggsString);
env.eggs = new ArrayList<Egg>();
for (JSONObject json : jsonEggs) {
Egg egg = json.toJavaObject(Egg.class);
env.eggs.add(egg);
}
System.out.println(
"Loaded " + env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.json" + "'.");
} else {
System.out.println("No eggs files ' " + Application.CLASSPATH + "eggs.json" + "' found, created "
+ env.EGG_QTY + " new eggs to do test.");
env.eggs = new ArrayList<Egg>();
for (int i = 0; i < env.EGG_QTY; i++)
env.eggs.add(Egg.createBrandNewEgg());
}
}
}

File diff suppressed because one or more lines are too long

BIN
eggs.ser

Binary file not shown.

BIN
frog.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 702 B