Javascript + HTML - ลองใช้
อัปเดตตามคำขอยอดนิยม
พฤติกรรมทั่วไป
โปรแกรมนี้มีการโต้ตอบค่อนข้าง
ซอร์สโค้ดเป็นพารามิเตอร์ที่สมบูรณ์ดังนั้นคุณสามารถปรับแต่งพารามิเตอร์ภายในอีกสองสามรายการได้ด้วยโปรแกรมแก้ไขข้อความที่คุณชื่นชอบ
คุณสามารถเปลี่ยนขนาดของฟอเรสต์ได้
อย่างน้อย 2 จะต้องมีพื้นที่มากพอที่จะวางต้นไม้คนตัดไม้และหมีในจุดที่แตกต่างกัน 3 จุดและค่าสูงสุดจะได้รับการแก้ไขโดยพลการถึง 100 (ซึ่งจะทำให้การรวบรวมข้อมูลคอมพิวเตอร์โดยเฉลี่ยของคุณ)
นอกจากนี้คุณยังสามารถเปลี่ยนความเร็วในการจำลอง
จอแสดงผลได้รับการอัพเดตทุก ๆ 20 มิลลิวินาทีดังนั้นขั้นตอนเวลาที่มากขึ้นจะสร้างภาพเคลื่อนไหวที่ละเอียดกว่า
ปุ่มอนุญาตให้หยุด / เริ่มการจำลองหรือใช้งานเป็นเวลาหนึ่งเดือนหรือหนึ่งปี
การเคลื่อนไหวของผู้อยู่อาศัยในป่าตอนนี้ค่อนข้างมีชีวิตชีวา การลอกคราบและการตัดต้นไม้ก็เกิดขึ้นเช่นกัน
บันทึกเหตุการณ์บางอย่างจะปรากฏขึ้นเช่นกัน มีข้อความเพิ่มเติมบางส่วนถ้าคุณเปลี่ยนระดับ verbosity แต่นั่นจะทำให้คุณท่วมด้วยการแจ้งเตือน "Bob ตัดต้นไม้อีกต้น"
ฉันจะไม่ทำถ้าฉันเป็นคุณ แต่ฉันไม่เป็นเช่นนั้น ...
ข้างสนามเด็กเล่นชุดกราฟิกที่ปรับขนาดอัตโนมัติจะถูกดึงออกมา:
- ประชากรหมีและคนตัดไม้
- จำนวนต้นไม้ทั้งหมดแบ่งออกเป็นต้นกล้าต้นใหญ่และต้นโต
คำอธิบายแผนภูมิยังแสดงปริมาณปัจจุบันของแต่ละรายการด้วย
ความเสถียรของระบบ
กราฟแสดงให้เห็นว่าเงื่อนไขเริ่มต้นไม่ได้ปรับขนาดได้อย่างสง่างาม หากป่าใหญ่เกินไปหมีจำนวนมากจะทำลายประชากรคนตัดไม้จนกว่าคนรักแพนเค้กจะถูกทิ้งไว้ข้างหลังบาร์ สิ่งนี้ทำให้เกิดการระเบิดครั้งแรกของต้นไม้ผู้สูงอายุซึ่งจะช่วยให้คนตัดไม้สามารถฟื้นตัวได้
ดูเหมือนว่า 15 เป็นขนาดที่เล็กที่สุดสำหรับป่าที่จะเอาชีวิตรอด ป่าขนาด 10 มักถูกทำลายหลังจากนั้นไม่กี่ร้อยปี ขนาดใดก็ได้ที่สูงกว่า 30 จะสร้างแผนที่เกือบเต็มไปด้วยต้นไม้ ระหว่างวันที่ 15 และ 30 คุณจะเห็นประชากรต้นไม้สั่นอย่างมีนัยสำคัญ
กฎบางประเด็นที่ถกเถียงกัน
ในความคิดเห็นของโพสต์ต้นฉบับดูเหมือนว่าสองฝ่ายต่าง ๆ ไม่ควรที่จะครอบครองจุดเดียวกัน สิ่งนี้ขัดแย้งกับกฎเกณฑ์เกี่ยวกับคนใจแคบที่หลงเข้าไปในมือสมัครเล่นแพนเค้ก
อย่างไรก็ตามฉันไม่ได้ปฏิบัติตามแนวทางนั้น เซลล์ฟอเรสต์ใด ๆ สามารถมีจำนวนผู้อยู่อาศัย (และเป็นศูนย์หรือต้นไม้หนึ่งต้น) นี่อาจมีผลกระทบบางอย่างต่อประสิทธิภาพของคนตัดไม้: ฉันคิดว่ามันจะช่วยให้พวกเขาขุดเข้าไปในกอต้นไม้ใหญ่ได้ง่ายขึ้น สำหรับหมีฉันไม่คาดหวังว่าสิ่งนี้จะสร้างความแตกต่างได้มากมาย
ฉันยังเลือกที่จะมีคนตัดไม้อย่างน้อยหนึ่งคนในป่าเสมอแม้จะมีจุดที่ประชากร Redneck สามารถไปถึงศูนย์ได้ (การยิงคนตัดไม้คนสุดท้ายบนแผนที่ถ้าการเก็บเกี่ยวไม่ดีจริง ๆ ซึ่งจะไม่เกิดขึ้นต่อไป สับให้สูญพันธุ์)
tweaking
เพื่อให้เกิดเสถียรภาพฉันได้เพิ่มพารามิเตอร์ที่ปรับแต่งสองอย่าง:
1) อัตราการเติบโตของคนตัดไม้
สัมประสิทธิ์นำไปใช้กับสูตรที่ให้จำนวนไม้แปรรูปพิเศษที่ได้รับการว่าจ้างเมื่อมีไม้เพียงพอ ตั้งค่าเป็น 1 เพื่อกลับไปใช้คำจำกัดความดั้งเดิม แต่ฉันพบว่ามีค่าประมาณ 0.5 อนุญาตให้ป่า (โดยเฉพาะต้นไม้อายุ) พัฒนาได้ดีขึ้น
2) เกณฑ์กำจัดหมี
สัมประสิทธิ์ที่กำหนดเปอร์เซ็นต์ต่ำสุดของการตัดไม้เพื่อส่งหมีไปที่สวนสัตว์ ตั้งค่าเป็น 0 เพื่อกลับไปที่คำจำกัดความดั้งเดิม แต่การกำจัดหมีที่รุนแรงนี้โดยทั่วไปจะ จำกัด ประชากรไว้ที่วัฏจักรการสั่น 0-1 ฉันตั้งค่าเป็น. 15 (เช่นหมีจะถูกลบออกเฉพาะในกรณีที่ 15% หรือมากกว่าของไม้แปรรูปถูกทำลายในปีนี้) สิ่งนี้ช่วยให้ประชากรหมีอยู่ในระดับปานกลางเพียงพอที่จะป้องกันไม่ให้คนใจแคบเช็ดบริเวณที่สะอาด แต่ยังคงอนุญาตให้ตัดส่วนที่ใหญ่ที่สุดของป่า
ในฐานะที่เป็นบันทึกย่อด้านการจำลองไม่เคยหยุดนิ่ง (แม้จะผ่าน 400 ปีที่ผ่านมา) มันสามารถทำได้อย่างง่ายดาย แต่ไม่
รหัส
รหัสมีอยู่ทั้งหมดในหน้า HTML เดียว
จะต้องมีการเข้ารหัส UTF-8เพื่อแสดงสัญลักษณ์ยูนิโค้ดที่เหมาะสมสำหรับหมีและไม้แปรรูป
สำหรับระบบที่มีความบกพร่อง Unicode (เช่น Ubuntu): ค้นหาบรรทัดต่อไปนี้:
jack :{ pic: '🙎', color:'#bc0e11' },
bear :{ pic: '🐻', color:'#422f1e' }},
และเปลี่ยนรูปสัญลักษณ์สำหรับตัวละครที่ง่ายต่อการแสดงผล ( #
, *
สิ่งที่)
<!doctype html>
<meta charset=utf-8>
<title>Of jacks and bears</title>
<body onload='init();'>
<style>
#log p { margin-top: 0; margin-bottom: 0; }
</style>
<div id='main'>
</div>
<table>
<tr>
<td><canvas id='forest'></canvas></td>
<td>
<table>
<tr>
<td colspan=2>
<div>Forest size <input type='text' size=10 onchange='create_forest(this.value);'> </div>
<div>Simulation tick <input type='text' size= 5 onchange='set_tick(this.value);' > (ms)</div>
<div>
<input type='button' value='◾' onclick='stop();'>
<input type='button' value='▸' onclick='start();'>
<input type='button' value='1 month' onclick='start(1);'>
<input type='button' value='1 year' onclick='start(12);'>
</div>
</td>
</tr>
<tr>
<td id='log' colspan=2>
</td>
</tr>
<tr>
<td><canvas id='graphs'></canvas></td>
<td id='legend'></td>
</tr>
<tr>
<td align='center'>evolution over 60 years</td>
<td id='counters'></td>
</tr>
</table>
</td>
</tr>
</table>
<script>
// ==================================================================================================
// Global parameters
// ==================================================================================================
var Prm = {
// ------------------------------------
// as defined in the original challenge
// ------------------------------------
// forest size
forest_size: 45, // 2025 cells
// simulation duration
duration: 400*12, // 400 years
// initial populations
populate: { trees: .5, jacks:.1, bears:.02 },
// tree ages
age: { mature:12, elder:120 },
// tree spawning probabilities
spawn: { sapling:0, mature:.1, elder:.2 },
// tree lumber yields
lumber: { mature:1, elder:2 },
// walking distances
distance: { jack:3, bear:5 },
// ------------------------------------
// extra tweaks
// ------------------------------------
// lumberjacks growth rate
// (set to 1 in original contest parameters)
jacks_growth: 1, // .5,
// minimal fraction of lumberjacks mauled to send a bear to the zoo
// (set to 0 in original contest parameters)
mauling_threshold: .15, // 0,
// ------------------------------------
// internal helpers
// ------------------------------------
// offsets to neighbouring cells
neighbours: [
{x:-1, y:-1}, {x: 0, y:-1}, {x: 1, y:-1},
{x:-1, y: 0}, {x: 1, y: 0},
{x:-1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}],
// ------------------------------------
// goodies
// ------------------------------------
// bear and people names
names:
{ bear: ["Art", "Ursula", "Arthur", "Barney", "Bernard", "Bernie", "Bjorn", "Orson", "Osborn", "Torben", "Bernadette", "Nita", "Uschi"],
jack: ["Bob", "Tom", "Jack", "Fred", "Paul", "Abe", "Roy", "Chuck", "Rob", "Alf", "Tim", "Tex", "Mel", "Chris", "Dave", "Elmer", "Ian", "Kyle", "Leroy", "Matt", "Nick", "Olson", "Sam"] },
// months
month: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ],
// ------------------------------------
// graphics
// ------------------------------------
// messages verbosity (set to 2 to be flooded, -1 to have no trace at all)
verbosity: 1,
// pixel sizes
icon_size: 100,
canvas_f_size: 600, // forest canvas size
canvas_g_width : 400, // graphs canvas size
canvas_g_height: 200,
// graphical representation
graph: {
soil: { color: '#82641e' },
sapling:{ radius:.1, color:'#52e311', next:'mature'},
mature :{ radius:.3, color:'#48b717', next:'elder' },
elder :{ radius:.5, color:'#8cb717', next:'elder' },
jack :{ pic: '🙎', color:'#2244ff' },
bear :{ pic: '🐻', color:'#422f1e' },
mauling:{ pic: '★', color:'#ff1111' },
cutting:{ pic: '●', color:'#441111' }},
// animation tick
tick:100 // ms
};
// ==================================================================================================
// Utilities
// ==================================================================================================
function int_rand (num)
{
return Math.floor (Math.random() * num);
}
function shuffle (arr)
{
for (
var j, x, i = arr.length;
i;
j = int_rand (i), x = arr[--i], arr[i] = arr[j], arr[j] = x);
}
function pick (arr)
{
return arr[int_rand(arr.length)];
}
function message (str, level)
{
level = level || 0;
if (level <= Prm.verbosity)
{
while (Gg.log.childNodes.length > 10) Gg.log.removeChild(Gg.log.childNodes[0]);
var line = document.createElement ('p');
line.innerHTML = Prm.month[Forest.date%12]+" "+Math.floor(Forest.date/12)+": "+str;
Gg.log.appendChild (line);
}
}
// ==================================================================================================
// Forest
// ==================================================================================================
// --------------------------------------------------------------------------------------------------
// a forest cell
// --------------------------------------------------------------------------------------------------
function cell()
{
this.contents = [];
}
cell.prototype = {
add: function (elt)
{
this.contents.push (elt);
},
remove: function (elt)
{
var i = this.contents.indexOf (elt);
this.contents.splice (i, 1);
},
contains: function (type)
{
for (var i = 0 ; i != this.contents.length ; i++)
{
if (this.contents[i].type == type)
{
return this.contents[i];
}
}
return null;
}
}
// --------------------------------------------------------------------------------------------------
// an entity (tree, jack, bear)
// --------------------------------------------------------------------------------------------------
function entity (x, y, type)
{
this.age = 0;
switch (type)
{
case "jack": this.name = pick (Prm.names.jack); break;
case "bear": this.name = pick (Prm.names.bear); break;
case "tree": this.name = "sapling"; Forest.t.low++; break;
}
this.x = this.old_x = x;
this.y = this.old_y = y;
this.type = type;
}
entity.prototype = {
move: function ()
{
Forest.remove (this);
var n = neighbours (this);
this.x = n[0].x;
this.y = n[0].y;
return Forest.add (this);
}
};
// --------------------------------------------------------------------------------------------------
// a list of entities (trees, jacks, bears)
// --------------------------------------------------------------------------------------------------
function elt_list (type)
{
this.type = type;
this.list = [];
}
elt_list.prototype = {
add: function (x, y)
{
if (x === undefined) x = int_rand (Forest.size);
if (y === undefined) y = int_rand (Forest.size);
var e = new entity (x, y, this.type);
Forest.add (e);
this.list.push (e);
return e;
},
remove: function (elt)
{
var i;
if (elt) // remove a specific element (e.g. a mauled lumberjack)
{
i = this.list.indexOf (elt);
}
else // pick a random element (e.g. a bear punished for the collective pancake rampage)
{
i = int_rand(this.list.length);
elt = this.list[i];
}
this.list.splice (i, 1);
Forest.remove (elt);
if (elt.name == "mature") Forest.t.mid--;
if (elt.name == "elder" ) Forest.t.old--;
return elt;
}
};
// --------------------------------------------------------------------------------------------------
// global forest handling
// --------------------------------------------------------------------------------------------------
function forest (size)
{
// initial parameters
this.size = size;
this.surface = size * size;
this.date = 0;
this.mauling = this.lumber = 0;
this.t = { low:0, mid:0, old:0 };
// initialize cells
this.cells = new Array (size);
for (var i = 0 ; i != size ; i++)
{
this.cells[i] = new Array(size);
for (var j = 0 ; j != size ; j++)
{
this.cells[i][j] = new cell;
}
}
// initialize entities lists
this.trees = new elt_list ("tree");
this.jacks = new elt_list ("jack");
this.bears = new elt_list ("bear");
this.events = [];
}
forest.prototype = {
populate: function ()
{
function fill (num, list)
{
for (var i = 0 ; i < num ; i++)
{
var coords = pick[i_pick++];
list.add (coords.x, coords.y);
}
}
// shuffle forest cells
var pick = new Array (this.surface);
for (var i = 0 ; i != this.surface ; i++)
{
pick[i] = { x:i%this.size, y:Math.floor(i/this.size)};
}
shuffle (pick);
var i_pick = 0;
// populate the lists
fill (Prm.populate.jacks * this.surface, this.jacks);
fill (Prm.populate.bears * this.surface, this.bears);
fill (Prm.populate.trees * this.surface, this.trees);
this.trees.list.forEach (function (elt) { elt.age = Prm.age.mature; });
},
add: function (elt)
{
var cell = this.cells[elt.x][elt.y];
cell.add (elt);
return cell;
},
remove: function (elt)
{
var cell = this.cells[elt.x][elt.y];
cell.remove (elt);
},
evt_mauling: function (jack, bear)
{
message (bear.name+" sniffs a delicious scent of pancake, unfortunately for "+jack.name, 1);
this.jacks.remove (jack);
this.mauling++;
Gg.counter.mauling.innerHTML = this.mauling;
this.register_event ("mauling", jack);
},
evt_cutting: function (jack, tree)
{
if (tree.name == 'sapling') return; // too young to be chopped down
message (jack.name+" cuts a "+tree.name+" tree: lumber "+this.lumber+" (+"+Prm.lumber[tree.name]+")", 2);
this.trees.remove (tree);
this.lumber += Prm.lumber[tree.name];
Gg.counter.cutting.innerHTML = this.lumber;
this.register_event ("cutting", jack);
},
register_event: function (type, position)
{
this.events.push ({ type:type, x:position.x, y:position.y});
},
tick: function()
{
this.date++;
this.events = [];
// monthly updates
this.trees.list.forEach (b_tree);
this.jacks.list.forEach (b_jack);
this.bears.list.forEach (b_bear);
// feed graphics
Gg.graphs.trees.add (this.trees.list.length);
Gg.graphs.jacks.add (this.jacks.list.length);
Gg.graphs.bears.add (this.bears.list.length);
Gg.graphs.sapling.add (this.t.low);
Gg.graphs.mature .add (this.t.mid);
Gg.graphs.elder .add (this.t.old);
// yearly updates
if (!(this.date % 12))
{
// update jacks
if (this.jacks.list.length == 0)
{
message ("An extra lumberjack is hired after a bear rampage");
this.jacks.add ();
}
if (this.lumber >= this.jacks.list.length)
{
var extra_jacks = Math.floor (this.lumber / this.jacks.list.length * Prm.jacks_growth);
message ("A good lumbering year. Lumberjacks +"+extra_jacks, 1);
for (var i = 0 ; i != extra_jacks ; i++) this.jacks.add ();
}
else if (this.jacks.list.length > 1)
{
var fired = this.jacks.remove();
message (fired.name+" has been chopped", 1);
}
// update bears
if (this.mauling > this.jacks.list.length * Prm.mauling_threshold)
{
var bear = this.bears.remove();
message (bear.name+" will now eat pancakes in a zoo", 1);
}
else
{
var bear = this.bears.add();
message (bear.name+" starts a quest for pancakes", 1);
}
// reset counters
this.mauling = this.lumber = 0;
}
}
}
function neighbours (elt)
{
var ofs,x,y;
var list = [];
for (ofs in Prm.neighbours)
{
var o = Prm.neighbours[ofs];
x = elt.x + o.x;
y = elt.y + o.y;
if ( x < 0 || x >= Forest.size
|| y < 0 || y >= Forest.size) continue;
list.push ({x:x, y:y});
}
shuffle (list);
return list;
}
// --------------------------------------------------------------------------------------------------
// entities behaviour
// --------------------------------------------------------------------------------------------------
function b_tree (tree)
{
// update tree age and category
if (tree.age == Prm.age.mature) { tree.name = "mature"; Forest.t.low--; Forest.t.mid++; }
else if (tree.age == Prm.age.elder ) { tree.name = "elder" ; Forest.t.mid--; Forest.t.old++; }
tree.age++;
// see if we can spawn something
if (Math.random() < Prm.spawn[tree.name])
{
var n = neighbours (tree);
for (var i = 0 ; i != n.length ; i++)
{
var coords = n[i];
var cell = Forest.cells[coords.x][coords.y];
if (cell.contains("tree")) continue;
Forest.trees.add (coords.x, coords.y);
break;
}
}
}
function b_jack (jack)
{
jack.old_x = jack.x;
jack.old_y = jack.y;
for (var i = 0 ; i != Prm.distance.jack ; i++)
{
// move
var cell = jack.move ();
// see if we stumbled upon a bear
var bear = cell.contains ("bear");
if (bear)
{
Forest.evt_mauling (jack, bear);
break;
}
// see if we reached an harvestable tree
var tree = cell.contains ("tree");
if (tree)
{
Forest.evt_cutting (jack, tree);
break;
}
}
}
function b_bear (bear)
{
bear.old_x = bear.x;
bear.old_y = bear.y;
for (var i = 0 ; i != Prm.distance.bear ; i++)
{
var cell = bear.move ();
var jack = cell.contains ("jack");
if (jack)
{
Forest.evt_mauling (jack, bear);
break; // one pancake hunt per month is enough
}
}
}
// --------------------------------------------------------------------------------------------------
// Graphics
// --------------------------------------------------------------------------------------------------
function init()
{
function create_counter (desc)
{
var counter = document.createElement ('span');
var item = document.createElement ('p');
item.innerHTML = desc.name+" ";
item.style.color = desc.color;
item.appendChild (counter);
return { item:item, counter:counter };
}
// initialize forest canvas
Gf = { period:20, tick:0 };
Gf.canvas = document.getElementById ('forest');
Gf.canvas.width =
Gf.canvas.height = Prm.canvas_f_size;
Gf.ctx = Gf.canvas.getContext ('2d');
Gf.ctx.textBaseline = 'Top';
// initialize graphs canvas
Gg = { counter:[] };
Gg.canvas = document.getElementById ('graphs');
Gg.canvas.width = Prm.canvas_g_width;
Gg.canvas.height = Prm.canvas_g_height;
Gg.ctx = Gg.canvas.getContext ('2d');
// initialize graphs
Gg.graphs = {
jacks: new graphic({ name:"lumberjacks" , color:Prm.graph.jack.color }),
bears: new graphic({ name:"bears" , color:Prm.graph.bear.color, ref:'jacks' }),
trees: new graphic({ name:"trees" , color:'#0F0' }),
sapling: new graphic({ name:"saplings" , color:Prm.graph.sapling.color, ref:'trees' }),
mature: new graphic({ name:"mature trees", color:Prm.graph.mature .color, ref:'trees' }),
elder: new graphic({ name:"elder trees" , color:Prm.graph.elder .color, ref:'trees' })
};
Gg.legend = document.getElementById ('legend');
for (g in Gg.graphs)
{
var gr = Gg.graphs[g];
var c = create_counter (gr);
gr.counter = c.counter;
Gg.legend.appendChild (c.item);
}
// initialize counters
var counters = document.getElementById ('counters');
var def = [ "mauling", "cutting" ];
var d; for (d in def)
{
var c = create_counter ({ name:def[d], color:Prm.graph[def[d]].color });
counters.appendChild (c.item);
Gg.counter[def[d]] = c.counter;
}
// initialize log
Gg.log = document.getElementById ('log');
// create our forest
create_forest(Prm.forest_size);
start();
}
function create_forest (size)
{
if (size < 2) size = 2;
if (size > 100) size = 100;
Forest = new forest (size);
Prm.icon_size = Prm.canvas_f_size / size;
Gf.ctx.font = 'Bold '+Prm.icon_size+'px Arial';
Forest.populate ();
draw_forest();
var g; for (g in Gg.graphs) Gg.graphs[g].reset();
draw_graphs();
}
function animate()
{
if (Gf.tick % Prm.tick == 0)
{
Forest.tick();
draw_graphs();
}
draw_forest();
Gf.tick+= Gf.period;
if (Gf.tick == Gf.stop_date) stop();
}
function draw_forest ()
{
function draw_dweller (dweller)
{
var type = Prm.graph[dweller.type];
Gf.ctx.fillStyle = type.color;
var x = dweller.x * time_fraction + dweller.old_x * (1 - time_fraction);
var y = dweller.y * time_fraction + dweller.old_y * (1 - time_fraction);
Gf.ctx.fillText (type.pic, x * Prm.icon_size, (y+1) * Prm.icon_size);
}
function draw_event (evt)
{
var gr = Prm.graph[evt.type];
Gf.ctx.fillStyle = gr.color;
Gf.ctx.fillText (gr.pic, evt.x * Prm.icon_size, (evt.y+1) * Prm.icon_size);
}
function draw_tree (tree)
{
// trees grow from one category to the next
var type = Prm.graph[tree.name];
var next = Prm.graph[type.next];
var radius = (type.radius + (next.radius - type.radius) / Prm.age[type.next] * tree.age) * Prm.icon_size;
Gf.ctx.fillStyle = Prm.graph[tree.name].color;
Gf.ctx.beginPath();
Gf.ctx.arc((tree.x+.5) * Prm.icon_size, (tree.y+.5) * Prm.icon_size, radius, 0, 2*Math.PI);
Gf.ctx.fill();
}
// background
Gf.ctx.fillStyle = Prm.graph.soil.color;
Gf.ctx.fillRect (0, 0, Gf.canvas.width, Gf.canvas.height);
// time fraction to animate displacements
var time_fraction = (Gf.tick % Prm.tick) / (Prm.tick-Gf.period);
// entities
Forest.trees.list.forEach (draw_tree);
Forest.jacks.list.forEach (draw_dweller);
Forest.bears.list.forEach (draw_dweller);
Forest.events.forEach (draw_event);
}
// --------------------------------------------------------------------------------------------------
// Graphs
// --------------------------------------------------------------------------------------------------
function graphic (prm)
{
this.name = prm.name || '?';
this.color = prm.color || '#FFF';
this.size = prm.size || 720;
this.ref = prm.ref;
this.values = [];
this.counter = document.getElement
}
graphic.prototype = {
draw: function ()
{
Gg.ctx.strokeStyle = this.color;
Gg.ctx.beginPath();
for (var i = 0 ; i != this.values.length ; i++)
{
var x = (i + this.size - this.values.length) / this.size * Gg.canvas.width;
var y = (1-(this.values[i] - this.min) / this.rng) * Gg.canvas.height;
if (i == 0) Gg.ctx.moveTo (x, y);
else Gg.ctx.lineTo (x, y);
}
Gg.ctx.stroke();
},
add: function (value)
{
// store value
this.values.push (value);
this.counter.innerHTML = value;
// cleanup history
while (this.values.length > this.size) this.values.splice (0,1);
// compute min and max
this.min = Math.min.apply(Math, this.values);
if (this.min > 0) this.min = 0;
this.max = this.ref
? Gg.graphs[this.ref].max
: Math.max.apply(Math, this.values);
this.rng = this.max - this.min;
if (this.rng == 0) this.rng = 1;
},
reset: function()
{
this.values = [];
}
}
function draw_graphs ()
{
function draw_graph (graph)
{
graph.draw();
}
// background
Gg.ctx.fillStyle = '#000';
Gg.ctx.fillRect (0, 0, Gg.canvas.width, Gg.canvas.height);
// graphs
var g; for (g in Gg.graphs)
{
var gr = Gg.graphs[g];
gr.draw();
}
}
// --------------------------------------------------------------------------------------------------
// User interface
// --------------------------------------------------------------------------------------------------
function set_tick(value)
{
value = Math.round (value / Gf.period);
if (value < 2) value = 2;
value *= Gf.period;
Prm.tick = value;
return value;
}
function start (duration)
{
if (Prm.timer) stop();
Gf.stop_date = duration ? Gf.tick + duration*Prm.tick : -1;
Prm.timer = setInterval (animate, Gf.period);
}
function stop ()
{
if (Prm.timer)
{
clearInterval (Prm.timer);
Prm.timer = null;
}
Gf.stop_date = -1;
}
</script>
</body>
อะไรต่อไป
ข้อสังเกตเพิ่มเติมยังคงยินดีต้อนรับ
NB: ฉันรู้ว่าต้นอ่อน / ผู้ใหญ่ / ผู้อาวุโสนับต้นไม้ยังคงยุ่งเหยิงเล็กน้อย
นอกจากนี้ฉันพบ document.getElementById อ่านได้มากกว่า $ ดังนั้นไม่จำเป็นต้องบ่นเกี่ยวกับการขาด jQueryisms มันฟรีโดย jQuery ถึงตัวเขาเองใช่ไหม?
Note that you will never reduce your Lumberjack labor force below 0
ในรายการส่วนคนตัดไม้ 3. อาจเปลี่ยนเป็น 1 เพื่อให้สอดคล้องกับสิ่งที่คุณพูดถึงในส่วนของหมี?