フォレスト-シミュレートされたエコシステム


19

注意

この問題は、このredditスレッド(スポイラーアラート!)から取られたものであり、このサイトのフォーマットに合うように調整しました。すべてのクレジットはredditユーザー「Coder_d00d」に送られます。

この問題では、フォレストをシミュレートします。

このシミュレートされたフォレストでは、3つの側面を扱います。

  • 苗木、ツリー、またはエルダーツリーになりうるツリー。
  • 木こり(彼は木を切り倒し、昼食を食べて、溶岩流に行きます)
  • クマ(彼はパンケーキのような匂いの木こりをひどく傷つける)

警告:これらのルールは、おそらく完全ではありません。それらをガイドラインとして参照し、問題ないものを少し微調整する必要がある場合は(スポーン率が問題として指摘されているので、この例としてkuroi nekoの答えを参照してください。

時間のサイクル:

シミュレーションは月単位でシミュレートされます。あなたは「ティック」に間に合うように前進します。各「目盛り」は月を表します。12個の「ティック」は1年を表します。私たちの森は変化し、常に変化します。森林の進捗状況を記録し、何が起こるかを分析します。

森林:

フォレストは2次元のフォレストになります。N x Nのサイズのグリッドでフォレストのサイズを表すには、Nの入力が必要です。各場所で、ツリー、ベア、またはランバージャックを保持できます。それらは同じ場所を占めることができますが、多くの場合、同じ場所を占めるときにイベントが発生します。

私たちの森は、サイズに基づいてランダムに生成されます。たとえば、N = 10の場合、10 x 10のフォレストと100のスポットがあります。

  • フォレストの10%は、ランダムに10か所で木こりを保持します。(100スポットフォレストを使用すると、これは10本の木こりです)
  • フォレストの50%は、ランダムな場所にツリーを保持します(ツリーは3種類のいずれかであり、「ツリー」の真ん中から始まります)。
  • フォレストの2%がベアを保持します。

フォレストのサイズをどのように受け取るかはあなた次第です(stdin、ファイルから読み取るか、ハードコーディングしてください)。Nを5以上にすることをお勧めします。小さな森はあまり楽しくありません。

イベント:

シミュレーション中にイベントが発生します。イベントは、以下で説明するいくつかのロジックに基づいて発生します。私たちの森の3つの要素の各説明で、以下のイベントを説明します。

イベントは最初に木の順序に従い、次に木こりが続き、最後に熊が続きます。

木:

  • 毎月、ツリーは10%の確率で新しい「苗木」を生成します。ツリーに隣接するランダムな空きスペースでは、10%の確率で「苗木」を作成できます。

  • たとえば、森の真ん中にあるツリーには、周囲に8つのスポットがあります。これらの1つ(空の場合)は「苗木」になります。

  • 存在してから12か月後、「苗木」は「ツリー」にアップグレードされます。「苗木」は、「ツリー」に成熟するまで他のツリーを生成できません。

  • 「苗木」がツリーになると、他の新しい「苗木」を生成できます。

  • 「ツリー」が120か月(10年)使用されていると、「エルダーツリー」になります。

  • エルダーツリーは10%ではなく20%の確率で新しい「苗木」を生成します。

  • ツリーまたはエルダーツリーに隣接するオープンスポットがない場合、新しいツリーは生成されません。

木こり:

木こりは木を切り倒し、スキップしてジャンプして野生の花を押します。

  • 毎月木こりはさまようでしょう。任意の方向に隣接するランダムに選択されたスポットに最大3回移動します。たとえば、グリッドの中央にある木こりには、移動先が8つあります。彼はランダムな場所にさまようでしょう。また。そして最後に三度目です。NB:これはどんな場所でも構いません(彼らはクマに足を踏み入れることができ、結果としてモールになります)。

  • 木こりが動くとき、彼が木(苗木ではない)に出会うと、彼は止まり、その月の放浪は終わります。彼はそれから材木を収穫します。ツリーを削除します。木材を1個獲得します。

  • 木こりは「苗木」を収穫しません。

  • 木こりはエルダーツリーも収穫します。ニワトコの木は2枚の木材の価値があります。

木材追跡:

12か月ごとに、伐採された木材の量は、森の中の木こりの数と比較されます。

  • 収集された材木が森林内の木こりの量と同じかそれを超える場合、多くの新しい木こりが雇われ、森の中にランダムに生成されます。

  • 採用する木こりの数を計算します。 floor(lumber_collected / number_of_lumberjacks)

  • ただし、12か月後に収集された木材の量が木こりの数を下回った場合、木こりはお金を節約するために放され、森から1つのランダムな木こりが取り除かれます。Lumberjackの労働力を0未満に減らすことは決してないことに注意してください。

くま:

クマは木こりのように森をさまよう。ただし、3つのスペースの代わりに、ベアは最大5つのスペースをローミングします。

  • クマが木こりに出くわした場合、彼はその月のさまようことを止めます。(たとえば、2移動後、クマは木こりのあるスペースに着地し、今月はそれ以上移動しません)

  • 木こりはパンケーキのような香りがします。クマはパンケーキが大好きです。したがって、残念ながらクマは木こりを傷つけて傷つけます。木こりは森から取り除かれます(彼は水曜日に家に帰って買い物をし、お茶のためにスコーンをバターで塗ります)。

  • これを「モール」事故として追跡します。

  • 木こりの個体数が1を下回ってはならないことに注意してください。したがって、最後の木こりが傷つけられた場合は、別の木こりが出現します。

モール追跡:

  • 12か月の間に「モール」事故が0回発生すると、クマの数が1増えます。ただし、「モール」事故が発生した場合、木こりは動物園を雇ってクマを捕まえて連れ去ります。ランダムなベアを1つ削除します。クマの個体数が0に達した場合、翌年には「モール」事故が発生しないため、来年は新しいクマが1匹発生することに注意してください。

  • 森に木こりが1匹しかない場合、彼はMauledになりますが、彼は家に送られますが、新しい木こりはすぐに雇われ、森のどこかで再出現します。木こりの個体数が1未満になることはありません。

時間:

シミュレーションは、4800か月(400年)の間、または苗木、樹木、または古木がなくなるまで行われます。

出力:

毎月、森の地図を印刷します-おそらくASCIIマップを使用するか、グラフィックと色を使用します。

オプションのエクストラ

  • 木、木こり、クマの個体数をティックごとに出力できます。
  • イベントが発生するたびに出力できます(例:「クマが木こりを襲った」)。

得点

これは人気コンテストなので、ほとんどの賛成票が勝ちます!

編集-人々は私のルールの多くの欠陥を指摘しており、気軽に私に質問することができますが、あなた自身のプログラムやプログラムの解釈に合うようにルールを少し調整しても大丈夫です。


について:Note that you will never reduce your Lumberjack labor force below 0木こりセクションのリスト項目3で、これを1に変更して、熊セクションで言及した内容と一致するようにしますか?
Teunプロンク

良い点は、今それを編集します。
ジェームズウィリアムズ14

2
動きのタイミングについて議論できますか?それは「木が動く/進む」、「木こりが動く」、「熊が動く」のでしょうか?また、クマと木は同じスペースを占有できますか?
durron597 14

1
2頭のクマが両方とも同じ場所に入った場合はどうなりますか?そして、2つの木こりはどうですか?彼らは同じ場所にいることができますか?
ジェリージェレミア14

1
これはreddit.com/r/dailyprogrammer/comments/27h53e/と同じです...少なくとも他の興味深い解決策を求めてそこに行くことができるように、クレジットを与えるべきです。

回答:


15

Javascript + HTML- 試してみてください

人気のリクエストに従って更新

森とグラフ

一般的な動作

このプログラムはややインタラクティブになりました。
ソースコードは完全にパラメータ化されているため、お気に入りのテキストエディタでさらにいくつかの内部パラメータを調整できます。

フォレストのサイズを変更できます。
木、木こり、熊を3つの異なる場所に配置するのに十分なスペースを確保するには、最低2つ必要です。最大は任意に100に固定されます(平均的なコンピューターのクロールになります)。

シミュレーション速度を変更することもできます。
表示は20ミリ秒ごとに更新されるため、より大きな時間ステップでより細かいアニメーションが生成されます。

ボタンを使用すると、シミュレーションを停止/開始したり、1か月または1年実行したりできます。

森林居住者の動きは今やや活気に満ちています。モールディングと伐採のイベントも計算されます。

一部のイベントのログも表示されます。冗長レベルを変更すると、さらにいくつかのメッセージを使用できますが、「ボブはさらに別のツリーをカットします」という通知であふれます。
私があなただったらやらないほうがいいのですが、そうではありません...

遊び場の横に、自動スケーリングされたグラフィックのセットが描画されます。

  • クマと木こりの個体群
  • 苗木、成熟した木、老木に分けられた木の総数

凡例には、各アイテムの現在の数量も表示されます。

システムの安定性

グラフは、初期条件が適切にスケーリングされないことを示しています。森が広すぎると、パンケーキ愛好家が十分にバーの後ろに置かれるまで、あまりにも多くのクマが木こりの数を減らします。これにより、老木が最初に爆発し、木こりの個体数が回復します。

森林が生き残るための最小サイズは15であると思われます。サイズ10の森林は通常、数百年後に破壊されます。30を超えるサイズでは、ほぼ木でいっぱいのマップが作成されます。15から30の間では、ツリーの人口が大幅に振動していることがわかります。

議論の余地のあるルールポイント

元の投稿のコメントでは、さまざまなBipedが同じ場所を占めることは想定されていないようです。これはどういうわけか、パンケーキのアマチュアにさまよう田舎者に関するルールと矛盾します。
とにかく、私はそのガイドラインに従わなかった。任意のフォレストセルは、任意の数のインヒビタント(および正確にゼロまたは1つのツリー)を保持できます。これは、木こりの効率にいくつかの結果をもたらす可能性があります。私は、木こりをより簡単に古い木の塊に掘り下げることができると思います。クマに関しては、これが大きな違いをもたらすとは思わない。

また、田舎の人口がゼロになる可能性があると述べているにもかかわらず、森林に少なくとも1つの木こりを常に置くことを選択しました絶滅まで切り刻まれた)。

