diff --git a/src/AoC_2017/Dazbo's_Advent_of_Code_2017.ipynb b/src/AoC_2017/Dazbo's_Advent_of_Code_2017.ipynb index c42db80..a08a1d1 100644 --- a/src/AoC_2017/Dazbo's_Advent_of_Code_2017.ipynb +++ b/src/AoC_2017/Dazbo's_Advent_of_Code_2017.ipynb @@ -54,7 +54,7 @@ }, "outputs": [], "source": [ - "%pip install jupyterlab-lsp colorama python-dotenv ipykernel " + "%pip install jupyterlab-lsp networkx dazbo-commons python-dotenv ipykernel sympy" ] }, { @@ -67,32 +67,34 @@ "outputs": [], "source": [ "from __future__ import annotations\n", + "import ast\n", + "from collections import Counter, deque, defaultdict\n", + "import copy\n", "from dataclasses import asdict, dataclass, field\n", "from enum import Enum, auto\n", "from functools import cache, reduce\n", - "from itertools import permutations, combinations, count\n", - "from collections import Counter, deque, defaultdict\n", "import heapq\n", - "import copy\n", - "import operator\n", + "from itertools import permutations, combinations, count, cycle\n", "import logging\n", - "import time\n", + "import math\n", + "import operator\n", "import os\n", + "import platform\n", "import re\n", - "import ast\n", - "import unittest\n", + "import sympy\n", "import requests\n", + "\n", + "import dazbo_commons as dc # my own utility library, which includes things like coloured logging\n", + "from dotenv import load_dotenv\n", + "from getpass import getpass\n", + "from IPython.display import display\n", + "from IPython.core.display import Markdown\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import networkx as nx\n", "import pandas as pd\n", - "from tqdm.notebook import tqdm\n", - "from dotenv import load_dotenv\n", "from pathlib import Path\n", - "from getpass import getpass\n", - "from colorama import Fore\n", - "from IPython.display import display\n", - "from IPython.core.display import Markdown" + "from tqdm.notebook import tqdm\n" ] }, { @@ -116,91 +118,22 @@ }, "outputs": [], "source": [ - "##########################################################################\n", - "# SETUP LOGGING\n", - "#\n", - "# Create a new instance of \"logger\" in the client application\n", - "# Set to your preferred logging level\n", - "# And add the stream_handler from this module, if you want coloured output\n", - "##########################################################################\n", - "\n", - "# logger for aoc_commons only\n", - "logger = logging.getLogger(__name__) # aoc_common.aoc_commons\n", + "# Setup logger\n", + "YEAR = 2017\n", + "logger_identifier = \"aoc\" + str(YEAR)\n", + "logger = dc.retrieve_console_logger(logger_identifier)\n", "logger.setLevel(logging.INFO)\n", - "stream_handler = None\n", - "\n", - "class ColouredFormatter(logging.Formatter):\n", - " \"\"\" Custom Formater which adds colour to output, based on logging level \"\"\"\n", - "\n", - " level_mapping = {\"DEBUG\": (Fore.BLUE, \"DBG\"),\n", - " \"INFO\": (Fore.GREEN, \"INF\"),\n", - " \"WARNING\": (Fore.YELLOW, \"WRN\"),\n", - " \"ERROR\": (Fore.RED, \"ERR\"),\n", - " \"CRITICAL\": (Fore.MAGENTA, \"CRT\")\n", - " }\n", - "\n", - " def __init__(self, *args, apply_colour=True, shorten_lvl=True, **kwargs) -> None:\n", - " \"\"\" Args:\n", - " apply_colour (bool, optional): Apply colouring to messages. Defaults to True.\n", - " shorten_lvl (bool, optional): Shorten level names to 3 chars. Defaults to True.\n", - " \"\"\"\n", - " super().__init__(*args, **kwargs)\n", - " self._apply_colour = apply_colour\n", - " self._shorten_lvl = shorten_lvl\n", - "\n", - " def format(self, record):\n", - " if record.levelname in ColouredFormatter.level_mapping:\n", - " new_rec = copy.copy(record)\n", - " colour, new_level = ColouredFormatter.level_mapping[record.levelname]\n", - "\n", - " if self._shorten_lvl:\n", - " new_rec.levelname = new_level\n", - "\n", - " if self._apply_colour:\n", - " msg = colour + super().format(new_rec) + Fore.RESET\n", - " else:\n", - " msg = super().format(new_rec)\n", - "\n", - " return msg\n", - "\n", - " # If our logging message is not using one of these levels...\n", - " return super().format(record)\n", - "\n", - "if not stream_handler:\n", - " stream_handler = logging.StreamHandler()\n", - " stream_fmt = ColouredFormatter(fmt='%(asctime)s.%(msecs)03d:%(name)s - %(levelname)s: %(message)s',\n", - " datefmt='%H:%M:%S')\n", - " stream_handler.setFormatter(stream_fmt)\n", - " \n", - "if not logger.handlers:\n", - " # Add our ColouredFormatter as the default console logging\n", - " logger.addHandler(stream_handler)\n", - "\n", - "def retrieve_console_logger(script_name):\n", - " \"\"\" Create and return a new logger, named after the script\n", - " So, in your calling code, add a line like this:\n", - " logger = ac.retrieve_console_logger(locations.script_name)\n", - " \"\"\"\n", - " a_logger = logging.getLogger(script_name)\n", - " a_logger.addHandler(stream_handler)\n", - " a_logger.propagate = False\n", - " return a_logger\n", - "\n", - "def setup_file_logging(a_logger: logging.Logger, folder: str|Path=\"\"):\n", - " \"\"\" Add a FileHandler to the specified logger. File name is based on the logger name.\n", - " In calling code, we can add a line like this:\n", - " td.setup_file_logging(logger, locations.output_dir)\n", + "logger.info(\"Logger initialised.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", "\n", - " Args:\n", - " a_logger (Logger): The existing logger\n", - " folder (str): Where the log file will be created. Will be created if it doesn't exist\n", - " \"\"\"\n", - " Path(folder).mkdir(parents=True, exist_ok=True) # Create directory if it does not exist\n", - " file_handler = logging.FileHandler(Path(folder, a_logger.name + \".log\"), mode='w')\n", - " file_fmt = logging.Formatter(fmt=\"%(asctime)s.%(msecs)03d:%(name)s:%(levelname)8s: %(message)s\",\n", - " datefmt='%H:%M:%S')\n", - " file_handler.setFormatter(file_fmt)\n", - " a_logger.addHandler(file_handler)" + "- [ffmpeg](https://ffmpeg.org/): in order to render video output, i.e. for visualisations.\n", + "- graphviz: for visualising graphs" ] }, { @@ -209,36 +142,41 @@ "metadata": {}, "outputs": [], "source": [ - "def top_and_tail(data, block_size=5, include_line_numbers=True, zero_indexed=False):\n", - " \"\"\" Print a summary of a large amount of data \n", + "def install_software():\n", + " os_name = platform.system()\n", + " logger.info(f\"Installing packages on {os_name}...\")\n", + " if os_name == \"Windows\":\n", + " os.system(\"winget install ffmpeg --silent --no-upgrade\")\n", + " os.system(\"winget install graphviz --silent --no-upgrade\")\n", + " elif os_name == \"Linux\":\n", + " os.system(\"apt-get -qq update && apt-get -qq -y install ffmpeg\")\n", + " os.system(\"apt -qq -y install graphviz\")\n", + " elif os_name == \"Darwin\":\n", + " os.system(\"brew install ffmpeg\")\n", + " os.system(\"brew install graphviz\")\n", + " else:\n", + " logger.error(f\"Unsupported operating system: {os_name}\")\n", "\n", - " Args:\n", - " data (_type_): The data to present in summary form.\n", - " block_size (int, optional): How many rows to include in the top, and in the tail.\n", - " include_line_numbers (bool, optional): Prefix with line number. Defaults to True.\n", - " zero_indexed (bool, optional): Lines start at 0? Defaults to False.\n", - " \"\"\"\n", - " if isinstance(data, list):\n", - " # Get the number of digits of the last item for proper alignment\n", - " num_digits_last_item = len(str(len(data)))\n", - "\n", - " # Format the string with line number\n", - " def format_with_line_number(idx, line):\n", - " start = 0 if zero_indexed else 1\n", - " if include_line_numbers:\n", - " return f\"{idx + start:>{num_digits_last_item}}: {line}\"\n", - " else:\n", - " return line\n", + "install_software()\n", "\n", - " start = 0 if zero_indexed else 1\n", - " if len(data) < 11:\n", - " return \"\\n\".join(format_with_line_number(i, line) for i, line in enumerate(data))\n", - " else:\n", - " top = [format_with_line_number(i, line) for i, line in enumerate(data[:block_size])]\n", - " tail = [format_with_line_number(i, line) for i, line in enumerate(data[-block_size:], start=len(data)-block_size)]\n", - " return \"\\n\".join(top + [\"...\"] + tail)\n", - " else:\n", - " return data" + "logger.info(\"Note that installed applications may not be immediately available after first installing.\\n\" \\\n", + " \"It may be necessary to relaunch the notebook environment.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Checking `ffmpeg` version:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!ffmpeg -version" ] }, { @@ -276,7 +214,7 @@ " logger.debug(\"Trying .env at %s\", os.path.realpath(potential_path))\n", " if os.path.exists(potential_path):\n", " logger.info(\"Using .env at %s\", os.path.realpath(potential_path))\n", - " load_dotenv(potential_path, verbose=True)\n", + " load_dotenv(potential_path, override=True, verbose=True)\n", " return True\n", " \n", " potential_path = os.path.join('..', potential_path)\n", @@ -284,18 +222,8 @@ " logger.warning(\"No .env file found.\")\n", " return False\n", "\n", - "get_envs_from_file() # read env variables from a .env file, if we can find one" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "kSem0cT_LApT", - "tags": [] - }, - "outputs": [], - "source": [ + "get_envs_from_file() # read env variables from a .env file, if we can find one\n", + "\n", "if os.getenv('AOC_SESSION_COOKIE'):\n", " logger.info('Session cookie retrieved: %s...%s', os.environ['AOC_SESSION_COOKIE'][0:6], os.environ['AOC_SESSION_COOKIE'][-6:])\n", "else: # it's not in our environment variables, so we'll need to input the value\n", @@ -410,7 +338,14 @@ " locations.input_dir.mkdir(parents=True, exist_ok=True)\n", "\n", " url = f\"https://adventofcode.com/{year}/day/{day}/input\"\n", - " cookies = {\"session\": session_cookie}\n", + " \n", + " # Don't think we need to set a user-agent\n", + " # headers = {\n", + " # \"User-Agent\": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'\n", + " # }\n", + " cookies = { \n", + " \"session\": session_cookie\n", + " }\n", " response = requests.get(url, cookies=cookies, timeout=5)\n", "\n", " data = \"\"\n", @@ -422,7 +357,9 @@ " file.write(data)\n", " return data\n", " else:\n", - " raise ValueError(f\"Unable to retrieve input data. HTTP response: {response.status_code}\")\n" + " raise ValueError(f\"Unable to retrieve input data.\\n\" +\n", + " f\"HTTP response: {response.status_code}\\n\" +\n", + " f\"{response.reason}: {response.content.decode('utf-8').strip()}\")\n" ] }, { @@ -733,31 +670,6 @@ " return ret_str if number > 0 else \"0\"\n" ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "6YtEtBnfNUKw" - }, - "source": [ - "### Generic Initialisation\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "sbdA-geUNqAF", - "tags": [] - }, - "outputs": [], - "source": [ - "FOLDER = \"aoc\"\n", - "YEAR = 2017\n", - "logger_identifier = \"aoc\" + str(YEAR)\n", - "logger = retrieve_console_logger(logger_identifier)\n", - "logger.setLevel(logging.DEBUG)" - ] - }, { "cell_type": "markdown", "metadata": { @@ -771,132 +683,6 @@ "To copy the template day, select all the cells in the `Day n` template, add a new cell at the end, and then paste the cells there." ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "xZvWwxmJbGbD" - }, - "source": [ - "## Day n: title" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "YGKQZAMNKA8M", - "tags": [] - }, - "outputs": [], - "source": [ - "DAY = \"n\" # replace with actual number (without leading digit)\n", - "logger.setLevel(logging.DEBUG)\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": { - "id": "8k00bAJR7vCX" - }, - "outputs": [], - "source": [ - "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", - "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", - "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\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", - "except ValueError as e:\n", - " logger.error(e)\n", - "\n", - "with open(locations.input_file, mode=\"rt\") as f:\n", - " input_data = f.read().splitlines()\n", - "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "W0tvEzJYxD6r" - }, - "source": [ - "### Day n Part 1\n", - "\n", - "Overview..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "yq4_ffMZ75iq" - }, - "outputs": [], - "source": [ - "def solve(data):\n", - " pass" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "QeazYTD0xS2C" - }, - "outputs": [], - "source": [ - "%%time\n", - "validate(solve(\"abcdef\"), \"uvwxyz\") # test with sample data\n", - "soln = solve(input_data)\n", - "logger.info(f\"Part 1 soln={soln}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "bG210YZNxPO5" - }, - "source": [ - "### Day n Part 2\n", - "\n", - "Overview..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "oGOtNVJ8xWHZ" - }, - "outputs": [], - "source": [ - "def solve(data):\n", - " pass" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "SuLYqDZX76u4" - }, - "outputs": [], - "source": [ - "%%time\n", - "validate(solve(\"abcdef\"), \"uvwxyz\") # test with sample data\n", - "soln = solve(input_data)\n", - "logger.info(f\"Part 2 soln={soln}\")" - ] - }, { "cell_type": "markdown", "metadata": { @@ -932,10 +718,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\n", "logger.setLevel(logging.INFO)\n", - "# td.setup_file_logging(logger, locations.output_dir)\n", "\n", "# Retrieve input and store in local file\n", "try:\n", @@ -946,7 +729,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().strip()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -1007,9 +790,18 @@ "outputs": [], "source": [ "%%time\n", - "validate(part1(\"91212129\"), 9) # test with sample data\n", + "sample_inputs = []\n", + "sample_inputs.append(\"\"\"91212129\"\"\")\n", + "sample_answers = [9]\n", + "\n", + "for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", + " validate(part1(curr_input), curr_ans) # test with sample data\n", + " logger.info(\"Test passed\")\n", + "\n", + "logger.info(\"All tests passed!\")\n", + "\n", "soln = part1(input_data)\n", - "logger.info(\"Part 1: total=%d\", soln)" + "logger.info(f\"Part 1 soln={soln}\")" ] }, { @@ -1048,7 +840,16 @@ "outputs": [], "source": [ "%%time\n", - "validate(part2(\"12131415\"), 4)\n", + "sample_inputs = []\n", + "sample_inputs.append(\"\"\"12131415\"\"\")\n", + "sample_answers = [4]\n", + "\n", + "for curr_input, curr_ans in zip(sample_inputs, sample_answers):\n", + " validate(part2(curr_input), curr_ans) # test with sample data\n", + " logger.info(\"Test passed\")\n", + "\n", + "logger.info(\"All tests passed!\")\n", + "\n", "soln = part2(input_data)\n", "logger.info(\"Part 2: total=%d\", soln)" ] @@ -1088,10 +889,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\n", "logger.setLevel(logging.INFO)\n", - "# td.setup_file_logging(logger, locations.output_dir)\n", "\n", "# Retrieve input and store in local file\n", "try:\n", @@ -1102,7 +900,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().splitlines()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -1258,10 +1056,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\n", "logger.setLevel(logging.INFO)\n", - "# td.setup_file_logging(logger, locations.output_dir)\n", "\n", "# Retrieve input and store in local file\n", "try:\n", @@ -1599,10 +1394,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\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", @@ -1613,7 +1405,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().splitlines()\n", "\n", - "logger.debug(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.debug(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -1760,10 +1552,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\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", @@ -1774,7 +1563,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = list(map(int, f.read().splitlines()))\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data, zero_indexed=True))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data, zero_indexed=True))" ] }, { @@ -1918,7 +1707,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = list(map(int, f.read().split()))\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data, zero_indexed=True))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data, zero_indexed=True))" ] }, { @@ -2063,10 +1852,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\n", "logger.setLevel(logging.INFO)\n", - "# td.setup_file_logging(logger, locations.output_dir)\n", "\n", "# Retrieve input and store in local file\n", "try:\n", @@ -2077,7 +1863,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().splitlines()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -2424,10 +2210,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\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", @@ -2438,7 +2221,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().splitlines()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -2675,10 +2458,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\n", "logger.setLevel(logging.INFO)\n", - "# td.setup_file_logging(logger, locations.output_dir)\n", "\n", "# Retrieve input and store in local file\n", "try:\n", @@ -2689,7 +2469,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -2884,10 +2664,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\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", @@ -2898,7 +2675,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().strip()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -3086,10 +2863,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\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", @@ -3100,7 +2874,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().splitlines()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -3131,10 +2905,7 @@ "d_name = \"d\" + str(DAY).zfill(2) # e.g. d01\n", "script_name = \"aoc\" + str(YEAR) + d_name # e.g. aoc2017d01\n", "locations = get_locations(d_name)\n", - "\n", - "# SETUP LOGGING\n", "logger.setLevel(logging.INFO)\n", - "# td.setup_file_logging(logger, locations.output_dir)\n", "\n", "# Retrieve input and store in local file\n", "try:\n", @@ -3145,7 +2916,7 @@ "with open(locations.input_file, mode=\"rt\") as f:\n", " input_data = f.read().strip()\n", "\n", - "logger.info(\"Input data:\\n%s\", top_and_tail(input_data))" + "logger.info(\"Input data:\\n%s\", dc.top_and_tail(input_data))" ] }, { @@ -3422,12 +3193,127 @@ "logger.info(f\"Part 2 soln={max_steps}\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## Day n: title" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "DAY = \"n\" # 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. aoc2017d01\n", + "locations = 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 n Part 1\n", + "\n", + "Overview..." + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "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 n 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}\")" + ] } ], "metadata": { @@ -3452,7 +3338,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.11.7" }, "toc-autonumbering": false, "toc-showcode": false,