From e3955b58ea32e2cd37b608e47dc56f230ee9cc31 Mon Sep 17 00:00:00 2001 From: Yong Zhu Date: Thu, 13 Jun 2019 01:32:50 -0600 Subject: [PATCH] Happy & Pain --- README.md | 11 ++-- .../java/com/github/drinkjava2/frog/Env.java | 10 ++-- .../java/com/github/drinkjava2/frog/Frog.java | 15 ++---- .../github/drinkjava2/frog/brain/Cell.java | 4 +- .../github/drinkjava2/frog/brain/Organ.java | 19 +++---- .../github/drinkjava2/frog/brain/Zone.java | 4 +- .../drinkjava2/frog/brain/group/Group.java | 4 +- .../frog/brain/group/RandomConnectGroup.java | 31 +++++++---- .../drinkjava2/frog/brain/organ/Eat.java | 10 +++- .../drinkjava2/frog/brain/organ/Eye.java | 8 +-- .../drinkjava2/frog/brain/organ/Happy.java | 40 +++++++++++++++ .../drinkjava2/frog/brain/organ/Hungry.java | 17 ++++--- .../drinkjava2/frog/brain/organ/Pain.java | 48 ++++++++++++++++++ .../com/github/drinkjava2/frog/egg/Egg.java | 24 +++++---- .../github/drinkjava2/frog/egg/EggTool.java | 2 +- .../github/drinkjava2/frog/env/CellGroup.java | 14 +++++ .../drinkjava2/frog/util/RandomUtils.java | 14 ++++- eggs.ser | Bin 282415 -> 159278 bytes result3.gif | Bin 0 -> 199271 bytes 版本提交记录.md | 6 +-- 20 files changed, 210 insertions(+), 71 deletions(-) create mode 100644 core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java create mode 100644 core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java create mode 100644 core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java create mode 100644 result3.gif diff --git a/README.md b/README.md index 8ba3183..df07403 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 项目要实现的短期和长远目标 * 脑模型和虚拟环境的初步搭建 [脑模型刚开始搭建。虚拟环境已完成,点击run.bat可以查看演示] -* 使脑模型具有视觉功能,如果有食物在它附近,将激发天生条件反射,向食物移动,并获得进食奖励 [未完成] +* 使脑模型具有视觉功能,如果有食物在它附近,将激发天生条件反射,向食物移动,并获得进食奖励 [未全部完成] * 引入现成的图像识别算法,使脑模型具有图像识别功能,根据形状区分食物、毒物、天敌 [未完成] * 如果误食有毒食物,将激发天生条件反射,获得惩罚并扣除能量,天生痛觉区兴奋。[未完成] * 如果被天敌攻击,将激发天生条件反射,获得惩罚并扣除能量,天生痛觉区强烈兴奋。[未完成] @@ -60,7 +60,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 目前进展和成绩 2019.03.11 虚拟环境已建好,可以模拟低等生命的遗传、繁殖、变异、进化现象,但目前只能往一个方向运动,相当于一个最简单的单细胞生物,还不具备视觉能力,不具备主动找食能力。 -运行run.bat可以查看演示。Env.java中的几个重要参数说明: +运行run.bat可以查看演示(需要安装Java8和Maven)。Env.java中的几个重要参数说明: * SHOW_SPEED: 调整实验的速度(1~1000),值越小则越慢。 * ENV_WIDTH: 虚拟环境的大小(100~1000) * EGG_QTY: 每次允许Frog下多少个蛋,每个蛋可以孵出4个青蛙。通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一个蛋。 @@ -70,8 +70,11 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 另外每步演示的结果(egg)会存盘在根目根目录下,名为egg.ser,可以删除这个文件以从头开始新的测试。因为还没涉及脑模型的搭建,可以看到有些青蛙跑得飞快,这是自然选择的结果,因为跑在最前面的吃得多。以后会改正这个bug,要让最聪明的、会抢食的Frog胜出,而不是让跑得快的胜出。 2019.03.21 添加了脑图,改进随机运动模式为Hungry区驱动。从脑图上可以直观地观察脑结构,方便调试。 2019.04.01 改进脑图的显示bug, 每一次生成Frog时添加随机神经元,并简单实现"卵+精子->受精卵"算法,以促进种群多样性。 -2019-04-12 添加一个简单的眼睛,自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图: -![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) +2019-04-12 添加一个简单的眼睛(只有四个感光细胞),自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图: +![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) +2019-06-13 做了一些重构清理,加上了Happy和Pain两个器官,分别对应进食奖励和痛苦感,后者在靠近边界时激发。观查它的表现,痛苦感生效了,一些Frog跑到边界后就不再前进,而是顺着边界溜下去了,但是Happy器官没有生效,这也很显然,因为Happy属于复杂的进食条件反射链的一部分,在没有记忆器官(算法)引入之前,再怎么优胜劣汰也是没办法用上进食奖励信号的。见下图: +![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) + ## 版权 | License [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) 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 8504bca..57af8e9 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Env.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Env.java @@ -21,7 +21,7 @@ import com.github.drinkjava2.frog.egg.EggTool; @SuppressWarnings("serial") public class Env extends JPanel { /** Speed of test */ - public static final int SHOW_SPEED = 1; // 测试速度,1~1000,可调, 数值越小,速度越慢 + public static final int SHOW_SPEED = 5; // 测试速度,1~1000,可调, 数值越小,速度越慢 public static final int ENV_WIDTH = 400; // 虚拟环境的宽度, 可调 @@ -32,7 +32,7 @@ public class Env extends JPanel { public static final int FROG_BRAIN_DISP_WIDTH = 300; // Frog的脑图在屏幕上的显示大小,可调 /** Steps of one test round */ - public static final int STEPS_PER_ROUND = 3000;// 每轮测试步数,可调 + public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调 /** Frog's brain width, fixed to 1000 unit */ public static final float FROG_BRAIN_WIDTH = 1000; // frog的脑宽度固定为1000,不要随便调整,因为器官的相对位置和大小是按脑大小设定的 @@ -47,7 +47,7 @@ public class Env extends JPanel { EggTool.deleteEggs(); } - public static final int FOOD_QTY = 2000; // 食物数量, 可调 + public static final int FOOD_QTY = 1000; // 食物数量, 可调 public static final int EGG_QTY = 50; // 每轮下n个蛋,可调,只有最优秀的前n个青蛙们才允许下蛋 @@ -129,6 +129,10 @@ public class Env extends JPanel { } } + public static boolean closeToEdge(Frog f) {// 青蛙靠近边界? 离死不远了 + return f.x < 20 || f.y < 20 || f.x > (Env.WIDTH - 20) || f.y > (Env.HEIGHT - 20); + } + public void run() throws InterruptedException { EggTool.loadEggs(this); // 从磁盘加载egg,或新建一批egg int round = 1; 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 1607324..43a610d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Frog.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Frog.java @@ -19,7 +19,6 @@ import java.util.List; import javax.imageio.ImageIO; 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.egg.Egg; @@ -41,7 +40,7 @@ public class Frog { public int x; // frog在Env中的x坐标 public int y; // frog在Env中的y坐标 - public long frogEngery = 100000; // 能量为0则死掉 + public long frogEngery = 10000; // 能量为0则死掉 public boolean alive = true; // 设为false表示青蛙死掉了,将不参与计算和显示,以节省时间 static Image frogImg; @@ -63,22 +62,16 @@ public class Frog { } public boolean active(Env v) { - frogEngery -= 1; + frogEngery-=0.01; if (!alive) { - frogEngery -= 50;// 死了需要消耗更多的能量,退出生存竞争 return false; } if (frogEngery < 0) { // 如果能量小于0则死 + frogEngery-=10; alive = false; return false; } - // for (Cell cell1 : cells) {// 大脑主循环 - // if (cell1.energy > 0) - // cell1.energy--; - // for (Input input : cell1.inputs) { - // // TODO - // } - // } + for (Organ o : organs) { // 调用每个Organ的active方法 o.active(this); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java index 0321019..a45ab9d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java @@ -19,6 +19,8 @@ import com.github.drinkjava2.frog.brain.group.Group; * @since 1.0 */ public class Cell { + public static final float MAX_ENERGY_LIMIT = 1000.0f; + // this cell belong to frog's which organ public Group group; @@ -29,6 +31,6 @@ public class Cell { public Output[] outputs; // 每个细胞有一组输出触突 // energy of cell, energy got from food - public long energy; // 每个细胞当前的能量值 + public float energy; // 每个细胞当前的能量值 } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java index f6d7a91..ada0047 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java @@ -27,22 +27,23 @@ public abstract class Organ extends Zone { private static final long serialVersionUID = 1L; public String name; // 显示在脑图上的器官名称,可选 - public long fat = 0; // 如果活跃多,fat值高,则保留(及变异)的可能性大,反之则很可能丢弃掉 + public long fat = 0; // 如果活跃多,fat值高,则保留(及变异)的可能性大,反之则很可能丢弃掉 public boolean allowBorrow() { // 是否允许在精子中将这个器官借出 return false; } /** If active in this organ's zone? */ - public boolean outputActive(Frog f) { + public boolean outputActive(Frog f) { // 如果一个细胞能量>10,且它的输出触突位于这个器官内,则器官被激活 for (Cell cell : f.cells) { - for (Output output : cell.outputs) { // - if (cell.energy > 10 && this.nearby(output)) { - cell.group.fat++; - cell.energy -= 1; - return true; + if (cell.energy > 10) + for (Output output : cell.outputs) { // + if (this.nearby(output)) { + cell.group.fat++; + cell.energy -= 3; + return true; + } } - } } return false; } @@ -72,7 +73,7 @@ public abstract class Organ extends Zone { newOrgan = this.getClass().newInstance(); copyXYR(this, newOrgan); newOrgan.name = this.name; - newOrgan.fat = this.fat; + newOrgan.fat = this.fat; return newOrgan; } catch (Exception e) { throw new UnknownError("Can not make new Organ copy for " + this); diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java index bd443cf..d8ae70e 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java @@ -31,7 +31,7 @@ public class Zone implements Serializable { // 空构造器不能省 } - public Zone(float x, float y, float r) { + public Zone(float x, float y, float r) {// 用x,y,r来构造 this.x = x; this.y = y; this.r = r; @@ -45,7 +45,7 @@ public class Zone implements Serializable { this.y = Env.FROG_BRAIN_WIDTH; } - public Zone(Zone z) { + public Zone(Zone z) {// 用另一个Zone来构造 this.x = z.x; this.y = z.y; this.r = z.r; diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java b/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java index 6328118..b2abdfa 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java @@ -29,7 +29,7 @@ import com.github.drinkjava2.frog.brain.Organ; * @author Yong Zhu * @since 1.0 */ -public abstract class Group extends Organ { +public abstract class Group extends Organ { private static final long serialVersionUID = 1L; @Override @@ -40,7 +40,7 @@ public abstract class Group extends Organ { /** Each loop step call active method, Child class can override this method */ @Override public void active(Frog f) { // 每一步都会调用器官的active方法 - f.frogEngery -= 3; // 每个器官运动都要消耗能量, 死了也要消耗能量 + f.frogEngery -= 1; // 每个器官运动都要消耗能量, 死了也要消耗能量 if (!f.alive) return; if (f.frogEngery < 0) { // 如果能量小于0则死 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 c47ebe4..5e8902f 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 @@ -38,6 +38,8 @@ public class RandomConnectGroup extends Group { public Zone inputZone; // 输入触突区 public Zone outputZone; // 输出触突区 + float inputWeight = 1; // 输入权重 + float outputWeight = 1; // 输出权重 @Override public void init(Frog f) { @@ -47,6 +49,7 @@ public class RandomConnectGroup extends Group { outputZone = RandomUtils.randomPosInZone(this); Cell c = new Cell(); + Input in = new Input(inputZone); in.cell = c; c.inputs = new Input[] { in }; @@ -61,19 +64,27 @@ public class RandomConnectGroup extends Group { @Override public Organ[] vary() { - if (fat <= 0) - if (RandomUtils.percent(30)) + if (fat <= 0)// 如果胖值为0,表示这个组的细胞没有用到,可以小概率丢掉它了 + if (RandomUtils.percent(50)) return new Organ[] {}; - if (RandomUtils.percent(80)) - return new Organ[] { this }; - return new Organ[] { this, newRandomConnGroup(this) }; + if (RandomUtils.percent(20)) { // 有20机率权重变大 + inputWeight = RandomUtils.vary(inputWeight); + outputWeight = RandomUtils.vary(outputWeight); + } + return new Organ[] { this }; // 大部分时间原样返回它的副本就行了,相当于儿子是父亲的克隆 + } + + public RandomConnectGroup(float x, float y, float r) { + this.x = x; + this.y = y; + this.r = r; + inputZone = RandomUtils.randomPosInZone(this); + outputZone = RandomUtils.randomPosInZone(this); } - public static RandomConnectGroup newRandomConnGroup(Zone z) { - RandomConnectGroup newOne = new RandomConnectGroup(); - newOne.inputZone = RandomUtils.randomPosInZone(z); - newOne.outputZone = RandomUtils.randomPosInZone(z); - return newOne; + public RandomConnectGroup(Zone z) { + inputZone = RandomUtils.randomPosInZone(z); + outputZone = RandomUtils.randomPosInZone(z); } /** Child class can override this method to drawing picture */ 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 4d7d29d..123feae 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,8 +22,14 @@ public class Eat extends Organ {// Eat这个类将食物转化为能量,能量 @Override public void active(Frog f) { - if (Env.foundAndDeleteFood(f.x, f.y)) - f.frogEngery = f.frogEngery + 1000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 + if (Env.foundAndDeleteFood(f.x, f.y)) { + f.frogEngery = f.frogEngery + 50000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 + + // 能量境加青蛙感觉不到,但是Happy区激活青蛙能感觉到,因为Happy区是一个脑器官 + + Organ o = f.organs.get(0); + ((Happy) o).happy += 200; // 找到食物有奖! + } } } 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 198924c..f2b2506 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 @@ -78,16 +78,16 @@ public class Eye extends Organ { for (Input input : cell.inputs) { if (input.nearby(this)) { if (foodAtUp && input.nearby(seeUp)) { - input.cell.energy += 30; + input.cell.energy += 500; // 所有的硬编码都是bug,这个500将来要参与进化,下同 } if (foodAtDown && input.nearby(seeDown)) { - input.cell.energy += 30; + input.cell.energy += 500; } if (foodAtLeft && input.nearby(seeLeft)) { - input.cell.energy += 30; + input.cell.energy += 500; } if (foodAtRight && input.nearby(seeRight)) { - input.cell.energy += 30; + input.cell.energy += 500; } } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java new file mode 100644 index 0000000..ded35c5 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java @@ -0,0 +1,40 @@ +/* + * 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.brain.organ; + +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Cell; +import com.github.drinkjava2.frog.brain.Input; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * Happy zone active after ate food + */ +public class Happy extends Organ { // Happy器官是进食后的产生的快感,痛苦和快感是条件反射形成的前题 + private static final long serialVersionUID = 1L; + public float happy = 0; // happy初始值为0, 进食后将由eat器官增加happy值 + + @Override + public void active(Frog f) { + if (happy > 0) { + happy--; + for (Cell cell : f.cells) { + if (cell.energy > 0) + cell.energy--; + if (cell.energy < Cell.MAX_ENERGY_LIMIT) + for (Input input : cell.inputs) + if (input.nearby(this)) // if input zone near by happy zone + cell.energy += happy / 10; // 所有的硬编码都是bug,包括这个2和10 + } + } + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java index dcd05f1..d92d15d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java @@ -16,19 +16,22 @@ import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; /** - * Move down frog 1 unit if outputs of nerve cells active in this zone + * Hungry will active cell's inputs, if frog's energy not enough */ public class Hungry extends Organ { private static final long serialVersionUID = 1L; @Override public void active(Frog f) { - for (Cell cell : f.cells) { - if (f.frogEngery < 10000 && cell.energy < 1000) - for (Input input : cell.inputs) - if (input.nearby(this)) // input zone near by hungry zone - cell.energy += 2; - } + if (f.frogEngery < 10000)// 所有的硬编码都是bug,包括这个10000 + for (Cell cell : f.cells) { + if (cell.energy > 0) + cell.energy--; + if (cell.energy < Cell.MAX_ENERGY_LIMIT) + for (Input input : cell.inputs) + if (input.nearby(this)) // input zone near by hungry zone + cell.energy += 2; // 所有的硬编码都是bug,包括这个2 + } } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java new file mode 100644 index 0000000..ec464d2 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java @@ -0,0 +1,48 @@ +/* + * 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.brain.organ; + +import com.github.drinkjava2.frog.Env; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Cell; +import com.github.drinkjava2.frog.brain.Input; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * Pain zone active after some bad thingg happen like close to edge, hurt... + * + * 痛是一种惩罚,表示青蛙做错了什么,但是又不至严重到判其死亡的地步 + */ +public class Pain extends Organ { // Pain器官目前激活的条件是离边境20个单元之类,痛苦和快感是条件反射形成的前题 + + private static final long serialVersionUID = 1L; + + public float pain = 0; // happy初始值为0, 如果frog靠近边界,将增加Pain值,将来如果天敌出现也会激活Frog的Pain区 + + @Override + public void active(Frog f) { + if (Env.closeToEdge(f)) + pain = 500;// 所有的硬编码都是bug,包括这个500 + else + pain = 0; + if (pain > 0) { + for (Cell cell : f.cells) { + if (cell.energy > 0) + cell.energy--; + if (cell.energy < Cell.MAX_ENERGY_LIMIT) + for (Input input : cell.inputs) + if (input.nearby(this)) // if input zone near by happy zone + cell.energy += pain / 10; // 所有的硬编码都是bug,包括这个10 + } + } + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java b/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java index 9419561..7e08a01 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java +++ b/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java @@ -20,11 +20,13 @@ import com.github.drinkjava2.frog.brain.group.Group; import com.github.drinkjava2.frog.brain.group.RandomConnectGroup; import com.github.drinkjava2.frog.brain.organ.Eat; import com.github.drinkjava2.frog.brain.organ.Eye; +import com.github.drinkjava2.frog.brain.organ.Happy; import com.github.drinkjava2.frog.brain.organ.Hungry; 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.Pain; import com.github.drinkjava2.frog.util.RandomUtils; /** @@ -45,6 +47,8 @@ public class Egg implements Serializable { public List groups = new ArrayList<>(); public Egg() {// 无中生有,创建一个蛋,先有蛋,后有鸡 + organs.add(new Happy().setXYRN(300, 700, 100, "Happy")); + organs.add(new Pain().setXYRN(600, 700, 100, "Pain")); organs.add(new Hungry().setXYRN(300, 100, 100, "Hungry")); organs.add(new MoveUp().setXYRN(800, 100, 60, "Up")); organs.add(new MoveDown().setXYRN(800, 400, 60, "Down")); @@ -52,9 +56,7 @@ public class Egg implements Serializable { organs.add(new MoveRight().setXYRN(900, 250, 60, "Right")); organs.add(new Eat().setXYRN(0, 0, 0, "Eat")); organs.add(new Eye().setXYRN(100, 400, 100, "Eye")); - for (int i = 0; i <10; i++) { - organs.add( new RandomConnectGroup().setXYRN(500, 500, 500, null)); - } + addRandomConnectionGroups(); } @@ -62,10 +64,14 @@ public class Egg implements Serializable { public Egg(Frog frog) { // 青蛙下蛋,每个青蛙的器官会创建自已的副本或变异,可以是0或多个 for (Organ organ : frog.organs) for (Organ newOrgan : organ.vary()) - organs.add(newOrgan); - for (int i = 0; i <10; i++) { - organs.add( new RandomConnectGroup().setXYRN(500, 500, 500, null)); - } + organs.add(newOrgan); + addRandomConnectionGroups(); + } + + private void addRandomConnectionGroups() { + for (int i = 0; i < 20; i++) { + organs.add(new RandomConnectGroup(500, 500, 500)); + } } /** @@ -87,9 +93,7 @@ public class Egg implements Serializable { if (o.allowBorrow()) organs.add(o); } - for (int i = 0; i <10; i++) { - organs.add( new RandomConnectGroup().setXYRN(500, 500, 500, null)); - } + addRandomConnectionGroups(); } } 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 508631b..c6317a3 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 @@ -58,7 +58,7 @@ public class EggTool { List newEggs = new ArrayList<>(); for (int i = 0; i < Env.EGG_QTY; i++) newEggs.add(new Egg(env.frogs.get(i))); - System.out.print("organs =" + newEggs.get(0).organs.size() + ", "); + System.out.print(", organs =" + newEggs.get(0).organs.size() + ", "); FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser"); ObjectOutputStream so = new ObjectOutputStream(fo); diff --git a/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java b/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java new file mode 100644 index 0000000..8f253df --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java @@ -0,0 +1,14 @@ +/* + * 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.env; + +public class CellGroup { +} 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 6249053..5f514c5 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 @@ -31,9 +31,19 @@ public class RandomUtils { return rand.nextFloat(); } - public static Zone randomPosInZone(Zone z) { + /** Return a random zone inside a zone */ + public static Zone randomPosInZone(Zone z) { // 在一个区内随机取一个小小区 return new Zone(z.x - z.r + z.r * 2 * rand.nextFloat(), z.y - z.r + z.r * 2 * rand.nextFloat(), - z.r * rand.nextFloat() * .02f); + z.r * rand.nextFloat() * .04f); + } + + /** vary a zone position, size a little bit */ + public static Zone varyZone(Zone z) { + Zone zz = new Zone(); + zz.x = vary(z.x); + zz.y = vary(z.y); + zz.r = vary(z.r); + return zz; } public static boolean percent(int percent) { diff --git a/eggs.ser b/eggs.ser index 29b6de0d412ba5ff34ffa25240dae87899c5fe1d..fa1238a6dade32b526d3c580a3e6bd125d0db522 100644 GIT binary patch literal 159278 zcmeGFc|2C@_s5T$%Z*5>OeynF2t^t0eeJc7$W)Y6rbH?vk_J&yNh*}mJkOeFo{#3z zJRl7!&66e?zc<%*&ij4d?{m8R9`DcZ`~Bnectq{{zMuQG*1m?d)^+WDZ+#^tKQ=+C zO-$IhFw3OG5u+?gLPA)I*NCx+~eo8*1 z9}zd&GHOI(bW*tGu!Iq@BO4$#mctX`qAVk$qAXpbq9pHZ_#-VNCF3Qf5S0*@6hAgm zO3ka`omLH}vuZe#qvW-?gs8CCv16oCrDVs)H~wz?WaG)C#{Yi6squi5mN-j2RbY!BG zIyGceSZtJ4zeI@(q8ueyqhDeN#l=ScL6vorl1`BP9WVKtGCrO^BP9h3rKHeGc#Gs$ zqLlpac1Ucu_~jX>?Y{Ba(M>2mRsBjX#q+_K>`*zV7#k!$*h%XlQv2ez5k4t35b`Vtr(RzpfN7_ zUwrf@IQ*M-xrX;P6Ymu{JdsNOvv$elg$cq-l3$5Zat-g5;H{gX-hV_?^k4A9{>+ze ze6!>P=8PwB4f{{@AAe#<9iH zKP+}w+-Qi4jg5>*bZ;1L1eKC@Bj+ZiG$J-WDRDq#gVWrkl;e^TfB&zSlw#wH4P7%) z%EU`@LMuA9S^Y7#Sv8DpR*j>JRl^%41DA+G8vfVNt&Ao8|JNfE75gWBf*;_ETu$jpLw*w2a(>M$jHRdgjw3+(w_jd{*H{Q2s=DWm`U>@^y-P&^%l_tz0mV1R{b^Kugau3$Rw%T;z$jEkS7*X68R@B~UxYCvlKkWYf zU#5-6{^BH39dhEu$+CLl>9r;TQvK2x&^)me_G-PQM>zZUl{h%V4ID@9`74Z+l*D8y zsfND-W}f#6$QOBF+phJ(kv4nX`Ln@&p~uKfcFdBbgHYGf3e4Vc0%k^DB6>xi!8TK# zvttV6GGRfQAG(`0HITNY8aQNo1@Io{n z`h;rnzU*ppt9tQyDQ^ikTeyzgwhei3xtlC%AM#?xh!Q0V)cBQu7}_YdO>SIU9@H8(-c5io?K zZ@OdOdT(Y7nP0RARC-^7y6?*=Mx5jt3SUM&hPdR8?3j#&<^06?OQF^^hhoUWptso8 zQyz|fq2m)v^CRg+ju?FiU1MUz<#_vwTQszpCS?a|VLn!H?H zc$TDziK=uMW>TYWp$IE>K8NF`ohgRP(X2t0tj%at(Vkt+oXT1JlPia?T`w&`&8!6( zPG&3RJ&9OYVM7@h6ALP zP#>D1X3VWau(S9h+*$BNP?PQMi`wIEqT+IWW;NotmTA~tYah0})HJU-96yDO1 zJ4X9N7!>m*aB{*Yis6h-bi~NbhWv~d+u1Qz)tfM)n-a{Le?h>ko?{L@W`$rDV2kdKw5uiPo;cQSvfSqq~9KH%rQ%p<2aah}}C@P(uoHVa)ug5OsGt zJ4VZ_FLsS4z@?iBYKm+xV)WP6koK|}fk{fS2UM@K;a8is6Vz~yX|RlQ;7i`LVOJBG zl@9YhSAs&mFcuTFmpforxhYK9bDtffG%OV~pYB2P-9pzS%F*|*eb0RmYf?tbFEWiZ zNi-rQ_2;ULbK?Q$#y7P1Z}p3YxLCR2lZ|gt`ERv{hPSBx{uZ?+O2hA_KMikDZzQzg z|4a7Y@UlkZ%k7$8{@47y;pGmEFKafw{HOf8;bq#GlqNjBLa5qN=54f)dHrUy*joy5)WUlG(%19mbd))#247* z-cpL;T8+92_YxNH`K#M9t0ChjRibRgc^omTDG2h6C`a`xyP(wQBRgh5Z7zRq=vI{a zM1xb2OY8hjyp*j8T7>&EW4JG8x4@RvWQ@Odk{U&l?^j|}yKb0R|B4wymS4V)QibM~CKy9yZb~PU_wTFk_-@=A|Lg|2v zX*~*E9%+*GR@ay@L@6``hMRxKlLq{MTxm9eji5XzH` zb;r=B7lBe+IwUg}n>J^Vq@M0nLUAp*-m( zs>j5>wWxl9>SIyEm7k6ShjsJ#4N-J-5fP17;W)^kCCbP@U{*u2s?{+pYZi8}4i;RT zZ+-!mA25aN5L&)tQA3Pwl;Yr#k$m-mt^#Jz`EfnU7+NK!rxT%Q2UyHzzP-#QJZoF=68|$W!=2 z)rhYw%f#ecpE)-ddW6L{Wd5)?Sp1*_ezs4f81DPz$LLz<4JIYDU9(`s*UOHf{TXHW z_>#^_A~Ln|0>)jlg8iRp$jE}>hE)V%yn`-k9N9W_DVni<3DVV7PC|6Z6!S&Skb&(!gs zb2YGEppk&#<*s6Q&kx8+JFu(C_UwbM9Q0Wrwii79zyqQ3}lJ-Hch2SgNA@%`C`E5Lz)=QRoNF*ljj5Rv14xPGS^z9}sc z)TldY!PmV0Q0=;EeB&XR#-EMR^q&(8XgmOoZ}=y%`2Rp+vBF|K+V*mU=hAdVKtz%? z>rqua6(jmZG+ri_{wuy2vl)Bsp9gspg;|I!?XQjM-T~0org3$JV`h=b_1^H*cNY3Y z(+awXg!SDE2AzMv2kE=)7}Jx3QKd)?$Hz1^)Ci+;C|Qw-YIlnp(l7QHkK}C2M#IQY zVENXsQGkf#FYE>*pSD0#*I$-v;}4Fe9}*X2m4b#=0F3LtoF3s!u|DTEx9Jx8my-wSgBSDVXJ&as9t7g^jN=aNI;8izC^tTG(}wC&(kNqXNyNP}dwok7RYzr*~#43`&|Nv=n0qE0}7 z0Cr2Ng!hvXV@iLm=68&?YBH*fd&{3YxJtlu^bCTJDKW6sgAT<^YSP!GqJ6M8DxK*g zU^>tCgwe_z+AM8GNUo;x1~y8!MIR3(is8*^0T+uF`~Lmh)nJUXHTPmu^`LQJ4v^XRsrlo>-7l^XN%*Y)B3(t}iuIPYr)|90|280SHo0E=(9`=gF?Cs%qvVO5D> zRL)s{l=^v!e^oq{Sq*2j)Ead!&c=4%=qxYd?!0;rJ2&5g4c9+2W5g%B=;MIQGQRGO zyr9NbEfp4z>x(86n$a0@R{n&Pgam%zP?}YUxU#4iIDfkhT86J>R>Q4~&IR{l6W~xu zQ)Hj6l?m^nuVa+@M`n!6@--dcs%8sRJ=wIHXS}Z?RH+s~%$8;ZGyaoy@zs*dr-RR2 z>KkspUKN?I`VH1QtYcQgZJPHDwS&iFl%-Jm6`vd^g&KGb*6HkJ#*if$&KMNN!&RA3 zs)l6O9E9TX*XS6)-foC|%}TVaQU_n}GXh5Hvnp>py%@WgZe>=(ZSE0+n%`QZqJcEU zaPvoBL$i`3^eb*gk$!xH9flOX02z7eP!V_Yavl1e%K$xt6lOJ~d;AmZGV3*tb{i!a zHQi|%8YmxwbGo(67_oTzZR{KB3wQ5D3z!+ZYf;W)E8LvYj5%*|m=noZS&iW}T?CA} zQzF_KMq}a|_O40%H*CP@kRXhyn=D||7GK1~nVwLv^Ek6nBq!?@YD;FekJD&{M?|Lo zT*&X9q5_FBZ`d&=JBCA)Qwn5f5m$L$9=jaKfq3ZZE%?*0|(#DmdZYco5> zY2JG{(DMxVccjwl zo1*iWHS8FR94pkFbpvj$ze6!Z@9r!3t>_BOT`$9qX&F>bzFx@(lhS+v)9+OWG^?J3 z#=cwr4l{CG<-hDZRCwixVX-%%GPS9C>!x`Yb?&Jnrds_SChgz0FZSpk1D~et0e2Y_ zLCpk@N>sU6&sR@t#!^Ps^aRwqKL@>fQWHengXkhCxj7s52}f9(AJ==CHMlFvW7mN+ zYLQ&GrqPH_#GM;t4S8d~@LEUav13#}E1^`~j?*pu|soNIRm4w0~I-)4N5jWWO&1@6`d&X9WfS1t#6N)gR4|t5f|! zmj9N+kJ|BA@J)iEC)90k2a#JoF&o7VoO~FydR_pv7rO<_sIABNxo6+P5v#-On6Jys zq3S{n*s7=qn8=$YC>@dq^H10_V@T5U?bt3`vT5*K2E}m7lBL1inquU)v0rd9CnOKe zHKZ}hccGvr-{&l9f0BY5ammbTxW}rcB)n7#Hm#=1C?f95ffJ~*X&y?KG$U;nhseVc ziyGjo-2|iT<7?3K>~k)_JAqjZSz*5)UB7RHH!^(%qec&CgN9|(u%*l%c8tXpBiJ>s z8qL=KfpZfQ)*idgN zEDf!NPfwe=rbq5%4Bh$-qfgN3m<7Yhp8d}6in@(bw~DA5?%M<u`6h1aamBaHz*WcKJLNxPiUCWVid`H zHjmFaH35oB>L`Y|C5GbY&N|rDq8GCo?t}a__<8XX{B)ivsL9d^hN|{;(8JD{8AFnC zPs7Qwx%_cQVV-ii_tPDHLRO=SlOZ#PJNH1+^e-HPCmz%U5t(s(9Nf4Szz2OVXU355 zDZzYOn=U9)+$I>6vC|ggQdhyYgV)(H3sUt_Se^stYG$xwqW!%1 z85Or6|9cZA^T~D`xHtm4nOgiZi*sqr;#?X}_fHo0f0o5bavkYY&C9{KRbM25&*|mZ zZ-0T%KH}EfL6pV@jDOg;i;q2dBC|HuK)7)LwD0dAupE-UqidQmJkE$}5XYWuaD%UJ zg)Sw%VC}%M0xLFAvd7wZ2*#Xx-oR=`CBwcZ1s(1`0*!k@2|_$d;Sg$!OMuHN4;$%B zW9LE*f2fxphnC0RQ%T%K1s{s>;dz}48aaFgwhpvRsS}eb)F2P?P>A+ zZ`8z0YMMnxXk3K{>tW}<`ppTT`}aH5sF1* zzEUi@T05fC^+D`LP3-)YFMoLgDp%0}PecY3UqT<9I_#N4y~U!2$ceXM@0b1I+V-Y7 zH!0~59LyO3YYQBi)o{H(dZM}Xa#%d0spP4Dt{VF|9w12`Nz541ZsaHzzI__He5Kir zh!k|whVr88a5}sh?Pi*tEJhCr#5PB0L@(kJFSw(7+hQh*=HEP0fdCua2S2{Evc~V_na~)!YbjUz68 zRE^m5w?$}nMF}44IK+;zSgDKsV`}-J0XHaysLY=W6|ZZNw_v~E+%})%aH7R`e%p0# z0i*o%D-K@Z2_ND$*wxH0x&;nrJA++%Q{_C3B(qqsG)H_1tx%}}98OYf4s996PMq>PT1j>QT0C?%NkTu$a~YX{|5E53;uS{EL3ipDv@STujNu;o24J7v{^Y4kPl_Rm z3D2?jrT(aD?a7WQSJ8x0j6tRKmnen{FY<(xxkmiLgD06WBu(rNQx8-?#7|Q}%|d<` z4vAfX{XZ;X$Aov(;S*AZU|aqZ3$(Nh)8_sw|L|p)I#h78t^dw9&I#FP+*}BW9?EVSn^=+z>ck*n_dmAr?6`Sce&f*&))qMnZ+hYPhQiLQ$ ze9Uk)toz&=+h=xTR>P@u|AeL++Q6wd%cyU-&)?I?`7Vj@WK=UkUwAFg7ae+lmd7dt z%;`^i`5zUrFy?_5vl`+U)*fa&If)iugkY1);$t9j;dvYwy_p%qt=qxDihe&~Yq#}O z4KY(*3aJl@_}YsG%orkCCb@f}Bn}Se_oEo`{H>RvQv^ayN+>f%thIOpJe^REdP%1# zhFe=TmA`Fv5@olqVa9Mz&*osfbYaTZ_QXvThZq%#;qC$&)wS#M(uoM$hSO@j?Vkog9gGoe}>@|-{5uV z1d1VpUm)b&TnP&*>Ab_#84@2Ez+UGQXm_?+P}3pF9Z0uy)N<_2>|!#-b^-tJzzZ}P zB9tLGue@~hl+wUVHM1DSVc9jAA z4zDg0L)uvKykqJh3_0D5t~qq80d+SZ9PSCv ze+UzdnzKL_e zICr;zX*s<=d~TNmL7khCT^J8CgL&r$KiQ+ z2~3(AM%8ffUoug3mKOSlP&1h@wTFGsM13>{^r4%_L}bo^Xc#ZE5Tjq!GrO3xyfGI$ zJLTcnecuJ&=*X-<-O6LIMer7j8q&UMC>-*L!Q`$&9?0pwx`w(%K9F^V22MX^BC(IR(2AYT^^?LOsXuW19$M36QNv}P z_TiV$oCop7)S)6GH|HqY4L{5ubsoyD#`lXhx_o(!YRj7f6QvWg;YrKO{A}6f%ox(T zwHq4fx5sgI-RYGQr%SHV(67EY-nQtM3EV%A9QZ#;;F`H?!GZi$ShYVHwMu%?i%7<% zDx!uj;b+aFNB*K^PTYOtkF6YJl14hLY;6q(@&{53SJZ)rl*31HT>T^FCM6EMv=&E) z&P3gsV4+DB?0f>p46?DyqF81OiCKIH=9L_T*oy5GL#Dh~3D>*>d1A)iYsvCf{bA6@ zR~UCAjbgajujAm|%dU`RSj(=)(V>PMc|DT9C?#}$68L62_AB#5uXy(2A$Q*G11gcj z@GaX!Flx!hK-jXT80IXv$F8Qug-G}<#-i((usEfj&s;_0(6DcBtSi&`;bxZU2gmt^1`Sb%MDC9@h*FnSQ|jkt}yTD7#9Hm-P(HLD2AzH;7$rY!BuT)jF!y#dBB;Zk zGWp?(>#_aoYXT-PyfY5ED-T7X?Aa`ls(FSZ`j1A7yllZYEsrVli#pY!P5l*SqsY7i zmoTB{eVElVpJH5s=c_`dLp0oU`pAx1WK@OSwpYSHU15R|cWh;iBdyh;R=tWHW1qSl z3UU=t;c0)WhA3aIhRY8^`SPG<6b#zf+rc+cF#j-c2*q%=hvTt@+eav9Z^f=Abjw}z zmmP^#ubRf285d8$Wu-N6xQ4cCrslU?Z6o%cDGwhFg@OS$y=6NLu!)1NN`E`~{`*+m zb%h61oN0%$2ZXX0X`vT{c4OmEL8$bzs3BJUhoJM@VX(@DPA4L6o83?t6IcNkw$V*N zEEuk~jXN5p_Jp~1Z-gtg;Kwk&bbuHw>uFTTf+49ZogpvcCp^$^+K}}9>mjI|Yk*z$ zvHM0mUFju`={N)j=FxdTM0)Rhi;81;SgO95{er6{bNsV*8(~;zh|q3&-&5l&6P=;D zhGWOf-KmQa+%%|}D}>CP)0tOjKXU<&zuS!I?pvGhKosPl?P(3c#a$oB^U5uUp>Jt3 zwwa_{S;j}*Ek*O>O@dK7+Dyffb7GVe+{8+KIB1uL2C{U4k;ymh)GuP^d%5T@oQ8nT{?j?{n5Kww6jmlYE%xS+~ z4Ra@}fmeqwf>HXBL9oZ=2HfrA&+Z%R@zS&uF-^E@2MA}F}P3g!g9CgYDq&?Wx zaN{#J!|4yE*m2K!0h6-&GCXU40X;#ASq-+!EX9(fD6PW}eDN_Y-B{JfRu+ ziG6Y`T5c~#$Kg!@;?jAKpi1otT$#hZ+D1Hwr=e<@0be^jof<`?GvxUYV-a7_mpzu^ zif$d@r`$AzdHu2k%rsp+m|ZX%Bi?Lf_6_0dr9mWFQ404OMlsy7fxQ6|B4NduBxVeE z#(yuLIqwU0x)Ve(;!~36C)%Fbj#9SM*fC*t@8QnK?&vp*Mnoc#v9|!ZlbcX^>tJRK znUyjW7JfYshl_+EoqNjffEK2@=x9MpVoaSO|Ajn1?eS?e##7WNZU=vsKe)&cN9}6Q zu4bmP7c8kON2kZ~0!Ce=3*`|V(EP$tW{kKx$O%1HZ{xEM(2AmnoAvT1nok)7ymKSNSs>BOQC9(WR#XrrQon^lTplCX){`V~FAVwovI@2zh}*pCbAv{II`+G@9w0 zW5=Y2b;9^HNlr1ji_=I^>e z&_1(Y=5GHiO#R<2Of@EOjZ0L${_b*)@|^I;+7g#n0+`tA8*1&(6q`S@=?1U2i=6k*`N;jpPYd&eV%=Qoo5h8^KUA7L0E zkXr((dmYhhO*0}p{njm^e)|o$I*FcJ#2xgh#e}F?2nuwdeA`T<0-1x;4wb_lzyYmQgHDZL!WZA65fL6+N#hY`G?8=8@A4-|kxO9KE14?_S zfLinuY81D5nj-`c`ha|M5>ma3Y7is40Tid+6nxWVhcmp$cnkH<*}EpU^wC!|n)Z!9 z=P_KsC@aKc(C3d}wQ(P_QQY0gR7e@4j<>n59r_Z7RvRS!i*sXVm}CqmwZjt zu44kGozhpR(dmWe94$>Uwc=#m96&D{Y}0!_#fbGDUVyKXn{#V&9x$unHuurN5cw)H zJ-ul>OgHjHuRA4ZHt9G!=9)z*wt8WKqp}OB8cuEaP$W0s^9Ri~Gh;}S0zvK4Tr{Z@ z22rxK+b|S=(c#UH(P5v-H-S@=;KKA<*j<@+L=kB>ZUfBTy9uf$A+s88)%ulaMy_Fu zD{Unr?qsKd=&0d@-G+p*V;naug{-t#e(rE1>KpNh0d2uCPaA#t+sqh}J9#TCTKobk zN)}NJ7yI)hCZ(Cc`TawgG2)@ckI-tEC3=UorWg`Y8;)bK6pij(WyWwBb0+gg6)T`- zuc?5UDSM31Ggp@kX0&@SU8$*CYSCP|7d&-%Enrd$tDuLME%pk(#I9z}QW0$Zb`|Z@ zcL=5O|(2{VgP+$~o*41Fg; zS%uDmnt0{+&^JsUjtrJ#R>NKRz8535tl?j~JQXlbLroxizcI8)oy(3Xn>P>pM|h+1 z?}d!TL7uS8v^%y=q9YKKQM!kuaL~LEj9he>s^NYw{*A!Tbh?(}J3r^S?s;k*OH3{hnP-kCT?L%*GEz z<6|jCykn;f+$r@&y^c7(@er+8N;UjxTm$+qUwzy#ZU3_<^#A^%5SgQY5JMK+N0_T3 zw2BRL$HA9ZacKC?v*9Y)F*gnI);vQP);bhN1l|!?Ne?cdY2Z)DE2m3NOx)h^qxk4gt-HALgB7~blQL6^6~1T{1JeMR%=*?gx>k?feR3k}i3 z?-YM#X;WO*GdUQC_NbS99jofEFw+*M(Q}LU$t{AlQ^c@gAdSLA+}=5na6F`TjODJ#4Mxa^c)<4xXC`08%X0G5tnr!65QHP z#*Q(`%oq|IREAo*yZD*{Ye7xGJT;8Vd4+8a=^V#$rMP!%$09L42kw5M6vN$dmh9D< zYmeiOP;W6|ZkM&-O?KPEtRKSsO7i0`W0$T^`IlMENc?3V`@yd6j_`5#M5;!->EH?2 zc4P(g+qH<@H<=HEVL?VZOpg~93W!xNbufF)!^L?P%oq;uJjcjU>gauCq2L>>6_)7g zFpvK}-i;k2v+Edy8cMcwNjXpqv0eWhLl1qzh_?~U7~;|D8DuJ2qsva(^hKP^;$!@) zAw1L$E@8%qE0;Q&#EY80n(%nnZF z9OAc^(Hx$o-H@!0&*0<9VbJAT(~{0?hXHWx=>~MV-3&~&brO2@K7(!{vc_Rwd zw`<{uHNBaQA}gHLU_g}xT=pv!FiXnLL-lD}7?aS48ROFDo)7H4tBGyjtQ0Uq&d$Z* zB^elA;?ImBGe$e2;gNDU-b?o?>uCgF|H9T z+i^FV8PEuyMGYz3cn1^RZeqad4b(RzYf^V~le>eemqyWX>z{a@R)qim{H2+V&uC^3 zzlqj&1yoxw1$+NS<5Cef@8UQx|M?Ai@~SKKGd&FC_<62d+=mD9s|4Mn5zo6xUX zi5=77K|fgN5r?e^t$K^dgo7Q>yXOLoh@t5LOY`IwJDdf)@d(mx{1lpJbX6I4?x%>> zBWN#V!n}{R!%^!h_<~t9^cNBFbRBdXIEQa%e4E{VEI>Zp=j8RZCKVvlPUV08S zZZxBWV^=X7;aD!}+GtXY%i6NHm^95v^0bGS%xXv*sax3Uu&;QlZPQYrTNt9Qx+$zb z(2TX=duQKbC%a$>ST|TON`J~0koqzJ`F44KrzTZn+P^GOt#q_SL$`gXd}g13>32&J z=G|I>i8%J}Fp_-Y4-B!3&qsCb)!4zmX~>Vg5QSRH=Rm&Cb!LqCp=)=NV<8X45p+dB zk3ZNk1ea zhQmwII4p)tzoo{mW=YsZ$wS1GLT>tLefX}kT?^w=@O>y0_xN`36CX(V8D zhG>9){0!J}ycxOZk{d;EP47C&91@oANaD*82;;Y6oJIk=n(P-txQHw%Sfe0hI3%}Y zIy~F84nj7vZwBD@{$>M4epYBViK9kw+Bd>D@lF@W9;nW)X5N)Yppy6!o%vaUZ%l0a zq2|7W=;=C@9h0vz9;|CiFxis`m@cVOlH$loIMjV0Glo0mZh?{Ouc1x>jZZ}4+yNP= ztgQ_PTx{7f&zzq@WyUn@F-eQ6;o1&Zhtfm)VZakQ?XwIN#5>RyT|G}?heIX;Moq;V zJH6kC=3)BGYQ&Fg6tMO4Ht4#L4&ah}skes-m&!W^8*=sKjv!!{@=1>$6ZzM1xKi-*CCyT#zg5g(Fjr32GD; z4}#+Z?J=?kJ;H(!r&oW0Mcd|~?pitzNWN94yb6XND941^51EZ3W>3eW z;k?{ph*)kltk9*Y6N?&d$3rDF8hMz1vh^-C%Ef#4N^~m=!;}RF+11#NNxi znkM+hYKSWKI~sz%nf2_Lv~|7tqe0=QzlhEQlDgp5deq6+f_b%*m@zJ;wsn}OXuz*N z~$QHxauX^zutznrZg}VaYNr{@;9^nQ2cf;b2B4-5^mr) z|6DltkPeNKGGbsS)Jq%4Zyl$=jNz6YA!swK94`6OEJ^ZopEl3XCw&(V9NeE7LzYbm zg}|tRpraMs_#w&N78!Puy;XW>o9fAqu~Z$#535;?9s3G_tILc79nfp97+q3n5#(>i zmGu3+gmYWoeuYl{7SJ|B2#3V&hFc?y-pD^#$R2Tu&)1sZ@T)RtR#qi|)2_6~_*vGd zlFvRMkR^JLG4aK3P`_&(#c)$&($QjK6@)yR@^`+OX1(TLg8JSG2`Fye4%>|vf-|n) z&sI33+ynQek}t^-A7sXGGi2Pb$Ky=w`NTuO8yJ7y`W|Yc0^$3MEL2EI5EUglYxGk0A&|0j8ip4Zs`f0#e04%RQC@i~hcGAdH?RLQMc{JRHDzS*c3%-hFK!9mX5 znbmM5F0)Z-+$+fQ7K%^A_Tyq6M9%1Qz?>OF-0t0n{dy_zTMOD|MZ~`UHyoX}4hE{x zcFkmz(#`X*^UD&@$}ph55g&KZ1gnn~sGcQeSJUt5F@A8b+t}8UdO}2cWL`ttp5c5z z%`EEkh*+*pN7En1Fh{W&14Sn}TO9P;V+?8IM~xyA25x}|ae=Vm z4Rtz;Z@B3y_o1+x6{3Dq4;TA}q16(AxWZ=44C?-8`ROkvfVoc7su{}F@de#>NS*^n*UC659JUJl2e<}io5wapi<|RX!W)e#c*=s5zx~p1iO82 zM!T7*&|k9Y#|iEXeZMcaQ-2-J*Y!kr=1bh7`~l^<8lJf_H{GH;?duRV)UUi*k#5E0h6@k8ozsbEXtGh z>_+88K0#H_(HPTVlz{2?qciv(D@LWEFPJeT;;sl|?d>r74xN=mobup0R8Vq4vnkEU zaBHJ(Vb{0=IPyq8K~37M;b2g)5nERJFstFxPJKWZRT&)7L1;I`>)`{~5pID&T?hR# zZ{iv^TXBu2`)6;}|7>p+eVUjgTaq2hd?ktH8!42t;7HjUTG0{_BkxEU&{DFiDdjCY zrqDMTIt91GmZgguKO{-(uW#lbZrOx`Y`(E$Mp!ywhjIR>Sl*PjeQF=cCq?ALy3t2} zg-O(UBb3A^lnh4~|ly52G#(nn^Z<2)J|h&bu+ zU8Lfg67Mr?4?AW6yzPbT{5 zpp9fjHmSZD(OAk%H4N{r2wN9k6TDSu70Tz?>GBuO)0~HCa?ZPS4@0*XqLwoqHY96! zJLO=-(r3^zoX%`am`6$a{IQ;L*gBGq%p#)Gw}{s-(1C-6*BY8~gGO1p!p{OE3)ZKC zRjd=g_JokJbGbdYqQR!_=w0l<>})Q}x)LK?C6D>+t4F=W$@zw(eDz^?znTWaENZyd z`9W}dr3Zng2a|9G#`i#OdjWR(Jb_saQ46X>@9GI?bWvJR^Ti_;p7Y_bZ%{fjhI5>e z&(D9g8Ewu9l|YgjR)<~goyM-igP1YIcY_+w5A;XP^jNCKWsm9xG|?*Ht*h9(1sS}x z8V9_3h+!RiQw+&4w1K%l?J#N``;fuuIhDYVb;cOFrm?L^?y-T&4>(4l7xEttFdN0G zN^Z<)w^kPNrZ)wf#;4cv(>6I`+{pxX%rxabFu!;{D(Rl4MsZb+b~xs+pX7ld@0l?K zYx|(?&ht>FU`jF03&(YW)3w>q-GN>^rsntQRXU2wZ}H{_o2nUh=`$eghYq~mcZ6L{ z<^+E}J1-I@`MOdyE_JVkdM%S#1U@nYL-;g z;^+fnO!B9VO+@BBaD!SSP1yL2eb^!)4~ig+e}diIn#P;4H{PIUmK2gfmh5WulG8C| zl@VMXxKi-Vit)a%1dRM!PxM_<4nMn2WyTQEl}p@I zSvw3ipy`^3L>nJO;|d-Fs&&~hOCI^b9qo-Ut?n~b!?h?T(EhiZa1G1ZF(X%N@>R#T zLuImH6sOZQir;Se4F^>|V8;X}%;k&rI-&bDcR@{1h&NiYcaP-E