微調整

安定性を実現するために、2つの調整パラメーターを追加しました。

1)木こりの成長率

十分な木材があるときに雇われる余分な木こりの数を与える式に適用される係数。元の定義に戻すには1に設定しますが、約0.5の値を使用すると、フォレスト(特に長老の木)の開発が向上することがわかりました。

2)クマの除去基準

動物園にクマを送るための木こりの最小パーセンテージを定義する係数。元の定義に戻るには0に設定しますが、この抜本的な熊の排除は、基本的に人口を0-1の振動サイクルに制限します。.15に設定しました(つまり、今年木こりの15%以上が傷つけられた場合にのみ熊が取り除かれます)。これにより、中程度の熊の個体群が可能になり、田舎者がその地域をきれいに拭くのを防ぐのに十分ですが、森のかなりの部分を切り刻むことができます。

補足として、シミュレーションは停止しません(必要な400年を過ぎても)。簡単にできますが、できません。

コード

コードは完全に単一のHTMLページに含まれています。
これは、UTF-8エンコードされている必要があり熊や木こりのための適切なUnicodeの記号を表示します。

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+"&nbsp;";
        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は$よりも読みやすいため、jQueryismの欠如について文句を言う必要はありません。意図的にjQueryは無料です。各自に、そうですか?


+1、これはお粗末に見える、私はインタラクティブ性を見たいです!
ウィリアムバルボサ14

クマと木こりが見えません。それらを見るにはどうすればいいですか?ところで、1年に最大1つのクマだけを削除する必要がありますか?
ちょうど半分14

@WilliamBarbosaヴォックス人口が十分に大声で叫ぶ場合、それは私をいくつか追加するように

@justhalfは、ユニコード文字に関する私の編集を参照してください。クマについては、スペックを正しく理解していれば、はい:何らかの怪我が起こった場合、毎年1匹のクマだけがランダムに動物園に送られます。

1
成長している木は素晴らしいです。よくやった!
ブラックホール14

14

AngularJS

ここに私のバージョンがありますが、それはまだ進行中の作業です。コードは少し…まあ……いです。そしてかなり遅い。また、進化をパラメータ化し、森林の状態を分析するためのオプションを追加する予定です。コメントと改善提案を歓迎します!

森のスクリーンショット

デモンストレーション

<div ng-app="ForestApp" ng-controller="ForestController">
    <form name="parametersForm" ng-hide="evolutionInProgress" autocomplete="off" novalidate>
        <div class="line">
            <label for="forestSize">Size of the forest:</label>
            <input type="number" ng-model="Parameters.forestSize" id="forestSize" min="5" ng-pattern="/^[0-9]+$/" required />
        </div>
        <div class="line">
            <label for="simulationInterval">Number of milliseconds between each tick</label>
            <input type="number" ng-model="Parameters.simulationInterval" id="simulationInterval" min="10" ng-pattern="/^[0-9]+$/" required />
        </div>
        <div class="line">
            <label for="animationsEnabled">Animations enabled?
                <br /><small>(>= 300 ms between each tick is advisable)</small>

            </label>
            <input type="checkbox" ng-model="Parameters.animationsEnabled" id="animationsEnabled" />
        </div>
        <div class="line">
            <button ng-disabled="parametersForm.$invalid || evolutionInProgress" ng-click="launchEvolution()">Launch the evolution!</button>
        </div>
    </form>
    <div id="forest" ng-style="{width: side = (20*Parameters.forestSize) + 'px', height: side, 'transition-duration': transitionDuration = (Parameters.animationsEnabled ? 0.8*Parameters.simulationInterval : 0) + 'ms', '-webkit-transition-duration': transitionDuration}">
        <div ng-repeat="bear in Forest.bearsList" class="entity entity--bear" ng-style="{left: (20*bear.x) + 'px', top: (20*bear.y) + 'px'}"></div>
        <div ng-repeat="lumberjack in Forest.lumberjacksList" class="entity entity--lumberjack" ng-style="{left: (20*lumberjack.x) + 'px', top: (20*lumberjack.y) + 'px'}"></div>
        <div ng-repeat="tree in Forest.treesList" class="entity entity--tree" ng-class="'entity--tree--' + tree.stage" ng-style="{left: (20*tree.x) + 'px', top: (20*tree.y) + 'px'}"></div>
    </div>
    <div class="line"><em>Age of the forest:</em><samp>{{floor(Forest.age/12)}} year{{floor(Forest.age/12) > 1 ? 's' : ''}} and {{Forest.age%12}} month{{Forest.age%12 > 1 ? 's' : ''}}</samp></div>
    <div class="line"><em>Number of bears:</em><samp>{{Forest.bearsList.length}}</samp></div>
    <div class="line"><em>Number of lumberjacks:</em><samp>{{Forest.lumberjacksList.length}}</samp></div>
    <br />
    <div class="line"><em>Number of lumbers collected:</em><samp>{{Forest.numberOfLumbers}}</samp></div>
    <div class="line"><em>Number of mauls:</em><samp>{{Forest.numberOfMauls}}</samp></div>
