Orman - Simüle Edilen Bir Ekosistem


19

NOT

Bu sorun bu reddit iş parçacığından (spoiler uyarısı!) Alınmıştır ve bu sitenin biçimine uyacak şekilde ayarladım. Tüm kredi "Coder_d00d" reddit kullanıcısına gider.

Bu problemde, bir ormanı simüle edeceğiz.

Bu simüle edilmiş orman için 3 yönü ele alacağız.

  • Fidan, Ağaç veya Yaşlı Ağaç olabilen ağaçlar.
  • Oduncular (Ağaçları keser, öğle yemeğini yer ve Lava-try'a gider)
  • Ayılar (Krep gibi kokan odunları kırıyor)

Bir ön uyarı: bu kurallar büyük olasılıkla mükemmel değildir. Onları bir rehber olarak görün ve eğer iyi olan herhangi bir şeyi hafifçe düzeltmeniz gerekiyorsa (yumurtlama oranları bir sorun olarak belirtilirse, bunun bir örneği olarak kuroi neko'nun cevabına bakın .

Zaman döngüsü:

Simülasyon aylara göre simüle edilecektir. Bir "kene" ile zaman içinde ilerleyeceksiniz. Her "kene" bir ayı temsil eder. Her 12 "keneler" bir yılı temsil eder. Ormanımız değişecek ve sürekli değişecek. Ormanımızın ilerlemesini kaydedeceğiz ve ona ne olduğunu analiz edeceğiz.

Orman:

Orman iki boyutlu bir orman olacak. N x N boyutunda bir ızgaradaki ormanın boyutunu temsil etmek için bir N girdisine ihtiyacımız olacaktır. Her yerde Ağaçlar, Ayılar veya Oduncuları tutabilirsiniz. Aynı noktayı işgal edebilirler, ancak genellikle aynı noktayı işgal ettiklerinde olaylar meydana gelir.

Ormanımız, büyüklüğüne göre rastgele doğacaktır. Örneğin, N = 10 değeriniz varsa. 10-10 orman ve 100 noktanız olacak.

  • Ormanın% 10'u 10 rastgele yerde Oduncu tutacak. (100 spot ormanımızı kullanarak bu 10 oduncu olmalıdır)
  • Ormanın% 50'si Ağaçları tutacak (Ağaçlar 3 türden biri olabilir ve "Ağaç" ın ortası olarak başlayacaktır) rastgele noktalarda.
  • Ormanın% 2'si Ayı tutacak.

Ormanın boyutunu nasıl alacağınız size bağlıdır (stdin'den, bir dosyadan veya sabit koddan okuyun). N'yi 5 veya daha yüksek tutmayı tavsiye ederim. Küçük Ormanlar pek eğlenceli değil.

Etkinlikler:

Simülasyon sırasında olaylar olacak. Olaylar, aşağıda açıklayacağım bazı mantığa dayanmaktadır. Ormanımızın 3 elementinin her tanımında aşağıdaki olayları anlatacağım.

Olaylar önce ağaçların sırasını, ikinci olarak odunları ve en son ayıları takip eder.

Ağaçlar:

  • Her ay bir Ağacın yeni bir "Fidan" üretme şansı% 10'dur. Bir Ağacın yanındaki rastgele açık alanda "Fidan" oluşturma şansınız% 10'dur.

  • Örneğin ormanın ortasındaki bir ağacın çevresinde 8 başka nokta vardır. Bunlardan biri (boşsa) "Fidan" olur.

  • 12 ay var olduktan sonra bir "Fidan" bir "Ağaç" yükseltilecek. Bir "Fidan" bir "Ağaç" haline gelene kadar diğer ağaçları yumurtlayamaz.

  • Bir "Fidan" bir ağaç haline geldiğinde, diğer yeni "Fidanları" üretebilir.

  • Bir "Ağaç" 120 ay (10 yıl) civarında olduğunda "Yaşlı Ağaç" olur.

  • Yaşlı Ağaçların% 10 yerine yeni bir "Fidan" üretme şansı% 20'dir.

  • Bir Ağaç veya Yaşlı Ağaca bitişik açık noktalar yoksa, yeni Ağaçlar üretilmez.

Ağaç kesen kimse:

Oduncular ağaçları keser, atlar ve kır çiçekleri bastırmaktan hoşlanırlar.

  • Her ay oduncu dolaşır. Herhangi bir yönde bitişik rastgele seçilmiş bir noktaya 3 kata kadar hareket edecekler. Mesela, ızgaranızın ortasındaki bir oduncu taşımak için 8 nokta var. Rastgele bir noktaya doğru yürüyecek. Sonra tekrardan. Ve son olarak üçüncü kez. Not: Bu herhangi bir nokta olabilir (böylece ayılar içine girebilir, bir maul ile sonuçlanabilir).

  • Oduncu hareket ettiğinde, bir Ağaçla (fidanla değil) karşılaşırsa durur ve o ay boyunca dolaşması sona erer. Daha sonra Ağacı kereste için hasat edecektir. Ağacı çıkarın. 1 parça kereste kazanın.

  • Oduncu "Fidan" hasat olmaz.

  • Lumberacks ayrıca Elder Ağaçlarını hasat eder. Yaşlı Ağaçlar 2 adet kereste değerinde.

Kereste Takibi:

Her 12 ayda bir hasat edilen kereste miktarı ormandaki oduncu sayısı ile karşılaştırılır.

  • Toplanan kereste, ormandaki oduncu miktarına eşitse veya bu değeri aşarsa, birkaç yeni oduncu kiralanır ve ormanda rastgele doğar.

  • İşe alınacak oduncu sayısını hesaplayın: floor(lumber_collected / number_of_lumberjacks)

  • Ancak, 12 aylık bir süreden sonra toplanan kereste miktarı oduncu sayısının altındaysa, bir oduncu para tasarrufu yapmaya bırakılır ve 1 rasgele oduncu ormandan çıkarılır. Lumberjack iş gücünüzü asla 0'ın altına düşürmeyeceğinizi unutmayın.

Ayılar:

Ayılar ormanı bir oduncu gibi gezer. Ancak 3 uzay yerine bir Ayı 5 uzay kadar dolaşacaktır.

  • Bir ayı bir Oduncu ile karşılaşırsa, ay boyunca dolaşmasını durduracaktır. (Örneğin, 2 hamle sonra ayı oduncu ile bir alana iner, bu ay için daha fazla hamle yapmaz)

  • Oduncu krep gibi kokuyor. Ayılar krep seviyorum. Bu nedenle Ayı maalesef odun kıracak ve incitecektir. Oduncu ormandan kaldırılacak (Çarşamba günleri eve gidip alışveriş yapacak ve çay için çörekler tereyağlı olacak).

  • Bunu bir "Maul" kazası olarak takip edeceğiz.

  • Oduncu popülasyonunun asla 1'in altına düşemeyeceğini unutmayın - bu yüzden son oduncu çekilirse sadece bir tane daha doğurur.

Maul Takibi:

  • 12 ay boyunca 0 "Maul" kazası varsa, o zaman Ayı nüfusu 1 artacaktır. 1 rastgele Ayıyı kaldırın. Ayı nüfusu 0 ayıya ulaşırsa, önümüzdeki yıl "Maul" kazası olmayacağını ve bu nedenle gelecek yıl 1 yeni Ayı doğuracağını unutmayın.

  • Ormanda sadece 1 oduncu varsa ve Mauled alırsa, eve gönderilecek, ancak hemen yeni bir tane işe alınacak ve ormanda başka bir yerde yeniden doğacak. Oduncu popülasyonu asla 1'in altına düşemez.

Zaman:

Simülasyon 4800 ay (400 yıl) veya Fidan, Ağaç veya Yaşlı Ağaç yok olana kadar gerçekleşir.

Çıktı:

Her ay ormanın bir haritasını yazdırabilirsiniz - belki bir ASCII haritası kullanarak veya grafik ve renkler kullanarak.

İsteğe bağlı ekstralar

  • Her kene ağaç, oduncu ve ayı popülasyonlarının çıktısını alabilirsiniz.
  • Bir olay meydana geldiğinde çıktı alabilirsiniz (örneğin: "Bir ayı oduncu taklit etti.")

puanlama

Bu bir popülerlik yarışmasıdır, bu yüzden çoğu upvotes kazanır!

EDIT - İnsanlar kurallarımda bir takım kusurlara dikkat çekti ve bana soru sormaktan çekinmeyin, ancak kendi programınıza veya programın yorumuna uyacak kuralları biraz düzeltmek de uygun.


Hakkında: Note that you will never reduce your Lumberjack labor force below 0oduncu bölümünde liste öğesi 3. belki ayı bölümünde bahsettiğinizle aynı olması için bunu 1 olarak değiştirin?
Teun Pronk

İyi bir nokta, bunu şimdi düzenleyecek.
James Williams

2
Hareketin zamanlamasını tartışabilir misiniz? "Ağaçlar hareket ediyor / ilerliyor", sonra "odunlar hareket ediyor", sonra "ayılar hareket ediyor" mu? Ayrıca, ayılar ve ağaçlar aynı alanları kaplayabilir mi?
durron597

1
İki ayı aynı yere yürürse ne olur? Peki ya iki oduncu? Aynı yerde olabilirler mi?
Jerry Jeremiah

1
Bu reddit.com/r/dailyprogrammer/comments/27h53e/… ile aynıdır. Kredi vermelisiniz - en azından insanlar başka ilginç çözümler için oraya gidebilecekler.

Yanıtlar:


15

Javascript + HTML - deneyin

Popüler isteklere göre güncellendi

orman ve grafik

Genel davranış

Program şimdi biraz etkileşimlidir.
Kaynak kodu tamamen parametrelendirilmiştir, böylece favori metin düzenleyicinizle birkaç dahili parametreyi değiştirebilirsiniz.

Orman boyutunu değiştirebilirsiniz.
3 farklı noktaya bir ağaç, bir oduncu ve bir ayı yerleştirmek için yeterli alana sahip olmak için en az 2 gereklidir ve maks. Keyfi olarak 100'e sabitlenir (bu da ortalama bilgisayarınızı tarar).

Simülasyon hızını da değiştirebilirsiniz.
Ekran her 20 ms'de bir güncellenir, böylece daha büyük bir zaman adımı daha iyi animasyonlar üretir.

Düğmeler simülasyonu durdurmaya / başlatmaya veya bir ay veya bir yıl boyunca çalıştırmaya izin verir.

Orman sakinlerinin hareketi artık biraz canlandı. Mauling ve ağaç kesme olayları da anlaşılmaktadır.

Bazı olayların günlüğü de görüntülenir. Ayrıntı düzeyini değiştirirseniz bazı mesajlar daha kullanılabilir, ancak bu sizi "Bob başka bir ağacı keser" bildirimleriyle dolduracaktır.
Siz olsaydım bunu yapmamayı tercih ederim, ama değilim, yani ...

Oyun alanının yanında, bir dizi otomatik ölçekli grafik çizilir:

  • ayılar ve oduncu popülasyonları
  • fidan, olgun ve yaşlı ağaçlara bölünmüş toplam ağaç sayısı

Gösterge ayrıca her bir öğenin mevcut miktarlarını gösterir.

Sistem kararlılığı

Grafikler, başlangıç ​​koşullarının bunu zarifçe ölçeklemediğini göstermektedir. Orman çok büyükse, çok fazla ayı odun popülasyonunu, yeterince krep severlerin parmaklıklar arkasına konuluncaya kadar yok eder. Bu yaşlı ağaçların ilk patlamasına neden olur, bu da oduncu popülasyonunun iyileşmesine yardımcı olur.

Görünüşe göre ormanın hayatta kalabilmesi için minimum boyut 15. 10 büyüklüğünde bir orman genellikle birkaç yüz yıl sonra yerle bir olur. 30'dan büyük herhangi bir boyut, neredeyse ağaçlarla dolu bir harita üretecektir. 15 ila 30 arasında, ağaç popülasyonunun önemli ölçüde salındığını görebilirsiniz.

Bazı tartışmalı kural noktaları

Orijinal yazının yorumlarında, çeşitli bipedlerin aynı noktayı işgal etmesi gerekmiyor gibi görünüyor. Bu, bir şekilde gözleme amatörüne dolaşan bir cahil hakkındaki kuralla çelişir.
Her halükarda, bu kılavuzu takip etmedim. Herhangi bir orman hücresi herhangi bir sayıda inhiyabitan (ve tam olarak sıfır veya bir ağaç) tutabilir. Bunun oduncu verimliliğinde bazı sonuçları olabilir: Sanırım yaşlı ağaçların daha kolay toplanmasına izin veriyor. Ayılar gelince, bunun çok fazla fark yaratmasını beklemiyorum.

Ayrıca, cahil nüfusun sıfıra ulaşabileceğini belirten noktaya rağmen, ormandaki her zaman en az bir oduncu bulundurmayı seçtim (hasat gerçekten zayıfsa haritadaki son oduncu fırlattı, bu da orman olmadıkça asla olmaz nesli tükenmek üzere doğranmış).

Tweaking

Kararlılık elde etmek için iki ayar parametresi ekledim:

1) Oduncu büyüme oranı

yeterli kereste olduğunda işe alınan ekstra oduncu sayısını veren formüle uygulanan bir katsayı. Orijinal tanımlamaya geri dönmek için 1'e ayarladım, ancak yaklaşık 5 değerinde bir ormanın (özellikle yaşlı ağaçların) daha iyi gelişmesine izin verdim.

2) Ayı Kaldırma Kriteri

hayvanat bahçesine ayı göndermek için asılsız oduncuların yüzdesini tanımlayan bir katsayı. Orijinal tanımlamaya geri dönmek için 0'a ayarlayın, ancak bu sert ayı ortadan kaldırılması temelde popülasyonu 0-1 salınım döngüsüyle sınırlayacaktır. Bunu .15 olarak ayarladım (yani bir ayı sadece bu yıl oduncuların% 15'i veya daha fazlası çekilirse çıkarılır). Bu, rednecks'ların alanı temizlemesini önlemek için yeterli olan ancak yine de ormanın büyük bir bölümünün kesilmesine izin veren yeterli bir ayı popülasyonuna izin verir.

