const readline = require('readline') const rl = readline.createInterface({ input: process.stdin, terminal: false }) lines = [] rl.on('line', (line) => { let raw = line.replace('\n', '').replace(' ', '') if (raw.length > 0) { lines.push(raw) } }) rl.on('close', () => { const db = false let rows = lines.map(l => l.split('').map(nb => parseInt(nb))) //console.log(rows) // first part: find low points let lowPoints = [] let lowPointsCoord = [] for (let i = 0; i < rows.length; i++) { for (let j = 0; j < rows[i].length; j++) { let val = rows[i][j] let toCmpWith = [[i-1, j], [i, j+1], [i+1, j], [i, j-1]] let success = true for (var k = 0; k < toCmpWith.length; k++) { let [ y,x ] = toCmpWith[k] if ( y < 0 || y >= rows.length || x < 0 || x >= rows[i].length ) { // ignore, because these point don't exists continue } // important: you have to use less or equal HERE! if (rows[y][x] <= val) { success = false break } } if (success) { lowPoints.push(val) lowPointsCoord.push([i, j]) } } } // second part: find bassins let findBassin = (alreadySeen, toSee) => { if (toSee.length == 0) { return [] } const e = toSee[0] const [y,x] = e // check if the point exists if ( y < 0 || y >= rows.length || x < 0 || x >= rows[y].length ) { return findBassin(alreadySeen, toSee.slice(1)) } // check if it's 9 if (rows[y][x] == 9) { return findBassin(alreadySeen, toSee.slice(1)) } // check if it's already seen if (alreadySeen.filter(([_y, _x]) => _y == y && _x == x).length > 0) { return findBassin(alreadySeen, toSee.slice(1)) } neighbours = [[y-1, x], [y, x+1], [y+1, x], [y, x-1]] res = findBassin([e, ...alreadySeen], [...neighbours, ...(toSee.slice(1))]) return [e, ...res] } let bassins = lowPointsCoord.map(c => findBassin([], [c])) let bassinsSizes = bassins .map(b => parseInt(b.length)) .sort((a, b) => a - b) .slice(-3) bassinsSizesProduct = bassinsSizes.reduce((a, p) => a*p) let bassinsCoords = bassins.flat() // output mini map of bassins if (db) { for (var i = 0; i < rows.length; i++) { rowOutput = '' for (var j = 0; j < rows[i].length; j++) { if (bassinsCoords.filter(([y, x]) => y == i && x == j).length > 0) { rowOutput += '\033[1m' + rows[i][j] + '\033[0m' } else { rowOutput += rows[i][j] } } console.log(rowOutput) } } let risks = lowPoints.map(height => 1+height) let sum = risks.reduce((e, s) => e+s) console.log(`Sum of the risk level of low points: ${sum}`) console.log(`Product of 3 largest bassins size: ${bassinsSizesProduct}`) })