</div>
/** @link http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array */
function shuffle(array) {
    var currentIndex = array.length,
        temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

var forestApp = angular.module('ForestApp', ['ngAnimate']);

forestApp.value('Parameters', {
    /** @var int[] Maximal number of moves by species */
    speed: {
        bear: 5,
        lumberjack: 3,
    },

    /** @var int[] Initial percentage of each species in the forest */
    initialPercentage: {
        bear: 2,
        lumberjack: 10,
        tree: 50,
    },

    /** @var int[] Spawing rate, in percentage, of new saplings around an existing tree */
    spawningPercentage: {
        0: 0,
        1: 10,
        2: 20,
    },

    /** @var int[] Age of growth for an existing tree */
    ageOfGrowth: {
        sapling: 12,
        tree: 120,
    },

    /** @var int[] Lumber collected on an existing tree */
    numberOfLumbers: {
        tree: 1,
        elderTree: 2,
    },

    /** @var int Size of each side of the forest */
    forestSize: 20,

    /** @var int Number of milliseconds between each tick (month in the forest) */
    simulationInterval: 50,
});

forestApp.constant('TREE_STAGE', {
    SAPLING: 0,
    TREE: 1,
    ELDER_TREE: 2,
});

forestApp.factory('Tree', ['Forest', 'Parameters', 'TREE_STAGE', function (Forest, Parameters, TREE_STAGE) {
    // Classes which represents a tree
    var Tree = function (stage, x, y) {
        /** @var TREE_STAGE Current stage of the tree */
        this.stage = stage;

        /** @var int Current age of the tree, in month */
        this.age = 0;

        /** @var int X coordinates of the tree */
        this.x = x;

        /** @var int Y coordinates of the tree */
        this.y = y;

        this.tick = function () {
            if (Math.random() < Parameters.spawningPercentage[this.stage] / 100) {
                var freePositionsList = shuffle(Forest.getFreePositionsAround(this.x, this.y));
                if (freePositionsList.length > 0) {
                    var saplingPosition = freePositionsList[0];

                    Tree.create(TREE_STAGE.SAPLING, saplingPosition[0], saplingPosition[1]);
                }
            }

            ++this.age;

            if (this.stage === TREE_STAGE.SAPLING && this.age == Parameters.ageOfGrowth.sapling) {
                this.stage = TREE_STAGE.TREE;
            } else if (this.stage === TREE_STAGE.TREE && this.age == Parameters.ageOfGrowth.tree) {
                this.stage = TREE_STAGE.ELDER_TREE;
            }
        };

        /**
         * Remove the entity
         */
        this.remove = function () {
            var index = Forest.treesList.indexOf(this);
            Forest.treesList.splice(index, 1);
        };
    };

    Tree.create = function (stage, x, y) {
        Forest.add.tree(new Tree(stage, x, y));
    };

    return Tree;
}]);

forestApp.factory('Lumberjack', ['Forest', 'Parameters', 'TREE_STAGE', function (Forest, Parameters, TREE_STAGE) {
    // Classes which represents a lumberjack
    var Lumberjack = function (x, y) {
        /** @var int X coordinates of the lumberjack */
        this.x = x;

        /** @var int Y coordinates of the lumberjack */
        this.y = y;

        this.tick = function () {
            for (movement = Parameters.speed.lumberjack; movement > 0; --movement) {
                var positionsList = shuffle(Forest.getPositionsAround(this.x, this.y));
                var newPosition = positionsList[0];
                this.x = newPosition[0];
                this.y = newPosition[1];

                var tree = Forest.getTreeAt(this.x, this.y);
                if (tree !== null) {
                    if (tree.stage === TREE_STAGE.SAPLING) {
                        return;
                    } else if (tree.stage === TREE_STAGE.TREE) {
                        Forest.numberOfLumbers += Parameters.numberOfLumbers.tree;
                    } else {
                        Forest.numberOfLumbers += Parameters.numberOfLumbers.elderTree;
                    }

                    tree.remove();
                    movement = 0;
                };
            }
        };

        /**
         * Remove the entity
         */
        this.remove = function () {
            if (Forest.lumberjacksList.length === 1) {
                this.x = Math.floor(Math.random() * Parameters.forestSize);
                this.y = Math.floor(Math.random() * Parameters.forestSize);
            } else {
                var index = Forest.lumberjacksList.indexOf(this);
                Forest.lumberjacksList.splice(index, 1);
            }
        };
    };

    Lumberjack.create = function (x, y) {
        Forest.add.lumberjack(new Lumberjack(x, y));
    };

    return Lumberjack;
}]);

forestApp.factory('Bear', ['Forest', 'Parameters', function (Forest, Parameters) {
    // Classes which represents a bear
    var Bear = function (x, y) {
        /** @var int X coordinates of the bear */
        this.x = x;

        /** @var int Y coordinates of the bear */
        this.y = y;

        this.tick = function () {
            for (movement = Parameters.speed.bear; movement > 0; --movement) {
                var positionsList = shuffle(Forest.getPositionsAround(this.x, this.y));
                var newPosition = positionsList[0];
                this.x = newPosition[0];
                this.y = newPosition[1];

                angular.forEach(Forest.getLumberjacksListAt(this.x, this.y), function (lumberjack) {
                    lumberjack.remove();
                    ++Forest.numberOfMauls;
                    movement = 0;
                });
            }
        };

        /**
         * Remove the entity
         */
        this.remove = function () {
            var index = Forest.bearsList.indexOf(this);
            Forest.bearsList.splice(index, 1);
        };
    };

    Bear.create = function (x, y) {
        Forest.add.bear(new Bear(x, y));
    };

    return Bear;
}]);

forestApp.service('Forest', ['Parameters', function (Parameters) {
    var forest = this;

    this.age = 0;
    this.numberOfLumbers = 0;
    this.numberOfMauls = 0;

    this.bearsList = [];
    this.lumberjacksList = [];
    this.treesList = [];

    this.getEntitiesList = function () {
        return forest.bearsList.concat(forest.lumberjacksList, forest.treesList);
    };

    /**
     * Age the forest by one month
     */
    this.tick = function () {
        angular.forEach(forest.getEntitiesList(), function (entity) {
            entity.tick();
        });

        ++forest.age;
    };

    this.add = {
        bear: function (bear) {
            forest.bearsList.push(bear);
        },
        lumberjack: function (lumberjack) {
            forest.lumberjacksList.push(lumberjack);
        },
        tree: function (tree) {
            forest.treesList.push(tree);
        },
    };

    /**
     * @return Tree|null Tree at this position, or NULL if there is no tree.
     */
    this.getTreeAt = function (x, y) {
        var numberOfTrees = forest.treesList.length;
        for (treeId = 0; treeId < numberOfTrees; ++treeId) {
            var tree = forest.treesList[treeId];
            if (tree.x === x && tree.y === y) {
                return tree;
            }
        }

        return null;
    };

    /**
     * @return Lumberjack[] List of the lumberjacks at this position
     */
    this.getLumberjacksListAt = function (x, y) {
        var lumberjacksList = [];
        angular.forEach(forest.lumberjacksList, function (lumberjack) {
            if (lumberjack.x === x && lumberjack.y === y) {
                lumberjacksList.push(lumberjack);
            }
        });

        return lumberjacksList;
    };

    /**
     * @return int[] Positions around this position
     */
    this.getPositionsAround = function (x, y) {
        var positionsList = [
            [x - 1, y - 1],
            [x, y - 1],
            [x + 1, y - 1],
            [x - 1, y],
            [x + 1, y],
            [x - 1, y + 1],
            [x, y + 1],
            [x + 1, y + 1]
        ];

        return positionsList.filter(function (position) {
            return (position[0] >= 0 && position[1] >= 0 && position[0] < Parameters.forestSize && position[1] < Parameters.forestSize);
        });
    };

    /**
     * @return int[] Positions without tree around this position
     */
    this.getFreePositionsAround = function (x, y) {
        var positionsList = forest.getPositionsAround(x, y);

        return positionsList.filter(function (position) {
            return forest.getTreeAt(position[0], position[1]) === null;
        });
    };
}]);

forestApp.controller('ForestController', ['$interval', '$scope', 'Bear', 'Forest', 'Lumberjack', 'Parameters', 'Tree', 'TREE_STAGE', function ($interval, $scope, Bear, Forest, Lumberjack, Parameters, Tree, TREE_STAGE) {
    $scope.Forest = Forest;
    $scope.Parameters = Parameters;
    $scope.evolutionInProgress = false;
    $scope.floor = Math.floor;

    var positionsList = [];

    /**
     * Start the evolution of the forest
     */
    $scope.launchEvolution = function () {
        $scope.evolutionInProgress = true;

        for (var x = 0; x < Parameters.forestSize; ++x) {
            for (var y = 0; y < Parameters.forestSize; ++y) {
                positionsList.push([x, y]);
            }
        }

        shuffle(positionsList);
        var numberOfBears = Parameters.initialPercentage.bear * Math.pow(Parameters.forestSize, 2) / 100;
        for (var bearId = 0; bearId < numberOfBears; ++bearId) {
            Bear.create(positionsList[bearId][0], positionsList[bearId][1]);
        }

        shuffle(positionsList);
        var numberOfLumberjacks = Parameters.initialPercentage.lumberjack * Math.pow(Parameters.forestSize, 2) / 100;
        for (var lumberjackId = 0; lumberjackId < numberOfLumberjacks; ++lumberjackId) {
            Lumberjack.create(positionsList[lumberjackId][0], positionsList[lumberjackId][1]);
        }

        shuffle(positionsList);
        var numberOfTrees = Parameters.initialPercentage.tree * Math.pow(Parameters.forestSize, 2) / 100;
        for (var treeId = 0; treeId < numberOfTrees; ++treeId) {
            Tree.create(TREE_STAGE.TREE, positionsList[treeId][0], positionsList[treeId][1]);
        }

        $interval(function () {
            Forest.tick();

            if (Forest.age % 12 === 0) {
                // Hire or fire lumberjacks
                if (Forest.numberOfLumbers >= Forest.lumberjacksList.length) {
                    shuffle(positionsList);
                    var numberOfLumberjacks = Math.floor(Forest.numberOfLumbers / Forest.lumberjacksList.length);
                    for (var lumberjackId = 0; lumberjackId < numberOfLumberjacks; ++lumberjackId) {
                        Lumberjack.create(positionsList[lumberjackId][0], positionsList[lumberjackId][1]);
                    }
                } else {
                    shuffle(Forest.lumberjacksList);
                    Forest.lumberjacksList[0].remove();
                }

                // Hire or fire bears
                if (Forest.numberOfMauls === 0) {
                    shuffle(positionsList);
                    Bear.create(positionsList[0][0], positionsList[0][1]);
                } else {
                    Forest.bearsList[0].remove();
                }

                Forest.numberOfLumbers = 0;
                Forest.numberOfMauls = 0;
            }

        }, Parameters.simulationInterval);
    };
}]);

1
また、シャッフル配列をランダム化するために同じコードを使用する方法が好きです
ケビンL 14

面白い。初めてシミュレーションを実行したとき、すべてのクマと木こりで終わったため、このシミュレーションは不均衡だと思いました。しかし、私はそれが(非常に多くのクマがある場合は、木こりはほぼ確実に死んでしまうので)すべての木こりがクマによって切り裂かてしまったことを、単に「不運」だったと思いますので、その後再び起こることはありません
justhalf

getEntitiesAtCPU独り占めのようです!50x50グリッドでシステムを実行すると、PCで1か月に1秒以上かかります。また、すべての木が切り刻まれ、すべての木こりが解雇され、マップがゆっくりとクマでいっぱいになる場合があります:)。小さいサイズ(10以下)で試してみてください。

