Bir Epidemiyolog olun!


13

Meydan okuma

Hastalığın bir grup insana nasıl yayıldığına dair basit bir model oluşturmalısınız.

Kurallar ve Gereksinimler

Model 1000 x 1000 2D bir dizi olmalıdır ve her eleman farklı bir kişidir.

Kullanıcı argv'yi kullanarak üç değişken girmelidir: iletim olasılığı (birisinin başkasını enfekte etme olasılığı), mutasyon şansı ve simülasyonun kaç dönem çalışması gerektiği.

İlk dönemde ( t=0), dört kişi rastgele seçilmeli ve hastalığa yakalanmalıdır.

Hastalığın davranış şekli aşağıdaki kurallara tabidir:

  • Hastalık sadece dikey ve yatay olarak hareket edebilir ve yandaki kişiye hareket edebilir.
  • Enfeksiyon her insanda 3 dönem sürer. İmmün yetmezlikleri hesaba katmayabilirsiniz.
  • Bir kişi üç kez enfekte olduktan sonra bağışıklık kazanır ve tekrar enfekte olmaz.
  • Hastalık, daha önce bağışıklığı olan insanları bu yeni mutasyona uğramış hastalığa karşı savunmasız hale getiren mutasyona tabidir. Mutasyon geçirmiş hastalık tam olarak aynı özelliklere sahiptir ve orijinal hastalık ile aynı kuralları takip eder.
  • Bir mutasyon meydana gelirse, tüm hastalık değişmez, sadece iletim üzerine belirli bir 'paket'.
  • Bir kişiye bir virüs bulaştığında, mevcut enfeksiyon geçene kadar tekrar enfekte olamaz.
  • Bir kişi enfekte olursa, enfeksiyon döneminin başlangıcından sonuna kadar bulaşıcıdır.
  • Bağışıklık seviyeleri yoktur - bir kişi ya bağışıktır ya da değildir.
  • Bellek aşırı yüklenmesini durdurmak için maksimum 800 mutasyon sınırı vardır.

Belirtilen nokta sayısının sonunda sonuçları çıkarmalısınız.

