4 changed files with 1324 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,210 @@ | 
				
			|||
#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; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
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; | 
				
			|||
} | 
				
			|||
					Loading…
					
					
				
		Reference in new issue