@kuroineko:それは、木こりが傷ついた後、クマで復活した場合、そこにいないバグ(または実装されていないルール)があるためです。そのため、0 になります。Forest.tick()、if Forest.lumberjackList.length == 0、thenの後にチェックして修正しLumberjack.create(<number>, <number>)ます。
ちょうど半分14

1
クマが森にとどまることを好むようにコードを微調整してみました(そして、@ kuroinekoのようなクマの除去基準を組み込みます。 )。振る舞いがどのように変化するかを見るのは興味深いです=)
ちょうど半分14

3

Javascript

これはほとんど機能すると思います。挿入の遅延が原因で、すべての新しいクマ/木こりを同期して互いに隣り合わせでスポーンするという奇妙な動作があります。

この実装では、木こりが苗木の上に立つことはできません。苗木を踏みつけるのは悪いことです。フィドルアートはデフォルトで色付きの長方形を使用しますが、2行目をfalseに変更して文字を使用して描画します。

フィドル

HTML:

<canvas id="c" width="1" height="1"></canvas>
<div id="p1"></div>
<div id="p2"></div>
<div id="p3"></div>
<div id="p4"></div>

Js:

var n = 10; // Size of the grid
var drawUsingColor = true; // If true, draws colors for each entity instead :D
var intervalTime = 1000; // how often each tick happens, in milliseconds
var jackRatio = 0.1;
var treeRatio = 0.5;
var bearRatio = 0.02;
var size = 48; // Pixels allocated (in size x size) for each entity
var font = "30px Lucida Console"; // if drawUsingColor is false

