diff --git a/rotagen.c b/rotagen.c new file mode 100644 index 0000000..6f1847b --- /dev/null +++ b/rotagen.c @@ -0,0 +1,148 @@ +#include "rotagen.h" + +#include +#include +#include + +#define POOL_SIZE 0x1000 + +/* Hard-coded test data. */ +static const char *people[] = { + "alice", "bob", "charlie", "dave", "eve", "fred", "george", +}; +static const int num_people = sizeof(people) / sizeof(people[0]); +static const char *jobs[] = { + "foo", + "bar", + "baz", +}; +static const int num_jobs = sizeof(jobs) / sizeof(jobs[0]); +static const char *slots[] = { + "mon", "tue", "wed", "thu", "fri", "sat", "sun", +}; +static const int num_slots = sizeof(slots) / sizeof(slots[0]); +static const struct constraint constraints[] = { + { + .person = 0, + .type = JOB_EXEMPTION_CONSTRAINT, + .object = { .job = 2 }, + }, + { + .person = 1, + .type = SLOT_EXEMPTION_CONSTRAINT, + .object = { .slot = 4 }, + }, +}; +static const int num_constraints = sizeof(constraints) / sizeof(constraints[0]); + +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); + + struct slot_result *rota + = pool_alloc(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) +{ + for (int slot = 0; slot < num_slots; ++slot) { + do { + for (int j = 0; j < num_jobs; ++j) { + struct allocation *allocation = &rota_out[slot].allocations[j]; + do { + generate_allocation(slot, j, allocation); + } while (!satisfies_allocation_constraints(allocation)); + } + } while (!satisfies_slot_constraints(&rota_out[slot])); + } +} + +void generate_allocation(int slot, int job, struct allocation *allocation_out) +{ + allocation_out->slot = slot; + allocation_out->job = job; + allocation_out->person = rand() % num_people; +} + +bool satisfies_allocation_constraints(const struct allocation *allocation) +{ + for (int i = 0; i < num_constraints; ++i) { + if (allocation->person != constraints[i].person) + continue; + switch (constraints[i].type) { + case JOB_EXEMPTION_CONSTRAINT: + if (allocation->job == constraints[i].object.job) + return false; + break; + case SLOT_EXEMPTION_CONSTRAINT: + if (allocation->slot == constraints[i].object.slot) + return false; + break; + default: + fprintf(stderr, + "Warning: unhandled constraint type %d in %s()", + constraints[i].type, + __func__); + break; + } + } + return true; +} + +bool satisfies_slot_constraints(const struct slot_result *result) +{ + for (int i = 0; i < num_jobs; ++i) { + for (int j = i + 1; j < num_jobs; ++j) { + if (result->allocations[i].person == result->allocations[j].person) + return false; + } + } + return true; +} + +void print_rota(const struct slot_result *rota) +{ + for (int slot = 0; slot < num_slots; ++slot) { + for (int job = 0; job < num_jobs; ++job) { + printf("%s\t%s\t%s\n", + job == 0 ? slots[slot] : " ", + jobs[job], + people[rota[slot].allocations[job].person]); + } + } +} diff --git a/rotagen.h b/rotagen.h index 180b120..863c731 100644 --- a/rotagen.h +++ b/rotagen.h @@ -29,4 +29,10 @@ struct slot_result { struct allocation allocations[MAX_JOBS]; }; +void generate_rota(struct slot_result *rota_out); +void generate_allocation(int slot, int job, struct allocation *allocation_out); +bool satisfies_allocation_constraints(const struct allocation *allocation); +bool satisfies_slot_constraints(const struct slot_result *slot); +void print_rota(const struct slot_result *rota); + #endif