181 lines
4.8 KiB
TypeScript
181 lines
4.8 KiB
TypeScript
interface Coordinate {
|
|
x: number;
|
|
y: number;
|
|
z: number;
|
|
}
|
|
|
|
export default async function Playground() {
|
|
const junction_boxes_coords = await read_junction_box_3d_positions(
|
|
"src/exercises/assets/day_8_input.txt",
|
|
);
|
|
console.log(
|
|
">> Three largest pairings mul: ",
|
|
get_three_largest_pairings_mul(junction_boxes_coords, 1000),
|
|
);
|
|
console.log(
|
|
">> Last pairing mul: ",
|
|
get_last_pairing_mul(junction_boxes_coords),
|
|
);
|
|
}
|
|
|
|
export function get_three_largest_pairings_mul(
|
|
box_list: Coordinate[],
|
|
max_pairings: number,
|
|
): number {
|
|
const pairing_list = generate_n_shortest_pairings(box_list, max_pairings)
|
|
.sort((a, b) => b.length - a.length);
|
|
let total = 1;
|
|
for (let i = 0; i < 3; i++) {
|
|
total *= pairing_list[i].length;
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
export function get_last_pairing_mul(box_list: Coordinate[]): number {
|
|
const last_pairing = get_last_pairing_circuit(box_list);
|
|
if (last_pairing) {
|
|
return box_list[last_pairing.a].x * box_list[last_pairing.b].x;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
interface DistancePairing {
|
|
a: number;
|
|
b: number;
|
|
distance: number;
|
|
}
|
|
|
|
function generate_n_shortest_distances(
|
|
box_list: Coordinate[],
|
|
n: number,
|
|
initial_distances?: DistancePairing[],
|
|
): DistancePairing[] {
|
|
const distances: DistancePairing[] = initial_distances ?? [];
|
|
for (let i = 0; i < n; i++) {
|
|
const shortest_distance: { distance: number; pair_index: number[] } = {
|
|
distance: Infinity, // Dirty, but it's late
|
|
pair_index: [],
|
|
};
|
|
box_list.forEach((box, box_index) => {
|
|
for (let next_i = box_index + 1; next_i < box_list.length; next_i++) {
|
|
const next_box = box_list[next_i];
|
|
const next_distance = calc_distance(box, next_box);
|
|
|
|
if (
|
|
next_distance < shortest_distance.distance &&
|
|
!distances.some((d) =>
|
|
(d.a === box_index && d.b === next_i) ||
|
|
(d.b === box_index && d.a === next_i)
|
|
)
|
|
) {
|
|
shortest_distance.distance = next_distance;
|
|
shortest_distance.pair_index = [box_index, next_i];
|
|
}
|
|
}
|
|
});
|
|
distances.push({
|
|
a: shortest_distance.pair_index[0],
|
|
b: shortest_distance.pair_index[1],
|
|
distance: shortest_distance.distance,
|
|
});
|
|
}
|
|
|
|
return distances;
|
|
}
|
|
|
|
function generate_n_shortest_pairings(
|
|
box_list: Coordinate[],
|
|
max_pairings: number,
|
|
): number[][] {
|
|
const distance_list = generate_n_shortest_distances(box_list, max_pairings);
|
|
const circuits: number[][] = box_list.map((_, i) => [i]);
|
|
|
|
distance_list.forEach((distance) => {
|
|
const a = circuits.find((c) => c.includes(distance.a));
|
|
const b = circuits.find((c) => c.includes(distance.b));
|
|
|
|
if (a?.length && b?.length && a !== b) {
|
|
const to_empty_index = circuits.findIndex((c) => c.includes(distance.b));
|
|
b.forEach((x) => a.push(x));
|
|
circuits[to_empty_index] = [];
|
|
}
|
|
});
|
|
|
|
return circuits;
|
|
}
|
|
|
|
function get_last_pairing_circuit(
|
|
box_list: Coordinate[],
|
|
): DistancePairing | undefined {
|
|
const INCREMENT = 10; // NOTE: to adjust computation cost, since the solution is inefficient
|
|
const circuits: number[][] = box_list.map((_, i) => [i]);
|
|
|
|
const is_done = (c: number[][]): boolean => {
|
|
return c.reduce((prev, current) => {
|
|
if (current.length > 0) {
|
|
return prev + 1;
|
|
}
|
|
return prev;
|
|
}, 0) > 1
|
|
? false
|
|
: true;
|
|
};
|
|
|
|
let last_pairing: DistancePairing | undefined;
|
|
|
|
let distance_list = generate_n_shortest_distances(box_list, INCREMENT);
|
|
while (!is_done(circuits)) {
|
|
distance_list = generate_n_shortest_distances(
|
|
box_list,
|
|
INCREMENT,
|
|
distance_list,
|
|
);
|
|
distance_list.forEach((distance) => {
|
|
const a = circuits.find((c) => c.includes(distance.a));
|
|
const b = circuits.find((c) => c.includes(distance.b));
|
|
|
|
if (a?.length && b?.length && a !== b) {
|
|
last_pairing = {
|
|
a: distance.a,
|
|
b: distance.b,
|
|
distance: distance.distance,
|
|
};
|
|
const to_empty_index = circuits.findIndex((c) =>
|
|
c.includes(distance.b)
|
|
);
|
|
b.forEach((x) => a.push(x));
|
|
circuits[to_empty_index] = [];
|
|
}
|
|
});
|
|
}
|
|
|
|
return last_pairing;
|
|
}
|
|
|
|
function calc_distance(a: Coordinate, b: Coordinate): number {
|
|
return Math.sqrt(
|
|
Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2) + Math.pow(a.z - b.z, 2),
|
|
);
|
|
}
|
|
|
|
export async function read_junction_box_3d_positions(
|
|
path: string,
|
|
): Promise<Coordinate[]> {
|
|
const file_txt = await Deno.readTextFile(path);
|
|
const coordinates: Coordinate[] = [];
|
|
file_txt.split("\n").forEach((raw_coord) => {
|
|
if (!raw_coord.length) {
|
|
return;
|
|
}
|
|
const coord_array = raw_coord.split(",");
|
|
coordinates.push({
|
|
x: parseInt(coord_array[0]),
|
|
y: parseInt(coord_array[1]),
|
|
z: parseInt(coord_array[2]),
|
|
});
|
|
});
|
|
|
|
return coordinates;
|
|
}
|