Day 18
This commit is contained in:
parent
bc6c2a9426
commit
aac2bbd95d
121
18/solution.mjs
Normal file
121
18/solution.mjs
Normal file
@ -0,0 +1,121 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
const input = readFileSync('input', 'utf-8');
|
||||
|
||||
const cubes = input
|
||||
.split('\n')
|
||||
.filter(line => !!line.trim())
|
||||
.map(coords => {
|
||||
const [x, y, z] = coords.split(',').map(n => parseInt(n));
|
||||
return {x, y, z};
|
||||
});
|
||||
|
||||
const surfaceArea = cubes.map(cubeA => {
|
||||
const touchingCubes = cubes.filter(cubeB => {
|
||||
const xDiff = Math.abs(cubeA.x - cubeB.x);
|
||||
const yDiff = Math.abs(cubeA.y - cubeB.y);
|
||||
const zDiff = Math.abs(cubeA.z - cubeB.z);
|
||||
|
||||
return (
|
||||
(xDiff === 1 && yDiff === 0 && zDiff === 0) ||
|
||||
(yDiff === 1 && zDiff === 0 && xDiff === 0) ||
|
||||
(zDiff === 1 && xDiff === 0 && yDiff === 0)
|
||||
);
|
||||
});
|
||||
|
||||
const nonConnectedSides = 6 - touchingCubes.length;
|
||||
return nonConnectedSides;
|
||||
}).reduce((total, sides) => total + sides);
|
||||
|
||||
console.log(`The surface area of the droplet is: ${surfaceArea}`);
|
||||
|
||||
function minMax(dimension) {
|
||||
return [
|
||||
cubes.reduce((min, coords) => Math.min(min, coords[dimension]), Infinity),
|
||||
cubes.reduce((max, coords) => Math.max(max, coords[dimension]), -Infinity),
|
||||
];
|
||||
}
|
||||
|
||||
function isCoordEqual(coordA, coordB) {
|
||||
return coordA.every((v, i) => coordB[i] === v);
|
||||
}
|
||||
|
||||
function uniqueCoordsFilter(coordA, i, coords) {
|
||||
return coords.findLastIndex(coordB => isCoordEqual(coordA, coordB)) === i;
|
||||
}
|
||||
|
||||
function getAllConnected(startX, startY, startZ, isConnected) {
|
||||
const connected = [];
|
||||
let toVisit = [[startX, startY, startZ]];
|
||||
|
||||
while (true) {
|
||||
connected.push(...toVisit);
|
||||
toVisit = toVisit.flatMap(([x, y, z]) => [
|
||||
[x + 1, y, z ],
|
||||
[x - 1, y, z ],
|
||||
[x, y + 1, z ],
|
||||
[x, y - 1, z ],
|
||||
[x, y, z + 1],
|
||||
[x, y, z - 1]
|
||||
])
|
||||
.filter(coordA =>
|
||||
!connected.find(coordB => isCoordEqual(coordA, coordB))
|
||||
)
|
||||
.filter(uniqueCoordsFilter)
|
||||
.filter(([x, y, z]) => isConnected(x, y, z));
|
||||
|
||||
if (!toVisit.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
const [minX, maxX] = minMax('x');
|
||||
const [minY, maxY] = minMax('y');
|
||||
const [minZ, maxZ] = minMax('z');
|
||||
|
||||
// Get all coordinates external to droplet with a border of 2
|
||||
const connected = getAllConnected(minX - 2, minY - 2, minZ - 2, (x, y, z) => {
|
||||
return (
|
||||
x >= minX - 2 &&
|
||||
x <= maxX + 2 &&
|
||||
y >= minY - 2 &&
|
||||
y <= maxY + 2 &&
|
||||
z >= minZ - 2 &&
|
||||
z <= maxZ + 2 &&
|
||||
// Not part of the droplet
|
||||
!cubes.find(coord => coord.x === x && coord.y === y && coord.z === z)
|
||||
);
|
||||
});
|
||||
|
||||
// Calculate internal surface area of inverted droplet
|
||||
const externalSurfaceArea = connected.map(([ax, ay, az]) => {
|
||||
// Skip coordinates right on the edge
|
||||
if (
|
||||
ax < minX - 1 || ax > maxX + 1 ||
|
||||
ay < minY - 1 || ay > maxY + 1 ||
|
||||
az < minZ - 1 || az > maxZ + 1
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const touchingCubes = connected.filter(([bx, by, bz]) => {
|
||||
const xDiff = Math.abs(ax - bx);
|
||||
const yDiff = Math.abs(ay - by);
|
||||
const zDiff = Math.abs(az - bz);
|
||||
|
||||
return (
|
||||
(xDiff === 1 && yDiff === 0 && zDiff === 0) ||
|
||||
(yDiff === 1 && zDiff === 0 && xDiff === 0) ||
|
||||
(zDiff === 1 && xDiff === 0 && yDiff === 0)
|
||||
);
|
||||
});
|
||||
const nonConnectedSides = 6 - touchingCubes.length;
|
||||
return nonConnectedSides;
|
||||
}).reduce((total, sides) => total + sides);
|
||||
|
||||
console.log(
|
||||
`The EXTERNAL surface area of the droplet is: ${externalSurfaceArea}`
|
||||
);
|
Loading…
Reference in New Issue
Block a user