Sonuçlar, hangi kişilerin enfekte olduğunu ve hangilerinin olmadığını gösteren 1000 x 1000 ızgara olmalıdır. Bu, bir metin dosyası, bir görüntü dosyası veya grafik çıktısı olarak çıkarılabilir (burada #FFFFFF sağlıklı bir kişidir ve # 40FF00 virüslü bir kişidir).

Lütfen dil adını ve cevabınıza çalıştırmak için bir komut ekleyebilir misiniz?

Kazanan

Bilgisayarımda çalıştırılacak en hızlı kod kazanır. Zamanı aşağıdaki Python kodu ile ölçülecektir:

import time, os
start = time.time()
os.system(command)
end = time.time()
print(end-start)

Bu komut dosyasını çalıştırırken aşağıdaki varsayılanları kullanacağımı unutmayın:

Probability of transmission = 1
Chance of mutation = 0.01
Number of periods = 1000

3
10- gigabaytlık bir dosya mı yapmak istiyorsunuz ?
Ypnypn

1
4 GB'lık bir sınıra sahip olarak, çıktıyı görüntü dosyasına kaydetme seçeneğini tamamen kaldırdınız ...
Optimizer

10
1000x1000 : Bu daha çok benziyor!
COTO

1
Ayrıca yan yana iki kişi olduğunu söyleyin. İlk virüs virüsü V, ikinci virüs virüsü V'. Kasılma her ikisi de aynı dönemde sona erecektir. Virüs Vikinci kişiye bulaşabilir mi? (Ya bir daha siyah-beyaz soru: bu mümkün iyileşinceye sonra o enfeksiyonun 6 ardışık dönem ile sona erecek bu yüzden bir kişinin, derhal enfekte olması?)
justhalf

1
Bir diğeri, iki bağımsız virüs aynı virüse dönüşebilir mi? Diyelim ki Vbizzat Ave Vyine bizzat B. Virüsü ilettiklerinde ikisi de aynı mutasyona dönüşebilir V'mi? Ya da belki aslında gerektiğini aynı virüs türünün için mutasyona? Keyfi olarak mutasyona uğrayabilirlerse, iki virüsün aynı virüs suşuna mutasyon geçirme olasılığı nedir?
sadece

Yanıtlar:


10

Bunun neye benzediğini merak ettim, bu yüzden JavaScript'te bu hızlı ve kirli hack'i yaptım: http://jsfiddle.net/andrewmaxwell/r8m54t9c/

// The probability that a healthy cell will be infected by an adjacent infected cell EACH FRAME.
var infectionProbability = 0.2

// The probability that the infection will mutate on transmission EACH FRAME.
var mutationProbability = 0.00001

// The maximum number of times a cell can be infected by the same infection.
var maxInfections = 3

// The number of frames a cell in infected before it becomes healthy again.
var infectionDuration = 3

// The width and heigh of the board
var size = 400

// The number of cells infected at the beginning.
var startingNum = 4

var imageData, // the visual representation of the board
    cells, // array of cells
    infectionCount // counter that is incremented whenever a mutation occurs

// Just some colors. The colors are re-used as the number of mutations increases.
var colors = [[255,0,0],[255,255,0],[0,255,0],[0,255,255],[0,0,255],[255,0,255],[128,0,0],[128,128,0],[0,128,0],[0,128,128],[0,0,128],[128,0,128],[255,128,128],[255,255,128],[128,255,128],[128,255,255],[128,128,255],[255,128,255]
]

// when a cell is infected, it isn't contagious until the next frame
function infect(person, infection){
    person.infect = true
    person.infectionCounts[infection] = (person.infectionCounts[infection] || 0) + 1
    person.currentInfection = infection
}

// when a mutation occurs, it is given a number and the counter is incremented
function mutation(){
    return infectionCount++
}

function reset(){

    cells = []
    infectionCount = 0
    imageData = T.createImageData(size, size)

    // initialize the cells, store them in a grid temporarily and an array for use in each frame
    var grid = []
    for (var i = 0; i < size; i++){
        grid[i] = []
        for (var j = 0; j < size; j++){
            cells.push(grid[i][j] = {
                infectionTime: 0, // how many frames until they are no longer infected, so 0 is healthy
                infectionCounts: [], // this stores how many times the cell has been infected by each mutation
                neighbors: [] // the neighboring cells
            })
        }
    }

    // store the neighbors of each cell, I just want to minimize the work done each frame
    var neighborCoords = [[0,-1],[1,0],[0,1],[-1,0]]
    for (var i = 0; i < size; i++){
        for (var j = 0; j < size; j++){
            for (var n = 0; n < neighborCoords.length; n++){
                var row = i + neighborCoords[n][0]
                var col = j + neighborCoords[n][1]
                if (grid[row] && grid[row][col]){
                    grid[i][j].neighbors.push(grid[row][col])
                }
            }
        }
    }

    // infect the initial cells
    for (var i = 0; i < startingNum; i++){
        infect(cells[Math.floor(cells.length * Math.random())], 0)
    }
}

function loop(){
    requestAnimationFrame(loop)

    // for each cell marked as infected, set its infectionTime
    for (var i = 0; i < cells.length; i++){
        var p = cells[i]
        if (p.infect){
            p.infect = false
            p.infectionTime = infectionDuration
        }
    }

    for (var i = 0; i < cells.length; i++){
        var p = cells[i]

        // for each infected cell, decrement its timer
        if (p.infectionTime){
            p.infectionTime--

            // for each neighbor that isn't infected, if the probability is right and the neighbor isn't immune to that infection, infect it
            for (var n = 0; n < p.neighbors.length; n++){
                var neighbor = p.neighbors[n]
                if (!neighbor.infectionTime && Math.random() < infectionProbability){
                    var infection = Math.random() < mutationProbability ? mutation() : p.currentInfection
                    if (!neighbor.infectionCounts[infection] || neighbor.infectionCounts[infection] < maxInfections){
                        infect(neighbor, infection)
                    }
                }
            }

            // colors! yay!
            var color = colors[p.currentInfection % colors.length]
            imageData.data[4 * i + 0] = color[0]
            imageData.data[4 * i + 1] = color[1]
            imageData.data[4 * i + 2] = color[2]
        } else {
            imageData.data[4 * i + 0] = imageData.data[4 * i + 1] = imageData.data[4 * i + 2] = 0
        }

        imageData.data[4 * i + 3] = 255
    }

    T.putImageData(imageData, 0, 0)
}

// init canvas and go
C.width = C.height = size
T = C.getContext('2d')
reset()
loop()

1
Enfeksiyonu 1'e ayarlamak, gördüğüm en tatlı desenlerden bazılarını yaptı!
William Barbosa

Programınızın cevabınıza ne kadar sürdüğünü ekleyebilir misiniz?
Beta Çürümesi

7

C ++ 11, 6-8 dakika

Test çalışmam Fedora 19, i5 makinemde yaklaşık 6-8 dakika sürüyor. Ancak mutasyonun rastgele olması nedeniyle, daha hızlı olabilir veya bundan daha uzun sürebilir. Bence puanlama kriterlerinin yeniden okunması gerekiyor.

Sonuç, tamamlanma sonunda metin olarak, nokta doğru ( .) ile gösterilen sağlıklı bir kişi , yıldız işareti ( *) ile enfekte olmuş bir kişi olarak, ANIMATEbayrak doğru olarak ayarlanmadığı sürece yazdırılır, bu durumda farklı virüs türünden etkilenen kişiler için farklı karakterler görüntülenir.

İşte 10x10, 200 dönem için bir GIF.

10x10Gif

Mutasyon davranışı

Her bir mutasyon, daha önce hiç görülmemiş yeni bir suş verecektir (bu nedenle, 800 suş üretilmedikçe, herhangi bir virüs daha fazla mutasyona girmeyecekse, bir komşu dört farklı suşa dört kişiyi enfekte etmek mümkündür).

8 dakikalık sonuç aşağıdaki sayıda enfekte kişiden gelir:

Dönem 0, Enfekte: 4
Dönem 100, Enfekte: 53743
Dönem 200, Enfekte: 134451
Dönem 300, Enfekte: 173369
Dönem 400, Enfekte: 228176
Dönem 500, Enfekte: 261473
Periyot 600, Enfekte: 276086
Periyod 700, Enfeksiyon: 265774
Periyod 800, Enfekte: 236828
Dönem 900, Enfeksiyon: 221275

6 dakikalık sonuç aşağıdakilerden gelir:

Dönem 0, Enfekte: 4
Dönem 100, Enfekte: 53627
Dönem 200, Enfeksiyon: 129033
Dönem 300, Enfekte: 186127
Dönem 400, Enfekte: 213633
Dönem 500, Enfekte: 193702
Periyot 600, Enfekte: 173995
Periyod 700, Enfeksiyon: 157966
Periyod 800, Enfekte: 138281
Dönem 900, Enfeksiyon: 129381

Kişi temsilciliği

Her kişi 205 bayt ile temsil edilir. Bu kişinin kasıldığı virüs tipini saklamak için dört bayt, bu kişiye ne kadar süredir bulaştığını depolamak için bir bayt ve her bir virüs suşunu kaç kez büzdüğünü saklamak için 200 bayt (her biri 2 bit). Belki de C ++ tarafından yapılan bazı ek bayt hizalama vardır, ancak toplam boyut 200MB civarında olacaktır. Bir sonraki adımı saklamak için iki ızgaram var, bu yüzden toplamda 400MB kullanıyor.

Enfekte kişilerin yerini bir sırada saklıyorum, erken dönemlerde gerekli zamanı kesmek için (<400'e kadar dönemler için gerçekten yararlı).

Program özellikleri

Her 100 adımda bir, ANIMATEbayrak ayarlanmadıkça virüs bulaşmış kişi sayısını basar, truebu durumda tüm ızgarayı her 100 ms'de bir yazdırır.

Bu, C ++ 11 kitaplıklarını gerektirir ( -std=c++11bayrak kullanarak derleme veya ile Mac'te clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread).

Varsayılan değerler için bağımsız değişkenler olmadan veya aşağıdaki gibi bağımsız değişkenlerle çalıştırın:

./virus_spread 1 0.01 1000

#include <cstdio>
#include <cstring>
#include <random>
#include <cstdlib>
#include <utility>
#include <iostream>
#include <deque>
#include <cmath>
#include <functional>
#include <unistd.h>

typedef std::pair<int, int> pair;
typedef std::deque<pair> queue;

const bool ANIMATE = false;
const int MY_RAND_MAX = 999999;

std::default_random_engine generator(time(0));
std::uniform_int_distribution<int> distInt(0, MY_RAND_MAX);
auto randint = std::bind(distInt, generator);
std::uniform_real_distribution<double> distReal(0, 1);
auto randreal = std::bind(distReal, generator);

const int VIRUS_TYPE_COUNT = 800;
const int SIZE = 1000;
const int VIRUS_START_COUNT = 4;

typedef struct Person{
    int virusType;
    char time;
    uint32_t immune[VIRUS_TYPE_COUNT/16];
} Person;

Person people[SIZE][SIZE];
Person tmp[SIZE][SIZE];
queue infecteds;

double transmissionProb = 1.0;
double mutationProb = 0.01;
int periods = 1000;

char inline getTime(Person person){
    return person.time;
}

char inline getTime(int row, int col){
    return getTime(people[row][col]);
}

Person inline setTime(Person person, char time){
    person.time = time;
    return person;
}

Person inline addImmune(Person person, uint32_t type){
    person.immune[type/16] += 1 << (2*(type % 16));
    return person;
}

bool inline infected(Person person){
    return getTime(person) > 0;
}

bool inline infected(int row, int col){
    return infected(tmp[row][col]);
}

bool inline immune(Person person, uint32_t type){
    return (person.immune[type/16] >> (2*(type % 16)) & 3) == 3;
}

bool inline immune(int row, int col, uint32_t type){
    return immune(people[row][col], type);
}

Person inline infect(Person person, uint32_t type){
    person.time = 1;
    person.virusType = type;
    return person;
}

bool inline infect(int row, int col, uint32_t type){
    auto person = people[row][col];
    auto tmpPerson = tmp[row][col];
    if(infected(tmpPerson) || immune(tmpPerson, type) || infected(person) || immune(person, type)) return false;
    person = infect(person, type);
    infecteds.push_back(std::make_pair(row, col));
    tmp[row][col] = person;
    return true;
}

uint32_t inline getType(Person person){
    return person.virusType;
}

uint32_t inline getType(int row, int col){
    return getType(people[row][col]);
}

void print(){
    for(int row=0; row < SIZE; row++){
        for(int col=0; col < SIZE; col++){
            printf("%c", infected(row, col) ? (ANIMATE ? getType(row, col)+48 : '*') : '.');
        }
        printf("\n");
    }
}

void move(){
    for(int row=0; row<SIZE; ++row){
        for(int col=0; col<SIZE; ++col){
            people[row][col] = tmp[row][col];
        }
    }
}

int main(const int argc, const char **argv){
    if(argc > 3){
        transmissionProb = std::stod(argv[1]);
        mutationProb = std::stod(argv[2]);
        periods = atoi(argv[3]);
    }
    int row, col, size;
    uint32_t type, newType=0;
    char time;
    Person person;
    memset(people, 0, sizeof(people));
    for(int row=0; row<SIZE; ++row){
        for(int col=0; col<SIZE; ++col){
            people[row][col] = {};
        }
    }
    for(int i=0; i<VIRUS_START_COUNT; i++){
        row = randint() % SIZE;
        col = randint() % SIZE;
        if(!infected(row, col)){
            infect(row, col, 0);
        } else {
            i--;
        }
    }
    move();
    if(ANIMATE){
        print();
    }
    for(int period=0; period < periods; ++period){
        size = infecteds.size();
        for(int i=0; i<size; ++i){
            pair it = infecteds.front();
            infecteds.pop_front();
            row = it.first;
            col = it.second;
            person = people[row][col];
            time = getTime(person);
            if(time == 0) continue;
            type = getType(person);
            if(row > 0 && randreal() < transmissionProb){
                if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
                    newType++;
                    if(!infect(row-1, col, newType)) newType--;
                } else {
                    infect(row-1, col, type);
                }
            }
            if(row < SIZE-1 && randreal() < transmissionProb){
                if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
                    newType++;
                    if(!infect(row+1, col, newType)) newType--;
                } else {
                    infect(row+1, col, type);
                }
            }
            if(col > 0 && randreal() < transmissionProb){
                if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
                    newType++;
                    if(!infect(row, col-1, newType)) newType--;
                } else {
                    infect(row, col-1, type);
                }
            }
            if(col < SIZE-1 && randreal() < transmissionProb){
                if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
                    newType++;
                    if(!infect(row, col+1, newType)) newType--;
                } else {
                    infect(row, col+1, type);
                }
            }
            time += 1;
            if(time == 4) time = 0;
            person = setTime(person, time);
            if(time == 0){
                person = addImmune(person, type);
            } else {
                infecteds.push_back(std::make_pair(row, col));
            }
            tmp[row][col] = person;
        }
        if(!ANIMATE && period % 100 == 0) printf("Period %d, Size: %d\n", period, size);
        move();
        if(ANIMATE){
            printf("\n");
            print();
            usleep(100000);
        }
    }
    if(!ANIMATE){
        print();
    }
    return 0;
}