Bir yan not olarak, simülasyon asla durmaz (gerekli 400 yılı geçse bile). Kolayca yapabilirdi, ama yapmıyor.

Kod

Kod tamamen tek bir HTML sayfasında bulunur.
Bu UTF-8 olarak kodlanmış olmalıdır ayılar ve lumberjacks için uygun unicode sembolleri görüntülemek için.

Unicode bozulmuş sistemler için (örn. Ubuntu): aşağıdaki satırları bulun:

    jack   :{ pic: '🙎', color:'#bc0e11' },
    bear   :{ pic: '🐻', color:'#422f1e' }},

ve ekrana kolay karakterler için piktogram değiştirin ( #, *ne olursa olsun)

<!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>

Sırada ne var?

Daha fazla açıklama bekliyoruz.

Not: Fidan / olgun / yaşlı ağaç sayısının hala biraz dağınık olduğunu biliyorum, ama cehennemle.

Ayrıca, document.getElementById $ 'dan daha okunabilir buluyorum, bu yüzden jQueryism eksikliği hakkında şikayet etmeye gerek yok. Amaç jQuery ücretsizdir. Her birine kendi başına, değil mi?


+1, Bu çok kötü görünüyor, etkileşimi görmek isterim!
William Barbosa

Ayıları ve oduncuları göremiyorum. Onları görmek için ne yapmalıyım? Ftw, yılda en fazla bir ayı çıkarılmalı, değil mi?
justhalf

@WilliamBarbosa Eğer vox populi yeterince yüksek sesle çığlık atarsa, beni biraz ekleyerek beni ikna edebilir :)

