소스 검색

Add day 9

Soof 4 주 전
부모
커밋
21917c4383
1개의 변경된 파일268개의 추가작업 그리고 0개의 파일을 삭제
  1. 268 0
      Day9.js

+ 268 - 0
Day9.js

@@ -0,0 +1,268 @@
+// Run this by pasting it into the browser window of the URL "https://adventofcode.com/2025/day/9/input"
+// It is very slow, takeing multiple seconds
+
+{
+    const response = await fetch(window.location.href)
+    const input = await response.text()
+    // const input = "7,1\n11,1\n11,7\n9,7\n9,5\n2,5\n2,3\n7,3"
+
+    const points = []
+
+    for (const line of input.split("\n")) {
+        const [x, y] = line.split(",")
+        if (x) {
+            const point = [parseInt(x), parseInt(y)]
+            points.push(point)
+        }
+    }
+    
+    let parity = 0
+    {
+        let p1 = points[points.length-2]
+        let p2 = points[points.length-1]
+        for (let i = 0; i < points.length; i++) {
+            const p3 = points[i]
+            if (p1[0] === p2[0] && p2[1] == p3[1]) {
+                parity = parity - Math.sign((p2[1] - p1[1]) * (p3[0] - p2[0]))
+            } else if (p1[1] === p2[1] && p2[0] == p3[0]) {
+                parity = parity + Math.sign((p2[0] - p1[0]) * (p3[1] - p2[1]))
+            }
+            p1 = p2
+            p2 = p3
+        }
+    }
+
+    let rightIsInside = parity > 0;
+    console.log(rightIsInside ? "Right is inside" : "Left is inside")
+    
+    let squares = []
+    for (const [i, p1] of points.entries()) {
+        for (let j = 0; j < i; j++) {
+            const p2 = points[j]
+            const size = (Math.abs(p1[0] - p2[0]) + 1) * (Math.abs(p1[1] - p2[1]) + 1)
+            squares.push([size, p1, p2])
+        }
+    }
+    
+    squares.sort(([s1], [s2]) => s2 - s1)
+    console.log("Answer part 1:", squares[0][0])
+
+    function cornersToRange(c1, c2) {
+        return square = [
+            [Math.min(c1[0], c2[0]), Math.min(c1[1], c2[1])],
+            [Math.max(c1[0], c2[0]), Math.max(c1[1], c2[1])]
+        ]
+    }
+    
+    function lineToVerticalRange(p1, p2) {
+        if (p1[1] == p2[1]) {
+            const lineParity = Math.sign(p2[0] - p1[0]) * parity
+            return [
+                [Math.min(p1[0], p2[0]), lineParity > 0 ? p1[1] : - Infinity],
+                [Math.max(p1[0], p2[0]), lineParity > 0 ? Infinity : p1[1]]
+            ]
+        }
+        return null
+    }
+
+    function intersect([lb1, ub1], [lb2, ub2]) {
+        const intersection = [
+            [Math.max(lb1[0], lb2[0]), Math.min(ub1[0], ub2[0])],
+            [Math.max(lb1[1], lb2[1]), Math.min(ub1[1], ub2[1])]
+        ]
+        if (intersection[0][0] > intersection[1][0] || intersection[0][1] > intersection[1][1]) {
+            return null
+        }
+    }
+
+    function combineVerticalRange([lb1, ub1], [lb2, ub2]) {
+        if (ub1[1] <= lb2[1] || ub2[1] <= lb1[1] || (ub1[1] > ub2[1] && lb1[1] < lb2[1]) || (ub2[1] > ub1[1] && lb2[1] < lb1[1])) {
+            return [[[lb1, ub1]], [[lb2, ub2]], []]
+        }
+        const x1 = Math.max(lb1[0], lb2[0])
+        const x2 = Math.min(ub1[0], ub2[0])
+        if (x2 <= x1) {
+            return [[[lb1, ub1]], [[lb2, ub2]], []]
+        }
+
+        const split1 = []
+        const split2 = []
+        const union = []
+        if (lb1[0] < lb2[0]) {
+            split1.push([
+                [lb1[0], lb1[1]], 
+                [lb2[0], ub1[1]]
+            ])
+        } else if (lb2[0] < lb1[0]) {
+            split2.push([
+                [lb2[0], lb2[1]], 
+                [lb1[0], ub2[1]]
+            ])
+        }
+        if (ub2[0] > ub1[0]) {
+            split2.push([
+                [ub1[0], lb2[1]],
+                [ub2[0], ub2[1]]
+            ])
+        } else if (ub1[0] > ub2[0]) {
+            split1.push([
+                [ub2[0], lb1[1]],
+                [ub1[0], ub1[1]]
+            ])
+        }
+        if (lb1[1] < lb2[1]) {
+            if (lb1[1] > -Infinity) {
+                split1.push([
+                    [x1, lb1[1]],
+                    [x2, lb2[1]]
+                ])
+            }
+        } else if (lb2[1] < lb1[1]) {
+            if (lb2[1] > -Infinity) {
+                split2.push([
+                    [x1, lb2[1]],
+                    [x2, lb1[1]]
+                ])
+            }
+        }
+        const y1 = Math.max(lb1[1], lb2[1])
+        if (ub2[1] > ub1[1]) {
+            if (ub2[1] < Infinity) {
+                split2.push([
+                    [x1, ub1[1]],
+                    [x2, ub2[1]]
+                ])
+            }
+        } else if (ub1[1] > ub2[1]) {
+            if (ub1[1] < Infinity) {
+                split1.push([
+                    [x1, ub2[1]],
+                    [x2, ub1[1]]
+                ])
+            }
+        }
+        const y2 = Math.min(ub1[1], ub2[1])
+        union.push([
+            [x1, y1],
+            [x2, y2]
+        ])
+        return [split1, split2, union]
+    }
+    
+    function splitByYBound([lb, ub], [lyb, uyb]) {
+        if (lyb > ub[1] || uyb < lb[1]) {
+            return [[[lb, ub]], null]
+        }
+        const outside = []
+        if (lb[1] < lyb) {
+            outside.push([
+                [lb[0], lb[1]],
+                [ub[0], lyb - 1]
+            ])
+        }
+        if (ub[1] > uyb) {
+            outside.push([
+                [lb[0], uyb + 1],
+                [ub[0], ub[1]]
+            ])
+        }
+        const inside = [
+            [lb[0], Math.max(lb[1], lyb)],
+            [ub[0], Math.min(ub[1], uyb)]
+        ]
+        return [outside, inside]
+    }
+    
+    function splitByXBound([lb, ub], [lxb, uxb]) {
+        if (lxb > ub[0] || uxb < lb[0]) {
+            return [[[lb, ub]], null]
+        }
+        const outside = []
+        if (lb[0] < lxb) {
+            outside.push([
+                [lb[0], lb[1]],
+                [lxb - 1, ub[1]]
+            ])
+        }
+        if (ub[0] > uxb) {
+            outside.push([
+                [uxb + 1, lb[1]],
+                [ub[0], ub[1]]
+            ])
+        }
+        const inside = [
+            [Math.max(lb[0], lxb), lb[1]],
+            [Math.min(ub[0], uxb), ub[1]]
+        ]
+        return [outside, inside]
+        
+    }
+    
+    function subtractRange([lb1, ub1], [lb2, ub2]) {
+        const [outsideY, insideY] = splitByYBound([lb1, ub1], [lb2[1], ub2[1]])
+        if (insideY) {
+            const [outsideX, _] = splitByXBound(insideY, [lb2[0], ub2[0]])
+            outsideY.push(...outsideX)
+        }
+        return outsideY
+    }
+    
+    function combineLists(ranges1, ranges2) {
+        for (let i = 0; i < ranges1.length; i++) {
+            for (let j = 0; j < ranges2.length; j++) {
+                const range1 = ranges1[i]
+                const range2 = ranges2[j]
+                if (!range1) {
+                    break
+                }
+                if (range2) {
+                    const [split1, split2, union] = combineVerticalRange(range1, range2)
+                    split1.push(...union)
+                    ranges1[i] = split1.pop()
+                    ranges2[j] = split2.pop()
+                    ranges1.push(...split1)
+                    ranges2.push(...split2)
+                }
+            }
+        }
+        ranges1.push(...ranges2)
+        return ranges1.filter((x) => !!x)
+    }
+    
+    function subtractLists(ranges1, ranges2) {
+        for (let j = 0; j < ranges2.length; j++) {
+            const range2 = ranges2[j]
+            for (let i = 0; i < ranges1.length; i++) {
+                const range1 = ranges1[i]
+                if (!range1) {
+                    break
+                }
+                if (range2) {
+                    const res = subtractRange(range1, range2)
+                    ranges1[i] = res.pop()
+                    ranges1.push(...res)
+                }
+            }
+        }
+        return ranges1.filter((x) => !!x)
+    }
+
+    let ranges = []
+    let p1 = points[points.length-1]
+    for (let i = 0; i < points.length; i++) {
+        const p2 = points[i]
+        const range = lineToVerticalRange(p1, p2)
+        if (range) {
+            ranges = combineLists(ranges, [range])
+        }
+        p1 = p2
+    }
+
+    for (const [s, c1, c2] of squares) {
+        const empty = subtractLists([cornersToRange(c1, c2)], ranges)
+        if (empty.length == 0) {
+            console.log("Answer part 2:", s)
+            break
+        }
+    }
+}