C ++ 11, 6-8 хвилин
Мій тестовий пробіг займає близько 6-8 хвилин на моїй машині Fedora 19, i5. Але через випадковість мутації це може бути швидше або тривати більше часу. Я думаю, що критерії оцінювання потрібно переглянути.
Результат друкується як текст у кінці завершення, здорова людина позначається крапкою ( .
), заражена людина зірочкою ( *
), якщо ANIMATE
прапор не встановлено як істинне; у цьому випадку він відображатиме різні символи для людей, заражених різним штамом вірусу.
Ось GIF на 10х10, 200 періодів.
Мутаційна поведінка
Кожна мутація дасть новий шум, який ніколи не бачили (тому можливо, що одна людина заразила чотирьох сусідніх людей чотирма різними штамами), якщо не буде сформовано 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;
}