//Perform all actions required on the Bunny world void BunnyWorld::takeTurn() { //if the population is greater than 1000, kill half of the population at random if (m_population >= 1000){ cullBunnies(); } //kill bunnies over the age of 10 and radioactive bunnies over the age of 50 killOldBunnies(); //increase age of every bunny increaseAge(); if(m_radioactivePopulation != m_population){ //infect x new bunnies at random, where x is the number of current radioactive bunnies infectBunnies(); /* if there is at least one male age 2 or over and not radioactive, give birth to one bunny for every female age 2 or over */ if(isEligibleMale()){ giveBirth(); } } //print all of the information about every bunny printBunnies(); }
/** * Order of actions: * a) transition of human into infected * b) giving birth to children - changes input * c) making love - changes input * d) movement */ static void simulateStep2(WorldPtr input, WorldPtr output) { simClock clock = output->clock; // notice that we iterate over xx and yy // and the real x and y are randomly switched between two directions double xxDir = randomDouble(); double yyDir = randomDouble(); // we want to force static scheduling because we suppose that the load // is distributed evenly over the map and we need to have predictable locking #ifdef _OPENMP // at least three columns per thread int threads = omp_get_max_threads(); int numThreads = MIN(MAX(input->localWidth / 3, 1), threads); #pragma omp parallel for num_threads(numThreads) schedule(static) #endif for (int xx = input->xStart; xx <= input->xEnd; xx++) { int x = (xxDir < 0.5) ? xx : (input->xEnd + input->xStart - xx); // stats are counted per column and summed at the end Stats stats = NO_STATS; lockColumn(output, x); for (int yy = input->yStart; yy <= input->yEnd; yy++) { int y = (yyDir < 0.5) ? yy : (input->yEnd + input->yStart - yy); Entity entity = GET_CELL(input, x, y); if (entity.type == NONE) { continue; } // Convert Human to Infected if (entity.type == HUMAN) { int zombieCount = countNeighbouringZombies(input, x, y); double infectionChance = zombieCount * PROBABILITY_INFECTION; if (randomDouble() <= infectionChance) { if (entity.gender == FEMALE) { stats.humanFemalesBecameInfected++; } else { stats.humanMalesBecameInfected++; } toInfected(&entity, clock); LOG_EVENT("A Human became infected\n"); } } // Here are performed natural processed of humans and infected if (entity.type == HUMAN || entity.type == INFECTED) { // giving birth if (entity.gender == FEMALE && entity.children > 0) { if (entity.origin + entity.borns <= clock) { if (entity.type == HUMAN) { stats.humanFemalesGivingBirth++; } else { stats.infectedFemalesGivingBirth++; } Entity * freePtr; while (entity.children > 0 && (freePtr = getFreeAdjacent(input, output, x, y)) != NULL) { Entity child = giveBirth(&entity, clock); if (child.type == HUMAN) { if (child.gender == FEMALE) { stats.humanFemalesBorn++; } else { stats.humanMalesBorn++; } } else { if (child.gender == FEMALE) { stats.infectedFemalesBorn++; } else { stats.infectedMalesBorn++; } } *freePtr = child; LOG_EVENT("A %s child was born\n", child.type == HUMAN ? "Human" : "Infected"); } } else { if (entity.type == HUMAN) { stats.humanFemalesPregnant++; } else { stats.infectedFemalesPregnant++; } } } // making love if (entity.gender == FEMALE && entity.children == 0 && clock >= entity.origin + entity.fertilityStart && clock < entity.origin + entity.fertilityEnd) { // can have baby EntityPtr adjacentMale = findAdjacentFertileMale(input, x, y, clock); if (adjacentMale != NULL) { stats.couplesMakingLove++; makeLove(&entity, adjacentMale, clock, input->stats); stats.childrenConceived += entity.children; LOG_EVENT("A couple made love\n"); } } } if (entity.type == HUMAN) { if (entity.gender == FEMALE) { stats.humanFemales++; } else { stats.humanMales++; } } else if (entity.type == INFECTED) { if (entity.gender == FEMALE) { stats.infectedFemales++; } else { stats.infectedMales++; } } else { stats.zombies++; } // MOVEMENT bearing bearing_ = getBearing(input, x, y); // optimal bearing bearing_ += getRandomBearing() * BEARING_FLUCTUATION; Direction dir = bearingToDirection(bearing_); if (dir != STAY) { double bearingRandomQuotient = (randomDouble() - 0.5) * BEARING_ABS_QUOTIENT_VARIANCE + BEARING_ABS_QUOTIENT_MEAN; entity.bearing = bearing_ / cabsf(bearing_) * bearingRandomQuotient; } else { entity.bearing = bearing_; } // some randomness in direction // the entity will never go in the opposite direction if (dir != STAY) { if (randomDouble() < getMaxSpeed(&entity, clock)) { double dirRnd = randomDouble(); if (dirRnd < DIRECTION_MISSED) { dir = DIRECTION_CCW(dir); // turn counter-clock-wise } else if (dirRnd < DIRECTION_MISSED * 2) { dir = DIRECTION_CW(dir); // turn clock-wise } else if (dirRnd > DIRECTION_FOLLOW + DIRECTION_MISSED * 2) { dir = STAY; } } else { dir = STAY; } } else { // if the entity would STAY, we'll try again to make it move // to make the entity bearing variable in terms of absolute value double bearingRandomQuotient = (randomDouble() - 0.5) * BEARING_ABS_QUOTIENT_VARIANCE + BEARING_ABS_QUOTIENT_MEAN; bearing_ += getRandomBearing() * bearingRandomQuotient; dir = bearingToDirection(bearing_); } // we will try to find the cell in the chosen direction CellPtr destPtr = NULL; if (dir != STAY) { destPtr = IF_CAN_MOVE_TO(x, y, dir); if (randomDouble() < MOVEMENT_TRY_ALTERNATIVE) { if (destPtr == NULL) { destPtr = IF_CAN_MOVE_TO(x, y, DIRECTION_CCW(dir)); } if (destPtr == NULL) { destPtr = IF_CAN_MOVE_TO(x, y, DIRECTION_CW(dir)); } } } if (destPtr == NULL) { destPtr = GET_CELL_PTR(output, x, y); } // actual assignment of entity to its destination *destPtr = entity; } unlockColumn(output, x); #ifdef _OPENMP #pragma omp critical (StatsCriticalRegion2) #endif { mergeStats(&output->stats, stats, true); } } }