var bearColor = '#8B4513'; // Saddlebrown
var elderColor = '#556B2F'; // DarkOliveGreen
var lumberjackColor = '#B22222'; // Firebrick
var treeColor = '#008000'; // Green
var saplingColor = '#ADFF2F'; // GreenYellow

// Game rules:
var spawnSaplingChance = 0.1;
var elderTreeAge = 120;
var elderSaplingChance = 0.2;
var treeAge = 12;
var lumberjackRange = 3;
var bearRange = 5;
var zooPeriod = 12; // If a maul happens within this period
var lumberPeriod = 12; // New lumberjacks hired in this period


var time = 1;

var world;
var n2 = n * n; //because one saved keystroke
var zooqueue = [];
var lumberqueue = [];
var canvas = document.getElementById('c'); // Needs more jquery
var context = canvas.getContext('2d');
context.font = font;

// various statistics
var treesAlive = 0;
var jacksAlive = 0;
var bearsAlive = 0;
var currentLumber = 0;
var lumberjacksMauled = 0;
var recentEvents = '';

// Entity is a bear, eldertree, lumberjack, tree, sapling, with age. aka belts.
function Entity(belts, birthday) {
    this.type = belts;
    this.age = 0;
    this.birthday = birthday;
}

function initWorld() {
    canvas.height = size * n;
    canvas.width = size * n;
    world = new Array(n2);

    // One pass spawning algorithm: numEntity = number of entity left to spawn
    // If rand() in range [0,numtrees), spawn tree
    // if rand() in range [numtrees, numtrees+numjacks), spawn lumberjack
    // if rand() in range [numtrees+numjacks, numtrees+numjacks+numbears), spawn bear

    var numTrees = treeRatio * n2;
    var numJacks = jackRatio * n2;
    var numBears = bearRatio * n2;

    var godseed = new Array(n2);
    for (var i = 0; i < n2; i++) {
        godseed[i] = i;
    }
    shuffle(godseed);

    for (var i = 0; i < n2; i++) {
        var god = godseed.pop();
        if (god < numTrees) {
            world[i] = new Entity('T', 0);
            treesAlive++;
        } else if (god < numTrees + numJacks) {
            world[i] = new Entity('L', 0);
            jacksAlive++;
        } else if (god < numTrees + numJacks + numBears) {
            world[i] = new Entity('B', 0);
            bearsAlive++;
        }
        // console.log(world, i);
    }

    // populate zoo array, lumber array
    for (var i = 0; i < zooPeriod; i++) {
        zooqueue.push(0);
    }

    for (var i = 0; i < lumberPeriod; i++) {
        lumberqueue.push(0);
    }
}

animateWorld = function () {
    recentEvents = '';
    computeWorld();
    drawWorld();
    time++;

    $('#p1').text(treesAlive + ' trees alive');
    $('#p2').text(bearsAlive + ' bears alive');
    $('#p3').text(jacksAlive + ' lumberjacks alive');
    $('#p4').text(recentEvents);
};

function computeWorld() {
    zooqueue.push(lumberjacksMauled);
    lumberqueue.push(currentLumber);

    // Calculate entity positions
    for (var i = 0; i < n2; i++) {
        if (world[i]) {
            switch (world[i].type) {
                case 'B':
                    bearStuff(i);
                    break;
                case 'E':
                    elderStuff(i);
                    break;
                case 'L':
                    lumberjackStuff(i);
                    break;
                case 'T':
                    treeStuff(i);
                    break;
                case 'S':
                    saplingStuff(i);
                    break;
            }
        }
    }

    // Pop the # mauls from zooPeriod's ago, if lumberjacksMauled > oldmauls, then someone was eaten.
    var oldmauls = zooqueue.shift();
    if (time % zooPeriod === 0) {
        if (lumberjacksMauled > oldmauls) {
            if (remove('B') == 1) {
                bearsAlive--;
                recentEvents += 'Bear sent to zoo! ';
            }
        } else {
            bearsAlive++;
            spawn('B');
            recentEvents += 'New bear appeared! ';
        }
    }

    var oldLumber = lumberqueue.shift();
    if (time % lumberPeriod === 0) {
        // # lumberjack to hire
        var hire = Math.floor((currentLumber - oldLumber) / jacksAlive);
        if (hire > 0) {
            recentEvents += 'Lumber jack hired! (' + hire + ') ';
            while (hire > 0) {
                jacksAlive++;
                spawn('L');
                hire--;
            }
        } else {
            if (remove('L') == 1) {
                recentEvents += 'Lumber jack fired!  ';
                jacksAlive--;
            }
            else {
            }
        }
    }

    // Ensure > 1 lumberjack
    if (jacksAlive === 0) {
        jacksAlive++;
        spawn('L');
        recentEvent += 'Lumberjack spontaneously appeared';
    }
}

// Not the job of spawn/remove to keep track of whatever was spawned/removed
function spawn(type) {
    var index = findEmpty(type);
    if (index != -1) {
        world[index] = new Entity(type, time);
    }
    // recentEvents += 'Spawned a ' + type + '\n';
}

function remove(type) {
    var index = findByType(type);
    if (index != -1) {
        world[index] = null;
        return 1;
    }
    return -1;
    // recentEvents += 'Removed a ' + type + '\n';
}

// Searches in world for an entity with type=type. Currently implemented as
// linear scan, which isn't very random
function findByType(type) {
    for (var i = 0; i < n2; i++) {
        if (world[i] && world[i].type == type) return i;
    }
    return -1;
}

// Also linear scan 
function findEmpty(type) {
    for (var i = 0; i < n2; i++) {
        if (!world[i]) {
            return i;
        }
    }
    return -1;
}

function bearStuff(index) {
    if (world[index].birthday == time) {
        return;
    }

    // Wander around
    var tindex = index;
    for (var i = 0; i < lumberjackRange; i++) {
        var neighbors = get8Neighbor(tindex);

        var mov = neighbors[Math.floor(Math.random() * neighbors.length)];
        if (world[mov] && world[mov].type == 'L') {
            recentEvents += 'Bear (' + index % 10 + ',' + Math.floor(index / 10) + ') mauled a Lumberjack (' + mov % 10 + ',' + Math.floor(mov / 10) + ') !';
            lumberjacksMauled++;
            jacksAlive--;
            world[mov] = new Entity('B', time);
            world[mov].age = ++world[index].age;
            world[index] = null;
            return;
        }
        tindex = mov;
    }

    if (!world[tindex]) {
        world[tindex] = new Entity('B', time);
        world[tindex].age = ++world[index].age;
        world[index] = null;
    }
}

function elderStuff(index) {
    if (world[index].birthday == time) {
        return;
    }
    neighbors = get8Neighbor(index);

    // spawn saplings
    for (var i = 0; i < neighbors.length; i++) {
        if (!world[neighbors[i]]) {
            if (Math.random() < elderSaplingChance) {
                world[neighbors[i]] = new Entity('S', time);
                treesAlive++;
            }
        }
    }

    // become older
    world[index].age++;
}

