From 77dd1077e56f83f1caaa002abd48f1974888bee3 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Mon, 17 Jan 2022 09:38:18 +0100 Subject: [PATCH 1/2] Counter().most_common() is twice as fast as searching in a for-loop --- day19.py | 10 +++++----- day24.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/day19.py b/day19.py index 90b197d..67e4207 100644 --- a/day19.py +++ b/day19.py @@ -1,4 +1,4 @@ -from collections import defaultdict +from collections import Counter from itertools import combinations from tools.aoc import AOCDay from tools.coordinate import Coordinate, DistanceAlgorithm @@ -17,7 +17,7 @@ ROTATION_PATH = [ def overlap(beacon1: Grid, beacon2: Grid) -> Union[Coordinate, None]: - diffs = defaultdict(int) + diffs = Counter() for c1 in beacon1.getActiveCells(): for c2 in beacon2.getActiveCells(): # Interestingly adding an if statement here to break out early when already 12 matches are found @@ -25,9 +25,9 @@ def overlap(beacon1: Grid, beacon2: Grid) -> Union[Coordinate, None]: # and checking the results afterwards. diffs[c1 - c2] += 1 - for d in diffs: - if diffs[d] >= 12: - return d + d = diffs.most_common(1)[0] + if d[1] >= 12: + return d[0] def converge(scanner_grids: List[Grid]) -> (Grid, List[Coordinate]): diff --git a/day24.py b/day24.py index c67b80d..3e7910c 100644 --- a/day24.py +++ b/day24.py @@ -8,7 +8,7 @@ def getTheNumberFast(pushpull, adders, subbers, part2=False): inc = 1 else: number_init = [9] * 14 - inc = - 1 + inc = -1 z = int(1e9) number = number_init.copy() From eeafe2a56e18311f3b525efe1f6052a9e758a259 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Sun, 7 Aug 2022 19:34:05 +0200 Subject: [PATCH 2/2] cleanup --- !NOTES_FOR_NEXT_YEAR | 6 ---- day22.py | 71 +++++--------------------------------------- 2 files changed, 7 insertions(+), 70 deletions(-) delete mode 100644 !NOTES_FOR_NEXT_YEAR diff --git a/!NOTES_FOR_NEXT_YEAR b/!NOTES_FOR_NEXT_YEAR deleted file mode 100644 index adec3ec..0000000 --- a/!NOTES_FOR_NEXT_YEAR +++ /dev/null @@ -1,6 +0,0 @@ -- add run() method to AOCDay, so every day can run on it's own -> enable Alt+Shit+F10 and avoid confusion - -> after wards add a "if __name__ == '__main__': day = Day(); day.run()" to the skeleton -- add download_input() and submit_solution() to AOCDay, this can be automated, so let it ... - -> submit_solution() should not submit None and keep track of past (wrong) attempts to not re-try those -- add some sort of "start_day.py", as the manual copy/create is tedious - -> maybe even download the problem description into that days .py? At least part1; adding part2 afterwards might be tricky diff --git a/day22.py b/day22.py index bb8828d..803d76d 100644 --- a/day22.py +++ b/day22.py @@ -1,66 +1,8 @@ from collections import defaultdict from tools.aoc import AOCDay -from tools.coordinate import Coordinate -from typing import Any, Generator, List, Union - - -class Cube: - coord_ulb: Coordinate # min_coord / up left back - coord_urb: Coordinate - coord_ulf: Coordinate - coord_urf: Coordinate - coord_dlb: Coordinate - coord_drb: Coordinate - coord_dlf: Coordinate - coord_drf: Coordinate # max_coord / down right front - - def __init__(self, min_coord: Coordinate, max_coord: Coordinate): - assert max_coord >= min_coord, "invalid cube spec: %s < %s" % (min_coord, max_coord) - self.coord_ulb = min_coord - self.coord_drf = max_coord - #self.coord_urb = Coordinate(self.coord_ulb.x, self.coord_drf.y, self.coord_ulb.z) - #self.coord_ulf = Coordinate(self.coord_ulb.x, self.coord_ulb.y, self.coord_drf.z) - #self.coord_urf = Coordinate(self.coord_ulb.x, self.coord_drf.y, self.coord_drf.z) - #self.coord_dlb = Coordinate(self.coord_drf.x, self.coord_ulb.y, self.coord_ulb.z) - #self.coord_drb = Coordinate(self.coord_drf.x, self.coord_drf.y, self.coord_ulb.z) - #self.coord_dlf = Coordinate(self.coord_drf.x, self.coord_ulb.y, self.coord_drf.z) - - def getSize(self): - return ( - (self.coord_drf.x - self.coord_ulb.x + 1) - * (self.coord_drf.y - self.coord_ulb.y + 1) - * (self.coord_drf.z - self.coord_ulb.z + 1) - ) - - def intersect(self, other: 'Cube') -> Union['Cube', None]: - intersect_ulr = Coordinate( - #max(self.coord_ulb.x, other.coord_ulb.x), - self.coord_ulb.x if self.coord_ulb.x > other.coord_ulb.x else other.coord_ulb.x, - #max(self.coord_ulb.y, other.coord_ulb.y), - self.coord_ulb.y if self.coord_ulb.y > other.coord_ulb.y else other.coord_ulb.y, - #max(self.coord_ulb.z, other.coord_ulb.z) - self.coord_ulb.z if self.coord_ulb.z > other.coord_ulb.z else other.coord_ulb.z, - ) - intersect_drf = Coordinate( - #min(self.coord_drf.x, other.coord_drf.x), - self.coord_drf.x if self.coord_drf.x < other.coord_drf.x else other.coord_drf.x, - #min(self.coord_drf.y, other.coord_drf.y), - self.coord_drf.y if self.coord_drf.y < other.coord_drf.y else other.coord_drf.y, - #min(self.coord_drf.z, other.coord_drf.z), - self.coord_drf.z if self.coord_drf.z < other.coord_drf.z else other.coord_drf.z, - ) - if intersect_ulr <= intersect_drf: - return Cube(intersect_ulr, intersect_drf) - - def __str__(self): - return "Cube(<%d,%d,%d>;<%d,%d,%d>)" % ( - self.coord_ulb.x, self.coord_ulb.y, self.coord_ulb.z, - self.coord_drf.x, self.coord_drf.y, self.coord_drf.z, - ) - - def __repr__(self): - return self.__str__() +from tools.coordinate import Coordinate, Cube +from typing import Any class Day(AOCDay): @@ -88,22 +30,23 @@ class Day(AOCDay): minZ, maxZ = map(int, zco.split("..")) new_cube = Cube(Coordinate(minX, minY, minZ), Coordinate(maxX, maxY, maxZ)) - if not part1 or (new_cube.coord_ulb >= Coordinate(-50, -50, -50) and new_cube.coord_drf <= Coordinate(50, 50, 50)): + if not part1 \ + or (new_cube.top_left >= Coordinate(-50, -50, -50) + and new_cube.bottom_right <= Coordinate(50, 50, 50)): yield state == "on", new_cube def getOnSum(self, part1: bool = False) -> int: cubes = defaultdict(int) for switch_state, this_cube in self.getCubeList(part1=part1): for prior_cube in cubes.copy(): - intersect_cube = this_cube.intersect(prior_cube) + intersect_cube = this_cube.intersection(prior_cube) if intersect_cube: cubes[intersect_cube] -= cubes[prior_cube] if switch_state: cubes[this_cube] = 1 - #print(cubes) - return sum(cube.getSize() * on_off for cube, on_off in cubes.items()) + return sum(len(cube) * on_off for cube, on_off in cubes.items()) def part1(self) -> Any: return self.getOnSum(part1=True)