mid-kid
6 years ago
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