เป็นนักระบาดวิทยา!


13

ท้าทาย

คุณต้องสร้างรูปแบบที่เรียบง่ายของการแพร่กระจายของโรครอบกลุ่มคน

กฎและข้อกำหนด

แบบจำลองต้องเป็นอาร์เรย์ 2 มิติ 1,000 คูณ 1,000 แต่ละองค์ประกอบจะเป็นคนละคนกัน

ผู้ใช้จะต้องป้อนตัวแปรสามตัวโดยใช้ argv: ความน่าจะเป็นของการส่งผ่าน (มีแนวโน้มว่ามีใครบางคนกำลังติดเชื้อคนอื่น) โอกาสในการกลายพันธุ์และระยะเวลาที่การจำลองควรทำงาน

ในช่วงแรก ( t=0) คนสี่คนควรได้รับการสุ่มเลือกและติดเชื้อ

วิธีการทำงานของโรคอยู่ภายใต้กฎต่อไปนี้:

  • โรคนี้สามารถเคลื่อนที่ในแนวตั้งและแนวนอนย้ายไปที่บุคคลที่อยู่ถัดไป
  • การติดเชื้อมีระยะเวลา 3 ครั้งในทุกคน คุณไม่สามารถแยกปัจจัยในการสร้างภูมิคุ้มกันโรค
  • หลังจากคนติดเชื้อสามครั้งพวกเขาจะมีภูมิคุ้มกันและไม่สามารถติดเชื้อได้อีก
  • โรคนี้อยู่ภายใต้การกลายพันธุ์ที่ทำให้คนภูมิคุ้มกันก่อนหน้านี้มีความเสี่ยงต่อโรคกลายพันธุ์ใหม่นี้ โรคที่กลายพันธุ์มีลักษณะเหมือนกันทุกประการและเป็นไปตามกฎเดียวกันกับโรคดั้งเดิม
  • หากการกลายพันธุ์เกิดขึ้นโรคทั้งหมดจะไม่เปลี่ยนแปลงเพียง 'แพ็คเก็ต' โดยเฉพาะเมื่อส่งสัญญาณ
  • เมื่อบุคคลได้รับเชื้อไวรัสตัวหนึ่งพวกเขาจะไม่สามารถติดเชื้อได้อีกจนกว่าการติดเชื้อในปัจจุบันจะผ่านไป
  • หากบุคคลนั้นติดเชื้อพวกเขาจะติดเชื้อตั้งแต่เริ่มต้นจนถึงสิ้นสุด
  • ไม่มีระดับภูมิคุ้มกัน - คนมีภูมิคุ้มกันหรือไม่
  • หากต้องการหยุดการโอเวอร์โหลดหน่วยความจำจะมีการ จำกัด การกลายพันธุ์สูงสุด 800 รายการ

เมื่อสิ้นสุดระยะเวลาตามที่ระบุคุณควรแสดงผลลัพธ์

