C ++ 11, 6-8 Minuten
Mein Testlauf dauert auf meiner Fedora 19, i5-Maschine ca. 6-8 Minuten. Aber aufgrund der Zufälligkeit der Mutation kann es genauso gut schneller sein oder länger dauern. Ich denke, dass die Bewertungskriterien neu ausgerichtet werden müssen.
Gibt das Ergebnis am Ende der Fertigstellung als Text aus, gesunde Person mit Punkt ( .
), infizierte Person mit Stern ( *
), sofern das ANIMATE
Flag nicht auf true gesetzt ist. In diesem Fall werden unterschiedliche Zeichen für Personen angezeigt, die mit unterschiedlichen Virusstämmen infiziert sind.
Hier ist ein GIF für 10x10, 200 Perioden.
Mutationsverhalten
Jede Mutation ergibt einen neuen Stamm, der noch nie zuvor gesehen wurde (es ist also möglich, dass eine Person die vier Nachbarn mit vier verschiedenen Stämmen infiziert), es sei denn, es wurden 800 Stämme erzeugt. In diesem Fall wird kein Virus mehr mutiert.
Das 8-Minuten-Ergebnis stammt von der folgenden Anzahl infizierter Personen:
Periode 0, infiziert: 4
Zeitraum 100, infiziert: 53743
Periode 200, infiziert: 134451
Zeitraum 300, infiziert: 173369
Zeitraum 400, infiziert: 228176
Zeitraum 500, infiziert: 261473
Zeitraum 600, infiziert: 276086
Zeitraum 700, infiziert: 265774
Zeitraum 800, infiziert: 236828
Zeitraum 900, infiziert: 221275
Das 6-Minuten-Ergebnis ergibt sich aus:
Periode 0, infiziert: 4
Zeitraum 100, infiziert: 53627
Zeitraum 200, infiziert: 129033
Zeitraum 300, infiziert: 186127
Zeitraum 400, infiziert: 213633
Zeitraum 500, infiziert: 193702
Zeitraum 600, infiziert: 173995
Zeitraum 700, infiziert: 157966
Zeitraum 800, infiziert: 138281
Zeitraum 900, infiziert: 129381
Personenvertretung
Jede Person ist in 205 Bytes vertreten. Vier Bytes zum Speichern des Virustyps, den diese Person infiziert, ein Byte zum Speichern, wie lange diese Person infiziert war, und 200 Bytes zum Speichern, wie oft sie jeden Virusstamm infiziert hat (jeweils 2 Bit). Möglicherweise werden einige zusätzliche Byte-Alignments von C ++ vorgenommen, aber die Gesamtgröße liegt bei 200 MB. Ich habe zwei Gitter, um den nächsten Schritt zu speichern, also verbraucht es insgesamt ungefähr 400 MB.
Ich speichere den Ort infizierter Personen in einer Warteschlange, um die Zeit zu verkürzen, die in den frühen Perioden benötigt wird (was bis zu Perioden <400 wirklich nützlich ist).
Programmtechniken
Alle 100 Schritte druckt dieses Programm die Anzahl der infizierten Personen, sofern das ANIMATE
Flag nicht auf gesetzt true
ist. In diesem Fall wird das gesamte Raster alle 100 ms gedruckt.
Dies erfordert C ++ 11-Bibliotheken (Kompilieren mit -std=c++11
flag oder in Mac mit clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
).
Führen Sie es ohne Argumente für die Standardwerte oder mit folgenden Argumenten aus:
./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;
}