diff --git a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb index eaa6355..3ce07c5 100644 --- a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb +++ b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb @@ -9589,7 +9589,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 76, "metadata": {}, "outputs": [], "source": [ @@ -9605,69 +9605,56 @@ "\n", " Returns:\n", " bool: True if the addition is valid, False otherwise.\n", - " \"\"\" \n", - " # wires_copy = wires.copy() # work with a fresh copy of wires with each validation\n", - " wires_copy = {k: 0 for k in wires if k.startswith(\"x\") or k.startswith(\"y\")} # Create a smaller structure\n", - " wires_copy.update({k: v for k, v in wires.items() if not (k.startswith(\"x\") or k.startswith(\"y\"))})\n", - " \n", + " \"\"\" \n", " # Set each x and y wire to 1 or 0, \n", " # based on the respective bit index of the supplied x / y values.\n", " # I.e. isolate the bit of input value, and set the corresponding wire to this bit\n", " for wire in wires.keys():\n", " if wire.startswith(\"x\"):\n", " bit_idx = int(wire[1:]) # E.g. 4\n", - " wires_copy[wire] = (x >> bit_idx) & 1 \n", + " wires[wire] = (x >> bit_idx) & 1 \n", " \n", " if wire.startswith(\"y\"):\n", " bit_idx = int(wire[1:])\n", - " wires_copy[wire] = (y >> bit_idx) & 1\n", + " wires[wire] = (y >> bit_idx) & 1\n", " \n", " for output in operations.keys():\n", " if output.startswith(\"z\"):\n", - " process_gates_dfs(output, wires_copy, operations)\n", + " process_gates_dfs(output, wires, operations)\n", " \n", - " z_out = get_output_for_wire_type(wires_copy, \"z\")\n", + " z_out = get_output_for_wire_type(wires, \"z\")\n", " return x + y == z_out # perform the check \n", "\n", - "def get_failures(wires: dict, operations: dict, to_validate: Iterable) -> list:\n", + "def get_failures(wires: dict, operations: dict, wires_count:int, start=2) -> list:\n", " \"\"\" Identify which bit positions fail the validation, \n", " i.e. when the z value does not represent the sum of the x and y wires.\n", + " \"\"\"\n", + "\n", + " # Validate specific x and y values\n", + " big_x = 30626032511001\n", + " big_y = 28716883075641\n", " \n", - " to_validate: an interable that stores the bit positions to check. \"\"\"\n", - " failures = set() # To store the bit positions that fail validation\n", - " \n", - " x_single_bit = 0\n", - " x_bits_so_far = 0\n", - " for i in to_validate: # this bit set to 1\n", - " x_single_bit = 2**i # Same as 1 << i\n", - " y_single_bit = 2**i # Same as 1 << i\n", - " x_bits_so_far += x_single_bit\n", + " for i in range(start, wires_count): # this bit set to 1\n", + " x = 2**(i-2) + 2**(i-1) + 2**i # Set three consecutive bits to test carry-over\n", + " y = 2**(i-2) + 2**(i-1) + 2**i\n", " \n", " # Try adding 1 and seeing where it fails\n", - " if not validate_addition(wires, operations, x_single_bit, 1):\n", - " failures.add(i)\n", + " if not validate_addition(wires.copy(), operations.copy(), x, 1):\n", + " return i\n", " \n", " # Try adding pairs of True bits and seeing where it fails\n", - " if not validate_addition(wires, operations, x_single_bit, y_single_bit):\n", - " failures.add(i)\n", + " if not validate_addition(wires.copy(), operations.copy(), x, y):\n", + " return i\n", " \n", - " # Validate specific x and y values if provided\n", - " x = 30626032511001\n", - " y = 28716883075641\n", - " for i in to_validate:\n", " # Create a mask with all bits set up to the ith position\n", - " mask = (1 << (i + 1)) - 1 # A mask with bits 0 through i set to 1\n", + " mask = (1 << (i + 1)) - 1 # A mask with bits 0 through i set to 1, e.g. 0b111\n", + " test_x = big_x & mask\n", + " test_y = big_y & mask\n", "\n", - " # Extract all bits up to the ith position for x and y\n", - " test_x = x & mask\n", - " test_y = y & mask\n", - "\n", - " # Validate with the current bit isolated\n", - " if i not in failures:\n", - " if not validate_addition(wires, operations, test_x, test_y):\n", - " failures.add(i) \n", + " if not validate_addition(wires.copy(), operations.copy(), test_x, test_y):\n", + " return i \n", " \n", - " return sorted(failures)\n", + " return -1\n", "\n", "def solve_part2(data: str, swaps_required=4):\n", " wires, operations = process_input(data)\n", @@ -9676,15 +9663,15 @@ " y_wires_count = len([wire for wire in wires if wire.startswith(\"y\")])\n", " assert x_wires_count == y_wires_count, \"There should be same number of x and y wires\"\n", " \n", - " failures = get_failures(wires, operations, list(range(x_wires_count)))\n", + " failures = get_failures(wires.copy(), operations.copy(), x_wires_count)\n", " logger.debug(f\"Initial failures: {failures}\")\n", " \n", " swap_candidates = []\n", " valid = False\n", " ignore = set()\n", " prev_ops = []\n", - " while not valid or len(swap_candidates) != swaps_required: \n", - " swap_candidates, local_ops = find_swap_candidates(wires, operations, failures, ignore=ignore)\n", + " while not valid or len(swap_candidates) != swaps_required: \n", + " swap_candidates, local_ops = find_swap_candidates(wires.copy(), operations.copy(), failures, ignore=ignore)\n", " \n", " if local_ops == prev_ops:\n", " logger.debug(\"No solution found\")\n", @@ -9714,23 +9701,21 @@ " swaps += [item for pair in swap_candidates for item in pair] # extend the list\n", " return \",\".join(sorted(swaps))\n", "\n", - "def find_swap_candidates(wires, operations, failures, ignore):\n", + "def find_swap_candidates(wires, ops, lowest_failure:int, ignore):\n", " logger.debug(\"find_swap_candidates()\")\n", - " local_wires = wires.copy()\n", - " local_ops = operations.copy()\n", - " local_failures = failures.copy()\n", - " new_failures = local_failures.copy()\n", + " x_wires_count = len([wire for wire in wires if wire.startswith(\"x\")])\n", " swap_candidates = []\n", " \n", - " logger.debug(f\"{local_wires=}\")\n", - " logger.debug(f\"{local_ops=}\")\n", - " logger.debug(f\"Initial failures: {local_failures}\")\n", + " logger.debug(f\"{wires=}\")\n", + " logger.debug(f\"{ops=}\")\n", + " logger.debug(f\"Lowest failures: {lowest_failure}\")\n", " logger.debug(f\"{ignore=}\")\n", " \n", - " while new_failures:\n", + " new_lowest = lowest_failure\n", + " while new_lowest != -1:\n", " # Loop until we've tried every pair - or there are no more failures\n", - " for op_x in local_ops: # E.g. fkp\n", - " for op_y in local_ops: # E.g. z06\n", + " for op_x in ops: # E.g. fkp\n", + " for op_y in ops: # E.g. z06\n", " if op_x == op_y: \n", " continue\n", " \n", @@ -9744,16 +9729,16 @@ " continue\n", " \n", " # Swap these two operations and test if we can remove lowest bit failure\n", - " local_ops[op_x], local_ops[op_y] = local_ops[op_y], local_ops[op_x]\n", + " ops[op_x], ops[op_y] = ops[op_y], ops[op_x]\n", " try:\n", - " new_failures = get_failures(local_wires, local_ops, local_failures)\n", - " if not new_failures: # if we've run out of failures\n", + " new_lowest = get_failures(wires, ops, x_wires_count, start=lowest_failure)\n", + " if new_lowest == -1: # if we've run out of failures\n", " logger.debug(\"No failures remaining\")\n", " break\n", " \n", - " if len(new_failures) < len(local_failures):\n", - " local_failures = new_failures\n", - " logger.debug(f\"Failures reduced: {local_failures}\")\n", + " if new_lowest > lowest_failure:\n", + " lowest_failure = new_lowest\n", + " logger.debug(f\"Lowest failure updated: {lowest_failure}\")\n", " swap_candidates.append(tuple(sorted((op_x, op_y))))\n", " logger.debug(swap_candidates)\n", " break # Go to next x\n", @@ -9761,7 +9746,7 @@ " pass # If no valid solution with this swap, we undo it\n", " \n", " # Undo swap\n", - " local_ops[op_x], local_ops[op_y] = local_ops[op_y], local_ops[op_x]\n", + " ops[op_x], ops[op_y] = ops[op_y], ops[op_x]\n", " else: # Only execute if we complete without a break\n", " continue\n", " \n", @@ -9771,15 +9756,25 @@ " logger.warning(\"No candidates found.\")\n", " break\n", " \n", - " return swap_candidates, local_ops\n", + " return swap_candidates, ops\n", " " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 75, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[34m17:53:11.746:aoc2024 - DBG: wires={'x00': 1, 'x01': 0, 'x02': 0, 'x03': 1, 'x04': 1, 'x05': 0, 'x06': 0, 'x07': 0, 'x08': 0, 'x09': 0, 'x10': 0, 'x11': 1, 'x12': 0, 'x13': 1, 'x14': 1, 'x15': 1, 'x16': 1, 'x17': 0, 'x18': 0, 'x19': 1, 'x20': 0, 'x21': 0, 'x22': 1, 'x23': 1, 'x24': 1, 'x25': 0, 'x26': 1, 'x27': 1, 'x28': 0, 'x29': 1, 'x30': 0, 'x31': 1, 'x32': 0, 'x33': 1, 'x34': 0, 'x35': 1, 'x36': 1, 'x37': 0, 'x38': 1, 'x39': 1, 'x40': 1, 'x41': 1, 'x42': 0, 'x43': 1, 'x44': 1, 'y00': 1, 'y01': 0, 'y02': 0, 'y03': 1, 'y04': 1, 'y05': 1, 'y06': 0, 'y07': 0, 'y08': 0, 'y09': 1, 'y10': 0, 'y11': 0, 'y12': 0, 'y13': 1, 'y14': 1, 'y15': 0, 'y16': 1, 'y17': 0, 'y18': 1, 'y19': 1, 'y20': 1, 'y21': 0, 'y22': 0, 'y23': 1, 'y24': 1, 'y25': 1, 'y26': 0, 'y27': 1, 'y28': 0, 'y29': 1, 'y30': 0, 'y31': 0, 'y32': 0, 'y33': 1, 'y34': 1, 'y35': 1, 'y36': 1, 'y37': 0, 'y38': 0, 'y39': 0, 'y40': 0, 'y41': 1, 'y42': 0, 'y43': 1, 'y44': 1}\u001b[39m\n", + "\u001b[34m17:53:11.747:aoc2024 - DBG: connections_lines=['x36 AND y36 -> rpc', 'swn OR jrk -> kfm', 'x36 XOR y36 -> mvv', 'y28 XOR x28 -> rnh', 'bfp OR wqc -> rgb', 'tkc OR mfm -> brs', 'kmb XOR gfj -> z16', 'x25 AND y25 -> mdt', 'mpp AND hfd -> gjp', 'dhd AND mvb -> vrf', 'y14 XOR x14 -> qvt', 'shc OR bkk -> wvr', 'x29 AND y29 -> gdn', 'x11 XOR y11 -> jpp', 'rws OR fts -> mpp', 'wmq OR ngr -> knj', 'x24 XOR y24 -> gfg', 'tpf AND mgq -> tkc', 'wvr XOR jgw -> fkp', 'brs AND nmr -> qpb', 'x18 AND y18 -> qsw', 'pnb OR vjh -> sfh', 'x44 XOR y44 -> gcd', 'x22 AND y22 -> mhd', 'x37 XOR y37 -> dgg', 'vfj XOR dmh -> z15', 'x30 XOR y30 -> qgd', 'rpw OR gdn -> wrv', 'ptj OR vqm -> vjn', 'gfg AND pqf -> pnb', 'x17 XOR y17 -> rtv', 'y19 AND x19 -> wpt', 'sfp AND sbq -> tcv', 'hvv OR vmr -> kpq', 'pgc XOR fvj -> z02', 'knj AND ctw -> vqm', 'y42 XOR x42 -> vfb', 'y13 XOR x13 -> vdk', 'x43 AND y43 -> nhd', 'krg XOR dkw -> z43', 'y32 AND x32 -> vdm', 'hfd XOR mpp -> z08', 'nfq OR qgm -> cqq', 'x02 AND y02 -> nss', 'rvw XOR dtb -> z10', 'qvt AND qqv -> rgj', 'mvv XOR sgr -> z36', 'y11 AND x11 -> wmq', 'cnd XOR jqv -> z29', 'vdk XOR vjn -> z13', 'x34 AND y34 -> kjj', 'qvt XOR qqv -> z14', 'y18 XOR x18 -> mkt', 'bwk OR krn -> pqf', 'nhs XOR cqq -> z41', 'y31 AND x31 -> z31', 'y23 AND x23 -> bwk', 'sfh AND pmf -> ctp', 'rvw AND dtb -> sgv', 'tns AND chq -> dwv', 'rqt XOR snv -> z22', 'jqv AND cnd -> rpw', 'x33 AND y33 -> vtd', 'ctw XOR knj -> z12', 'bpp OR ghf -> z06', 'ffn AND rdj -> shc', 'cfw OR tnc -> sgr', 'wdm AND psv -> fwc', 'vwn OR wpt -> bvc', 'jkn OR gvk -> z45', 'x00 XOR y00 -> z00', 'qpf XOR mkt -> z18', 'y12 AND x12 -> ptj', 'dvq XOR rkm -> z04', 'x15 XOR y15 -> dmh', 'qrm OR nss -> wdm', 'mhv OR mnv -> rcs', 'qtq OR cqn -> nwk', 'x20 XOR y20 -> tpw', 'x04 AND y04 -> ptd', 'nhd OR pnk -> mdn', 'hjc OR hth -> pgc', 'x20 AND y20 -> qtq', 'gcd XOR mdn -> z44', 'mgq XOR tpf -> mfm', 'x30 AND y30 -> bbk', 'dmh AND vfj -> cpc', 'x44 AND y44 -> gvk', 'dwv OR jvf -> jjj', 'pkh AND fkp -> rws', 'x39 AND y39 -> wqc', 'fwc OR nbc -> rkm', 'bdc AND bbd -> dnc', 'x26 XOR y26 -> tns', 'csh AND mst -> vwn', 'x43 XOR y43 -> dkw', 'bvc XOR tpw -> z20', 'nwk XOR ngm -> z21', 'rtv XOR kfm -> z17', 'x06 AND y06 -> bpp', 'x10 XOR y10 -> dtb', 'y29 XOR x29 -> cnd', 'y08 XOR x08 -> hfd', 'y03 XOR x03 -> psv', 'rgj OR bph -> vfj', 'psv XOR wdm -> z03', 'dnc OR vtd -> mvb', 'gcn AND tqf -> krn', 'y38 XOR x38 -> krj', 'x24 AND y24 -> vjh', 'y41 AND x41 -> vmr', 'jgw AND wvr -> ghf', 'x09 XOR y09 -> sfp', 'y28 AND x28 -> wpw', 'x40 XOR y40 -> mkc', 'hsn AND dgg -> snc', 'jpp XOR stv -> ngr', 'mjb OR cpc -> gfj', 'rcs XOR rnh -> z28', 'sfp XOR sbq -> z09', 'rtv AND kfm -> jfr', 'tjh OR wpw -> jqv', 'x16 XOR y16 -> kmb', 'bgn OR wnm -> snv', 'nmr XOR brs -> z32', 'rpc OR dvm -> hsn', 'gfg XOR pqf -> z24', 'dkw AND krg -> pnk', 'kmb AND gfj -> jrk', 'skt XOR kjn -> z01', 'gcn XOR tqf -> z23', 'jjj XOR rhc -> z27', 'y07 AND x07 -> fts', 'y21 AND x21 -> wnm', 'kvd OR snc -> ntr', 'nht XOR hsp -> z39', 'wrv XOR qgd -> z30', 'y07 XOR x07 -> pkh', 'tdv OR krj -> hsp', 'stv AND jpp -> z11', 'x27 AND y27 -> mhv', 'bdc XOR bbd -> z33', 'x12 XOR y12 -> ctw', 'mvv AND sgr -> dvm', 'x27 XOR y27 -> rhc', 'x21 XOR y21 -> ngm', 'mhn XOR mdg -> z35', 'x19 XOR y19 -> csh', 'y35 XOR x35 -> mhn', 'snv AND rqt -> tfs', 'rkm AND dvq -> cjp', 'pgc AND fvj -> qrm', 'kpq XOR vfb -> z42', 'qgd AND wrv -> gqt', 'y26 AND x26 -> jvf', 'x39 XOR y39 -> nht', 'vdk AND vjn -> jqm', 'bvc AND tpw -> cqn', 'y32 XOR x32 -> nmr', 'x25 XOR y25 -> pmf', 'y09 AND x09 -> prs', 'y14 AND x14 -> bph', 'qpb OR vdm -> bdc', 'gqt OR bbk -> tpf', 'x40 AND y40 -> qgm', 'sfh XOR pmf -> z25', 'x22 XOR y22 -> rqt', 'rhc AND jjj -> mnv', 'csh XOR mst -> z19', 'x42 AND y42 -> krw', 'x34 XOR y34 -> dhd', 'x35 AND y35 -> tnc', 'ngm AND nwk -> bgn', 'tdh OR jqm -> qqv', 'y00 AND x00 -> skt', 'y41 XOR x41 -> nhs', 'ntr XOR bpt -> z38', 'vrf OR kjj -> mdg', 'kvf OR krw -> krg', 'x03 AND y03 -> nbc', 'dhd XOR mvb -> z34', 'qpf AND mkt -> rsd', 'y01 XOR x01 -> kjn', 'x17 AND y17 -> bvg', 'jfr OR bvg -> qpf', 'y13 AND x13 -> tdh', 'bpb OR gjp -> sbq', 'x16 AND y16 -> swn', 'x02 XOR y02 -> fvj', 'y15 AND x15 -> mjb', 'x23 XOR y23 -> tqf', 'rnh AND rcs -> tjh', 'x05 AND y05 -> bkk', 'hsn XOR dgg -> z37', 'qsw OR rsd -> mst', 'sgv OR qnf -> stv', 'y01 AND x01 -> hth', 'y38 AND x38 -> bpt', 'rgb AND mkc -> nfq', 'y33 XOR x33 -> bbd', 'tns XOR chq -> z26', 'ctp OR mdt -> chq', 'nhs AND cqq -> hvv', 'pkh XOR fkp -> z07', 'rdj XOR ffn -> z05', 'mhd OR tfs -> gcn', 'y10 AND x10 -> qnf', 'hsp AND nht -> bfp', 'gcd AND mdn -> jkn', 'ntr AND bpt -> tdv', 'prs OR tcv -> rvw', 'x05 XOR y05 -> ffn', 'y04 XOR x04 -> dvq', 'x31 XOR y31 -> mgq', 'y08 AND x08 -> bpb', 'mhn AND mdg -> cfw', 'y37 AND x37 -> kvd', 'rgb XOR mkc -> z40', 'cjp OR ptd -> rdj', 'x06 XOR y06 -> jgw', 'skt AND kjn -> hjc', 'vfb AND kpq -> kvf']\u001b[39m\n", + "\u001b[34m17:56:06.715:aoc2024 - DBG: Initial failures: 3\u001b[39m\n" + ] + } + ], "source": [ "logger.setLevel(logging.DEBUG)\n", "soln = solve_part2(input_data)\n",