Update config & checks

This commit is contained in:
Gabriel Augendre 2022-12-02 13:35:44 +01:00
parent bebb4de924
commit a1782c4cae
78 changed files with 205 additions and 163 deletions

View file

@ -3,24 +3,43 @@ repos:
rev: v4.4.0 rev: v4.4.0
hooks: hooks:
- id: check-ast - id: check-ast
types: [python] - id: check-json
- id: check-toml - id: check-toml
types: [toml] - id: check-xml
- id: check-yaml - id: check-yaml
types: [yaml]
- id: end-of-file-fixer - id: end-of-file-fixer
types: [python]
- id: check-merge-conflict - id: check-merge-conflict
- id: pretty-format-json
args:
- --autofix
- --no-sort-keys
- id: trailing-whitespace - id: trailing-whitespace
args: args:
- --markdown-linebreak-ext=md - --markdown-linebreak-ext=md
- repo: https://github.com/timothycrosley/isort - repo: https://github.com/asottile/pyupgrade
rev: v3.2.2
hooks:
- id: pyupgrade
args: [--py311-plus]
- repo: https://github.com/PyCQA/isort
rev: 5.10.1 rev: 5.10.1
hooks: hooks:
- id: isort - id: isort
types: [python] args: [--profile, black]
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.10.0 rev: 22.10.0
hooks: hooks:
- id: black - id: black
types: [python] args: [--target-version, py310]
- repo: https://github.com/flakeheaven/flakeheaven
rev: 3.2.1
hooks:
- id: flakeheaven
additional_dependencies:
- flake8-annotations-complexity
- flake8-bandit
- flake8-builtins
- flake8-bugbear
- flake8-comprehensions
- flake8-noqa
- pep8-naming

View file

@ -1,5 +1,5 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, List from typing import Dict
@dataclass @dataclass
@ -21,7 +21,7 @@ class Node:
chain.append(current) chain.append(current)
return chain return chain
def common_chain(self, other: "Node") -> List["Node"]: def common_chain(self, other: "Node") -> list["Node"]:
chain = [] chain = []
for el1, el2 in zip(reversed(self.chain()), reversed(other.chain())): for el1, el2 in zip(reversed(self.chain()), reversed(other.chain())):
if el1 != el2: if el1 != el2:

View file

