4 changed files with 1312 additions and 0 deletions
			
			
		@ -0,0 +1,12 @@ | 
				
			|||||
 | 
					CFLAGS := -Wall -Wextra -std=c17 -D_GNU_SOURCE | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					LIBS := glib-2.0 | 
				
			||||
 | 
					CFLAGS += $(shell pkg-config --cflags $(LIBS)) | 
				
			||||
 | 
					LDLIBS := $(shell pkg-config --libs $(LIBS)) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.PHONY: all | 
				
			||||
 | 
					all: main | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.PHONY: clean | 
				
			||||
 | 
					clean: | 
				
			||||
 | 
						rm -f main | 
				
			||||
								
									
										File diff suppressed because it is too large
									
								
							
						
					
								
									Binary file not shown.
								
							
						
					@ -0,0 +1,198 @@ | 
				
			|||||
 | 
					#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; | 
				
			||||
 | 
					} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue