refactor: make day 5 part 2 code fast
This commit is contained in:
109
day_5.c
109
day_5.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
4
list.h
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user