enum Indicator { ON = "#", OFF = ".", } type ButtonWiring = number[]; type Joltage = number; interface MachineManual { indicators: Indicator[]; button_wirings: ButtonWiring[]; joltage_requirements: Joltage[]; } export default async function Factory() { console.log("== Factory =="); const manual_list = await read_machine_manuals_quick( "src/exercises/assets/day_10_input.txt", ); const min_presses = count_min_button_presses(manual_list); console.log( ">> Min button presses to start: ", min_presses, ); } export function count_min_button_presses(manuals: MachineManual[]): number { let total_sum = 0; manuals.forEach((manual, m_i) => { const wiring_list = manual.button_wirings; let min_presses = Infinity; for (let size = 1; size < wiring_list.length; size++) { const button_combinations = make_all_combinations_of_size( wiring_list, size, ); button_combinations.forEach((combination) => { // Apply combination let pairing_indicator = manual.indicators.map((_) => Indicator.OFF); combination.forEach((b) => { pairing_indicator = apply_wiring_to_indicators( b, pairing_indicator, ); }); // Check if valid if (pairing_indicator.join("") === manual.indicators.join("")) { min_presses = combination.length; return; } }); if (min_presses < Infinity) { break; } } total_sum += min_presses; }); return total_sum; } function apply_wiring_to_indicators( wiring: ButtonWiring, indicator: Indicator[], ): Indicator[] { return indicator.map((w, i) => wiring.includes(i) ? w === Indicator.ON ? Indicator.OFF : Indicator.ON : w ); } function make_all_combinations_of_size( list: T, size: number, ): T[] { const binary_cap = Math.pow(2, list.length); const result_list: T[] = []; for (let i = 0; i < binary_cap; i++) { const combination = i.toString(2).padStart(list.length, "0").split(""); if ( combination.reduce((sum, n) => sum + (n === "1" ? 1 : 0), 0) !== size ) { continue; } const next_l = list.map((l, i) => combination[i] === "1" ? l : null).filter( (l) => l !== null, ); result_list.push(next_l as T); } return result_list; } export async function read_machine_manuals( path: string, ): Promise { const line_regex = /\[([.#]+)\] (.*)+ \{(.*)\}/g; const input_txt = await Deno.readTextFile(path); const lines = input_txt.split("\n"); const manual_list: MachineManual[] = lines.map((line) => { const matched_line = line.matchAll(line_regex)?.toArray()?.[0]; if (matched_line && matched_line.length > 3) { const indicators = matched_line[1].toString().split("").map((ch) => ch === Indicator.ON ? Indicator.ON : Indicator.OFF ); const buttons = matched_line[2].split(" ").map((b) => b.replaceAll("(", "").replaceAll(")", "").split(",").map((n) => parseInt(n) ) ); const joltages = matched_line[3].split(",").map((j) => parseInt(j)); return { indicators, button_wirings: buttons, joltage_requirements: joltages, }; } return null; }).filter((v) => v !== null); return manual_list; } export async function read_machine_manuals_quick( path: string, ): Promise { const input_txt = await Deno.readTextFile(path); const lines = input_txt.split("\n"); const manual_list: MachineManual[] = []; lines.forEach((line, line_i) => { const manual: MachineManual = { indicators: [], button_wirings: [], joltage_requirements: [], }; line.split(" ").forEach((element) => { if (element.includes("[")) { manual.indicators = element.replaceAll("[", "").replaceAll("]", "") .split("").map((e) => e as Indicator); } else if (element.includes("{")) { manual.joltage_requirements = element.replaceAll("{", "").replaceAll( "}", "", ).split(",").map((e) => parseInt(e)); } else if (element.includes("(")) { manual.button_wirings.push( element.replaceAll("(", "").replaceAll(")", "").split(",").map((e) => parseInt(e) ), ); } }); if ( manual.button_wirings.length > 0 && manual.joltage_requirements.length > 0 && manual.indicators.length > 0 ) { manual_list.push(manual); } }); return manual_list; }