Будьте епідеміологом!


13

Виклик

Ви повинні створити просту модель того, як хвороба поширюється на групу людей.

Правила та вимоги

Модель має бути двовимірним набором 1000 на 1000, кожен елемент має іншу особу.

Користувач повинен ввести три змінні, використовуючи argv: ймовірність передачі (наскільки ймовірно, що хтось збирається заразити когось іншого), шанс мутації та скільки періодів має тривати моделювання.

У перший період ( t=0) чотири людини повинні бути обрані випадковим чином та заражені хворобою.

Спосіб поведінки захворювання регулюється такими правилами:

  • Хвороба може рухатися тільки вертикально і горизонтально, рухаючись до людини поруч.
  • Інфекція триває 3 періоди у кожної людини. Ви не можете брати участь у імунодефіциті.
  • Після того, як людина заразилася тричі, вона перебуває в імунітеті і не може заразитися знову.
  • Захворювання піддається мутації, роблячи раніше імунізованих людей вразливими до цієї нової мутованої хвороби. Мутоване захворювання має абсолютно ті ж ознаки і дотримується тих же правил, що і первісне захворювання.
  • Якщо відбувається мутація, вся хвороба не змінюється, саме той конкретний "пакет" при передачі.
  • Після того, як людина заразилася одним вірусом, вона не може бути заражена знову, поки поточна інфекція не пройде.
  • Якщо людина заражена, то вона заразна від початку періоду зараження до кінця.
  • Рівень імунітету немає - людина або імунна, або ні.
  • Щоб зупинити перевантаження пам'яті, існує максимальна межа 800 мутацій.

Після закінчення вказаної кількості періодів слід вивести результати.

Результати повинні бути сіткою 1000 х 1000, яка показує, які люди заражені, а які - ні. Це може виводитись як текстовий файл, як файл зображення або графічний вихід (де #FFFFFF - здорова людина, а # 40FF00 - заражена людина).

Будь ласка, можете включити ім’я мови та команду для запуску у відповідь.

Перемога

Виграє найшвидший код на моєму комп’ютері. Його час буде вимірюватися наступним фрагментом коду Python:

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

Зауважте, що під час запуску цього сценарію я буду використовувати такі типові настройки:

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

3
Ви хочете створити 10- гігабайтний файл?
Ypnypn

1
Маючи обмеження в 4 ГБ, ви повністю видалили можливість збереження виводу у файл зображення ...
Optimizer

10
1000x1000 : Це більше подобається!
COTO

1
Також скажіть, що поруч є двоє людей. Перший контрактує вірус V, другий контрактує вірус V'. Скорочення закінчується в той же період. Чи може вірус Vзаражати другу людину? (Або більш чорно-біле питання: чи можливо, що людина заразиться одразу після того, як вилікується, тож у нього закінчиться 6 період поспіль зараження?)
justhalf

1
Ще один, чи можуть два незалежні віруси мутувати до одного вірусу? Скажімо, у нас Vособисто A, і Vзнову особисто B. Чи можуть вони передати вірус, коли вони передають вірус, однакову мутацію V'? Чи, можливо, вони насправді повинні мутувати на той самий штам вірусу? Якщо вони можуть мутувати довільно, яка ймовірність двох вірусів мутувати до одного і того ж штаму вірусу?
justhalf

Відповіді:


10

Мені було цікаво, як це буде виглядати, тому я зробив цей швидкий і брудний злом у 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
Встановлення інфекціїProbability на 1 зробило кілька найсолодших моделей, які я бачив!
Вільям Барбоса

Чи можете ви додати, скільки часу займає ваша програма, щоб відповісти?
Бета-розпад

7

C ++ 11, 6-8 хвилин

Мій тестовий пробіг займає близько 6-8 хвилин на моїй машині Fedora 19, i5. Але через випадковість мутації це може бути швидше або тривати більше часу. Я думаю, що критерії оцінювання потрібно переглянути.

Результат друкується як текст у кінці завершення, здорова людина позначається крапкою ( .), заражена людина зірочкою ( *), якщо ANIMATEпрапор не встановлено як істинне; у цьому випадку він відображатиме різні символи для людей, заражених різним штамом вірусу.

Ось GIF на 10х10, 200 періодів.

10x10Gif

Мутаційна поведінка

Кожна мутація дасть новий шум, який ніколи не бачили (тому можливо, що одна людина заразила чотирьох сусідніх людей чотирма різними штамами), якщо не буде сформовано 800 штамів, і в цьому випадку жоден вірус не піде на подальшу мутацію.

8-хвилинний результат походить від такої кількості заражених:

Період 0, заражений: 4
Період 100, Заражений: 53743
Період 200, Заражений: 134451
Період 300, Заражений: 173369
Період 400, Заражений: 228176
Період 500, заражений: 261473
Період 600, Заражений: 276086
Період 700, Заражений: 265774
Період 800, Заражений: 236828
Період 900, Заражений: 221275

тоді як 6-хвилинний результат виходить з наступного:

Період 0, заражений: 4
Період 100, Заражений: 53627
Період 200, Заражений: 129033
Період 300, Заражений: 186127
Період 400, Заражений: 213633
Період 500, заражений: 193702
Період 600, Заражений: 173995
Період 700, Заражений: 157966
Період 800, Заражений: 138281
Період 900, Заражений: 129381

Представництво особи

Кожна людина представлена ​​в 205 байтах. Чотири байти для зберігання типу вірусу ця людина заражається, один байт для зберігання того часу, як ця людина заразився, і 200 байт для зберігання, скільки разів він заразився кожним штамом вірусу (по 2 біта кожен). Можливо, є додаткове вирівнювання байтів, виконане C ++, але загальний розмір буде близько 200 МБ. У мене є дві сітки для зберігання наступного кроку, тому в цілому він використовує близько 400 Мб.

Я зберігаю розташування заражених людей у ​​черзі, щоб скоротити час, необхідний на ранніх періодах (що справді корисно до періодів <400).

Технічні можливості програми

Кожні 100 кроків у цій програмі буде надруковано кількість заражених людей, якщо ANIMATEне встановлено прапор true, і в цьому випадку вона надрукує всю сітку кожні 100 мс.

Для цього потрібні бібліотеки C ++ 11 (компілювати за допомогою -std=c++11прапора або в Mac з clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread).

Запустити його без аргументів для значень за замовчуванням або з такими аргументами:

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

Мені це дуже подобається! Єдине моє питання - як зробити GIF?
бета-розпад

1
Я використовую цей інструмент: linux.die.net/man/1/byzanz-record . Наразі у нього немає графічного інтерфейсу, тому вам потрібно буде використовувати командний рядок = D
justhalf

О, це приємно, дякую! :)
бета-розпад

