Something went wrong. Try again.
Hello.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173#include <stdio.h>#include <stdlib.h>#include <string.h>
#include "post.h"#include "town.h"#include "weather.h"
static const char *const days[] = { "Weekdays", "Weekdays", "Weekdays", "Weekdays", "Weekdays", "Saturday", "Sunday",};
static int minutes(int metres, int speed){ return (metres + speed - 1) / speed;}
static const struct record *rounds;
/* Rounds. From | until | days | round | leaves the office | boxes, in order. */enum { FROM, UNTIL, DAYS, ROUND, LEAVES, BOXES };
static int by_departure(const void *a, const void *b){ int x = *(const int *)a, y = *(const int *)b; return clock_time(rounds->field[x][LEAVES]) - clock_time(rounds->field[y][LEAVES]);}
#define MONTHS (301 * 12) /* 1900 to 2200. */
/* The rounds on the first of each month, once worked out. */static struct { int known, n; struct visit visit[MAX_DAILY];} firsts[MONTHS];
static int work_out(struct day day, struct visit out[]);
int visits(struct day day, struct visit out[]){ int month = month_of(day); if (day.d != 1 || month < 0 || month >= MONTHS) return work_out(day, out); if (!firsts[month].known) { firsts[month].n = work_out(day, firsts[month].visit); firsts[month].known = 1; } memcpy(out, firsts[month].visit, sizeof out[0] * (size_t)firsts[month].n); return firsts[month].n;}
static int work_out(struct day day, struct visit out[]){ int van = conditions(day).van; int n = 0; rounds = read_record("rounds");
int today[MAX_ROWS], count = 0; for (int row = 0; row < rounds->rows; row++) if (strcmp(rounds->field[row][DAYS], days[weekday(day)]) == 0 && in_force(rounds->field[row][FROM], rounds->field[row][UNTIL], day)) today[count++] = row; qsort(today, count, sizeof today[0], by_departure);
/* There is one van. A round leaves on time, or when the van is back, whichever is later. * The sorting office sets its clock by the bell every first of the month. */ int returned = 0; for (int i = 0; i < count; i++) { int row = today[i]; const char *name = rounds->field[row][ROUND]; int time = clock_time(rounds->field[row][LEAVES]); if (time < returned) time = returned; int left = time; char stops[FIELD], here[FIELD] = OFFICE; int first = n; snprintf(stops, sizeof stops, "%s", rounds->field[row][BOXES]); for (char *box = stops, *comma; box; box = comma ? comma + 1 : NULL) { if ((comma = strchr(box, ','))) *comma = '\0'; while (*box == ' ') box++; time += minutes(distance(day, here, box), van); if (n == MAX_DAILY) { fprintf(stderr, "the van cannot empty more than %d boxes a day\n", MAX_DAILY); exit(1); } snprintf(out[n].round, FIELD, "%s", name); snprintf(out[n].box, FIELD, "%s", box); out[n].at = time; n++; time += STOP; snprintf(here, FIELD, "%s", box); } int back = time + minutes(distance(day, here, OFFICE), van); for (int j = first; j < n; j++) { out[j].left = left; out[j].back = back; } returned = back; } return n;}
static int by_name(const void *a, const void *b){ return strcmp(*(const char *const *)a, *(const char *const *)b);}
int post(const struct sender *sender, struct day day, struct letter *letter){ struct visit today[MAX_DAILY]; int n = visits(day, today); if (n == 0) return 0;
const char *boxes[MAX_DAILY]; int count = 0; for (int i = 0; i < n; i++) { int seen = 0; for (int j = 0; j < count; j++) seen |= strcmp(boxes[j], today[i].box) == 0; if (!seen) boxes[count++] = today[i].box; } qsort(boxes, count, sizeof boxes[0], by_name);
const char *box = nearest(day, sender->home, boxes, count); int posted = sender->ready + minutes(distance(day, sender->home, box), conditions(day).walk); const struct visit *next = NULL; for (int i = 0; i < n; i++) if (strcmp(today[i].box, box) == 0 && today[i].at >= posted && (!next || today[i].at < next->at)) next = &today[i]; if (!next) return 0; letter->sender = *sender; letter->posted = posted; letter->visit = *next; return 1;}
static int opening_order(const void *a, const void *b){ const struct letter *x = a, *y = b; if (x->visit.back != y->visit.back) return x->visit.back - y->visit.back; if (x->visit.at != y->visit.at) return y->visit.at - x->visit.at; if (x->posted != y->posted) return y->posted - x->posted; return strcmp(x->sender.name, y->sender.name);}
int letters_from(const struct town *town, struct day day, struct letter out[]){ if (day.d != 1) return 0; int count = 0; for (int i = 0; i < town->lines; i++) { if (!active(&town->line[i], day) || town->line[i].member) continue; struct sender writer = sender_of(&town->line[i], day); count += post(&writer, day, &out[count]); } qsort(out, (size_t)count, sizeof out[0], opening_order); return count;}
int dead_letters(struct day day, struct letter out[]){ return letters_from(town_on(day), day, out);}