Skip to content

Latest commit

 

History

History
552 lines (499 loc) · 15.5 KB

README.md

File metadata and controls

552 lines (499 loc) · 15.5 KB

Advent Of Code Tools

Collection of tools for solving Advent of Code puzzles in python

Installation

git clone https://github.com/brtwrst/aoc-tools.git

### Install in edit mode so the packet can be updated just by git pulling
cd aoc-tools
pip install -e . --config-settings editable_mode=compat
or
pip install -e . --user --config-settings editable_mode=compat

Template file generation

  • Can be run anywhere once installed with: python -m aoctools.create <year>
  • This will create 25 template files (1 for each day) in a Subfolder for a given year.
  • You will be asked if you want to add optional timing code

Usage example

from aoctools import *
aocd = AOCD(2021, 1)
puzzle_input = aocd.as_str
# calculate the answers
aocd.p1('<answer to part 1>')
aocd.p2('<answer to part 2>')

Detailed usage description

AOCD(year, day)

aocd = AOCD(2021, 1)

This Class will pull your input and submit your solutions.
This will ask you for your AOC session-cookie on the first run. The cookie can be found in the chrome dev tools while you are logged in to adventofcode.com (Application -> Cookies)

Parsing Input

string / number parsing

  • Example Input
    1234
    
  • aocd.as_int parse input as single int
    • aocd.as_int -> 1234
  • aocd.as_str parse input as single str
    • aocd.as_str -> '1234'

List Parsing (split at newline)

  • Example Input
    12
    34
    
  • aocd.ilist parse input as list of int (split at newline)
    • aocd.ilist -> [12, 34]
  • aocd.slist parse input as list of str (split at newline)
    • aocd.slist -> ['12', '34']

List Parsing (split at arbitrary separator)

  • Example Input
    1;2;3;4
    
  • aocd.ilist_split_at(sep) parse input as list of int (split at sep)
    • aocd.ilist_split_at(';') -> [1,2,3,4]
  • aocd.slist_split_at(sep) parse input as list of str (split at sep)
    • aocd.slist_split_at(';') -> ['1','2','3','4']

Multi-List Parsing - Columns

  • Example Input
    1 2
    3 4
    
  • aocd.icolumns parse input columns as multiple lists of int
    • aocd.icolumns -> [[1,3],[2,4]]
  • aocd.scolumns parse input columns as multiple lists of str
    • aocd.scolumns -> [['1','3'],['2','4']]

Multi-List Parsing - Columns (split at arbitrary separator)

  • Example Input
    1,2
    3,4
    
  • aocd.icolumns_split_at(sep=',') parse input columns as multiple lists of int (split at sep)
    • aocd.icolumns -> [[1,3],[2,4]]
  • aocd.scolumns_split_at(sep=',') parse input columns as multiple lists of str (split at sep)
    • aocd.scolumns -> [['1','3'],['2','4']]

Multi-List Parsing - Rows

  • Example Input
    1 2
    3 4
    
  • aocd.irows parse input rows as multiple lists of int
    • aocd.irows -> [[1,2],[3,4]]
  • aocd.srows parse input rows as multiple lists of str
    • aocd.srows -> [['1','2'],['3','4']]

Multi-List Parsing - Rows (split at arbitrary separator)

  • Example Input
    1,2
    3,4
    
  • aocd.irows_split_at(sep=',') parse input rows as multiple lists of int (split at sep)
    • aocd.irows -> [[1,2],[3,4]]
  • aocd.srows_split_at(sep=',') parse input rows as multiple lists of str (split at sep)
    • aocd.srows -> [['1','2'],['3','4']]

Set Parsing (split at newline)

  • Example Input
    12
    34
    
  • aocd.iset parse input as set of int
    • aocd.iset -> {12, 34}
  • aocd.sset parse input as set of str
    • aocd.sset -> {'12', '34'}

Set Parsing (split at arbitrary separator)

  • Example Input
    1;2;3;4;4
    
  • aocd.ilist_split_at(sep) parse input as list of int (split at sep)
    • aocd.iset_split_at(';') -> {1,2,3,4}
  • aocd.slist_split_at(sep) parse input as list of str (split at sep)
    • aocd.sset_split_at(';') -> {'1','2','3','4'}]

Grid Parsing (when input is formatted as a grid of single digits/characters)

  • Example Input
    12
    34
    
  • aocd.igrid parse input as a grid of single digit numbers (split input at newline)
    • aocd.igrid ->
      {
          (0,0) : 1, 
          (1,0) : 2, 
          (0,1) : 3, 
          (1,1) : 4, 
      }
  • aocd.sgrid parse input as a grid of single characters (split input at newline)
    • aocd.sgrid ->
      {
          (0,0) : '1', 
          (1,0) : '2', 
          (0,1) : '3', 
          (1,1) : '4', 
      }

