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 e62c2e1..d45b698 100644 --- a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb +++ b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb @@ -1058,6 +1058,317 @@ "logger.info(f\"Part 2 soln={soln}\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## Day 3: Mull It Over" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "DAY = \"3\" # replace with actual number (without leading digit)\n", + "day_link = f\"#### See [Day {DAY}](https://adventofcode.com/{YEAR}/day/{DAY}).\"\n", + "display(Markdown(day_link))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", + "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2024d01\n", + "locations = dc.get_locations(d_name)\n", + "logger.setLevel(logging.DEBUG)\n", + "# td.setup_file_logging(logger, locations.output_dir)\n", + "\n", + "# Retrieve input and store in local file\n", + "try:\n", + " write_puzzle_input_file(YEAR, DAY, locations)\n", + " with open(locations.input_file, mode=\"rt\") as f:\n", + " input_data = f.read()\n", + "\n", + " logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))\n", + "except ValueError as e:\n", + " logger.error(e)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Day 3 Part 1\n", + "\n", + "A shop computer is trying to run a program, but its memory - the puzzle input - is corrupted.\n", + "\n", + "It should be doing instructions like:\n", + "\n", + "- `mul(X,Y)` where `X` and `Y` are 1-3 digit numbers.\n", + "\n", + "Our instructions:\n", + "\n", + "- There are many invalid characters which should be ignored.\n", + "- If an invalid character is part of a `mul()` instruction, then the whole instruction does nothing.\n", + "- Scan the corrupted memory for uncorrupted mul instructions.\n", + "\n", + "**What do you get if you add up all of the results of the multiplications?**\n", + "\n", + "#### Solution Approach\n", + "\n", + "We can just use [regex](https://aoc.just2good.co.uk/python/regex).\n", + "\n", + "- Use a regex pattern to identify substrints that match the required input format.\n", + "- Use the regex `finditer()` to retrieve all non-overlapping matches.\n", + "- The `matches.groups()` retrieves the captured groups, i.e. the digits themselves. We identify capture groups by placing each digit in brackets in the pattern string.\n", + "- Then, multiply the two digits together, as required." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def solve_part1(data):\n", + " # match all \"mul(x,y)\"\n", + " matches = re.finditer(r\"mul\\((\\d{1,3}),(\\d{1,3})\\)\", data)\n", + " \n", + " ans = 0\n", + " for match in matches:\n", + " val_x, val_y = match.groups()\n", + " ans += int(val_x)*int(val_y)\n", + " \n", + " return ans\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "sample_inputs = []\n", + "sample_inputs.append(\"\"\"xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))\"\"\")\n", + "sample_answers = [161]\n", + "\n", + "for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", + " validate(solve_part1(curr_input), curr_ans) # test with sample data\n", + " logger.info(\"Test passed\")\n", + "\n", + "logger.info(\"All tests passed!\")\n", + "\n", + "soln = solve_part1(input_data)\n", + "logger.info(f\"Part 1 soln={soln}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Day 3 Part 2\n", + "\n", + "Now we also want to handle intact conditional statements. We need to handle:\n", + "\n", + "- `do()` which enables future `mul` instructions\n", + "- `don't()` which disables future `mul` instructions.\n", + "\n", + "We start enabled.\n", + "\n", + "**What is the sum of just the enabled multiplications?**\n", + "\n", + "#### Solution Approach\n", + "\n", + "- Okay, we start `enabled`.\n", + "- Whilst `enabled==True`, everything up to the next `don't()` should be parsed for `mul()` instructions.\n", + "- When we hit a `don't()`, we set `enabled=False`.\n", + "- Now, everything up to the next `do()` should be ignored.\n", + "- When we hit a `do()`, we set `enabled=True` again.\n", + "\n", + "I'm shocked... This worked first time with no bugs!!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def solve_part2(data: str):\n", + " # match all \"mul(x,y)\"\n", + " matcher = re.compile(r\"mul\\((\\d{1,3}),(\\d{1,3})\\)\")\n", + " \n", + " remaining_program = data\n", + " enabled = True # We start enabled\n", + " ans = 0\n", + " while remaining_program:\n", + " if enabled:\n", + " # split into the part before the next \"don't()\", and everything afterwards\n", + " this_part, _, remaining_program = remaining_program.partition(r\"don't()\")\n", + " \n", + " for match in matcher.finditer(this_part):\n", + " val_x, val_y = match.groups()\n", + " ans += int(val_x)*int(val_y)\n", + " \n", + " enabled = False\n", + " else:\n", + " # split into the part before the next \"do()\", and everything afterwards\n", + " this_part, _, remaining_program = remaining_program.partition(r\"do()\")\n", + " enabled = True\n", + " \n", + " return ans" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "sample_inputs = []\n", + "sample_inputs.append(\"\"\"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))\"\"\")\n", + "sample_answers = [48]\n", + "\n", + "for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", + " validate(solve_part2(curr_input), curr_ans) # test with sample data\n", + " logger.info(\"Test passed\") \n", + "\n", + "logger.info(\"Tests passed!\")\n", + "\n", + "soln = solve_part2(input_data)\n", + "logger.info(f\"Part 2 soln={soln}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## Day 4: title" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "DAY = \"4\" # replace with actual number (without leading digit)\n", + "day_link = f\"#### See [Day {DAY}](https://adventofcode.com/{YEAR}/day/{DAY}).\"\n", + "display(Markdown(day_link))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", + "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2024d01\n", + "locations = dc.get_locations(d_name)\n", + "logger.setLevel(logging.DEBUG)\n", + "# td.setup_file_logging(logger, locations.output_dir)\n", + "\n", + "# Retrieve input and store in local file\n", + "try:\n", + " write_puzzle_input_file(YEAR, DAY, locations)\n", + " with open(locations.input_file, mode=\"rt\") as f:\n", + " input_data = f.read().splitlines()\n", + "\n", + " logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))\n", + "except ValueError as e:\n", + " logger.error(e)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Day 4 Part 1\n", + "\n", + "Overview..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def solve_part1(data):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "sample_inputs = []\n", + "sample_inputs.append(\"\"\"abcdef\"\"\")\n", + "sample_answers = [\"uvwxyz\"]\n", + "\n", + "for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", + " validate(solve_part1(curr_input), curr_ans) # test with sample data\n", + " logger.info(\"Test passed\")\n", + "\n", + "logger.info(\"All tests passed!\")\n", + "\n", + "soln = solve_part1(input_data)\n", + "logger.info(f\"Part 1 soln={soln}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Day 4 Part 2\n", + "\n", + "Overview..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def solve_part2(data):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "sample_inputs = []\n", + "sample_inputs.append(\"\"\"abcdef\"\"\")\n", + "sample_answers = [\"uvwxyz\"]\n", + "\n", + "for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", + " validate(solve_part2(curr_input), curr_ans) # test with sample data\n", + " logger.info(\"Test passed\") \n", + "\n", + "logger.info(\"Tests passed!\")\n", + "\n", + "soln = solve_part2(input_data)\n", + "logger.info(f\"Part 2 soln={soln}\")" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/src/AoC_2024/d03/input/input.txt b/src/AoC_2024/d03/input/input.txt new file mode 100644 index 0000000..301347f Binary files /dev/null and b/src/AoC_2024/d03/input/input.txt differ