const ASSIGNMENT = 'assignment'; const ANSWER = 'answer'; const ALGORITHM_CHECKBOX = 'algorithm'; const NEWLINE_CHARACTER = '\n'; /** * Main function */ window.onload = function () { document.getElementById(ASSIGNMENT).addEventListener("input", calculateAnswer); document.getElementById(ALGORITHM_CHECKBOX).addEventListener("click", calculateAnswer); } /** * Listener function for input in assignment field. * @param event the onInput event */ function calculateAnswer(event) { console.info("Calculating answer for input..."); let assignment = document.getElementById(ASSIGNMENT).value; let getHighestScenicScore = document.getElementById(ALGORITHM_CHECKBOX).checked; let answer = algorithm(assignment, getHighestScenicScore); document.getElementById(ANSWER).innerText = answer; } /** * Calculate the answer to assignment. * @param assignment the input from the assignment. * @return string the answer */ function algorithm(assignment, getHighestScenicScore) { let lines = assignment.trim().split(NEWLINE_CHARACTER); console.info("Linecount:" + lines.length); let visibleTreeCount = 0; let highestScenicScore = 0; for (let i = 0; i < lines.length; i++) { let row = lines[i].trim(); for (let j = 0; j < row.length; j++) { if (i <= 0 || i >= lines.length - 1 || j <= 0 || j >= row.length - 1) { // Edge node //console.debug("Edge node found."); visibleTreeCount++; continue; } let height = parseInt(lines[i].charAt(j)); if (!walkRowVisible(height, j, row) && !walkColumnVisible(height, i, j, lines)) { console.log("Found invisible tree, height:" + height + ", i:" + i + ", j:" + j); visibleTreeCount--; } if (getHighestScenicScore) { let scenicScore = walkRowCount(height, j, row) * walkColumnCount(height, i, j, lines); if (scenicScore > highestScenicScore) { console.debug("Found new highest scenic score: " + scenicScore); highestScenicScore = scenicScore; } } // Tree is on edge. visibleTreeCount++; } } if (getHighestScenicScore) { return "Highest scenic score: " + highestScenicScore; } return "Amount of visible trees in the grid: " + visibleTreeCount; } function walkColumnCount(height, index, rowIndex, column) { return walkCount(height, index, column, false, rowIndex); } function walkRowCount(height, index, row) { return walkCount(height, index, row, true, -1); } function walkColumnVisible(height, index, rowIndex, column) { return walkVisible(height, index, column, false, rowIndex); } function walkRowVisible(height, index, row) { return walkVisible(height, index, row, true, -1); } function walkCount(height, index, line, isRow, rowIndex) { let visibleLeftCount = __walkHelper(height, index, line, isRow, -1, rowIndex, 0); let visibleRightCount = __walkHelper(height, index, line, isRow, 1, rowIndex, 0); return visibleLeftCount * visibleRightCount; } function walkVisible(height, index, line, isRow, rowIndex) { let visibleLeft = __walkHelper(height, index, line, isRow, -1, rowIndex); let visibleRight = __walkHelper(height, index, line, isRow, 1, rowIndex); return visibleLeft || visibleRight; } function __walkHelper(height, index, line, isRow, direction, rowIndex, count) { if (direction == 0) { console.error("Invalid direction 0 in __walkhelper"); return -1; } direction = direction / Math.abs(direction); // Edge reached if ((direction < 0 && index <= 0) || (direction > 0 && index >= line.length - 1)) { return (count == undefined) ? true : count; } let nextIndex = index + direction; let nextHeightCharacter = (isRow) ? line.charAt(nextIndex) : line[nextIndex].trim().charAt(rowIndex); let nextHeight = parseInt(nextHeightCharacter); if (isNaN(height) || isNaN(nextHeightCharacter)) { console.error("Invalid height found, height:" + height + ", nextHeight: " + nextHeightCharacter); return -1; } if (height <= nextHeight) { if (count == undefined) return false; return count + 1; } return __walkHelper(height, nextIndex, line, isRow, direction, rowIndex, (count !=undefined)? count + 1 : undefined); }