day04_02.c (5105B)
1 #if 0 2 # Self-building c file. Invoke like: `./file.c` 3 outdir=out 4 input=$(basename "$0") 5 output="$outdir"/$(basename "$0" .c) 6 if [ "$input" -nt "$output" ]; 7 then 8 mkdir --parents "$outdir" || exit 9 echo "Building ${output}." || exit 10 clang -std=c11 -Wall -Wextra -pedantic -Wno-unused-function -I../../amlibs/ "$input" -o "$output" || exit 11 fi 12 if [ "$1" = "-r" ]; 13 then 14 ./"$output" "$@" 15 fi 16 exit 17 #endif 18 19 #include <inttypes.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 _Noreturn void assert_fail(const char *expr, const char *file, int line, const char *func) { 25 fprintf(stderr, "%s:%d: %s: Assertion failed: '%s'\n", file, line, func, expr); 26 abort(); 27 } 28 29 #define AM_ENABLE_ASSERT 1 30 #define AM_ASSERT_FAIL(expr, file, line, func) assert_fail(expr, file, line, func) 31 #include "am_base.h" 32 #include "am_memory.h" 33 #include "am_list.h" 34 #include "am_string.h" 35 36 Str open_file(MemArena *arena, char *path) { 37 FILE *f = fopen(path, "r"); 38 assert(f); 39 40 s32 error = fseek(f, 0L, SEEK_END); 41 assert(!error); 42 43 s64 size = ftell(f); 44 assert(size >= 0); 45 rewind(f); 46 47 u8 *buf = am_mem_arena_push(arena, size); 48 assert(buf); 49 50 size_t items_read = fread(buf, 1, size, f); 51 assert(items_read == (size_t)size); 52 53 error = fclose(f); 54 assert(!error); 55 56 return am_str(buf, size); 57 } 58 59 int compare_u64(const void *a, const void *b) { 60 u64 num_a = *((u64 *)a); 61 u64 num_b = *((u64 *)b); 62 if (num_a == num_b) { 63 return 0; 64 } else if (num_a < num_b) { 65 return -1; 66 } else { 67 return 1; 68 } 69 } 70 71 s64 parse_number(Str s) { 72 s64 number = 0; 73 for (u64 i = 0; i < s.size; i++) { 74 assert(s.str[i] >= '0' && s.str[i] <= '9'); 75 number = (number * 10) + (s.str[i] - '0'); 76 } 77 return number; 78 } 79 80 int main(void) { 81 MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc()); 82 Str input = open_file(&a, "day04_input.txt"); 83 84 StrList split_data = am_str_split(&a, input, (u8 *)"\n ", 2); 85 am_str_list_discard_empty(&split_data); 86 StrList split_first_line = am_str_split(&a, split_data.first->s, (u8 *)",", 1); 87 88 u64 drawn_number_count = split_first_line.node_count; 89 u64 board_number_count = split_data.node_count - 1; 90 assert(board_number_count % 25 == 0); 91 92 s64 *drawn_numbers = AM_MEM_ARENA_PUSH_ARRAY(&a, s64, drawn_number_count); 93 s64 *board_numbers = AM_MEM_ARENA_PUSH_ARRAY(&a, s64, board_number_count); 94 95 { 96 u64 i = 0; 97 for (StrListNode *number = split_first_line.first; number; number = number->next) { 98 drawn_numbers[i] = parse_number(number->s); 99 i++; 100 } 101 assert(i == drawn_number_count); 102 } 103 104 { 105 u64 i = 0; 106 for (StrListNode *number = split_data.first->next; number; number = number->next) { 107 board_numbers[i] = parse_number(number->s); 108 i++; 109 } 110 assert(i == board_number_count); 111 } 112 113 u64 winning_score = 0; 114 u64 win_count = 0; 115 u64 board_count = board_number_count / 25; 116 bool *board_win_status = AM_MEM_ARENA_PUSH_ARRAY(&a, bool, board_count); 117 memset(board_win_status, 0, board_count * sizeof(bool)); 118 119 for (u64 drawn_i = 0; drawn_i < drawn_number_count; drawn_i++) { 120 s64 drawn = drawn_numbers[drawn_i]; 121 122 for (u64 board_i = 0; board_i < board_number_count; board_i++) { 123 if (board_numbers[board_i] == drawn) { 124 board_numbers[board_i] = -1; 125 } 126 } 127 128 u8 row_count = 0; 129 u8 col_count[5] = {0}; 130 for (u64 board_i = 0; board_i < board_number_count; board_i++) { 131 u64 board = board_i / 25; 132 if (board_win_status[board]) { 133 continue; 134 } 135 136 u64 cell = board_i % 25; 137 u64 row = cell / 5; 138 u64 col = cell % 5; 139 140 row_count += board_numbers[board_i] == -1; 141 col_count[col] += board_numbers[board_i] == -1; 142 143 bool game_won = false; 144 if ((cell + 1) / 5 != row) { 145 if (row_count == 5) { 146 game_won = true; 147 } 148 row_count = 0; 149 } 150 151 if (row == 4) { 152 if (col_count[col] == 5) { 153 game_won = true; 154 } 155 col_count[col] = 0; 156 } 157 158 if (game_won) { 159 board_win_status[board] = true; 160 win_count++; 161 if (win_count == board_count) { 162 for (u64 i = board * 25; i < board * 25 + 25; i++) { 163 winning_score += board_numbers[i] * (board_numbers[i] != -1); 164 } 165 winning_score *= drawn; 166 goto game_over; 167 } 168 row_count = 0; 169 memset(col_count, 0, 5); 170 } 171 } 172 } 173 174 game_over: 175 if (win_count) { 176 printf("Winning score of last winning board: %" PRIu64 "\n", winning_score); 177 } else { 178 printf("No Winning Board!\n"); 179 } 180 181 am_mem_arena_release(&a); 182 return 0; 183 }