diff --git a/dist/index.html b/dist/index.html
index 9022567..70f160b 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -77,6 +77,9 @@
+
+
+
diff --git a/src/Controllers/ControlPanel.js b/src/Controllers/ControlPanel.js
index f57b94b..11e81eb 100644
--- a/src/Controllers/ControlPanel.js
+++ b/src/Controllers/ControlPanel.js
@@ -1,7 +1,6 @@
const Hyperparams = require("../Hyperparameters");
const Modes = require("./ControlModes");
const StatsPanel = require("../Stats/StatsPanel");
-const RandomOrganismGenerator = require("../Organism/RandomOrganismGenerator")
const WorldConfig = require("../WorldConfig");
class ControlPanel {
@@ -279,9 +278,9 @@ class ControlPanel {
downloadEl.click();
});
$('#load-controls').click(() => {
- $('#upload-el').click();
+ $('#upload-hyperparams').click();
});
- $('#upload-el').change((e)=>{
+ $('#upload-hyperparams').change((e)=>{
let files = e.target.files;
if (!files.length) {return;};
let reader = new FileReader();
@@ -290,7 +289,7 @@ class ControlPanel {
Hyperparams.loadJsonObj(result);
this.updateHyperparamUIValues();
// have to clear the value so change() will be triggered if the same file is uploaded again
- $('#upload-el')[0].value = '';
+ $('#upload-hyperparams')[0].value = '';
};
reader.readAsText(files[0]);
});
@@ -428,7 +427,6 @@ class ControlPanel {
this.env_controller.org_to_clone = this.engine.organism_editor.getCopyOfOrg();
this.env_controller.add_new_species = this.editor_controller.new_species;
this.editor_controller.new_species = false;
- // console.log(this.env_controller.add_new_species)
}
}
diff --git a/src/Controllers/EditorController.js b/src/Controllers/EditorController.js
index d5c2cb7..38cec42 100644
--- a/src/Controllers/EditorController.js
+++ b/src/Controllers/EditorController.js
@@ -13,6 +13,7 @@ class EditorController extends CanvasController{
this.new_species = false;
this.defineCellTypeSelection();
this.defineEditorDetails();
+ this.defineSaveLoad();
}
mouseMove() {
@@ -109,6 +110,43 @@ class EditorController extends CanvasController{
}.bind(this));
}
+ defineSaveLoad() {
+ $('#save-org').click(()=>{
+ let org = this.env.organism.serialize();
+ let data = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(org));
+ let downloadEl = document.getElementById('download-el');
+ downloadEl.setAttribute("href", data);
+ downloadEl.setAttribute("download", "organism.json");
+ downloadEl.click();
+ });
+ $('#load-org').click(() => {
+ $('#upload-org').click();
+ });
+ $('#upload-org').change((e)=>{
+ let files = e.target.files;
+ if (!files.length) {return;};
+ let reader = new FileReader();
+ reader.onload = (e) => {
+ try {
+ let org=JSON.parse(e.target.result);
+ this.env.clear();
+ this.env.organism.loadRaw(org);
+ this.refreshDetailsPanel();
+ this.env.organism.updateGrid();
+ this.env.renderFull();
+ if (this.mode === Modes.Clone)
+ $('#drop-org').click();
+ // have to clear the value so change() will be triggered if the same file is uploaded again
+ $('#upload-org')[0].value = '';
+ } catch(except) {
+ console.error(except)
+ alert('Failed to load organism');
+ }
+ };
+ reader.readAsText(files[0]);
+ });
+ }
+
clearDetailsPanel() {
$('#organism-details').css('display', 'none');
$('#edit-organism-details').css('display', 'none');
diff --git a/src/Organism/Anatomy.js b/src/Organism/Anatomy.js
index 1e8cebb..ec3173d 100644
--- a/src/Organism/Anatomy.js
+++ b/src/Organism/Anatomy.js
@@ -1,14 +1,19 @@
const CellStates = require("./Cell/CellStates");
const BodyCellFactory = require("./Cell/BodyCells/BodyCellFactory");
+const SerializeHelper = require("../Utils/SerializeHelper");
class Anatomy {
constructor(owner) {
this.owner = owner;
+ this.birth_distance = 4;
+ this.clear();
+ }
+
+ clear() {
this.cells = [];
this.is_producer = false;
this.is_mover = false;
this.has_eyes = false;
- this.birth_distance = 4;
}
canAddCellAt(c, r) {
@@ -118,6 +123,24 @@ class Anatomy {
}
return true;
}
+
+ serialize() {
+ let anatomy = SerializeHelper.copyNonObjects(this);
+ anatomy.cells = [];
+ for (let cell of this.cells) {
+ let newcell = SerializeHelper.copyNonObjects(cell);
+ newcell.state = {name: cell.state.name};
+ anatomy.cells.push(newcell)
+ }
+ return anatomy;
+ }
+
+ loadRaw(anatomy) {
+ this.clear();
+ for (let cell of anatomy.cells){
+ this.addInheritCell(cell);
+ }
+ }
}
module.exports = Anatomy;
\ No newline at end of file
diff --git a/src/Organism/Organism.js b/src/Organism/Organism.js
index dcaabaa..0461f27 100644
--- a/src/Organism/Organism.js
+++ b/src/Organism/Organism.js
@@ -5,6 +5,7 @@ const Directions = require("./Directions");
const Anatomy = require("./Anatomy");
const Brain = require("./Perception/Brain");
const FossilRecord = require("../Stats/FossilRecord");
+const SerializeHelper = require("../Utils/SerializeHelper");
class Organism {
constructor(col, row, env, parent=null) {
@@ -38,10 +39,8 @@ class Organism {
//deep copy parent cells
this.anatomy.addInheritCell(c);
}
- if(parent.anatomy.is_mover) {
- for (var i in parent.brain.decisions) {
- this.brain.decisions[i] = parent.brain.decisions[i];
- }
+ if(parent.anatomy.is_mover && parent.anatomy.has_eyes) {
+ this.brain.copy(parent.brain);
}
}
@@ -104,7 +103,6 @@ class Organism {
var new_c = this.c + (direction_c*basemovement) + (direction_c*offset);
var new_r = this.r + (direction_r*basemovement) + (direction_r*offset);
- // console.log(org.isClear(new_c, new_r, org.rotation, true))
if (org.isClear(new_c, new_r, org.rotation, true) && org.isStraightPath(new_c, new_r, this.c, this.r, this)){
org.c = new_c;
org.r = new_r;
@@ -125,7 +123,6 @@ class Organism {
let changed = false;
let removed = false;
if (this.calcRandomChance(Hyperparams.addProb)) {
- // console.log('add')
let branch = this.anatomy.getRandomCell();
let state = CellStates.getRandomLivingType();//branch.state;
let growth_direction = Neighbors.all[Math.floor(Math.random() * Neighbors.all.length)]
@@ -321,6 +318,26 @@ class Organism {
return this.env.grid_map.cellAt(real_c, real_r);
}
+ serialize() {
+ let org = SerializeHelper.copyNonObjects(this);
+ org.anatomy = this.anatomy.serialize();
+ if (this.brain)
+ org.brain = this.brain.serialize();
+ return org;
+ }
+
+ loadRaw(org) {
+ for (let key in org)
+ if (typeof org[key] !== 'object')
+ this[key] = org[key];
+ this.anatomy.loadRaw(org.anatomy)
+ console.log(org)
+ if (org.brain) {
+ console.log('load brain')
+ this.brain.copy(org.brain)
+ }
+ }
+
}
module.exports = Organism;
diff --git a/src/Organism/Perception/Brain.js b/src/Organism/Perception/Brain.js
index 20c6258..4c60b03 100644
--- a/src/Organism/Perception/Brain.js
+++ b/src/Organism/Perception/Brain.js
@@ -20,16 +20,18 @@ class Brain {
this.observations = [];
// corresponds to CellTypes
- this.decisions = [];
- this.decisions[CellStates.empty.name] = Decision.neutral;
+ this.decisions = {};
+ for (let cell of CellStates.all) {
+ this.decisions[cell.name] = Decision.neutral;
+ }
this.decisions[CellStates.food.name] = Decision.chase;
- this.decisions[CellStates.wall.name] = Decision.neutral;
- this.decisions[CellStates.mouth.name] = Decision.neutral;
- this.decisions[CellStates.producer.name] = Decision.neutral;
- this.decisions[CellStates.mover.name] = Decision.neutral;
this.decisions[CellStates.killer.name] = Decision.retreat;
- this.decisions[CellStates.armor.name] = Decision.neutral;
- this.decisions[CellStates.eye.name] = Decision.neutral;
+ }
+
+ copy(brain) {
+ for (let dec in brain.decisions) {
+ this.decisions[dec] = brain.decisions[dec];
+ }
}
randomizeDecisions(randomize_all=false) {
@@ -58,9 +60,7 @@ class Brain {
continue;
}
if (obs.distance < closest) {
- // console.log(obs.cell.state)
decision = this.decisions[obs.cell.state.name];
- // console.log(decision)
move_direction = obs.direction;
closest = obs.distance;
}
@@ -81,6 +81,10 @@ class Brain {
this.decisions[CellStates.getRandomName()] = Decision.getRandom();
this.decisions[CellStates.empty.name] = Decision.neutral; // if the empty cell has a decision it gets weird
}
+
+ serialize() {
+ return {decisions: this.decisions};
+ }
}
Brain.Decision = Decision;
diff --git a/src/Utils/SerializeHelper.js b/src/Utils/SerializeHelper.js
new file mode 100644
index 0000000..c96c8c2
--- /dev/null
+++ b/src/Utils/SerializeHelper.js
@@ -0,0 +1,12 @@
+const SerializeHelper = {
+ copyNonObjects(obj) {
+ let newobj = {};
+ for (let key in obj) {
+ if (typeof obj[key] !== 'object')
+ newobj[key] = obj[key];
+ }
+ return newobj;
+ }
+}
+
+module.exports = SerializeHelper;
\ No newline at end of file