/* Require bison minimal version */ %require "3.2" /* write out a header file containing the token defines */ %header // Code for the header file generated by bison %code requires { typedef void* yyscan_t; struct parser_state { /// Layout of the data: forest[row][col] unsigned short **forest; size_t rows; size_t cols; unsigned short *current_line; /// for tracking the current position in a line during parsing size_t pos; size_t allocated; }; } // Code for the c file %{ #include #include #include #include "parser.h" #include "lexer.h" void yyerror(struct parser_state* state, yyscan_t scanner, const char* msg) { (void)state; (void)scanner; fprintf(stderr, "\033[93mSyntax Error: %s\033[0m\n", msg); } %} // define a reentrant parser %define api.pure // enable parser tracing and detailed error messages (plus Lookahead Correction) %define parse.trace %define parse.error detailed %define parse.lac full %lex-param { yyscan_t scanner } %parse-param { struct parser_state* state } %parse-param { yyscan_t scanner } %union { unsigned long num; } %start input %token NEWLINE %token NUM %term END_OF_FILE %% input : treerow input | END_OF_FILE { return 0; } ; treerow : NUM treerow { if (state->pos >= state->allocated) { state->allocated += 10; state->current_line = realloc(state->current_line, state->allocated * sizeof(unsigned short)); if (!state->current_line) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); YYABORT; } } state->current_line[state->pos] = $1; state->pos++; } | NEWLINE { if (state->pos != 0) { state->forest = realloc(state->forest, (state->rows + 1) * sizeof(unsigned short *)); if (!state->forest) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); YYABORT; } // resize the current line if necessary if (state->allocated > state->pos) { state->current_line = realloc(state->current_line, state->pos * sizeof(unsigned short)); // cannot really fail but oh well if (!state->current_line) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); YYABORT; } } if (state->pos != state->cols) { if (state->cols != 0) { fprintf(stderr, "\033[91m[error] Column size has changed mid-parse\033[0m\n"); YYERROR; } state->cols = state->pos; } // write the current line to the forest state->forest[state->rows] = state->current_line; state->rows++; // initialize a new row state->allocated = state->cols; state->pos = 0; state->current_line = calloc(state->allocated, sizeof(unsigned short)); if (!state->current_line) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); YYABORT; } } } ; %% unsigned long compute_scenic_score(struct parser_state *state, size_t row, size_t col) { unsigned short height = state->forest[row][col]; unsigned long up = 0; for (int r = row - 1; r >= 0; r--) { up++; if (state->forest[r][col] >= height) { break; } } unsigned long down = 0; for (size_t r = row + 1; r < state->rows; r++) { down++; if (state->forest[r][col] >= height) { break; } } unsigned long left = 0; for (int c = col - 1; c >= 0; c--) { left++; if (state->forest[row][c] >= height) { break; } } unsigned long right = 0; for (size_t c = col + 1; c < state->cols; c++) { right++; if (state->forest[row][c] >= height) { break; } } return up * down * left * right; } int main(void) { struct parser_state *state = calloc(1, sizeof(struct parser_state)); if (!state) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); return EXIT_FAILURE; } state->allocated = 100; state->current_line = calloc(state->allocated, sizeof(unsigned short)); if (!state->current_line) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); return EXIT_FAILURE; } yyscan_t scanner; if (yylex_init(&scanner)) { fprintf(stderr, "\033[91m[error] Could not initialize lexer\033[0m\n"); return EXIT_FAILURE; } if (yyparse(state, scanner)) { // TODO: Error handling https://www.gnu.org/software/bison/manual/html_node/Parser-Function.html // error during parse occured return EXIT_FAILURE; } yylex_destroy(scanner); // task 1 // create a bitmap marking counted visible trees bool **bitmap = calloc(state->rows, sizeof(bool *)); if (!bitmap) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); return EXIT_FAILURE; } for (size_t i = 0; i < state->rows; i++) { bitmap[i] = calloc(state->cols, sizeof(bool)); if (!bitmap[i]) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); return EXIT_FAILURE; } } // count all outer rows and cols as visible unsigned long visible = 0; for (size_t c = 0; c < state->cols; c++) { unsigned short tallest = state->forest[0][c]; bitmap[0][c] = true; visible++; // top->down for (size_t r = 0; r < (state->rows - 1); r++) { if (state->forest[r][c] > tallest) { tallest = state->forest[r][c]; if (!bitmap[r][c]) { visible++; bitmap[r][c] = true; } } } // bottom->up tallest = state->forest[state->rows - 1][c]; visible++; bitmap[state->rows - 1][c] = true; for (size_t r = state->rows - 1; r > 0; r--) { if (state->forest[r][c] > tallest) { tallest = state->forest[r][c]; if (!bitmap[r][c]) { visible++; bitmap[r][c] = true; } } } } // move through individual rows for (size_t r = 0; r < state->rows; r++) { unsigned short tallest = state->forest[r][0]; if (!bitmap[r][0]) { bitmap[r][0] = true; visible++; } // left->right for (size_t c = 0; c < (state->cols - 1); c++) { if (state->forest[r][c] > tallest) { tallest = state->forest[r][c]; if (!bitmap[r][c]) { visible++; bitmap[r][c] = true; } } } // right->left tallest = state->forest[r][state->cols - 1]; if (!bitmap[r][state->cols - 1]) { bitmap[r][state->cols - 1] = true; visible++; } for (size_t c = state->cols - 1; c > 0; c--) { if (state->forest[r][c] > tallest) { tallest = state->forest[r][c]; if (!bitmap[r][c]) { visible++; bitmap[r][c] = true; } } } } printf("Visible trees: %zu\n", visible); unsigned long best = 0; for (size_t r = 0; r < state->rows; r++) { for (size_t c = 0; c < state->cols; c++) { unsigned long tmp = compute_scenic_score(state, r, c); if (tmp > best) { best = tmp; } } } printf("Best scenic score: %zu\n", best); return 0; }