generated from eric/adventofcode2023
day nine both parts
This commit is contained in:
151
09/code.js
Normal file
151
09/code.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
let sampleMode = false;
|
||||
let usedArray = [];
|
||||
|
||||
const sampleArray = readFileSync('sample.txt').toString().split("\n");
|
||||
const inputArray = readFileSync('input.txt').toString().split("\n");
|
||||
|
||||
if (sampleMode) {
|
||||
usedArray = sampleArray;
|
||||
} else {
|
||||
usedArray = inputArray;
|
||||
}
|
||||
|
||||
// Part One
|
||||
|
||||
console.time("part1");
|
||||
|
||||
let coordinatesArray = [];
|
||||
|
||||
for (const element of usedArray) {
|
||||
const coordinates = element.split(",");
|
||||
coordinatesArray.push({ x: Number.parseInt(coordinates[0]), y: Number.parseInt(coordinates[1]) });
|
||||
}
|
||||
|
||||
let segments = [];
|
||||
|
||||
for (let i = 0; i < coordinatesArray.length; i++) {
|
||||
for (let j = i + 1; j < coordinatesArray.length; j++) {
|
||||
const dx = Math.abs(coordinatesArray[i].x - coordinatesArray[j].x) + 1;
|
||||
const dy = Math.abs(coordinatesArray[i].y - coordinatesArray[j].y) + 1;
|
||||
const area = dx * dy;
|
||||
segments.push({ dx: dx, dy: dy, area: area });
|
||||
}
|
||||
}
|
||||
|
||||
segments.sort((a, b) => a.area > b.area ? -1 : 1);
|
||||
|
||||
console.timeEnd("part1");
|
||||
console.log(segments[0].area);
|
||||
|
||||
|
||||
// Part Two
|
||||
|
||||
console.time("part2");
|
||||
|
||||
// Only collect the RED tile coordinates (endpoints)
|
||||
const xSet = new Set();
|
||||
const ySet = new Set();
|
||||
|
||||
for (const tile of coordinatesArray) {
|
||||
xSet.add(tile.x);
|
||||
ySet.add(tile.y);
|
||||
}
|
||||
|
||||
const xCoords = [...xSet].sort((a, b) => a - b);
|
||||
const yCoords = [...ySet].sort((a, b) => a - b);
|
||||
|
||||
// Store horizontal and vertical line segments for boundary checking
|
||||
const hLines = []; // {y, x1, x2}
|
||||
const vLines = []; // {x, y1, y2}
|
||||
|
||||
for (let i = 0; i < coordinatesArray.length; i++) {
|
||||
const curr = coordinatesArray[i];
|
||||
const next = coordinatesArray[(i + 1) % coordinatesArray.length];
|
||||
|
||||
if (curr.x === next.x) {
|
||||
vLines.push({ x: curr.x, y1: Math.min(curr.y, next.y), y2: Math.max(curr.y, next.y) });
|
||||
} else {
|
||||
hLines.push({ y: curr.y, x1: Math.min(curr.x, next.x), x2: Math.max(curr.x, next.x) });
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a point is on the boundary
|
||||
function isOnBoundary(x, y) {
|
||||
for (const line of hLines) {
|
||||
if (y === line.y && x >= line.x1 && x <= line.x2) return true;
|
||||
}
|
||||
for (const line of vLines) {
|
||||
if (x === line.x && y >= line.y1 && y <= line.y2) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if a point is inside using ray casting (count vertical line crossings to the left)
|
||||
function isInside(x, y) {
|
||||
let crossings = 0;
|
||||
for (const line of vLines) {
|
||||
if (line.x < x && y >= line.y1 && y < line.y2) {
|
||||
crossings++;
|
||||
}
|
||||
}
|
||||
return crossings % 2 === 1;
|
||||
}
|
||||
|
||||
// Check if a point is valid (on boundary or inside)
|
||||
function isValid(x, y) {
|
||||
return isOnBoundary(x, y) || isInside(x, y);
|
||||
}
|
||||
|
||||
// Check if entire rectangle is valid
|
||||
function isRectValid(x1, y1, x2, y2) {
|
||||
// Check all corner and edge points at compressed coordinates within the rectangle
|
||||
for (const y of yCoords) {
|
||||
if (y < y1 || y > y2) continue;
|
||||
for (const x of xCoords) {
|
||||
if (x < x1 || x > x2) continue;
|
||||
if (!isValid(x, y)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Also check if any boundary line crosses through the rectangle's interior
|
||||
// creating an "outside" region
|
||||
for (const line of vLines) {
|
||||
if (line.x > x1 && line.x < x2) {
|
||||
// Vertical line inside rectangle - check if it creates a gap
|
||||
if (line.y1 > y1 || line.y2 < y2) {
|
||||
// Line doesn't span full height - might create invalid region
|
||||
if (line.y1 > y1 && !isValid(line.x, y1)) return false;
|
||||
if (line.y2 < y2 && !isValid(line.x, y2)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find largest valid rectangle with red corners
|
||||
let maxArea = 0;
|
||||
|
||||
for (let i = 0; i < coordinatesArray.length; i++) {
|
||||
for (let j = i + 1; j < coordinatesArray.length; j++) {
|
||||
const r1 = coordinatesArray[i];
|
||||
const r2 = coordinatesArray[j];
|
||||
|
||||
const x1 = Math.min(r1.x, r2.x);
|
||||
const x2 = Math.max(r1.x, r2.x);
|
||||
const y1 = Math.min(r1.y, r2.y);
|
||||
const y2 = Math.max(r1.y, r2.y);
|
||||
|
||||
if (isRectValid(x1, y1, x2, y2)) {
|
||||
const area = (x2 - x1 + 1) * (y2 - y1 + 1);
|
||||
if (area > maxArea) maxArea = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.timeEnd("part2");
|
||||
console.log(maxArea);
|
||||
|
||||
// functions
|
||||
Reference in New Issue
Block a user