function lumberjackStuff(index) {
    if (world[index].birthday == time) {
        return;
    }

    // Wander around
    var tindex = index;
    for (var i = 0; i < lumberjackRange; i++) {
        var neighbors = get8Neighbor(tindex);

        var mov = neighbors[Math.floor(Math.random() * neighbors.length)];
        if (world[mov] && (world[mov].type == 'T' || world[mov].type == 'E')) {
            world[mov].type == 'T' ? currentLumber++ : currentLumber += 2;
            treesAlive--;
            world[mov] = new Entity('L', time);
            world[mov].age = ++world[index].age;
            world[index] = null;
            return;
        }
        tindex = mov;
    }

    if (!world[tindex]) {
        world[tindex] = new Entity('L', time);
        world[tindex].age = ++world[index].age;
        world[index] = null;
    }
}

function treeStuff(index) {
    if (world[index].birthday == time) {
        return;
    }
    neighbors = get8Neighbor(index);

    // spawn saplings
    for (var i = 0; i < neighbors.length; i++) {
        if (!world[neighbors[i]]) {
            if (Math.random() < spawnSaplingChance) {
                world[neighbors[i]] = new Entity('S', time);
                treesAlive++;
            }
        }
    }

    // promote to elder tree?
    if (world[index].age >= elderTreeAge) {
        world[index] = new Entity('E', time);
        return;
    }

    // become older
    world[index].age++;
}

function saplingStuff(index) {
    if (world[index].birthday == time) {
        return;
    }

    // promote to tree?
    if (world[index].age > treeAge) {
        world[index] = new Entity('T', time);
        return;
    }
    world[index].age++;
}

// Returns array containing up to 8 valid neighbors.
// Prolly gonna break for n < 3 but oh well
function get8Neighbor(index) {
    neighbors = [];

    if (index % n != 0) {
        neighbors.push(index - n - 1);
        neighbors.push(index - 1);
        neighbors.push(index + n - 1);
    }
    if (index % n != n - 1) {
        neighbors.push(index - n + 1);
        neighbors.push(index + 1);
        neighbors.push(index + n + 1);
    }
    neighbors.push(index - n);
    neighbors.push(index + n);
    return neighbors.filter(function (val, ind, arr) {
        return (0 <= val && val < n2)
    });
}

// Each entity allocated 5x5px for their art
function drawWorld() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    for (var i = 0; i < n2; i++) {
        if (world[i]) {
            var x = i % n;
            var y = Math.floor(i / n);
            switch (world[i].type) {
                case 'B':
                    drawBear(x, y);
                    break;
                case 'E':
                    drawElder(x, y);
                    break;
                case 'L':
                    drawJack(x, y);
                    break;
                case 'T':
                    drawTree(x, y);
                    break;
                case 'S':
                    drawSapling(x, y);
                    break;
            }
        }
    }
}

function drawBear(x, y) {
    if (drawUsingColor) {
        drawRect(x * size, y * size, size, size, bearColor);
    } else {
        drawLetter(x * size, y * size, 'B');
    }
}

function drawElder(x, y) {
    if (drawUsingColor) {
        drawRect(x * size, y * size, size, size, elderColor);
    } else {
        drawLetter(x * size, y * size, 'E');
    }
}

function drawJack(x, y) {
    if (drawUsingColor) {
        drawRect(x * size, y * size, size, size, lumberjackColor);
    } else {
        drawLetter(x * size, y * size, 'J');
    }
}

function drawTree(x, y) {
    if (drawUsingColor) {
        drawRect(x * size, y * size, size, size, treeColor);
    } else {
        drawLetter(x * size, y * size, 'T');
    }
}

function drawSapling(x, y) {
    if (drawUsingColor) {
        drawRect(x * size, y * size, size, size, saplingColor);
    } else {
        drawLetter(x * size, y * size, 'S');
    }
}

function drawLine(x1, y1, x2, y2, c) {
    context.beginPath();
    context.moveTo(x1, y1);
    context.lineTo(x2, y2);
    context.lineWidth = 3;
    context.strokeStyle = c;
    context.stroke();
}

function drawRect(x, y, w, h, c) {
    context.fillStyle = c;
    context.fillRect(x, y, w, h);
}

function drawLetter(x, y, l) {
    context.fillText(l, x, y);
}

$(document).ready(function () {
    initWorld();
    intervalID = window.setInterval(animateWorld, intervalTime);
    /*$('#s').click(function() {
        animateWorld();
    })*/
});

// http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
function shuffle(array) {
    var currentIndex = array.length,
        temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element. 
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }
    return array;
}

大規模なフォレストには奇妙なものがありn = 50ます(たとえば、try )。
ブラックホール14

@Blackhole strange strange = ____?
ケビンL 14


私はクマが立ち往生し、森は、地図の上部にI以来、マップの下の部分の上に産卵木こりを取って気づく
ケビン・Lを

1
新しいクマと木こりの産卵方法に問題があります。そのすべてを左上隅に置くと、システムのグローバルバランスがかなり変化すると思います。

3

Python

派手なものは何もありません。私はものを追加し続けたので、リファクタリングが適切かもしれません。(そして、私は団結しなかったので、バグがまだ存在するかもしれません)。

木こりと熊にランダムな名前を付けました。木はi、それIから#、木こりはx、熊はo

import os

from random import randint, choice, shuffle
from time import sleep

NGRID = 15
SLEEPTIME = 0.0125
DURATION = 4800
VERBOSE = True

###init
grid = [[[] for _ in range(NGRID)] for _ in range(NGRID)]
#Money earned this year
n_lumbers = 0
#Lumberjacks killed this year
n_maul = 0

tick = 0
events = []
#total number of
d_total = {'trees':0,
           'lumberjacks': 0,
           'bears': 0,
           'cut': 0,
           'maul': 0,
           'capture': 0,
           'lumbers': 0,
           'fired': 0}

d_oldest = {'tree': 0,
            'lumberjack': (0, ""),
            'bear': (0, "")}

d_most = {'n_maul': (0, ""),
          'n_lumber': (0, ""),
          'n_cut': (0, "")}

d_year = {'n_maul': 0,
          'n_lumber': 0}

###Classes
class Tree(object):
    """Represent a Sapling, Tree, or Elder Tree"""
    def __init__(self, coords, m=0, t='Sapling'):
        self.months = m
        self.typeof = t
        self.coords = coords
    def grow(self, m=1):
        """the tree grows 1 month and its type might change"""
        self.months = self.months + m
        if self.months == 12:
            self.typeof = 'Tree'
        elif self.months == 480:
            self.typeof = 'Elder Tree'
    def __str__(self):
        if self.typeof == 'Sapling':
            return 'i'
        elif self.typeof == 'Tree':
            return 'I'
        else:
            return '#'

