refactor: make day 5 part 2 code fast

This commit is contained in:
2023-12-08 19:46:04 +01:00
parent cd316d54f9
commit 68c473e78f
3 changed files with 95 additions and 21 deletions

109
day_5.c
View File

@@ -38,9 +38,15 @@ typedef struct {
} Almanac; } Almanac;
//endregion types //endregion types
// Functions
Almanac* load_almanac(FILE *f); Almanac* load_almanac(FILE *f);
RangeList* load_map(FILE *f, const char *name); RangeList* load_map(FILE *f, const char *name);
void almanac_free(Almanac *almanac); void almanac_free(Almanac *almanac);
uint32_t nearest_location_in_range(RangeList **maps, int map_count, uint32_t range_start, uint32_t range_end);
static int compare_range(const Range *a, const Range *b);
// Global state (used to avoid having to allocate new memory on every iteration)
RangeList *range_list_buffer;
int main() { int main() {
FILE *f = fopen("day_5.txt", "r"); FILE *f = fopen("day_5.txt", "r");
@@ -49,6 +55,7 @@ int main() {
exit(1); exit(1);
} }
Almanac *almanac = load_almanac(f); Almanac *almanac = load_almanac(f);
range_list_buffer = rlist_create(16);
// Part 1 - Iterate over each seed and transform number using first matching range for each map // Part 1 - Iterate over each seed and transform number using first matching range for each map
uint32_t min_location = UINT32_MAX; uint32_t min_location = UINT32_MAX;
@@ -73,37 +80,92 @@ int main() {
printf("Result #1: %u\n", min_location); printf("Result #1: %u\n", min_location);
// Part 2 // Part 2
printf("Solving part 2.\nHold your horses... this might take a while.\n");
min_location = UINT32_MAX; min_location = UINT32_MAX;
for(int i = 0; i < almanac->seeds->length; i += 2) { for(int i = 0; i < almanac->seeds->length; i += 2) {
uint32_t min = almanac->seeds->data[i]; uint32_t min = almanac->seeds->data[i];
uint32_t icount = almanac->seeds->data[i + 1]; uint32_t max = min + almanac->seeds->data[i + 1];
for(int i2 = 0; i2 < icount; i2++) {
uint32_t source = min + i2;
for(int j = 0; j < 7; j++) {
RangeList ranges = * ((RangeList**) almanac)[j + 1];
for(int k = 0; k < ranges.length; k++) {
Range range = ranges.data[k];
if(source >= range.source && source < range.source + range.length) {
source = source - range.source + range.destination;
break;
}
}
}
if(source < min_location) { RangeList **maps = &((RangeList**) almanac)[1];
min_location = source; min_location = MIN(min_location, nearest_location_in_range(maps, 7, min, max));
} }
} printf("Result #2: %u\n", min_location);
printf(".");
}
printf("\nResult #2: %u\n", min_location);
rlist_free(range_list_buffer);
almanac_free(almanac); almanac_free(almanac);
fclose(f); fclose(f);
return 0; return 0;
} }
uint32_t nearest_location_in_range(RangeList **maps, int map_count, uint32_t range_start, uint32_t range_end) {
RangeList *map = maps[0];
if(__glibc_unlikely(map->length == 0)) return range_start;
RangeList *temp_ranges = range_list_buffer;
rlist_clear(temp_ranges);
uint32_t cursor = range_start;
for(int i = 0; i < map->length; i++) {
Range input_range = map->data[i];
if(input_range.source + input_range.length <= range_start) {
continue; // input range before current range - skip
}
if(input_range.source >= range_end) {
break; // input range after current range - finish
}
// Add unmapped range
if(cursor < input_range.source) {
Range new_range;
new_range.source = cursor;
new_range.destination = cursor;
new_range.length = new_range.source - cursor;
rlist_add(temp_ranges, new_range);
cursor = input_range.source;
}
// Add mapped range
uint32_t mapped_end = MIN(input_range.source + input_range.length, range_end);
Range mapped_range;
mapped_range.length = mapped_end - cursor;
mapped_range.source = cursor;
mapped_range.destination = input_range.destination + cursor - input_range.source;
rlist_add(temp_ranges, mapped_range);
cursor = MAX(cursor, mapped_range.source + mapped_range.length);
}
// Add final unmapped range
if(cursor < range_end) {
Range new_range;
new_range.source = cursor;
new_range.destination = cursor;
new_range.length = range_end - cursor;
rlist_add(temp_ranges, new_range);
}
// Copy new ranges
uint num_ranges = temp_ranges->length;
Range ranges[num_ranges];
memcpy(&ranges[0], temp_ranges->data, num_ranges * sizeof(Range));
// Find nearest
uint32_t nearest = UINT32_MAX;
if(map_count > 1) {
for(int i = 0; i < num_ranges; i++) {
Range range = ranges[i];
uint32_t next_nearest = nearest_location_in_range(
&maps[1], map_count - 1,
range.destination, range.destination + range.length);
nearest = MIN(nearest, next_nearest);
}
} else {
for(int i = 0; i < num_ranges; i++) {
Range range = ranges[i];
nearest = MIN(nearest, range.destination);
}
}
return nearest;
}
Almanac* load_almanac(FILE *f) { Almanac* load_almanac(FILE *f) {
Almanac *almanac = malloc(sizeof (Almanac)); Almanac *almanac = malloc(sizeof (Almanac));
char *buffer = NULL; char *buffer = NULL;
@@ -120,7 +182,7 @@ Almanac* load_almanac(FILE *f) {
ilist_add(almanac->seeds, seed); ilist_add(almanac->seeds, seed);
} }
read_line(f, &buffer, &bufferLen); read_line(f, &buffer, &bufferLen);
assert(strcmp(, "") == 0); // expect empty line at end assert(strcmp(buffer, "") == 0); // expect empty line at end
almanac->seed_to_soil = load_map(f, "seed-to-soil"); almanac->seed_to_soil = load_map(f, "seed-to-soil");
almanac->soil_to_fertilizer = load_map(f, "soil-to-fertilizer"); almanac->soil_to_fertilizer = load_map(f, "soil-to-fertilizer");
@@ -134,6 +196,10 @@ Almanac* load_almanac(FILE *f) {
return almanac; return almanac;
} }
static int compare_range(const Range *a, const Range *b) {
return a->source > b->source;
}
RangeList* load_map(FILE *f, const char *name) { RangeList* load_map(FILE *f, const char *name) {
RangeList *list = rlist_create(16); RangeList *list = rlist_create(16);
char *buffer = NULL; char *buffer = NULL;
@@ -147,6 +213,7 @@ RangeList* load_map(FILE *f, const char *name) {
rlist_add(list, range); rlist_add(list, range);
} }
qsort(list->data, list->length, sizeof(Range), (__compar_fn_t) compare_range);
free(buffer); free(buffer);
return list; return list;
} }

View File

@@ -8,6 +8,9 @@
char* read_line(FILE *f, char **buffer, int *capacity); char* read_line(FILE *f, char **buffer, int *capacity);
#define MAX(a, b) a > b ? a : b
#define MIN(a, b) a < b ? a : b
static inline int min(const int a, const int b) { static inline int min(const int a, const int b) {
return a < b ? a : b; return a < b ? a : b;
} }

4
list.h
View File

@@ -52,6 +52,10 @@ static __inline void LIST_FN(remove)(LIST_NAME *alist, int index) {
#endif //LIST_UNORDERED #endif //LIST_UNORDERED
} }
static __inline void LIST_FN(clear)(LIST_NAME *alist) {
alist->length = 0;
}
static __inline void LIST_FN(free)(LIST_NAME *alist) { static __inline void LIST_FN(free)(LIST_NAME *alist) {
free(alist->data); free(alist->data);
free(alist); free(alist);