Last active
November 12, 2021 14:14
-
-
Save harjitmoe/6f0b218b79b0fd3eb559cb7038797d73 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ReWild - Replacement for Wildfire. | |
* Copyright (c) 2016, 2018, 2020 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="#6200FF"; | |
INCUBATION_C="#FF9F00"; | |
EXPRESS_INCUBATION_C="#FF9F00"; | |
SICK_C="#FC002A"; | |
IMMUNE_C="#00D4B7"; | |
DEAD_C="#000"; | |
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