Bunu gerçekten beğendim! Tek sorum GIF nasıl yapılır?
Beta Çürümesi

1
Bu aracı kullanıyorum: linux.die.net/man/1/byzanz-record . Şu anda GUI'ye sahip değil, bu nedenle = D
justhalf

Oh, bu güzel, teşekkürler! :)
Beta Çürümesi

3

C # 6-7 Dakika

Düzenle 2

Sonunda (5 saat) 1000x1000'de 1000 periyotta (sadece 840 kare sonra çöktü) ayrıntılı bir çıktı oluşturdum, her 1 periyotta, ancak 160MB'a yakın ve görüntülemek için sistemimdeki tüm belleği gerektiriyor (IrfanView) , bir tarayıcıda çalışacağından bile emin değilim, daha sonra koyayım.

DÜZENLE

Ben "Beta Çürüme" nin "Gerilimi rastgele seç" cevabına göre daha verimli hale getirmek için çok zaman harcadım. Periyodu kimin etkilediğini seçmek için sadece rastgele bir yöntem seçtim, ancak hesaplanan yolu değiştirdim ve her şeyi düzelttim, yayınlarımı yeni ayrıntılarla güncelledim.

Buna en yakın tahminimi kodlayabilirim, umarım tüm kurallara uyar, sistemimde bir ton bellek kullanır (yaklaşık 1.2GB). Program animasyonlu gif (harika, gerçekten yavaş görünüyor) veya sadece "Beta Çürüme" nin özellikleri ile eşleşen bir görüntü çıktısı verebilir. Bu, tekerleği yeniden icat etmek biraz, ama kesinlikle harika görünüyor:


