diff --git a/dist/css/style.css b/dist/css/style.css
index f98f464..86af6b0 100644
--- a/dist/css/style.css
+++ b/dist/css/style.css
@@ -169,6 +169,9 @@ button:hover{
.edit-mode-btn#drag-view {
background-color: #81d2c7;
}
+.randomize-button {
+ margin-top: 5px;
+}
#clear-walls {
margin-top: 5px;
}
diff --git a/dist/index.html b/dist/index.html
index f833752..bd57ef2 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -100,6 +100,7 @@
+
@@ -169,6 +170,24 @@
+
+
Generate Random Organism
+
+
+
+ 5
+
+
+
+
+ 75%
+
+
+
+
+
+
+
diff --git a/src/Controllers/ControlModes.js b/src/Controllers/ControlModes.js
index 882e500..97ecfa2 100644
--- a/src/Controllers/ControlModes.js
+++ b/src/Controllers/ControlModes.js
@@ -6,7 +6,8 @@ const Modes = {
Select: 4,
Edit: 5,
Clone: 6,
- Drag: 7
+ Drag: 7,
+ Randomize: 8,
}
module.exports = Modes;
\ No newline at end of file
diff --git a/src/Controllers/ControlPanel.js b/src/Controllers/ControlPanel.js
index ab5eaa5..7d92c53 100644
--- a/src/Controllers/ControlPanel.js
+++ b/src/Controllers/ControlPanel.js
@@ -1,6 +1,7 @@
const Hyperparams = require("../Hyperparameters");
const Modes = require("./ControlModes");
const StatsPanel = require("../Stats/StatsPanel");
+const RandomOrganismGenerator = require("../Organism/RandomOrganismGenerator")
class ControlPanel {
constructor(engine) {
@@ -21,7 +22,7 @@ class ControlPanel {
this.stats_panel = new StatsPanel(this.engine.env);
this.headless_opacity = 1;
this.opacity_change_rate = -0.8;
- this.paused=false;
+ //this.paused=false;
}
defineMinMaxControls(){
@@ -84,17 +85,12 @@ class ControlPanel {
}
$('#fps').text("Target FPS: "+this.fps);
}.bind(this);
+
$('.pause-button').click(function() {
- $('.pause-button').find("i").toggleClass("fa fa-pause");
- $('.pause-button').find("i").toggleClass("fa fa-play");
- this.paused = !this.paused;
- if (this.engine.running) {
- this.engine.stop();
- }
- else if (!this.engine.running){
- this.engine.start(this.fps);
- }
+ // toggle pause
+ this.setPaused(this.engine.running);
}.bind(this));
+
$('.headless').click(function() {
$('.headless').find("i").toggleClass("fa fa-eye");
$('.headless').find("i").toggleClass("fa fa-eye-slash");
@@ -263,6 +259,9 @@ class ControlPanel {
self.setMode(Modes.Edit);
self.editor_controller.setEditorPanel();
break;
+ case "randomize":
+ self.setMode(Modes.Randomize);
+ self.editor_controller.setRandomizePanel();
case "drop-org":
self.setMode(Modes.Clone);
self.env_controller.org_to_clone = self.engine.organism_editor.getCopyOfOrg();
@@ -298,6 +297,24 @@ class ControlPanel {
this.engine.organism_editor.clear();
this.editor_controller.setEditorPanel();
}.bind(this));
+ document.getElementById("random-width").addEventListener('input', function() {
+ var width = 2 * this.value + 1;
+ $('#random-width-display').text(width);
+ RandomOrganismGenerator.organismLayers = this.value;
+ });
+ document.getElementById("cell-spawn-chance").addEventListener("input", function() {
+ var value = parseFloat(this.value);
+ $('#spawn-chance-display').text((value * 100).toFixed(1) + "%");
+ RandomOrganismGenerator.cellSpawnChance = value;
+ });
+ $('#generate-random').click( function() {
+ this.engine.organism_editor.createRandom();
+ }.bind(this));
+
+ $('#create-random-world').click( function() {
+ this.setPaused(true);
+ this.engine.organism_editor.createRandomWorld(this.engine.env);
+ }.bind(this));
}
defineChallenges() {
@@ -307,6 +324,20 @@ class ControlPanel {
});
}
+ setPaused(paused) {
+
+ if (paused) {
+ $('.pause-button').find("i").removeClass("fa-pause");
+ $('.pause-button').find("i").addClass("fa-play");
+ this.engine.stop();
+ }
+ else if (!paused) {
+ $('.pause-button').find("i").addClass("fa-pause");
+ $('.pause-button').find("i").removeClass("fa-play");
+ this.engine.start(this.fps);
+ }
+ }
+
setMode(mode) {
this.env_controller.mode = mode;
this.editor_controller.mode = mode;
@@ -325,7 +356,7 @@ class ControlPanel {
}
updateHeadlessIcon(delta_time) {
- if (this.paused)
+ if (this.engine.running)
return;
var op = this.headless_opacity + (this.opacity_change_rate*delta_time/1000);
if (op <= 0.4){
diff --git a/src/Controllers/EditorController.js b/src/Controllers/EditorController.js
index e7c2152..2a47afa 100644
--- a/src/Controllers/EditorController.js
+++ b/src/Controllers/EditorController.js
@@ -108,6 +108,7 @@ class EditorController extends CanvasController{
clearDetailsPanel() {
$('#organism-details').css('display', 'none');
$('#edit-organism-details').css('display', 'none');
+ $('#randomize-organism-details').css('display', 'none');
}
setDetailsPanel() {
@@ -193,6 +194,11 @@ class EditorController extends CanvasController{
var reaction = this.env.organism.brain.decisions[name];
$('#reaction-edit').val(reaction);
}
+
+ setRandomizePanel() {
+ this.clearDetailsPanel();
+ $('#randomize-organism-details').css('display', 'block');
+ }
}
module.exports = EditorController;
diff --git a/src/Controllers/EnvironmentController.js b/src/Controllers/EnvironmentController.js
index 451d2a9..cf0c644 100644
--- a/src/Controllers/EnvironmentController.js
+++ b/src/Controllers/EnvironmentController.js
@@ -122,21 +122,7 @@ class EnvironmentController extends CanvasController{
case Modes.Clone:
if (this.org_to_clone != null){
- var new_org = new Organism(this.mouse_c, this.mouse_r, this.env, this.org_to_clone);
- if (this.add_new_species){
- FossilRecord.addSpeciesObj(new_org.species);
- new_org.species.start_tick = this.env.total_ticks;
- this.add_new_species = false;
- new_org.species.population = 0;
- }
- else if (this.org_to_clone.species.extinct){
- FossilRecord.resurrect(this.org_to_clone.species);
- }
-
- if (new_org.isClear(this.mouse_c, this.mouse_r)){
- this.env.addOrganism(new_org);
- new_org.species.addPop();
- }
+ this.dropOrganism(this.org_to_clone, this.mouse_c, this.mouse_r);
}
break;
case Modes.Drag:
@@ -151,6 +137,26 @@ class EnvironmentController extends CanvasController{
}
}
+ dropOrganism(organism, col, row) {
+
+ // close the organism and drop it in the world
+ var new_org = new Organism(col, row, this.env, organism);
+ if (this.add_new_species){
+ FossilRecord.addSpeciesObj(new_org.species);
+ new_org.species.start_tick = this.env.total_ticks;
+ this.add_new_species = false;
+ new_org.species.population = 0;
+ }
+ else if (this.org_to_clone.species.extinct){
+ FossilRecord.resurrect(this.org_to_clone.species);
+ }
+
+ if (new_org.isClear(this.mouse_c, this.mouse_r)){
+ this.env.addOrganism(new_org);
+ new_org.species.addPop();
+ }
+ }
+
dropCellType(col, row, state, killBlocking=false) {
for (var loc of Neighbors.allSelf){
var c=col + loc[0];
diff --git a/src/Environments/OrganismEditor.js b/src/Environments/OrganismEditor.js
index b969774..c9d48e1 100644
--- a/src/Environments/OrganismEditor.js
+++ b/src/Environments/OrganismEditor.js
@@ -5,6 +5,7 @@ const Renderer = require('../Rendering/Renderer');
const CellStates = require('../Organism/Cell/CellStates');
const EditorController = require("../Controllers/EditorController");
const Species = require('../Stats/Species');
+const RandomOrganismGenerator = require('../Organism/RandomOrganismGenerator')
class OrganismEditor extends Environment{
constructor() {
@@ -87,6 +88,38 @@ class OrganismEditor extends Environment{
this.organism.updateGrid();
this.organism.species = new Species(this.organism.anatomy, null, 0);
}
+
+ createRandom() {
+
+ this.grid_map.fillGrid(CellStates.empty);
+
+ this.organism = RandomOrganismGenerator.generate(this);
+ this.organism.updateGrid();
+ this.organism.species = new Species(this.organism.anatomy, null, 0);
+ }
+
+ createRandomWorld(worldEnvironment) {
+
+ worldEnvironment.clear();
+
+ var numOrganismCols = Math.floor(worldEnvironment.grid_map.cols / this.grid_map.cols);
+ var numOrganismRows = Math.floor(worldEnvironment.grid_map.rows / this.grid_map.rows);
+ var center = this.grid_map.getCenter();
+
+ for (var x = 0; x < numOrganismCols; x++) {
+ for (var y = 0; y < numOrganismRows; y++) {
+
+ var newOrganism = RandomOrganismGenerator.generate(this);
+ //newOrganism.updateGrid();
+ newOrganism.species = new Species(newOrganism.anatomy, null, 0);
+
+ var col = x * this.grid_map.cols + center[0];
+ var row = y * this.grid_map.rows + center[1];
+ worldEnvironment.controller.add_new_species = true;
+ worldEnvironment.controller.dropOrganism(newOrganism, col, row);
+ }
+ }
+ }
}
module.exports = OrganismEditor;
\ No newline at end of file
diff --git a/src/Environments/WorldEnvironment.js b/src/Environments/WorldEnvironment.js
index da7bb40..1470b0e 100644
--- a/src/Environments/WorldEnvironment.js
+++ b/src/Environments/WorldEnvironment.js
@@ -131,13 +131,17 @@ class WorldEnvironment extends Environment{
}
reset() {
+ this.clear();
+ this.OriginOfLife();
+ }
+
+ clear() {
this.organisms = [];
this.grid_map.fillGrid(CellStates.empty);
this.renderer.renderFullGrid(this.grid_map.grid);
this.total_mutability = 0;
this.total_ticks = 0;
FossilRecord.clear_record();
- this.OriginOfLife();
}
resizeGridColRow(cell_size, cols, rows) {
diff --git a/src/Organism/Anatomy.js b/src/Organism/Anatomy.js
index 8175024..b1c3cb6 100644
--- a/src/Organism/Anatomy.js
+++ b/src/Organism/Anatomy.js
@@ -91,6 +91,22 @@ class Anatomy {
getRandomCell() {
return this.cells[Math.floor(Math.random() * this.cells.length)];
}
+
+ getNeighborsOfCell(col, row) {
+
+ var neighbors = [];
+
+ for (var x = -1; x <= 1; x++) {
+ for (var y = -1; y <= 1; y++) {
+
+ var neighbor = this.getLocalCell(col + x, row + y);
+ if (neighbor)
+ neighbors.push(neighbor)
+ }
+ }
+
+ return neighbors;
+ }
}
module.exports = Anatomy;
\ No newline at end of file
diff --git a/src/Organism/Cell/CellStates.js b/src/Organism/Cell/CellStates.js
index 4a01aa7..9bf54f8 100644
--- a/src/Organism/Cell/CellStates.js
+++ b/src/Organism/Cell/CellStates.js
@@ -95,6 +95,7 @@ const CellStates = {
return this.living[Math.floor(Math.random() * this.living.length)];
}
}
+
CellStates.defineLists();
module.exports = CellStates;
diff --git a/src/Organism/Perception/Brain.js b/src/Organism/Perception/Brain.js
index e52d8a3..6aba956 100644
--- a/src/Organism/Perception/Brain.js
+++ b/src/Organism/Perception/Brain.js
@@ -79,4 +79,6 @@ class Brain {
}
}
+Brain.Decision = Decision;
+
module.exports = Brain;
\ No newline at end of file
diff --git a/src/Organism/RandomOrganismGenerator.js b/src/Organism/RandomOrganismGenerator.js
new file mode 100644
index 0000000..3379e6f
--- /dev/null
+++ b/src/Organism/RandomOrganismGenerator.js
@@ -0,0 +1,77 @@
+const CellStates = require("./Cell/CellStates");
+const Organism = require("./Organism");
+const Brain = require("./Perception/Brain")
+
+class RandomOrganismGenerator {
+
+ static generate(env) {
+
+ var center = env.grid_map.getCenter();
+ var organism = new Organism(center[0], center[1], env, null);
+ organism.anatomy.addDefaultCell(CellStates.mouth, 0, 0);
+
+ var outermostLayer = RandomOrganismGenerator.organismLayers;
+ var x, y;
+
+ // iterate from center to edge of organism
+ // layer 0 is the central cell of the organism
+ for (var layer = 1; layer <= outermostLayer; layer++) {
+
+ var someCellSpawned = false;
+ var spawnChance = RandomOrganismGenerator.cellSpawnChance * 1 - ((layer - 1) / outermostLayer);
+
+ // top
+ y = -layer;
+ for (x = -layer; x <= layer; x++)
+ someCellSpawned = RandomOrganismGenerator.trySpawnCell(organism, x, y, spawnChance);
+
+ // bottom
+ y = layer;
+ for (x = -layer; x <= layer; x++)
+ someCellSpawned = RandomOrganismGenerator.trySpawnCell(organism, x, y, spawnChance);
+
+ // left
+ x = -layer;
+ for (y = -layer + 1; y <= layer - 1; y++)
+ someCellSpawned = RandomOrganismGenerator.trySpawnCell(organism, x, y, spawnChance);
+
+ // right
+ x = layer;
+ for (y = -layer + 1; y < layer - 1; y++)
+ someCellSpawned = RandomOrganismGenerator.trySpawnCell(organism, x, y, spawnChance);
+
+ if (!someCellSpawned)
+ break;
+ }
+
+ // randomize the organism's brain
+ var decisions = organism.brain.decisions;
+ decisions[CellStates.empty.name] = Brain.Decision.getRandom();
+ decisions[CellStates.food.name] = Brain.Decision.getRandom();
+ decisions[CellStates.wall.name] = Brain.Decision.getRandom();
+ decisions[CellStates.mouth.name] = Brain.Decision.getRandom();
+ decisions[CellStates.producer.name] = Brain.Decision.getRandom();
+ decisions[CellStates.mover.name] = Brain.Decision.getRandom();
+ decisions[CellStates.killer.name] = Brain.Decision.getRandom();
+ decisions[CellStates.armor.name] = Brain.Decision.getRandom();
+ decisions[CellStates.eye.name] = Brain.Decision.getRandom();
+
+ return organism;
+ }
+
+ static trySpawnCell(organism, x, y, spawnChance) {
+
+ var neighbors = organism.anatomy.getNeighborsOfCell(x, y);
+ if (neighbors.length && Math.random() < spawnChance) {
+ organism.anatomy.addRandomizedCell(CellStates.getRandomLivingType(), x, y);
+ return true;
+ }
+ return false;
+ }
+
+}
+
+RandomOrganismGenerator.organismLayers = 2;
+RandomOrganismGenerator.cellSpawnChance = 0.75;
+
+module.exports = RandomOrganismGenerator;
\ No newline at end of file