diff --git a/README.md b/README.md index 97f57ca..1622d89 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # EvolutionSimulatorV2 Version 2 of the evolution simulator + +Requirements: +- npm +- webpack + +To build minified: `npm run build` +To build in dev mode: `npm run build-dev` +To build in dev/watch mode: `npm run build-watch` diff --git a/dist/bundle.js b/dist/bundle.js index c8fcfa3..36e7855 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -126,7 +126,7 @@ eval("const Environment = __webpack_require__(/*! ./Environment */ \"./src/Envir /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { -eval("const Grid = __webpack_require__(/*! ./GridMap */ \"./src/GridMap.js\");\r\nconst Renderer = __webpack_require__(/*! ./Rendering/Renderer */ \"./src/Rendering/Renderer.js\");\r\nconst GridMap = __webpack_require__(/*! ./GridMap */ \"./src/GridMap.js\");\r\nconst Organism = __webpack_require__(/*! ./Organism */ \"./src/Organism.js\");\r\nconst CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\nconst Cell = __webpack_require__(/*! ./Cell */ \"./src/Cell.js\");\r\nconst EnvironmentController = __webpack_require__(/*! ./EnvironmentController */ \"./src/EnvironmentController.js\");\r\n\r\nclass Environment{\r\n constructor(cell_size) {\r\n this.renderer = new Renderer('canvas', this, cell_size);\r\n this.controller = new EnvironmentController(this, this.renderer.canvas);\r\n this.grid_rows = Math.floor(this.renderer.height / cell_size);\r\n this.grid_cols = Math.floor(this.renderer.width / cell_size);\r\n this.grid_map = new GridMap(this.grid_cols, this.grid_rows, cell_size);\r\n this.renderer.renderFullGrid();\r\n this.organisms = [];\r\n }\r\n\r\n \r\n // {\r\n // running: 0,\r\n // paused: 1,\r\n // headless: 2\r\n // };\r\n\r\n update(delta_time) {\r\n var to_remove = [];\r\n for (var i in this.organisms) {\r\n var org = this.organisms[i];\r\n if (!org.update()) {\r\n to_remove.push(i);\r\n }\r\n }\r\n this.removeOrganisms(to_remove);\r\n }\r\n\r\n render() {\r\n // console.log(this.cells_to_render);\r\n this.renderer.renderCells();\r\n this.renderer.renderHighlights();\r\n }\r\n\r\n removeOrganisms(org_indeces) {\r\n for (var i of org_indeces.reverse()){\r\n this.organisms.splice(i, 1);\r\n }\r\n }\r\n\r\n OriginOfLife() {\r\n var center = this.grid_map.getCenter();\r\n var org = new Organism(center[0], center[1], this);\r\n org.addCell(CellTypes.mouth, -1, -1);\r\n org.addCell(CellTypes.producer, 0, 0);\r\n org.addCell(CellTypes.mouth, 1, 1);\r\n this.addOrganism(org);\r\n }\r\n\r\n addOrganism(organism) {\r\n organism.updateGrid();\r\n this.organisms.push(organism);\r\n }\r\n\r\n changeCell(c, r, type, owner) {\r\n this.grid_map.setCellType(c, r, type);\r\n this.grid_map.setCellOwner(c, r, owner);\r\n this.renderer.addToRender(this.grid_map.cellAt(c, r));\r\n }\r\n}\r\n\r\nmodule.exports = Environment;\r\n\r\n\n\n//# sourceURL=webpack:///./src/Environment.js?"); +eval("const Grid = __webpack_require__(/*! ./GridMap */ \"./src/GridMap.js\");\r\nconst Renderer = __webpack_require__(/*! ./Rendering/Renderer */ \"./src/Rendering/Renderer.js\");\r\nconst GridMap = __webpack_require__(/*! ./GridMap */ \"./src/GridMap.js\");\r\nconst Organism = __webpack_require__(/*! ./Organism */ \"./src/Organism.js\");\r\nconst CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\nconst Cell = __webpack_require__(/*! ./Cell */ \"./src/Cell.js\");\r\nconst EnvironmentController = __webpack_require__(/*! ./EnvironmentController */ \"./src/EnvironmentController.js\");\r\n\r\nclass Environment{\r\n constructor(cell_size) {\r\n this.renderer = new Renderer('canvas', this, cell_size);\r\n this.controller = new EnvironmentController(this, this.renderer.canvas);\r\n this.grid_rows = Math.floor(this.renderer.height / cell_size);\r\n this.grid_cols = Math.floor(this.renderer.width / cell_size);\r\n this.grid_map = new GridMap(this.grid_cols, this.grid_rows, cell_size);\r\n this.renderer.renderFullGrid();\r\n this.organisms = [];\r\n }\r\n\r\n update(delta_time) {\r\n var to_remove = [];\r\n for (var i in this.organisms) {\r\n var org = this.organisms[i];\r\n if (!org.update()) {\r\n to_remove.push(i);\r\n }\r\n }\r\n this.removeOrganisms(to_remove);\r\n }\r\n\r\n render() {\r\n // console.log(this.cells_to_render);\r\n this.renderer.renderCells();\r\n this.renderer.renderHighlights();\r\n }\r\n\r\n removeOrganisms(org_indeces) {\r\n for (var i of org_indeces.reverse()){\r\n this.organisms.splice(i, 1);\r\n }\r\n }\r\n\r\n OriginOfLife() {\r\n var center = this.grid_map.getCenter();\r\n var org = new Organism(center[0], center[1], this);\r\n org.addCell(CellTypes.mouth, -1, -1);\r\n org.addCell(CellTypes.producer, 0, 0);\r\n org.addCell(CellTypes.mouth, 1, 1);\r\n this.addOrganism(org);\r\n }\r\n\r\n addOrganism(organism) {\r\n organism.updateGrid();\r\n this.organisms.push(organism);\r\n }\r\n\r\n changeCell(c, r, type, owner) {\r\n this.grid_map.setCellType(c, r, type);\r\n this.grid_map.setCellOwner(c, r, owner);\r\n this.renderer.addToRender(this.grid_map.cellAt(c, r));\r\n }\r\n}\r\n\r\nmodule.exports = Environment;\r\n\r\n\n\n//# sourceURL=webpack:///./src/Environment.js?"); /***/ }), @@ -170,7 +170,7 @@ eval("const CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { -eval("const CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\nconst Cell = __webpack_require__(/*! ./Cell */ \"./src/Cell.js\");\r\nconst GridMap = __webpack_require__(/*! ./GridMap */ \"./src/GridMap.js\");\r\nconst LocalCell = __webpack_require__(/*! ./LocalCell */ \"./src/LocalCell.js\");\r\nconst { producer } = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\n\r\nclass Organism {\r\n constructor(col, row, env, parent=null) {\r\n this.c = col;\r\n this.r = row;\r\n this.env = env;\r\n this.lifetime = 0;\r\n this.food_collected = 0;\r\n this.living = true;\r\n this.cells = [];\r\n this.is_producer = false;\r\n this.is_mover = false;\r\n if (parent != null) {\r\n this.inherit(parent);\r\n }\r\n }\r\n\r\n addCell(type, c, r) {\r\n for (var cell of this.cells) {\r\n if (cell.loc_col == c && cell.loc_row == r)\r\n return false;\r\n }\r\n this.checkProducerMover(type);\r\n this.cells.push(new LocalCell(type, c, r));\r\n return true;\r\n }\r\n\r\n removeCell(c, r) {\r\n var check_change = false;\r\n for (var i=0; i 1) {\r\n this.cells.splice(Math.floor(Math.random() * this.cells.length), 1);\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n attemptMove(col, row) {\r\n var direction = this.getRandomDirection();\r\n var direction_c = direction[0];\r\n var direction_r = direction[1];\r\n var new_c = this.c + direction_c;\r\n var new_r = this.r + direction_r;\r\n if (this.isClear(new_c, new_r)) {\r\n for (var cell of this.cells) {\r\n var real_c = this.c + cell.loc_col;\r\n var real_r = this.r + cell.loc_row;\r\n this.env.changeCell(real_c, real_r, CellTypes.empty, null);\r\n }\r\n this.c = new_c;\r\n this.r = new_r;\r\n this.updateGrid();\r\n }\r\n }\r\n\r\n getRandomDirection(){\r\n var directions = [[0,1],[0,-1],[1,0],[-1,0]]\r\n return directions[Math.floor(Math.random() * directions.length)];\r\n }\r\n\r\n // assumes either c1==c2 or r1==r2, returns true if there is a clear path from point a to b\r\n isStraightPath(c1, r1, c2, r2, parent){\r\n // TODO FIX!!!\r\n if (c1 == c2) {\r\n if (r1 > r2){\r\n var temp = r2;\r\n r2 = r1;\r\n r1 = temp;\r\n }\r\n for (var i=r1; i!=r2; i++) {\r\n var cell = this.env.grid_map.cellAt(c1, i)\r\n if (!this.isPassableCell(cell, parent)){\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n else {\r\n if (c1 > c2){\r\n var temp = c2;\r\n c2 = c1;\r\n c1 = temp;\r\n }\r\n for (var i=c1; i!=c2; i++) {\r\n var cell = this.env.grid_map.cellAt(i, r1);\r\n if (!this.isPassableCell(cell, parent)){\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n }\r\n\r\n isPassableCell(cell, parent){\r\n return cell.type == CellTypes.empty || cell.owner == this || cell.owner == parent;\r\n }\r\n\r\n isClear(col, row) {\r\n for(var loccell of this.cells) {\r\n var cell = this.getRealCell(loccell, col, row);\r\n if(cell == null || cell.type != CellTypes.empty && cell.owner != this) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n die() {\r\n for (var cell of this.cells) {\r\n var real_c = this.c + cell.loc_col;\r\n var real_r = this.r + cell.loc_row;\r\n this.env.changeCell(real_c, real_r, CellTypes.food, null);\r\n }\r\n this.living = false;\r\n }\r\n\r\n updateGrid() {\r\n for (var cell of this.cells) {\r\n var real_c = this.c + cell.loc_col;\r\n var real_r = this.r + cell.loc_row;\r\n this.env.changeCell(real_c, real_r, cell.type, this);\r\n }\r\n }\r\n\r\n update() {\r\n // this.food_collected++;\r\n this.lifetime++;\r\n if (this.lifetime > this.lifespan()) {\r\n this.die();\r\n return this.living;\r\n }\r\n for (var cell of this.cells) {\r\n this.getRealCell(cell).performFunction(this.env);\r\n }\r\n if (!this.living){\r\n return this.living\r\n }\r\n if (this.is_mover) {\r\n this.attemptMove();\r\n }\r\n if (this.food_collected >= this.foodNeeded()) {\r\n this.reproduce();\r\n }\r\n\r\n return this.living;\r\n }\r\n\r\n getRealCell(local_cell, c=this.c, r=this.r){\r\n var real_c = c + local_cell.loc_col;\r\n var real_r = r + local_cell.loc_row;\r\n return this.env.grid_map.cellAt(real_c, real_r);\r\n }\r\n\r\n}\r\n\r\nmodule.exports = Organism;\r\n\n\n//# sourceURL=webpack:///./src/Organism.js?"); +eval("const CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\nconst Cell = __webpack_require__(/*! ./Cell */ \"./src/Cell.js\");\r\nconst GridMap = __webpack_require__(/*! ./GridMap */ \"./src/GridMap.js\");\r\nconst LocalCell = __webpack_require__(/*! ./LocalCell */ \"./src/LocalCell.js\");\r\nconst { producer } = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\n\r\nclass Organism {\r\n constructor(col, row, env, parent=null) {\r\n this.c = col;\r\n this.r = row;\r\n this.env = env;\r\n this.lifetime = 0;\r\n this.food_collected = 0;\r\n this.living = true;\r\n this.cells = [];\r\n this.is_producer = false;\r\n this.is_mover = false;\r\n this.direction = this.getRandomDirection();\r\n this.move_count = 0;\r\n this.move_range = 1;\r\n this.mutability = 5;\r\n if (parent != null) {\r\n this.inherit(parent);\r\n }\r\n }\r\n\r\n addCell(type, c, r) {\r\n for (var cell of this.cells) {\r\n if (cell.loc_col == c && cell.loc_row == r)\r\n return false;\r\n }\r\n this.checkProducerMover(type);\r\n this.cells.push(new LocalCell(type, c, r));\r\n return true;\r\n }\r\n\r\n removeCell(c, r) {\r\n var check_change = false;\r\n for (var i=0; i 1) {\r\n this.cells.splice(Math.floor(Math.random() * this.cells.length), 1);\r\n return true;\r\n }\r\n }\r\n\r\n if (this.is_mover) {\r\n this.move_range += Math.floor(Math.random() * 4) - 2;\r\n }\r\n return false;\r\n }\r\n\r\n attemptMove(direction) {\r\n var direction_c = direction[0];\r\n var direction_r = direction[1];\r\n var new_c = this.c + direction_c;\r\n var new_r = this.r + direction_r;\r\n if (this.isClear(new_c, new_r)) {\r\n for (var cell of this.cells) {\r\n var real_c = this.c + cell.loc_col;\r\n var real_r = this.r + cell.loc_row;\r\n this.env.changeCell(real_c, real_r, CellTypes.empty, null);\r\n }\r\n this.c = new_c;\r\n this.r = new_r;\r\n this.updateGrid();\r\n }\r\n }\r\n\r\n getRandomDirection(){\r\n var directions = [[0,1],[0,-1],[1,0],[-1,0]]\r\n return directions[Math.floor(Math.random() * directions.length)];\r\n }\r\n\r\n // assumes either c1==c2 or r1==r2, returns true if there is a clear path from point a to b\r\n isStraightPath(c1, r1, c2, r2, parent){\r\n // TODO FIX!!!\r\n if (c1 == c2) {\r\n if (r1 > r2){\r\n var temp = r2;\r\n r2 = r1;\r\n r1 = temp;\r\n }\r\n for (var i=r1; i!=r2; i++) {\r\n var cell = this.env.grid_map.cellAt(c1, i)\r\n if (!this.isPassableCell(cell, parent)){\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n else {\r\n if (c1 > c2){\r\n var temp = c2;\r\n c2 = c1;\r\n c1 = temp;\r\n }\r\n for (var i=c1; i!=c2; i++) {\r\n var cell = this.env.grid_map.cellAt(i, r1);\r\n if (!this.isPassableCell(cell, parent)){\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n }\r\n\r\n isPassableCell(cell, parent){\r\n return cell.type == CellTypes.empty || cell.owner == this || cell.owner == parent;\r\n }\r\n\r\n isClear(col, row) {\r\n for(var loccell of this.cells) {\r\n var cell = this.getRealCell(loccell, col, row);\r\n if(cell == null || cell.type != CellTypes.empty && cell.owner != this) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n die() {\r\n for (var cell of this.cells) {\r\n var real_c = this.c + cell.loc_col;\r\n var real_r = this.r + cell.loc_row;\r\n this.env.changeCell(real_c, real_r, CellTypes.food, null);\r\n }\r\n this.living = false;\r\n }\r\n\r\n updateGrid() {\r\n for (var cell of this.cells) {\r\n var real_c = this.c + cell.loc_col;\r\n var real_r = this.r + cell.loc_row;\r\n this.env.changeCell(real_c, real_r, cell.type, this);\r\n }\r\n }\r\n\r\n update() {\r\n // this.food_collected++;\r\n this.lifetime++;\r\n if (this.lifetime > this.lifespan()) {\r\n this.die();\r\n return this.living;\r\n }\r\n for (var cell of this.cells) {\r\n this.getRealCell(cell).performFunction(this.env);\r\n }\r\n if (!this.living){\r\n return this.living\r\n }\r\n if (this.is_mover) {\r\n this.move_count++;\r\n if (this.move_count > this.move_range){\r\n this.move_count = 0;\r\n this.direction = this.getRandomDirection()\r\n }\r\n this.attemptMove(this.direction);\r\n }\r\n if (this.food_collected >= this.foodNeeded()) {\r\n this.reproduce();\r\n }\r\n\r\n return this.living;\r\n }\r\n\r\n getRealCell(local_cell, c=this.c, r=this.r){\r\n var real_c = c + local_cell.loc_col;\r\n var real_r = r + local_cell.loc_row;\r\n return this.env.grid_map.cellAt(real_c, real_r);\r\n }\r\n\r\n}\r\n\r\nmodule.exports = Organism;\r\n\n\n//# sourceURL=webpack:///./src/Organism.js?"); /***/ }), diff --git a/src/Environment.js b/src/Environment.js index e01decf..3f33ecc 100644 --- a/src/Environment.js +++ b/src/Environment.js @@ -17,13 +17,6 @@ class Environment{ this.organisms = []; } - - // { - // running: 0, - // paused: 1, - // headless: 2 - // }; - update(delta_time) { var to_remove = []; for (var i in this.organisms) { diff --git a/src/Organism.js b/src/Organism.js index bd31d79..1e93c3c 100644 --- a/src/Organism.js +++ b/src/Organism.js @@ -15,6 +15,10 @@ class Organism { this.cells = []; this.is_producer = false; this.is_mover = false; + this.direction = this.getRandomDirection(); + this.move_count = 0; + this.move_range = 1; + this.mutability = 5; if (parent != null) { this.inherit(parent); } @@ -59,6 +63,8 @@ class Organism { } inherit(parent) { + this.move_range = parent.move_range; + this.mutability = parent.mutability; for (var c of parent.cells){ //deep copy parent cells this.addCell(c.type, c.loc_col, c.loc_row); @@ -78,18 +84,22 @@ class Organism { //produce mutated child //check nearby locations (is there room and a direct path) var org = new Organism(0, 0, this.env, this); - if (Math.random() * 100 <= 5) { + if (Math.random() * 100 <= this.mutability) { org.mutate(); } + else if (Math.random() * 100 <= 2) { + org.mutability--; + if (org.mutability < 1) + org.mutability = 1; + } var direction = this.getRandomDirection(); var direction_c = direction[0]; var direction_r = direction[1]; - var boost = Math.floor(Math.random() * 2) + 1; - boost = 1; + var offset = (Math.floor(Math.random() * 2)); - var new_c = this.c + (direction_c*this.cells.length*2) + (direction_c*boost); - var new_r = this.r + (direction_r*this.cells.length*2) + (direction_r*boost); + var new_c = this.c + (direction_c*this.cells.length*2) + (direction_c*offset); + var new_r = this.r + (direction_r*this.cells.length*2) + (direction_r*offset); if (org.isClear(new_c, new_r)){// && org.isStraightPath(new_c, new_r, this.c, this.r, this)){ org.c = new_c; org.r = new_r; @@ -103,6 +113,7 @@ class Organism { } mutate() { + this.mutability += 2; var choice = Math.floor(Math.random() * 3); if (choice == 0) { var type = CellTypes.getRandomLivingType(); @@ -125,11 +136,14 @@ class Organism { return true; } } + + if (this.is_mover) { + this.move_range += Math.floor(Math.random() * 4) - 2; + } return false; } - attemptMove(col, row) { - var direction = this.getRandomDirection(); + attemptMove(direction) { var direction_c = direction[0]; var direction_r = direction[1]; var new_c = this.c + direction_c; @@ -229,7 +243,12 @@ class Organism { return this.living } if (this.is_mover) { - this.attemptMove(); + this.move_count++; + if (this.move_count > this.move_range){ + this.move_count = 0; + this.direction = this.getRandomDirection() + } + this.attemptMove(this.direction); } if (this.food_collected >= this.foodNeeded()) { this.reproduce();