Grid Parsing with Vectors as "coordinates"

  • aocd.vigrid parse input as a grid of single digit numbers (split input at newline)

    • aocd.igrid ->
      {
          Vec(0,0) : 1, 
          Vec(1,0) : 2, 
          Vec(0,1) : 3, 
          Vec(1,1) : 4, 
      }
  • aocd.vsgrid parse input as a grid of single characters (split input at newline)

    • aocd.sgrid ->
      {
          Vec(0,0) : '1', 
          Vec(1,0) : '2', 
          Vec(0,1) : '3', 
          Vec(1,1) : '4', 
      }
  • aocd.mgrid(mapping, vectors=False) parse input as a grid of single characters but map them to a new value in the dict

    • aocd.mgrid(mapping={'1': 'FOO', '2':'BAR'}) ->
      {
          (0,0) : 'FOO', 
          (1,0) : 'BAR', 
          (0,1) : '3', 
          (1,1) : '4', 
      }

Grid Parsing (when input is formatted as a grid of separated values on each line)

You can set vectors=True to get the keys() as Vectors

  • Example Input
    1,2
    3,4
    
  • aocd.igrid_split_at(sep, vectors=False) parse input as a grid of integers (split input at newline) (split line at sep)
    • aocd.igrid_split_at(',') ->
      {
          (0,0) : 1, 
          (1,0) : 2, 
          (0,1) : 3, 
          (1,1) : 4, 
      }
  • aocd.sgrid_split_at(sep, vectors=False) parse input as a grid of strings (split input at newline) (split line at sep)
    • aocd.sgrid_split_at(',') ->
      {
          (0,0) : '1', 
          (1,0) : '2', 
          (0,1) : '3', 
          (1,1) : '4', 
      }
  • aocd.mgrid_split_at(mapping, sep, vectors=False) parse input as a grid of single characters but map them to a new value in the dict
    • aocd.mgrid(mapping={'1': 'FOO', '2':'BAR'}, sep=',') ->
      {
          (0,0) : 'FOO', 
          (1,0) : 'BAR', 
          (0,1) : '3', 
          (1,1) : '4', 
      }

Key-Value Parsing (when input is formatted as lines of key value pairs)

  • Example Input
    ab-cd
    de-fg
    
  • aocd.key_value_split_at(sep, keytype=str, valuetype=str) parse input as lines of key-value pairs with specific types (default str)
    • aocd.dict_split_at('-') ->
      {
          'ab': 'cd', 
          'de': 'fg'
      }

Literal Parsing (when input is formatted as a valid python object (list, set, dict))

  • Example Input
    {
        a:1,
        b:2
    }
    
  • aocd.literal parse input as python object
    • aocd.literal ->
      {
          a:1,
          b:2
      }

Literal List Parsing (when input is formatted as lines of valid python objects(lists, sets, dicts))

  • Example Input
    [1,2]
    [3,4]
    
  • aocd.literal_list parse input as lines of python objects
    • aocd.literal_list ->
      [
          [1,2],
          [3,4]
      ]

Submitting Output

You can use the tool to submit your answer to adventofcode.com The tool will inform you if the answer was wrong and it will cache all submitted answers so you don't submit the same wrong result twice.

  • aocd.p1(answer) submit answer for part 1
  • aocd.p2(answer) submit answer for part 2

Use example or custom input

The tool allows you to use arbitrary input for a Puzzle. This can be used to test with example input or to run your code with different input.
While you are in "example mode" and use aocd.p1() or aocd.p2(), the answer will only be displayed and not submitted to the website. So in order to submit your answer, you have to comment out the set_example() or get_example()

Auto download the example input

Use aocd.get_example() to attempt to download the example for the day from the adventofcode.com automatically.

Using arbitrary example input

Give the input verbatim as multiline string to aocd.set_example(<input>) before parsing. The following example uses the input of https://adventofcode.com/2021/day/3

aocd = AOCD(2021, 3)
aocd.set_example("""00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010""")

Tools

Some tool functions/classes that help with programming puzzles.

Fast primality checks

  • miller_rabin(n) only works up to about 10**23
  • miller_rabin2(n) works for big primes but is probability based
  • Both will return True if the given number n is prime and False if it is not

Matrix manipulation functions

  • matrix_transpose will transpose a 2D matrix, the result will be a list of tuples.
  • matrix_transpose_lists will transpose a 2D matrix, the result will be a list of lists.
  • matrix_transpose_strings will transpose a 2D matrix, the result will be a list of strings.
  • matrix_transpose_dicts will transpose a 2D matrix, the result will be a list of dicts.
  • matrix_rotate will rotate a 2D matrix clockwise 90 degrees, the result will be a list of tuples.
  • matrix_rotate_lists will rotate a 2D matrix clockwise 90 degrees, the result will be a list of lists.
  • matrix_rotate_strings will rotate a 2D matrix clockwise 90 degrees, the result will be a list of strings.
  • matrix_rotate_dicts will rotate a 2D matrix clockwise 90 degrees, the result will be a list of dicts.
