|
| 1 | +// adapted from: https://www.algorithms-and-technologies.com/point_in_polygon/javascript |
| 2 | +const pointInPolygon = function (polygon, point) { |
| 3 | + let odd = false; |
| 4 | + |
| 5 | + // for each edge (in this case for each point of the polygon and the previous one) |
| 6 | + for (let i = 0, j = polygon.length - 1; i < polygon.length; i++) { |
| 7 | + // if a line from the point into infinity crosses this edge |
| 8 | + if (((polygon[i][1] > point[1]) !== (polygon[j][1] > point[1])) // one point needs to be above, one below our y coordinate |
| 9 | + // ...and the edge doesn't cross our x corrdinate before our x coordinate (but between our x coordinate and infinity) |
| 10 | + && (point[0] < ((polygon[j][0] - polygon[i][0]) * (point[1] - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0]))) { |
| 11 | + odd = !odd; |
| 12 | + } |
| 13 | + |
| 14 | + j = i; |
| 15 | + } |
| 16 | + |
| 17 | + return odd; |
| 18 | +}; |
| 19 | + |
| 20 | +module.exports = (input) => { |
| 21 | + let start = [0, 0]; |
| 22 | + |
| 23 | + const map = input.split('\n').map((line, y) => { |
| 24 | + return line.trim().split('').map((pipe, x) => { |
| 25 | + if (pipe === 'S') { |
| 26 | + start = [x, y]; |
| 27 | + } |
| 28 | + |
| 29 | + return { |
| 30 | + n: ['|', 'L', 'J'].includes(pipe), |
| 31 | + e: ['-', 'L', 'F'].includes(pipe), |
| 32 | + s: ['|', '7', 'F'].includes(pipe), |
| 33 | + w: ['-', 'J', '7'].includes(pipe), |
| 34 | + }; |
| 35 | + }); |
| 36 | + }); |
| 37 | + |
| 38 | + // patch map |
| 39 | + const sn = ((map[start[1] - 1] || [])[start[0]] || { s: false }).s; |
| 40 | + const se = (map[start[1]][start[0] + 1] || { w: false }).w; |
| 41 | + const ss = ((map[start[1] + 1] || [])[start[0]] || { n: false }).n; |
| 42 | + const sw = (map[start[1]][start[0] - 1] || { e: false }).e; |
| 43 | + |
| 44 | + if (sn && ss) { |
| 45 | + map[start[1]][start[0]] = { n: true, e: false, s: true, w: false }; |
| 46 | + } else if (sw && se) { |
| 47 | + map[start[1]][start[0]] = { n: false, e: true, s: false, w: true }; |
| 48 | + } else if (sn && se) { |
| 49 | + map[start[1]][start[0]] = { n: true, e: true, s: false, w: false }; |
| 50 | + } else if (sn && sw) { |
| 51 | + map[start[1]][start[0]] = { n: true, e: false, s: false, w: true }; |
| 52 | + } else if (ss && sw) { |
| 53 | + map[start[1]][start[0]] = { n: false, e: false, s: true, w: true }; |
| 54 | + } else if (ss && se) { |
| 55 | + map[start[1]][start[0]] = { n: false, e: true, s: true, w: false }; |
| 56 | + } |
| 57 | + |
| 58 | + let vector = sn ? [0, -1] : se ? [1, 0] : ss ? [0, 1] : sw ? [-1, 0] : undefined; |
| 59 | + let position = [start[0], start[1]]; |
| 60 | + let positions = new Set(); |
| 61 | + let vertices = []; |
| 62 | + |
| 63 | + do { |
| 64 | + const [vx, vy] = vector; |
| 65 | + const [x2, y2] = [position[0] + vector[0], position[1] + vector[1]]; |
| 66 | + const { n, e, s, w } = map[y2][x2]; |
| 67 | + |
| 68 | + vector = vx === -1 ? (n ? [0, -1] : w ? [-1, 0] : [0, 1]) : |
| 69 | + vx === 1 ? (n ? [0, -1] : e ? [1, 0] : [0, 1]) : |
| 70 | + vy === -1 ? (n ? [0, -1] : e ? [1, 0] : [-1, 0]) : |
| 71 | + vy === 1 ? (s ? [0, 1] : e ? [1, 0] : [-1, 0]) : undefined; |
| 72 | + |
| 73 | + if (vector[0] !== vx && vector[1] !== vy) { |
| 74 | + vertices.push([x2, y2]); |
| 75 | + } |
| 76 | + |
| 77 | + position = [x2, y2]; |
| 78 | + positions.add(`${position[0]},${position[1]}`); |
| 79 | + } while (position[0] !== start[0] || position[1] !== start[1]); |
| 80 | + |
| 81 | + let inside = 0; |
| 82 | + |
| 83 | + for (let y = 0; y < map.length; y++) { |
| 84 | + for (let x = 0; x < map[y].length; x++) { |
| 85 | + inside += !positions.has(`${x},${y}`) && pointInPolygon(vertices, [x, y]) ? 1 : 0; |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + return inside; |
| 90 | +}; |
0 commit comments