291 lines
8.6 KiB
Text
291 lines
8.6 KiB
Text
|
/* 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdbool.h>
|
||
|
#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> 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;
|
||
|
}
|