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 { 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; }