Sonuçlar

(Not: Bu sadece enfekte olan ve enfekte olmayan, yani ayrıntılı olmayanlar arasında ayrım yapar)

1000 Dönem,% 1 Mutasyon Oranı,% 100 Yayılma:

Sonuç

Örnekler (Ayrıntılı)

Yine de ayrıntılı olmayan modda% 100 "İletim olasılığı" kullanmak, her zaman aynı şekilleri aldığınız ve parametreleri biraz değiştirdiğinizde (ve ayrıntılı modu etkinleştirdiğinizde) farklı mutasyonları göremediğiniz için sıkıcıdır. serin görünümlü bir çıktı elde edersiniz (animasyonlu GIF'ler her 10. karede görüntülenir):

Rastgele - Izgara Boyutu: 200, ProbTransmission: 100%, ProbMutation: 1%

100Precent

Rastgele - Izgara Boyutu: 200, ProbTransmission: 20%, ProbMutation: 1%

20Precent

puanlama

"Herhalde", mutasyonların rastgele olması ve rastgele başlangıç ​​noktalarının konumu nedeniyle her çalışma farklı olacağından skorlama kriterlerinin adil olmayabileceğine katılıyorum. Belki birkaç koşu ya da bunun gibi bir şey ortalama yapabiliriz ..., yine de bu C # için benim için çok lütuf :( neyse.

kod

MagickImage kitaplığını eklediğinizden emin olun (x64 bit'i derleyecek şekilde ayarlanmıştır) aksi takdirde oluşturulmaz ( http://pastebin.com/vEmPF1PM ):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using ImageMagick;
using System.IO;

namespace Infection
{
    class Program
    {
        #region Infection Options
        private const double ProbabilityOfTransmission = .2;
        private const double ChanceOfMutation = 0.01;
        private const Int16 StageSize = 1000;
        private const Int16 MaxNumberOfMutations = 800;
        private const byte MaxInfectionTime = 3;
        private const byte NumberOfPeopleToRandomlyInfect = 4;
        private static int NumberOfPeriods = 1000;
        #endregion Infection Options

        #region Run Options
        private const bool VerbosMode = false;        
        private const int ImageFrequency = 10;
        #endregion Run Options

        #region Stage        
        private static Int16 MutationNumber = 1;

        private class Person
        {
            public Person()
            {
                PreviousInfections = new Dictionary<Int16, byte>();
                InfectionTime = 0;
                CurrentInfection = 0;
                PossibleNewInfections = new List<short>(4);
            }
            public Dictionary<Int16, byte> PreviousInfections { get; set; }
            public byte InfectionTime { get; set; }
            public Int16 CurrentInfection { get; set; }
            public List<Int16> PossibleNewInfections { get; set; }
        }
        private static Person[][] Stage = new Person[StageSize][];
        #endregion Stage

        static void Main(string[] args)
        {
            DateTime start = DateTime.UtcNow;

            //Initialize stage
            for (Int16 i = 0; i < Stage.Length; i++)
            {
                var tmpList = new List<Person>();
                for (Int16 j = 0; j < Stage.Length; j++)
                    tmpList.Add(new Person());
                Stage[i] = tmpList.ToArray();
            }

            //Randomly infect people
            RandomlyInfectPeople(NumberOfPeopleToRandomlyInfect);

            //Run through the periods(NumberOfPeriods times)
            List<MagickImage> output = new List<MagickImage>();
            while (NumberOfPeriods > 0)
            {
                //Print details(verbose)                
                if (VerbosMode && NumberOfPeriods % ImageFrequency == 0)
                {
                    Console.WriteLine("Current Number: " + NumberOfPeriods);
                    Console.WriteLine("Current Mutation: " + MutationNumber);
                    output.Add(BoardToImage());
                }

                Period();
            }

            //Outputs a Animated Gif(verbose)
            if (VerbosMode)
            {
                ImagesToAnimatedGIF(output.ToArray(), Directory.GetCurrentDirectory() + "\\Output.gif");
                System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "\\Output.gif");
            }
            //Only outputs the basic result image matching the specs
            SaveBoardToSimpleImage(Directory.GetCurrentDirectory() + "\\FinalState.gif");

            Console.WriteLine("Total run time in seconds: " + (DateTime.UtcNow - start).TotalSeconds);
            Console.WriteLine("Press enter to exit");
            Console.ReadLine();
        }

        #region Image
        private static void SaveBoardToSimpleImage(string filepath)
        {
            using (Bitmap img = new Bitmap(StageSize, StageSize))
            {
                for (int i = 0; i < img.Width; i++)
                    for (int j = 0; j < img.Height; j++)
                        img.SetPixel(i, j, Stage[i][j].CurrentInfection == 0 ? Color.FromArgb(255, 255, 255) :
                            Color.FromArgb(64, 255, 0));
                img.Save(filepath, ImageFormat.Gif);
            }
        }
        private static MagickImage BoardToImage()
        {
            using (Bitmap img = new Bitmap(StageSize, StageSize))
            {
                for (int i = 0; i < img.Width; i++)
                    for (int j = 0; j < img.Height; j++)
                        img.SetPixel(i, j, Stage[i][j].CurrentInfection == 0 ? Color.White :
                            Color.FromArgb(Stage[i][j].CurrentInfection % 255,
                            Math.Abs(Stage[i][j].CurrentInfection - 255) % 255,
                            Math.Abs(Stage[i][j].CurrentInfection - 510) % 255));
                return new MagickImage(img);
            }
        }
        private static void ImagesToAnimatedGIF(MagickImage[] images, string filepath)
        {
            using (MagickImageCollection collection = new MagickImageCollection())
            {
                foreach (var image in images)
                {
                    collection.Add(image);
                    collection.Last().AnimationDelay = 20;
                }
                collection.Write(filepath);
            }
        }
        #endregion Image

        #region Infection
        private static void Period()
        {
            Infect();
            ChooseRandomInfections();
            IncrementDiseaseProgress();
            Cure();

            NumberOfPeriods--;
        }
        private static void Cure()
        {
            Parallel.For(0, Stage.Length, i =>
            {
                for (Int16 j = 0; j < Stage.Length; j++)
                    if (Stage[i][j].CurrentInfection != 0 && Stage[i][j].InfectionTime == MaxInfectionTime + 1)
                    {
                        //Add disease to already infected list
                        if (Stage[i][j].PreviousInfections.ContainsKey(Stage[i][j].CurrentInfection))
                            Stage[i][j].PreviousInfections[Stage[i][j].CurrentInfection]++;
                        else
                            Stage[i][j].PreviousInfections.Add(Stage[i][j].CurrentInfection, 1);

                        //Cure
                        Stage[i][j].InfectionTime = 0;
                        Stage[i][j].CurrentInfection = 0;
                    }
            });
        }
        private static void IncrementDiseaseProgress()
        {
            Parallel.For(0, Stage.Length, i =>
            {
                for (Int16 j = 0; j < Stage.Length; j++)
                    if (Stage[i][j].CurrentInfection != 0)
                        Stage[i][j].InfectionTime++;
            });
        }
        private static void RandomlyInfectPeople(Int16 numberOfPeopleToInfect)
        {
            var randomList = new List<int>();
            while (randomList.Count() < numberOfPeopleToInfect * 2)
            {
                randomList.Add(RandomGen2.Next(StageSize));
                randomList = randomList.Distinct().ToList();
            }
            while (randomList.Count() > 0)
            {
                Stage[randomList.Last()][randomList[randomList.Count() - 2]].CurrentInfection = MutationNumber;
                Stage[randomList.Last()][randomList[randomList.Count() - 2]].InfectionTime = 1;
                randomList.RemoveAt(randomList.Count() - 2);
                randomList.RemoveAt(randomList.Count() - 1);
            }
        }
        private static void Infect()
        {
            Parallel.For(0, Stage.Length, i =>
            {
                for (Int16 j = 0; j < Stage.Length; j++)
                    InfectAllSpacesAround((short)i, j);
            });
        }
        private static void InfectAllSpacesAround(Int16 x, Int16 y)
        {
            //If not infected or just infected this turn return
            if (Stage[x][y].CurrentInfection == 0 || (Stage[x][y].CurrentInfection != 0 && Stage[x][y].InfectionTime == 0)) return;

            //Infect all four directions(if possible)
            if (x > 0)
                InfectOneSpace(Stage[x][y].CurrentInfection, (short)(x - 1), y);

            if (x < Stage.Length - 1)
                InfectOneSpace(Stage[x][y].CurrentInfection, (short)(x + 1), y);

            if (y > 0)
                InfectOneSpace(Stage[x][y].CurrentInfection, x, (short)(y - 1));

            if (y < Stage.Length - 1)
                InfectOneSpace(Stage[x][y].CurrentInfection, x, (short)(y + 1));
        }
        private static void InfectOneSpace(Int16 currentInfection, Int16 x, Int16 y)
        {
            //If the person is infected, or If they've already been infected "MaxInfectionTime" then don't infect
            if (Stage[x][y].CurrentInfection != 0 || (Stage[x][y].PreviousInfections.ContainsKey(currentInfection) &&
                    Stage[x][y].PreviousInfections[currentInfection] >= MaxInfectionTime)) return;

            //If random is larger than change of transmission don't transmite disease
            if (RandomGen2.Next(100) + 1 > ProbabilityOfTransmission * 100) return;

            //Possible mutate
            if (MutationNumber <= MaxNumberOfMutations && RandomGen2.Next(100) + 1 <= ChanceOfMutation * 100)
                lock (Stage[x][y])
                {
                    MutationNumber++;
                    Stage[x][y].PossibleNewInfections.Add(MutationNumber);
                }
            //Regular infection
            else
                lock (Stage[x][y])
                    Stage[x][y].PossibleNewInfections.Add(currentInfection);

        }
        private static void ChooseRandomInfections()
        {
            Parallel.For(0, Stage.Length, i =>
            {
                for (Int16 j = 0; j < Stage.Length; j++)
                {
                    if (Stage[i][j].CurrentInfection != 0 || !Stage[i][j].PossibleNewInfections.Any()) continue;
                    Stage[i][j].CurrentInfection = Stage[i][j].PossibleNewInfections[RandomGen2.Next(Stage[i][j].PossibleNewInfections.Count)];
                    Stage[i][j].PossibleNewInfections.Clear();
                    Stage[i][j].InfectionTime = 0;
                }
            }
            );
        }
        #endregion Infection
    }

    //Fancy Schmancy new random number generator for threaded stuff, fun times
    //http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx
    public static class RandomGen2
    {
        private static Random _global = new Random();
        [ThreadStatic]
        private static Random _local;

        public static int Next()
        {
            Random inst = _local;
            if (inst == null)
            {
                int seed;
                lock (_global) seed = _global.Next();
                _local = inst = new Random(seed);
            }
            return inst.Next();
        }

        public static int Next(int input)
        {
            Random inst = _local;
            if (inst == null)
            {
                int seed;
                lock (_global) seed = _global.Next();
                _local = inst = new Random(seed);
            }
            return inst.Next(input);
        }
    }
}
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.