#include "rotagen.h" #include #include #include #include #include #define POOL_SIZE 0x1000 #define MAX_PEOPLE 32 static struct config conf; static uint8_t pool[POOL_SIZE]; static uint8_t *free_ptr; static void *pool_alloc(int size) { if (free_ptr + size > pool + POOL_SIZE) return NULL; void *ptr = free_ptr; free_ptr += size; return ptr; } int main(void) { free_ptr = &pool[0]; unsigned seed; struct timeval now; if (gettimeofday(&now, NULL) == 0) { seed = now.tv_usec; } else { fprintf(stderr, "Warning: failed to get time of day to seed random number " "generation; falling back to hard-coded seed.\n"); seed = 0xdeadbeef; } srand(seed); memset(&conf, 0, sizeof(conf)); read_config("rotagen.conf", &conf); struct slot_result *rota = pool_alloc(conf.num_slots * sizeof(struct slot_result)); if (rota == NULL) { fprintf(stderr, "Fatal error: memory pool exhausted in %s().\n", __func__); exit(1); } generate_rota(rota); print_rota(rota); return 0; } void generate_rota(struct slot_result *rota_out) { int prev[MAX_JOBS]; for (int job = 0; job < conf.num_jobs; ++job) prev[job] = conf.num_people; for (int slot = 0; slot < conf.num_slots; ++slot) { do { for (int job = 0; job < conf.num_jobs; ++job) { struct assignment *assignment = &rota_out[slot].assignments[job]; do { assignment->slot = slot; assignment->job = job; assignment->person = rand() % conf.num_people; } while (!satisfies_assignment_constraints(assignment) || previously_allocated(prev, assignment->person)); } } while (!satisfies_slot_constraints(&rota_out[slot])); for (int job = 0; job < conf.num_jobs; ++job) prev[job] = rota_out[slot].assignments[job].person; } } bool satisfies_assignment_constraints(const struct assignment *assignment) { for (int i = 0; i < conf.num_constraints; ++i) { if (assignment->person != conf.constraints[i].person) continue; switch (conf.constraints[i].type) { case JOB_EXEMPTION_CONSTRAINT: if (assignment->job == conf.constraints[i].object.job) return false; break; case SLOT_EXEMPTION_CONSTRAINT: if (assignment->slot == conf.constraints[i].object.slot) return false; break; default: fprintf(stderr, "Warning: unhandled constraint type %d in %s()", conf.constraints[i].type, __func__); break; } } return true; } bool previously_allocated(int prev[MAX_JOBS], int person) { for (int job = 0; job < conf.num_jobs; ++job) { if (prev[job] == person) return true; } return false; } bool satisfies_slot_constraints(const struct slot_result *result) { for (int i = 0; i < conf.num_jobs; ++i) { for (int j = i + 1; j < conf.num_jobs; ++j) { if (result->assignments[i].person == result->assignments[j].person) return false; } } return true; } void print_rota(const struct slot_result *rota) { for (int slot = 0; slot < conf.num_slots; ++slot) { printf("----------------------------------------\n"); for (int job = 0; job < conf.num_jobs; ++job) { printf("%s\t%s\t\t%s\n", job == 0 ? conf.slots[slot] : " ", conf.jobs[job], conf.people[rota[slot].assignments[job].person]); } } printf("----------------------------------------\n"); }