ผลลัพธ์จะต้องเป็นกริด 1,000 x 1,000 รายการที่แสดงว่าคนใดติดไวรัสและคนไหน สามารถส่งออกเป็นไฟล์ข้อความเป็นไฟล์รูปภาพหรือเอาต์พุตกราฟิก (โดยที่ #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 GB คุณจะลบตัวเลือกในการบันทึกผลลัพธ์ในไฟล์รูปภาพอย่างสมบูรณ์ ...
เครื่องมือเพิ่มประสิทธิภาพ

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 นาที

การทดสอบของฉันใช้เวลาประมาณ 6-8 นาทีในเครื่อง Fedora 19, i5 ของฉัน แต่เนื่องจากการสุ่มของการกลายพันธุ์มันอาจจะเร็วกว่าหรือใช้เวลานานกว่านั้น ฉันคิดว่าเกณฑ์การให้คะแนนต้องได้รับการใส่ใหม่

พิมพ์ผลลัพธ์เป็นข้อความเมื่อเสร็จสิ้นบุคคลที่มีสุขภาพแสดงโดย dot ( .) ผู้ติดเชื้อโดยเครื่องหมายดอกจัน ( *) ยกเว้นว่าANIMATEตั้งค่าสถานะเป็นจริงในกรณีนี้จะแสดงอักขระที่แตกต่างกันสำหรับผู้ติดเชื้อไวรัสที่แตกต่างกัน

นี่คือ GIF สำหรับ 10x10, 200 คาบ

10x10Gif

พฤติกรรมการกลายพันธุ์

การกลายพันธุ์แต่ละครั้งจะให้สายพันธุ์ใหม่ที่ไม่เคยเห็นมาก่อน (ดังนั้นจึงเป็นไปได้ที่คนคนหนึ่งจะติดเชื้อสี่คนที่อยู่ใกล้เคียงกับ 4 สายพันธุ์ที่แตกต่างกัน) เว้นแต่จะมี 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 ++ แต่ขนาดโดยรวมจะอยู่ที่ประมาณ 200MB ฉันมีสองกริดเพื่อเก็บขั้นตอนต่อไปดังนั้นทั้งหมดจะใช้ประมาณ 400MB

ฉันจัดเก็บตำแหน่งของผู้ติดเชื้อในคิวเพื่อลดเวลาที่ต้องใช้ในช่วงต้น (ซึ่งมีประโยชน์จริง ๆ ในช่วง <400)

โปรแกรมทางเทคนิค

ทุก ๆ 100 ขั้นตอนโปรแกรมนี้จะพิมพ์จำนวนผู้ติดไวรัสยกเว้นว่าANIMATEตั้งค่าสถานะเป็น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

ในที่สุดฉันก็ได้สร้างเอาต์พุต verbose เกือบ 5 ช่วงเวลา (5 ชั่วโมง) (เพียง 840 เฟรมจากนั้นก็ล้มเหลว) ที่ 1000x1000 ทุก ๆ 1 คาบ แต่ใกล้ถึง 160MB และต้องการหน่วยความจำทั้งหมดในระบบของฉันเพื่อแสดง (IrfanView) ไม่แน่ใจด้วยซ้ำว่าจะใช้งานกับเบราว์เซอร์ได้ไหม

แก้ไข

ฉันใช้เวลากับการทำสิ่งนี้ให้มีประสิทธิภาพมากขึ้นต่อคำตอบ "การสลายตัวเบต้า" ที่ระบุ "เลือกสายพันธุ์แบบสุ่ม" ฉันเลือกวิธีสุ่มเลือกผู้ที่ติดเชื้อใครต่อระยะเวลา แต่ฉันเปลี่ยนวิธีการคำนวณ และนับเป็นทุกสิ่งฉันได้อัปเดตโพสต์ด้วยรายละเอียดใหม่

รหัสการประมาณค่าที่ใกล้เคียงที่สุดของฉันกับสิ่งที่ฉันทำได้ฉันหวังว่ามันจะเป็นไปตามกฎทั้งหมดมันใช้หน่วยความจำจำนวนมากในระบบของฉัน (ประมาณ 1.2GB) โปรแกรมสามารถส่งออก gif เคลื่อนไหว (ดูเจ๋งช้าจริง ๆ ) หรือเพียงแค่ภาพที่ตรงกับสเปค "Beta Decay" นี่เป็นเพียงเล็กน้อยในการฟื้นฟูล้อ แต่ดูดีอย่างแน่นอน:


ผล

(หมายเหตุ: สิ่งนี้มีความแตกต่างเพียงอย่างเดียวระหว่างการติดเชื้อและไม่ติดเชื้อกล่าวคือไม่ได้ verbose)

1000 ช่วงเวลา, อัตราการกลายพันธุ์ 1%, การแพร่กระจาย 100%:

ผลลัพธ์

ตัวอย่าง (ละเอียด)

อย่างไรก็ตามการใช้ 100% "ความน่าจะเป็นของการส่งสัญญาณ" ในโหมดที่ไม่ใช่ verbose นั้นเป็นเรื่องที่น่าเบื่อเพราะคุณจะได้รูปร่างที่เหมือนกันและคุณจะไม่สามารถเห็นการกลายพันธุ์ที่แตกต่างกันได้หากคุณปรับพารามิเตอร์รอบ ๆ บิต คุณจะได้ผลลัพธ์ที่ดูเท่ (GIF แบบเคลื่อนไหวแสดงทุกเฟรมที่ 10):

สุ่ม - ขนาดกริด: 200, ProbTransmission: 100%, ProbMutation: 1%

100Precent

สุ่ม - ขนาดกริด: 200, ProbTransmission: 20%, ProbMutation: 1%

20Precent

เกณฑ์การให้คะแนน

ฉันเห็นด้วยกับ "justhalf" ว่าเกณฑ์การให้คะแนนอาจไม่ยุติธรรมเนื่องจากการวิ่งทุกครั้งจะแตกต่างกันเนื่องจากการสุ่มของการกลายพันธุ์และตำแหน่งของจุดเริ่มต้นแบบสุ่ม บางทีเราอาจทำได้โดยเฉลี่ยในการวิ่งหลายครั้งหรืออะไรทำนองนั้น ... เอาละนี่อยู่ใน 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.