#include #include #include #include #include // Check if a tree is newly seen, by being taller than max or not // // If it is seen, update max. // // If the tree is seen, and has not been seen before, return 1 // Otherwise return 0 int tree_seen(int * max, unsigned char * tree) { int height = (*tree & 0x7F) - '0'; int seen = 0; if (height > *max) { if (!(*tree & 0x80u)) { *tree |= 0x80u; ++seen; } *max = height; } return seen; } // Check the number of seen trees in a forest int forest_seen(unsigned char * forest, int rows, int cols) { int i, j, max, seen = 0; // For each row... for (i = 0; i < rows; ++i) { // Check which trees can be newly seen from the left for (j = 0, max = -1; j < cols - 1 && max < 9; ++j) { seen += tree_seen(&max, forest + i * cols + j); } // Check which trees can be newly seen from the right for (j = cols - 2, max = -1; j >= 0 && max < 9; --j) { seen += tree_seen(&max, forest + i * cols + j); } } // For each column... for (j = 0; j < cols - 1; ++j) { // Check which trees can be newly seen from the top for (i = 0, max = -1; i < rows && max < 9; ++i) { seen += tree_seen(&max, forest + i * cols + j); } // Check which trees can be newly seen from the bottom for (i = rows - 1, max = -1; i >= 0 && max < 9; --i) { seen += tree_seen(&max, forest + i * cols + j); } } return seen; } // Get the maximum scenic score for a tree int forest_maxscore(unsigned char * forest, int rows, int cols) { int i, j, max = 0; for (i = 1; i < rows - 1; ++i) { for (j = 1; j < cols - 2; ++j) { int dist; int score = 1; int height = forest[i * cols + j]; for (dist = 1; j - dist > 0; ++dist) if (forest[i * cols + j - dist] >= height) break; score *= dist; for (dist = 1; j + dist < cols - 2; ++dist) if (forest[i * cols + j + dist] >= height) break; score *= dist; for (dist = 1; i - dist > 0; ++dist) if (forest[(i - dist) * cols + j] >= height) break; score *= dist; for (dist = 1; i + dist < rows - 1; ++dist) if (forest[(i + dist) * cols + j] >= height) break; score *= dist; if (score > max) max = score; } } return max; } int main(int argc, char ** argv) { int i, part = 1; int cols = 0, rows = 0; char * forest; while ((i = getopt(argc, argv, "p:")) != -1) { switch (i) { case 'p': part = atoi(optarg); break; default: return -1; } } // Read first line forest = malloc(BUFSIZ); if (!fgets(forest, BUFSIZ, stdin)) { fprintf(stderr, "Need more input!\n"); return -1; } cols = strlen(forest); if (cols < 2 || forest[cols - 1] != '\n') { fprintf(stderr, "Unexpected first line! (length %d)\n", cols); return -1; } ++rows; while (1) { // Resize forest for next line. // Do the dumb thing and rely on realloc() to overallocate and manage // exponential growth of the underlying buffer // // If we were expecting huge input, we could just ask for a filename and // mmap() it. char * p = realloc(forest, (long) cols * (rows + 1) + 1); if (!p) { fprintf(stderr, "Realloc %ld fail! (%s)\n", (long) cols * (rows + 1) + 2, strerror(errno)); free(forest); return -1; } forest = p; // Read line. p = forest + cols * rows; if (!fgets(p, cols + 1, stdin)) break; // Check line length if (strlen(p) != cols || p[cols - 1] != '\n') { fprintf(stderr, "Unexpected line length for %s\n", p); free(forest); return -1; } ++rows; } switch (part) { case 1: printf("Trees seen: %d\n", forest_seen((unsigned char *) forest, rows, cols)); break; case 2: printf("Best visibility: %d\n", forest_maxscore((unsigned char *) forest, rows, cols)); break; default: fprintf(stderr, "Unexpected part %d\n", part); free(forest); return -1; } free(forest); return 0; }