전염병 학자가 되십시오!


13

도전

한 그룹의 사람들에게 질병이 어떻게 퍼지는 지에 대한 간단한 모델을 만들어야합니다.

규칙 및 요구 사항

모델은 1000 x 1000 2D 배열이어야하며 각 요소는 서로 다른 사람이어야합니다.

사용자는 argv를 사용하여 전송 확률 (누군가가 다른 사람을 감염시킬 가능성이 있는지), 돌연변이 가능성 및 시뮬레이션을 실행해야하는 기간의 세 가지 변수를 입력해야합니다.

첫 번째 기간 ( t=0)에는 4 명이 무작위로 선택되어 질병에 감염되어야합니다.

질병의 행동 방식은 다음 규칙에 따라 결정됩니다.

  • 질병은 세로 및 가로로만 움직일 수 있으며 옆집 사람으로 이동합니다.
  • 감염은 모든 사람에게 3 기간 동안 지속됩니다. 면역 결핍을 고려하지 않을 수 있습니다.
  • 사람이 세 번 감염된 후에는 면역성이 있으며 다시 감염 될 수 없습니다.
  • 이 질병은 돌연변이를 일으켜 이전에 면역 된 사람들을이 새로운 돌연변이 질병에 취약하게 만듭니다. 변이 된 질병은 정확히 동일한 특성을 가지며 원래 질병과 동일한 규칙을 따릅니다.
  • 돌연변이가 발생하면 전염병이 변하지 않으며 전염시 특정 '패킷'만 변경됩니다.
  • 한 바이러스에 감염된 사람은 현재 감염이 통과 할 때까지 다시 감염 될 수 없습니다.
  • 사람이 감염된 경우 감염 기간 시작부터 끝까지 전염성이 있습니다.
  • 면역력이 없습니다-사람은 면역력이 있는지 여부입니다.
  • 메모리 과부하를 막기 위해 최대 800 개의 돌연변이가 있습니다.

지정된 기간이 끝나면 결과를 출력해야합니다.

결과는 감염된 사람과 감염되지 않은 사람을 나타내는 1000 x 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
4GB 제한이 있으면 이미지 파일에 출력을 저장하는 옵션이 완전히 제거되었습니다.
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
감염 설정 확률을 1로 설정하면 내가 본 가장 달콤한 패턴을 만들었습니다!
William Barbosa

귀하의 프로그램이 답변에 얼마나 시간을 추가 할 수 있습니까?
Beta Decay

7

C ++ 11, 6-8 분

Fedora 19, i5 컴퓨터에서 테스트 실행에 약 6-8 분이 걸립니다. 그러나 돌연변이의 무작위성으로 인해 그보다 더 빠르거나 오래 걸릴 수 있습니다. 점수 기준을 다시 정해야한다고 생각합니다.

플래그가 true로 설정 되지 않은 경우 완료 후 끝에 텍스트, 점 ( .)으로 표시된 건강한 사람 , 별표 ( *)로 감염된 사람으로 결과를 텍스트로 인쇄합니다 ANIMATE.이 경우 다른 바이러스 균주에 감염된 사람들에 대해 다른 문자가 표시됩니다.

다음은 10x10, 200 기간의 GIF입니다.

10x10 기프

돌연변이 행동

800 개 균주가 생성되지 않는 한, 각각의 돌연변이는 이전에 전혀 볼 수 없었던 새로운 균주를 이전에 볼 수 없었을 것이다 (따라서 한 사람이 4 명의 다른 균주로 4 명의 균주를 감염시킬 수있다).

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 바이트로 표시됩니다. 이 사람이 계약 한 바이러스 유형을 저장하기위한 4 바이트,이 사람이 감염된 기간을 저장하기위한 1 바이트 및 각 바이러스 변종 (각각 2 비트)을 계약 한 횟수를 저장하는 200 바이트. 아마도 C ++에서 추가 바이트 정렬이 있지만 총 크기는 약 200MB입니다. 다음 단계를 저장할 두 개의 그리드가 있으므로 총 400MB를 사용합니다.

감염된 사람의 위치를 ​​대기열에 저장하여 초기 기간에 필요한 시간을 줄입니다 (최대 400 개 미만의 기간에 유용함).

프로그램 기술

ANIMATE플래그가로 설정되어 있지 않는 한이 프로그램은 100 단계마다 감염된 사람의 수를 인쇄합니다 true.이 경우 100ms마다 전체 그리드를 인쇄합니다.

이를 위해서는 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를 만드나요?
Beta Decay

1
이 도구를 사용하고 있습니다 : linux.die.net/man/1/byzanz-record를 . 현재 GUI가 없으므로 명령 줄 = D
justhalf

오, 감사합니다! :)
Beta Decay

3

C # 6-7 분

편집 2

나는 마침내 1 시간마다 1000x1000에서 1000 시간에 가까운 (약 840 프레임 후 충돌) 장황한 출력을 생성했지만 160MB에 가깝고 시스템의 모든 메모리를 표시해야합니다 (IrfanView) 브라우저에서 작동하는지 확실하지 않은 경우 나중에 다시 설명하겠습니다.

편집하다

나는 "Beta Decay"의 대답에 따라 "균주를 무작위로 선택하십시오"라는 답변에 따라이 작업을보다 효율적으로 만드는 데 많은 시간을 보냈습니다. 기간 당 누가 감염자를 선택하는 무작위 방법 만 선택했지만 계산 방법을 변경했습니다. 모든 것을 처리하기 위해 새로운 세부 사항으로 게시물을 업데이트했습니다.

내가 할 수있는 가장 가까운 평가를 코딩하여 모든 규칙을 따르기를 바랍니다. 시스템의 메모리 (약 1.2GB)를 사용합니다. 이 프로그램은 애니메이션 gif (차가워 요, 느리게 보임) 또는 "Beta Decay"사양과 일치하는 이미지 만 출력 할 수 있습니다. 이것은 바퀴를 재발견하는 약간이지만, 멋지게 보입니다.


결과

(참고 : 이것은 감염된 것과 감염되지 않은, 즉 상세하지 않은 것만 구별합니다)

1000주기, 1 % 돌연변이 속도, 100 % 확산 :

결과

예 (자세한 내용)

어쨌든 non-verbose 모드에서 100 % "전송 가능성"을 사용하는 것은 항상 같은 모양을 취하기 때문에 지루한 종류입니다. 당신은 멋진 찾고 출력을 얻습니다 (애니메이션 GIF는 매 10 프레임마다 표시됩니다) :

랜덤-그리드 크기 : 200, ProbTransmission : 100 %, ProbMutation : 1 %

100Precent

랜덤-그리드 크기 : 200, ProbTransmission : 20 %, ProbMutation : 1 %

20Precent

채점

나는 돌연변이의 무작위성과 무작위 시작점의 위치로 인해 모든 실행이 다를 수 있기 때문에 점수 기준이 공평하지 않을 수 있다는 "정의"에 동의합니다. 어쩌면 우리는 몇 번의 런 또는 그와 비슷한 것을 할 수 있습니다 ..., 어쨌든 이것은 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);
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.