class Animated(object):
    """Animated beings can move"""
    def __init__(self, coords):
        self.coords = coords
        self.old_coords = None
        self.months = 0
    def where(self):
        return c_neighbors(self.coords)
    def choose_new_coords(self):
        self.old_coords = self.coords
        possible = self.where()
        if possible:
            direction = choice(self.where())
            self.coords = [(self.coords[i]+direction[i]) % NGRID for i in range(2)]
#    def __del__(self):
#        print "died at "+ str(self.coords)


class Lumberjack(Animated):
    """Lumberjacks chop down trees"""
    def __init__(self, coords):
        super(Lumberjack, self).__init__(coords)
        self.nb_cut = 0
        self.nb_lumber = 0
        self.name = gen_name("l")
    def __str__(self):
        return "x"

class Bear(Animated):
    """Bears maul"""
    def __init__(self, coords):
        super(Bear, self).__init__(coords)
        self.nb_maul = 0
        self.name = gen_name("b")
    def where(self):
        return c_land_neighbors(self.coords)
    def __str__(self):
        return "o"

###list of coords
def c_neighbors(coords):
    """returns the list of coordinates of adjacent cells"""
    return [[(coords[0] + i) % NGRID, (coords[1] + j) % NGRID] \
            for i in [-1, 0, 1] \
            for j in [-1, 0, 1] \
            if (i,j) != (0, 0)]

def c_empty_neighbors(coords):
    """returns the list of coordinates of adjacent cells that are empty """
    return [[i, j] for [i,j] in c_neighbors(coords) if grid[i][j] == []]

def c_land_neighbors(coords):
    """returns the list of coordinates of adjacent cells that contain not Trees
    for bears"""
    return [[i, j] for [i,j] in c_neighbors(coords)\
            if (grid[i][j] == []) or (not isinstance(grid[i][j][0], Tree))]

def c_empty_cells():
    """returns list of coords of empty cells in the grid"""
    return [[i, j] for i in range(NGRID) for j in range(NGRID) if grid[i][j] == []]

def c_not_bear_cells():
    """returns list of coords of cells without bear"""
    return [[i, j] for i in range(NGRID) for j in range(NGRID) \
            if not isinstance(grid[i][j], Bear)]

###one less
def maul(lumberjack):
    """a lumberjack will die"""
    global n_maul
    n_maul = n_maul + 1
    d_total['maul'] = d_total['maul'] + 1
    remove_from_grid(lumberjack.coords, lumberjack)
    return lumberjack.name + " is sent to hospital" + check_lumberjacks()

def capture_bear():
    """too many mauls, a Zoo traps a bear"""
    d_total['capture'] = d_total['capture'] + 1
    bear = choice(get_bears())
    remove_from_grid(bear.coords, bear)
    return bear.name + " has been captured"

def fire_lumberjack():
    """the job is not done correctly, one lumberjack is let go"""
    d_total['fired'] = d_total['fired'] + 1
    lumberjack = choice(get_lumberjacks())
    remove_from_grid(lumberjack.coords, lumberjack)
    return lumberjack.name + " has been fired" + check_lumberjacks()

def remove_from_grid(coords, item):
    """remove item from the grid at the coords"""
    grid[coords[0]][coords[1]].remove(item)
    del item

###one more
def new_animate(class_):
    """a new lumberjack or bear joins the forest"""
    if class_==Bear:
        d_total['bears'] = d_total['bears'] + 1
        x, y = choice(c_empty_cells())
    else:
        d_total['lumberjacks'] = d_total['lumberjacks'] + 1
        x, y = choice(c_not_bear_cells())
    new_being = class_([x,y])
    grid[x][y].append(new_being)
    return "a new " + class_.__name__ + " enters the forest: " + new_being.name

def check_lumberjacks():
    """we will never reduce our Lumberjack labor force below 0"""
    if len(get_lumberjacks())==0:
        return " - no more lumberjack, " + new_animate(Lumberjack)
    return ""

###movements
def move_on_grid(being):
    [x, y] = being.old_coords
    grid[x][y].remove(being)
    [x, y] = being.coords
    grid[x][y].append(being)

def move_lumberjack(lumberjack):
    """Lumberjacks move 3 times if they don't encounter a (Elder) Tree or a Bear"""
    global n_lumbers
    for _ in range(3):
        lumberjack.choose_new_coords()
        move_on_grid(lumberjack)
        [x, y] = lumberjack.coords
        #is there something at the new coordinate?
        #move append so this lumberjack is at the end
        if grid[x][y][:-1] != []:
            if isinstance(grid[x][y][0], Tree):
                the_tree = grid[x][y][0]
                price = worth(the_tree)
                if price > 0:
                    lumberjack.nb_cut = lumberjack.nb_cut + 1
                    d_most['n_cut'] = max((lumberjack.nb_cut, lumberjack.name), \
                                           d_most['n_cut'])
                    d_total['cut'] = d_total['cut'] + 1
                    n_lumbers = n_lumbers + price
                    d_total['lumbers'] = d_total['lumbers'] + 1
                    lumberjack.nb_lumber = lumberjack.nb_lumber + price
                    d_most['n_lumber'] = max(d_most['n_lumber'], \
                                             (lumberjack.nb_lumber, lumberjack.name))
                    remove_from_grid([x, y], the_tree)
                    return lumberjack.name + " cuts 1 " + the_tree.typeof
            #if there is a bear, all lumberjacks have been sent to hospital
            if isinstance(grid[x][y][0], Bear):
                #the first bear is the killer
                b = grid[x][y][0]
                b.nb_maul = b.nb_maul + 1
                d_most['n_maul'] = max((b.nb_maul, b.name), d_most['n_maul'])
                return maul(lumberjack)
    return None

def move_bear(bear):
    """Bears move 5 times if they don't encounter a Lumberjack"""
    for _ in range(5):
        bear.choose_new_coords()
        move_on_grid(bear)
        [x, y] = bear.coords
        there_was_something = (grid[x][y][:-1] != [])
        if there_was_something:
            #bears wander where there is no tree
            #so it's either a lumberjack or another bear
            #can't be both.
            if isinstance(grid[x][y][0], Lumberjack):
                bear.nb_maul = bear.nb_maul + 1
                d_most['n_maul'] = max((bear.nb_maul, bear.name), \
                                       d_most['n_maul'])
                return maul(grid[x][y][0])
    return None

###get objects
def get_objects(class_):
    """get a list of instances in the grid"""
    l = []
    for i in range(NGRID):
        for j in range(NGRID):
          if grid[i][j]:
              for k in grid[i][j]:
                  if isinstance(k, class_):
                      l.append(k)
    return l

def get_trees():
    """list of trees"""
    return get_objects(Tree)

def get_bears():
    """list of bears"""
    return get_objects(Bear)

def get_lumberjacks():
    """list of lumberjacks"""
    return get_objects(Lumberjack)

###utils
def gen_name(which="l"):
    """generate random name"""
    name = ""
    for _ in range(randint(1,4)):
        name = name + choice("bcdfghjklmnprstvwxz") + choice("auiey")
    if which == "b":
        name = name[::-1]
    return name.capitalize()

def worth(tree):
    """pieces for a tree"""
    if tree.typeof == 'Elder Tree':
        return 2
    if tree.typeof == 'Tree':
        return 1
    return 0

