source: js/standard_expdef_demo/js/simulation/core.js @ 880

Last change on this file since 880 was 880, checked in by Maciej Komosinski, 5 years ago

A simple javascript demo/animation of the basic behavior of "standard.expdef" experiment definition in Framsticks

File size: 14.9 KB
Line 
1/**
2 * @file Simulation Module
3 * @author Patryk Gliszczynski, with further modifications
4 * @version 1.0
5 */
6
7class Simulation {
8  /**
9   * Class reponsible for the control of simulation flow.
10   */
11
12  constructor(world) {
13    this.world = world;
14
15    this.genPoolText = this.getText("Genotype Pool", EVOLUTION_METHOD_TEXT_POSITION);
16    this.mutationText = this.getText("Mutation", EVOLUTION_METHOD_TEXT_POSITION);
17    this.crossoverText = this.getText("Crossover", EVOLUTION_METHOD_TEXT_POSITION);
18    this.cloningText = this.getText("Cloning", EVOLUTION_METHOD_TEXT_POSITION);
19    this.mutatedText = this.getText("Mutated", EVOLUTION_METHOD_TEXT_POSITION);
20    this.offspringText = this.getText("Offspring", EVOLUTION_METHOD_TEXT_POSITION);
21    this.clonedText = this.getText("Cloned", EVOLUTION_METHOD_TEXT_POSITION);
22    this.fitnessText = this.getText("Fitness", Config.Simulation.Element.Position.FITNESS_TEXT);
23
24    this.world.scene.add(this.genPoolText);
25    this.world.scene.add(this.mutationText);
26    this.world.scene.add(this.crossoverText);
27    this.world.scene.add(this.cloningText);
28    this.world.scene.add(this.mutatedText);
29    this.world.scene.add(this.offspringText);
30    this.world.scene.add(this.clonedText);
31    this.world.scene.add(this.fitnessText);
32
33    this.state = State.INITIAL;
34    this.timing = Config.Simulation.Timing.INITIAL;
35  }
36
37  run() {
38    switch (this.state) {
39
40      case State.INITIAL:
41        this.showText(this.genPoolText);
42
43        this.state = State.EVOLUTION_METHOD_SELECTION;
44        this.timing = Config.Simulation.Timing.INITIAL;
45        break;
46
47      case State.EVOLUTION_METHOD_SELECTION:
48        this.moveCamera(Config.Simulation.Camera.Position.TABLE);
49
50        this.timing = Config.Simulation.Timing.EVOLUTION_METHOD_SELECTION;
51        let randomVal = Math.random()
52        if (randomVal < Config.Simulation.MUTATION_PROBABILITY) {
53          this.state = State.MUTATION_GENOTYPE_SELECTION;
54        } else if (randomVal < Config.Simulation.MUTATION_PROBABILITY +
55                               Config.Simulation.CROSSOVER_PROBABILITY){
56          this.state = State.CROSSOVER_GENOTYPE_SELECTION;
57        } else {
58          this.state = State.CLONING_GENOTYPE_SELECTION;
59        }
60        this.evolutionMethod = this.state;
61        break;
62
63      case State.MUTATION_GENOTYPE_SELECTION:
64        this.showText(this.mutationText)
65        this.hideText(this.genPoolText);
66
67        this.mutationIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
68        this.mutationArrow = this.getArrow(this.mutationIdx).mesh;
69        this.world.scene.add(this.mutationArrow);
70
71        this.timing = Config.Simulation.Timing.GENOTYPE_SELECTION;
72        this.state = State.MUTATION_RESULT;
73        break;
74
75      case State.MUTATION_RESULT:
76        this.evolvedGenotype = this.getMutatedGenotype(this.world.table.genotypes[this.mutationIdx]);
77        this.evolvedFitness = Math.max(0, (parseFloat(this.world.table.fitnessPlanks[this.mutationIdx].fitness) +
78                                           (Math.random() * 20 - 10)).toFixed(2));
79        this.showEvolutionResult();
80
81        this.timing = Config.Simulation.Timing.EVOLUTION_RESULT;
82        this.state = State.SHOW_FRAMSTICK;
83        break;
84
85      case State.MUTATION_RETURN:
86        this.moveCamera(Config.Simulation.Camera.Position.TABLE);
87        this.evolutionReturn()
88
89        this.hideText(this.mutationText);
90        this.hideText(this.mutatedText);
91        this.world.scene.remove(this.mutationArrow);
92        this.world.scene.remove(this.evolvedFramstick);
93
94        this.timing = Config.Simulation.Timing.EVOLUTION_RETURN;
95        this.state = State.INITIAL;
96        break;
97
98      case State.CLONING_GENOTYPE_SELECTION:
99        this.showText(this.cloningText);
100        this.hideText(this.genPoolText);
101
102        this.cloningIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
103        this.cloningArrow = this.getArrow(this.cloningIdx).mesh;
104        this.world.scene.add(this.cloningArrow);
105
106        this.timing = Config.Simulation.Timing.GENOTYPE_SELECTION;
107        this.state = State.CLONING_RESULT;
108        break;
109
110      case State.CLONING_RESULT:
111        this.evolvedGenotype = this.world.table.genotypes[this.cloningIdx];
112        this.evolvedFitness = Math.max(0, (parseFloat(this.world.table.fitnessPlanks[this.cloningIdx].fitness) +
113                                           (Math.random() * 2 - 1)).toFixed(2));
114        this.showEvolutionResult();
115
116        this.timing = Config.Simulation.Timing.EVOLUTION_RESULT;
117        this.state = State.SHOW_FRAMSTICK;
118        break;
119
120      case State.CLONING_RETURN:
121        this.moveCamera(Config.Simulation.Camera.Position.TABLE);
122        this.evolutionReturn()
123
124        this.hideText(this.cloningText);
125        this.hideText(this.clonedText);
126        this.world.scene.remove(this.cloningArrow);
127        this.world.scene.remove(this.evolvedFramstick);
128
129        this.timing = Config.Simulation.Timing.EVOLUTION_RETURN;
130        this.state = State.INITIAL;
131        break;
132
133      case State.CROSSOVER_GENOTYPE_SELECTION:
134        this.showText(this.crossoverText)
135        this.hideText(this.genPoolText);
136
137        this.crossoverIdx1 = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
138        do {
139          this.crossoverIdx2 = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
140        } while (this.crossoverIdx1 == this.crossoverIdx2);
141
142        this.crossoverArrow1 = this.getArrow(this.crossoverIdx1).mesh;
143        this.world.scene.add(this.crossoverArrow1);
144        this.crossoverArrow2 = this.getArrow(this.crossoverIdx2).mesh;
145        this.world.scene.add(this.crossoverArrow2);
146
147        this.timing = Config.Simulation.Timing.GENOTYPE_SELECTION;
148        this.state = State.CROSSOVER_RESULT;
149        break;
150
151      case State.CROSSOVER_RESULT:
152        this.evolvedGenotype = this.getCrossoveredGenotype(this.world.table.genotypes[this.crossoverIdx1],
153                                                           this.world.table.genotypes[this.crossoverIdx2]);
154        this.evolvedFitness = ((parseFloat(this.world.table.fitnessPlanks[this.crossoverIdx1].fitness) +
155                               parseFloat(this.world.table.fitnessPlanks[this.crossoverIdx2].fitness)) / 2).toFixed(2);
156        this.showEvolutionResult();
157
158        this.timing = Config.Simulation.Timing.EVOLUTION_RESULT;
159        this.state = State.SHOW_FRAMSTICK;
160        break;
161
162      case State.CROSSOVER_RETURN:
163        this.moveCamera(Config.Simulation.Camera.Position.TABLE);
164        this.evolutionReturn()
165
166        this.hideText(this.crossoverText);
167        this.hideText(this.offspringText);
168        this.world.scene.remove(this.crossoverArrow1);
169        this.world.scene.remove(this.crossoverArrow2);
170        this.world.scene.remove(this.evolvedFramstick.mesh);
171
172        this.timing = Config.Simulation.Timing.EVOLUTION_RETURN;
173        this.state = State.INITIAL;
174        break;
175
176      case State.SHOW_FRAMSTICK:
177        this.moveCamera(Config.Simulation.Camera.Position.FRAMSTICK);
178
179        this.evolvedFramstick = new Framstick(this.evolvedGenotype);
180        this.world.scene.add(this.evolvedFramstick.mesh);
181
182        this.timing = Config.Simulation.Timing.SHOW_FRAMSTICK;
183        this.state = State.DESTROY_FRAMSTICK;
184        break;
185
186      case State.DESTROY_FRAMSTICK:
187        this.evolvedFramstick.scaleUpSize = 0.01;
188        this.evolvedFramstick.scaleDownSize = 0.01;
189
190        this.showText(this.fitnessText);
191        this.rotateText(this.fitnessText, Config.Simulation.Element.Angle.SIDE_VIEW);
192        this.evolvedFitnessPlank = new FitnessPlank(this.evolvedFitness, 10);
193        this.evolvedFitnessPlank.mesh.position.set(0, 0, 0);
194        this.evolvedFitnessPlank.textMesh.position.set(0, 0, 0);
195        this.evolvedFitnessPlank.move(Config.Simulation.Element.Position.EVOLVED_FITNESS_PLANK);
196        this.evolvedFitnessPlank.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
197        this.world.scene.add(this.evolvedFitnessPlank.mesh)
198        this.world.scene.add(this.evolvedFitnessPlank.textMesh)
199
200        this.timing = Config.Simulation.Timing.DESTROY_FRAMSTICK;
201        if (this.evolutionMethod == State.MUTATION_GENOTYPE_SELECTION) {
202          this.state = State.MUTATION_RETURN;
203        } else if (this.evolutionMethod == State.CROSSOVER_GENOTYPE_SELECTION) {
204          this.state = State.CROSSOVER_RETURN;
205        } else if (this.evolutionMethod == State.CLONING_GENOTYPE_SELECTION) {
206          this.state = State.CLONING_RETURN;
207        }
208        break;
209    }
210
211    setTimeout(this.run.bind(this), this.timing);
212  }
213
214  getMutatedGenotype(genotype) {
215    let genoF4 = new Module.Geno_f4();
216    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoF4);
217    let genetics = new Module.PreconfiguredGenetics();
218    let iteration = 0;
219
220    do {
221      if (genoOperatorsHelper.mutate(genotype.replace("/*4*/", "")) == 0) {
222        let mutated = genoOperatorsHelper.getLastMutateGeno();
223        let newGenotype = "/*4*/ " + mutated;
224
225        let stringObj = new Module.SString();
226        stringObj.set(newGenotype);
227        let genoObj = new Module.Geno(stringObj);
228
229        if (genoObj.isValid()) {
230          genotype = newGenotype;
231          iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
232        }
233
234        Module.destroy(stringObj);
235        Module.destroy(genoObj);
236      } else {
237        iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
238      }
239      iteration += 1;
240    } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
241
242    Module.destroy(genoF4);
243    Module.destroy(genoOperatorsHelper);
244    return genotype;
245  }
246
247  getCrossoveredGenotype(genotype1, genotype2) {
248    let genoF4 = new Module.Geno_f4();
249    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoF4);
250    let genetics = new Module.PreconfiguredGenetics();
251    let iteration = 0;
252
253    do {
254      if (genoOperatorsHelper.crossOver(genotype1.replace("/*4*/", ""),
255                                        genotype2.replace("/*4*/", "")) == 0) {
256        let crossovered = genoOperatorsHelper.getLastCrossGeno1();
257        let newGenotype = "/*4*/ " + crossovered;
258
259        let stringObj = new Module.SString();
260        stringObj.set(newGenotype);
261        let genoObj = new Module.Geno(stringObj);
262
263        if (genoObj.isValid()) {
264          genotype1 = newGenotype;
265          iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
266        }
267
268        Module.destroy(stringObj);
269        Module.destroy(genoObj);
270      } else {
271        iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
272      }
273      iteration += 1;
274    } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
275
276    Module.destroy(genoF4);
277    Module.destroy(genoOperatorsHelper);
278    return genotype1;
279  }
280
281  showEvolutionResult() {
282    this.evolvedGenotypePlank = new GenotypePlank(this.evolvedGenotype, 10);
283    this.evolvedGenotypePlank.move(Config.Simulation.Element.Position.EVOLVED_GENOTYPE_PLANK);
284    this.evolvedGenotypePlank.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
285    this.world.scene.add(this.evolvedGenotypePlank.mesh);
286    this.world.scene.add(this.evolvedGenotypePlank.textMesh);
287
288    if (this.evolutionMethod == State.MUTATION_GENOTYPE_SELECTION) {
289      this.showText(this.mutatedText);
290      this.moveText(this.mutatedText, Config.Simulation.Element.Position.RESULT_TEXT);
291      this.rotateText(this.mutatedText, Config.Simulation.Element.Angle.SIDE_VIEW);
292    } else if (this.evolutionMethod == State.CROSSOVER_GENOTYPE_SELECTION) {
293      this.showText(this.offspringText);
294      this.moveText(this.offspringText, Config.Simulation.Element.Position.RESULT_TEXT);
295      this.rotateText(this.offspringText, Config.Simulation.Element.Angle.SIDE_VIEW);
296    } else if (this.evolutionMethod == State.CLONING_GENOTYPE_SELECTION) {
297      this.showText(this.clonedText);
298      this.moveText(this.clonedText, Config.Simulation.Element.Position.RESULT_TEXT);
299      this.rotateText(this.clonedText, Config.Simulation.Element.Angle.SIDE_VIEW);
300    }
301  }
302
303  evolutionReturn() {
304    let replaceIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
305    let genotypePlank = this.world.table.genotypePlanks[replaceIdx];
306    let fitnessPlank = this.world.table.fitnessPlanks[replaceIdx];
307
308    this.world.scene.remove(genotypePlank.mesh);
309    this.world.scene.remove(genotypePlank.textMesh);
310    this.world.scene.remove(fitnessPlank.mesh);
311    this.world.scene.remove(fitnessPlank.textMesh);
312
313    this.evolvedGenotypePlank.position = genotypePlank.position;
314    this.evolvedGenotypePlank.move(this.evolvedGenotypePlank.position);
315    this.evolvedGenotypePlank.rotate(Config.Simulation.Element.Angle.NORMAL);
316
317    this.evolvedFitnessPlank.position = fitnessPlank.position;
318    this.evolvedFitnessPlank.move(this.evolvedFitnessPlank.position);
319    this.evolvedFitnessPlank.rotate(Config.Simulation.Element.Angle.NORMAL);
320
321    this.world.table.genotypes[replaceIdx] = this.evolvedGenotype;
322    this.world.table.genotypePlanks[replaceIdx] = this.evolvedGenotypePlank;
323    this.world.table.fitnessPlanks[replaceIdx] = this.evolvedFitnessPlank;
324    this.hideText(this.fitnessText);
325  }
326
327  getText(text, position) {
328    let textMesh = Text.getInfoMesh(text);
329    textMesh.position.set(position.x, position.y, position.z);
330    textMesh.scale.set(0.01, 0.01, 0.01);
331    return textMesh;
332  }
333
334  showText(text) {
335    let tween = new TWEEN.Tween(text.scale).to({x: 1, y: 1, z: 1}, 500);
336    tween.easing(TWEEN.Easing.Quadratic.InOut);
337    tween.start();
338  }
339
340  hideText(text) {
341    let tween = new TWEEN.Tween(text.scale).to({x: 0.01, y: 0.01, z: 0.01}, 500);
342    tween.easing(TWEEN.Easing.Quadratic.InOut);
343    tween.start();
344  }
345
346  getFramstick(genotype) {
347    this.moveCamera(Config.Simulation.Camera.Position.FRAMSTICK);
348    return new Framstick(genotype).mesh;
349  }
350
351  getArrow(idx) {
352    return new Arrow(50 + (Config.Table.FitnessPlank.HEIGHT + Config.Table.Board.SPACING) * idx);
353  }
354
355  moveCamera(position) {
356    let tween = new TWEEN.Tween(this.world.camera.position).to(position, Config.Simulation.Camera.SPEED);
357    tween.easing(TWEEN.Easing.Quadratic.Out);
358    tween.start();
359  }
360
361  moveText(textMesh, position) {
362    let tween = new TWEEN.Tween(textMesh.position).to(position, Config.Simulation.Camera.SPEED);
363    tween.easing(TWEEN.Easing.Quadratic.Out);
364    tween.start();
365  }
366
367  rotateText(textMesh, angle) {
368    let tween = new TWEEN.Tween(textMesh.rotation).to(angle, Config.Simulation.Camera.SPEED);
369    tween.easing(TWEEN.Easing.Quadratic.Out);
370    tween.start();
371  }
372}
373
374var State = {
375  "INITIAL": 0, "EVOLUTION_METHOD_SELECTION": 1, "MUTATION_GENOTYPE_SELECTION": 2,
376  "MUTATION_SIDE_VIEW": 3, "MUTATION_RESULT": 4, "SHOW_FRAMSTICK": 5,
377  "SHOW_RESULT": 6, "MUTATION_RETURN": 7, "CROSSOVER_GENOTYPE_SELECTION": 8,
378  "CROSSOVER_SIDE_VIEW": 9, "CROSSOVER_RESULT": 10, "CROSSOVER_RETURN": 11,
379  "DESTROY_FRAMSTICK": 12, "CLONING_GENOTYPE_SELECTION": 13,
380  "CLONING_SIDE_VIEW": 14, "CLONING_RESULT": 15, "CLONING_RETURN": 16
381};
382
383var EVOLUTION_METHOD_TEXT_POSITION = {
384  x: -210,
385  y: 80 + (Config.Table.FitnessPlank.HEIGHT + Config.Table.Board.SPACING) * (Config.Simulation.GENOTYPES.length + 1),
386  z: -500
387};
Note: See TracBrowser for help on using the repository browser.