Sii un epidemiologo!


13

Sfida

È necessario creare un modello semplice di come la malattia si diffonde in un gruppo di persone.

Regole e requisiti

Il modello deve essere un array 2D 1000 per 1000 con ogni elemento diverso da una persona.

L'utente deve inserire tre variabili usando argv: la probabilità di trasmissione (la probabilità che qualcuno infetti qualcun altro), la possibilità di mutazione e il numero di periodi per i quali deve essere eseguita la simulazione.

Nel primo periodo ( t=0), quattro persone dovrebbero essere scelte in modo casuale e infettate dalla malattia.

Il modo in cui la malattia si comporta è regolato dalle seguenti regole:

  • La malattia può spostarsi solo in verticale e in orizzontale, passando alla persona della porta accanto.
  • L'infezione dura 3 periodi in ogni persona. Non è possibile considerare le immunodeficienze.
  • Dopo che una persona è stata infettata tre volte, è immune e non può più essere infettata.
  • La malattia è soggetta a mutazione che rende le persone precedentemente immuni vulnerabili a questa nuova malattia mutata. La malattia mutata ha esattamente gli stessi tratti e segue le stesse regole della malattia originale.
  • Se si verifica una mutazione, l'intera malattia non cambia, solo quel particolare "pacchetto" al momento della trasmissione.
  • Una volta che una persona è stata infettata da un virus, non può più essere infettata finché non passa l'infezione attuale.
  • Se una persona è infetta, è contagiosa dall'inizio del periodo di infezione fino alla fine.
  • Non ci sono livelli di immunità: una persona è immune o no.
  • Per arrestare il sovraccarico di memoria, esiste un limite massimo di 800 mutazioni.

Alla fine del numero di periodi specificato, è necessario generare i risultati.

I risultati devono essere una griglia 1000 x 1000 che mostra quali persone sono infette e quali non lo sono. Questo può essere emesso come file di testo, come file immagine o output grafico (dove #FFFFFF è una persona sana e # 40FF00 è una persona infetta).

Per favore, puoi includere il nome della lingua e un comando per eseguirlo nella tua risposta.

vincente

Vince il codice più veloce da eseguire sul mio computer. Il suo tempo verrà misurato con il seguente pezzo di codice Python:

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

Si noti che durante l'esecuzione di questo script, userò i seguenti valori predefiniti:

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

3
Vuoi fare un file da 10 gigabyte ?
Ypnypn,

1
Avendo un limite di 4 GB, hai completamente rimosso l'opzione di salvare l'output nel file di immagine ...
Ottimizzatore

10
1000x1000 : è più simile!
COTO

1
Dì anche che ci sono due persone una accanto all'altra. Il primo contrae il virus V, il secondo contrae il virus V'. La contrazione terminerà entrambi nello stesso periodo. Il virus può Vinfettare la seconda persona? (O una domanda più in bianco e nero: è possibile che una persona sia infettata subito dopo la sua guarigione, quindi finirà con 6 periodi consecutivi di infezione?)
solo

1
Un altro, due virus indipendenti possono mutare nello stesso virus? Di 'che abbiamo Vdi persona Ae di Vnuovo di persona B. Quando trasmettono il virus, possono entrambi mutare nella stessa mutazione V'? O forse in realtà dovrebbero mutare nello stesso ceppo virale? Se possono mutare arbitrariamente, qual è la probabilità che due virus mutino nello stesso ceppo virale?
solo

Risposte:


10

Ero curioso di sapere come sarebbe stato, quindi ho fatto questo hack rapido e sporco in JavaScript: 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
Impostare infezione La probabilità su 1 ha creato alcuni dei modelli più dolci che abbia mai visto!
William Barbosa,

Potresti aggiungere quanto tempo impiega il tuo programma alla tua risposta?
Decadimento beta

7

C ++ 11, 6-8 minuti

Il mio test dura circa 6-8 minuti nella mia macchina Fedora 19, i5. Ma a causa della casualità della mutazione, potrebbe anche essere più veloce o richiedere più tempo. Penso che i criteri di punteggio debbano essere rivisitati.

Stampa il risultato come testo al termine del completamento, persona sana indicata da punto ( .), persona infetta da asterisco ( *), a meno che la ANIMATEbandiera non sia impostata su true, nel qual caso mostrerà caratteri diversi per le persone infette da un diverso ceppo virale.

Ecco una GIF per 10x10, 200 periodi.

10x10Gif

Comportamento mutazione

Ogni mutazione produrrà un nuovo ceppo mai visto prima (quindi è possibile che una persona contagini le quattro persone vicine con 4 ceppi distinti), a meno che non siano stati generati 800 ceppi, nel qual caso nessun virus andrà in ulteriore mutazione.

Il risultato di 8 minuti proviene dal seguente numero di persone infette:

Periodo 0, infetto: 4
Periodo 100, infetto: 53743
Periodo 200, infetto: 134451
Periodo 300, infetto: 173369
Periodo 400, infetto: 228176
Periodo 500, infetto: 261473
Periodo 600, infetto: 276086
Periodo 700, infetto: 265774
Periodo 800, infetto: 236828
Periodo 900, infetto: 221275

mentre il risultato di 6 minuti deriva da quanto segue:

Periodo 0, infetto: 4
Periodo 100, infetto: 53627
Periodo 200, infetto: 129033
Periodo 300, infetto: 186127
Periodo 400, infetto: 213633
Periodo 500, infetto: 193702
Periodo 600, infetto: 173995
Periodo 700, infetto: 157966
Periodo 800, infetto: 138281
Periodo 900, infetto: 129381

Rappresentazione della persona

Ogni persona è rappresentata in 205 byte. Quattro byte per memorizzare il tipo di virus che questa persona sta contraendo, un byte per memorizzare da quanto tempo questa persona è stata infettata e 200 byte per memorizzare quante volte ha contratto ogni ceppo di virus (2 bit ciascuno). Forse c'è qualche ulteriore allineamento di byte fatto da C ++, ma la dimensione totale sarà di circa 200 MB. Ho due griglie per memorizzare il passaggio successivo, quindi in totale utilizza circa 400 MB.

Conservo la posizione delle persone infette in una coda, per ridurre il tempo richiesto nei primi periodi (che è davvero utile fino a periodi <400).

Tecnici del programma

Ogni 100 passaggi questo programma stampa il numero di persone infette, a meno ANIMATEche non sia impostato flag true, nel qual caso stampa l'intera griglia ogni 100 ms.

Ciò richiede librerie C ++ 11 (compilare usando -std=c++11flag o in Mac con clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread).

Eseguilo senza argomenti per i valori predefiniti o con argomenti come questo:

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

Mi piace molto questo! La mia unica domanda è come si realizza la GIF?
Decadimento beta

1
Sto usando questo strumento: linux.die.net/man/1/byzanz-record . Attualmente non ha la GUI, quindi dovrai usare la riga di comando = D
solo il

Oh, è carino, grazie! :)
Decadimento beta

