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 @@ + + +
@@ -237,7 +240,7 @@ - +
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