//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();
}
Пример #2
0
/**
 * 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);
		}
	}
}