C ++ 11, 6-8 dakika
Test çalışmam Fedora 19, i5 makinemde yaklaşık 6-8 dakika sürüyor. Ancak mutasyonun rastgele olması nedeniyle, daha hızlı olabilir veya bundan daha uzun sürebilir. Bence puanlama kriterlerinin yeniden okunması gerekiyor.
Sonuç, tamamlanma sonunda metin olarak, nokta doğru ( .
) ile gösterilen sağlıklı bir kişi , yıldız işareti ( *
) ile enfekte olmuş bir kişi olarak, ANIMATE
bayrak doğru olarak ayarlanmadığı sürece yazdırılır, bu durumda farklı virüs türünden etkilenen kişiler için farklı karakterler görüntülenir.
İşte 10x10, 200 dönem için bir GIF.
Mutasyon davranışı
Her bir mutasyon, daha önce hiç görülmemiş yeni bir suş verecektir (bu nedenle, 800 suş üretilmedikçe, herhangi bir virüs daha fazla mutasyona girmeyecekse, bir komşu dört farklı suşa dört kişiyi enfekte etmek mümkündür).
8 dakikalık sonuç aşağıdaki sayıda enfekte kişiden gelir:
Dönem 0, Enfekte: 4
Dönem 100, Enfekte: 53743
Dönem 200, Enfekte: 134451
Dönem 300, Enfekte: 173369
Dönem 400, Enfekte: 228176
Dönem 500, Enfekte: 261473
Periyot 600, Enfekte: 276086
Periyod 700, Enfeksiyon: 265774
Periyod 800, Enfekte: 236828
Dönem 900, Enfeksiyon: 221275
6 dakikalık sonuç aşağıdakilerden gelir:
Dönem 0, Enfekte: 4
Dönem 100, Enfekte: 53627
Dönem 200, Enfeksiyon: 129033
Dönem 300, Enfekte: 186127
Dönem 400, Enfekte: 213633
Dönem 500, Enfekte: 193702
Periyot 600, Enfekte: 173995
Periyod 700, Enfeksiyon: 157966
Periyod 800, Enfekte: 138281
Dönem 900, Enfeksiyon: 129381
Kişi temsilciliği
Her kişi 205 bayt ile temsil edilir. Bu kişinin kasıldığı virüs tipini saklamak için dört bayt, bu kişiye ne kadar süredir bulaştığını depolamak için bir bayt ve her bir virüs suşunu kaç kez büzdüğünü saklamak için 200 bayt (her biri 2 bit). Belki de C ++ tarafından yapılan bazı ek bayt hizalama vardır, ancak toplam boyut 200MB civarında olacaktır. Bir sonraki adımı saklamak için iki ızgaram var, bu yüzden toplamda 400MB kullanıyor.
Enfekte kişilerin yerini bir sırada saklıyorum, erken dönemlerde gerekli zamanı kesmek için (<400'e kadar dönemler için gerçekten yararlı).
Program özellikleri
Her 100 adımda bir, ANIMATE
bayrak ayarlanmadıkça virüs bulaşmış kişi sayısını basar, true
bu durumda tüm ızgarayı her 100 ms'de bir yazdırır.
Bu, C ++ 11 kitaplıklarını gerektirir ( -std=c++11
bayrak kullanarak derleme veya ile Mac'te clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
).
Varsayılan değerler için bağımsız değişkenler olmadan veya aşağıdaki gibi bağımsız değişkenlerle çalıştırın:
./virus_spread 1 0.01 1000
#include <cstdio>
#include <cstring>
#include <random>
#include <cstdlib>
#include <utility>
#include <iostream>
#include <deque>
#include <cmath>
#include <functional>
#include <unistd.h>
typedef std::pair<int, int> pair;
typedef std::deque<pair> queue;
const bool ANIMATE = false;
const int MY_RAND_MAX = 999999;
std::default_random_engine generator(time(0));
std::uniform_int_distribution<int> distInt(0, MY_RAND_MAX);
auto randint = std::bind(distInt, generator);
std::uniform_real_distribution<double> distReal(0, 1);
auto randreal = std::bind(distReal, generator);
const int VIRUS_TYPE_COUNT = 800;
const int SIZE = 1000;
const int VIRUS_START_COUNT = 4;
typedef struct Person{
int virusType;
char time;
uint32_t immune[VIRUS_TYPE_COUNT/16];
} Person;
Person people[SIZE][SIZE];
Person tmp[SIZE][SIZE];
queue infecteds;
double transmissionProb = 1.0;
double mutationProb = 0.01;
int periods = 1000;
char inline getTime(Person person){
return person.time;
}
char inline getTime(int row, int col){
return getTime(people[row][col]);
}
Person inline setTime(Person person, char time){
person.time = time;
return person;
}
Person inline addImmune(Person person, uint32_t type){
person.immune[type/16] += 1 << (2*(type % 16));
return person;
}
bool inline infected(Person person){
return getTime(person) > 0;
}
bool inline infected(int row, int col){
return infected(tmp[row][col]);
}
bool inline immune(Person person, uint32_t type){
return (person.immune[type/16] >> (2*(type % 16)) & 3) == 3;
}
bool inline immune(int row, int col, uint32_t type){
return immune(people[row][col], type);
}
Person inline infect(Person person, uint32_t type){
person.time = 1;
person.virusType = type;
return person;
}
bool inline infect(int row, int col, uint32_t type){
auto person = people[row][col];
auto tmpPerson = tmp[row][col];
if(infected(tmpPerson) || immune(tmpPerson, type) || infected(person) || immune(person, type)) return false;
person = infect(person, type);
infecteds.push_back(std::make_pair(row, col));
tmp[row][col] = person;
return true;
}
uint32_t inline getType(Person person){
return person.virusType;
}
uint32_t inline getType(int row, int col){
return getType(people[row][col]);
}
void print(){
for(int row=0; row < SIZE; row++){
for(int col=0; col < SIZE; col++){
printf("%c", infected(row, col) ? (ANIMATE ? getType(row, col)+48 : '*') : '.');
}
printf("\n");
}
}
void move(){
for(int row=0; row<SIZE; ++row){
for(int col=0; col<SIZE; ++col){
people[row][col] = tmp[row][col];
}
}
}
int main(const int argc, const char **argv){
if(argc > 3){
transmissionProb = std::stod(argv[1]);
mutationProb = std::stod(argv[2]);
periods = atoi(argv[3]);
}
int row, col, size;
uint32_t type, newType=0;
char time;
Person person;
memset(people, 0, sizeof(people));
for(int row=0; row<SIZE; ++row){
for(int col=0; col<SIZE; ++col){
people[row][col] = {};
}
}
for(int i=0; i<VIRUS_START_COUNT; i++){
row = randint() % SIZE;
col = randint() % SIZE;
if(!infected(row, col)){
infect(row, col, 0);
} else {
i--;
}
}
move();
if(ANIMATE){
print();
}
for(int period=0; period < periods; ++period){
size = infecteds.size();
for(int i=0; i<size; ++i){
pair it = infecteds.front();
infecteds.pop_front();
row = it.first;
col = it.second;
person = people[row][col];
time = getTime(person);
if(time == 0) continue;
type = getType(person);
if(row > 0 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row-1, col, newType)) newType--;
} else {
infect(row-1, col, type);
}
}
if(row < SIZE-1 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row+1, col, newType)) newType--;
} else {
infect(row+1, col, type);
}
}
if(col > 0 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row, col-1, newType)) newType--;
} else {
infect(row, col-1, type);
}
}
if(col < SIZE-1 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row, col+1, newType)) newType--;
} else {
infect(row, col+1, type);
}
}
time += 1;
if(time == 4) time = 0;
person = setTime(person, time);
if(time == 0){
person = addImmune(person, type);
} else {
infecteds.push_back(std::make_pair(row, col));
}
tmp[row][col] = person;
}
if(!ANIMATE && period % 100 == 0) printf("Period %d, Size: %d\n", period, size);
move();
if(ANIMATE){
printf("\n");
print();
usleep(100000);
}
}
if(!ANIMATE){
print();
}
return 0;
}