@ -1,5 +1,5 @@
import itertools import itertools
from typing import List, Union from typing import List
NUMBER_OF_PARAMS_MAP = { NUMBER_OF_PARAMS_MAP = {
1: 3, 1: 3,
@ -54,13 +54,13 @@ class Computer:
self.pointer += offset self.pointer += offset
self.pointer_moved = False self.pointer_moved = False
def __init__(self, initial_program: List[int], inputs: List[int] = None): def __init__(self, initial_program: list[int], inputs: list[int] = None):
self.program = initial_program.copy() # type: List[int] self.program = initial_program.copy() # type: List[int]
self.inputs = inputs.copy() # type: List[int] self.inputs = inputs.copy() # type: List[int]
self.pointer = 0 self.pointer = 0
self.pointer_moved = False self.pointer_moved = False
def compute(self, additional_inputs: List[int] = None) -> int: def compute(self, additional_inputs: list[int] = None) -> int:
if additional_inputs is None: if additional_inputs is None:
additional_inputs = [] additional_inputs = []
self.inputs.extend(additional_inputs) self.inputs.extend(additional_inputs)

View file

@ -1,5 +1,3 @@
from typing import List
WIDTH = 25 WIDTH = 25
HEIGHT = 6 HEIGHT = 6
LAYER_SIZE = WIDTH * HEIGHT LAYER_SIZE = WIDTH * HEIGHT
@ -9,7 +7,7 @@ BLACK = "0"
TRANSPARENT = "2" TRANSPARENT = "2"
def find_pixel(layers: List[str], index: int) -> str: def find_pixel(layers: list[str], index: int) -> str:
for layer in layers: for layer in layers:
pixel = layer[index] pixel = layer[index]
if pixel in [WHITE, BLACK]: if pixel in [WHITE, BLACK]:

View file

@ -1,6 +1,5 @@
import itertools
from collections import defaultdict from collections import defaultdict
from typing import List, Union from typing import List
RELATIVE_MODE = 2 RELATIVE_MODE = 2
POSITION_MODE = 0 POSITION_MODE = 0
@ -36,7 +35,7 @@ class IntcodeOutput(Exception):
class Computer: class Computer:
def __init__(self, initial_program: List[int], inputs: List[int] = None): def __init__(self, initial_program: list[int], inputs: list[int] = None):
self.program = defaultdict(int, enumerate(initial_program)) self.program = defaultdict(int, enumerate(initial_program))
if inputs is None: if inputs is None:
inputs = [] inputs = []
@ -75,7 +74,7 @@ class Computer:
self.pointer += offset self.pointer += offset
self.pointer_moved = False self.pointer_moved = False
def compute(self, additional_inputs: List[int] = None) -> int: def compute(self, additional_inputs: list[int] = None) -> int:
if additional_inputs is None: if additional_inputs is None:
additional_inputs = [] additional_inputs = []
self.inputs.extend(additional_inputs) self.inputs.extend(additional_inputs)

View file

@ -1,5 +1,4 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Set, Tuple
@dataclass @dataclass
@ -41,7 +40,7 @@ class Asteroid:
return True return True
def can_see(self, other: "Asteroid", asteroids: Set["Asteroid"]) -> bool: def can_see(self, other: "Asteroid", asteroids: set["Asteroid"]) -> bool:
for asteroid in asteroids: for asteroid in asteroids:
if asteroid in [self, other]: if asteroid in [self, other]:
continue continue

View file

@ -1,5 +1,4 @@
from collections import Counter from collections import Counter
from typing import Tuple
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -20,7 +19,7 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert counter_part_2 == expected_part_2 assert counter_part_2 == expected_part_2
def extract_password_and_policy(line) -> Tuple[Tuple[int, int], str, str]: def extract_password_and_policy(line) -> tuple[tuple[int, int], str, str]:
policy, password = line.strip().split(": ") policy, password = line.strip().split(": ")
range_, letter = policy.split(" ") range_, letter = policy.split(" ")
range_ = range_.split("-") range_ = range_.split("-")
@ -28,12 +27,12 @@ def extract_password_and_policy(line) -> Tuple[Tuple[int, int], str, str]:
return range_, letter, password return range_, letter, password
def is_valid_part_1(range_: Tuple[int, int], letter: str, password: str): def is_valid_part_1(range_: tuple[int, int], letter: str, password: str):
counter = Counter(password) counter = Counter(password)
return range_[0] <= counter[letter] <= range_[1] return range_[0] <= counter[letter] <= range_[1]
def is_valid_part_2(range_: Tuple[int, int], letter: str, password: str): def is_valid_part_2(range_: tuple[int, int], letter: str, password: str):
first_index = password[range_[0] - 1] first_index = password[range_[0] - 1]
second_index = password[range_[1] - 1] second_index = password[range_[1] - 1]
return first_index != second_index and ( return first_index != second_index and (

View file

@ -28,7 +28,7 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert prod_trees == expected_part_2 assert prod_trees == expected_part_2
def trees_for_slope(forest: List[str], right: int, down: int) -> int: def trees_for_slope(forest: list[str], right: int, down: int) -> int:
trees = 0 trees = 0
current_line = 0 current_line = 0
current_col = 0 current_col = 0

View file

@ -1,6 +1,6 @@
import functools import functools
import itertools import itertools
from typing import List, Tuple from typing import List
import networkx as nx import networkx as nx
@ -39,13 +39,13 @@ def count_diffs(jolts):
return diffs return diffs
def solve_part_2(jolts: List[int]): def solve_part_2(jolts: list[int]):
jolts = tuple(jolts) jolts = tuple(jolts)
return with_recursion(jolts, jolts[-1]) return with_recursion(jolts, jolts[-1])
@functools.lru_cache(maxsize=None) @functools.cache
def with_recursion(jolts: Tuple[int], target: int): def with_recursion(jolts: tuple[int], target: int):
if target == 0: if target == 0:
return 1 return 1
counter = 0 counter = 0

View file

@ -1,6 +1,6 @@
import functools import functools
from collections import Counter from collections import Counter
from typing import List, Tuple, Dict, Optional from typing import Dict
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -25,7 +25,7 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == counter_part_2 assert expected_part_2 == counter_part_2
Coordinates = Tuple[int, int] Coordinates = tuple[int, int]
class SeatMap: class SeatMap:
@ -90,7 +90,7 @@ class SeatMap:
count_occupied += 1 count_occupied += 1
return count_occupied return count_occupied
def _visible_seats(self, coordinates: Coordinates) -> List[str]: def _visible_seats(self, coordinates: Coordinates) -> list[str]:
adjacent_cells = [ adjacent_cells = [
self._find_top_left(coordinates), self._find_top_left(coordinates),
self._find_top(coordinates), self._find_top(coordinates),
@ -105,13 +105,13 @@ class SeatMap:
return list(map(self._square_at, filter(None, adjacent_cells))) return list(map(self._square_at, filter(None, adjacent_cells)))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_top_left(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_top_left(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (-1, -1)) return self._find_with_delta(coordinates, (-1, -1))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_with_delta( def _find_with_delta(
self, coordinates: Coordinates, delta: Tuple[int, int] self, coordinates: Coordinates, delta: tuple[int, int]
) -> Optional[Coordinates]: ) -> Coordinates | None:
other_coord = (coordinates[0] + delta[0], coordinates[1] + delta[1]) other_coord = (coordinates[0] + delta[0], coordinates[1] + delta[1])
try: try:
self._square_at(other_coord) self._square_at(other_coord)
@ -120,31 +120,31 @@ class SeatMap:
return other_coord return other_coord
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_top(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_top(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (-1, 0)) return self._find_with_delta(coordinates, (-1, 0))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_top_right(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_top_right(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (-1, 1)) return self._find_with_delta(coordinates, (-1, 1))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_right(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_right(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (0, 1)) return self._find_with_delta(coordinates, (0, 1))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_bottom_right(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_bottom_right(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (1, 1)) return self._find_with_delta(coordinates, (1, 1))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_bottom(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_bottom(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (1, 0)) return self._find_with_delta(coordinates, (1, 0))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_bottom_left(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_bottom_left(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (1, -1)) return self._find_with_delta(coordinates, (1, -1))
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_left(self, coordinates: Coordinates) -> Optional[Coordinates]: def _find_left(self, coordinates: Coordinates) -> Coordinates | None:
return self._find_with_delta(coordinates, (0, -1)) return self._find_with_delta(coordinates, (0, -1))
@ -153,8 +153,8 @@ class SeatMapPart2(SeatMap):
@functools.lru_cache(None) @functools.lru_cache(None)
def _find_with_delta( def _find_with_delta(
self, coordinates: Coordinates, delta: Tuple[int, int] self, coordinates: Coordinates, delta: tuple[int, int]
) -> Optional[Coordinates]: ) -> Coordinates | None:
other_coord = (coordinates[0] + delta[0], coordinates[1] + delta[1]) other_coord = (coordinates[0] + delta[0], coordinates[1] + delta[1])
try: try:
other_square = self._square_at(other_coord) other_square = self._square_at(other_coord)

View file

@ -1,6 +1,5 @@
import enum import enum
import functools import functools
from typing import List
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -20,13 +19,13 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == counter_part_2 assert expected_part_2 == counter_part_2
def solve_part_1(instructions: List[str]): def solve_part_1(instructions: list[str]):
ship = ShipPart1() ship = ShipPart1()
ship.apply_instructions(instructions) ship.apply_instructions(instructions)
return ship.distance_from_origin return ship.distance_from_origin
def solve_part_2(instructions: List[str]): def solve_part_2(instructions: list[str]):
ship = ShipPart2() ship = ShipPart2()
ship.apply_instructions(instructions) ship.apply_instructions(instructions)
return ship.distance_from_origin return ship.distance_from_origin

View file

@ -1,7 +1,6 @@
import enum
import functools import functools
import math import math
from typing import List, Dict from typing import Dict
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):

View file

@ -1,6 +1,7 @@
import functools import functools
import re import re
from typing import List, Dict, Iterable, Union from collections.abc import Iterable
from typing import Union
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -24,7 +25,7 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == counter_part_2 assert expected_part_2 == counter_part_2
Memory = Dict[Union[str, int], Union[str, int]] Memory = dict[Union[str, int], Union[str, int]]
class Program: class Program:
@ -72,7 +73,7 @@ class ProgramPart1(Program):
self.memory[address] = self.get_masked_value(value) self.memory[address] = self.get_masked_value(value)
def get_masked_value(self, value: int) -> str: def get_masked_value(self, value: int) -> str:
binary_value = "{:036b}".format(value) binary_value = f"{value:036b}"
masked_value = [] masked_value = []
for binary_bit, mask_bit in zip(binary_value, self.mask): for binary_bit, mask_bit in zip(binary_value, self.mask):
if mask_bit == "X": if mask_bit == "X":
@ -102,7 +103,7 @@ class ProgramPart2(Program):
self.memory[masked_address] = value self.memory[masked_address] = value
def get_masked_addresses(self, address: int) -> Iterable[int]: def get_masked_addresses(self, address: int) -> Iterable[int]:
binary_address = "{:036b}".format(address) binary_address = f"{address:036b}"
corrected_binary_address = "" corrected_binary_address = ""
for binary_bit, mask_bit in zip(binary_address, self.mask): for binary_bit, mask_bit in zip(binary_address, self.mask):
if mask_bit == "1": if mask_bit == "1":
@ -113,7 +114,7 @@ class ProgramPart2(Program):
int_base_2 = functools.partial(int, base=2) int_base_2 = functools.partial(int, base=2)
return map(int_base_2, addresses) return map(int_base_2, addresses)
def get_floating_addresses(self, prefix: str, address: str, mask: str) -> List[str]: def get_floating_addresses(self, prefix: str, address: str, mask: str) -> list[str]:
if "X" not in mask: if "X" not in mask:
return [prefix + address] return [prefix + address]
first_x = mask.index("X") first_x = mask.index("X")

View file

@ -1,6 +1,4 @@
import functools from typing import Union
import re
from typing import Dict, Iterable, List, Tuple, Union
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -20,8 +18,8 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == counter_part_2 assert expected_part_2 == counter_part_2
SeenTuple = Union[Tuple[int], Tuple[int, int]] SeenTuple = Union[tuple[int], tuple[int, int]]
Seen = Dict[int, SeenTuple] Seen = dict[int, SeenTuple]
def solve_part_1(starting_numbers): def solve_part_1(starting_numbers):

View file

@ -1,6 +1,6 @@
import re import re
from collections import defaultdict from collections import defaultdict
from typing import Iterable, List, Tuple from collections.abc import Iterable
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -22,8 +22,8 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == counter_part_2 assert expected_part_2 == counter_part_2
Range = Tuple[int, int] Range = tuple[int, int]
Ranges = List[Range] Ranges = list[Range]
class TicketAnalyserPart1: class TicketAnalyserPart1:
@ -40,7 +40,7 @@ class TicketAnalyserPart1:
self.valid_tickets = [] self.valid_tickets = []
@staticmethod @staticmethod
def extract_ranges(named_range: str) -> Tuple[str, Ranges]: def extract_ranges(named_range: str) -> tuple[str, Ranges]:
name, ranges = named_range.split(": ") name, ranges = named_range.split(": ")
reg = re.compile(r"(\d+)-(\d+) or (\d+)-(\d+)$") reg = re.compile(r"(\d+)-(\d+) or (\d+)-(\d+)$")
matches = reg.match(ranges) matches = reg.match(ranges)
@ -57,7 +57,7 @@ class TicketAnalyserPart1:
self.valid_tickets.append(ticket) self.valid_tickets.append(ticket)
return error_rate return error_rate
def get_invalid_values(self, ticket: List[int]) -> List[int]: def get_invalid_values(self, ticket: list[int]) -> list[int]:
invalid_values = [] invalid_values = []
for value in ticket: for value in ticket:
if self.value_is_invalid(value): if self.value_is_invalid(value):
@ -77,8 +77,7 @@ class TicketAnalyserPart1:
def iter_ranges(self) -> Iterable[Range]: def iter_ranges(self) -> Iterable[Range]:
for ranges in self.ranges.values(): for ranges in self.ranges.values():
for rng in ranges: yield from ranges
yield rng
def compute_class_assignation(self): def compute_class_assignation(self):
possible_columns_for_range = defaultdict(list) possible_columns_for_range = defaultdict(list)

View file

@ -998,4 +998,3 @@
95914697526990 95914697526990
99484174471360 99484174471360
100861876842026 100861876842026

View file

@ -1,5 +1,4 @@
import pytest import pytest
from day11_seating import SeatMap from day11_seating import SeatMap

View file

@ -1,5 +1,4 @@
import pytest import pytest
from day14_docking import ProgramPart2 from day14_docking import ProgramPart2

View file

@ -1,4 +1,3 @@
let total = 0; let total = 0;
$("pre").innerText.trim().split("\n").map(el => Number(el)).map((el, index, array) => el + array[index+1] + array[index+2]).reduce((prev, current) => {if (prev < current) {total += 1} return current}); $("pre").innerText.trim().split("\n").map(el => Number(el)).map((el, index, array) => el + array[index+1] + array[index+2]).reduce((prev, current) => {if (prev < current) {total += 1} return current});
console.log(total); console.log(total);

View file

@ -1,8 +1,8 @@
import itertools import itertools
from typing import List, Set, TypeAlias from typing import TypeAlias
Numbers: TypeAlias = List[int] Numbers: TypeAlias = list[int]
Grid: TypeAlias = List[Numbers] Grid: TypeAlias = list[Numbers]
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -23,10 +23,10 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == solution_part_2 assert expected_part_2 == solution_part_2
def parse_data(data: List[str]) -> (Numbers, List[Grid]): def parse_data(data: list[str]) -> (Numbers, list[Grid]):
numbers: Numbers = list(map(int, data[0].split(","))) numbers: Numbers = list(map(int, data[0].split(",")))
data = data[1:] data = data[1:]
grids: List[Grid] = [] grids: list[Grid] = []
for grid in data: for grid in data:
parsed_grid: Grid = [] parsed_grid: Grid = []
grid_lines = grid.split("\n") grid_lines = grid.split("\n")
@ -37,8 +37,8 @@ def parse_data(data: List[str]) -> (Numbers, List[Grid]):
return numbers, grids return numbers, grids
def solve_part_1(numbers: Numbers, grids: List[Grid]) -> int: def solve_part_1(numbers: Numbers, grids: list[Grid]) -> int:
seen: Set[int] = set() seen: set[int] = set()
for number in numbers: for number in numbers:
seen.add(number) seen.add(number)
for grid in grids: for grid in grids:
@ -46,18 +46,18 @@ def solve_part_1(numbers: Numbers, grids: List[Grid]) -> int:
return sum(unseen(grid, seen)) * number return sum(unseen(grid, seen)) * number
def check_bingo(grid: Grid, seen: Set[int]) -> bool: def check_bingo(grid: Grid, seen: set[int]) -> bool:
return check_row(grid, seen) or check_column(grid, seen) return check_row(grid, seen) or check_column(grid, seen)
def check_row(grid: Grid, seen: Set[int]) -> bool: def check_row(grid: Grid, seen: set[int]) -> bool:
for row in grid: for row in grid:
if check_line(row, seen): if check_line(row, seen):
return True return True
return False return False
def check_column(grid: Grid, seen: Set[int]) -> bool: def check_column(grid: Grid, seen: set[int]) -> bool:
for i in range(len(grid[0])): for i in range(len(grid[0])):
column = [row[i] for row in grid] column = [row[i] for row in grid]
if check_line(column, seen): if check_line(column, seen):
@ -65,21 +65,21 @@ def check_column(grid: Grid, seen: Set[int]) -> bool:
return False return False
def check_line(line: Numbers, seen: Set[int]) -> bool: def check_line(line: Numbers, seen: set[int]) -> bool:
for number in line: for number in line:
if number not in seen: if number not in seen:
return False return False
return True return True
def unseen(grid: Grid, seen: Set[int]) -> Numbers: def unseen(grid: Grid, seen: set[int]) -> Numbers:
return [n for n in itertools.chain.from_iterable(grid) if n not in seen] return [n for n in itertools.chain.from_iterable(grid) if n not in seen]
def solve_part_2(numbers: Numbers, grids: List[Grid]) -> int: def solve_part_2(numbers: Numbers, grids: list[Grid]) -> int:
seen: Set[int] = set() seen: set[int] = set()
score = 0 score = 0
winners: Set[int] = set() winners: set[int] = set()
for number in numbers: for number in numbers:
seen.add(number) seen.add(number)
for index, grid in enumerate(grids): for index, grid in enumerate(grids):

View file

@ -1,5 +1,4 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import List, Set
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -37,7 +36,7 @@ class Segment:
def is_vertical(self): def is_vertical(self):
return self.start.x == self.end.x return self.start.x == self.end.x
def get_points_part_1(self) -> Set[Point]: def get_points_part_1(self) -> set[Point]:
if self.is_horizontal(): if self.is_horizontal():
start = min(self.start.x, self.end.x) start = min(self.start.x, self.end.x)
end = max(self.start.x, self.end.x) end = max(self.start.x, self.end.x)
@ -48,7 +47,7 @@ class Segment:
return {Point(self.start.x, y) for y in range(start, end + 1)} return {Point(self.start.x, y) for y in range(start, end + 1)}
return set() return set()
def get_points_part_2(self) -> Set[Point]: def get_points_part_2(self) -> set[Point]:
part_1 = self.get_points_part_1() part_1 = self.get_points_part_1()
if part_1: if part_1:
return part_1 return part_1
@ -71,7 +70,7 @@ class Segment:
return points return points
def parse_data(data: List[str]) -> List[Segment]: def parse_data(data: list[str]) -> list[Segment]:
segments = [] segments = []
for line in data: for line in data:
start, end = line.split(" -> ") start, end = line.split(" -> ")
@ -84,7 +83,7 @@ def parse_data(data: List[str]) -> List[Segment]:
return segments return segments
def solve_part_1(data: List[Segment]) -> int: def solve_part_1(data: list[Segment]) -> int:
seen_points = set() seen_points = set()
multiple_times = set() multiple_times = set()
for segment in data: for segment in data:
@ -95,7 +94,7 @@ def solve_part_1(data: List[Segment]) -> int:
return len(multiple_times) return len(multiple_times)
def solve_part_2(data: List[Segment]) -> int: def solve_part_2(data: list[Segment]) -> int:
seen_points = set() seen_points = set()
multiple_times = set() multiple_times = set()
for segment in data: for segment in data:

View file

@ -1,6 +1,4 @@
from collections import defaultdict from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Dict, Iterator, List
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -21,7 +19,7 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == solution_part_2 assert expected_part_2 == solution_part_2
def parse_data(data: List[str]) -> Dict[int, int]: def parse_data(data: list[str]) -> dict[int, int]:
dct = defaultdict(int) dct = defaultdict(int)
for x in map(int, data[0].split(",")): for x in map(int, data[0].split(",")):
dct[x] += 1 dct[x] += 1
@ -34,7 +32,7 @@ def solve_part_1(data) -> int:
return sum(data.values()) return sum(data.values())
def _run_day(data: Dict[int, int]) -> Dict[int, int]: def _run_day(data: dict[int, int]) -> dict[int, int]:
new_data = defaultdict(int) new_data = defaultdict(int)
for k, v in data.items(): for k, v in data.items():
if k == 0: if k == 0:

View file

@ -1,6 +1,5 @@
import math import math
import statistics import statistics
from typing import List
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
@ -21,11 +20,11 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == solution_part_2 assert expected_part_2 == solution_part_2
def parse_data(data: List[str]) -> List[int]: def parse_data(data: list[str]) -> list[int]:
return list(map(int, data[0].split(","))) return list(map(int, data[0].split(",")))
def solve_part_1(data: List[int]) -> int: def solve_part_1(data: list[int]) -> int:
target_position = int(statistics.median(data)) target_position = int(statistics.median(data))
fuel_cost = 0 fuel_cost = 0
for crab in data: for crab in data:
@ -33,7 +32,7 @@ def solve_part_1(data: List[int]) -> int:
return fuel_cost return fuel_cost
def solve_part_2(data: List[int]) -> int: def solve_part_2(data: list[int]) -> int:
target_position_1 = math.floor(statistics.mean(data)) target_position_1 = math.floor(statistics.mean(data))
target_position_2 = math.ceil(statistics.mean(data)) target_position_2 = math.ceil(statistics.mean(data))
return min( return min(
@ -44,7 +43,7 @@ def solve_part_2(data: List[int]) -> int:
) )
def compute_part_2(data: List[int], target_position: int) -> int: def compute_part_2(data: list[int], target_position: int) -> int:
fuel_cost = 0 fuel_cost = 0
for index, crab in enumerate(data): for index, crab in enumerate(data):
fuel_for_crab = sum([i for i in range(abs(crab - target_position) + 1)]) fuel_for_crab = sum([i for i in range(abs(crab - target_position) + 1)])

View file

@ -1,6 +1,3 @@
from typing import List
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
print(f"\n+ Running on {filename}") print(f"\n+ Running on {filename}")
with open(filename) as f: with open(filename) as f:
@ -19,7 +16,7 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
assert expected_part_2 == solution_part_2 assert expected_part_2 == solution_part_2
def parse_data(data: List[str]): def parse_data(data: list[str]):
return data return data

View file

@ -22,4 +22,3 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org> For more information, please refer to <https://unlicense.org>

23
baseline.txt Normal file
View file

@ -0,0 +1,23 @@
192ba80a7bf992445f8320737416cfd1
ea9c1c33a5879bb5c437218a0eb0ec99
12f99f3b98ebc4e1225798400e307f47
5f3b0f184c3e7cacd25d4bf3f9fc0e62
408296793fc6e98b5959c0c17510e584
10fb4c63998a627df816295f2507f786
2ec39e0044b1212025f7a7bcf047fd4f
38579bf5ef8a53dd86b290137e90ef07
02f5c14b08c62eb4bb9d39ae1f99dbf8
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
81a486b330b1a68b74c12c897d258930
78f847458ed2bbf800bc9b0a87d24b83
505c155f15a5f931779aebcc8defa624
fe797f6243a22a070cdbcc2bc60519df
4c869a5cb1ed32f419a0f8677798d1b4

View file

@ -3,7 +3,7 @@ name = "advent-of-code"
version = "0.1.0" version = "0.1.0"
description = "" description = ""
authors = ["Gabriel Augendre <gabriel@augendre.info>"] authors = ["Gabriel Augendre <gabriel@augendre.info>"]
license = "MIT" license = "Unlicense"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = "^3.10"
@ -18,8 +18,29 @@ pytest = ">=6.1.2"
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.black]
target-version = ['py38']
[tool.isort] ###############################################################################
profile = "black" # flake8 / flakeheaven
###############################################################################
[tool.flakeheaven]
max_complexity = 10
format = "grouped"
baseline = "baseline.txt"
# Base rules
#############################
[tool.flakeheaven.plugins]
"*" = [
"+*",
"-E501", # long lines
"-E203", # conflict with black on PEP8 interpretation
"-W503", # deprecated rule: https://www.flake8rules.com/rules/W503.html
]
flake8-builtins = [
"+*",
"-A003", # class attribute is shadowing a python builtin
]
flake8-bandit = [
"+*",
"-S101", # Use of assert detected.
]