diff --git a/dist/bundle.js b/dist/bundle.js index 36e7855..ce1fe87 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -93,7 +93,7 @@ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { -eval("const CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\n\r\n// A cell exists in a grid system.\r\nclass Cell{\r\n constructor(type, col, row, x, y){\r\n this.owner = null;\r\n this.setType(type);\r\n this.col = col;\r\n this.row = row;\r\n this.x = x;\r\n this.y = y;\r\n }\r\n\r\n setType(type) {\r\n this.type = type;\r\n }\r\n\r\n performFunction(env) {\r\n switch(this.type){\r\n case CellTypes.mouth:\r\n eatFood(this, env);\r\n break;\r\n case CellTypes.producer:\r\n growFood(this, env);\r\n break;\r\n case CellTypes.killer:\r\n killNeighbors(this, env);\r\n break;\r\n }\r\n }\r\n\r\n getColor() {\r\n return CellTypes.colors[this.type];\r\n }\r\n\r\n isLiving() {\r\n return this.type != CellTypes.empty && \r\n this.type != CellTypes.food && \r\n this.type != CellTypes.wall;\r\n }\r\n}\r\n\r\nfunction eatFood(self, env){\r\n eatNeighborFood(env.grid_map.cellAt(self.col+1, self.row), self, env);\r\n eatNeighborFood(env.grid_map.cellAt(self.col-1, self.row), self, env);\r\n eatNeighborFood(env.grid_map.cellAt(self.col, self.row+1), self, env);\r\n eatNeighborFood(env.grid_map.cellAt(self.col, self.row-1), self, env);\r\n}\r\n\r\nfunction eatNeighborFood(n_cell, self, env){\r\n if (n_cell == null)\r\n return;\r\n if (n_cell.type == CellTypes.food){\r\n env.changeCell(n_cell.col, n_cell.row, CellTypes.empty, null);\r\n self.owner.food_collected++;\r\n }\r\n}\r\n\r\nfunction growFood(self, env){\r\n if (self.owner.is_mover)\r\n return;\r\n for (var c=-1; c<=1; c++){\r\n for (var r=-1; r<=1; r++){\r\n if (r==0 && c==0)\r\n continue;\r\n var cell = env.grid_map.cellAt(self.col+c, self.row+r);\r\n if (cell != null && cell.type == CellTypes.empty && Math.random() * 100 <= 0.5){\r\n env.changeCell(self.col+c, self.row+r, CellTypes.food, null);\r\n return;\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction killNeighbors(self, env) {\r\n killNeighbor(env.grid_map.cellAt(self.col+1, self.row));\r\n killNeighbor(env.grid_map.cellAt(self.col-1, self.row));\r\n killNeighbor(env.grid_map.cellAt(self.col, self.row+1));\r\n killNeighbor(env.grid_map.cellAt(self.col, self.row-1));\r\n}\r\n\r\nfunction killNeighbor(n_cell) {\r\n if(n_cell == null) {\r\n return\r\n }\r\n if (n_cell.type != CellTypes.armor && n_cell.owner != null && n_cell.owner != self.owner && n_cell.owner.living){\r\n n_cell.owner.die();\r\n if (n_cell == CellTypes.killer){\r\n self.owner.die();\r\n }\r\n }\r\n}\r\n\r\nmodule.exports = Cell;\r\n\n\n//# sourceURL=webpack:///./src/Cell.js?"); +eval("const CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes.js\");\r\n\r\n// A cell exists in a grid system.\r\nclass Cell{\r\n constructor(type, col, row, x, y){\r\n this.owner = null;\r\n this.setType(type);\r\n this.col = col;\r\n this.row = row;\r\n this.x = x;\r\n this.y = y;\r\n }\r\n\r\n setType(type) {\r\n this.type = type;\r\n }\r\n\r\n performFunction(env) {\r\n switch(this.type){\r\n case CellTypes.mouth:\r\n eatFood(this, env);\r\n break;\r\n case CellTypes.producer:\r\n growFood(this, env);\r\n break;\r\n case CellTypes.killer:\r\n killNeighbors(this, env);\r\n break;\r\n }\r\n }\r\n\r\n getColor() {\r\n return CellTypes.colors[this.type];\r\n }\r\n\r\n isLiving() {\r\n return this.type != CellTypes.empty && \r\n this.type != CellTypes.food && \r\n this.type != CellTypes.wall;\r\n }\r\n}\r\n\r\nfunction eatFood(self, env){\r\n eatNeighborFood(env.grid_map.cellAt(self.col+1, self.row), self, env);\r\n eatNeighborFood(env.grid_map.cellAt(self.col-1, self.row), self, env);\r\n eatNeighborFood(env.grid_map.cellAt(self.col, self.row+1), self, env);\r\n eatNeighborFood(env.grid_map.cellAt(self.col, self.row-1), self, env);\r\n}\r\n\r\nfunction eatNeighborFood(n_cell, self, env){\r\n if (n_cell == null)\r\n return;\r\n if (n_cell.type == CellTypes.food){\r\n env.changeCell(n_cell.col, n_cell.row, CellTypes.empty, null);\r\n self.owner.food_collected++;\r\n }\r\n}\r\n\r\nfunction growFood(self, env){\r\n if (self.owner.is_mover)\r\n return;\r\n for (var c=-1; c<=1; c++){\r\n for (var r=-1; r<=1; r++){\r\n if (r==0 && c==0)\r\n continue;\r\n var cell = env.grid_map.cellAt(self.col+c, self.row+r);\r\n if (cell != null && cell.type == CellTypes.empty && Math.random() * 100 <= 1){\r\n env.changeCell(self.col+c, self.row+r, CellTypes.food, null);\r\n return;\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction killNeighbors(self, env) {\r\n killNeighbor(self, env.grid_map.cellAt(self.col+1, self.row));\r\n killNeighbor(self, env.grid_map.cellAt(self.col-1, self.row));\r\n killNeighbor(self, env.grid_map.cellAt(self.col, self.row+1));\r\n killNeighbor(self, env.grid_map.cellAt(self.col, self.row-1));\r\n}\r\n\r\nfunction killNeighbor(self, n_cell) {\r\n if(n_cell == null) {\r\n // console.log(\"null cell\")\r\n return;\r\n }\r\n if(n_cell.owner == null) {\r\n // console.log(\"is no one's cell\")\r\n return;\r\n }\r\n if(n_cell.owner == self.owner) {\r\n // console.log(\"is my cell\")\r\n return;\r\n }\r\n if (!n_cell.owner.living) {\r\n // console.log(\"cell is dead\")\r\n return;\r\n }\r\n if (n_cell.type == CellTypes.armor) {\r\n // console.log(\"armor block\")\r\n // self.owner.die();\r\n return\r\n }\r\n var should_die = n_cell.type == CellTypes.killer; // has to be calculated before death\r\n n_cell.owner.die();\r\n if (should_die){\r\n self.owner.die();\r\n }\r\n}\r\n\r\nmodule.exports = Cell;\r\n\n\n//# sourceURL=webpack:///./src/Cell.js?"); /***/ }), @@ -108,6 +108,17 @@ eval("const CellTypes = {\r\n empty: 0,\r\n food: 1,\r\n wall: 2,\r\n /***/ }), +/***/ "./src/ControlPanel.js": +/*!*****************************!*\ + !*** ./src/ControlPanel.js ***! + \*****************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +eval("\r\nclass ControlPanel {\r\n constructor(engine) {\r\n this.engine = engine;\r\n this.defineEngineSpeedControls();\r\n this.fps = engine.fps;\r\n }\r\n\r\n defineEngineSpeedControls(){\r\n this.slider = document.getElementById(\"slider\");\r\n this.slider.oninput = function() {\r\n this.fps = this.slider.value\r\n if (this.engine.running) {\r\n this.changeEngineSpeed(this.fps);\r\n }\r\n }.bind(this);\r\n $('#pause-button').click(function() {\r\n if ($('#pause-button').text() == \"Pause\" && this.engine.running) {\r\n $('#pause-button').text(\"Play\")\r\n this.engine.stop();\r\n }\r\n else if (!this.engine.running){\r\n $('#pause-button').text(\"Pause\")\r\n this.engine.start(this.fps);\r\n }\r\n console.log()\r\n }.bind(this));\r\n }\r\n\r\n changeEngineSpeed(change_val) {\r\n this.engine.stop();\r\n this.engine.start(change_val)\r\n this.fps = this.engine.fps;\r\n }\r\n\r\n}\r\n\r\n\r\nmodule.exports = ControlPanel;\n\n//# sourceURL=webpack:///./src/ControlPanel.js?"); + +/***/ }), + /***/ "./src/Engine.js": /*!***********************!*\ !*** ./src/Engine.js ***! @@ -115,7 +126,7 @@ eval("const CellTypes = {\r\n empty: 0,\r\n food: 1,\r\n wall: 2,\r\n /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { -eval("const Environment = __webpack_require__(/*! ./Environment */ \"./src/Environment.js\");\r\n\r\nclass Engine{\r\n constructor(){\r\n this.fps = 0;\r\n this.environment = new Environment(5);\r\n this.environment.OriginOfLife();\r\n this.last_update = Date.now();\r\n this.delta_time = 0;\r\n this.running = false;\r\n }\r\n\r\n start(fps=60) {\r\n this.fps = fps;\r\n this.game_loop = setInterval(function(){this.update();}.bind(this), 1000/fps);\r\n this.runnning = true;\r\n }\r\n \r\n stop() {\r\n clearInterval(this.game_loop);\r\n this.running = false;\r\n }\r\n\r\n\r\n update() {\r\n this.delta_time = Date.now() - this.last_update;\r\n this.last_update = Date.now();\r\n this.environment.update(this.delta_time);\r\n this.environment.render();\r\n }\r\n\r\n}\r\n\r\nmodule.exports = Engine;\r\n\n\n//# sourceURL=webpack:///./src/Engine.js?"); +eval("const Environment = __webpack_require__(/*! ./Environment */ \"./src/Environment.js\");\r\nconst ControlPanel = __webpack_require__(/*! ./ControlPanel */ \"./src/ControlPanel.js\");\r\n\r\nclass Engine{\r\n constructor(){\r\n this.fps = 0;\r\n this.environment = new Environment(5);\r\n this.controlpanel = new ControlPanel(this);\r\n this.environment.OriginOfLife();\r\n this.last_update = Date.now();\r\n this.delta_time = 0;\r\n this.actual_fps = 0;\r\n this.running = false;\r\n }\r\n\r\n start(fps=60) {\r\n if (fps <= 0)\r\n fps = 1;\r\n if (fps > 500)\r\n fps = 500;\r\n this.fps = fps;\r\n this.game_loop = setInterval(function(){this.update();}.bind(this), 1000/fps);\r\n this.running = true;\r\n }\r\n \r\n stop() {\r\n clearInterval(this.game_loop);\r\n this.running = false;\r\n }\r\n\r\n\r\n update() {\r\n this.delta_time = Date.now() - this.last_update;\r\n this.last_update = Date.now();\r\n this.environment.update(this.delta_time);\r\n this.environment.render();\r\n this.actual_fps = 1/this.delta_time*1000;\r\n }\r\n\r\n}\r\n\r\nmodule.exports = Engine;\r\n\n\n//# sourceURL=webpack:///./src/Engine.js?"); /***/ }), @@ -170,7 +181,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 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?"); +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 return true;\r\n }\r\n return false;\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 if (this.food_collected >= this.foodNeeded()) {\r\n this.reproduce();\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 var success = this.attemptMove(this.direction);\r\n if (this.move_count > this.move_range || !success){\r\n this.move_count = 0;\r\n this.direction = this.getRandomDirection()\r\n }\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?"); /***/ }), @@ -181,7 +192,7 @@ eval("const CellTypes = __webpack_require__(/*! ./CellTypes */ \"./src/CellTypes /*! no static exports found */ /***/ (function(module, exports) { -eval("\r\n// Renderer controls access to a canvas. There is one renderer for each canvas\r\nclass Renderer {\r\n constructor(canvas_id, env, cell_size) {\r\n this.cell_size = cell_size;\r\n this.env = env;\r\n this.canvas = document.getElementById(canvas_id);\r\n this.ctx = canvas.getContext(\"2d\");\r\n this.canvas.width = window.innerWidth;\r\n this.canvas.height = window.innerHeight;\r\n\t\tthis.height = canvas.height;\r\n this.width = canvas.width;\r\n this.cells_to_render = new Set();\r\n this.cells_to_highlight = new Set();\r\n this.highlighted_cells = new Set();\r\n }\r\n\r\n clear() {\r\n this.ctx.fillStyle = 'white';\r\n this.ctx.fillRect(0, 0, this.height, this.width);\r\n }\r\n\r\n renderFullGrid() {\r\n var grid = this.env.grid_map.grid;\r\n for (var col of grid) {\r\n for (var cell of col){\r\n this.ctx.fillStyle = cell.getColor();\r\n this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);\r\n }\r\n }\r\n }\r\n\r\n renderCells() {\r\n for (var cell of this.cells_to_render) {\r\n this.renderCell(cell);\r\n }\r\n this.cells_to_render.clear();\r\n }\r\n\r\n renderCell(cell) {\r\n this.ctx.fillStyle = cell.getColor();\r\n this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);\r\n }\r\n\r\n renderOrganism(org) {\r\n for(var org_cell of org.cells) {\r\n var cell = org.getRealCell(org_cell);\r\n this.renderCell(cell);\r\n }\r\n }\r\n\r\n addToRender(cell) {\r\n if (this.highlighted_cells.has(cell)){\r\n this.cells_to_highlight.add(cell);\r\n }\r\n this.cells_to_render.add(cell);\r\n }\r\n\r\n renderHighlights() {\r\n for (var cell of this.cells_to_highlight) {\r\n this.renderCellHighlight(cell);\r\n this.highlighted_cells.add(cell);\r\n }\r\n this.cells_to_highlight.clear();\r\n \r\n }\r\n\r\n highlightOrganism(org) {\r\n for(var org_cell of org.cells) {\r\n var cell = org.getRealCell(org_cell);\r\n this.cells_to_highlight.add(cell);\r\n }\r\n }\r\n\r\n highlightCell(cell) {\r\n this.cells_to_highlight.add(cell);\r\n }\r\n\r\n renderCellHighlight(cell, color=\"yellow\") {\r\n this.renderCell(cell);\r\n this.ctx.fillStyle = color;\r\n this.ctx.globalAlpha = 0.5;\r\n this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);\r\n this.ctx.globalAlpha = 1;\r\n this.highlighted_cells.add(cell);\r\n }\r\n\r\n clearAllHighlights(clear_to_highlight=false) {\r\n for (var cell of this.highlighted_cells) {\r\n this.renderCell(cell);\r\n }\r\n this.highlighted_cells.clear();\r\n if (clear_to_highlight) {\r\n this.cells_to_highlight.clear();\r\n }\r\n }\r\n}\r\n\r\n// $(\"body\").mousemove(function(e) {\r\n// console.log(\"hello\");\r\n// });\r\n\r\nmodule.exports = Renderer;\r\n\n\n//# sourceURL=webpack:///./src/Rendering/Renderer.js?"); +eval("\r\n// Renderer controls access to a canvas. There is one renderer for each canvas\r\nclass Renderer {\r\n constructor(canvas_id, env, cell_size) {\r\n this.cell_size = cell_size;\r\n this.env = env;\r\n this.canvas = document.getElementById(canvas_id);\r\n this.ctx = this.canvas.getContext(\"2d\");\r\n this.canvas.width = $('.env').width();\r\n this.canvas.height = $('.env').height();\r\n\t\tthis.height = canvas.height;\r\n this.width = canvas.width;\r\n this.cells_to_render = new Set();\r\n this.cells_to_highlight = new Set();\r\n this.highlighted_cells = new Set();\r\n }\r\n\r\n clear() {\r\n this.ctx.fillStyle = 'white';\r\n this.ctx.fillRect(0, 0, this.height, this.width);\r\n }\r\n\r\n renderFullGrid() {\r\n var grid = this.env.grid_map.grid;\r\n for (var col of grid) {\r\n for (var cell of col){\r\n this.ctx.fillStyle = cell.getColor();\r\n this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);\r\n }\r\n }\r\n }\r\n\r\n renderCells() {\r\n for (var cell of this.cells_to_render) {\r\n this.renderCell(cell);\r\n }\r\n this.cells_to_render.clear();\r\n }\r\n\r\n renderCell(cell) {\r\n this.ctx.fillStyle = cell.getColor();\r\n this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);\r\n }\r\n\r\n renderOrganism(org) {\r\n for(var org_cell of org.cells) {\r\n var cell = org.getRealCell(org_cell);\r\n this.renderCell(cell);\r\n }\r\n }\r\n\r\n addToRender(cell) {\r\n if (this.highlighted_cells.has(cell)){\r\n this.cells_to_highlight.add(cell);\r\n }\r\n this.cells_to_render.add(cell);\r\n }\r\n\r\n renderHighlights() {\r\n for (var cell of this.cells_to_highlight) {\r\n this.renderCellHighlight(cell);\r\n this.highlighted_cells.add(cell);\r\n }\r\n this.cells_to_highlight.clear();\r\n \r\n }\r\n\r\n highlightOrganism(org) {\r\n for(var org_cell of org.cells) {\r\n var cell = org.getRealCell(org_cell);\r\n this.cells_to_highlight.add(cell);\r\n }\r\n }\r\n\r\n highlightCell(cell) {\r\n this.cells_to_highlight.add(cell);\r\n }\r\n\r\n renderCellHighlight(cell, color=\"yellow\") {\r\n this.renderCell(cell);\r\n this.ctx.fillStyle = color;\r\n this.ctx.globalAlpha = 0.5;\r\n this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);\r\n this.ctx.globalAlpha = 1;\r\n this.highlighted_cells.add(cell);\r\n }\r\n\r\n clearAllHighlights(clear_to_highlight=false) {\r\n for (var cell of this.highlighted_cells) {\r\n this.renderCell(cell);\r\n }\r\n this.highlighted_cells.clear();\r\n if (clear_to_highlight) {\r\n this.cells_to_highlight.clear();\r\n }\r\n }\r\n}\r\n\r\n// $(\"body\").mousemove(function(e) {\r\n// console.log(\"hello\");\r\n// });\r\n\r\nmodule.exports = Renderer;\r\n\n\n//# sourceURL=webpack:///./src/Rendering/Renderer.js?"); /***/ }), @@ -193,7 +204,7 @@ eval("\r\n// Renderer controls access to a canvas. There is one renderer for eac /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Engine */ \"./src/Engine.js\");\n/* harmony import */ var _Engine__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_Engine__WEBPACK_IMPORTED_MODULE_0__);\n'user strict';\r\n\r\n\r\n\r\nvar engine = new _Engine__WEBPACK_IMPORTED_MODULE_0___default.a();\r\nengine.start(45);\n\n//# sourceURL=webpack:///./src/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Engine */ \"./src/Engine.js\");\n/* harmony import */ var _Engine__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_Engine__WEBPACK_IMPORTED_MODULE_0__);\n'user strict';\r\n\r\n\r\n\r\n$('document').ready(function(){\r\n var engine = new _Engine__WEBPACK_IMPORTED_MODULE_0___default.a();\r\n engine.start(60);\r\n});\r\n\n\n//# sourceURL=webpack:///./src/index.js?"); /***/ }) diff --git a/dist/css/style.css b/dist/css/style.css index 3b47219..ea26f29 100644 --- a/dist/css/style.css +++ b/dist/css/style.css @@ -6,9 +6,44 @@ body{ canvas { display: block; + } * { margin: 0; padding: 0; +} + +.env { + height: 80vh; + position: static; +} + +.control-panel { + height: 20vh; + width: 100vw; + background-color: gray; + position: fixed; + display: grid; +} + +.control-set { + margin: 5px; + padding: 5px; + border: 10px; + border-color: black; + grid-row: 1; + height: 100%; +} + +#speed-controller { + grid-column: 1; +} + +#hyperparameters { + grid-column: 2; +} + +#powers { + grid-column: 3; } \ No newline at end of file diff --git a/dist/html/index.html b/dist/html/index.html index 8450a8e..751fa52 100644 --- a/dist/html/index.html +++ b/dist/html/index.html @@ -4,9 +4,29 @@ Evolution Simulator + - +
+ +
+ +
+
+

Simulation Speed

+ + +
+ +
+

Hyperparameters

+
+ +
+

Powers

+
+
+ \ No newline at end of file diff --git a/src/Cell.js b/src/Cell.js index 088ee35..2239b16 100644 --- a/src/Cell.js +++ b/src/Cell.js @@ -64,7 +64,7 @@ function growFood(self, env){ if (r==0 && c==0) continue; var cell = env.grid_map.cellAt(self.col+c, self.row+r); - if (cell != null && cell.type == CellTypes.empty && Math.random() * 100 <= 0.5){ + if (cell != null && cell.type == CellTypes.empty && Math.random() * 100 <= 1){ env.changeCell(self.col+c, self.row+r, CellTypes.food, null); return; } @@ -73,21 +73,38 @@ function growFood(self, env){ } function killNeighbors(self, env) { - killNeighbor(env.grid_map.cellAt(self.col+1, self.row)); - killNeighbor(env.grid_map.cellAt(self.col-1, self.row)); - killNeighbor(env.grid_map.cellAt(self.col, self.row+1)); - killNeighbor(env.grid_map.cellAt(self.col, self.row-1)); + killNeighbor(self, env.grid_map.cellAt(self.col+1, self.row)); + killNeighbor(self, env.grid_map.cellAt(self.col-1, self.row)); + killNeighbor(self, env.grid_map.cellAt(self.col, self.row+1)); + killNeighbor(self, env.grid_map.cellAt(self.col, self.row-1)); } -function killNeighbor(n_cell) { +function killNeighbor(self, n_cell) { if(n_cell == null) { + // console.log("null cell") + return; + } + if(n_cell.owner == null) { + // console.log("is no one's cell") + return; + } + if(n_cell.owner == self.owner) { + // console.log("is my cell") + return; + } + if (!n_cell.owner.living) { + // console.log("cell is dead") + return; + } + if (n_cell.type == CellTypes.armor) { + // console.log("armor block") + // self.owner.die(); return } - if (n_cell.type != CellTypes.armor && n_cell.owner != null && n_cell.owner != self.owner && n_cell.owner.living){ - n_cell.owner.die(); - if (n_cell == CellTypes.killer){ - self.owner.die(); - } + var should_die = n_cell.type == CellTypes.killer; // has to be calculated before death + n_cell.owner.die(); + if (should_die){ + self.owner.die(); } } diff --git a/src/ControlPanel.js b/src/ControlPanel.js new file mode 100644 index 0000000..48b907a --- /dev/null +++ b/src/ControlPanel.js @@ -0,0 +1,39 @@ + +class ControlPanel { + constructor(engine) { + this.engine = engine; + this.defineEngineSpeedControls(); + this.fps = engine.fps; + } + + defineEngineSpeedControls(){ + this.slider = document.getElementById("slider"); + this.slider.oninput = function() { + this.fps = this.slider.value + if (this.engine.running) { + this.changeEngineSpeed(this.fps); + } + }.bind(this); + $('#pause-button').click(function() { + if ($('#pause-button').text() == "Pause" && this.engine.running) { + $('#pause-button').text("Play") + this.engine.stop(); + } + else if (!this.engine.running){ + $('#pause-button').text("Pause") + this.engine.start(this.fps); + } + console.log() + }.bind(this)); + } + + changeEngineSpeed(change_val) { + this.engine.stop(); + this.engine.start(change_val) + this.fps = this.engine.fps; + } + +} + + +module.exports = ControlPanel; \ No newline at end of file diff --git a/src/Engine.js b/src/Engine.js index a08757c..78b8d18 100644 --- a/src/Engine.js +++ b/src/Engine.js @@ -1,19 +1,26 @@ const Environment = require('./Environment'); +const ControlPanel = require('./ControlPanel'); class Engine{ constructor(){ this.fps = 0; this.environment = new Environment(5); + this.controlpanel = new ControlPanel(this); this.environment.OriginOfLife(); this.last_update = Date.now(); this.delta_time = 0; + this.actual_fps = 0; this.running = false; } start(fps=60) { + if (fps <= 0) + fps = 1; + if (fps > 500) + fps = 500; this.fps = fps; this.game_loop = setInterval(function(){this.update();}.bind(this), 1000/fps); - this.runnning = true; + this.running = true; } stop() { @@ -27,6 +34,7 @@ class Engine{ this.last_update = Date.now(); this.environment.update(this.delta_time); this.environment.render(); + this.actual_fps = 1/this.delta_time*1000; } } diff --git a/src/Organism.js b/src/Organism.js index 1e93c3c..66d286c 100644 --- a/src/Organism.js +++ b/src/Organism.js @@ -39,7 +39,7 @@ class Organism { for (var i=0; i= this.foodNeeded()) { + this.reproduce(); + } for (var cell of this.cells) { this.getRealCell(cell).performFunction(this.env); } @@ -244,14 +254,11 @@ class Organism { } if (this.is_mover) { this.move_count++; - if (this.move_count > this.move_range){ + var success = this.attemptMove(this.direction); + if (this.move_count > this.move_range || !success){ this.move_count = 0; this.direction = this.getRandomDirection() } - this.attemptMove(this.direction); - } - if (this.food_collected >= this.foodNeeded()) { - this.reproduce(); } return this.living; diff --git a/src/Rendering/Renderer.js b/src/Rendering/Renderer.js index f3e5c9b..2eac3d4 100644 --- a/src/Rendering/Renderer.js +++ b/src/Rendering/Renderer.js @@ -5,9 +5,9 @@ class Renderer { this.cell_size = cell_size; this.env = env; this.canvas = document.getElementById(canvas_id); - this.ctx = canvas.getContext("2d"); - this.canvas.width = window.innerWidth; - this.canvas.height = window.innerHeight; + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = $('.env').width(); + this.canvas.height = $('.env').height(); this.height = canvas.height; this.width = canvas.width; this.cells_to_render = new Set(); diff --git a/src/index.js b/src/index.js index cf95018..a0992bc 100644 --- a/src/index.js +++ b/src/index.js @@ -2,5 +2,7 @@ import Engine from './Engine'; -var engine = new Engine(); -engine.start(45); \ No newline at end of file +$('document').ready(function(){ + var engine = new Engine(); + engine.start(60); +});