You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
5.6 KiB
198 lines
5.6 KiB
#include <stdio.h>
|
|
|
|
#include <glib.h>
|
|
|
|
enum action {
|
|
ACTION_BEGIN,
|
|
ACTION_SLEEP,
|
|
ACTION_WAKE
|
|
};
|
|
|
|
struct event {
|
|
unsigned year;
|
|
unsigned month;
|
|
unsigned day;
|
|
unsigned hour;
|
|
unsigned minute;
|
|
enum action action;
|
|
unsigned guard;
|
|
};
|
|
|
|
struct slept_minute {
|
|
unsigned minute;
|
|
unsigned count;
|
|
};
|
|
|
|
gint compare_event(gconstpointer a, gconstpointer b)
|
|
{
|
|
#define _(x) (int)( \
|
|
(x)->year * 12 * 32 * 24 * 60 + \
|
|
(x)->month * 32 * 24 * 60 + \
|
|
(x)->day * 24 * 60 + \
|
|
(x)->hour * 60 + \
|
|
(x)->minute)
|
|
return (_((struct event *)a) - _((struct event *)b));
|
|
#undef _
|
|
}
|
|
|
|
GSList *parse_events(const char *fname)
|
|
{
|
|
FILE *f = fopen(fname, "r");
|
|
if (!f) {
|
|
perror(fname);
|
|
return NULL;
|
|
}
|
|
|
|
GSList *list = NULL;
|
|
|
|
char *line = NULL;
|
|
size_t line_len = 0;
|
|
while (getline(&line, &line_len, f) != -1) {
|
|
g_strstrip(line);
|
|
|
|
// Find the action text
|
|
char *action = line;
|
|
while (*action && *action++ != '[');
|
|
while (*action && *action++ != ']');
|
|
if (*action) *action++ = '\0'; // Expect a minimum of one space
|
|
if (!*action) {
|
|
fprintf(stderr, "Warning: ignoring '%s': No action found.\n", line);
|
|
continue;
|
|
}
|
|
g_strstrip(action);
|
|
|
|
struct event *event = g_malloc0(sizeof(struct event));
|
|
|
|
// Haha what is proper parsing
|
|
sscanf(line, "[%u-%u-%u %u:%u]",
|
|
&event->year,
|
|
&event->month,
|
|
&event->day,
|
|
&event->hour,
|
|
&event->minute
|
|
);
|
|
|
|
// Basic sanity check
|
|
if (event->month >= 12 ||
|
|
event->day >= 32 ||
|
|
event->hour >= 24 ||
|
|
event->minute >= 60) {
|
|
fprintf(stderr, "Warning: ignoring '%s': Invalid time.\n", line);
|
|
g_free(event);
|
|
continue;
|
|
}
|
|
|
|
// Figure out the action
|
|
if (strcmp(action, "falls asleep") == 0) {
|
|
event->action = ACTION_SLEEP;
|
|
} else if (strcmp(action, "wakes up") == 0) {
|
|
event->action = ACTION_WAKE;
|
|
} else {
|
|
sscanf(action, "Guard #%u begins shift", &event->guard);
|
|
if (!event->guard) continue;
|
|
}
|
|
|
|
list = g_slist_prepend(list, event);
|
|
}
|
|
|
|
free(line);
|
|
fclose(f);
|
|
|
|
// We can't do much without information about the guards
|
|
unsigned current_guard = 0;
|
|
list = g_slist_sort(list, compare_event);
|
|
for (GSList *l = list; l; l = l->next) {
|
|
struct event *event = (struct event *)l->data;
|
|
if (event->action == ACTION_BEGIN) {
|
|
current_guard = event->guard;
|
|
} else {
|
|
event->guard = current_guard;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
unsigned find_sleepiest_minute(GSList *events, unsigned guard, unsigned *count)
|
|
{
|
|
// Figure out which is the guard's most slept minute
|
|
// Also assuming all sleep hours are at 12am
|
|
unsigned char slept[60] = {0};
|
|
|
|
unsigned start_time = 0;
|
|
for (GSList *l = events; l; l = l->next) {
|
|
struct event *event = (struct event *)l->data;
|
|
if (event->guard != guard) continue;
|
|
|
|
if (event->action == ACTION_SLEEP) {
|
|
start_time = event->minute;
|
|
} else if (event->action == ACTION_WAKE) {
|
|
for (unsigned i = start_time; i < event->minute; i++) {
|
|
if (slept[i] >= UCHAR_MAX) continue;
|
|
slept[i]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned slept_minute = 0;
|
|
unsigned slept_minute_count = 0;
|
|
for (unsigned i = 0; i < 60; i++) {
|
|
if (slept[i] > slept_minute_count) {
|
|
slept_minute = i;
|
|
slept_minute_count = slept[i];
|
|
}
|
|
}
|
|
|
|
if (count) *count = slept_minute_count;
|
|
return slept_minute;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
GSList *events = parse_events("input");
|
|
for (GSList *l = events; l; l = l->next) {
|
|
struct event *event = (struct event *)l->data;
|
|
printf("[%04u-%02u-%02u %02u:%02u] %u (%u)\n",
|
|
event->year, event->month, event->day,
|
|
event->hour, event->minute,
|
|
event->action, event->guard);
|
|
}
|
|
|
|
// Find the sleepiest minute for each guard
|
|
GHashTable *table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
|
|
for (GSList *l = events; l; l = l->next) {
|
|
struct event *event = (struct event *)l->data;
|
|
if (event->action != ACTION_BEGIN) continue;
|
|
if (g_hash_table_contains(table, GUINT_TO_POINTER(event->guard))) continue;
|
|
|
|
struct slept_minute *minute = g_malloc(sizeof(struct slept_minute));
|
|
minute->minute = find_sleepiest_minute(events, event->guard, &minute->count);
|
|
g_hash_table_insert(table, GUINT_TO_POINTER(event->guard), minute);
|
|
|
|
printf("Guard %u: minute %u, %u times\n", event->guard, minute->minute, minute->count);
|
|
}
|
|
|
|
// Find the sleepiest of them all
|
|
unsigned sleepiest_guard = 0;
|
|
struct slept_minute *sleepiest = NULL;
|
|
GHashTableIter iter;
|
|
gpointer key, value;
|
|
g_hash_table_iter_init (&iter, table);
|
|
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
unsigned guard = GPOINTER_TO_UINT(key);
|
|
struct slept_minute *minute = value;
|
|
|
|
if (sleepiest && sleepiest->count >= minute->count) continue;
|
|
sleepiest_guard = guard;
|
|
sleepiest = minute;
|
|
}
|
|
|
|
printf("Sleepiest guard: %u, minute %u, %u times\n",
|
|
sleepiest_guard, sleepiest->minute, sleepiest->count);
|
|
|
|
printf("Result hash: %u\n", sleepiest_guard * sleepiest->minute);
|
|
|
|
g_hash_table_destroy(table);
|
|
g_slist_free_full(events, g_free);
|
|
return 0;
|
|
}
|
|
|