def one_month():
    """a step of one month"""
    events = []
    global tick
    tick = tick + 1
    #each Tree can spawn a new sapling
    for t in get_trees():
        l_empty_spaces = c_empty_neighbors(t.coords)
        percent = 10 if t.typeof == 'Tree' else \
                  20 if t.typeof == 'Elder Tree' else 0
        if (randint(1,100) < percent):
            if l_empty_spaces:
                [x, y] = choice(l_empty_spaces)
                grid[x][y] = [Tree([x,y])]
                d_total['trees'] = d_total['trees'] + 1
        t.grow()
        d_oldest['tree'] = max(t.months, d_oldest['tree'])
    #each lumberjack/bear moves
    for l in get_lumberjacks():
        l.months = l.months + 1
        d_oldest['lumberjack'] = max((l.months, l.name), \
                                     d_oldest['lumberjack'])
        event = move_lumberjack(l)
        if event:
            events.append(event)
    for b in get_bears():
        b.months = b.months + 1
        d_oldest['bear'] = max((b.months, b.name), d_oldest['bear'])
        event = move_bear(b)
        if event:
            events.append(event)
    return events

def print_grid():
    """print the grid
    if more than 1 thing is at a place, print the last.
    At 1 place, there is
    - at most a tree and possibly several lumberjack
    - or 1 bear
    """
    print "-" * 2 * NGRID
    print '\n'.join([' '.join([str(i[-1]) if i != [] else ' ' \
                               for i in line]) \
                     for line in grid])
    print "-" * 2 * NGRID

def clean():
    """clear the console"""
    os.system('cls' if os.name == 'nt' else 'clear')

def print_grid_and_events():
    """print grid and list of events"""
    clean()
    print_grid()
    if VERBOSE:
        print '\n'.join(events)
        print "-" * 2 * NGRID

###populate the forest
l = c_empty_cells()
shuffle(l)
for x, y in l[:((NGRID*NGRID) / 2)]:
    grid[x][y] = [Tree([x, y], 12, 'Tree')]
    d_total['trees'] = d_total['trees'] + 1

l = c_empty_cells()
shuffle(l)
for x, y in l[:((NGRID*NGRID) / 10)]:
    grid[x][y] = [Lumberjack([x, y])]
    d_total['lumberjacks'] = d_total['lumberjacks'] + 1

l = c_empty_cells()
shuffle(l)
for x, y in l[:((NGRID*NGRID) / 10)]:
    grid[x][y] = [Bear([x, y])]
    d_total['bears'] = d_total['bears'] + 1

###time goes on
while (tick <= DURATION and len(get_trees())>0):
    events = one_month()
    #end of the year
    if (tick % 12)==0:
        events.append("End of the year")
        #lumber tracking
        nlumberjacks = len(get_lumberjacks())
        events.append(str(n_lumbers) + " lumbers VS " +\
                      str(nlumberjacks) + " Lumberjacks")
        if n_lumbers >= nlumberjacks:
            n_hire = n_lumbers/nlumberjacks
            events.append("we hire " + str(n_hire) +\
                          " new Lumberjack" + ("s" if (n_hire > 1) else ""))
            for _ in range(n_hire):
                events.append(new_animate(Lumberjack))
        else:
            events.append(fire_lumberjack())
        d_year['n_lumber'] = max(d_year['n_lumber'], n_lumbers)
        n_lumbers = 0
        #maul tracking
        events.append("maul this year: " + str(n_maul))
        if n_maul == 0:
            events.append(new_animate(Bear))
        else:
            events.append(capture_bear())
        d_year['n_maul'] = max(d_year['n_maul'], n_maul)
        n_maul = 0
    print_grid_and_events()
    sleep(SLEEPTIME)

print "-"*70
print "End of the game"
print "-"*70
print "month:" + str(tick - 1)
print "number of trees still alive: " + str(len(get_trees()))
print "number of lumberjacks still alive: " + str(len(get_lumberjacks()))
print "number of bears still alive: " + str(len(get_bears()))

print "-"*70
print "oldest Tree ever is/was: " + str(d_oldest['tree'])
print "oldest Lumberjack ever is/was: " + str(d_oldest['lumberjack'][0]) + \
    " yo " + d_oldest['lumberjack'][1]
print "oldest Bear ever is/was: " + str(d_oldest['bear'][0]) + \
    " yo " + d_oldest['bear'][1]
print "-"*70
print "max cut by a Lumberjack: " + str(d_most['n_cut'][0]) + \
    " by " + str(d_most['n_cut'][1])
print "max lumber by a Lumberjack: " + str(d_most['n_lumber'][0]) + \
    " by " + str(d_most['n_lumber'][1])
print "max maul by a Bear: " + str(d_most['n_maul'][0]) + \
    " by " + str(d_most['n_maul'][1])
print "-"*70
print "max lumber in a year: " + str(d_year['n_lumber'])
print "max maul in a year: " + str(d_year['n_maul'])
print "-"*70
print "Total of:"
for i, j in d_total.items():
    print i, str(j)

いくつかの出力:

------------------------------
          x



    I
    I
  x   i                     I

      i i i   i       I I x i
i   I   I i I I   i i     o
      i i I I I           i
    i I   x i
    I I   I I
      I     I i
            x
------------------------------
Dy is sent to hospital
Lehuniru cuts 1 Tree
------------------------------

年の終わり

------------------------------
            x

    x

i I     I
    i     I               x
      I
                          i i
      x                   I I
  i I   i I     i       i
  I         i I
            i x i
    I         i I
          o
        x
------------------------------
Fuha cuts 1 Tree
Ka cuts 1 Tree
Ky is sent to hospital
End of the year
11 lumbers VS 4 Lumberjacks
we hire 2 new Lumberjacks
a new Lumberjack enters the forest: Di
a new Lumberjack enters the forest: Dy
maul this year: 6
Evykut has been captured
------------------------------

ゲームの終わり

------------------------------
          x
  i
        x     x

          x                 x
                  x i     x
    i               I
    I i x x   I i           x
                    x   i   i
      x i i i i I
      i i I   I i I   i
I       i     i i
        i   x   i
            I   i I
    I I   x i   I I         x
------------------------------
Vanabixy cuts 1 Tree
Fasiguvy cuts 1 Tree
------------------------------
----------------------------------------------------------------------
End of the game
----------------------------------------------------------------------
month:4800
number of trees still alive: 36
number of lumberjacks still alive: 15
number of bears still alive: 0
----------------------------------------------------------------------
oldest Tree ever is/was: 129
oldest Lumberjack ever is/was: 308 yo Cejuka
oldest Bear ever is/was: 288 yo Ekyx
----------------------------------------------------------------------
max cut by a Lumberjack: 44 by Cejuka
max lumber by a Lumberjack: 44 by Cejuka
max maul by a Bear: 52 by Ekyx
----------------------------------------------------------------------
max lumber in a year: 84
max maul in a year: 86
----------------------------------------------------------------------
Total of:
bears 211
cut 5054
fired 67
capture 211
lumberjacks 1177
lumbers 5054
maul 1095
trees 5090
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.