diff --git a/dist/css/style.css b/dist/css/style.css
index f78c279..f98f464 100644
--- a/dist/css/style.css
+++ b/dist/css/style.css
@@ -9,7 +9,7 @@ body{
* {
margin: 0;
padding: 0;
- font-family: Arial, Helvetica, sans-serif;
+ font-family: Arial, Helvetica, sans-serif;
}
#env {
@@ -39,12 +39,12 @@ body{
background-color: #3a4b68;
display: grid;
grid-template-columns: repeat(3, 1fr);
- opacity: 0.8;
+ /* opacity: 0.8; */
}
-.control-panel:hover {
+/* .control-panel:hover {
opacity: 1;
-}
+} */
.control-set {
margin: 5px;
@@ -226,6 +226,12 @@ button:hover{
margin: 5px;
}
+#chartContainer {
+ height: 200px;
+ width: 100%;
+}
+
+
.hot-controls {
position: fixed;
bottom: 10px;
@@ -233,6 +239,16 @@ button:hover{
display: none;
}
+#headless-notification {
+ display: none;
+ position: fixed;
+ color: white;
+ font-size: 200px;
+ left: 0;
+ top: 0;
+ padding-left: 10px;
+}
+
#minimize {
margin: 10px;
float: right;
diff --git a/dist/index.html b/dist/index.html
index e581c6f..56477dd 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -7,6 +7,7 @@
+
@@ -28,6 +29,7 @@
Simulation Speed
+
Target FPS: 60
@@ -50,10 +52,6 @@
-
+
@@ -220,13 +222,24 @@
-
Stats
-
Organism count:
-
Highest count:
+
Statistics
+
Total Population:
+
Number of Species:
+
Largest Organism Ever:
Average Mutation Rate:
-
Largest Organism:
+
+
+
+
+
+
-
@@ -254,7 +267,10 @@
-
+
+
+
+
diff --git a/dist/js/bundle.js b/dist/js/bundle.js
index 1e05899..13032a9 100644
--- a/dist/js/bundle.js
+++ b/dist/js/bundle.js
@@ -1 +1 @@
-!function(e){var t={};function i(s){if(t[s])return t[s].exports;var r=t[s]={i:s,l:!1,exports:{}};return e[s].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=t,i.d=function(e,t,s){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(i.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(s,r,function(t){return e[t]}.bind(null,r));return s},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=13)}([function(e,t){class i{constructor(e){this.name=e,this.color="black"}render(e,t,i){e.fillStyle=this.color,e.fillRect(t.x,t.y,i,i)}}const s={empty:new class extends i{constructor(){super("empty")}},food:new class extends i{constructor(){super("food")}},wall:new class extends i{constructor(){super("wall")}},mouth:new class extends i{constructor(){super("mouth")}},producer:new class extends i{constructor(){super("producer")}},mover:new class extends i{constructor(){super("mover")}},killer:new class extends i{constructor(){super("killer")}},armor:new class extends i{constructor(){super("armor")}},eye:new class extends i{constructor(){super("eye"),this.slit_color="black"}render(e,t,i){if(e.fillStyle=this.color,e.fillRect(t.x,t.y,i,i),1!=i){var s=i/2,r=-i/8,o=-s,n=i/2+i/4,l=i/4;e.translate(t.x+s,t.y+s),e.rotate(90*t.cell_owner.getAbsoluteDirection()*Math.PI/180),e.fillStyle=this.slit_color,e.fillRect(r,o,l,n),e.setTransform(1,0,0,1,0,0)}}},defineLists(){this.all=[this.empty,this.food,this.wall,this.mouth,this.producer,this.mover,this.killer,this.armor,this.eye],this.living=[this.mouth,this.producer,this.mover,this.killer,this.armor,this.eye]},getRandomName:function(){return this.all[Math.floor(Math.random()*this.all.length)].name},getRandomLivingType:function(){return this.living[Math.floor(Math.random()*this.living.length)]}};s.defineLists(),e.exports=s},function(e,t,i){const s=i(4),r={setDefaults:function(){this.lifespanMultiplier=100,this.foodProdProb=4,this.foodProdProbScalar=4,this.killableNeighbors=s.adjacent,this.edibleNeighbors=s.adjacent,this.growableNeighbors=s.adjacent,this.useGlobalMutability=!1,this.globalMutability=5,this.addProb=33,this.changeProb=33,this.removeProb=33,this.moversCanRotate=!0,this.offspringRotate=!0,this.foodBlocksReproduction=!0,this.moversCanProduce=!1,this.instaKill=!1,this.lookRange=20,this.foodDropProb=0},balanceMutationProbs:function(e){if(1==e){var t=100-this.addProb;this.changeProb=t/2,this.removeProb=t/2}else if(2==e){t=100-this.changeProb;this.addProb=t/2,this.removeProb=t/2}else{t=100-this.removeProb;this.changeProb=t/2,this.addProb=t/2}}};r.setDefaults(),e.exports=r},function(e,t){const i={up:0,right:1,down:2,left:3,scalars:[[0,-1],[1,0],[0,1],[-1,0]],getRandomDirection:function(){return Math.floor(4*Math.random())},getRandomScalar:function(){return this.scalars[Math.floor(Math.random()*this.scalars.length)]},getOppositeDirection:function(e){switch(e){case this.up:return this.down;case this.down:return this.up;case this.left:return this.right;case this.right:return this.left}},rotateRight:function(e){return++e>3&&(e=0),e}};e.exports=i},function(e,t,i){i(0);const s=i(2);e.exports=class{constructor(e,t,i,s){this.state=e,this.org=t,this.loc_col=i,this.loc_row=s;var r=Math.max(2*Math.abs(s)+2,2*Math.abs(i)+2);this.org.birth_distance1){c=this.cells[Math.floor(Math.random()*this.cells.length)];t=this.removeCell(c.loc_col,c.loc_row)}return t}attemptMove(){var e=l.scalars[this.direction],t=e[0],i=e[1],r=this.c+t,o=this.r+i;if(this.isClear(r,o)){for(var n of this.cells){var a=this.c+n.rotatedCol(this.rotation),h=this.r+n.rotatedRow(this.rotation);this.env.changeCell(a,h,s.empty,null)}return this.c=r,this.r=o,this.updateGrid(),!0}return!1}attemptRotate(){if(!this.can_rotate)return this.direction=l.getRandomDirection(),this.move_count=0,!0;var e=l.getRandomDirection();if(this.isClear(this.c,this.r,e)){for(var t of this.cells){var i=this.c+t.rotatedCol(this.rotation),r=this.r+t.rotatedRow(this.rotation);this.env.changeCell(i,r,s.empty,null)}return this.rotation=e,this.direction=l.getRandomDirection(),this.updateGrid(),this.move_count=0,!0}return!1}changeDirection(e){this.direction=e,this.move_count=0}isStraightPath(e,t,i,s,r){if(e==i){if(t>s){var o=s;s=t,t=o}for(var n=t;n!=s;n++){var l=this.env.grid_map.cellAt(e,n);if(!this.isPassableCell(l,r))return!1}return!0}if(e>i){o=i;i=e,e=o}for(n=e;n!=i;n++){l=this.env.grid_map.cellAt(n,t);if(!this.isPassableCell(l,r))return!1}return!0}isPassableCell(e,t){return null!=e&&(e.state==s.empty||e.owner==this||e.owner==t||e.state==s.food)}isClear(e,t,i=this.rotation,r=!1){for(var o of this.cells){var l=this.getRealCell(o,e,t,i);if(null==l)return!1;if(!(l.owner==this||l.state==s.empty||!n.foodBlocksReproduction&&l.state==s.food||r&&o.state==s.armor&&l.state==s.food))return!1}return!0}harm(){this.damage++,(this.damage>=this.maxHealth()||n.instaKill)&&this.die()}die(){for(var e of this.cells){var t=this.c+e.rotatedCol(this.rotation),i=this.r+e.rotatedRow(this.rotation);this.env.changeCell(t,i,s.food,null)}this.living=!1}updateGrid(){for(var e of this.cells){var t=this.c+e.rotatedCol(this.rotation),i=this.r+e.rotatedRow(this.rotation);this.env.changeCell(t,i,e.state,e)}}update(){if(this.lifetime++,this.lifetime>this.lifespan())return this.die(),this.living;for(var e of(this.food_collected>=this.foodNeeded()&&this.reproduce(),this.cells))if(e.performFunction(),!this.living)return this.living;if(this.is_mover){this.move_count++;var t=!1;0==this.ignore_brain_for?t=this.brain.decide():this.ignore_brain_for--;var i=this.attemptMove();if(this.move_count>this.move_range&&!t||!i)this.attemptRotate()||(this.changeDirection(l.getRandomDirection()),t&&(this.ignore_brain_for=this.move_range+1))}return this.living}getRealCell(e,t=this.c,i=this.r,s=this.rotation){var r=t+e.rotatedCol(s),o=i+e.rotatedRow(s);return this.env.grid_map.cellAt(r,o)}}e.exports=h},function(e,t){e.exports={None:0,FoodDrop:1,WallDrop:2,ClickKill:3,Select:4,Edit:5,Clone:6,Drag:7}},function(e,t){e.exports=class{constructor(){}update(){alert("Environment.update() must be overriden")}changeCell(e,t,i,s){this.grid_map.setCellType(e,t,i),this.grid_map.setCellOwner(e,t,s)}}},function(e,t,i){i(0),i(2);e.exports=class{constructor(e,t,i){this.cell_size=i,this.canvas=document.getElementById(e),this.ctx=this.canvas.getContext("2d"),this.fillWindow(t),this.height=this.canvas.height,this.width=this.canvas.width,this.cells_to_render=new Set,this.cells_to_highlight=new Set,this.highlighted_cells=new Set}fillWindow(e){this.fillShape($("#"+e).height(),$("#"+e).width())}fillShape(e,t){this.canvas.width=t,this.canvas.height=e,this.height=this.canvas.height,this.width=this.canvas.width}clear(){this.ctx.fillStyle="white",this.ctx.fillRect(0,0,this.height,this.width)}renderFullGrid(e){for(var t of e)for(var i of t)this.renderCell(i)}renderCells(){for(var e of this.cells_to_render)this.renderCell(e);this.cells_to_render.clear()}renderCell(e){e.state.render(this.ctx,e,this.cell_size)}renderOrganism(e){for(var t of e.cells){var i=e.getRealCell(t);this.renderCell(i)}}addToRender(e){this.highlighted_cells.has(e)&&this.cells_to_highlight.add(e),this.cells_to_render.add(e)}renderHighlights(){for(var e of this.cells_to_highlight)this.renderCellHighlight(e),this.highlighted_cells.add(e);this.cells_to_highlight.clear()}highlightOrganism(e){for(var t of e.cells){var i=e.getRealCell(t);this.cells_to_highlight.add(i)}}highlightCell(e){this.cells_to_highlight.add(e)}renderCellHighlight(e,t="yellow"){this.renderCell(e),this.ctx.fillStyle=t,this.ctx.globalAlpha=.5,this.ctx.fillRect(e.x,e.y,this.cell_size,this.cell_size),this.ctx.globalAlpha=1,this.highlighted_cells.add(e)}clearAllHighlights(e=!1){for(var t of this.highlighted_cells)this.renderCell(t);this.highlighted_cells.clear(),e&&this.cells_to_highlight.clear()}}},function(e,t,i){const s=i(10),r=i(0);e.exports=class{constructor(e,t,i){this.resize(e,t,i)}resize(e,t,i){this.grid=[],this.cols=e,this.rows=t,this.cell_size=i;for(var o=0;o=0&&t>=0}getCenter(){return[Math.floor(this.cols/2),Math.floor(this.rows/2)]}xyToColRow(e,t){var i=Math.floor(e/this.cell_size),s=Math.floor(t/this.cell_size);return i>=this.cols?i=this.cols-1:i<0&&(i=0),s>=this.rows?s=this.rows-1:s<0&&(s=0),[i,s]}}},function(e,t,i){i(0),i(1);e.exports=class{constructor(e,t,i,s,r){this.owner=null,this.cell_owner=null,this.setType(e),this.col=t,this.row=i,this.x=s,this.y=r}setType(e){this.state=e}}},function(e,t){e.exports=class{constructor(e,t){this.env=e,this.canvas=t,this.mouse_x,this.mouse_y,this.mouse_c,this.mouse_r,this.left_click=!1,this.right_click=!1,this.cur_cell=null,this.cur_org=null,this.highlight_org=!0,this.defineEvents()}setControlPanel(e){this.control_panel=e}defineEvents(){this.canvas.addEventListener("mousemove",e=>{this.updateMouseLocation(e.offsetX,e.offsetY),this.mouseMove()}),this.canvas.addEventListener("mouseup",function(e){e.preventDefault(),this.updateMouseLocation(e.offsetX,e.offsetY),this.mouseUp(),this.left_click=!1,this.right_click=!1}.bind(this)),this.canvas.addEventListener("mousedown",function(e){e.preventDefault(),this.updateMouseLocation(e.offsetX,e.offsetY),0==e.button&&(this.left_click=!0),2==e.button&&(this.right_click=!0),this.mouseDown()}.bind(this)),this.canvas.addEventListener("contextmenu",(function(e){e.preventDefault()})),this.canvas.addEventListener("mouseleave",function(){this.right_click=!1,this.left_click=!1,this.env.renderer.clearAllHighlights(!0)}.bind(this))}updateMouseLocation(e,t){var i=this.cur_cell,s=this.cur_org;this.mouse_x=e,this.mouse_y=t;var r=this.env.grid_map.xyToColRow(this.mouse_x,this.mouse_y);this.mouse_c=r[0],this.mouse_r=r[1],this.cur_cell=this.env.grid_map.cellAt(this.mouse_c,this.mouse_r),this.cur_org=this.cur_cell.owner,this.cur_org==s&&this.cur_cell==i||(this.env.renderer.clearAllHighlights(!0),null!=this.cur_org&&this.highlight_org?this.env.renderer.highlightOrganism(this.cur_org):null!=this.cur_cell&&this.env.renderer.highlightCell(this.cur_cell,!0))}mouseMove(){alert("mouse move must be overridden")}mouseDown(){alert("mouse down must be overridden")}mouseUp(){alert("mouse up must be overridden")}}},function(e,t,i){const s=i(14),r=i(25),o=i(26),n=i(28);e.exports=class{constructor(){this.fps=60,this.env=new s(5),this.organism_editor=new o,this.controlpanel=new r(this),this.colorscheme=new n(this.env,this.organism_editor),this.colorscheme.loadColorScheme(),this.env.OriginOfLife(),this.last_update=Date.now(),this.delta_time=0,this.actual_fps=0,this.running=!1}start(e=60){e<=0&&(e=1),e>300&&(e=300),this.fps=e,this.game_loop=setInterval(function(){this.environmentUpdate()}.bind(this),1e3/e),this.running=!0,this.fps>=60?null!=this.render_loop&&(clearInterval(this.render_loop),this.render_loop=null):this.setRenderLoop()}stop(){clearInterval(this.game_loop),this.running=!1,this.setRenderLoop()}setRenderLoop(){null==this.render_loop&&(this.render_loop=setInterval(function(){this.necessaryUpdate()}.bind(this),1e3/60))}environmentUpdate(){this.delta_time=Date.now()-this.last_update,this.last_update=Date.now(),this.env.update(this.delta_time),this.actual_fps=1/this.delta_time*1e3,null==this.render_loop&&this.necessaryUpdate()}necessaryUpdate(){this.env.render(),this.controlpanel.update(),this.organism_editor.update()}}},function(e,t,i){"use strict";i.r(t);var s=i(12),r=i.n(s);$("document").ready((function(){(function(){let e=!1;return function(t){(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(t)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(t.substr(0,4)))&&(e=!0)}(navigator.userAgent||navigator.vendor||window.opera),e})()&&(alert("Though the simulation still works on mobile, most features are disabled. Try it on desktop for the full experience!"),$(".control-panel").css("display","none")),(new r.a).start(60)}))},function(e,t,i){const s=i(7),r=i(8),o=i(9),n=i(5),l=i(0),a=i(24),h=i(1);i(10);e.exports=class extends s{constructor(e){super(),this.renderer=new r("env-canvas","env",e),this.controller=new a(this,this.renderer.canvas);var t=Math.floor(this.renderer.height/e),i=Math.floor(this.renderer.width/e);this.grid_map=new o(i,t,e),this.organisms=[],this.walls=[],this.total_mutability=0,this.auto_reset=!0,this.largest_cell_count=0,this.reset_count=0}update(e){var t=[];for(var i in this.organisms){var s=this.organisms[i];s.living&&s.update()||t.push(i)}h.foodDropProb>0&&this.generateFood(),this.removeOrganisms(t)}render(){this.renderer.renderCells(),this.renderer.renderHighlights()}removeOrganisms(e){for(var t of e.reverse())this.total_mutability-=this.organisms[t].mutability,this.organisms.splice(t,1);0==this.organisms.length&&this.auto_reset&&(this.reset_count++,this.reset())}OriginOfLife(){var e=this.grid_map.getCenter(),t=new n(e[0],e[1],this);t.addDefaultCell(l.mouth,0,0),t.addDefaultCell(l.producer,1,1),t.addDefaultCell(l.producer,-1,-1),this.addOrganism(t)}addOrganism(e){e.updateGrid(),this.total_mutability+=e.mutability,this.organisms.push(e),e.cells.length>this.largest_cell_count&&(this.largest_cell_count=e.cells.length)}averageMutability(){return this.organisms.length<1?0:this.total_mutability/this.organisms.length}changeCell(e,t,i,s){super.changeCell(e,t,i,s),this.renderer.addToRender(this.grid_map.cellAt(e,t)),i==l.wall&&this.walls.push(this.grid_map.cellAt(e,t))}clearWalls(){for(var e of this.walls)this.grid_map.cellAt(e.col,e.row).state==l.wall&&this.changeCell(e.col,e.row,l.empty,null)}clearOrganisms(){for(var e of this.organisms)e.die();this.organisms=[]}generateFood(){for(var e=Math.max(Math.floor(this.grid_map.cols*this.grid_map.rows*h.foodDropProb/5e4),1),t=h.foodDropProb,i=0;i3&&(e-=4),e}performFunction(){var e=this.look();this.org.brain.observe(e)}look(){var e=this.org.env,t=this.getAbsoluteDirection(),i=0,r=0;switch(t){case n.up:r=-1;break;case n.down:r=1;break;case n.right:i=1;break;case n.left:i=-1}for(var a=this.getRealCol(),h=this.getRealRow(),c=a,d=h,u=null,g=0;gthis.organism_record&&(this.organism_record=e),$("#org-record").text("Highest count: "+this.organism_record),$("#avg-mut").text("Average Mutation Rate: "+Math.round(100*this.engine.env.averageMutability())/100),$("#largest-org").text("Largest Organism: "+this.engine.env.largest_cell_count+" cells"),$("#reset-count").text("Auto reset count: "+this.engine.env.reset_count)}}},function(e,t,i){const s=i(7),r=i(5),o=i(9),n=i(8),l=i(0),a=i(27);i(2);e.exports=class extends s{constructor(){super(),this.is_active=!0;this.renderer=new n("editor-canvas","editor-env",13),this.controller=new a(this,this.renderer.canvas),this.grid_map=new o(15,15,13),this.clear()}update(){this.is_active&&this.renderer.renderHighlights()}changeCell(e,t,i,s){super.changeCell(e,t,i,s),this.renderFull()}renderFull(){this.renderer.renderFullGrid(this.grid_map.grid)}addCellToOrg(e,t,i){var s=this.grid_map.getCenter(),r=e-s[0],o=t-s[1],n=this.organism.getLocalCell(r,o);if(null!=n){var l=this.organism.replaceCell(i,n.loc_col,n.loc_row,!1);this.changeCell(e,t,i,l)}else this.organism.canAddCellAt(r,o)&&this.changeCell(e,t,i,this.organism.addDefaultCell(i,r,o))}removeCellFromOrg(e,t){var i=this.grid_map.getCenter(),s=e-i[0],r=t-i[1];0!=s||0!=r?null!=this.organism.getLocalCell(s,r)&&this.organism.removeCell(s,r)&&this.changeCell(e,t,l.empty,null):alert("Cannot remove center cell")}setOrganismToCopyOf(e){this.grid_map.fillGrid(l.empty);var t=this.grid_map.getCenter();this.organism=new r(t[0],t[1],this,e),this.organism.updateGrid(),this.controller.updateDetails()}getCopyOfOrg(){return new r(0,0,null,this.organism)}clear(){this.grid_map.fillGrid(l.empty);var e=this.grid_map.getCenter();this.organism=new r(e[0],e[1],this,null),this.organism.addDefaultCell(l.mouth,0,0),this.organism.updateGrid()}}},function(e,t,i){const s=i(11),r=i(6),o=i(0),n=i(2),l=i(1);e.exports=class extends s{constructor(e,t){super(e,t),this.mode=r.None,this.edit_cell_type=null,this.highlight_org=!1,this.defineCellTypeSelection(),this.defineEditorDetails()}mouseMove(){(this.right_click||this.left_click)&&this.editOrganism()}mouseDown(){this.editOrganism()}mouseUp(){}getCurLocalCell(){return this.env.organism.getLocalCell(this.mouse_c-this.env.organism.c,this.mouse_r-this.env.organism.r)}editOrganism(){if(null!=this.edit_cell_type&&this.mode==r.Edit){if(this.left_click)if(this.edit_cell_type==o.eye&&this.cur_cell.state==o.eye){var e=this.getCurLocalCell();e.direction=n.rotateRight(e.direction),this.env.renderFull()}else this.env.addCellToOrg(this.mouse_c,this.mouse_r,this.edit_cell_type);this.right_click&&this.env.removeCellFromOrg(this.mouse_c,this.mouse_r),this.setBrainPanelVisibility(),this.setMoveRangeVisibility(),this.updateDetails()}}updateDetails(){$(".cell-count").text("Cell count: "+this.env.organism.cells.length)}defineCellTypeSelection(){var e=this;$(".cell-type").click((function(){switch(this.id){case"mouth":e.edit_cell_type=o.mouth;break;case"producer":e.edit_cell_type=o.producer;break;case"mover":e.edit_cell_type=o.mover;break;case"killer":e.edit_cell_type=o.killer;break;case"armor":e.edit_cell_type=o.armor;break;case"eye":e.edit_cell_type=o.eye}$(".cell-type").css("border-color","black");var t="#"+this.id+".cell-type";$(t).css("border-color","yellow")}))}defineEditorDetails(){this.details_html=$("#organism-details"),this.edit_details_html=$("#edit-organism-details"),this.decision_names=["ignore","move away","move towards"],$("#move-range-edit").change(function(){this.env.organism.move_range=parseInt($("#move-range-edit").val())}.bind(this)),$("#observation-type-edit").change(function(){this.setBrainEditorValues($("#observation-type-edit").val()),this.setBrainDetails()}.bind(this)),$("#reaction-edit").change(function(){var e=$("#observation-type-edit").val(),t=parseInt($("#reaction-edit").val());this.env.organism.brain.decisions[e]=t,this.setBrainDetails()}.bind(this))}clearDetailsPanel(){$("#organism-details").css("display","none"),$("#edit-organism-details").css("display","none")}setDetailsPanel(){this.clearDetailsPanel();var e=this.env.organism;$(".cell-count").text("Cell count: "+e.cells.length),$("#move-range").text("Move Range: "+e.move_range),$("#mutation-rate").text("Mutation Rate: "+e.mutability),l.useGlobalMutability?$("#mutation-rate").css("display","none"):$("#mutation-rate").css("display","block"),this.setMoveRangeVisibility(),this.setBrainPanelVisibility()&&this.setBrainDetails(),$("#organism-details").css("display","block")}setEditorPanel(){this.clearDetailsPanel();var e=this.env.organism;$(".cell-count").text("Cell count: "+e.cells.length),this.setMoveRangeVisibility()&&$("#move-range-edit").val(e.move_range),this.setBrainPanelVisibility()&&this.setBrainEditorValues($("#observation-type-edit").val()),$("#cell-selections").css("display","grid"),$("#edit-organism-details").css("display","block")}setBrainPanelVisibility(){var e=this.env.organism;return e.has_eyes&&e.is_mover?($(".brain-details").css("display","block"),!0):($(".brain-details").css("display","none"),!1)}setBrainDetails(){var e=[],t=[];for(var i in this.env.organism.brain.decisions){var s=this.env.organism.brain.decisions[i];1==s?t.push(i):2==s&&e.push(i)}$(".chase-types").text("Move Towards: "+e),$(".retreat-types").text("Move Away From: "+t)}setMoveRangeVisibility(){return this.env.organism.is_mover?($("#move-range-cont").css("display","block"),$("#move-range").css("display","block"),!0):($("#move-range-cont").css("display","none"),$("#move-range").css("display","none"),!1)}setBrainEditorValues(e){$("#observation-type-edit").val(e);var t=this.env.organism.brain.decisions[e];$("#reaction-edit").val(t)}}},function(e,t,i){const s=i(0);var r={empty:"#0E1318",food:"#2F7AB7",wall:"gray",mouth:"#DEB14D",producer:"#15DE59",mover:"#60D4FF",killer:"#F82380",armor:"#7230DB",eye:"#B6C1EA","eye-slit":"#0E1318"};e.exports=class{constructor(e,t){this.world_env=e,this.editor_env=t}loadColorScheme(){for(var e of s.all)e.color=r[e.name];for(var t in s.eye.slit_color=r["eye-slit"],r)$("#"+t+".cell-type ").css("background-color",r[t]),$("#"+t+".cell-legend-type").css("background-color",r[t]);this.world_env.renderer.renderFullGrid(this.world_env.grid_map.grid),this.editor_env.renderer.renderFullGrid(this.editor_env.grid_map.grid)}}}]);
\ No newline at end of file
+!function(t){var e={};function i(s){if(e[s])return e[s].exports;var o=e[s]={i:s,l:!1,exports:{}};return t[s].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=t,i.c=e,i.d=function(t,e,s){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:s})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var s=Object.create(null);if(i.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)i.d(s,o,function(e){return t[e]}.bind(null,o));return s},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=15)}([function(t,e){class i{constructor(t){this.name=t,this.color="black"}render(t,e,i){t.fillStyle=this.color,t.fillRect(e.x,e.y,i,i)}}const s={empty:new class extends i{constructor(){super("empty")}},food:new class extends i{constructor(){super("food")}},wall:new class extends i{constructor(){super("wall")}},mouth:new class extends i{constructor(){super("mouth")}},producer:new class extends i{constructor(){super("producer")}},mover:new class extends i{constructor(){super("mover")}},killer:new class extends i{constructor(){super("killer")}},armor:new class extends i{constructor(){super("armor")}},eye:new class extends i{constructor(){super("eye"),this.slit_color="black"}render(t,e,i){if(t.fillStyle=this.color,t.fillRect(e.x,e.y,i,i),1!=i){var s=i/2,o=-i/8,r=-s,a=i/2+i/4,n=i/4;t.translate(e.x+s,e.y+s),t.rotate(90*e.cell_owner.getAbsoluteDirection()*Math.PI/180),t.fillStyle=this.slit_color,t.fillRect(o,r,n,a),t.setTransform(1,0,0,1,0,0)}}},defineLists(){this.all=[this.empty,this.food,this.wall,this.mouth,this.producer,this.mover,this.killer,this.armor,this.eye],this.living=[this.mouth,this.producer,this.mover,this.killer,this.armor,this.eye]},getRandomName:function(){return this.all[Math.floor(Math.random()*this.all.length)].name},getRandomLivingType:function(){return this.living[Math.floor(Math.random()*this.living.length)]}};s.defineLists(),t.exports=s},function(t,e,i){const s=i(6),o={setDefaults:function(){this.headless=!1,this.lifespanMultiplier=100,this.foodProdProb=4,this.foodProdProbScalar=4,this.killableNeighbors=s.adjacent,this.edibleNeighbors=s.adjacent,this.growableNeighbors=s.adjacent,this.useGlobalMutability=!1,this.globalMutability=5,this.addProb=33,this.changeProb=33,this.removeProb=33,this.moversCanRotate=!0,this.offspringRotate=!0,this.foodBlocksReproduction=!0,this.moversCanProduce=!1,this.instaKill=!1,this.lookRange=20,this.foodDropProb=0},balanceMutationProbs:function(t){if(1==t){var e=100-this.addProb;this.changeProb=e/2,this.removeProb=e/2}else if(2==t){e=100-this.changeProb;this.addProb=e/2,this.removeProb=e/2}else{e=100-this.removeProb;this.changeProb=e/2,this.addProb=e/2}}};o.setDefaults(),t.exports=o},function(t,e,s){const o=s(0),r=s(12),a={init:function(){this.extant_species=[],this.extinct_species=[],this.min_discard=10,this.record_size_limit=500},setEnv:function(t){this.env=t,this.setData()},addSpecies:function(t,e){var i=new r(t.anatomy,e,this.env.total_ticks);return this.extant_species.push(i),t.species=i,i},addSpeciesObj:function(t){return this.extant_species.push(t),t},fossilize:function(t){for(i in t.end_tick=this.env.total_ticks,this.extant_species){var e=this.extant_species[i];if(e==t)return this.extant_species.splice(i,1),!(t.cumulative_popthis.record_size_limit&&(this.tick_record.shift(),this.pop_counts.shift(),this.species_counts.shift(),this.av_mut_rates.shift(),this.av_cells.shift(),this.av_cell_counts.shift())},calcCellCountAverages(){var t=0,e={};for(let t of o.living)e[t.name]=0;var i=!0;for(let s of this.extant_species)if(!(s.cumulative_pop3&&(t=0),t}};t.exports=i},function(t,e,i){i(0);const s=i(3);t.exports=class{constructor(t,e,i,s){this.state=t,this.org=e,this.loc_col=i,this.loc_row=s;var o=Math.max(2*Math.abs(s)+2,2*Math.abs(i)+2);this.org.anatomy.birth_distance0&&(e=this.data[0].dataPoints[this.data[0].dataPoints.length-1].x,e=this.data[0].dataPoints[0].x),e1){c=this.anatomy.getRandomCell();e=this.anatomy.removeCell(c.loc_col,c.loc_row)}return e}attemptMove(){var t=a.scalars[this.direction],e=t[0],i=t[1],o=this.c+e,r=this.r+i;if(this.isClear(o,r)){for(var n of this.anatomy.cells){var l=this.c+n.rotatedCol(this.rotation),h=this.r+n.rotatedRow(this.rotation);this.env.changeCell(l,h,s.empty,null)}return this.c=o,this.r=r,this.updateGrid(),!0}return!1}attemptRotate(){if(!this.can_rotate)return this.direction=a.getRandomDirection(),this.move_count=0,!0;var t=a.getRandomDirection();if(this.isClear(this.c,this.r,t)){for(var e of this.anatomy.cells){var i=this.c+e.rotatedCol(this.rotation),o=this.r+e.rotatedRow(this.rotation);this.env.changeCell(i,o,s.empty,null)}return this.rotation=t,this.direction=a.getRandomDirection(),this.updateGrid(),this.move_count=0,!0}return!1}changeDirection(t){this.direction=t,this.move_count=0}isStraightPath(t,e,i,s,o){if(t==i){if(e>s){var r=s;s=e,e=r}for(var a=e;a!=s;a++){var n=this.env.grid_map.cellAt(t,a);if(!this.isPassableCell(n,o))return!1}return!0}if(t>i){r=i;i=t,t=r}for(a=t;a!=i;a++){n=this.env.grid_map.cellAt(a,e);if(!this.isPassableCell(n,o))return!1}return!0}isPassableCell(t,e){return null!=t&&(t.state==s.empty||t.owner==this||t.owner==e||t.state==s.food)}isClear(t,e,i=this.rotation,o=!1){for(var a of this.anatomy.cells){var n=this.getRealCell(a,t,e,i);if(null==n)return!1;if(!(n.owner==this||n.state==s.empty||!r.foodBlocksReproduction&&n.state==s.food||o&&a.state==s.armor&&n.state==s.food))return!1}return!0}harm(){this.damage++,(this.damage>=this.maxHealth()||r.instaKill)&&this.die()}die(){for(var t of this.anatomy.cells){var e=this.c+t.rotatedCol(this.rotation),i=this.r+t.rotatedRow(this.rotation);this.env.changeCell(e,i,s.food,null)}this.species.decreasePop(),this.living=!1}updateGrid(){for(var t of this.anatomy.cells){var e=this.c+t.rotatedCol(this.rotation),i=this.r+t.rotatedRow(this.rotation);this.env.changeCell(e,i,t.state,t)}}update(){if(this.lifetime++,this.lifetime>this.lifespan())return this.die(),this.living;for(var t of(this.food_collected>=this.foodNeeded()&&this.reproduce(),this.anatomy.cells))if(t.performFunction(),!this.living)return this.living;if(this.anatomy.is_mover){this.move_count++;var e=!1;0==this.ignore_brain_for?e=this.brain.decide():this.ignore_brain_for--;var i=this.attemptMove();if(this.move_count>this.move_range&&!e||!i)this.attemptRotate()||(this.changeDirection(a.getRandomDirection()),e&&(this.ignore_brain_for=this.move_range+1))}return this.living}getRealCell(t,e=this.c,i=this.r,s=this.rotation){var o=e+t.rotatedCol(s),r=i+t.rotatedRow(s);return this.env.grid_map.cellAt(o,r)}}t.exports=c},function(t,e){t.exports={None:0,FoodDrop:1,WallDrop:2,ClickKill:3,Select:4,Edit:5,Clone:6,Drag:7}},function(t,e){t.exports=class{constructor(){}update(){alert("Environment.update() must be overriden")}changeCell(t,e,i,s){this.grid_map.setCellType(t,e,i),this.grid_map.setCellOwner(t,e,s)}}},function(t,e,i){i(0),i(3);t.exports=class{constructor(t,e,i){this.cell_size=i,this.canvas=document.getElementById(t),this.ctx=this.canvas.getContext("2d"),this.fillWindow(e),this.height=this.canvas.height,this.width=this.canvas.width,this.cells_to_render=new Set,this.cells_to_highlight=new Set,this.highlighted_cells=new Set}fillWindow(t){this.fillShape($("#"+t).height(),$("#"+t).width())}fillShape(t,e){this.canvas.width=e,this.canvas.height=t,this.height=this.canvas.height,this.width=this.canvas.width}clear(){this.ctx.fillStyle="white",this.ctx.fillRect(0,0,this.height,this.width)}renderFullGrid(t){for(var e of t)for(var i of e)this.renderCell(i)}renderCells(){for(var t of this.cells_to_render)this.renderCell(t);this.cells_to_render.clear()}renderCell(t){t.state.render(this.ctx,t,this.cell_size)}renderOrganism(t){for(var e of t.anatomy.cells){var i=t.getRealCell(e);this.renderCell(i)}}addToRender(t){this.highlighted_cells.has(t)&&this.cells_to_highlight.add(t),this.cells_to_render.add(t)}renderHighlights(){for(var t of this.cells_to_highlight)this.renderCellHighlight(t),this.highlighted_cells.add(t);this.cells_to_highlight.clear()}highlightOrganism(t){for(var e of t.anatomy.cells){var i=t.getRealCell(e);this.cells_to_highlight.add(i)}}highlightCell(t){this.cells_to_highlight.add(t)}renderCellHighlight(t,e="yellow"){this.renderCell(t),this.ctx.fillStyle=e,this.ctx.globalAlpha=.5,this.ctx.fillRect(t.x,t.y,this.cell_size,this.cell_size),this.ctx.globalAlpha=1,this.highlighted_cells.add(t)}clearAllHighlights(t=!1){for(var e of this.highlighted_cells)this.renderCell(e);this.highlighted_cells.clear(),t&&this.cells_to_highlight.clear()}}},function(t,e,i){const s=i(17),o=i(0);t.exports=class{constructor(t,e,i){this.resize(t,e,i)}resize(t,e,i){this.grid=[],this.cols=t,this.rows=e,this.cell_size=i;for(var r=0;r=0&&e>=0}getCenter(){return[Math.floor(this.cols/2),Math.floor(this.rows/2)]}xyToColRow(t,e){var i=Math.floor(t/this.cell_size),s=Math.floor(e/this.cell_size);return i>=this.cols?i=this.cols-1:i<0&&(i=0),s>=this.rows?s=this.rows-1:s<0&&(s=0),[i,s]}}},function(t,e,i){const s=i(0);t.exports=class{constructor(t,e,i){if(this.anatomy=t,this.ancestor=e,this.population=1,this.cumulative_pop=1,this.start_tick=i,this.end_tick=-1,this.color=Math.floor(16777215*Math.random()).toString(16),null!=e){var s=Math.floor(16777215*Math.random())-8e6;this.color=(s+parseInt(e.color,16)).toString(16)}this.name="_"+Math.random().toString(36).substr(2,9),this.extinct=!1,this.calcAnatomyDetails()}calcAnatomyDetails(){var t={};for(let e of s.living)t[e.name]=0;for(let e of this.anatomy.cells)t[e.state.name]+=1;this.cell_counts=t}addPop(){this.population++,this.cumulative_pop++}decreasePop(){if(this.population--,this.population<=0){this.extinct=!0;i(2).fossilize(this)}}lifespan(){return this.end_tick-this.start_tick}}},function(t,e){t.exports=class{constructor(t,e){this.env=t,this.canvas=e,this.mouse_x,this.mouse_y,this.mouse_c,this.mouse_r,this.left_click=!1,this.right_click=!1,this.cur_cell=null,this.cur_org=null,this.highlight_org=!0,this.defineEvents()}setControlPanel(t){this.control_panel=t}defineEvents(){this.canvas.addEventListener("mousemove",t=>{this.updateMouseLocation(t.offsetX,t.offsetY),this.mouseMove()}),this.canvas.addEventListener("mouseup",function(t){t.preventDefault(),this.updateMouseLocation(t.offsetX,t.offsetY),this.mouseUp(),this.left_click=!1,this.right_click=!1}.bind(this)),this.canvas.addEventListener("mousedown",function(t){t.preventDefault(),this.updateMouseLocation(t.offsetX,t.offsetY),0==t.button&&(this.left_click=!0),2==t.button&&(this.right_click=!0),this.mouseDown()}.bind(this)),this.canvas.addEventListener("contextmenu",(function(t){t.preventDefault()})),this.canvas.addEventListener("mouseleave",function(){this.right_click=!1,this.left_click=!1,this.env.renderer.clearAllHighlights(!0)}.bind(this))}updateMouseLocation(t,e){var i=this.cur_cell,s=this.cur_org;this.mouse_x=t,this.mouse_y=e;var o=this.env.grid_map.xyToColRow(this.mouse_x,this.mouse_y);this.mouse_c=o[0],this.mouse_r=o[1],this.cur_cell=this.env.grid_map.cellAt(this.mouse_c,this.mouse_r),this.cur_org=this.cur_cell.owner,this.cur_org==s&&this.cur_cell==i||(this.env.renderer.clearAllHighlights(!0),null!=this.cur_org&&this.highlight_org?this.env.renderer.highlightOrganism(this.cur_org):null!=this.cur_cell&&this.env.renderer.highlightCell(this.cur_cell,!0))}mouseMove(){alert("mouse move must be overridden")}mouseDown(){alert("mouse down must be overridden")}mouseUp(){alert("mouse up must be overridden")}}},function(t,e,i){const s=i(16),o=i(29),r=i(35),a=i(37);t.exports=class{constructor(){this.fps=60,this.env=new s(5),this.organism_editor=new r,this.controlpanel=new o(this),this.colorscheme=new a(this.env,this.organism_editor),this.colorscheme.loadColorScheme(),this.env.OriginOfLife(),this.last_update=Date.now(),this.delta_time=0,this.actual_fps=0,this.running=!1}start(t=60){t<=0&&(t=1),this.fps=t,this.game_loop=setInterval(function(){this.updateDeltaTime(),this.environmentUpdate()}.bind(this),1e3/t),this.running=!0,this.fps>=60?null!=this.render_loop&&(clearInterval(this.render_loop),this.render_loop=null):this.setRenderLoop()}stop(){clearInterval(this.game_loop),this.running=!1,this.setRenderLoop()}setRenderLoop(){null==this.render_loop&&(this.render_loop=setInterval(function(){this.updateDeltaTime(),this.necessaryUpdate()}.bind(this),1e3/60))}updateDeltaTime(){this.delta_time=Date.now()-this.last_update,this.last_update=Date.now()}environmentUpdate(){this.env.update(this.delta_time),this.actual_fps=1/this.delta_time*1e3,null==this.render_loop&&this.necessaryUpdate()}necessaryUpdate(){this.env.render(),this.controlpanel.update(this.delta_time),this.organism_editor.update()}}},function(t,e,i){"use strict";i.r(e);var s=i(14),o=i.n(s);$("document").ready((function(){(function(){let t=!1;return function(e){(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(e)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(e.substr(0,4)))&&(t=!0)}(navigator.userAgent||navigator.vendor||window.opera),t})()&&(alert("Though the simulation still works on mobile, most features are disabled. Try it on desktop for the full experience!"),$(".control-panel").css("display","none")),(new o.a).start(60)}))},function(t,e,i){const s=i(9),o=i(10),r=i(11),a=i(7),n=i(0),l=i(28),h=i(1),c=i(2);t.exports=class extends s{constructor(t){super(),this.renderer=new o("env-canvas","env",t),this.controller=new l(this,this.renderer.canvas);var e=Math.floor(this.renderer.height/t),i=Math.floor(this.renderer.width/t);this.grid_map=new r(i,e,t),this.organisms=[],this.walls=[],this.total_mutability=0,this.auto_reset=!0,this.largest_cell_count=0,this.reset_count=0,this.total_ticks=0,this.data_update_rate=100,c.setEnv(this)}update(t){var e=[];for(var i in this.organisms){var s=this.organisms[i];s.living&&s.update()||e.push(i)}h.foodDropProb>0&&this.generateFood(),this.removeOrganisms(e),this.total_ticks++,this.total_ticks%this.data_update_rate==0&&c.updateData()}render(){h.headless?this.renderer.cells_to_render.clear():(this.renderer.renderCells(),this.renderer.renderHighlights())}renderFull(){this.renderer.renderFullGrid(this.grid_map.grid)}removeOrganisms(t){for(var e of t.reverse())this.total_mutability-=this.organisms[e].mutability,this.organisms.splice(e,1);0==this.organisms.length&&this.auto_reset&&(this.reset_count++,this.reset())}OriginOfLife(){var t=this.grid_map.getCenter(),e=new a(t[0],t[1],this);e.anatomy.addDefaultCell(n.mouth,0,0),e.anatomy.addDefaultCell(n.producer,1,1),e.anatomy.addDefaultCell(n.producer,-1,-1),this.addOrganism(e),c.addSpecies(e,null)}addOrganism(t){t.updateGrid(),this.total_mutability+=t.mutability,this.organisms.push(t),t.anatomy.cells.length>this.largest_cell_count&&(this.largest_cell_count=t.anatomy.cells.length)}averageMutability(){return this.organisms.length<1?0:h.useGlobalMutability?h.globalMutability:this.total_mutability/this.organisms.length}changeCell(t,e,i,s){super.changeCell(t,e,i,s),this.renderer.addToRender(this.grid_map.cellAt(t,e)),i==n.wall&&this.walls.push(this.grid_map.cellAt(t,e))}clearWalls(){for(var t of this.walls)this.grid_map.cellAt(t.col,t.row).state==n.wall&&this.changeCell(t.col,t.row,n.empty,null)}clearOrganisms(){for(var t of this.organisms)t.die();this.organisms=[]}generateFood(){for(var t=Math.max(Math.floor(this.grid_map.cols*this.grid_map.rows*h.foodDropProb/5e4),1),e=h.foodDropProb,i=0;i3&&(t-=4),t}performFunction(){var t=this.look();this.org.brain.observe(t)}look(){var t=this.org.env,e=this.getAbsoluteDirection(),i=0,o=0;switch(e){case a.up:o=-1;break;case a.down:o=1;break;case a.right:i=1;break;case a.left:i=-1}for(var l=this.getRealCol(),h=this.getRealRow(),c=l,d=h,u=null,p=0;p=1&&(e=1,this.opacity_change_rate=-this.opacity_change_rate),this.headless_opacity=e,$("#headless-notification").css("opacity",100*e+"%")}}update(t){$("#fps-actual").text("Actual FPS: "+Math.floor(this.engine.actual_fps)),$("#reset-count").text("Auto reset count: "+this.engine.env.reset_count),this.stats_panel.updateDetails(),s.headless&&this.updateHeadlessIcon(t)}}},function(t,e,i){const s=i(31),o=i(32),r=i(33),a=i(34),n=i(2),l=[s,o,a,r];t.exports=class{constructor(t){this.defineControls(),this.chart_selection=0,this.setChart(),this.env=t,this.last_reset_count=t.reset_count}setChart(t=this.chart_selection){this.chart_controller=new l[t],this.chart_controller.setData(),this.chart_controller.render()}startAutoRender(){this.setChart(),this.render_loop=setInterval(function(){this.updateChart()}.bind(this),1e3)}stopAutoRender(){clearInterval(this.render_loop)}defineControls(){$("#chart-option").change(function(){this.chart_selection=$("#chart-option")[0].selectedIndex,this.setChart()}.bind(this))}updateChart(){this.last_reset_count= 1){
+ op=1;
+ this.opacity_change_rate = -this.opacity_change_rate;
+ }
+ this.headless_opacity = op;
+ $('#headless-notification').css('opacity',(op*100)+'%');
+ }
+
+ update(delta_time) {
$('#fps-actual').text("Actual FPS: " + Math.floor(this.engine.actual_fps));
- var org_count = this.engine.env.organisms.length;
- $('#org-count').text("Organism count: " + org_count);
- if (org_count > this.organism_record)
- this.organism_record = org_count;
- $('#org-record').text("Highest count: " + this.organism_record);
- $('#avg-mut').text("Average Mutation Rate: " + Math.round(this.engine.env.averageMutability() * 100) / 100);
- $('#largest-org').text("Largest Organism: " + this.engine.env.largest_cell_count + " cells");
$('#reset-count').text("Auto reset count: " + this.engine.env.reset_count);
+ this.stats_panel.updateDetails();
+ if (Hyperparams.headless)
+ this.updateHeadlessIcon(delta_time);
+
}
}
diff --git a/src/Controllers/EditorController.js b/src/Controllers/EditorController.js
index 5b55c6d..e7c2152 100644
--- a/src/Controllers/EditorController.js
+++ b/src/Controllers/EditorController.js
@@ -10,6 +10,7 @@ class EditorController extends CanvasController{
this.mode = Modes.None;
this.edit_cell_type = null;
this.highlight_org = false;
+ this.new_species = false;
this.defineCellTypeSelection();
this.defineEditorDetails();
}
@@ -26,7 +27,7 @@ class EditorController extends CanvasController{
mouseUp(){}
getCurLocalCell(){
- return this.env.organism.getLocalCell(this.mouse_c-this.env.organism.c, this.mouse_r-this.env.organism.r);
+ return this.env.organism.anatomy.getLocalCell(this.mouse_c-this.env.organism.c, this.mouse_r-this.env.organism.r);
}
editOrganism() {
@@ -41,15 +42,17 @@ class EditorController extends CanvasController{
else
this.env.addCellToOrg(this.mouse_c, this.mouse_r, this.edit_cell_type);
}
- if (this.right_click)
+ else if (this.right_click)
this.env.removeCellFromOrg(this.mouse_c, this.mouse_r);
+
+ this.new_species = true;
this.setBrainPanelVisibility();
this.setMoveRangeVisibility();
this.updateDetails();
}
updateDetails() {
- $('.cell-count').text("Cell count: "+this.env.organism.cells.length);
+ $('.cell-count').text("Cell count: "+this.env.organism.anatomy.cells.length);
}
defineCellTypeSelection() {
@@ -111,7 +114,7 @@ class EditorController extends CanvasController{
this.clearDetailsPanel();
var org = this.env.organism;
- $('.cell-count').text("Cell count: "+org.cells.length);
+ $('.cell-count').text("Cell count: "+org.anatomy.cells.length);
$('#move-range').text("Move Range: "+org.move_range);
$('#mutation-rate').text("Mutation Rate: "+org.mutability);
if (Hyperparams.useGlobalMutability) {
@@ -134,7 +137,7 @@ class EditorController extends CanvasController{
this.clearDetailsPanel();
var org = this.env.organism;
- $('.cell-count').text("Cell count: "+org.cells.length);
+ $('.cell-count').text("Cell count: "+org.anatomy.cells.length);
if (this.setMoveRangeVisibility()){
$('#move-range-edit').val(org.move_range);
}
@@ -149,7 +152,7 @@ class EditorController extends CanvasController{
setBrainPanelVisibility() {
var org = this.env.organism;
- if (org.has_eyes && org.is_mover) {
+ if (org.anatomy.has_eyes && org.anatomy.is_mover) {
$('.brain-details').css('display', 'block');
return true;
}
@@ -175,7 +178,7 @@ class EditorController extends CanvasController{
setMoveRangeVisibility() {
var org = this.env.organism;
- if (org.is_mover) {
+ if (org.anatomy.is_mover) {
$('#move-range-cont').css('display', 'block');
$('#move-range').css('display', 'block');
return true;
diff --git a/src/Controllers/EnvironmentController.js b/src/Controllers/EnvironmentController.js
index ec4dbae..451d2a9 100644
--- a/src/Controllers/EnvironmentController.js
+++ b/src/Controllers/EnvironmentController.js
@@ -3,12 +3,15 @@ const Organism = require('../Organism/Organism');
const Modes = require("./ControlModes");
const CellStates = require("../Organism/Cell/CellStates");
const Neighbors = require("../Grid/Neighbors");
+const FossilRecord = require("../Stats/FossilRecord");
+const Hyperparams = require("../Hyperparameters");
class EnvironmentController extends CanvasController{
constructor(env, canvas) {
super(env, canvas);
this.mode = Modes.Drag;
this.org_to_clone = null;
+ this.add_new_species = false;
this.defineZoomControls();
this.scale = 1;
}
@@ -76,6 +79,8 @@ class EnvironmentController extends CanvasController{
}
performModeAction() {
+ if (Hyperparams.headless)
+ return;
var mode = this.mode;
var right_click = this.right_click;
var left_click = this.left_click;
@@ -118,8 +123,19 @@ 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)
+ this.env.addOrganism(new_org);
+ new_org.species.addPop();
}
}
break;
diff --git a/src/Engine.js b/src/Engine.js
index 7143629..a74f693 100644
--- a/src/Engine.js
+++ b/src/Engine.js
@@ -5,7 +5,7 @@ const ColorScheme = require('./Rendering/ColorScheme');
const render_speed = 60;
-class Engine{
+class Engine {
constructor(){
this.fps = 60;
this.env = new WorldEnvironment(5);
@@ -23,10 +23,8 @@ class Engine{
start(fps=60) {
if (fps <= 0)
fps = 1;
- if (fps > 300)
- fps = 300;
this.fps = fps;
- this.game_loop = setInterval(function(){this.environmentUpdate();}.bind(this), 1000/fps);
+ this.game_loop = setInterval(function(){this.updateDeltaTime();this.environmentUpdate();}.bind(this), 1000/fps);
this.running = true;
if (this.fps >= render_speed) {
if (this.render_loop != null) {
@@ -46,14 +44,17 @@ class Engine{
setRenderLoop() {
if (this.render_loop == null) {
- this.render_loop = setInterval(function(){this.necessaryUpdate();}.bind(this), 1000/render_speed);
+ this.render_loop = setInterval(function(){this.updateDeltaTime();this.necessaryUpdate();}.bind(this), 1000/render_speed);
}
}
+ updateDeltaTime() {
+ this.delta_time = Date.now() - this.last_update;
+ this.last_update = Date.now();
+ }
+
environmentUpdate() {
- this.delta_time = Date.now() - this.last_update;
- this.last_update = Date.now();
this.env.update(this.delta_time);
this.actual_fps = 1/this.delta_time*1000;
if(this.render_loop == null){
@@ -64,7 +65,7 @@ class Engine{
necessaryUpdate() {
this.env.render();
- this.controlpanel.update();
+ this.controlpanel.update(this.delta_time);
this.organism_editor.update();
}
diff --git a/src/Environments/OrganismEditor.js b/src/Environments/OrganismEditor.js
index 9294549..b969774 100644
--- a/src/Environments/OrganismEditor.js
+++ b/src/Environments/OrganismEditor.js
@@ -4,7 +4,7 @@ const GridMap = require('../Grid/GridMap');
const Renderer = require('../Rendering/Renderer');
const CellStates = require('../Organism/Cell/CellStates');
const EditorController = require("../Controllers/EditorController");
-const Directions = require('../Organism/Directions');
+const Species = require('../Stats/Species');
class OrganismEditor extends Environment{
constructor() {
@@ -37,14 +37,15 @@ class OrganismEditor extends Environment{
var center = this.grid_map.getCenter();
var loc_c = c - center[0];
var loc_r = r - center[1];
- var prev_cell = this.organism.getLocalCell(loc_c, loc_r)
+ var prev_cell = this.organism.anatomy.getLocalCell(loc_c, loc_r)
if (prev_cell != null) {
- var new_cell = this.organism.replaceCell(state, prev_cell.loc_col, prev_cell.loc_row, false);
+ var new_cell = this.organism.anatomy.replaceCell(state, prev_cell.loc_col, prev_cell.loc_row, false);
this.changeCell(c, r, state, new_cell);
}
- else if (this.organism.canAddCellAt(loc_c, loc_r)){
- this.changeCell(c, r, state, this.organism.addDefaultCell(state, loc_c, loc_r));
+ else if (this.organism.anatomy.canAddCellAt(loc_c, loc_r)){
+ this.changeCell(c, r, state, this.organism.anatomy.addDefaultCell(state, loc_c, loc_r));
}
+ this.organism.species = new Species(this.organism.anatomy, null, 0);
}
removeCellFromOrg(c, r) {
@@ -55,20 +56,22 @@ class OrganismEditor extends Environment{
alert("Cannot remove center cell");
return;
}
- var prev_cell = this.organism.getLocalCell(loc_c, loc_r)
+ var prev_cell = this.organism.anatomy.getLocalCell(loc_c, loc_r)
if (prev_cell != null) {
- if (this.organism.removeCell(loc_c, loc_r)) {
+ if (this.organism.anatomy.removeCell(loc_c, loc_r)) {
this.changeCell(c, r, CellStates.empty, null);
+ this.organism.species = new Species(this.organism.anatomy, null, 0);
}
}
}
- setOrganismToCopyOf(orig_org){
+ setOrganismToCopyOf(orig_org) {
this.grid_map.fillGrid(CellStates.empty);
var center = this.grid_map.getCenter();
this.organism = new Organism(center[0], center[1], this, orig_org);
this.organism.updateGrid();
this.controller.updateDetails();
+ this.controller.new_species = false;
}
getCopyOfOrg() {
@@ -80,8 +83,9 @@ class OrganismEditor extends Environment{
this.grid_map.fillGrid(CellStates.empty);
var center = this.grid_map.getCenter();
this.organism = new Organism(center[0], center[1], this, null);
- this.organism.addDefaultCell(CellStates.mouth, 0, 0);
+ this.organism.anatomy.addDefaultCell(CellStates.mouth, 0, 0);
this.organism.updateGrid();
+ this.organism.species = new Species(this.organism.anatomy, null, 0);
}
}
diff --git a/src/Environments/WorldEnvironment.js b/src/Environments/WorldEnvironment.js
index dbca6a4..e09add8 100644
--- a/src/Environments/WorldEnvironment.js
+++ b/src/Environments/WorldEnvironment.js
@@ -5,7 +5,7 @@ const Organism = require('../Organism/Organism');
const CellStates = require('../Organism/Cell/CellStates');
const EnvironmentController = require('../Controllers/EnvironmentController');
const Hyperparams = require('../Hyperparameters.js');
-const Cell = require('../Organism/Cell/GridCell');
+const FossilRecord = require('../Stats/FossilRecord');
class WorldEnvironment extends Environment{
constructor(cell_size) {
@@ -21,6 +21,9 @@ class WorldEnvironment extends Environment{
this.auto_reset = true;
this.largest_cell_count = 0;
this.reset_count = 0;
+ this.total_ticks = 0;
+ this.data_update_rate = 100;
+ FossilRecord.setEnv(this);
}
update(delta_time) {
@@ -35,13 +38,25 @@ class WorldEnvironment extends Environment{
this.generateFood();
}
this.removeOrganisms(to_remove);
+ this.total_ticks ++;
+ if (this.total_ticks % this.data_update_rate == 0) {
+ FossilRecord.updateData();
+ }
}
render() {
+ if (Hyperparams.headless) {
+ this.renderer.cells_to_render.clear();
+ return;
+ }
this.renderer.renderCells();
this.renderer.renderHighlights();
}
+ renderFull() {
+ this.renderer.renderFullGrid(this.grid_map.grid);
+ }
+
removeOrganisms(org_indeces) {
for (var i of org_indeces.reverse()){
this.total_mutability -= this.organisms[i].mutability;
@@ -56,26 +71,27 @@ class WorldEnvironment extends Environment{
OriginOfLife() {
var center = this.grid_map.getCenter();
var org = new Organism(center[0], center[1], this);
- // org.addDefaultCell(CellStates.eye, 0, 0);
- // org.addDefaultCell(CellStates.mouth, 1, 1);
- // org.addDefaultCell(CellStates.mover, 1, -1);
- org.addDefaultCell(CellStates.mouth, 0, 0);
- org.addDefaultCell(CellStates.producer, 1, 1);
- org.addDefaultCell(CellStates.producer, -1, -1);
+ org.anatomy.addDefaultCell(CellStates.mouth, 0, 0);
+ org.anatomy.addDefaultCell(CellStates.producer, 1, 1);
+ org.anatomy.addDefaultCell(CellStates.producer, -1, -1);
this.addOrganism(org);
+ FossilRecord.addSpecies(org, null);
}
addOrganism(organism) {
organism.updateGrid();
this.total_mutability += organism.mutability;
this.organisms.push(organism);
- if (organism.cells.length > this.largest_cell_count)
- this.largest_cell_count = organism.cells.length;
+ if (organism.anatomy.cells.length > this.largest_cell_count)
+ this.largest_cell_count = organism.anatomy.cells.length;
}
averageMutability() {
if (this.organisms.length < 1)
return 0;
+ if (Hyperparams.useGlobalMutability) {
+ return Hyperparams.globalMutability;
+ }
return this.total_mutability / this.organisms.length;
}
@@ -114,11 +130,13 @@ class WorldEnvironment extends Environment{
}
}
- reset(clear_walls=true) {
+ reset() {
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();
}
@@ -126,7 +144,6 @@ class WorldEnvironment extends Environment{
this.renderer.cell_size = cell_size;
this.renderer.fillShape(rows*cell_size, cols*cell_size);
this.grid_map.resize(cols, rows, cell_size);
- this.reset();
}
resizeFillWindow(cell_size) {
@@ -135,7 +152,6 @@ class WorldEnvironment extends Environment{
var cols = Math.floor(this.renderer.width / cell_size);
var rows = Math.floor(this.renderer.height / cell_size);
this.grid_map.resize(cols, rows, cell_size);
- this.reset();
}
}
diff --git a/src/Hyperparameters.js b/src/Hyperparameters.js
index c5c7be1..d7c34ed 100644
--- a/src/Hyperparameters.js
+++ b/src/Hyperparameters.js
@@ -2,6 +2,8 @@ const Neighbors = require("./Grid/Neighbors");
const Hyperparams = {
setDefaults: function() {
+ this.headless = false;
+
this.lifespanMultiplier = 100;
this.foodProdProb = 4;
this.foodProdProbScalar = 4;
diff --git a/src/Organism/Anatomy.js b/src/Organism/Anatomy.js
new file mode 100644
index 0000000..8175024
--- /dev/null
+++ b/src/Organism/Anatomy.js
@@ -0,0 +1,96 @@
+const CellStates = require("./Cell/CellStates");
+const BodyCellFactory = require("./Cell/BodyCells/BodyCellFactory");
+
+class Anatomy {
+ constructor(owner) {
+ this.owner = owner;
+ this.cells = [];
+ this.is_producer = false;
+ this.is_mover = false;
+ this.has_eyes = false;
+ this.birth_distance = 4;
+ }
+
+ canAddCellAt(c, r) {
+ for (var cell of this.cells) {
+ if (cell.loc_col == c && cell.loc_row == r){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ addDefaultCell(state, c, r) {
+ var new_cell = BodyCellFactory.createDefault(this.owner, state, c, r);
+ this.cells.push(new_cell);
+ return new_cell;
+ }
+
+ addRandomizedCell(state, c, r) {
+ if (state==CellStates.eye && !this.has_eyes) {
+ this.owner.brain.randomizeDecisions();
+ }
+ var new_cell = BodyCellFactory.createRandom(this.owner, state, c, r);
+ this.cells.push(new_cell);
+ return new_cell;
+ }
+
+ addInheritCell(parent_cell) {
+ var new_cell = BodyCellFactory.createInherited(this.owner, parent_cell);
+ this.cells.push(new_cell);
+ return new_cell;
+ }
+
+ replaceCell(state, c, r, randomize=true) {
+ this.removeCell(c, r, true);
+ if (randomize) {
+ return this.addRandomizedCell(state, c, r);
+ }
+ else {
+ return this.addDefaultCell(state, c, r);
+ }
+ }
+
+ removeCell(c, r, allow_center_removal=false) {
+ if (c == 0 && r == 0 && !allow_center_removal)
+ return false;
+ for (var i=0; i 1) {
- var cell = this.cells[Math.floor(Math.random() * this.cells.length)];
- mutated = this.removeCell(cell.loc_col, cell.loc_row);
+ if(this.anatomy.cells.length > 1) {
+ var cell = this.anatomy.getRandomCell();
+ mutated = this.anatomy.removeCell(cell.loc_col, cell.loc_row);
}
}
return mutated;
@@ -237,7 +166,7 @@ class Organism {
var new_c = this.c + direction_c;
var new_r = this.r + direction_r;
if (this.isClear(new_c, new_r)) {
- for (var cell of this.cells) {
+ for (var cell of this.anatomy.cells) {
var real_c = this.c + cell.rotatedCol(this.rotation);
var real_r = this.r + cell.rotatedRow(this.rotation);
this.env.changeCell(real_c, real_r, CellStates.empty, null);
@@ -258,7 +187,7 @@ class Organism {
}
var new_rotation = Directions.getRandomDirection();
if(this.isClear(this.c, this.r, new_rotation)){
- for (var cell of this.cells) {
+ for (var cell of this.anatomy.cells) {
var real_c = this.c + cell.rotatedCol(this.rotation);
var real_r = this.r + cell.rotatedRow(this.rotation);
this.env.changeCell(real_c, real_r, CellStates.empty, null);
@@ -277,7 +206,7 @@ class Organism {
this.move_count = 0;
}
- // assumes either c1==c2 or r1==r2, returns true if there is a clear path from point a to b
+ // assumes either c1==c2 or r1==r2, returns true if there is a clear path from point 1 to 2
isStraightPath(c1, r1, c2, r2, parent){
if (c1 == c2) {
if (r1 > r2){
@@ -314,11 +243,12 @@ class Organism {
}
isClear(col, row, rotation=this.rotation, ignore_armor=false) {
- for(var loccell of this.cells) {
+ for(var loccell of this.anatomy.cells) {
var cell = this.getRealCell(loccell, col, row, rotation);
- if(cell==null) {
+ if (cell==null) {
return false;
}
+ // console.log(cell.owner == this)
if (cell.owner==this || cell.state==CellStates.empty || (!Hyperparams.foodBlocksReproduction && cell.state==CellStates.food) || (ignore_armor && loccell.state==CellStates.armor && cell.state==CellStates.food)){
continue;
}
@@ -335,16 +265,17 @@ class Organism {
}
die() {
- for (var cell of this.cells) {
+ for (var cell of this.anatomy.cells) {
var real_c = this.c + cell.rotatedCol(this.rotation);
var real_r = this.r + cell.rotatedRow(this.rotation);
this.env.changeCell(real_c, real_r, CellStates.food, null);
}
+ this.species.decreasePop();
this.living = false;
}
updateGrid() {
- for (var cell of this.cells) {
+ for (var cell of this.anatomy.cells) {
var real_c = this.c + cell.rotatedCol(this.rotation);
var real_r = this.r + cell.rotatedRow(this.rotation);
this.env.changeCell(real_c, real_r, cell.state, cell);
@@ -360,13 +291,13 @@ class Organism {
if (this.food_collected >= this.foodNeeded()) {
this.reproduce();
}
- for (var cell of this.cells) {
+ for (var cell of this.anatomy.cells) {
cell.performFunction();
if (!this.living)
return this.living
}
- if (this.is_mover) {
+ if (this.anatomy.is_mover) {
this.move_count++;
var changed_dir = false;
if (this.ignore_brain_for == 0){
diff --git a/src/Rendering/Renderer.js b/src/Rendering/Renderer.js
index e60e457..647a9a8 100644
--- a/src/Rendering/Renderer.js
+++ b/src/Rendering/Renderer.js
@@ -52,7 +52,7 @@ class Renderer {
}
renderOrganism(org) {
- for(var org_cell of org.cells) {
+ for(var org_cell of org.anatomy.cells) {
var cell = org.getRealCell(org_cell);
this.renderCell(cell);
}
@@ -75,7 +75,7 @@ class Renderer {
}
highlightOrganism(org) {
- for(var org_cell of org.cells) {
+ for(var org_cell of org.anatomy.cells) {
var cell = org.getRealCell(org_cell);
this.cells_to_highlight.add(cell);
}
diff --git a/src/Stats/Charts/CellsChart.js b/src/Stats/Charts/CellsChart.js
new file mode 100644
index 0000000..9a10c5b
--- /dev/null
+++ b/src/Stats/Charts/CellsChart.js
@@ -0,0 +1,55 @@
+const CellStates = require("../../Organism/Cell/CellStates");
+const FossilRecord = require("../FossilRecord");
+const ChartController = require("./ChartController");
+
+class CellsChart extends ChartController {
+ constructor() {
+ super("Organism Size / Composition",
+ "Avg. Number of Cells per Organism",
+ "Note: to maintain efficiency, species with very small populations are discarded when collecting cell statistics.");
+ }
+
+ setData() {
+ this.clear();
+ //this.mouth, this.producer, this.mover, this.killer, this.armor, this.eye
+ this.data.push({
+ type: "line",
+ markerType: "none",
+ color: 'black',
+ showInLegend: true,
+ name: "pop1",
+ legendText: "Avg. organism size",
+ dataPoints: []
+ }
+ );
+ for (var c of CellStates.living) {
+ this.data.push({
+ type: "line",
+ markerType: "none",
+ color: c.color,
+ showInLegend: true,
+ name: c.name,
+ legendText: "Avg. " + c.name + " cells",
+ dataPoints: []
+ }
+ );
+ }
+ this.addAllDataPoints();
+
+
+ }
+
+ addDataPoint(i) {
+ var t = FossilRecord.tick_record[i];
+ var p = FossilRecord.av_cells[i];
+ this.data[0].dataPoints.push({x:t, y:p});
+ var j=1;
+ for (var name in FossilRecord.av_cell_counts[i]) {
+ var count = FossilRecord.av_cell_counts[i][name];
+ this.data[j].dataPoints.push({x:t,y:count})
+ j++;
+ }
+ }
+}
+
+module.exports = CellsChart;
\ No newline at end of file
diff --git a/src/Stats/Charts/ChartController.js b/src/Stats/Charts/ChartController.js
new file mode 100644
index 0000000..999fdf4
--- /dev/null
+++ b/src/Stats/Charts/ChartController.js
@@ -0,0 +1,84 @@
+const FossilRecord = require("../FossilRecord");
+
+class ChartController {
+ constructor(title, y_axis="", note="") {
+ this.data = [];
+ this.chart = new CanvasJS.Chart("chartContainer", {
+ zoomEnabled: true,
+ title:{
+ text: title
+ },
+ axisX:{
+ title: "Ticks",
+ minimum: 0,
+ },
+ axisY:{
+ title: y_axis,
+ minimum: 0,
+ },
+ data: this.data
+ });
+ this.chart.render();
+ $('#chart-note').text(note);
+ }
+
+ setData() {
+ alert("Must override updateData!");
+ }
+
+ setMinimum() {
+ var min = 0;
+ if (this.data[0].dataPoints != [])
+ min = this.data[0].dataPoints[0].x;
+ this.chart.options.axisX.minimum = min;
+ }
+
+ addAllDataPoints(){
+ for (var i in FossilRecord.tick_record) {
+ this.addDataPoint(i)
+ }
+ }
+
+ render() {
+ this.setMinimum();
+ this.chart.render();
+ }
+
+ updateData() {
+ var r_len = FossilRecord.tick_record.length;
+ var newest_t = -1;
+ var oldest_t = 0;
+ if (this.data[0].dataPoints.length>0) {
+ newest_t = this.data[0].dataPoints[this.data[0].dataPoints.length-1].x;
+ newest_t = this.data[0].dataPoints[0].x;
+ }
+ if (newest_t < FossilRecord.tick_record[r_len-1]) {
+ this.addNewest();
+ }
+ if (oldest_t < FossilRecord.tick_record[0]) {
+ this.removeOldest();
+ }
+ }
+
+ addNewest() {
+ var i = FossilRecord.tick_record.length-1;
+ this.addDataPoint(i);
+ }
+
+ addDataPoint(i) {
+ alert("Must override addDataPoint")
+ }
+
+ removeOldest() {
+ for (var dps of this.data) {
+ dps.dataPoints.shift();
+ }
+ }
+
+ clear() {
+ this.data.length = 0;
+ this.chart.render();
+ }
+}
+
+module.exports = ChartController;
\ No newline at end of file
diff --git a/src/Stats/Charts/MutationChart.js b/src/Stats/Charts/MutationChart.js
new file mode 100644
index 0000000..f211bdb
--- /dev/null
+++ b/src/Stats/Charts/MutationChart.js
@@ -0,0 +1,31 @@
+const FossilRecord = require("../FossilRecord");
+const ChartController = require("./ChartController");
+
+class MutationChart extends ChartController {
+ constructor() {
+ super("Mutation Rate");
+ }
+
+ setData() {
+ this.clear();
+ this.data.push({
+ type: "line",
+ markerType: "none",
+ color: 'black',
+ showInLegend: true,
+ name: "pop1",
+ legendText: "Average Mutation Rate",
+ dataPoints: []
+ }
+ );
+ this.addAllDataPoints();
+ }
+
+ addDataPoint(i) {
+ var t = FossilRecord.tick_record[i];
+ var p = FossilRecord.av_mut_rates[i];
+ this.data[0].dataPoints.push({x:t, y:p});
+ }
+}
+
+module.exports = MutationChart;
\ No newline at end of file
diff --git a/src/Stats/Charts/PopulationChart.js b/src/Stats/Charts/PopulationChart.js
new file mode 100644
index 0000000..99a02af
--- /dev/null
+++ b/src/Stats/Charts/PopulationChart.js
@@ -0,0 +1,31 @@
+const FossilRecord = require("../FossilRecord");
+const ChartController = require("./ChartController");
+
+class PopulationChart extends ChartController {
+ constructor() {
+ super("Population");
+ }
+
+ setData() {
+ this.clear();
+ this.data.push({
+ type: "line",
+ markerType: "none",
+ color: 'black',
+ showInLegend: true,
+ name: "pop1",
+ legendText: "Total Population",
+ dataPoints: []
+ }
+ );
+ this.addAllDataPoints();
+ }
+
+ addDataPoint(i) {
+ var t = FossilRecord.tick_record[i];
+ var p = FossilRecord.pop_counts[i];
+ this.data[0].dataPoints.push({x:t, y:p});
+ }
+}
+
+module.exports = PopulationChart;
\ No newline at end of file
diff --git a/src/Stats/Charts/SpeciesChart.js b/src/Stats/Charts/SpeciesChart.js
new file mode 100644
index 0000000..50c6b84
--- /dev/null
+++ b/src/Stats/Charts/SpeciesChart.js
@@ -0,0 +1,31 @@
+const FossilRecord = require("../FossilRecord");
+const ChartController = require("./ChartController");
+
+class SpeciesChart extends ChartController {
+ constructor() {
+ super("Species");
+ }
+
+ setData() {
+ this.clear();
+ this.data.push({
+ type: "line",
+ markerType: "none",
+ color: 'black',
+ showInLegend: true,
+ name: "spec",
+ legendText: "Number of Species",
+ dataPoints: []
+ }
+ );
+ this.addAllDataPoints();
+ }
+
+ addDataPoint(i) {
+ var t = FossilRecord.tick_record[i];
+ var p = FossilRecord.species_counts[i];
+ this.data[0].dataPoints.push({x:t, y:p});
+ }
+}
+
+module.exports = SpeciesChart;
\ No newline at end of file
diff --git a/src/Stats/FossilRecord.js b/src/Stats/FossilRecord.js
new file mode 100644
index 0000000..16e58dd
--- /dev/null
+++ b/src/Stats/FossilRecord.js
@@ -0,0 +1,133 @@
+const CellStates = require("../Organism/Cell/CellStates");
+const Species = require("./Species");
+
+const FossilRecord = {
+ init: function(){
+ this.extant_species = [];
+ this.extinct_species = [];
+
+ // if an organism has fewer than this cumulative pop, discard them on extinction
+ this.min_discard = 10;
+
+ this.record_size_limit = 500; // store this many data points
+ },
+
+ setEnv: function(env) {
+ this.env = env;
+ this.setData();
+ },
+
+ addSpecies: function(org, ancestor) {
+ // console.log("Adding Species")
+ var new_species = new Species(org.anatomy, ancestor, this.env.total_ticks);
+ this.extant_species.push(new_species);
+ org.species = new_species;
+ return new_species;
+ },
+
+ addSpeciesObj: function(species) {
+ // console.log("Adding Species")
+ this.extant_species.push(species);
+ return species;
+ },
+
+ fossilize: function(species) {
+ // console.log("Extinction")
+ species.end_tick = this.env.total_ticks;
+ for (i in this.extant_species) {
+ var s = this.extant_species[i];
+ if (s == species) {
+ this.extant_species.splice(i, 1);
+ if (species.cumulative_pop < this.min_pop) {
+ return false;
+ }
+ this.extinct_species.push(s);
+ // console.log("Extant species:", this.extant_species.length)
+ // console.log("Extinct species:", this.extinct_species.length)
+ return true;
+ }
+ }
+ },
+
+ resurrect: function(species) {
+ // console.log("Resurrecting species")
+ if (species.extinct) {
+ for (i in this.extinct_species) {
+ var s = this.extinct_species[i];
+ if (s == species) {
+ this.extinct_species.splice(i, 1);
+ this.extant_species.push(species);
+ species.extinct = false;
+ }
+ }
+ }
+ },
+
+ setData() {
+ // all parallel arrays
+ this.tick_record = [0];
+ this.pop_counts = [0];
+ this.species_counts = [0];
+ this.av_mut_rates = [0];
+ this.av_cells = [0];
+ this.av_cell_counts = [this.calcCellCountAverages()];
+ },
+
+ updateData() {
+ var tick = this.env.total_ticks;
+ this.tick_record.push(tick);
+ this.pop_counts.push(this.env.organisms.length);
+ this.species_counts.push(this.extant_species.length);
+ this.av_mut_rates.push(this.env.averageMutability());
+ this.calcCellCountAverages();
+
+ if (this.tick_record.length > this.record_size_limit) {
+ this.tick_record.shift();
+ this.pop_counts.shift();
+ this.species_counts.shift();
+ this.av_mut_rates.shift();
+ this.av_cells.shift();
+ this.av_cell_counts.shift();
+ }
+ },
+
+ calcCellCountAverages() {
+ var total_org = 0;
+ var cell_counts = {};
+ for (let c of CellStates.living) {
+ cell_counts[c.name] = 0;
+ }
+ var first=true;
+ for (let s of this.extant_species) {
+ if (s.cumulative_pop < this.min_discard && !first){
+ continue;
+ }
+ for (let name in s.cell_counts) {
+ cell_counts[name] += s.cell_counts[name] * s.population;
+ }
+ total_org += s.population;
+ first=false;
+ }
+ if (total_org == 0)
+ return cell_counts;
+
+ var total_cells = 0;
+ for (let c in cell_counts) {
+ total_cells += cell_counts[c];
+ cell_counts[c] /= total_org;
+ }
+ this.av_cells.push(total_cells / total_org);
+ this.av_cell_counts.push(cell_counts);
+ },
+
+ clear_record: function() {
+ this.extant_species = [];
+ this.extinct_species = [];
+ this.setData();
+ },
+
+}
+
+FossilRecord.init();
+
+module.exports = FossilRecord;
\ No newline at end of file
diff --git a/src/Stats/Species.js b/src/Stats/Species.js
new file mode 100644
index 0000000..37daadd
--- /dev/null
+++ b/src/Stats/Species.js
@@ -0,0 +1,52 @@
+const CellStates = require("../Organism/Cell/CellStates");
+
+class Species {
+ constructor(anatomy, ancestor, start_tick) {
+ this.anatomy = anatomy;
+ this.ancestor = ancestor;
+ this.population = 1;
+ this.cumulative_pop = 1;
+ this.start_tick = start_tick;
+ this.end_tick = -1;
+ this.color = Math.floor(Math.random()*16777215).toString(16);
+ if (ancestor != null) {
+ // needs to be reworked, maybe removed
+ var mutator = Math.floor(Math.random()*16777215)-8000000;
+ this.color = (mutator + parseInt(ancestor.color, 16)).toString(16);
+ }
+ this.name = '_' + Math.random().toString(36).substr(2, 9);
+ this.extinct = false;
+ this.calcAnatomyDetails();
+ }
+
+ calcAnatomyDetails() {
+ var cell_counts = {};
+ for (let c of CellStates.living) {
+ cell_counts[c.name] = 0;
+ }
+ for (let cell of this.anatomy.cells) {
+ cell_counts[cell.state.name]+=1;
+ }
+ this.cell_counts=cell_counts;
+ }
+
+ addPop() {
+ this.population++;
+ this.cumulative_pop++;
+ }
+
+ decreasePop() {
+ this.population--;
+ if (this.population <= 0) {
+ this.extinct = true;
+ const FossilRecord = require("./FossilRecord");
+ FossilRecord.fossilize(this);
+ }
+ }
+
+ lifespan() {
+ return this.end_tick - this.start_tick;
+ }
+}
+
+module.exports = Species;
\ No newline at end of file
diff --git a/src/Stats/StatsPanel.js b/src/Stats/StatsPanel.js
new file mode 100644
index 0000000..4487861
--- /dev/null
+++ b/src/Stats/StatsPanel.js
@@ -0,0 +1,66 @@
+const PopulationChart = require("./Charts/PopulationChart");
+const SpeciesChart = require("./Charts/SpeciesChart");
+const MutationChart = require("./Charts/MutationChart");
+const CellsChart = require("./Charts/CellsChart");
+const FossilRecord = require("./FossilRecord");
+
+
+const ChartSelections = [PopulationChart, SpeciesChart, CellsChart, MutationChart];
+
+class StatsPanel {
+ constructor(env) {
+ this.defineControls();
+ this.chart_selection = 0;
+ this.setChart();
+ this.env = env;
+ this.last_reset_count=env.reset_count;
+ }
+
+ setChart(selection=this.chart_selection) {
+ this.chart_controller = new ChartSelections[selection]();
+ this.chart_controller.setData();
+ this.chart_controller.render();
+ }
+
+ startAutoRender() {
+ this.setChart();
+ this.render_loop = setInterval(function(){this.updateChart();}.bind(this), 1000);
+ }
+
+ stopAutoRender() {
+ clearInterval(this.render_loop);
+ }
+
+ defineControls() {
+ $('#chart-option').change ( function() {
+ this.chart_selection = $("#chart-option")[0].selectedIndex;
+ this.setChart();
+ }.bind(this));
+ }
+
+ updateChart() {
+ if (this.last_reset_count < this.env.reset_count){
+ this.reset()
+ }
+ this.last_reset_count = this.env.reset_count;
+ this.chart_controller.updateData();
+ this.chart_controller.render();
+ }
+
+ updateDetails() {
+ var org_count = this.env.organisms.length;
+ $('#org-count').text("Total Population: " + org_count);
+ $('#species-count').text("Number of Species: " + FossilRecord.extant_species.length);
+ $('#largest-org').text("Largest Organism Ever: " + this.env.largest_cell_count + " cells");
+ $('#avg-mut').text("Average Mutation Rate: " + Math.round(this.env.averageMutability() * 100) / 100);
+
+
+ }
+
+ reset() {
+ this.setChart();
+ }
+
+}
+
+module.exports = StatsPanel;
\ No newline at end of file