Cập nhật theo yêu cầu phổ biến
Hành vi chung
Chương trình hiện có phần tương tác.
Mã nguồn hoàn toàn được tham số hóa, vì vậy bạn có thể điều chỉnh thêm một vài tham số bên trong bằng trình soạn thảo văn bản yêu thích của mình.
Bạn có thể thay đổi kích thước rừng.
Cần tối thiểu 2 cái để có đủ chỗ để đặt một cái cây, một người đốn gỗ và một con gấu ở 3 điểm khác nhau và tối đa được cố định tùy ý thành 100 (sẽ làm cho máy tính trung bình của bạn bò lên).
Bạn cũng có thể thay đổi tốc độ mô phỏng.
Hiển thị được cập nhật cứ sau 20 ms, vì vậy bước thời gian lớn hơn sẽ tạo ra hình ảnh động tốt hơn.
Các nút cho phép dừng / bắt đầu mô phỏng hoặc chạy nó trong một tháng hoặc một năm.
Chuyển động của cư dân rừng bây giờ có phần hoạt hình. Sự kiện kéo dài và chặt cây cũng được tìm ra.
Một bản ghi của một số sự kiện cũng được hiển thị. Một số thông báo khác có sẵn nếu bạn thay đổi mức độ chi tiết, nhưng điều đó sẽ tràn ngập bạn với thông báo "Bob cắt một cây khác".
Tôi thà không làm điều đó nếu tôi là bạn, nhưng tôi thì không, vì vậy ...
Bên cạnh sân chơi, một bộ đồ họa được thu nhỏ tự động được vẽ:
- gấu và quần thể lumberjacks
- tổng số cây, được chia thành cây non, cây trưởng thành và cây già
Truyền thuyết cũng hiển thị số lượng hiện tại của từng mặt hàng.
Ổn định hệ thống
Các biểu đồ cho thấy các điều kiện ban đầu không mở rộng một cách duyên dáng. Nếu khu rừng quá lớn, quá nhiều con gấu sẽ làm suy giảm dân số gỗ cho đến khi đủ số người yêu thích bánh kếp được đặt sau song sắt. Điều này gây ra một vụ nổ ban đầu của cây già, từ đó giúp dân số gỗ phục hồi.
Dường như 15 là kích thước tối thiểu để rừng tồn tại. Một khu rừng có kích thước 10 thường sẽ bị san bằng sau vài trăm năm. Bất kỳ kích thước nào trên 30 sẽ tạo ra một bản đồ gần đầy cây. Từ 15 đến 30, bạn có thể thấy quần thể cây dao động đáng kể.
Một số điểm quy tắc gây tranh cãi
Trong các bình luận của bài viết gốc, có vẻ như nhiều người khác không được phép chiếm cùng một vị trí. Điều này mâu thuẫn bằng cách nào đó quy tắc về một redneck lang thang vào một bánh kếp nghiệp dư.
Ở mức nào, tôi đã không tuân theo hướng dẫn đó. Bất kỳ tế bào rừng nào cũng có thể chứa bất kỳ số lượng người sống (và chính xác là 0 hoặc một cây). Điều này có thể có một số hậu quả đối với hiệu quả của gỗ xẻ: Tôi nghi ngờ nó cho phép chúng đào sâu vào một cụm cây già dễ dàng hơn. Đối với gấu, tôi không hy vọng điều này sẽ tạo ra nhiều sự khác biệt.
Tôi cũng đã chọn luôn có ít nhất một người đốn gỗ trong rừng, mặc dù quan điểm rằng dân số redneck có thể đạt tới 0 (bắn người gỗ xẻ cuối cùng trên bản đồ nếu việc thu hoạch thực sự kém, dù sao thì rừng sẽ không bao giờ xảy ra băm nhỏ đến tuyệt chủng).
Tinh chỉnh
Để đạt được sự ổn định, tôi đã thêm hai tham số điều chỉnh:
1) tốc độ tăng trưởng gỗ xẻ
một hệ số được áp dụng cho công thức cho số lượng gỗ xẻ được thuê thêm khi có đủ gỗ. Đặt thành 1 để quay lại định nghĩa ban đầu, nhưng tôi thấy giá trị khoảng 0,5 cho phép rừng (đặc biệt là cây già) phát triển tốt hơn.
2) tiêu chí loại bỏ gấu
một hệ số xác định tỷ lệ phần trăm tối thiểu của gỗ xẻ bị đánh cắp để gửi một con gấu đến sở thú. Đặt thành 0 để quay lại định nghĩa ban đầu, nhưng việc loại bỏ gấu quyết liệt này về cơ bản sẽ giới hạn dân số trong chu kỳ dao động 0-1. Tôi đặt nó thành 0,15 (tức là một con gấu chỉ bị loại bỏ nếu 15% hoặc nhiều hơn số gỗ xẻ đã bị loại bỏ trong năm nay). Điều này cho phép một quần thể gấu vừa phải, đủ để ngăn chặn những con quỷ đỏ lau sạch khu vực nhưng vẫn cho phép một phần lớn của khu rừng bị chặt.
Là một lưu ý phụ, mô phỏng không bao giờ dừng lại (thậm chí vượt quá 400 năm cần thiết). Nó có thể dễ dàng làm như vậy, nhưng nó không.
Mật mã
Mã này hoàn toàn được chứa trong một trang HTML duy nhất.
Nó phải được mã hóa UTF-8 để hiển thị các ký hiệu unicode thích hợp cho gấu và gỗ.
Đối với các hệ thống bị suy giảm Unicode (ví dụ: Ubuntu): tìm các dòng sau:
jack :{ pic: '🙎', color:'#bc0e11' },
bear :{ pic: '🐻', color:'#422f1e' }},
và thay đổi chữ tượng hình cho nhân vật dễ dàng hơn để hiển thị ( #
, *
, bất cứ điều gì)
<!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>
Tiếp theo là gì?
Nhiều nhận xét vẫn được chào đón.
Lưu ý: Tôi biết rằng cây non / cây trưởng thành / cây già vẫn còn hơi lộn xộn, nhưng với địa ngục với nó.
Ngoài ra, tôi thấy document.getEuityById dễ đọc hơn $, vì vậy không cần phải phàn nàn về việc thiếu jQueryism. Đó là jQuery miễn phí về mục đích. Để mỗi mình, phải không?
Note that you will never reduce your Lumberjack labor force below 0
trong mục danh sách phần gỗ xẻ 3. có lẽ thay đổi điều này thành 1 để phù hợp với những gì bạn đề cập trong phần gấu?