organism saving/loading
This commit is contained in:
5
dist/index.html
vendored
5
dist/index.html
vendored
@@ -77,6 +77,9 @@
|
|||||||
<button class="edit-mode-btn select" id="select" title="Select organism from world. Hotkey: Z"><i class="fa fa-hand-pointer-o"></i></button>
|
<button class="edit-mode-btn select" id="select" title="Select organism from world. Hotkey: Z"><i class="fa fa-hand-pointer-o"></i></button>
|
||||||
<button class="edit-mode-btn edit" id="edit" title="Edit organism. Hotkey: X"><i class="fa fa-pencil"></i></button>
|
<button class="edit-mode-btn edit" id="edit" title="Edit organism. Hotkey: X"><i class="fa fa-pencil"></i></button>
|
||||||
<button class="edit-mode-btn drop-org" id="drop-org" title="Drop organism in world. Hotkey: C"><i class="fa fa-plus"></i></button>
|
<button class="edit-mode-btn drop-org" id="drop-org" title="Drop organism in world. Hotkey: C"><i class="fa fa-plus"></i></button>
|
||||||
|
<button id="save-org" title="Save Organism"><i class="fa fa-save"></i></button>
|
||||||
|
<button id="load-org" title="Load Organism"><i class="fa fa-upload"></i></button>
|
||||||
|
<input id="upload-org" style="display: none;" type="file">
|
||||||
</div>
|
</div>
|
||||||
<div id='editor-env'>
|
<div id='editor-env'>
|
||||||
<canvas id='editor-canvas'></canvas>
|
<canvas id='editor-canvas'></canvas>
|
||||||
@@ -237,7 +240,7 @@
|
|||||||
<button id='save-controls' title="Save all Evolution Controls in a .json file">Save & Download</button>
|
<button id='save-controls' title="Save all Evolution Controls in a .json file">Save & Download</button>
|
||||||
<button id='load-controls' title="Load saved Evolution Controls with a .json file">Load</button>
|
<button id='load-controls' title="Load saved Evolution Controls with a .json file">Load</button>
|
||||||
<a id="download-el" style="display: none;"></a>
|
<a id="download-el" style="display: none;"></a>
|
||||||
<input id="upload-el" style="display: none;" type="file">
|
<input id="upload-hyperparams" style="display: none;" type="file">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='stats' class='tab'>
|
<div id='stats' class='tab'>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const Hyperparams = require("../Hyperparameters");
|
const Hyperparams = require("../Hyperparameters");
|
||||||
const Modes = require("./ControlModes");
|
const Modes = require("./ControlModes");
|
||||||
const StatsPanel = require("../Stats/StatsPanel");
|
const StatsPanel = require("../Stats/StatsPanel");
|
||||||
const RandomOrganismGenerator = require("../Organism/RandomOrganismGenerator")
|
|
||||||
const WorldConfig = require("../WorldConfig");
|
const WorldConfig = require("../WorldConfig");
|
||||||
|
|
||||||
class ControlPanel {
|
class ControlPanel {
|
||||||
@@ -279,9 +278,9 @@ class ControlPanel {
|
|||||||
downloadEl.click();
|
downloadEl.click();
|
||||||
});
|
});
|
||||||
$('#load-controls').click(() => {
|
$('#load-controls').click(() => {
|
||||||
$('#upload-el').click();
|
$('#upload-hyperparams').click();
|
||||||
});
|
});
|
||||||
$('#upload-el').change((e)=>{
|
$('#upload-hyperparams').change((e)=>{
|
||||||
let files = e.target.files;
|
let files = e.target.files;
|
||||||
if (!files.length) {return;};
|
if (!files.length) {return;};
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
@@ -290,7 +289,7 @@ class ControlPanel {
|
|||||||
Hyperparams.loadJsonObj(result);
|
Hyperparams.loadJsonObj(result);
|
||||||
this.updateHyperparamUIValues();
|
this.updateHyperparamUIValues();
|
||||||
// have to clear the value so change() will be triggered if the same file is uploaded again
|
// 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]);
|
reader.readAsText(files[0]);
|
||||||
});
|
});
|
||||||
@@ -428,7 +427,6 @@ class ControlPanel {
|
|||||||
this.env_controller.org_to_clone = this.engine.organism_editor.getCopyOfOrg();
|
this.env_controller.org_to_clone = this.engine.organism_editor.getCopyOfOrg();
|
||||||
this.env_controller.add_new_species = this.editor_controller.new_species;
|
this.env_controller.add_new_species = this.editor_controller.new_species;
|
||||||
this.editor_controller.new_species = false;
|
this.editor_controller.new_species = false;
|
||||||
// console.log(this.env_controller.add_new_species)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class EditorController extends CanvasController{
|
|||||||
this.new_species = false;
|
this.new_species = false;
|
||||||
this.defineCellTypeSelection();
|
this.defineCellTypeSelection();
|
||||||
this.defineEditorDetails();
|
this.defineEditorDetails();
|
||||||
|
this.defineSaveLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseMove() {
|
mouseMove() {
|
||||||
@@ -109,6 +110,43 @@ class EditorController extends CanvasController{
|
|||||||
}.bind(this));
|
}.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() {
|
clearDetailsPanel() {
|
||||||
$('#organism-details').css('display', 'none');
|
$('#organism-details').css('display', 'none');
|
||||||
$('#edit-organism-details').css('display', 'none');
|
$('#edit-organism-details').css('display', 'none');
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
const CellStates = require("./Cell/CellStates");
|
const CellStates = require("./Cell/CellStates");
|
||||||
const BodyCellFactory = require("./Cell/BodyCells/BodyCellFactory");
|
const BodyCellFactory = require("./Cell/BodyCells/BodyCellFactory");
|
||||||
|
const SerializeHelper = require("../Utils/SerializeHelper");
|
||||||
|
|
||||||
class Anatomy {
|
class Anatomy {
|
||||||
constructor(owner) {
|
constructor(owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
this.birth_distance = 4;
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
this.cells = [];
|
this.cells = [];
|
||||||
this.is_producer = false;
|
this.is_producer = false;
|
||||||
this.is_mover = false;
|
this.is_mover = false;
|
||||||
this.has_eyes = false;
|
this.has_eyes = false;
|
||||||
this.birth_distance = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canAddCellAt(c, r) {
|
canAddCellAt(c, r) {
|
||||||
@@ -118,6 +123,24 @@ class Anatomy {
|
|||||||
}
|
}
|
||||||
return true;
|
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;
|
module.exports = Anatomy;
|
||||||
@@ -5,6 +5,7 @@ const Directions = require("./Directions");
|
|||||||
const Anatomy = require("./Anatomy");
|
const Anatomy = require("./Anatomy");
|
||||||
const Brain = require("./Perception/Brain");
|
const Brain = require("./Perception/Brain");
|
||||||
const FossilRecord = require("../Stats/FossilRecord");
|
const FossilRecord = require("../Stats/FossilRecord");
|
||||||
|
const SerializeHelper = require("../Utils/SerializeHelper");
|
||||||
|
|
||||||
class Organism {
|
class Organism {
|
||||||
constructor(col, row, env, parent=null) {
|
constructor(col, row, env, parent=null) {
|
||||||
@@ -38,10 +39,8 @@ class Organism {
|
|||||||
//deep copy parent cells
|
//deep copy parent cells
|
||||||
this.anatomy.addInheritCell(c);
|
this.anatomy.addInheritCell(c);
|
||||||
}
|
}
|
||||||
if(parent.anatomy.is_mover) {
|
if(parent.anatomy.is_mover && parent.anatomy.has_eyes) {
|
||||||
for (var i in parent.brain.decisions) {
|
this.brain.copy(parent.brain);
|
||||||
this.brain.decisions[i] = parent.brain.decisions[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +103,6 @@ class Organism {
|
|||||||
var new_c = this.c + (direction_c*basemovement) + (direction_c*offset);
|
var new_c = this.c + (direction_c*basemovement) + (direction_c*offset);
|
||||||
var new_r = this.r + (direction_r*basemovement) + (direction_r*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)){
|
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.c = new_c;
|
||||||
org.r = new_r;
|
org.r = new_r;
|
||||||
@@ -125,7 +123,6 @@ class Organism {
|
|||||||
let changed = false;
|
let changed = false;
|
||||||
let removed = false;
|
let removed = false;
|
||||||
if (this.calcRandomChance(Hyperparams.addProb)) {
|
if (this.calcRandomChance(Hyperparams.addProb)) {
|
||||||
// console.log('add')
|
|
||||||
let branch = this.anatomy.getRandomCell();
|
let branch = this.anatomy.getRandomCell();
|
||||||
let state = CellStates.getRandomLivingType();//branch.state;
|
let state = CellStates.getRandomLivingType();//branch.state;
|
||||||
let growth_direction = Neighbors.all[Math.floor(Math.random() * Neighbors.all.length)]
|
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);
|
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;
|
module.exports = Organism;
|
||||||
|
|||||||
@@ -20,16 +20,18 @@ class Brain {
|
|||||||
this.observations = [];
|
this.observations = [];
|
||||||
|
|
||||||
// corresponds to CellTypes
|
// corresponds to CellTypes
|
||||||
this.decisions = [];
|
this.decisions = {};
|
||||||
this.decisions[CellStates.empty.name] = Decision.neutral;
|
for (let cell of CellStates.all) {
|
||||||
|
this.decisions[cell.name] = Decision.neutral;
|
||||||
|
}
|
||||||
this.decisions[CellStates.food.name] = Decision.chase;
|
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.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) {
|
randomizeDecisions(randomize_all=false) {
|
||||||
@@ -58,9 +60,7 @@ class Brain {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (obs.distance < closest) {
|
if (obs.distance < closest) {
|
||||||
// console.log(obs.cell.state)
|
|
||||||
decision = this.decisions[obs.cell.state.name];
|
decision = this.decisions[obs.cell.state.name];
|
||||||
// console.log(decision)
|
|
||||||
move_direction = obs.direction;
|
move_direction = obs.direction;
|
||||||
closest = obs.distance;
|
closest = obs.distance;
|
||||||
}
|
}
|
||||||
@@ -81,6 +81,10 @@ class Brain {
|
|||||||
this.decisions[CellStates.getRandomName()] = Decision.getRandom();
|
this.decisions[CellStates.getRandomName()] = Decision.getRandom();
|
||||||
this.decisions[CellStates.empty.name] = Decision.neutral; // if the empty cell has a decision it gets weird
|
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;
|
Brain.Decision = Decision;
|
||||||
|
|||||||
12
src/Utils/SerializeHelper.js
Normal file
12
src/Utils/SerializeHelper.js
Normal file
@@ -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;
|
||||||
Reference in New Issue
Block a user