Created
November 30, 2024 06:19
-
-
Save selimrbd/fb4e871617858798b7927f9cd005250c to your computer and use it in GitHub Desktop.
My Dialog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {"cells": [{"cell_type": "markdown", "metadata": {}, "source": "[LINK](https://adventofcode.com/2023/day/3)"}, {"cell_type": "markdown", "metadata": {}, "source": "# Part 1"}, {"cell_type": "code", "metadata": {}, "source": "from aocd import get_data\nengine = get_data(day=3, year=2023)\nengine_lines = data.split(\"\\n\")\n\nprint(engine_lines[:3])", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["['...733.......289..262.....520..................161.462..........450.........................183.............................................', '....*....................*.............707.352....*............/.....................801...@...............333..196........484.635......287.', '....42.........131....913..............*......&..........634..................440..&...............83.....@...........404$..=....*..423.*...']\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "What are all the possible symbols ?\n\nLet's build `is_symbol` to determine if a character is a symbol.\n\nFrom the definition, any character that isn't a digit or a period is a symbol."}, {"cell_type": "markdown", "source": "**AI Prompt**\n\nIn python how would I check if a character is not a digit ? can I do so without using a regex", "metadata": {}}, {"cell_type": "markdown", "source": "**AI Response**\n\nYes! Python has a built-in string method called `isdigit()` that checks if a character is a digit. \n\nTo check if a character is NOT a digit, you can use:\n```python\nnot character.isdigit()\n```\n\nWould you like to try writing the full `is_symbol` function yourself using this method? Remember we need to check for both non-digits AND non-periods.", "is_reply": true, "metadata": {}}, {"cell_type": "code", "metadata": {}, "source": "def is_symbol(character: str) -> bool:\n is_digit = character.isdigit()\n is_period = character == '.'\n return not is_digit and not is_period", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def find_all_symbols(engine_lines: list[str]):\n symbols = list()\n for line in engine_lines:\n for character in line:\n if is_symbol(character):\n symbols.append(character)\n return set(symbols)", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "symbols = find_all_symbols(engine_lines)\nsymbols", "outputs": [{"output_type": "execute_result", "data": {"text/plain": ["{'#', '$', '%', '&', '*', '+', '-', '/', '=', '@'}"]}, "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "import re \n\ndef extract_numbers(engine_lines: list[str]) -> list[list[int]]:\n numbers = list()\n for line in engine_lines:\n numbers.append(re.findall('\\d+', line))\n return numbers", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "inp = engine_lines[:2]\nprint('input:')\nprint(inp)\nprint('extracted numbers:')\nprint(extract_numbers(inp))", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["input:\n", "['...733.......289..262.....520..................161.462..........450.........................183.............................................', '....*....................*.............707.352....*............/.....................801...@...............333..196........484.635......287.']\n", "extracted numbers:\n", "[['733', '289', '262', '520', '161', '462', '450', '183'], ['707', '352', '801', '333', '196', '484', '635', '287']]\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "markdown", "source": "**AI Prompt**\n\nI want to match all digits on a line but also get the beginning and ending position", "metadata": {}}, {"cell_type": "markdown", "source": "**AI Response**\n\nThere are a couple of ways to do this without regex. One simple approach would be to iterate through the line and track positions. Would you like to try implementing this yourself? \n\nHere's a way to think about it:\n1. Keep track of the current number and its start position\n2. When you find a digit, either start a new number or continue the current one\n3. When you find a non-digit, save the completed number and its positions\n\nWould you like to try implementing this, or would you like me to show you how?", "is_reply": true, "metadata": {}}, {"cell_type": "markdown", "source": "**AI Prompt**\n\nIsn't there an equivalent to \"findall\" that also gives the positions ?", "metadata": {}}, {"cell_type": "markdown", "source": "**AI Response**\n\nYes! You can use `re.finditer()` which returns match objects that include the positions. Each match object has `.start()` and `.end()` methods to get the positions, and `.group()` to get the actual text that matched.\n\nWould you like to see an example of how to use it?", "is_reply": true, "metadata": {}}, {"cell_type": "code", "metadata": {}, "source": "ex = '...345..34.'\nfor element in re.finditer('\\d+', ex):\n print(element)\n print(element.group())\n print(element.start())\n print(element.end())", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["<re.Match object; span=(3, 6), match='345'>\n", "345\n", "3\n", "6\n", "<re.Match object; span=(8, 10), match='34'>\n", "34\n", "8\n", "10\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "I want to adapt extract_numbers, so that I also get the start and end position of the digit.\n\nWith this information, I can get the range of positions to check for a symbol (next function we will create)"}, {"cell_type": "code", "metadata": {}, "source": "def extract_numbers(line: str) -> list[list[int]]:\n numbers = list()\n for n in re.finditer('\\d+', line):\n numbers.append((int(n.group()), n.start(), n.end()))\n return numbers", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "inp = engine_lines[2]\nprint('input:')\nprint(inp)\nprint('extracted numbers:')\nprint(extract_numbers(inp))", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["input:\n", "....42.........131....913..............*......&..........634..................440..&...............83.....@...........404$..=....*..423.*...\n", "extracted numbers:\n", "[(42, 4, 6), (131, 15, 18), (913, 22, 25), (634, 57, 60), (440, 78, 81), (83, 99, 101), (404, 118, 121), (423, 132, 135)]\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "Now let's build `get_index_adjacent_horizontal` that retrieves the indexes to check for a symbol on the **same** line of the digit"}, {"cell_type": "code", "metadata": {}, "source": "def get_index_adjacent_horizontal(start: int, end: int, line_length: int):\n indexes = list()\n if start > 0:\n indexes.append(start-1)\n if end < line_length:\n indexes.append(end)\n return indexes", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "print(get_index_adjacent_horizontal(3, 5, 10))\nprint(get_index_adjacent_horizontal(3, 5, 5))\nprint(get_index_adjacent_horizontal(0, 5, 10))", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["[2, 5]\n", "[2]\n", "[5]\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "How about the lines above and below the line ? You have to account for:\n- the full range of the digit\n- potential diagonal matches"}, {"cell_type": "code", "metadata": {}, "source": "def get_index_adjacent_vertical(start: int, end: int, line_length: int):\n i1 = start - 1 if start > 0 else start \n i2 = end + 1 if end < line_length else end\n return list(range(i1, i2))", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "print(get_index_adjacent_vertical(3, 5, 10))\nprint(get_index_adjacent_vertical(0, 5, 10))\nprint(get_index_adjacent_vertical(3, 5, 5))", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["[2, 3, 4, 5]\n", "[0, 1, 2, 3, 4, 5]\n", "[2, 3, 4]\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def is_part_number(engine_lines, line_nb, start, end):\n line_length = len(engine_lines[0])\n index_h = get_index_adjacent_horizontal(start, end, line_length)\n index_v = get_index_adjacent_vertical(start, end, line_length)\n\n characters = [engine_lines[line_nb][i] for i in index_h]\n if line_nb > 0:\n characters += [engine_lines[line_nb-1][i] for i in index_v]\n if line_nb < len(engine_lines) - 1:\n characters += [engine_lines[line_nb+1][i] for i in index_v]\n \n return any([c in symbols for c in characters])", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "inp = engine_lines[:3]\nprint('input:')\nprint(inp)\nprint(extract_numbers(inp[0]))\nprint(f'733: {is_part_number(inp, 0, 3, 6)}')\nprint(f'289: {is_part_number(inp, 0, 13, 16)}')", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["input:\n", "['...733.......289..262.....520..................161.462..........450.........................183.............................................', '....*....................*.............707.352....*............/.....................801...@...............333..196........484.635......287.', '....42.........131....913..............*......&..........634..................440..&...............83.....@...........404$..=....*..423.*...']\n", "[(733, 3, 6), (289, 13, 16), (262, 18, 21), (520, 26, 29), (161, 47, 50), (462, 51, 54), (450, 64, 67), (183, 92, 95)]\n", "733: True\n", "289: False\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def solve_day3_part1(engine_lines: list[str]):\n total = 0\n for i, line in enumerate(engine_lines):\n numbers = extract_numbers(line)\n for number in numbers:\n nb, start, end = number\n if is_part_number(engine_lines, i, start, end):\n total += nb\n return total", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "solve_day3_part1(engine_lines)", "outputs": [{"output_type": "execute_result", "data": {"text/plain": ["525181"]}, "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "# Part 2"}, {"cell_type": "code", "metadata": {}, "source": "ex = \"...*..*..\"\nfor e in re.finditer('\\*', ex):\n print(e)", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["<re.Match object; span=(3, 4), match='*'>\n", "<re.Match object; span=(6, 7), match='*'>\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def extract_gears(line: str) -> tuple[int, int]:\n gears = list()\n for e in re.finditer('\\*', line):\n gears.append(e.start())\n return gears", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "ex = \"...*..*..\"\nextract_gears(ex)", "outputs": [{"output_type": "execute_result", "data": {"text/plain": ["[3, 6]"]}, "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def is_number_adjacent_h(start, end, gear_index):\n return (end == gear_index) or (start == gear_index + 1)\n\ndef is_number_adjacent_v(start, end, gear_index):\n return ((end - 1) >= gear_index - 1) and (start <= gear_index + 1)", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def extract_adjacent_numbers(engine_lines, gear_line, gear_index):\n \n adjacent = list()\n numbers = extract_numbers(engine_lines[gear_line])\n \n adjacent = [nb for (nb, start, end) in numbers if is_number_adjacent_h(start, end, gear_index)]\n\n if gear_line > 0:\n numbers = extract_numbers(engine_lines[gear_line - 1])\n adjacent += [nb for (nb, start, end) in numbers if is_number_adjacent_v(start, end, gear_index)]\n \n if gear_line < len(engine_lines) - 1:\n numbers = extract_numbers(engine_lines[gear_line + 1])\n adjacent += [nb for (nb, start, end) in numbers if is_number_adjacent_v(start, end, gear_index)]\n \n return adjacent", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "inp = engine_lines[:3]\nprint('input:')\nprint(inp)\nprint(extract_adjacent_numbers(engine_lines, 1, 4))", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["input:\n", "['...733.......289..262.....520..................161.462..........450.........................183.............................................', '....*....................*.............707.352....*............/.....................801...@...............333..196........484.635......287.', '....42.........131....913..............*......&..........634..................440..&...............83.....@...........404$..=....*..423.*...']\n", "[733, 42]\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def solve_day3_part2(engine_lines) -> int:\n\n total = 0\n for i, line in enumerate(engine_lines):\n gears = extract_gears(line)\n for gear_index in gears:\n numbers = extract_adjacent_numbers(engine_lines, i, gear_index)\n if len(numbers) == 2:\n total += numbers[0] * numbers[1]\n return total", "outputs": [], "images": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "answer = solve_day3_part2(engine_lines)\nprint(answer)", "outputs": [{"output_type": "stream", "name": "stdout", "text": ["84289137\n"], "metadata": {}, "execution_count": null}], "images": [], "execution_count": null}], "metadata": {"kernelspec": {"display_name": "python3", "language": "python", "name": "python3"}}, "nbformat": 4, "nbformat_minor": 4} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment