rotagen/rotagen.c

167 lines
3.9 KiB
C

#include "rotagen.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#define POOL_SIZE 0x1000
#define MAX_PEOPLE 32
/* 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[] = {
"washing dishes",
"putting away",
"wiping surfaces",
};
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)
{
int prev[MAX_JOBS];
for (int job = 0; job < num_jobs; ++job)
prev[job] = num_people;
for (int slot = 0; slot < num_slots; ++slot) {
do {
for (int job = 0; job < num_jobs; ++job) {
struct allocation *allocation
= &rota_out[slot].allocations[job];
do {
allocation->slot = slot;
allocation->job = job;
allocation->person = rand() % num_people;
} while (!satisfies_allocation_constraints(allocation)
|| previously_allocated(prev, allocation->person));
}
} while (!satisfies_slot_constraints(&rota_out[slot]));
for (int job = 0; job < num_jobs; ++job)
prev[job] = rota_out[slot].allocations[job].person;
}
}
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 previously_allocated(int prev[MAX_JOBS], int person)
{
for (int job = 0; job < 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 < 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) {
printf("----------------------------------------\n");
for (int job = 0; job < num_jobs; ++job) {
printf("%s\t%s\t\t%s\n",
job == 0 ? slots[slot] : " ",
jobs[job],
people[rota[slot].allocations[job].person]);
}
}
printf("----------------------------------------\n");
}