@justhalf unicode karakterler hakkındaki düzenlememi görün. Ayılar gelince, özellikleri doğru anlarsam, evet: her yıl hayvanat bahçesine rastgele seçilen sadece bir ayı, bazı mauling'ler meydana gelirse.

1
Büyüyen ağaçlar muhteşem. Aferin!
Kara delik

14

angularjs

İşte hala sürmekte olan bir versiyonum : kod biraz… iyi… çirkin. Ve oldukça yavaş. Ayrıca evrimi parametrize etmek ve ormanın durumunu analiz etmek için daha fazla seçenek eklemeyi planlıyorum. Yorumlar ve iyileştirme önerileri bekliyoruz!

Orman ekran görüntüsü

gösteri

<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
Ayrıca shuffle dizi randomize etmek için nasıl aynı kodu kullanmak gibi
Kevin L

İlginç. Simülasyonunuzu ilk kez çalıştırdığımda, tüm ayılarla ve oduncu yok ile bitiyor, bu da beni bu simülasyonun dengesiz olduğunu düşünmeye itti. Ama daha sonra bir daha asla olmaz, bu yüzden tüm oduncuların ayılar tarafından
yönetildiği

getEntitiesAtbir CPU domuz gibi görünüyor! sistemi 50x50 ızgara ile çalıştırmak bilgisayarımda ayda bir saniyeden fazla sürüyor. Ayrıca, tüm ağaçların kesildiği, sonra tüm odunların ateşlendiği ve harita yavaşça ayılarla dolduğu bir durum var :). Gerçekleştiğini görmek için küçük bir boyut (10 veya daha az) deneyin.