3

C # 6-7 хвилин

Редагувати 2

Нарешті, я (5 годин) генерував багатослівний вихід протягом майже 1000 періодів (лише 840 кадрів, тоді він вийшов з ладу) на 1000x1000, кожні 1 період, однак близько до 160 Мб і для відображення потрібна вся пам'ять у моїй системі (IrfanView) , навіть не впевнений, що це буде працювати у браузері. Можливо, я викладу це пізніше.

EDIT

Я витратив багато часу на те, щоб зробити це більш ефективним на відповідь "Бета-розпад", вказавши "Вибрати штам випадковим чином". У мене є вибір лише випадкового методу для вибору того, хто заражає, хто за період, проте я змінив спосіб, який розраховується і вишикував кожну річ, я оновлював свої публікації новими деталями.

Зашифрував мою найближчу оцінку до цього, я міг би сподіватися, що він дотримується всіх правил, він використовує тонну пам'яті в моїй системі (близько 1,2 ГБ). Програма може виводити анімовані gif (виглядає круто, дуже повільно) або просто зображення, що відповідає специфікаціям "Beta Decay". Це трохи винаходить колесо, але, безумовно, виглядає круто:


Результати

(Примітка. Це розрізняє лише інфікованих та незаражених, тобто невербальних)

1000 періодів, 1% коефіцієнт мутації, 100% поширення:

Результат

Приклади (багатослівний)

У будь-якому випадку використання 100% "ймовірності передачі" в невербальному режимі є дещо нудним, оскільки ви завжди отримуєте однакові форми і не можете побачити різні мутації, якщо налаштувати параметри навколо a-bit (і включити багатослівний режим) Ви отримуєте чудовий вигляд (анімовані GIF-зображення відображаються кожен 10-й кадр):

Випадкові - розмір сітки: 200, передача передачі даних: 100%, модуляція випробувань: 1%

100 відсотків

Випадкові - розмір сітки: 200, передача передачі даних: 20%, модуляція випробувань: 1%

20Процент

Оцінка балів

Я погоджуюся з "справедливою полицею", що критерії оцінки можуть бути не справедливими, оскільки кожен пробіг буде відрізнятися через випадковість мутацій та положення випадкових стартових точок. Можливо, ми могли б виконати в середньому кілька пробіжок або щось подібне ..., так чи інакше це в C # так для мене щедро :( все одно.

Код

Не забудьте включити бібліотеку MagickImage (встановлена ​​для компіляції x64 біт), інакше вона не буде складена ( 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);
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.