C ++ 11, 6-8 menit
Uji coba saya memakan waktu 6-8 menit di mesin Fedora 19, i5 saya. Tetapi karena keacakan mutasi, mungkin lebih cepat atau lebih lama dari itu. Saya pikir kriteria penilaian perlu disusun kembali.
Mencetak hasilnya sebagai teks pada akhir penyelesaian, orang sehat dilambangkan dengan titik (.
), orang yang terinfeksi oleh asterisk ( *
), kecuali jika ANIMATE
flag disetel ke true, dalam hal ini akan menampilkan karakter yang berbeda untuk orang yang terinfeksi dengan strain virus yang berbeda.
Berikut adalah GIF untuk 10x10, 200 periode.
Perilaku mutasi
Setiap mutasi akan memberikan galur baru yang tidak pernah terlihat sebelumnya (jadi mungkin satu orang menginfeksi empat orang tetangga dengan 4 galur berbeda), kecuali 800 galur telah dihasilkan, dalam hal ini tidak ada virus yang akan mengalami mutasi lebih lanjut.
Hasil 8 menit berasal dari jumlah orang yang terinfeksi berikut:
Periode 0, Terinfeksi: 4
Periode 100, Terinfeksi: 53743
Periode 200, Terinfeksi: 134451
Periode 300, Terinfeksi: 173369
Periode 400, Terinfeksi: 228176
Periode 500, Terinfeksi: 261473
Periode 600, Terinfeksi: 276086
Periode 700, Terinfeksi: 265774
Periode 800, Terinfeksi: 236828
Periode 900, Terinfeksi: 221275
sedangkan hasil 6 menit berasal dari yang berikut:
Periode 0, Terinfeksi: 4
Periode 100, Terinfeksi: 53627
Periode 200, Terinfeksi: 129033
Periode 300, Terinfeksi: 186127
Periode 400, Terinfeksi: 213633
Periode 500, Terinfeksi: 193702
Periode 600, Terinfeksi: 173995
Periode 700, Terinfeksi: 157966
Periode 800, Terinfeksi: 138281
Periode 900, Terinfeksi: 129381
Representasi orang
Setiap orang diwakili dalam 205 byte. Empat byte untuk menyimpan jenis virus yang dikontrak oleh orang ini, satu byte untuk menyimpan berapa lama orang ini telah terinfeksi, dan 200 byte untuk menyimpan berapa kali ia telah mengontrak setiap jenis virus (masing-masing 2 bit). Mungkin ada beberapa byte-alignment yang dilakukan oleh C ++, tetapi ukuran totalnya sekitar 200MB. Saya memiliki dua kotak untuk menyimpan langkah selanjutnya, jadi totalnya menggunakan sekitar 400MB.
Saya menyimpan lokasi orang yang terinfeksi dalam antrian, untuk memotong waktu yang diperlukan pada periode awal (yang benar-benar berguna hingga periode <400).
Teknis program
Setiap 100 langkah program ini akan mencetak jumlah orang yang terinfeksi, kecuali jika ANIMATE
flag ditetapkan true
, dalam hal ini akan mencetak seluruh grid setiap 100 ms.
Ini membutuhkan pustaka C ++ 11 (kompilasi menggunakan -std=c++11
flag, atau di Mac with clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
).
Jalankan tanpa argumen untuk nilai default, atau dengan argumen seperti ini:
./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;
}