3

C # 6-7 minuti

Modifica 2

Alla fine (5 ore) ho generato un output dettagliato per quasi 1000 periodi (solo 840 frame poi si è bloccato) a 1000x1000, ogni 1 periodo, tuttavia è vicino a 160 MB e richiede tutta la memoria del mio sistema per visualizzare (IrfanView) , nemmeno sicuro che funzionerebbe in un browser, potrei metterlo su più tardi.

MODIFICARE

Ho dedicato molto tempo a rendere questo più efficiente per la risposta di "Beta Decay" affermando "Scegli la deformazione in modo casuale" Ho scelto solo il metodo casuale per scegliere chi infetta chi per periodo, tuttavia ho cambiato il modo in cui è calcolato e risolto tutto, ho aggiornato i miei post con i nuovi dettagli.

Ho codificato la mia stima più vicina a ciò che potevo, spero che segua tutte le regole, usi una tonnellata di memoria sul mio sistema (circa 1,2 GB). Il programma può produrre gif animate (sembra bello, molto lento) o solo un'immagine che corrisponde alle specifiche di "Beta Decay". Questo è un po 'di reinventare la ruota, ma sicuramente sembra fantastico:


risultati

(Nota: questo distingue solo tra infetti e non infetti, cioè non verbosi)

1000 periodi, 1% di mutazione, 100% di diffusione:

Risultato

Esempi (verbose)

Ad ogni modo usare il 100% di "Probabilità di trasmissione" in modalità non dettagliata è un po 'noioso in quanto ottieni sempre le stesse forme e non puoi vedere le diverse mutazioni, se modifichi i parametri intorno a un bit (e abiliti la modalità dettagliata) ottieni un risultato interessante (le GIF animate vengono visualizzate ogni 10 frame):

Casuale - Dimensione griglia: 200, ProbTransmission: 100%, ProbMutation: 1%

100Precent

Casuale - Dimensione griglia: 200, ProbTransmission: 20%, ProbMutation: 1%

20Precent

punteggio

Concordo con "justhalf" sul fatto che i criteri di punteggio potrebbero non essere giusti in quanto ogni corsa differirà a causa della casualità delle mutazioni e della posizione dei punti di partenza casuali. Forse potremmo fare la media di diverse corse o qualcosa del genere ..., beh comunque questo è in C # quindi taglie per me :( comunque.

Codice

Assicurati di includere la libreria MagickImage (impostata per compilare x64 bit) altrimenti non verrà compilata ( 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);
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.