#include #include #include #include #include #include #include #define RESET "\033[0m" #define RED "\033[31m" #define DEBUG #define INPUT_FILE ("../input.txt") #define MAX_NUMBERS_DRAWN (1024) #define MAX_BOARDS (256) /* Think of the win_conditions array as this table of win conditions WIN CONDITIONS * x x x x x * x x x x x * x x x x x * x x x x x * * x x x x x * x x x x x * x x x x x * x x x x x * * x x x x x * x x x x x * x x x x x * x x x x x * * x x x x x * x x x x x * x x x x x * x x x x x * * x x x x x * x x x x x * x x x x x * x x x x x * * * * * * x x x x x x x x x x x x x x x x x x x x x x x x x * * * * * x x x x x x x x x x x x x x x x x x x x x x x x x * * * * * x x x x x x x x x x x x x x x x x x x x x x x x x * * * * * x x x x x x x x x x x x x x x x x x x x x x x x x * * * * * */ const uint32_t win_conditions[10] = { 0b00000000000100001000010000100001, 0b00000000001000010000100001000010, 0b00000000010000100001000010000100, 0b00000000100001000010000100001000, 0b00000001000010000100001000010000, 0b00000000000000000000000000011111, 0b00000000000000000000001111100000, 0b00000000000000000111110000000000, 0b00000000000011111000000000000000, 0b00000001111100000000000000000000 }; typedef struct board_t { uint8_t matrix[5][5]; // idk what to call this // its just a u32, if the number in a slot x has been drawn, // then a 1 will be in that bit position inside of this number // example: slot[3][4] = (3 * 5) + 4 = 19, if this slot has been drawn, // bit position 19 will be a 1 uint32_t output; uint8_t most_recently_drawn; // if true, its got a bingo bool bingo_status; }board_t; bool bingo_board_win_check(const board_t* board); int bingo_board_compute_answer(const board_t* board); bool bingo_add_new_entry(board_t* board, uint8_t num); void print_bingo_board(const board_t* board); int main(void) { int p1_answer = 0; int p2_answer = 0; board_t bingo_bank[MAX_BOARDS]; uint16_t bingo_board_count = 0; uint8_t bingo_drawn_numbers[MAX_NUMBERS_DRAWN]; uint16_t bingo_drawn_numbers_ct = 0; memset(bingo_bank, 0, sizeof(board_t) * MAX_BOARDS); FILE* fp = fopen(INPUT_FILE, "r"); if(fp == NULL) { printf("Failed to open input file for reading...\n"); exit(-1); } size_t len; ssize_t rc; char* line = NULL; rc = getline(&line, &len, fp); const char* delim = ", \r\n"; char* tok = strtok(line, delim); while(tok != NULL) { bingo_drawn_numbers[bingo_drawn_numbers_ct++] = strtoul(tok, NULL, 10); tok = strtok(NULL, delim); } while(bingo_board_count < MAX_BOARDS && fp != NULL) { // continue to numbers.... char c = '\0'; while(!isdigit(c) && !feof(fp)) { c = fgetc(fp); } if(feof(fp)) { break; } fseek(fp, -1, SEEK_CUR); for(int ind = 0; ind < 5; ind++) { rc = getline(&line, &len, fp); if(rc < 0) { printf("some error while parsing"); exit(-1); } sscanf(line, "%2" SCNu8 " " "%2" SCNu8 " " "%2" SCNu8 " " "%2" SCNu8 " " "%2" SCNu8 " ", &bingo_bank[bingo_board_count].matrix[ind][0], &bingo_bank[bingo_board_count].matrix[ind][1], &bingo_bank[bingo_board_count].matrix[ind][2], &bingo_bank[bingo_board_count].matrix[ind][3], &bingo_bank[bingo_board_count].matrix[ind][4]); } bingo_board_count++; } #ifdef DEBUG for(int ind = 0; ind < bingo_board_count; ind++) { print_bingo_board(&bingo_bank[ind]); } #endif for(int ind = 0; ind < bingo_drawn_numbers_ct; ind++) { #ifdef DEBUG printf("... drawing number ... Number #%d!\n", bingo_drawn_numbers[ind]); #endif for(int board = 0; board < bingo_board_count; board++) { if(bingo_add_new_entry(&bingo_bank[board], bingo_drawn_numbers[ind])) { p1_answer = bingo_board_compute_answer(&bingo_bank[board]); #ifdef DEBUG print_bingo_board(&bingo_bank[board]); #endif break; } #ifdef DEBUG print_bingo_board(&bingo_bank[board]); #endif } if(p1_answer != 0) { break; } } printf("Answer for part 1: %d\n", p1_answer); printf("Part 2... Begin!\n"); // to do part 2, we're going to completely restart // we could just keep going off of the above for loop to save time // but i want the solutions to be as separate as possible // so lets reset the count for(int board = 0; board < bingo_board_count; board++) { bingo_bank[board].output = 0; } // now we restart the process int completed_boards = 0; for(int ind = 0; ind < bingo_drawn_numbers_ct; ind++) { #ifdef DEBUG printf("... drawing number ... #%d!\n", bingo_drawn_numbers[ind]); #endif for(int board = 0; board < bingo_board_count; board++) { if(bingo_bank[board].bingo_status) { continue; } if(bingo_add_new_entry(&bingo_bank[board], bingo_drawn_numbers[ind])) { p2_answer = bingo_board_compute_answer(&bingo_bank[board]); bingo_bank[board].bingo_status = true; ++completed_boards; } #ifdef DEBUG print_bingo_board(&bingo_bank[board]); printf("Number of completed boards: %d\n", completed_boards); #endif } if(completed_boards >= bingo_board_count) { break; } } printf("Answer for part 2: %d\n", p2_answer); return 0; } // returns bool bingo_add_new_entry(board_t* board, uint8_t num) { for(int ind = 0; ind < 5; ind++) { for(int jind = 0; jind < 5; jind++) { if(board->matrix[ind][jind] == num) { board->output |= (1 << (ind * 5 + jind)); board->most_recently_drawn = num; return bingo_board_win_check(board); } } } return false; } bool bingo_board_win_check(const board_t* board) { for(int wc = 0; wc < 10; wc++) { // found a winner check if((board->output & win_conditions[wc]) == win_conditions[wc]) { return true; } } return false; } int bingo_board_compute_answer(const board_t* board) { int result = 0; for(int ind = 0; ind < 5; ind++) { for(int jind = 0; jind < 5; jind++) { if(!(board->output & (1 << ((ind * 5) + jind)))) { result += board->matrix[ind][jind]; } } } result *= board->most_recently_drawn; return result; } void print_bingo_board(const board_t* board) { printf("\n"); for(int ind = 0; ind < 5; ind++) { for(int jind = 0; jind < 5; jind++) { if(board->output & (1 << ((ind * 5) + jind))) { printf(RED "%2d " RESET, board->matrix[ind][jind]); } else { printf("%2d ", board->matrix[ind][jind]); } } printf("\r\n"); } }