const reversedCopy = (array) => { array = Array.from(array); array.reverse(); return array; } const multiply = (array) => array.reduce((prev, curr) => prev * curr); const flatten = (arr) => { return arr.reduce(function (flat, toFlatten) { return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten); }, []); } const countInArray = (array, idGenerator) => { const visibleTrees = []; let maxHeight = -1; for (let j=0; j < array.length; j++) { if (array[j] > maxHeight) { visibleTrees.push(idGenerator(j)); maxHeight = array[j]; } } return visibleTrees; } const getVisibleRow = (matrix, rowIndex, reverse) => { let row = matrix[rowIndex]; if (reverse) { row = reversedCopy(row); } return countInArray(row, (idx) => { return [ rowIndex, reverse ? row.length -1 - idx : idx ] }); } const getVisibleColumn = (matrix, columnIndex, reverse) => { let column = matrix.map(row => { return row[columnIndex]; }) if (reverse) { column = reversedCopy(column); } return countInArray(column, (idx) => { return [ reverse ? column.length - 1 - idx : idx, columnIndex ] }); } const main = (inputString) => { const matrix = inputString .split('\n') .map(line => { return line.split(''); }) const rowCount = matrix.length; const colCount = matrix[0].length; let visibleTrees = []; for (let i=0; i < rowCount; i++) { visibleTrees = visibleTrees .concat(getVisibleRow(matrix, i, false)) .concat(getVisibleRow(matrix, i, true)); } for (let i=0; i < colCount; i++) { visibleTrees = visibleTrees .concat(getVisibleColumn(matrix, i, false)) .concat(getVisibleColumn(matrix, i, true)); } const set = new Set(visibleTrees.map(t => `${t[0]}-${t[1]}`)); console.log('part 1', set.size); // brute force in all directions const directions = [ [-1, 0], [1, 0], [0, 1], [0, -1] ]; const scores = matrix.map((row, i) => { return row.map((height, j) => { const scores = directions.map(dir => { let x = i + dir[0]; let y = j + dir[1]; let viewDistance = 0; while (x >= 0 && x < matrix.length && y >= 0 && y < row.length) { viewDistance++; if (matrix[x][y] >= height) { break; } x += dir[0]; y += dir[1]; } return viewDistance; }) return multiply(scores) }) }) console.log('part 2', Math.max.apply(Math, flatten(scores))); }