@kuroineko: Çünkü bir oduncu bozulduktan sonra ve bir ayı üzerinde yeniden doğarsa, orada olmayacak bir böcek (ya da daha ziyade uygulanmamış bir kural) var. O sonra bir çek ile 0. Fix it alır Yani Forest.tick()eğer Forest.lumberjackList.length == 0, o zaman Lumberjack.create(<number>, <number>).
justhalf

1
Ayıları ormanda kalmayı tercih etmek için kodunuzu değiştirmeyi denedim (ve ayrıca% 10'dan az mauling varsa ayı eklemek gibi @ kuroineko benzeri ayı çıkarma kriterlerini dahil edin ve% 15'ten fazla mauling varsa ayı kaldırmak ). Davranışın nasıl değiştiğini görmek ilginçtir =)
sadece

3

JavaScript

Bence bu çoğunlukla işe yarıyor. Tüm yeni ayıları / oduncuları eşzamanlı olarak ve hemen yan yana doğurduğum bazı sakat davranışlar var, çünkü eklemelerde tembellik.

Bu uygulama oduncuların fidanların üzerinde durmasına izin vermez, biliyorsunuz, fidanları çiğnemek kötüdür. Keman sanatı varsayılan olarak renkli dikdörtgenler kullanır, çizmek için harfleri kullanmak için ikinci satırı yanlış olarak değiştirin.

Vaktini boşa harcamak

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;
}

Yüksek boyutlu ormanlarda garip bir şey var ( n = 50örneğin deneyin ).
Kara delik

@Blackhole garip bir şey = ____?
Kevin L


Ayıların takıldığını ve haritanın üst kısmındaki oduncuları çıkardığımdan beri haritanın alt kısmını ele geçirdiğini fark ettim
Kevin L

1
Yeni ayılar ve oduncuların doğuşunda yanlış bir şey var. Bence hepsini sol üst köşeye koymak sistemin küresel dengesini biraz değiştiriyor.

3

piton

Hiçbir şey fantezi. Bir şeyler eklemeye devam ettim, bu yüzden yeniden düzenleme sırayla olabilir. (Ve bugüne kadar bug hala hataları olabilir birimest yapmadım).

Odunculara ve ayılara rastgele isimler verdim. AğaçlariO zamanI zaman #, Odunculardır x, Ayılaro

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)

Bazı çıktılar:

------------------------------
          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
------------------------------

Yılın sonu

------------------------------
            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
------------------------------

Oyunun sonu

------------------------------
          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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.