diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c70bee..c5e5c8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,5 +3,5 @@ project(aoc_2021 C) set(CMAKE_C_STANDARD 99) -add_executable(aoc_2021 src/main.c src/day_1.c src/day.h src/day_2.c src/puzzle_input.c src/puzzle_input.h src/day_3.c src/day_4.c src/day_5.c src/day_6.c src/day_7.c src/day_8.c) +add_executable(aoc_2021 src/main.c src/day_1.c src/day.h src/day_2.c src/puzzle_input.c src/puzzle_input.h src/day_3.c src/day_4.c src/day_5.c src/day_6.c src/day_7.c src/day_8.c src/day_9.c src/queue.c src/queue.h) target_link_libraries(aoc_2021 m) diff --git a/inputs/day_9.txt b/inputs/day_9.txt new file mode 100644 index 0000000..19adf1b --- /dev/null +++ b/inputs/day_9.txt @@ -0,0 +1,100 @@ +3235678976543234569109899875456987676387679999878953234987656895457998743212347892123999912987632489 +2124899989932145698998789994329876545235567899768995349898546789346987654423656789339889899986541678 +1012567897898756797987678989212985432103458987656789456789435691235998775634987897998776798775430567 +2343489956789987976798899578901299654512578998545899567894326890449899896845898945899655987654321378 +3455697645678999875679965467892398999323456789656798998952018921598799987896789235789544398765435459 +4589789432567987764597654358679497878954578996987987999543459433697689899987892123498732129879646589 +5678994321456976543989543236568986769895989654599876789765569555987578778999989014987653234998789678 +6789875432349897659878943123459875458789996543298765678987678976899434569019878925998754345679898789 +7894987654599798798768932012598766345678997692199854567898789987998923978998767899899987456789989899 +9993298765987689988957899129679953237899989989987623456789898698987899899998756798789896588899878967 +8989109876796569977845678998998767129949876979798544587899954569876786799987546989656799679999865456 +7678912987965498765434567897899643298939965765679656798998768998765125899997639876545678996598754321 +6567894599876329896545878976987654987898954354598787899999879129654014768998549865434568995439863210 +5456789678997547989656789454598767976767976123459898976799989098643123456789998754323456789521994921 +4347998799987656978967894323789879765656891012567999765789899987654354799999876543212368996542989899 +3298949898998799867899965434678998654346789123458998654576789298966455678935987654345679987759878788 +4989534987899987656789879765799998743235679254569876543445679019878766789124598775656799999898765667 +9878921256999876546899989878987879865123789365678989521234695434989899893012349987878898989987654545 +9967892345987655434989999989876565986239895478789998432345696549999989932123457898999947678998943234 +8756793496796542323478999898785454987645996589893987643456789698999878943934578999986434567899932123 +4345789989987641014567896797685323498656789699912397654567999987899867999895689598765323456997821012 +3234699879876532123479965986543212349987899898901469895689109876987656789789791459853212349876543156 +0134589965998743234569534598655304558998910967893456976789999965496544345678992398654101256997643245 +1234567894569854375678976789766412367899321256789569987896789896986432234569989987653212397987656356 +2547678923456975676989997999896567898996432345679678998935698789876531023789877999765323989998975457 +3458789212689876989299989123987878979987593958798989899123987678987632234989765789876439879899876568 +5569896345678987892109878994698989767998989899997898789239899568998544345678954567999949768799987679 +6789965456789998943498767789899694545899878789986787679398798457899765459899543456798798656689998989 +8992986767898969894989345699986543236789765699875656568997656356789876567989212378999659543567899992 +9901299878987656789875234599997654697999873987654343459789543235899989678978934567998943212578923901 +7899988989876545678984123678939765789876542198843212345678910124589998789567895979876432101458939892 +6798767998783234569873234569219896899965431097652101234889321234678999893459976789987943242357898789 +7987657789656123698764675678909987939878592198963213455695432348989876932347997895699894343456789678 +9876546678943234999878786789698998921989989999984323567789543567898765421286789934598789658767893467 +9965436567894549898989897896567899993998767899876544568897654578919976982345690129987678969878912345 +9894325476789698787898999965456789989897656791987675689999879989102989876456789398776579899989423456 +8763212345998789656797897654239999976798745690998786789899998996212399988767891987654456779997678967 +7654323466789899645685679793198898765679659989879897896789987895475498999898910399743234568998789878 +8876434578899998921434998989987679954549798878764998945698976796786987989979521249432123456789892989 +9987545699998987890129897678976567893234987654353459936987895989899896878965434598543234587899921094 +1099786789997876789298786567897789964645898983232345899876764878998795769896545697654355699999992123 +2199899899896765678999543498999899875776789872101236789965743767896543456789676898768456789998989934 +3987989998765434567895432345699912986989899654312345679874232456965432345678987999899567899987679895 +9876378987654323456989541016989993997893998765459569797662101247894321234569998999999698919876567789 +8765459876543212345678952345679889898912999877568678989543212348973210123459899989998789909865434697 +9896567997654101456789763456798768789909899989679789978965343459765421234598768978999897898954323456 +3987678998783216598899874567987654567899769998789898869897654789987532345987659767893956797895412345 +2198789659854427689976985678995453478999878919899987656798765678998743456976745457891045976589101956 +1019894345967838798765696789984322246789989434989998745689977899987654579875432345679134989678999897 +2129943259878545897654987899876510135678998765678986534567898945998775689976543678989245698789989789 +3498899198989656976543498998765421234569999878789198645778999439899976789989774567899876789999877676 +9987788987698767897662349899896544346789789989891099876889789598789997898798765679943989899998764565 +8976547896549878999743456789987675487895679797992987989997678987678989998549978789952199978999543634 +7987436789432989987654589992398789598934589656789976599986569876569878987634599897893298767997432123 +6798545697653498998765678990999897679545678934699954349875498765498767896545987956789987659876541012 +5569658789894567899878799789897998798696799129789897598764349854323458997659876545678998434989752123 +3498767999965678945989895699766569999989894298998789987543212976212356789998987676799129323499843234 +2349879569876789234997964578957346988778995987688678999674309765301235789897698987899997434568974365 +1234989435989892199875453689541239879569789876576567898764312943213376898767539398999876567899765486 +0145895323499953987654312795432498765489678965435456999985429894524567999754321239899987678969876597 +2256789212989879876543201976643987654344567894324345899876998789634789698765210156799998789943987678 +3457894109876989987859349897656996432253456799210236789989897678945797549874321234567899999899998789 +7568943298765799998998998799787897641012345678921234999896789567896965434989939545689949876788999899 +8678954369934678999897687678998999832243658789762349896765689456789876629897898956893235965457999999 +9889876459895799999765458567899998954354567899943498775674578967899997898766757897932101294356789998 +2999987598789899987654323457899987895465678999899987654323789878998798987654646798943912989245679987 +1989998997678989987543212346789896789878789989768999765454789999997669597543434789799899878968798766 +9978999986569678998654343677898785698989899877657898986565678999976543496532323597698798967899999854 +8867898765474567898767654578998674567899998765434587897878989989898932989421014976597677657999878975 +7656569876343569999898767689776543456789679879523456789989999879789891978993429897989556547689969989 +6547434987212345899999878797654312367996567997612346789599899965656789767989598789876443234567898795 +5432129998323456789785989896543201498923489876324457893456789654345698654678987698654321015798997654 +7321098999974567897674599987654432349314567965435678932969898769296987563567897549976572123456789543 +5432987898765678976553678998865543458909689976645679659899999898989995432456789432987654234569899654 +7649876549989989865442345679976754567898990987876789798789999987678986321568897643498765365878978985 +8998765430199998754321256989987866678987891298987899898698789876569854310978998756789876476989767976 +9987654321248999987532347899998978989876789459998923999569656965498765423989989867899989588995456897 +3298765442357897598675456999899989896765678999879212679678949854349876534599878989989997678985345789 +4109877675456789459986587899788998765634789989765424598789799765456988545679767495678998789873276789 +5298988786767894367987898997697989654325699978996876969897678976567997657889654323567899898762177899 +6987699887878985499098999876586478999438798767889989853934569989698998768999767015678976999654567977 +7996567998989876989139798965432367878949899848779998762123493194989879879999899524569345999965678956 +9875456789991989878945697654331456567899995437567899643434789012978767989989998434679999889876789545 +3984345678910198867896989963210123458999876523458998755645678999767856899978987678798788768989897632 +1296456789321997457997979894523236569996543212568979877876799987653345678969998989989678456896999743 +3989587898459876346789868789754347678987954323678965989987894699542126789458999899876543267895989654 +9878999996598754265697754699965498789599875434567894395998913398653234892347898757995432126789878965 +8767898789987662154986543659876789894323987565678943214879901298764345891276789549876574235678969897 +8656797678996543012965432348997898965634598986789432102367892989865456789345678932997865348789556798 +6545689589898784329876541557889967996789679797899543223456999879876869995457799321099876789894346789 +5432123497659895839865432345678959889898797698998674334567896567987878976569899932989987899921256999 +6563234987643976749877565456789545678999896549019775476878923456798989987878979893978598978932349898 +7854599865532397956988987667896734567899975432129896587889212769899690198989458789867439569899998767 +8965987654321298967899998778954323479989876543599987898992101278943591989693245698754523498788897656 +9876998765434349879998999899655212345678987655989998999653234568932989876562134987643212989697789643 +9987899876545656989587899976542103456789198779878999998765356789549979989431023987654109878576679932 +9898943999856767895456789989653214567891019889767899979976487899998768999545124598543298765434567893 +9769432349767878974367895397654323456789326998752398765987599959897656598657234987654998654323478954 +8754321239879999865458943239765464567895445987631259854398910145789543498765345698769876543212356799 +9653210123989439876789432129896875689976556796532349876459321234895432349877456789878987643101234678 \ No newline at end of file diff --git a/src/day.h b/src/day.h index 4290ac7..88291db 100644 --- a/src/day.h +++ b/src/day.h @@ -9,5 +9,6 @@ int day_5(); int day_6(); int day_7(); int day_8(); +int day_9(); #endif //AOC_2021_DAY_H diff --git a/src/day_9.c b/src/day_9.c new file mode 100644 index 0000000..b684d32 --- /dev/null +++ b/src/day_9.c @@ -0,0 +1,288 @@ +#include +#include +#include + +#include "puzzle_input.h" +#include "day.h" +#include "queue.h" + +#define MAX_WIDTH 100 +#define QUEUE_SIZE 500 + +typedef struct { + int ii; + int jj; +} point_t; + +typedef struct { + int8_t map_data[MAX_WIDTH*MAX_WIDTH]; + uint8_t basin[MAX_WIDTH*MAX_WIDTH]; + uint8_t basin_count; + int16_t line_width; +} map_data_t; + +map_data_t map_data_g = {}; + +parse_ret_t parse_map_line(char * buffer, void * data, uint16_t index) { + map_data_t * map_data = (map_data_t *)data; + int8_t * map_line = map_data->map_data + index * MAX_WIDTH; + + int16_t line_ndx = 0; + while (buffer[line_ndx] != '\0') { + map_line[line_ndx] = buffer[line_ndx] - '0'; + line_ndx++; + } + + map_data->line_width = line_ndx; + + return PARSER_OK; +} + +uint8_t get_map_data(const uint8_t * data, int ii, int jj, uint16_t i_len, uint16_t j_len) { + if ((ii >= i_len) || (ii < 0) || (jj >= j_len) || (jj < 0)) { + return UINT8_MAX; + } + else { + return *(data + jj + ii * MAX_WIDTH); + } +} + +void set_map_data(uint8_t * data, int ii, int jj, uint16_t i_len, uint16_t j_len, uint8_t val) { + if ((ii >= i_len) || (ii < 0) || (jj >= j_len) || (jj < 0)) { + return; + } + else { + *(data + jj + ii * MAX_WIDTH) = val; + } +} + +int8_t is_min(uint8_t * data, int ii, int jj, uint16_t i_len, uint16_t j_len) { + uint8_t middle = get_map_data(data, ii, jj, i_len, j_len); + uint8_t up = get_map_data(data, ii-1, jj, i_len, j_len); + uint8_t down = get_map_data(data, ii+1, jj, i_len, j_len); + uint8_t left = get_map_data(data, ii, jj-1, i_len, j_len); + uint8_t right = get_map_data(data, ii, jj+1, i_len, j_len); + + if ((middle < up) && (middle < down) && (middle < left) && (middle < right)) { + return 1; + } + else { + return 0; + } +} + +static void print_map(uint8_t * map, uint16_t max_i, uint16_t max_j) { + for (int16_t ii = 0; (int16_t)ii < max_i; ii++) { + for (int16_t jj = 0; (int16_t) jj < max_j; jj++) { + printf("%u", get_map_data(map, ii, jj, max_i, max_j)); + } + printf("\n"); + } +} + +static void part_1(uint16_t len) { + uint16_t risk_sum = 0; + uint8_t basin_count = 1; + for (int ii = 0; ii < len; ii++) { + for (int jj = 0; jj < map_data_g.line_width; jj++) { + if (is_min((uint8_t *)map_data_g.map_data, ii, jj, len, map_data_g.line_width)) { + risk_sum += get_map_data((uint8_t *) map_data_g.map_data, ii, jj, len, map_data_g.line_width) + 1; + set_map_data(map_data_g.basin, ii, jj, len, map_data_g.line_width, basin_count); + basin_count++; + } + } + } + + map_data_g.basin_count = basin_count; + printf("PART 1: Low point risk sum is: %d\n", risk_sum); +} + +#define WALL 9 +static queue_ret_t queue_point(queue_t *queue, int pos_i, int pos_j, uint16_t max_i, uint16_t max_j) { + point_t point = {0}; + + if (get_map_data(map_data_g.basin, pos_i, pos_j, max_i, max_j) > 0) { + return QUEUE_OK; + } + + if (get_map_data((uint8_t *)map_data_g.map_data, pos_i, pos_j, max_i, max_j) == WALL) { + return QUEUE_OK; + } + + point.ii = pos_i; + point.jj = pos_j; + + if (point.ii > max_i || point.jj > max_j) { + printf("Invalid point attempted to be pushed onto queue\n"); + return QUEUE_DATA_INVALID; + } + + return push(queue, &point); +} + +point_t q_data_g[QUEUE_SIZE] = {0}; +static int flood_fill( int pos_i, int pos_j, uint16_t max_i, uint16_t max_j, uint8_t basin_count, uint8_t * basin_counts) +{ + queue_t queue = {0}; + point_t point = {0}; + queue_ret_t res; + + init(&queue, q_data_g, QUEUE_SIZE, sizeof(point_t)); + + point.ii = pos_i; + point.jj = pos_j; + + res = push(&queue, &point); + + basin_counts[basin_count - 1] = 1; + + if (res != QUEUE_OK) { + printf("Unable to insert element: %d", res); + return -1; + } + + while (queue.queued_elements > 0) { + res = pop(&queue, &point); + + if (res != QUEUE_OK) { + printf("Unable to pop element: %d", res); + return -1; + } + + if (point.ii > max_i || point.jj > max_j) { + printf("Invalid point popped from queue\n"); + return -1; + } + + uint8_t val = get_map_data(map_data_g.basin, point.ii, point.jj, max_i, max_j); + if (val == 0) { + set_map_data(map_data_g.basin, point.ii, point.jj, max_i, max_j, basin_count); + basin_counts[basin_count - 1]++; + } + + res = queue_point(&queue, point.ii + 1, point.jj, max_i, max_j); + + if (res != QUEUE_OK) { + printf("Unable to push element: %d\n", res); + return -1; + } + + res = queue_point(&queue, point.ii, point.jj + 1, max_i, max_j); + + if (res != QUEUE_OK) { + printf("Unable to push element: %d\n", res); + return -1; + } + + res = queue_point(&queue, point.ii -1, point.jj, max_i, max_j); + + if (res != QUEUE_OK) { + printf("Unable to push element: %d\n", res); + return -1; + } + + res = queue_point(&queue, point.ii, point.jj - 1, max_i, max_j); + + if (res != QUEUE_OK) { + printf("Unable to push element: %d\n", res); + return -1; + } + + //printf("%d: (%d, %d)\n", basin_count, point.ii, point.jj); + //print_map(map_data_g.basin, max_i, max_j); + //printf("\n"); + } + + return 0; +} + +static int find_basin(uint8_t basin, uint16_t max_i, uint16_t max_j, int16_t *ret_ii, int16_t *ret_jj) { + int found = 0; + int16_t ii; + int16_t jj; + + for (ii = 0; (int16_t)ii < max_i; ii++) { + for (jj= 0; (int16_t)jj < max_j; jj++) { + if (get_map_data(map_data_g.basin, ii, jj, max_i, max_j) == basin) { + found = 1; + break; + } + } + + if (found) { + break; + } + } + + if (found) { + *ret_ii = ii; + *ret_jj = jj; + return 1; + } + else { + return 0; + } +} + + + + +static int uin8t_cmp(const void * a, const void * b) { + return ( *(uint8_t *)a - *(uint8_t *)b ); +} + +#define BASIN_COUNTS 250 +uint8_t basin_counts[BASIN_COUNTS] = {0}; +static void part_2(uint16_t len) { + uint16_t max_i = len; + uint16_t max_j = map_data_g.line_width; + uint32_t basin_size_multiplied; + uint8_t basin_count = map_data_g.basin_count; + int16_t basin_ii = 0; + int16_t basin_jj = 0; + + if (basin_count - 1 > BASIN_COUNTS) { + printf("Too many basin counts! Need: %u\n", basin_count); + return; + } + + for (uint8_t basin_ndx = 1; basin_ndx < map_data_g.basin_count; basin_ndx++) { + + if (find_basin(basin_ndx, max_i, max_j, &basin_ii, &basin_jj)) { + if (flood_fill(basin_ii, basin_jj, max_i, max_j, basin_ndx, basin_counts) < 0) { + printf("Unable to process basin: %d\n", basin_ndx); + return; + } + } + else { + printf("Basin %u, not found!\n", basin_ndx); + return; + } + } + + + qsort(basin_counts, basin_count-1, sizeof(uint8_t), uin8t_cmp); + + basin_size_multiplied = basin_counts[basin_count-2] * basin_counts[basin_count - 3] * basin_counts[basin_count - 4]; + + printf("PART 2: Multiplying the size of the 3 largest basins gives: %d\n", basin_size_multiplied); +} + +int day_9() { + parse_ret_t res; + uint16_t len; + + res = read_input_single_line("../inputs/day_9.txt", (void *)&map_data_g, MAX_WIDTH, parse_map_line, &len); + + if (res != PARSER_OK) { + printf("Failed to parse input: %d\n", res); + return -1; + } + + part_1(len); + part_2(len); + + + return 0; + +} \ No newline at end of file diff --git a/src/main.c b/src/main.c index c49f7ac..17bb462 100644 --- a/src/main.c +++ b/src/main.c @@ -40,6 +40,9 @@ int main(int argc, char * argv[]) { case 8: day_8(); break; + case 9: + day_9(); + break; default: printf("Invalid day ding dong!\n"); return -2; diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..6f4eff6 --- /dev/null +++ b/src/queue.c @@ -0,0 +1,46 @@ +#include "string.h" +#include "queue.h" + +static size_t next_element(size_t index, size_t max_len) { + return (index + 1) % max_len; +} + +queue_ret_t init(queue_t * queue, void * data, size_t max_data_size, size_t element_size) { + queue->data = data; + queue->max_data_size = max_data_size; + queue->element_size = element_size; + queue->queued_elements = 0; + queue->pop_ndx = 0; + queue->push_ndx = 0; + + return QUEUE_OK; +} + +queue_ret_t push(queue_t * queue, void * element) { + if (queue->queued_elements >= queue->max_data_size) { + return QUEUE_FULL; + } + + memcpy(queue->data + (queue->push_ndx*queue->element_size), element, queue->element_size); + + queue->push_ndx = next_element(queue->push_ndx, queue->max_data_size); + + queue->queued_elements++; + + return QUEUE_OK; +} + +queue_ret_t pop(queue_t * queue, void * store_to) { + if (queue->queued_elements == 0) { + return QUEUE_EMPTY; + } + + memcpy(store_to, queue->data + (queue->pop_ndx*queue->element_size), queue->element_size); + + queue->pop_ndx = next_element(queue->pop_ndx, queue->max_data_size); + + queue->queued_elements--; + + return QUEUE_OK; + +} \ No newline at end of file diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 0000000..5eaff2b --- /dev/null +++ b/src/queue.h @@ -0,0 +1,28 @@ +#ifndef AOC_2021_QUEUE_H +#define AOC_2021_QUEUE_H + +#include +#include + +typedef enum { + QUEUE_OK, + QUEUE_FULL = -1, + QUEUE_EMPTY = -1, + QUEUE_DATA_INVALID = -1, +} queue_ret_t; + +typedef struct { + void * data; + size_t push_ndx; + size_t pop_ndx; + size_t queued_elements; + size_t max_data_size; + size_t element_size; +} queue_t; + +queue_ret_t init(queue_t * queue, void * data, size_t max_data_size, size_t element_size); +queue_ret_t push(queue_t * queue, void * element); +queue_ret_t pop(queue_t * queue, void * store_to); + + +#endif //AOC_2021_QUEUE_H