#include #include 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; }; 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_guard(GSList *events) { // Figure out which guard has slept the most // Assumptions: // - All sleep/wake hours are 00 // - Every sleep action is coupled with a wake action from the same guard // According to the puzzle these are safe assumptions to make, // and it's not worth my time to do everything "properly" right now. GHashTable *table = g_hash_table_new(NULL, NULL); unsigned start_time = 0; for (GSList *l = events; l; l = l->next) { struct event *event = (struct event *)l->data; if (event->action == ACTION_SLEEP) { start_time = event->minute; } else if (event->action == ACTION_WAKE) { unsigned time = event->minute - start_time; unsigned current_time = GPOINTER_TO_UINT(g_hash_table_lookup(table, GUINT_TO_POINTER(event->guard))); current_time += time; g_hash_table_insert(table, GUINT_TO_POINTER(event->guard), GUINT_TO_POINTER(current_time)); } } unsigned sleepiest_guard = 0; unsigned sleepiest_guard_time = 0; gpointer key, value; GHashTableIter iter; g_hash_table_iter_init(&iter, table); while (g_hash_table_iter_next(&iter, &key, &value)) { unsigned guard = GPOINTER_TO_UINT(key); unsigned time = GPOINTER_TO_UINT(value); printf("Guard #%u: %u minutes\n", guard, time); if (time > sleepiest_guard_time) { sleepiest_guard = guard; sleepiest_guard_time = time; } } g_hash_table_destroy(table); return sleepiest_guard; } unsigned find_sleepiest_minute(GSList *events, unsigned guard) { // 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]; } } 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); } unsigned sleepiest_guard = find_sleepiest_guard(events); printf("Sleepiest guard: %u\n", sleepiest_guard); unsigned sleepiest_minute = find_sleepiest_minute(events, sleepiest_guard); printf("Most slept minute: %u\n", sleepiest_minute); printf("Result hash: %u\n", sleepiest_guard * sleepiest_minute); g_slist_free_full(events, g_free); return 0; }