Created
December 3, 2024 17:29
-
-
Save algal/addf3dfd287eb629c8574de3ef4ae10b to your computer and use it in GitHub Desktop.
My Dialog
This file contains 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": "code", "metadata": {}, "source": "from aocd import get_data\ninp = get_data(day=3, year=2023)", "outputs": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "The engineer explains that an engine part seems to be missing from the engine, but nobody can figure out which one. If you can add up all the part numbers in the engine schematic, it should be easy to work out which part is missing.\n\nThe engine schematic (your puzzle input) consists of a visual representation of the engine. There are lots of numbers and symbols you don't really understand, but apparently any number adjacent to a symbol, even diagonally, is a \"part number\" and should be included in your sum. (Periods (.) do not count as a symbol.)\n\nHere is an example engine schematic:\n\n```\n467..114..\n...*......\n..35..633.\n......#...\n617*......\n.....+.58.\n..592.....\n......755.\n...$.*....\n.664.598..\n```\n\nIn this schematic, two numbers are not part numbers because they are not adjacent to a symbol: 114 (top right) and 58 (middle right). Every other number is adjacent to a symbol and so is a part number; their sum is 4361."}, {"cell_type": "code", "metadata": {}, "source": "sample = \"\"\"467..114..\n...*......\n..35..633.\n......#...\n617*......\n.....+.58.\n..592.....\n......755.\n...$.*....\n.664.598..\"\"\"", "outputs": [], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "Approaches:\n\n- read the file\n- collect all numbers, and map every number to a set of coordinates for its digits\n- also collect all symbols\n- then go through every number, and check if it is near a symbol"}, {"cell_type": "code", "metadata": {}, "source": "import re\nms = re.finditer(r'(?P<num>[0-9]+)',\"467..114..\")", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "ms = list(ms)\nms", "outputs": [{"data": {"text/plain": ["[<re.Match object; span=(0, 3), match='467'>,\n", " <re.Match object; span=(5, 8), match='114'>]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "ms[0].group('num')", "outputs": [{"data": {"text/plain": ["'467'"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "dir(ms[0])", "outputs": [{"data": {"text/plain": ["['__class__',\n", " '__class_getitem__',\n", " '__copy__',\n", " '__deepcopy__',\n", " '__delattr__',\n", " '__dir__',\n", " '__doc__',\n", " '__eq__',\n", " '__format__',\n", " '__ge__',\n", " '__getattribute__',\n", " '__getitem__',\n", " '__getstate__',\n", " '__gt__',\n", " '__hash__',\n", " '__init__',\n", " '__init_subclass__',\n", " '__le__',\n", " '__lt__',\n", " '__module__',\n", " '__ne__',\n", " '__new__',\n", " '__reduce__',\n", " '__reduce_ex__',\n", " '__repr__',\n", " '__setattr__',\n", " '__sizeof__',\n", " '__str__',\n", " '__subclasshook__',\n", " 'end',\n", " 'endpos',\n", " 'expand',\n", " 'group',\n", " 'groupdict',\n", " 'groups',\n", " 'lastgroup',\n", " 'lastindex',\n", " 'pos',\n", " 're',\n", " 'regs',\n", " 'span',\n", " 'start',\n", " 'string']"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "(ms[0].start(),ms[0].end())", "outputs": [{"data": {"text/plain": ["(0, 3)"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "(ms[1].start(),ms[1].end())", "outputs": [{"data": {"text/plain": ["(5, 8)"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "import re\n\ndef parse_line(s:str, line_index:int) -> []:\n retval = []\n pat = r'(?P<num>[0-9]+)'\n for m in re.finditer(pat,s):\n x_coords = range(m.start(),m.end())\n positions = [(line_index,x_pos) for x_pos in x_coords]\n val = int(m.group('num'))\n record = [val,positions]\n retval.append(record)\n return retval", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "l1out = parse_line(\"467..114..\",0)\nl1out[0]", "outputs": [{"data": {"text/plain": ["[467, [(0, 0), (0, 1), (0, 2)]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "l1out = parse_line(\"467..114..\",0)\nl1out[1]", "outputs": [{"data": {"text/plain": ["[114, [(0, 5), (0, 6), (0, 7)]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def parse_multiline(s:str) -> list:\n retval = []\n for i,line in enumerate(s.splitlines()):\n records = parse_line(line,i)\n retval.extend(records)\n return retval", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "parse_multiline(sample)", "outputs": [{"data": {"text/plain": ["[[467, [(0, 0), (0, 1), (0, 2)]],\n", " [114, [(0, 5), (0, 6), (0, 7)]],\n", " [35, [(2, 2), (2, 3)]],\n", " [633, [(2, 6), (2, 7), (2, 8)]],\n", " [617, [(4, 0), (4, 1), (4, 2)]],\n", " [58, [(5, 7), (5, 8)]],\n", " [592, [(6, 2), (6, 3), (6, 4)]],\n", " [755, [(7, 6), (7, 7), (7, 8)]],\n", " [664, [(9, 1), (9, 2), (9, 3)]],\n", " [598, [(9, 5), (9, 6), (9, 7)]]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "import re\n\ndef parse_line_for_symbol(s:str, line_index:int) -> []:\n retval = []\n pat = r'(?P<symbol>[^.0123456789])'\n for m in re.finditer(pat,s):\n x_coords = range(m.start(),m.end())\n positions = [(line_index,x_pos) for x_pos in x_coords]\n val = m.group('symbol')\n record = [val,positions]\n retval.append(record)\n return retval", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "parse_line_for_symbol(sample.splitlines()[-2],0)", "outputs": [{"data": {"text/plain": ["[['$', [(0, 3)]], ['*', [(0, 5)]]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "**AI Prompt**\n\nWhat is the python regular expression syntax to match any character which is not a numerical digit and not a full stop and not whitespace?"}, {"cell_type": "markdown", "metadata": {}, "source": "**AI Response**\n\nTo match any character that is not a digit, not a period (full stop), and not whitespace, you can use this pattern:\n\n`[^.0-9\\s]`\n\nThis works because:\n- `^` inside `[]` means \"not these characters\"\n- `.` is the literal period\n- `0-9` is the range of digits\n- `\\s` represents any whitespace character\n\nWould you like me to explain any part of this in more detail?"}, {"cell_type": "code", "metadata": {}, "source": "re.findall(r'(?P<symbol>[^.0-9])',\"...$.*....\")", "outputs": [{"data": {"text/plain": ["['$', '*']"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def parse_multiline_symbols(s:str) -> list:\n retval = []\n for i,line in enumerate(s.splitlines()):\n records = parse_line_for_symbol(line,i)\n retval.extend(records)\n return retval", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "parse_multiline_symbols(sample)", "outputs": [{"data": {"text/plain": ["[['*', [(1, 3)]],\n", " ['#', [(3, 6)]],\n", " ['*', [(4, 3)]],\n", " ['+', [(5, 5)]],\n", " ['$', [(8, 3)]],\n", " ['*', [(8, 5)]]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "To recap, we now have:\n\n- parse_multiline_symbols :: returns a list of records of symbols\n- parse_multiline :: returns a list of records of numbers, and their numerical values\n\nEvery record is of teh format `[value, list_of_positions_in_line_x_notation]`"}, {"cell_type": "markdown", "metadata": {}, "source": "Now we want to find all the numbers which are neighoring to a symbol."}, {"cell_type": "code", "metadata": {}, "source": "def is_touching(number_record, symbol_record):\n def positions_near(pos_a,pos_b):\n line_a, x_a = pos_a\n line_b, x_b = pos_b\n return abs(line_a - line_b) <= 1 and abs(x_a - x_b) <= 1\n symbol_pos = symbol_record[1][0]\n for pos in number_record[1]:\n if positions_near(pos,symbol_pos):\n return True\n return False", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "sample_nums = parse_multiline(sample)\nsample_nums", "outputs": [{"data": {"text/plain": ["[[467, [(0, 0), (0, 1), (0, 2)]],\n", " [114, [(0, 5), (0, 6), (0, 7)]],\n", " [35, [(2, 2), (2, 3)]],\n", " [633, [(2, 6), (2, 7), (2, 8)]],\n", " [617, [(4, 0), (4, 1), (4, 2)]],\n", " [58, [(5, 7), (5, 8)]],\n", " [592, [(6, 2), (6, 3), (6, 4)]],\n", " [755, [(7, 6), (7, 7), (7, 8)]],\n", " [664, [(9, 1), (9, 2), (9, 3)]],\n", " [598, [(9, 5), (9, 6), (9, 7)]]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "sample_symbols = parse_multiline_symbols(sample)\nsample_symbols", "outputs": [{"data": {"text/plain": ["[['*', [(1, 3)]],\n", " ['#', [(3, 6)]],\n", " ['*', [(4, 3)]],\n", " ['+', [(5, 5)]],\n", " ['$', [(8, 3)]],\n", " ['*', [(8, 5)]]]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "is_touching(sample_nums[0],sample_symbols[0])", "outputs": [{"data": {"text/plain": ["True"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "is_touching(sample_nums[0],sample_symbols[3])", "outputs": [{"data": {"text/plain": ["False"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def numbers_touching_symbols(number_records,symbol_records):\n toucher_idxs = []\n for i,nr in enumerate(number_records):\n if any([is_touching(nr,sym) for sym in symbol_records]):\n toucher_idxs.append(i)\n unique_toucher_idxs = list(set(toucher_idxs))\n touchers = [number_records[i] for i in unique_toucher_idxs]\n toucher_vals = [r[0] for r in touchers]\n return toucher_vals", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "numbers_touching_symbols(sample_nums,sample_symbols)", "outputs": [{"data": {"text/plain": ["[467, 35, 633, 617, 592, 755, 664, 598]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def sum_valid_nums(s:str):\n numrecords = parse_multiline(s)\n symrecords = parse_multiline_symbols(s)\n touchers = numbers_touching_symbols(numrecords,symrecords)\n return sum(touchers)", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "sum_valid_nums(sample)", "outputs": [{"data": {"text/plain": ["4361"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "sum_valid_nums(inp)", "outputs": [{"data": {"text/plain": ["535351"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "markdown", "metadata": {}, "source": "## part 2\n\nNeed to find all gears (symbol is asterisk) which are neighboring exactly two numbers.\nThen need to multiply those numbers\nThen need to add the products"}, {"cell_type": "code", "metadata": {}, "source": "def is_gear(sym_record,num_records):\n \"Returns list of two touching numbers, or empty list\"\n if sym_record[0] != '*': return []\n touchers_idx = set()\n for i,nr in enumerate(num_records):\n if is_touching(nr,sym_record):\n touchers_idx = touchers_idx | set([i])\n if len(touchers_idx) != 2: return []\n touchers = [num_records[i][0] for i in list(touchers_idx)]\n return touchers", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "is_gear(sample_symbols[-1],sample_nums)", "outputs": [{"data": {"text/plain": ["[598, 755]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "is_gear(sample_symbols[-2],sample_nums)", "outputs": [{"data": {"text/plain": ["[]"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "def sum_gear_ratios(s:str) -> int:\n numrecords = parse_multiline(s)\n symrecords = parse_multiline_symbols(s)\n total = 0\n for sr in symrecords:\n gr = is_gear(sr,numrecords)\n if len(gr) == 2:\n total += gr[0] * gr[1]\n return total", "outputs": [], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "sum_gear_ratios(sample)", "outputs": [{"data": {"text/plain": ["467835"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "execution_count": null}, {"cell_type": "code", "metadata": {}, "source": "sum_gear_ratios(inp)", "outputs": [{"data": {"text/plain": ["87287096"]}, "metadata": {}, "output_type": "execute_result", "execution_count": null}], "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