Ben Ashton
1 year ago
2 changed files with 2313 additions and 0 deletions
@ -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