/* | |
* ReWild - Replacement for Wildfire. | |
* Copyright (c) 2016, 2018 HarJIT | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated | |
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation | |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all copies or substantial portions | |
* of the Software. | |
* | |
* The origin of this software must not be misrepresented; you must not claim that you wrote the original | |
* software. If you use this software in a product, an acknowledgement in the product documentation would be | |
* appreciated but is not required. | |
* | |
* Altered versions of the Software shall not be misrepresented as being the original Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | |
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
* DEALINGS IN THE SOFTWARE. | |
* | |
* --- | |
* | |
* As an alternative to the above, you may redistribute and/or modify the Software under the following terms: | |
* | |
* rewild.js is free software: you can redistribute it and/or modify it under the terms of the GNU General | |
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your | |
* option) any later version. | |
* | |
* Additionally, rewild.js shall be subject to the following Section 7(c) permitted restrictions: | |
* | |
* The origin of this software must not be misrepresented; you must not claim that you wrote the original | |
* software. If you use this software in a product, an acknowledgement in the product documentation would be | |
* appreciated but is not required. | |
* | |
* Altered versions of the Software shall not be misrepresented as being the original Software. | |
* | |
*/ | |
/* | |
* Directions: Include in a script tag (either sourced from external file or else included in the .html), after a | |
* <div id="rewild"></div> tag. Include Chart.js first if you want it (otherwise it will report in CSV). | |
* | |
* Don't transclude from Gist itself (it will fail in Chrome due to MIME mismatch). | |
* | |
* Avoiding older IE compatibility modes so as to use HTML5 features (sliders) is nice, hence you may wish to | |
* <meta http-equiv="X-UA-Compatible" content="IE=10,chrome=1" /> (or later compatibility strings) | |
* | |
*/ | |
/* | |
* Included as the conditional of an empty if-statement so as to be reliably parsed as a called anonymous defn | |
* rather than borked on. | |
* Done like that in the first place so as not to clutter the global namespace, thus facilitating embedding. | |
* | |
*/ | |
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later | |
if(function(main_div){ | |
var reset_params = function(){ | |
/* Width in pixels. */ | |
WIDTH=300; | |
/* Height in pixels. */ | |
HEIGHT=200; | |
/* A number of individuals, expensive (makes app slow when too large). */ | |
POPULATION=300; | |
/* Contagion during incubation period, between 0 and 1 */ | |
CONTAG_IN=0.7; | |
/* Contagion when ill, between 0 and 1 */ | |
CONTAG_CS=0.3; | |
/* Probability of death from one infection, between 0 and 1 */ | |
FATALITY=0.7; | |
/* Can gain immunity: 1 (yes) or 0 (no) */ | |
IMMUNISES=1; | |
/* Probability of genetic immunity, between 0 and 1 */ | |
IMMUN_GENE=0.02; | |
/* Duration of incubation period, in frames. */ | |
INCUBATION=80; | |
/* Duration of illness, in frames. */ | |
COURSE=20; | |
/* Distance needed for infection, in pixels across and down, very expensive. */ | |
PROXIMITY=5; | |
/* Minimum duration between exposures (set to zero to disable). */ | |
REFRACTORY=10; | |
/* | |
* For reference, in the original Wildfire: | |
* | |
* Flu: Immunity, involuntary exposure, range 20 out of 50, infection on contact 30%, duration 7 days, | |
* mortality 1%. | |
* Measles: Immunity, involuntary exposure, range 10 out of 50, infection on contact 30%, duration 10 days, | |
* mortality 1%. | |
* Smallpox: Immunity, involuntary exposure, range 20 out of 50, infection on contact 20%, duration 10 days, | |
* mortality 30%. | |
* Satan bug: No immunity, involuntary exposure, range 40 out of 50, infection on contact 80%, duration 2 days, | |
* mortality 80%. | |
* AIDS: No immunity, voluntary exposure, 7 days between exposures, infection on contact 5%, duration 1000 days, | |
* mortality 99%. | |
* | |
*/ | |
HEALTHY_C="blue"; | |
INCUBATION_C="orange"; | |
EXPRESS_INCUBATION_C="orange"; | |
SICK_C="deeppink"; | |
IMMUNE_C="green"; | |
DEAD_C="black"; | |
SIZE=PROXIMITY; | |
/* | |
* There is not need for the typical user to change anything below this line. | |
* | |
*/ | |
}; | |
var WIDTH;var HEIGHT;var POPULATION;var CONTAG_IN; | |
var CONTAG_CS;var FATALITY;var IMMUNISES;var IMMUN_GENE; | |
var INCUBATION;var COURSE;var PROXIMITY;var REFRACTORY; | |
var HEALTHY_C;var INCUBATION_C;var SICK_C;var IMMUNE_C; | |
var DEAD_C;var SIZE;var EXPRESS_INCUBATION_C; | |
/* Names used by WF itself (only it lists Immune after healthy) | |
var HEALTHY_LABEL="Healthy"; | |
var INCUBATION_LABEL="Infected"; | |
var SICK_LABEL="Sick"; | |
var IMMUNE_LABEL="Immune"; | |
var DEAD_LABEL="Dead"; | |
*/ | |
var HEALTHY_LABEL="Unaffected"; | |
var INCUBATION_LABEL="Incubating"; | |
var SICK_LABEL="Sick"; | |
var IMMUNE_LABEL="Immune"; | |
var DEAD_LABEL="Dead"; | |
var FRAMES_LABEL_TITLE="Days: "; | |
var FRAMES_LABEL_UNIT=" days"; | |
var FRAMES_LABEL_SINGULAR="Day "; | |
var USE_SVG=(typeof SVGRectElement != "undefined"); | |
reset_params(); | |
var myRemove = function(arra,item){ | |
for(var i=0;i<arra.length;i+=1){ | |
if(arra[i]===item){ | |
arra.splice(i,1); | |
i-=1; | |
}; | |
}; | |
return -1; | |
}; | |
var countsToCsv = function(counts){ | |
var ret='"'+HEALTHY_LABEL+'","'+INCUBATION_LABEL+'","'+SICK_LABEL+'","'+IMMUNE_LABEL+'","'+DEAD_LABEL+'"\n'; | |
for(var i=0;i<counts.length;i+=1){ | |
var line=""; | |
for(var j=0;j<counts[i].length;j+=1){ | |
line+=counts[i][j]+","; | |
}; | |
ret+=line.substr(0,line.length-1)+"\n"; | |
}; | |
return ret; | |
}; | |
var countsToChart = function(counts){ | |
var canv=MyCreateElement("canvas"); | |
report.appendChild(canv); | |
var dnos=[]; | |
for(var i=1;i<=counts.length;i+=1){ | |
dnos[dnos.length]=FRAMES_LABEL_SINGULAR+i; | |
}; | |
var labels=[HEALTHY_LABEL,INCUBATION_LABEL,SICK_LABEL,IMMUNE_LABEL,DEAD_LABEL]; | |
var colours=[HEALTHY_C,EXPRESS_INCUBATION_C,SICK_C,IMMUNE_C,DEAD_C]; | |
var ogdos=[]; | |
if(!counts.length){ | |
return canv; | |
}; | |
for(var j=0;j<counts[0].length;j+=1){ | |
ogdos[j]=[]; | |
}; | |
for(var i=0;i<counts.length;i+=1){ | |
for(var j=0;j<counts[i].length;j+=1){ | |
ogdos[j][i]=counts[i][j]; | |
}; | |
}; | |
var datas=[]; | |
for(var j=0;j<counts[0].length;j+=1){ | |
datas[datas.length]={ | |
label: labels[j], | |
fill: false, | |
borderColor: colours[j], | |
backgroundColor: colours[j], // for tooltips. | |
pointBorderColor: colours[j], | |
pointStrokeColor: colours[j], | |
pointStyle: "line", | |
data: ogdos[j] | |
}; | |
}; | |
canv.width="1000"; | |
canv.height="700"; | |
canv.style.display="block"; | |
canv.style["margin-left"]="auto"; | |
canv.style["margin-right"]="auto"; | |
canv._rewild_chart=new Chart(canv.getContext("2d"), { | |
type: "line", | |
data: {"labels":dnos, "datasets":datas}, | |
options: { | |
animation: {"duration":0}, | |
elements: {"line": {"tension": 0}}, | |
scales: { | |
yAxes: [{ | |
scaleLabel: { | |
display: true, | |
labelString: '(+) count' | |
} | |
}] | |
} | |
} | |
}); | |
return canv; | |
}; | |
var set=function(bar,key,val){ | |
tosvg = {"top": "y", "left": "x", "background": "fill"}; | |
tocss = {"x": "left", "y": "top", "fill": "background"}; | |
if (bar.nodeName.toLowerCase() == "div") { | |
bar.style.position = "absolute"; | |
} | |
if (!key) { | |
return; | |
} else if (bar.nodeName.toLowerCase() == "rect" || bar.nodeName.toLowerCase() == "svg") { | |
bar.setAttribute(tosvg[key] || key, val); | |
} else if (bar.nodeName.toLowerCase() == "g") { | |
bar.setAttribute("data-" + (tosvg[key] || key), parseInt(val) + ""); | |
var x = bar.getAttribute("data-x"); | |
var y = bar.getAttribute("data-y"); | |
if (x && y) { | |
bar.setAttribute("transform", "translate(" + x + " " + y + ")"); | |
} | |
} else { | |
bar.style[tocss[key] || key] = val; | |
}; | |
}; | |
var MyCreateElement = function(name){ | |
var namespace; | |
if (name == "svg" || name == "g" || name == "rect") { | |
namespace = "http://www.w3.org/2000/svg"; | |
} | |
return (namespace)?(document.createElementNS(namespace, name)):(document.createElement(name)); | |
} | |
var Cross=function(area,stack,WIDTH,HEIGHT,POPULATION,CONTAG_IN,CONTAG_CS,FATALITY,IMMUNISES,IMMUN_GENE, | |
INCUBATION,COURSE,PROXIMITY,REFRACTORY){ | |
var thus=this; | |
this._countdown=-1; | |
this._intrinsic_randv=Math.random(); | |
/**/ | |
this.area=area; | |
this.stack=stack; | |
if (area.nodeName.toLowerCase() == "svg") { | |
this.groupel=MyCreateElement("g"); | |
area.appendChild(this.groupel); | |
var downbar=MyCreateElement("rect"); | |
this.groupel.appendChild(downbar); | |
var crossbar=MyCreateElement("rect"); | |
this.groupel.appendChild(crossbar); | |
} else { | |
this.groupel=MyCreateElement("div"); | |
area.appendChild(this.groupel); | |
var downbar=MyCreateElement("div"); | |
this.groupel.appendChild(downbar); | |
var crossbar=MyCreateElement("div"); | |
this.groupel.appendChild(crossbar); | |
} | |
set(this.groupel); | |
set(downbar, "top", "0"); | |
set(downbar, "shape-rendering", "crispEdges"); | |
downbar.style["margin"] = "0"; | |
set(crossbar, "left", "0"); | |
set(crossbar, "shape-rendering", "crispEdges"); | |
crossbar.style["margin"] = "0"; | |
/**/ | |
this._set_zed = function(zed){ | |
thus.groupel.style["z-index"] = zed; | |
if (stack.zed_indices != null && typeof stack.zed_indices[zed] != "undefined") { | |
stack.zed_indices[zed].appendChild(thus.groupel); | |
} | |
}; | |
this._place=function(x,y){ | |
thus.x=Math.floor(x); | |
set(thus.groupel, "left", this.x+"px"); | |
thus.y=Math.floor(y); | |
set(thus.groupel, "top", this.y+"px"); | |
stack.superstack[this.x][this.y][stack.superstack[this.x][this.y].length]=thus; | |
}; | |
this.place=function(x,y){ | |
myRemove(stack.superstack[thus.x][thus.y],thus); | |
this._place(x,y); | |
}; | |
this.setSize=function(siz){ | |
thus._size=siz; | |
set(thus.groupel, "width", siz+"px"); | |
set(thus.groupel, "height", (2*siz)+"px"); | |
set(crossbar, "width", siz+"px"); | |
set(crossbar, "height", ((((siz%2)+1)%2)+1)+"px"); /* 2 if siz even else 1 */ | |
set(crossbar, "top", Math.floor((siz-1)/2)+"px"); | |
set(downbar, "width", ((((siz%2)+1)%2)+1)+"px"); /* 2 if siz even else 1 */ | |
set(downbar, "height", siz+"px"); | |
set(downbar, "left", Math.floor((siz-1)/2)+"px"); | |
this._place(Math.random()*(WIDTH-siz-1),Math.random()*(HEIGHT-(2*siz)-1)); | |
}; | |
this.setSize(SIZE); | |
/**/ | |
this._state="h"; /* Healthy */ | |
this._set_zed("2"); | |
set(downbar, "background", HEALTHY_C); | |
set(crossbar, "background", HEALTHY_C); | |
this.setState=function(state){ | |
var save_state=thus.getState(); | |
thus._state=state; | |
thus.stack.nt[state]+=1; | |
thus.stack.nt[save_state]-=1; | |
switch(state){ | |
case "h": /* Healthy */ | |
set(crossbar, "background", HEALTHY_C); | |
set(downbar, "background", HEALTHY_C); | |
set(downbar, "height", thus._size+"px"); | |
thus._set_zed("2"); | |
return; | |
case "c": /* inCubation */ | |
set(crossbar, "background", INCUBATION_C); | |
set(downbar, "background", INCUBATION_C); | |
set(downbar, "height", thus._size+"px"); | |
thus._countdown=INCUBATION; | |
thus._set_zed("4"); | |
return; | |
case "s": /* Sick */ | |
set(crossbar, "background", SICK_C); | |
set(downbar, "background", SICK_C); | |
set(downbar, "height", thus._size+"px"); | |
thus._countdown=COURSE; | |
thus._set_zed("5"); | |
return; | |
case "m": /* iMMune */ | |
set(crossbar, "background", IMMUNE_C); | |
set(downbar, "background", IMMUNE_C); | |
set(downbar, "height", thus._size+"px"); | |
thus._set_zed("3"); | |
return; | |
case "d": /* Dead */ | |
set(crossbar, "background", DEAD_C); | |
set(downbar, "background", DEAD_C); | |
set(downbar, "height", (thus._size*2)+"px"); | |
thus._set_zed("1"); | |
return; | |
case "r": /* Refractory */ | |
set(crossbar, "background", HEALTHY_C); | |
set(downbar, "background", HEALTHY_C); | |
set(downbar, "height", thus._size+"px"); | |
thus._countdown=REFRACTORY; | |
thus._set_zed("2"); | |
return; | |
default: | |
thus._state=save_state; | |
this.stack.nt[save_state]+=1; | |
alert("Invalid state character: "+state); | |
} | |
} | |
this.getState=function(){ | |
return thus._state; | |
} | |
/**/ | |
this._laststep=-1; | |
this.step=function(){ | |
var sst=thus.getState(); | |
if(sst=="d"){ return; }; | |
while(1){ | |
var clik=Math.random() | |
if(this._laststep==-1){clik*=0.49;}; | |
var y=thus.y; | |
var x=thus.x; | |
while(1){ | |
if (clik<0.125) { | |
y=y+2; | |
break; | |
} else if (clik<0.25) { | |
y=y-2; | |
break; | |
} else if (clik<0.375) { | |
x=x+2; | |
break; | |
} else if (clik<0.5) { | |
x=x-2; | |
break; | |
} else { | |
clik=this._laststep; | |
}; | |
}; | |
if(clik<0.5){ | |
this._laststep=clik; | |
}; | |
if ( ((y+(thus._size*2))<=HEIGHT) && ((x+thus._size)<=WIDTH) | |
&& (y>=0) && (x>=0) ) { | |
break; | |
}; | |
}; | |
thus.place(x,y); | |
if (thus._intrinsic_randv<IMMUN_GENE) { | |
if(sst=="h"){ /* Should still be a valid seed, else difficulties. */ | |
thus.setState("m"); | |
}; | |
}; | |
if (sst=="h") { | |
var tryx=x-PROXIMITY; | |
while(tryx<0){ tryx+=1; }; | |
while(1){ | |
if ( (tryx>(WIDTH-thus._size)) || (tryx>(x+PROXIMITY)) ) { | |
break; | |
}; | |
var tryy=y-PROXIMITY; | |
while(tryy<0){ tryy+=1; }; | |
while(1){ | |
if ( (tryy>(HEIGHT-thus._size)) || (tryy>(y+PROXIMITY)) ) { | |
break; | |
}; | |
var substac=stack.superstack[tryx][tryy]; | |
for(var i=0;i<substac.length;i+=1){ | |
var other=substac[i]; | |
var ost=other.getState(); | |
if (ost=="s") { | |
var randv=Math.random(); | |
if (randv<CONTAG_CS) { | |
thus.setState("c"); | |
} else if (REFRACTORY) { | |
thus.setState("r"); | |
}; | |
} else if (ost=="c") { | |
var randv=Math.random(); | |
if (randv<CONTAG_IN) { | |
thus.setState("c"); | |
} else if (REFRACTORY) { | |
thus.setState("r"); | |
}; | |
}; | |
}; | |
tryy+=1; | |
}; | |
tryx+=1; | |
}; | |
} else if (sst=="r") { | |
thus._countdown-=1; | |
if(thus._countdown<=0){ | |
thus.setState("h"); | |
}; | |
} else if (sst=="c") { | |
thus._countdown-=1; | |
if(thus._countdown<=0){ | |
thus.setState("s"); | |
}; | |
} else if(sst=="s") { | |
thus._countdown-=1; | |
if(thus._countdown<=0){ | |
var rand=Math.random(); | |
if (rand<FATALITY) { | |
thus.setState("d"); | |
} else { | |
if(IMMUNISES){ | |
thus.setState("m"); | |
} else { | |
thus.setState("h"); | |
}; | |
}; | |
}; | |
}; | |
}; | |
}; | |
function Stack(main_div,WIDTH,HEIGHT,POPULATION,CONTAG_IN,CONTAG_CS,FATALITY,IMMUNISES,IMMUN_GENE, | |
INCUBATION,COURSE,PROXIMITY,REFRACTORY){ | |
this.frame=1; | |
var thus=this; | |
this.closed=true; | |
this.frozen=true; | |
this.counts=[]; | |
this.step=function(){ | |
if(!thus.closed){ | |
for(var i=0;i<thus.all.length;i+=1){ | |
thus.all[i].step(); | |
}; | |
sample_h.span.removeChild(sample_h.span_t); | |
sample_h.span_t=document.createTextNode("| "+HEALTHY_LABEL+": "+(thus.nt.h+thus.nt.r)+" "); | |
sample_h.span.appendChild(sample_h.span_t); | |
sample_c.span.removeChild(sample_c.span_t); | |
sample_c.span_t=document.createTextNode("| "+INCUBATION_LABEL+": "+(thus.nt.c)+" "); | |
sample_c.span.appendChild(sample_c.span_t); | |
sample_s.span.removeChild(sample_s.span_t); | |
sample_s.span_t=document.createTextNode("| "+SICK_LABEL+": "+(thus.nt.s)+" "); | |
sample_s.span.appendChild(sample_s.span_t); | |
sample_m.span.removeChild(sample_m.span_t); | |
sample_m.span_t=document.createTextNode("| "+IMMUNE_LABEL+": "+(thus.nt.m)+" "); | |
sample_m.span.appendChild(sample_m.span_t); | |
sample_d.span.removeChild(sample_d.span_t); | |
sample_d.span_t=document.createTextNode("| "+DEAD_LABEL+": "+(thus.nt.d)+" "); | |
sample_d.span.appendChild(sample_d.span_t); | |
dayno_h.removeChild(dayno_h_t); | |
dayno_h_t=document.createTextNode(FRAMES_LABEL_TITLE+thus.frame+" "); | |
dayno_h.appendChild(dayno_h_t); | |
}; | |
if(!thus.frozen){ | |
thus.frame+=1; | |
thus.counts[thus.counts.length]=[thus.nt.h+thus.nt.r,thus.nt.c,thus.nt.s,thus.nt.m,thus.nt.d]; | |
if( (thus.nt.c==0) && (thus.nt.s==0) ){ | |
thus.frozen=true; | |
}; | |
}; | |
setTimeout(thus.step,5); | |
}; | |
this.seed=function(){ | |
/* Note: must be thus, not this, inside this func. */ | |
var rand=Math.random(); | |
thus.frozen=false; | |
thus.all[Math.floor(rand*thus.all.length)].setState("c"); | |
}; | |
this.report=function(){ | |
/* Note: must be thus, not this, inside this func. */ | |
configbox.style.display="none"; | |
report.removeChild(report.textnode); | |
report.removeChild(report.canvnode); | |
if( (typeof Chart != "undefined") && (MyCreateElement("canvas").getContext) && (MyCreateElement("canvas").getContext("2d")) ){ | |
report.textnode=document.createTextNode("Graph rendered using Chart.js, see https://github.com/chartjs/Chart.js"); | |
report.appendChild(report.textnode); | |
report.canvnode=countsToChart(thus.counts); | |
}else{ | |
report.textnode=document.createTextNode(countsToCsv(thus.counts)); | |
report.appendChild(report.textnode); | |
report.canvnode=document.createTextNode(""); | |
report.appendChild(report.canvnode); | |
}; | |
}; | |
this.reset=function(){ | |
/* Note: must be thus, not this, inside this func. */ | |
thus.frozen=true; | |
thus.closed=true; | |
for(var i=0;i<thus.all.length;i+=1){ | |
thus.all[i].setState("m"); | |
}; | |
for(var i=0;i<thus.all.length;i+=1){ | |
thus.all[i].setState("h"); | |
}; | |
thus.nt.h=POPULATION; | |
thus.nt.c=0; | |
thus.nt.s=0; | |
thus.nt.m=0; | |
thus.nt.d=0; | |
thus.nt.r=0; | |
thus.frame=1; | |
thus.counts=[]; | |
thus.closed=false; /* Still frozen, though, as no infection. */ | |
}; | |
this.close=function(){ | |
thus.frozen=true; | |
thus.closed=true; | |
thus.all=[]; | |
main_div.removeChild(thus.area); | |
}; | |
this.open=function(button, buttonr, buttonp){ | |
button.onclick=thus.seed; | |
buttonr.onclick=thus.reset; | |
buttonp.onclick=thus.report; | |
thus.area=MyCreateElement((USE_SVG)?("svg"):("div")); | |
thus.zed_indices = null; | |
main_div.appendChild(thus.area); | |
set(thus.area, "width", WIDTH+"px"); | |
set(thus.area, "height", HEIGHT+"px"); | |
if (thus.area.nodeName.toLowerCase() != "svg") { | |
thus.area.style["margin-left"]="auto"; | |
thus.area.style["margin-right"]="auto"; | |
thus.area.style.position="relative"; | |
} else { | |
// Z-index is determined differently in HTML versus SVG 1.1 | |
thus.zed_indices = {}; | |
thus.zed_indices["1"] = MyCreateElement("g"); | |
thus.area.appendChild(thus.zed_indices["1"]); | |
thus.zed_indices["2"] = MyCreateElement("g"); | |
thus.area.appendChild(thus.zed_indices["2"]); | |
thus.zed_indices["3"] = MyCreateElement("g"); | |
thus.area.appendChild(thus.zed_indices["3"]); | |
thus.zed_indices["4"] = MyCreateElement("g"); | |
thus.area.appendChild(thus.zed_indices["4"]); | |
thus.zed_indices["5"] = MyCreateElement("g"); | |
thus.area.appendChild(thus.zed_indices["5"]); | |
} | |
for(var i=0;i<POPULATION;i+=1){ | |
thus.all[thus.all.length]=new Cross(thus.area,thus,WIDTH,HEIGHT,POPULATION,CONTAG_IN, | |
CONTAG_CS,FATALITY,IMMUNISES,IMMUN_GENE, | |
INCUBATION,COURSE,PROXIMITY,REFRACTORY); | |
}; | |
thus.all[0].setSize(SIZE*3); | |
thus.nt={}; | |
thus.nt.h=POPULATION; | |
thus.nt.c=0; | |
thus.nt.s=0; | |
thus.nt.m=0; | |
thus.nt.d=0; | |
thus.nt.r=0; | |
thus.counts=[]; | |
thus.closed=false; | |
} | |
this.all=[]; | |
this.superstack=[]; | |
for(var x=0;x<=WIDTH;x+=1){ | |
this.superstack[x]=[]; | |
for(var y=0;y<=HEIGHT;y+=1){ | |
this.superstack[x][y]=[]; | |
}; | |
}; | |
setTimeout(thus.step,50); | |
}; | |
main_div.style["text-align"]="center"; | |
var titl=MyCreateElement("h6"); | |
titl.style["font-size"]="24px"; | |
titl.style["margin"]="0"; | |
main_div.appendChild(titl); | |
var titl_t=document.createTextNode("Replacement for Wildfire"); | |
titl.appendChild(titl_t); | |
var subtitl=MyCreateElement("p"); | |
subtitl.style["font-style"]="italic"; | |
main_div.appendChild(subtitl); | |
var subtitl_t=document.createTextNode("By HarJIT"); | |
subtitl.appendChild(subtitl_t); | |
var canv=MyCreateElement("div"); | |
main_div.appendChild(canv); | |
function SetSample(colour,text){ | |
this.span=MyCreateElement("span"); | |
main_div.appendChild(this.span); | |
this.span.style.color=colour; | |
this.span_t=document.createTextNode(text); | |
this.span.appendChild(this.span_t); | |
} | |
var sample_h=new SetSample(HEALTHY_C, HEALTHY_LABEL+" | "); | |
var sample_c=new SetSample(INCUBATION_C, INCUBATION_LABEL+" | "); | |
var sample_s=new SetSample(SICK_C, SICK_LABEL+" | "); | |
var sample_m=new SetSample(IMMUNE_C, IMMUNE_LABEL+" | "); | |
var sample_d=new SetSample(DEAD_C, DEAD_LABEL+" | "); | |
main_div.appendChild(MyCreateElement("br")); | |
var dayno_h=MyCreateElement("span"); | |
main_div.appendChild(dayno_h); | |
var dayno_h_t=document.createTextNode(" / "); | |
dayno_h.appendChild(dayno_h_t); | |
main_div.appendChild(MyCreateElement("br")); | |
var button=MyCreateElement("button"); | |
main_div.appendChild(button); | |
button.setAttribute("type","button"); | |
var button_t=document.createTextNode("Seed"); | |
button.appendChild(button_t); | |
var buttonr=MyCreateElement("button"); | |
main_div.appendChild(buttonr); | |
buttonr.setAttribute("type","button"); | |
var buttonr_t=document.createTextNode("Reset"); | |
buttonr.appendChild(buttonr_t); | |
var buttonp=MyCreateElement("button"); | |
main_div.appendChild(buttonp); | |
buttonp.setAttribute("type","button"); | |
var buttonp_t=document.createTextNode("Report"); | |
buttonp.appendChild(buttonp_t); | |
/* | |
* Note: IE7/IE8 only allow setting type before adding to DOM. | |
* IE11 does it properly. IE7/IE8 don't support range | |
* input anyway (it falls back) but (a) trying to set | |
* after adding terminates the whole script with an | |
* exception, (b) it *does* support checkbox, and the | |
* API differences make it imperative that that one | |
* *does not* fall back. | |
*/ | |
var Control=function(tbody,lab,lab2,typ,init_callback,onchange){ | |
this.tr=MyCreateElement("tr"); | |
tbody.appendChild(this.tr); | |
this.th=MyCreateElement("th"); | |
this.th.style.height="4em"; | |
this.tr.appendChild(this.th); | |
this.th.style.border="1px solid black"; | |
this.th.style["text-align"]="right"; | |
this.th.style["padding"]="2px"; | |
this.td=MyCreateElement("td"); | |
this.tr.appendChild(this.td); | |
this.td.style.border="1px solid black"; | |
this.td2=MyCreateElement("td"); | |
this.tr.appendChild(this.td2); | |
this.td2.style.border="1px solid black"; | |
this.box_t=document.createTextNode(lab); | |
this.th.appendChild(this.box_t); | |
this.th.appendChild(MyCreateElement("br")); | |
this.box_t2=document.createTextNode(lab2); | |
this.box_t2s=MyCreateElement("span"); | |
this.box_t2s.appendChild(this.box_t2); | |
this.box_t2s.style["font-weight"]=400; | |
this.box_t2s.style["font-size"]="smaller"; | |
this.th.appendChild(this.box_t2s); | |
this.box=MyCreateElement("input"); | |
this.box.setAttribute("type",typ); | |
this.td.appendChild(this.box); | |
this.box.control=this; /* cyclic ref */ | |
init_callback(this.box); | |
this.box.onchange=onchange; | |
}; | |
var expandlink=MyCreateElement("a"); | |
main_div.appendChild(expandlink); | |
expandlink.appendChild(document.createTextNode("Show/hide parameters.")); | |
expandlink.setAttribute("href","javascript:void(0);"); /* Format as link but don't navigate. */ | |
expandlink.style.display="block"; | |
var configbox=MyCreateElement("div"); | |
main_div.appendChild(configbox); | |
configbox.style.display="none"; | |
expandlink.onclick=function(){ | |
configbox.style.display=(configbox.style.display=="none")?("block"):("none"); | |
}; | |
var ctable=MyCreateElement("table"); | |
configbox.appendChild(ctable); | |
ctable.style.border="1px solid black"; | |
ctable.style["border-collapse"]="collapse"; | |
ctable.style["margin-left"]="auto"; | |
ctable.style["margin-right"]="auto"; | |
var ctbody=MyCreateElement("tbody"); | |
ctable.appendChild(ctbody); | |
var notice_tr=MyCreateElement("tr"); | |
ctbody.appendChild(notice_tr); | |
var notice_td=MyCreateElement("th"); | |
notice_td.style.height="4em"; | |
notice_tr.appendChild(notice_td); | |
notice_td.style.border="1px solid black"; | |
notice_td.style.background="black"; | |
notice_td.style.color="white"; | |
notice_td.setAttribute("colspan",3); | |
notice_td.appendChild(document.createTextNode("Parameters.")); | |
notice_td.appendChild(MyCreateElement("br")); | |
var notice_span=MyCreateElement("span"); | |
notice_td.appendChild(notice_span); | |
notice_span.appendChild(document.createTextNode("(Note that changing the below resets the simulation.)")); | |
notice_span.style["font-weight"]=400; | |
notice_span.style["font-size"]="smaller"; | |
var expbox_o=new Control(ctbody,"Incubation visible:","(can see if a non-sick (+) is infected)","checkbox",function(box){ | |
box.setAttribute("value","unused"); | |
box.setAttribute("checked",INCUBATION_C!=HEALTHY_C); | |
box.control.td2_t=document.createTextNode((INCUBATION_C!=HEALTHY_C)?("Yes"):("No")); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
INCUBATION_C=(this.checked)?(EXPRESS_INCUBATION_C):(HEALTHY_C); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode((INCUBATION_C!=HEALTHY_C)?("Yes"):("No")); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var widslid_o=new Control(ctbody,"Width:","(width of area, affects population density)","range",function(box){ | |
/* one more than minimum: freezes if both dimens are at minimum */ | |
box.setAttribute("min",(SIZE*3)+2); | |
box.setAttribute("max",1000); | |
box.setAttribute("value",WIDTH); | |
box.control.td2_t=document.createTextNode(WIDTH+"px"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
WIDTH=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(WIDTH+"px"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var heislid_o=new Control(ctbody,"Height:","(height of area, affects population density)","range",function(box){ | |
box.setAttribute("min",(SIZE*6)+1); | |
box.setAttribute("max",700); | |
box.setAttribute("value",HEIGHT); | |
box.control.td2_t=document.createTextNode(HEIGHT+"px"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
HEIGHT=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(HEIGHT+"px"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var popslid_o=new Control(ctbody,"Population:","(number of (+)s in area, affects population density)","range",function(box){ | |
box.setAttribute("min",1); | |
box.setAttribute("max",800); | |
box.setAttribute("value",POPULATION); | |
box.control.td2_t=document.createTextNode(POPULATION+""); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
POPULATION=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(POPULATION+""); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var contaginslid_o=new Control(ctbody,"Incubating contagion:","(likeliness to catch infection from an infected (+) not yet showing symptoms)","range",function(box){ | |
box.setAttribute("min",0); | |
box.setAttribute("max",1); | |
box.setAttribute("step","0.01"); | |
box.setAttribute("value",CONTAG_IN); | |
box.control.td2_t=document.createTextNode(Math.round(CONTAG_IN*100)+"%"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atof should work for both. */ | |
CONTAG_IN=parseFloat(this.value+""); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(Math.round(CONTAG_IN*100)+"%"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var contagcsslid_o=new Control(ctbody,"Contagion in course:","(likeliness to catch from a sick (+))","range",function(box){ | |
box.setAttribute("min",0); | |
box.setAttribute("max",1); | |
box.setAttribute("step","0.01"); | |
box.setAttribute("value",CONTAG_CS); | |
box.control.td2_t=document.createTextNode(Math.round(CONTAG_CS*100)+"%"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atof should work for both. */ | |
CONTAG_CS=parseFloat(this.value+""); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(Math.round(CONTAG_CS*100)+"%"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var fataslid_o=new Control(ctbody,"Fatality per infection:","(likeliness to die from an infection)","range",function(box){ | |
box.setAttribute("min",0); | |
box.setAttribute("max",1); | |
box.setAttribute("step","0.01"); | |
box.setAttribute("value",FATALITY); | |
box.control.td2_t=document.createTextNode(Math.round(FATALITY*100)+"%"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atof should work for both. */ | |
FATALITY=parseFloat(this.value+""); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(Math.round(FATALITY*100)+"%"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var immubox_o=new Control(ctbody,"Acquire immunity:","(after recovery, cannot catch again)","checkbox",function(box){ | |
box.setAttribute("value","unused"); | |
box.setAttribute("checked",IMMUNISES); | |
box.control.td2_t=document.createTextNode((IMMUNISES)?("Yes"):("No")); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
IMMUNISES=this.checked; | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode((IMMUNISES)?("Yes"):("No")); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var gimmuslid_o=new Control(ctbody,"Genetic immunity:","(probability of not being successfully infectable for genetic reasons)","range",function(box){ | |
box.setAttribute("min",0); | |
box.setAttribute("max",1); | |
box.setAttribute("step","0.01"); | |
box.setAttribute("value",IMMUN_GENE); | |
box.control.td2_t=document.createTextNode(Math.round(IMMUN_GENE*100)+"%"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atof should work for both. */ | |
IMMUN_GENE=parseFloat(this.value+""); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(Math.round(IMMUN_GENE*100)+"%"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var incuslid_o=new Control(ctbody,"Incubation period:","(duration after infection before showing symptoms)","range",function(box){ | |
box.setAttribute("min",1); | |
box.setAttribute("max",300); | |
box.setAttribute("value",INCUBATION); | |
box.control.td2_t=document.createTextNode(INCUBATION+FRAMES_LABEL_UNIT); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
INCUBATION=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(INCUBATION+FRAMES_LABEL_UNIT); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var courseslid_o=new Control(ctbody,"Illness duration:","(duration showing symptoms)","range",function(box){ | |
box.setAttribute("min",1); | |
box.setAttribute("max",300); | |
box.setAttribute("value",COURSE); | |
box.control.td2_t=document.createTextNode(COURSE+FRAMES_LABEL_UNIT); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
COURSE=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(COURSE+FRAMES_LABEL_UNIT); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var proxislid_o=new Control(ctbody,"Infection proximity:","(how near a (+) needs to be to catch infection)","range",function(box){ | |
box.setAttribute("min",1); | |
box.setAttribute("max",20); | |
box.setAttribute("value",PROXIMITY); | |
box.control.td2_t=document.createTextNode(PROXIMITY+" pixels"); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
PROXIMITY=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(PROXIMITY+" pixels"); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var refraslid_o=new Control(ctbody,"Minimum time between exposures:","(if exposure is an action which is not performed constantly, e.g. STIs)","range",function(box){ | |
box.setAttribute("min",0); | |
box.setAttribute("max",300); | |
box.setAttribute("value",REFRACTORY); | |
box.control.td2_t=document.createTextNode(REFRACTORY+FRAMES_LABEL_UNIT); | |
box.control.td2.appendChild(box.control.td2_t); | |
},function(){ | |
/* Maybe a string in HTML4 - string coerce then atoi should work for both. */ | |
REFRACTORY=parseInt(this.value+"",10); | |
restac2(buttonu); | |
this.control.td2.removeChild(this.control.td2_t); | |
this.control.td2_t=document.createTextNode(REFRACTORY+FRAMES_LABEL_UNIT); | |
this.control.td2.appendChild(this.control.td2_t); | |
}); | |
var report=MyCreateElement("pre"); | |
main_div.appendChild(report); | |
report.textnode=document.createTextNode(""); | |
report.appendChild(report.textnode); | |
report.canvnode=document.createTextNode(""); | |
report.appendChild(report.canvnode); | |
var buttonu={}; | |
buttonu.stac=new Stack(canv,WIDTH,HEIGHT,POPULATION,CONTAG_IN,CONTAG_CS,FATALITY, | |
IMMUNISES,IMMUN_GENE,INCUBATION,COURSE,PROXIMITY,REFRACTORY); | |
buttonu.stac.open(button, buttonr, buttonp); | |
var restac2=function(thus){ | |
thus.stac.close(); | |
thus.stac=new Stack(canv,WIDTH,HEIGHT,POPULATION,CONTAG_IN,CONTAG_CS,FATALITY, | |
IMMUNISES,IMMUN_GENE,INCUBATION,COURSE,PROXIMITY,REFRACTORY); | |
thus.stac.open(button, buttonr, buttonp); | |
}; | |
}(document.getElementById("rewild"))){}; | |
// @license-end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment