aoc-2022/day_8/parser.y

291 lines
8.6 KiB
Text
Raw Permalink Normal View History

2023-01-08 22:21:01 +00:00
/* 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;
}