# consider the following 2D matrix
matrix = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

transposed_matrix = matrix_transpose(matrix)

# result
'''
transposed_matrix = [
    (1,4,7),
    (2,5,8),
    (3,6,9)
]
'''

transposed_matrix_lists = matrix_transpose_lists(matrix)

# result
'''
transposed_matrix_lists = [
    [1,4,7],
    [2,5,8],
    [3,6,9]
]
'''

# consider the following 2D matrix - strings are iterables too
matrix = [
    '123',
    '456',
    '789'
]

transposed_matrix_strings = matrix_transpose_strings(matrix)

# result
'''
transposed_matrix_strings = [
    '147',
    '258',
    '369'
]
'''

# consider the following 2D matrix
matrix = [
    {'A': 1, 'B': 2, 'C': 3},
    {'D': 4, 'E': 5, 'F': 6},
    {'G': 7, 'H': 8, 'I': 9}
]

transposed_matrix_dicts = matrix_transpose_dicts(matrix)

# result
'''
transposed_matrix_dicts = [
    {'A': 1, 'D': 4, 'G': 7},
    {'B': 2, 'E': 5, 'H': 8},
    {'C': 3, 'F': 6, 'I': 9}
]
'''

# consider the following 2D matrix
matrix = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

rotated_matrix = matrix_rotate(matrix)

# result
'''
rotated_matrix = [
    (7,4,1),
    (8,5,2),
    (9,6,3)
]
'''

rotated_matrix_lists = matrix_rotate_lists(matrix)

# result
'''
rotated_matrix_lists = [
    [7,4,1],
    [8,5,2],
    [9,6,3]
]
'''

# consider the following 2D matrix - strings are iterables too
matrix = [
    '123',
    '456',
    '789'
]

rotated_matrix_strings = matrix_rotate_strings(matrix)

# result
'''
rotated_matrix_strings = [
    '741',
    '852',
    '963'
]
'''

# consider the following 2D matrix
matrix = [
    {'A': 1, 'B': 2, 'C': 3},
    {'D': 4, 'E': 5, 'F': 6},
    {'G': 7, 'H': 8, 'I': 9}
]

rotated_matrix_dicts = matrix_rotate_dicts(matrix)

# result
'''
rotated_matrix_dicts = [
    {'G': 7, 'D': 4, 'A': 1},
    {'H': 8, 'E': 5, 'B': 2},
    {'I': 9, 'F': 6, 'C': 3}
]
'''

Simple vector

v = Vec(1,2,3)
  • This is a simple implementation of a vector.
  • Objects of this class are hashable (can be used as dict keys)
  • Vectors can be any length/dimension Vec(1,2) / Vec(1,2,3,4,5) although only vectors of the same dimension can be added/multiplied

Supported operations

  • Dimension/Length len(Vec(1,2,3))
  • Addition Vec(1,2,3) + Vec(1,2,3)
  • Subtraction Vec(1,2,3) - Vec(1,2,3)
  • Vector Multiplication Vec(1,2,3) * Vec(2,3,4)
  • Scalar Multiplication Vec(1,2,3) * 2
  • Scalar Division/Floor Division Vec(1,2,3) / 2 Vec(1,2,3) // 2
  • Cross Product Vec(1,2,3) @ Vec(1,1,1) or Vec(1,2,3).cross_product(Vec(1,1,1))
  • Modulo each element Vec(1,2,3) % 2
  • Exponentiate each element Vec(1,2,3) ** 2
  • Left-Shift each element Vec(1,2,3) << 2
  • Right-Shift each element Vec(1,2,3) >> 2
  • Bitwise-And each element Vec(1,2,3) & 2
  • Bitwise-XOr each element Vec(1,2,3) ^ 2
  • Bitwise-Or each element Vec(1,2,3) | 2
  • Comparison < > == != <= >=
  • Length/Absolute abs(Vec(1,2,3)) (will give the vector magnitude)
  • element access Vec(1,2,3)[0] (also assignment Vec(1,2,3)[2] = 2)
  • count occurances of specific element Vec(1,2,3).count(0) (Number of 0s in the vector)
  • Rotate vector by a Matrix (Matrix is a list of Vec, each Vec represents one row of the matrix) Vec(1,2,3).rotate_with_matrix([Vec(0,1,0),Vec(0,0,1),Vec(1,0,0)])