diff --git a/.env b/.env index 36ca0235..96444a78 100644 Binary files a/.env and b/.env differ diff --git a/scripts/build_aoc_commons.ps1 b/scripts/build_aoc_commons.ps1 new file mode 100644 index 00000000..a5966080 --- /dev/null +++ b/scripts/build_aoc_commons.ps1 @@ -0,0 +1,21 @@ +# Author: Darren +# +# Utility script to build dazbo-aoc-commons and upload it to PyPI. +# Then, install the module: +# py -m pip install dazbo-aoc-commons + +Set-Location C:\Users\djl\localdev\Python\Advent-of-Code\scripts +Set-Location ..\src\aoc_common\ +"`nDeleting dist folder..." +if (Test-Path "dist") { + Remove-Item -LiteralPath "dist" -Recurse -Force +} + +"`nRunning package build..." +py -m setup sdist + +"`nUploading to PyPi..." +py ..\..\scripts\upload_to_pypi.py + +"`nResetting folder." +Set-Location ..\.. diff --git a/scripts/upload_to_pypi.py b/scripts/upload_to_pypi.py new file mode 100644 index 00000000..e974ac6c --- /dev/null +++ b/scripts/upload_to_pypi.py @@ -0,0 +1,25 @@ +""" Python to upload the dist folder to PyPi """ +import os +import subprocess +from dotenv import load_dotenv + +def upload_to_pypi(): + """ + So that we can skip having to run this command (and pass in username and pwd) separately: + twine upload dist/* + """ + load_dotenv() + + # expect vars to be stored in .env or environment vars + username = os.getenv('PYPI_USERNAME') + api_key = os.getenv('PYPI_API_KEY') + + if username is None or api_key is None: + raise ValueError("PYPI_USERNAME and/or PYPI_PASSWORD are not set in the .env file") + + try: + subprocess.run(['twine', 'upload', 'dist/*', '-u', username, '-p', api_key], check=True) + except subprocess.CalledProcessError as e: + print(f"An error occurred during the upload: {e}") + +upload_to_pypi() diff --git a/src/AoC_2015/d19_molecular_retrosynthesis_str_replacement/reindeer_chemistry.py b/src/AoC_2015/d19_molecular_retrosynthesis_str_replacement/reindeer_chemistry.py index 06a98814..26a8937b 100644 --- a/src/AoC_2015/d19_molecular_retrosynthesis_str_replacement/reindeer_chemistry.py +++ b/src/AoC_2015/d19_molecular_retrosynthesis_str_replacement/reindeer_chemistry.py @@ -44,10 +44,10 @@ import re import logging from collections import defaultdict -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.INFO) def main(): diff --git a/src/AoC_2015/d20_elf_visits_counting_generators_factors_and_set_algebra/elf_delivery.py b/src/AoC_2015/d20_elf_visits_counting_generators_factors_and_set_algebra/elf_delivery.py index 55066bc6..5a8cbf73 100644 --- a/src/AoC_2015/d20_elf_visits_counting_generators_factors_and_set_algebra/elf_delivery.py +++ b/src/AoC_2015/d20_elf_visits_counting_generators_factors_and_set_algebra/elf_delivery.py @@ -35,10 +35,10 @@ import time from collections import defaultdict import logging -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.INFO) TARGET = 36000000 @@ -53,7 +53,7 @@ def main(): presents_dropped, house_num = 0, 0 while presents_dropped < TARGET: house_num += 1 - presents_dropped = sum(factor * 10 for factor in td.get_factors(house_num)) + presents_dropped = sum(factor * 10 for factor in ac.get_factors(house_num)) logger.info("Part 1: House=%d, presents dropped=%d", house_num, presents_dropped) @@ -77,7 +77,7 @@ def generate_presents_for_house(per_elf_multiplier: int, elf_visit_limit: int = while True: # iterate for each house, yielding each time house_num += 1 presents_dropped = 0 - factors_for_house = td.get_factors(house_num) + factors_for_house = ac.get_factors(house_num) # iterate through all the factors for this house for factor in factors_for_house: diff --git a/src/AoC_2015/d21_boss_fight_classes_namedtuples_combinations_comprehension_if/boss_fight.py b/src/AoC_2015/d21_boss_fight_classes_namedtuples_combinations_comprehension_if/boss_fight.py index 07a91440..4730f0be 100644 --- a/src/AoC_2015/d21_boss_fight_classes_namedtuples_combinations_comprehension_if/boss_fight.py +++ b/src/AoC_2015/d21_boss_fight_classes_namedtuples_combinations_comprehension_if/boss_fight.py @@ -32,10 +32,10 @@ from os import path from itertools import combinations from player import Player -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.DEBUG) BOSS_FILE = "boss_stats.txt" diff --git a/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting.py b/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting.py index aa545ae6..3d85660f 100644 --- a/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting.py +++ b/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting.py @@ -40,10 +40,10 @@ from os import path from typing import Iterable -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.INFO) # td.setup_file_logging(logger, folder=locations.output_dir) @@ -372,7 +372,7 @@ def attack_combos_generator(count_different_attacks: int) -> Iterable[str]: i = 0 while True: # convert i to base-n (where n is the number of attacks we can choose from) - yield td.to_base_n(i, count_different_attacks) + yield ac.to_base_n(i, count_different_attacks) i += 1 @cache # I think there are only about 3000 different sorted attacks diff --git a/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting_old.py b/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting_old.py index 8ceaf4cc..293af062 100644 --- a/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting_old.py +++ b/src/AoC_2015/d22_wizards_factories_dataclass_generators/spell_casting_old.py @@ -30,10 +30,10 @@ import time from os import path from typing import Iterable -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.INFO) # td.setup_file_logging(logger, folder=locations.script_dir) diff --git a/src/AoC_2015/d23_computer/computer.py b/src/AoC_2015/d23_computer/computer.py index f90e2e64..cda26702 100644 --- a/src/AoC_2015/d23_computer/computer.py +++ b/src/AoC_2015/d23_computer/computer.py @@ -17,10 +17,10 @@ """ import logging import time -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.INFO) class Instructions(): diff --git a/src/AoC_2015/d24_sleigh_balance_subset_sum/sleigh_balance.py b/src/AoC_2015/d24_sleigh_balance_subset_sum/sleigh_balance.py index b3727f85..aaa80f51 100644 --- a/src/AoC_2015/d24_sleigh_balance_subset_sum/sleigh_balance.py +++ b/src/AoC_2015/d24_sleigh_balance_subset_sum/sleigh_balance.py @@ -30,15 +30,15 @@ import time from math import prod from itertools import combinations -import aoc_common.aoc_commons as td +import aoc_commons as ac YEAR = 2015 DAY = 24 -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.INFO) -td.write_puzzle_input_file(YEAR, DAY, locations) +ac.write_puzzle_input_file(YEAR, DAY, locations) def main(): # with open(locations.sample_input_file, mode="rt") as f: diff --git a/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes.py b/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes.py index 62993fae..8afffdf7 100644 --- a/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes.py +++ b/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes.py @@ -21,10 +21,10 @@ """ import logging import time -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.DEBUG) TARGET_ROW = 2947 diff --git a/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes_numpy.py b/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes_numpy.py index c0ff3432..2866fa25 100644 --- a/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes_numpy.py +++ b/src/AoC_2015/d25_instr_manual_2d_list_gen/instr_manual_codes_numpy.py @@ -22,10 +22,10 @@ import logging import time import numpy as np -import aoc_common.aoc_commons as td +import aoc_commons as ac -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.DEBUG) TARGET_ROW = 2947 diff --git a/src/AoC_2022/d01_calorie_counting/elf_calories.py b/src/AoC_2022/d01_calorie_counting/elf_calories.py index b1fc2ae5..de3d7240 100644 --- a/src/AoC_2022/d01_calorie_counting/elf_calories.py +++ b/src/AoC_2022/d01_calorie_counting/elf_calories.py @@ -29,7 +29,7 @@ import logging from pathlib import Path import time -import aoc_common.aoc_commons as td +import aoc_commons as ac SCRIPT_NAME = Path(__file__).stem SCRIPT_DIR = Path(__file__).parent @@ -38,7 +38,7 @@ logger = logging.getLogger(SCRIPT_NAME) logger.setLevel(logging.DEBUG) -logger.addHandler(td.stream_handler) +logger.addHandler(ac.stream_handler) def main(): with open(INPUT_FILE, mode="rt") as f: diff --git a/src/AoC_2022/d12_hill_climbing_algorithm/hill_climbing_E_to_a.py b/src/AoC_2022/d12_hill_climbing_algorithm/hill_climbing_E_to_a.py index 73b5be36..82e07926 100644 --- a/src/AoC_2022/d12_hill_climbing_algorithm/hill_climbing_E_to_a.py +++ b/src/AoC_2022/d12_hill_climbing_algorithm/hill_climbing_E_to_a.py @@ -31,7 +31,7 @@ from pathlib import Path import time from matplotlib import pyplot as plt -import aoc_common.aoc_commons as td +import aoc_commons as ac from aoc_common.aoc_commons import Point SCRIPT_NAME = Path(__file__).stem @@ -42,7 +42,7 @@ logger = logging.getLogger(SCRIPT_NAME) logger.setLevel(logging.DEBUG) -logger.addHandler(td.stream_handler) +logger.addHandler(ac.stream_handler) # td.setup_file_logging(logger, OUTPUT_DIR, SCRIPT_NAME) class Grid(): diff --git a/src/aoc_commons_package/README.md b/src/aoc_common/README.md similarity index 80% rename from src/aoc_commons_package/README.md rename to src/aoc_common/README.md index 49f12fa7..8b3fa08a 100644 --- a/src/aoc_commons_package/README.md +++ b/src/aoc_common/README.md @@ -8,4 +8,4 @@ pip install dazbo-aoc-commons ## Use -import aoc_common.aoc_commons as td \ No newline at end of file +import aoc_commons as ac \ No newline at end of file diff --git a/src/aoc_commons_package/aoc_common/__init__.py b/src/aoc_common/__init__.py similarity index 100% rename from src/aoc_commons_package/aoc_common/__init__.py rename to src/aoc_common/__init__.py diff --git a/src/aoc_commons_package/aoc_common/aoc_commons.py b/src/aoc_common/aoc_commons.py similarity index 89% rename from src/aoc_commons_package/aoc_common/aoc_commons.py rename to src/aoc_common/aoc_commons.py index cf8a69cc..cbad4a84 100644 --- a/src/aoc_commons_package/aoc_common/aoc_commons.py +++ b/src/aoc_common/aoc_commons.py @@ -5,8 +5,8 @@ A set of helper functions, reusable classes and attributes used by my AoC solutions Test with tests/test_aoc_commons.py -You could import as follows: -import common.aoc_commons as td +You can import as follows: +import aoc_commons as ac """ # py -m pip install requests python-dotenv from __future__ import annotations @@ -111,7 +111,8 @@ class Locations: sample_input_file: Path input_file: Path -def get_locations(script_file): +def get_locations(script_file) -> Locations: + """ Set various paths, based on the location of the calling script. """ script_name = Path(script_file).stem # this script file, without .py script_dir = Path(script_file).parent # the folder where this script lives input_dir = Path(script_dir, "input") @@ -128,51 +129,61 @@ def get_locations(script_file): # Retrieving input data ################################################################## -def write_puzzle_input_file(year: int, day: int, locations: Locations) -> bool: - """ Use session key to obtain user's unique data for this year and day. - Only retrieve if the input file does not already exist. - Return True if retrieved; False if file exists. - """ - if os.path.exists(locations.input_file): - logger.debug("%s already exists", os.path.basename(locations.input_file)) - return False - - potential_paths = [ +def get_envs_from_file() -> bool: + """ Look for .env files, read variables from it, and store as environment variables """ + potential_paths = [ # look for .env '.env', os.path.join('..', '.env'), os.path.join('..', '..', '.env'), ] - env_path = "" for a_path in potential_paths: if os.path.exists(a_path): logger.info("Using .env at %s", a_path) - env_path = a_path + load_dotenv(a_path, verbose=True) + return True + + logger.warning("No .env file found.") + return False + +get_envs_from_file() # read env variables from a .env file, if we can find one + +def write_puzzle_input_file(year: int, day: int, locations: Locations) -> bool: + """ Use session key to obtain user's unique data for this year and day. + Only retrieve if the input file does not already exist. + Return True if successful. + Requires env: AOC_SESSION_COOKIE, which can be set from the .env. + """ + if os.path.exists(locations.input_file): + logger.debug("%s already exists", os.path.basename(locations.input_file)) + return True - load_dotenv(env_path) - SESSION_COOKIE = os.getenv('AOC_SESSION_COOKIE') - if SESSION_COOKIE: + session_cookie = os.getenv('AOC_SESSION_COOKIE') + if session_cookie: logger.info('Session cookie retrieved.') - else: - logger.error('Failed to retrieve session cookie. Is it in your .env?') - url = f"https://adventofcode.com/{year}/day/{day}/input" - cookies = {"session": SESSION_COOKIE} - response = requests.get(url, cookies=cookies) - data = "" - - if response.status_code == 200: - data = response.text + # Create input folder, if it doesn't exist + if not locations.input_dir.exists(): + locations.input_dir.mkdir(parents=True, exist_ok=True) + + url = f"https://adventofcode.com/{year}/day/{day}/input" + cookies = {"session": session_cookie} + response = requests.get(url, cookies=cookies, timeout=5) + + data = "" + if response.status_code == 200: + data = response.text + else: + data = f"Failed to retrieve puzzle input: {response.status_code}" + + with open(locations.input_file, 'w') as file: + logger.debug("Writing input file %s", os.path.basename(locations.input_file)) + file.write(data) + return True else: - data = f"Failed to retrieve puzzle input: {response.status_code}" - - if not locations.input_dir.exists(): - locations.input_dir.mkdir(parents=True, exist_ok=True) - logger.debug("Writing %s", os.path.basename(locations.input_file)) - with open(locations.input_file, 'w') as file: - file.write(data) + logger.error('Failed to retrieve session cookie. Is it in your .env?') - return True + return False ################################################################# # POINTS, VECTORS AND GRIDS diff --git a/src/aoc_common/setup.py b/src/aoc_common/setup.py new file mode 100644 index 00000000..0f62d66c --- /dev/null +++ b/src/aoc_common/setup.py @@ -0,0 +1,28 @@ +""" +Used to setup the aoc_commons package. +Make sure you have installed twine first. +py -m pip install twine + +1. Delete any existing dist folder from aoc_commons_package. +2. Before updating, be sure to increment the version number. +3. Create the package. From the aoc_commons_package folder, run: + py -m setup sdist +4. Upload to PyPi: + twine upload dist/* +5. Install the package from your venv at the project folder level: + py -m pip install dazbo-aoc-commons +""" +from setuptools import setup + +setup( + name='dazbo-aoc-commons', + version='0.1.10', + url='https://github.com/derailed-dash/Advent-of-Code', + author='derailed-dash', + description='A set up of helper functions and classes to assist with Advent of Code problems', + long_description=open('README.md').read(), + long_description_content_type="text/markdown", + py_modules=["aoc_commons"], + package_dir={'': '.'}, # Current directory + install_requires=[], +) diff --git a/src/aoc_commons_package/aoc_common/tests/input/input.txt b/src/aoc_commons_package/aoc_common/tests/input/input.txt deleted file mode 100644 index 8ca0ad5a..00000000 Binary files a/src/aoc_commons_package/aoc_common/tests/input/input.txt and /dev/null differ diff --git a/src/aoc_commons_package/setup.py b/src/aoc_commons_package/setup.py deleted file mode 100644 index 4ba94311..00000000 --- a/src/aoc_commons_package/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -Used to setup the aoc_commons package. -1. Delete any existing dist folder from aoc_commons_package. -2. When updating, be sure to increment the version number. -3. Create the package. From the aoc_commons_package folder, run: - py -m setup sdist -4. Upload to PyPi: - twine upload dist/* -5. Install the package from venv at project folder level: - py -m pip install dazbo-aoc-commons -""" -from setuptools import setup, find_packages - -# Read the content of README.md -with open("README.md", "r", encoding="utf-8") as fh: - long_description = fh.read() - -setup( - name='dazbo-aoc-commons', - version='0.1.2', - url='https://github.com/derailed-dash/Advent-of-Code', - author='derailed-dash', - description='A set up of helper functions and classes to assist with Advent of Code problems', - long_description=long_description, - long_description_content_type="text/markdown", - packages=find_packages(), - install_requires=[], -) diff --git a/src/template_folder/template.py b/src/template_folder/template.py index 9ef581b2..5ec430dc 100644 --- a/src/template_folder/template.py +++ b/src/template_folder/template.py @@ -11,16 +11,16 @@ """ import logging import time -import aoc_common.aoc_commons as td +import aoc_commons as ac YEAR = 2017 DAY = 1 -locations = td.get_locations(__file__) -logger = td.retrieve_console_logger(locations.script_name) +locations = ac.get_locations(__file__) +logger = ac.retrieve_console_logger(locations.script_name) logger.setLevel(logging.DEBUG) # td.setup_file_logging(logger, locations.output_dir) -td.write_puzzle_input_file(YEAR, DAY, locations) +ac.write_puzzle_input_file(YEAR, DAY, locations) def main(): with open(locations.sample_input_file, mode="rt") as f: diff --git a/src/aoc_commons_package/aoc_common/tests/test_aoc_commons.py b/src/tests/test_aoc_commons.py similarity index 64% rename from src/aoc_commons_package/aoc_common/tests/test_aoc_commons.py rename to src/tests/test_aoc_commons.py index 1fa459c9..53e70cf1 100644 --- a/src/aoc_commons_package/aoc_common/tests/test_aoc_commons.py +++ b/src/tests/test_aoc_commons.py @@ -1,34 +1,28 @@ -""" Testing the type_defs module """ +""" Testing the aoc_commons module """ import unittest from shutil import rmtree from os import path -from aoc_common.aoc_commons import ( - Point, - Grid, - Vectors, - VectorDicts, - write_puzzle_input_file, - binary_search, - merge_intervals, - get_factors, - get_locations, - to_base_n -) + +# py -m pip uninstall dazbo-aoc-commons +# import aoc_common.aoc_commons as ac # for local testing + +# py -m pip install dazbo-aoc-commons +import aoc_commons as ac # for testing using installed pip package class TestTypes(unittest.TestCase): """ Unit tests of various classes in type_defs """ def setUp(self): - self.locations = get_locations(__file__) - self.clear_input_file() + self.locations = ac.get_locations(__file__) + self.clear_input_folder() self.points = set() - self.a_point = Point(5, 5) - self.b_point = Point(1, 2) - self.c_point = Point(6, 7) - self.d_point = Point(4, 3) - self.e_point = Point(3, 6) - self.y_invert_point = Point(0, -1) + self.a_point = ac.Point(5, 5) + self.b_point = ac.Point(1, 2) + self.c_point = ac.Point(6, 7) + self.d_point = ac.Point(4, 3) + self.e_point = ac.Point(3, 6) + self.y_invert_point = ac.Point(0, -1) self.points.add(self.a_point) self.points.add(self.b_point) @@ -38,8 +32,12 @@ def setUp(self): self.a_point_neighbours = self.a_point.neighbours() - def clear_input_file(self): - """ Clear the input file """ + def tearDown(self) -> None: + self.clear_input_folder() + return super().tearDown() + + def clear_input_folder(self): + """ Clear the input folder """ if self.locations.input_dir.exists(): print(f"Deleting {self.locations.input_dir}") rmtree(self.locations.input_dir) @@ -57,44 +55,44 @@ def test_write_puzzle_input_file(self): """ We can create an input folder and input file """ # Try to retrieve input that does not exist - self.assertTrue(write_puzzle_input_file(2010, 1, self.locations)) + self.assertTrue(ac.write_puzzle_input_file(2010, 1, self.locations)) with open(self.locations.input_file, "r") as file: data = file.read() self.assertIn("Failed", data) # Clear the folder and then retrieve legitimate input - self.clear_input_file() - self.assertTrue(write_puzzle_input_file(2015, 1, self.locations)) + self.clear_input_folder() + self.assertTrue(ac.write_puzzle_input_file(2015, 1, self.locations)) with open(self.locations.input_file, "r") as file: data = file.read() self.assertIn("(((())))", data) # Does not retrieve file if it already exists - self.assertFalse(write_puzzle_input_file(2015, 1, self.locations)) + self.assertTrue(ac.write_puzzle_input_file(2015, 1, self.locations)) def test_vectors(self): - self.assertEqual(Vectors.N.value, (0, 1)) - self.assertEqual(Vectors.NW.value, (-1, 1)) - self.assertEqual(Vectors.S.value, (0, -1)) - self.assertEqual(Vectors.E.value, (1, 0)) - self.assertEqual(Vectors.N.y_inverted, (0, -1)) - self.assertEqual(Vectors.SW.value, (-1, -1)) + self.assertEqual(ac.Vectors.N.value, (0, 1)) + self.assertEqual(ac.Vectors.NW.value, (-1, 1)) + self.assertEqual(ac.Vectors.S.value, (0, -1)) + self.assertEqual(ac.Vectors.E.value, (1, 0)) + self.assertEqual(ac.Vectors.N.y_inverted, (0, -1)) + self.assertEqual(ac.Vectors.SW.value, (-1, -1)) def test_vector_dicts(self): - self.assertEqual(VectorDicts.ARROWS[">"], (1, 0)) - self.assertEqual(VectorDicts.ARROWS["v"], (0, -1)) - self.assertEqual(VectorDicts.DIRS["L"], (-1, 0)) - self.assertEqual(VectorDicts.DIRS["U"], (0, 1)) - self.assertEqual(VectorDicts.NINE_BOX["tr"], (1, 1)) - self.assertEqual(VectorDicts.NINE_BOX["bl"], (-1, -1)) + self.assertEqual(ac.VectorDicts.ARROWS[">"], (1, 0)) + self.assertEqual(ac.VectorDicts.ARROWS["v"], (0, -1)) + self.assertEqual(ac.VectorDicts.DIRS["L"], (-1, 0)) + self.assertEqual(ac.VectorDicts.DIRS["U"], (0, 1)) + self.assertEqual(ac.VectorDicts.NINE_BOX["tr"], (1, 1)) + self.assertEqual(ac.VectorDicts.NINE_BOX["bl"], (-1, -1)) def test_point_arithmetic(self): self.assertEqual(self.a_point + self.b_point, self.c_point, "Asserting Point addition") self.assertEqual(self.a_point - self.b_point, self.d_point, "Asserting Point subtraction") - self.assertEqual(self.b_point * Point(3, 3), self.e_point, "Asserting multiplication") + self.assertEqual(self.b_point * ac.Point(3, 3), self.e_point, "Asserting multiplication") def test_manhattan_distance(self): - self.assertEqual(Point.manhattan_distance(self.e_point), 3+6) + self.assertEqual(ac.Point.manhattan_distance(self.e_point), 3+6) self.assertEqual(self.c_point.manhattan_distance_from(self.b_point), abs(self.a_point.x)+abs(self.a_point.y)) def test_point_containers(self): @@ -133,18 +131,18 @@ def test_grid(self): "2176841721"] input_array_data = [[int(posn) for posn in row] for row in input_grid] - grid = Grid(input_array_data) + grid = ac.Grid(input_array_data) self.assertEqual(grid.height, len(input_grid)) self.assertEqual(grid.width, len(input_grid[0])) - self.assertTrue(grid.valid_location(Point(1, 1))) - self.assertFalse(grid.valid_location(Point(11,8))) - self.assertEqual(grid.value_at_point(Point(1, 1)), 7) + self.assertTrue(grid.valid_location(ac.Point(1, 1))) + self.assertFalse(grid.valid_location(ac.Point(11,8))) + self.assertEqual(grid.value_at_point(ac.Point(1, 1)), 7) self.assertEqual(grid.rows_as_str()[0], "5483143223") self.assertEqual(grid.cols_as_str()[0], "5256642") def test_binary_search(self): - self.assertEqual(binary_search(225, 0, 20, lambda x: x**2, reverse_search=True), None) - self.assertEqual(binary_search(225, 0, 20, lambda x: x**2), 15) + self.assertEqual(ac.binary_search(225, 0, 20, lambda x: x**2, reverse_search=True), None) + self.assertEqual(ac.binary_search(225, 0, 20, lambda x: x**2), 15) def test_merge_intervals(self): pairs = [ @@ -157,18 +155,18 @@ def test_merge_intervals(self): expected = [[1, 7], [8, 15], [18, 20]] - self.assertEqual(merge_intervals(pairs), expected) + self.assertEqual(ac.merge_intervals(pairs), expected) def test_get_factors(self): expected = {1, 2, 4, 8} - self.assertEqual(get_factors(8), expected) + self.assertEqual(ac.get_factors(8), expected) def test_to_base_n(self): - self.assertEqual(to_base_n(10, 2), "1010") - self.assertEqual(to_base_n(38, 5), "123") - self.assertEqual(to_base_n(24, 12), "20") - self.assertEqual(to_base_n(0, 12), "0") - self.assertEqual(to_base_n(57, 10), "57") + self.assertEqual(ac.to_base_n(10, 2), "1010") + self.assertEqual(ac.to_base_n(38, 5), "123") + self.assertEqual(ac.to_base_n(24, 12), "20") + self.assertEqual(ac.to_base_n(0, 12), "0") + self.assertEqual(ac.to_base_n(57, 10), "57") if __name__ == "__main__": unittest.main(verbosity=2)