C ++ 11, 6-8 minutos
Mi ejecución de prueba tarda unos 6-8 minutos en mi máquina Fedora 19, i5. Pero debido a la aleatoriedad de la mutación, bien podría ser más rápido o tomar más tiempo que eso. Creo que los criterios de puntuación deben ser reorientados.
Imprime el resultado como texto al final de la finalización, persona sana indicada por punto ( .
), persona infectada por asterisco ( *
), a menos queANIMATE
indicador se establezca en verdadero, en cuyo caso mostrará diferentes caracteres para las personas infectadas con una cepa de virus diferente.
Aquí hay un GIF para 10x10, 200 períodos.
Comportamiento de mutación
Cada mutación dará una nueva cepa nunca antes vista (por lo que es posible que una persona infecte a las cuatro personas vecinas con 4 cepas distintas), a menos que se hayan generado 800 cepas, en cuyo caso ningún virus continuará con ninguna mutación.
El resultado de 8 minutos proviene del siguiente número de personas infectadas:
Período 0, infectado: 4
Período 100, infectado: 53743
Período 200, infectado: 134451
Período 300, infectado: 173369
Período 400, infectado: 228176
Período 500, infectado: 261473
Período 600, infectado: 276086
Período 700, infectado: 265774
Período 800, infectado: 236828
Período 900, infectado: 221275
mientras que el resultado de 6 minutos proviene de lo siguiente:
Período 0, infectado: 4
Período 100, infectado: 53627
Período 200, infectado: 129033
Período 300, infectado: 186127
Período 400, infectado: 213633
Período 500, infectado: 193702
Período 600, infectado: 173995
Período 700, infectado: 157966
Período 800, infectado: 138281
Período 900, infectado: 129381
Representación de la persona
Cada persona está representada en 205 bytes. Cuatro bytes para almacenar el tipo de virus que esta persona está contrayendo, un byte para almacenar cuánto tiempo ha estado infectada esta persona y 200 bytes para almacenar cuántas veces ha contraído cada cepa de virus (2 bits cada uno). Quizás haya una alineación de bytes adicional realizada por C ++, pero el tamaño total será de alrededor de 200 MB. Tengo dos cuadrículas para almacenar el siguiente paso, por lo que en total usa alrededor de 400 MB.
Guardo la ubicación de las personas infectadas en una cola, para reducir el tiempo requerido en los primeros períodos (que es realmente útil hasta períodos <400).
Tecnicismos del programa
Cada 100 pasos, este programa imprimirá el número de personas infectadas, a menos que la ANIMATE
marca esté configurada true
, en cuyo caso imprimirá la cuadrícula completa cada 100 ms.
Esto requiere bibliotecas C ++ 11 (compilar usando -std=c++11
flag, o en Mac con clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
).
Ejecútelo sin argumentos para los valores predeterminados, o con argumentos como este:
./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;
}