void free_cell(vtab_p table, int row, int col) { cell_p c_ptr = GET_CELL_PTR(row, col); if ((c_ptr->type == CELL_TYPE_STRING) && (c_ptr->flags & CELL_FLAG_FREEABLE) && (c_ptr->s != NULL)) { free(c_ptr->s); } memset(c_ptr, 0, sizeof(cell_t)); }
void zero_table_data(vtab_p table, int type) { // Sets data area of table to zeros of specified type for (int row = table->header_rows; (row < ALL_TABLE_ROWS); row++) { for (int col = table->header_cols; (col < ALL_TABLE_COLS); col++) { cell_p c_ptr = GET_CELL_PTR(row, col); memset(c_ptr, 0, sizeof(cell_t)); c_ptr->type = type; } } }
void sort_rows_descending_by_col(vtab_p table, int start_row, int stop_row, int col) { // Rearrange row_ix_map[] indices so the rows will be in // descending order by the value in the specified column for (int ix = start_row; (ix <= stop_row); ix++) { int biggest_ix = ix; cell_p biggest_ix_c_ptr = GET_CELL_PTR(table->row_ix_map[ix], col); for (int iy = ix + 1; (iy <= stop_row); iy++) { cell_p iy_c_ptr = GET_CELL_PTR(table->row_ix_map[iy], col); if (biggest_ix_c_ptr->d < iy_c_ptr->d) { biggest_ix_c_ptr = iy_c_ptr; biggest_ix = iy; } } if (biggest_ix != ix) { int tmp = table->row_ix_map[ix]; table->row_ix_map[ix] = table->row_ix_map[biggest_ix]; table->row_ix_map[biggest_ix] = tmp; } } }
/** * Fills the world with specified number of people and zombies. * The people are of different age; zombies are "brand new". */ void randomDistribution(WorldPtr world, int people, int zombies, simClock clock) { world->stats.clock = clock; world->stats.infectedFemales = 0; world->stats.infectedMales = 0; for (int i = 0; i < people;) { int x = randomInt(world->xStart, world->xEnd); int y = randomInt(world->yStart, world->yEnd); CellPtr cellPtr = GET_CELL_PTR(world, x, y); if (cellPtr->type != NONE) { continue; } newHuman(cellPtr, clock); if (cellPtr->gender == FEMALE) { world->stats.humanFemales++; } else { world->stats.humanMales++; } i++; } for (int i = 0; i < zombies;) { int x = randomInt(world->xStart, world->xEnd); int y = randomInt(world->yStart, world->yEnd); CellPtr cellPtr = GET_CELL_PTR(world, x, y); if (cellPtr->type != NONE) { continue; } newZombie(cellPtr, clock); world->stats.zombies++; i++; } }
void auto_set_col_width(vtab_p table, int col, int min_width, int max_width) { int width = min_width; for (int row = 0; (row < ALL_TABLE_ROWS); row++) { cell_p c_ptr = GET_CELL_PTR(row, col); if (c_ptr->type == CELL_TYPE_REPCHAR) { continue; } char *p = fmt_cell_data(c_ptr, max_width, (int)(table->col_decimal_places[col])); int l = strlen(p); if (width < l) { width = l; } } width += USUAL_GUTTER_WIDTH; if (width > max_width) { width = max_width; } table->col_width[col] = (uint8_t)width; }
void display_table(vtab_p table, int screen_width, int show_unseen_rows, int show_unseen_cols, int show_zero_rows, int show_zero_cols) { // Set row and column flags according to whether data in rows and cols // has been assigned, and is currently non-zero. int some_seen_data = 0; int some_non_zero_data = 0; for (int row = table->header_rows; (row < ALL_TABLE_ROWS); row++) { for (int col = table->header_cols; (col < ALL_TABLE_COLS); col++) { cell_p c_ptr = GET_CELL_PTR(row, col); // Currently, "seen data" includes not only numeric data, but also // any strings, etc -- anything non-NULL (other than rephcars). if ((c_ptr->type != CELL_TYPE_NULL) && (c_ptr->type != CELL_TYPE_REPCHAR)) { some_seen_data = 1; set_row_flag(table, row, ROW_FLAG_SEEN_DATA); set_col_flag(table, col, COL_FLAG_SEEN_DATA); // Currently, "non-zero data" includes not only numeric data, // but also any strings, etc -- anything non-zero (other than // repchars, which are already excluded above). So, note a // valid non-NULL pointer to an empty string would still be // counted as non-zero data. if (c_ptr->l != (int64_t)0) { some_non_zero_data = 1; set_row_flag(table, row, ROW_FLAG_NON_ZERO_DATA); set_col_flag(table, col, COL_FLAG_NON_ZERO_DATA); } } } } if (!some_seen_data) { printf("Table has no data.\n"); return; } if (!some_non_zero_data && !show_zero_rows && !show_zero_cols) { printf("Table has no non-zero data.\n"); return; } // Start with first data column and try to display table, // folding lines as necessary per screen_width int col = -1; int data_col = table->header_cols; while (data_col < ALL_TABLE_COLS) { // Skip data columns until we have one to display if ((!test_col_flag(table, data_col, COL_FLAG_ALWAYS_SHOW)) && (((!show_unseen_cols) && (!test_col_flag(table, data_col, COL_FLAG_SEEN_DATA))) || ((!show_zero_cols) && (!test_col_flag(table, data_col, COL_FLAG_NON_ZERO_DATA))))) { data_col += 1; continue; } // Display blank line between table sections if (col > 0) { printf("\n"); } // For each row, display as many columns as possible for (int row_ix = 0; (row_ix < ALL_TABLE_ROWS); row_ix++) { int row = table->row_ix_map[row_ix]; // If past the header rows, conditionally skip rows if ((row >= table->header_rows) && (!test_row_flag(table, row, ROW_FLAG_ALWAYS_SHOW))) { // Optionally skip row if no data seen or if all zeros if (((!show_unseen_rows) && (!test_row_flag(table, row, ROW_FLAG_SEEN_DATA))) || ((!show_zero_rows) && (!test_row_flag(table, row, ROW_FLAG_NON_ZERO_DATA)))) { continue; } } // Begin a new row... int cur_line_width = 0; // All lines start with the left header columns for (col = 0; (col < table->header_cols); col++) { display_justified_cell(GET_CELL_PTR(row, col), (int)(table->row_flags[row]), (int)(table->col_flags[col]), (int)(table->col_width[col]), (int)(table->col_decimal_places[col])); cur_line_width += (int)(table->col_width[col]); } // Reset column index to starting data column for each new row col = data_col; // Try to display as many data columns as possible in every section for (;;) { // See if we should print this column if (test_col_flag(table, col, COL_FLAG_ALWAYS_SHOW) || (((show_unseen_cols) || (test_col_flag(table, col, COL_FLAG_SEEN_DATA))) && ((show_zero_cols) || (test_col_flag(table, col, COL_FLAG_NON_ZERO_DATA))))) { display_justified_cell(GET_CELL_PTR(row, col), (int)(table->row_flags[row]), (int)(table->col_flags[col]), (int)(table->col_width[col]), (int)(table->col_decimal_places[col])); cur_line_width += (int)(table->col_width[col]); } col += 1; // End the line if no more columns or next column would exceed screen width if ((col >= ALL_TABLE_COLS) || ((cur_line_width + (int)(table->col_width[col])) > screen_width)) { break; } } printf("\n"); } // Remember next starting data column for next section data_col = col; } }
void clear_assign(vtab_p table, int row, int col) { cell_p c_ptr = GET_CELL_PTR(row, col); memset(c_ptr, 0, sizeof(cell_t)); }
void long_addto(vtab_p table, int row, int col, int64_t l) { cell_p c_ptr = GET_CELL_PTR(row, col); c_ptr->type = CELL_TYPE_LONG; c_ptr->l += l; }
void double_addto(vtab_p table, int row, int col, double d) { cell_p c_ptr = GET_CELL_PTR(row, col); c_ptr->type = CELL_TYPE_DOUBLE; c_ptr->d += d; }
void repchar_assign(vtab_p table, int row, int col, char c) { cell_p c_ptr = GET_CELL_PTR(row, col); c_ptr->type = CELL_TYPE_REPCHAR; c_ptr->c[0] = c; }
void string_assign(vtab_p table, int row, int col, char *s) { cell_p c_ptr = GET_CELL_PTR(row, col); c_ptr->type = CELL_TYPE_STRING; c_ptr->s = s; }
int test_cell_flag(vtab_p table, int row, int col, int flag) { cell_p c_ptr = GET_CELL_PTR(row, col); return ((c_ptr->flags & (uint32_t)flag) != 0); }
void clear_cell_flag(vtab_p table, int row, int col, int flag) { cell_p c_ptr = GET_CELL_PTR(row, col); c_ptr->flags &= (uint32_t)~flag; }
void set_cell_flag(vtab_p table, int row, int col, int flag) { cell_p c_ptr = GET_CELL_PTR(row, col); c_ptr->flags |= (uint32_t)flag; }
/** * Order of actions: * a) death of human or infected * b) decomposition of zombie * c) transition of infected to zombie */ static void simulateStep1(WorldPtr input, WorldPtr output) { simClock clock = output->clock; // 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 x = input->xStart; x < input->xEnd; x++) { Stats stats = NO_STATS; for (int y = input->yStart; y <= input->yEnd; y++) { EntityPtr entity = GET_CELL_PTR(input, x, y); if (entity->type == NONE) { continue; } // Death of living entity if (entity->type == HUMAN || entity->type == INFECTED) { if (randomDouble() < getDeathRate(entity, clock)) { if (entity->type == HUMAN) { if (entity->gender == FEMALE) { stats.humanFemalesDied++; } else { stats.humanMalesDied++; } } else { if (entity->gender == FEMALE) { stats.infectedFemalesDied++; } else { stats.infectedMalesDied++; } } LOG_EVENT("A %s died\n", entity->type == HUMAN ? "Human" : "Infected"); // just forget this entity entity->type = NONE; } } // Decompose Zombie if (entity->type == ZOMBIE) { if (randomDouble() < getDecompositionRate(entity, clock)) { stats.zombiesDecomposed++; LOG_EVENT("A Zombie decomposed\n"); // just forgot this entity entity->type = NONE; } } // Convert Infected to Zombie if (entity->type == INFECTED) { if (randomDouble() < PROBABILITY_BECOME_ZOMBIE) { if (entity->gender == FEMALE) { stats.infectedFemalesBecameZombies++; } else { stats.infectedMalesBecameZombies++; } toZombie(entity, clock); LOG_EVENT("An Infected became Zombie\n"); } } } #ifdef _OPENMP #pragma omp critical (StatsCriticalRegion2) #endif { mergeStats(&output->stats, stats, true); } } }
/** * 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); } } }