C ++ 11, 6-8 minutes
Mon test dure environ 6 à 8 minutes sur ma machine Fedora 19, i5. Mais en raison du caractère aléatoire de la mutation, elle pourrait aussi bien être plus rapide ou prendre plus de temps. Je pense que les critères de notation doivent être revus.
Imprime le résultat sous forme de texte à la fin de l'opération, personne en bonne santé indiquée par un point ( .
), personne infectée par un astérisque ( *
), sauf si le ANIMATE
drapeau est défini sur vrai, auquel cas il affichera différents caractères pour les personnes infectées par une souche virale différente.
Voici un GIF pour 10x10, 200 périodes.
Comportement de mutation
Chaque mutation donnera une nouvelle souche jamais vue auparavant (il est donc possible qu'une personne infecte les quatre personnes voisines avec 4 souches distinctes), à moins que 800 souches aient été générées, auquel cas aucun virus ne subira de mutation supplémentaire.
Le résultat de 8 minutes provient du nombre de personnes infectées suivantes:
Période 0, infectée: 4
Période 100, infectée: 53743
Période 200, infecté: 134451
Période 300, infectée: 173369
Période 400, infecté: 228176
Période 500, infecté: 261473
Période 600, infecté: 276086
Période 700, infecté: 265774
Période 800, infecté: 236828
Période 900, infectée: 221275
tandis que le résultat de 6 minutes provient des éléments suivants:
Période 0, infectée: 4
Période 100, infectée: 53627
Période 200, infecté: 129033
Période 300, infectée: 186127
Période 400, infecté: 213633
Période 500, infecté: 193702
Période 600, infectée: 173995
Période 700, infecté: 157966
Période 800, infecté: 138281
Période 900, infectée: 129381
Représentation des personnes
Chaque personne est représentée en 205 octets. Quatre octets pour stocker le type de virus contracté par cette personne, un octet pour enregistrer depuis combien de temps cette personne a été infectée et 200 octets pour stocker combien de fois il a contracté chaque souche de virus (2 bits chacun). Il y a peut-être un alignement d'octets supplémentaire effectué par C ++, mais la taille totale sera d'environ 200 Mo. J'ai deux grilles pour stocker la prochaine étape, donc au total, il utilise environ 400 Mo.
Je stocke l'emplacement des personnes infectées dans une file d'attente, pour réduire le temps requis dans les premières périodes (ce qui est vraiment utile jusqu'à des périodes <400).
Caractéristiques techniques du programme
Toutes les 100 étapes, ce programme imprimera le nombre de personnes infectées, sauf si l' ANIMATE
indicateur est défini sur true
, auquel cas il imprimera la grille entière toutes les 100 ms.
Cela nécessite des bibliothèques C ++ 11 (compiler en utilisant -std=c++11
flag, ou dans Mac avec clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
).
Exécutez-le sans arguments pour les valeurs par défaut, ou avec des arguments comme celui-ci:
./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;
}