diff --git a/dist/css/style.css b/dist/css/style.css
index 3b15873..a0624dc 100644
--- a/dist/css/style.css
+++ b/dist/css/style.css
@@ -75,6 +75,7 @@ button {
display: inline-block;
font-size: 16px;
min-width: 30px;
+ margin: 2px;
}
button:hover{
background-color: #81d2c7;
diff --git a/dist/index.html b/dist/index.html
index 99fba39..5585f26 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -35,6 +35,8 @@
+
+
diff --git a/src/Controllers/ControlPanel.js b/src/Controllers/ControlPanel.js
index 5396a9e..fcbe8b3 100644
--- a/src/Controllers/ControlPanel.js
+++ b/src/Controllers/ControlPanel.js
@@ -327,6 +327,9 @@ class ControlPanel {
env.auto_reset = false;
$('#auto-reset').prop('checked', false);;
});
+ $('#random-walls').click( function() {
+ this.env_controller.randomizeWalls();
+ }.bind(this));
$('#auto-reset').change(function() {
env.auto_reset = this.checked;
});
diff --git a/src/Controllers/EnvironmentController.js b/src/Controllers/EnvironmentController.js
index 8722d61..5e8b963 100644
--- a/src/Controllers/EnvironmentController.js
+++ b/src/Controllers/EnvironmentController.js
@@ -5,6 +5,7 @@ const CellStates = require("../Organism/Cell/CellStates");
const Neighbors = require("../Grid/Neighbors");
const FossilRecord = require("../Stats/FossilRecord");
const Hyperparams = require("../Hyperparameters");
+const Perlin = require("../Utils/Perlin");
class EnvironmentController extends CanvasController{
constructor(env, canvas) {
@@ -51,8 +52,34 @@ class EnvironmentController extends CanvasController{
this.scale = 1;
}
+ /*
+ Iterate over grid from 0,0 to env.num_cols,env.num_rows and create random walls using perlin noise to create a more organic shape.
+ */
+ randomizeWalls(thickness=1) {
+ this.env.clearWalls();
+ const noise_threshold = -0.017;
+ let avg_noise = 0;
+ let resolution = 20;
+ Perlin.seed();
+
+ for (let r = 0; r < this.env.num_rows; r++) {
+ for (let c = 0; c < this.env.num_cols; c++) {
+ let xval = c/this.env.num_cols*(resolution/this.env.renderer.cell_size*(this.env.num_cols/this.env.num_rows));
+ let yval = r/this.env.num_rows*(resolution/this.env.renderer.cell_size*(this.env.num_rows/this.env.num_cols));
+ let noise = Perlin.get(xval, yval);
+ avg_noise += noise/(this.env.num_rows*this.env.num_cols);
+ if (noise > noise_threshold && noise < noise_threshold + thickness/resolution) {
+ let cell = this.env.grid_map.cellAt(c, r);
+ if (cell != null) {
+ if(cell.owner != null) cell.owner.die();
+ this.env.changeCell(c, r, CellStates.wall, null);
+ }
+ }
+ }
+ }
+ }
+
updateMouseLocation(offsetX, offsetY){
-
super.updateMouseLocation(offsetX, offsetY);
}
diff --git a/src/Environments/WorldEnvironment.js b/src/Environments/WorldEnvironment.js
index 1da6c73..fdf48c3 100644
--- a/src/Environments/WorldEnvironment.js
+++ b/src/Environments/WorldEnvironment.js
@@ -12,9 +12,9 @@ class WorldEnvironment extends Environment{
super();
this.renderer = new Renderer('env-canvas', 'env', cell_size);
this.controller = new EnvironmentController(this, this.renderer.canvas);
- var grid_rows = Math.ceil(this.renderer.height / cell_size);
- var grid_cols = Math.ceil(this.renderer.width / cell_size);
- this.grid_map = new GridMap(grid_cols, grid_rows, cell_size);
+ this.num_rows = Math.ceil(this.renderer.height / cell_size);
+ this.num_cols = Math.ceil(this.renderer.width / cell_size);
+ this.grid_map = new GridMap(this.num_cols, this.num_rows, cell_size);
this.organisms = [];
this.walls = [];
this.total_mutability = 0;
@@ -104,7 +104,8 @@ class WorldEnvironment extends Environment{
clearWalls() {
for(var wall of this.walls){
- if (this.grid_map.cellAt(wall.col, wall.row).state == CellStates.wall)
+ let wcell = this.grid_map.cellAt(wall.col, wall.row);
+ if (wcell && wcell.state == CellStates.wall)
this.changeCell(wall.col, wall.row, CellStates.empty, null);
}
}
@@ -154,9 +155,9 @@ class WorldEnvironment extends Environment{
resizeFillWindow(cell_size) {
this.renderer.cell_size = cell_size;
this.renderer.fillWindow('env');
- var cols = Math.ceil(this.renderer.width / cell_size);
- var rows = Math.ceil(this.renderer.height / cell_size);
- this.grid_map.resize(cols, rows, cell_size);
+ this.num_cols = Math.ceil(this.renderer.width / cell_size);
+ this.num_rows = Math.ceil(this.renderer.height / cell_size);
+ this.grid_map.resize(this.num_cols, this.num_rows, cell_size);
}
}
diff --git a/src/Utils/Perlin.js b/src/Utils/Perlin.js
new file mode 100644
index 0000000..ab9b5ca
--- /dev/null
+++ b/src/Utils/Perlin.js
@@ -0,0 +1,46 @@
+let perlin = {
+ rand_vect: function(){
+ let theta = Math.random() * 2 * Math.PI;
+ return {x: Math.cos(theta), y: Math.sin(theta)};
+ },
+ dot_prod_grid: function(x, y, vx, vy){
+ let g_vect;
+ let d_vect = {x: x - vx, y: y - vy};
+ if (this.gradients[[vx,vy]]){
+ g_vect = this.gradients[[vx,vy]];
+ } else {
+ g_vect = this.rand_vect();
+ this.gradients[[vx, vy]] = g_vect;
+ }
+ return d_vect.x * g_vect.x + d_vect.y * g_vect.y;
+ },
+ smootherstep: function(x){
+ return 6*x**5 - 15*x**4 + 10*x**3;
+ },
+ interp: function(x, a, b){
+ return a + this.smootherstep(x) * (b-a);
+ },
+ seed: function(){
+ this.gradients = {};
+ this.memory = {};
+ },
+ get: function(x, y) {
+ if (this.memory.hasOwnProperty([x,y]))
+ return this.memory[[x,y]];
+ let xf = Math.floor(x);
+ let yf = Math.floor(y);
+ //interpolate
+ let tl = this.dot_prod_grid(x, y, xf, yf);
+ let tr = this.dot_prod_grid(x, y, xf+1, yf);
+ let bl = this.dot_prod_grid(x, y, xf, yf+1);
+ let br = this.dot_prod_grid(x, y, xf+1, yf+1);
+ let xt = this.interp(x-xf, tl, tr);
+ let xb = this.interp(x-xf, bl, br);
+ let v = this.interp(y-yf, xt, xb);
+ this.memory[[x,y]] = v;
+ return v;
+ }
+}
+perlin.seed();
+
+module.exports = perlin;
\ No newline at end of file