From e7a1efc09ab615592f9d79fb36aae13edbd73b7b Mon Sep 17 00:00:00 2001 From: FrederikBaerentsen Date: Tue, 10 Dec 2024 15:14:29 +0100 Subject: [PATCH] Started working on 2024/10 P1 --- 2024/10/10.md | 106 ++++++++++++++++++++ 2024/10/solution.py | 31 ++++++ 2024/10/solution_old.py | 162 +++++++++++++++++++++++++++++++ __pycache__/fred.cpython-311.pyc | Bin 23989 -> 23869 bytes fred.py | 6 +- 5 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 2024/10/10.md create mode 100644 2024/10/solution.py create mode 100644 2024/10/solution_old.py diff --git a/2024/10/10.md b/2024/10/10.md new file mode 100644 index 0000000..3c2e6aa --- /dev/null +++ b/2024/10/10.md @@ -0,0 +1,106 @@ +## \-\-- Day 10: Hoof It \-\-- + +You all arrive at a [Lava Production Facility](/2023/day/15) on a +floating island in the sky. As the others begin to search the massive +industrial complex, you feel a small nose boop your leg and look down to +discover a reindeer wearing a hard +hat. + +The reindeer is holding a book titled \"Lava Island Hiking Guide\". +However, when you open the book, you discover that most of it seems to +have been scorched by lava! As you\'re about to ask how you can help, +the reindeer brings you a blank [topographic +map](https://en.wikipedia.org/wiki/Topographic_map) of +the surrounding area (your puzzle input) and looks up at you excitedly. + +Perhaps you can help fill in the missing hiking trails? + +The topographic map indicates the *height* at each position using a +scale from `0` (lowest) to `9` (highest). For example: + + 0123 + 1234 + 8765 + 9876 + +Based on un-scorched scraps of the book, you determine that a good +hiking trail is *as long as possible* and has an *even, gradual, uphill +slope*. For all practical purposes, this means that a *hiking trail* is +any path that starts at height `0`, ends at height `9`, and always +increases by a height of exactly 1 at each step. Hiking trails never +include diagonal steps - only up, down, left, or right (from the +perspective of the map). + +You look up from the map and notice that the reindeer has helpfully +begun to construct a small pile of pencils, markers, rulers, compasses, +stickers, and other equipment you might need to update the map with +hiking trails. + +A *trailhead* is any position that starts one or more hiking trails - +here, these positions will always have height `0`. Assembling more +fragments of pages, you establish that a trailhead\'s *score* is the +number of `9`-height positions reachable from that trailhead via a +hiking trail. In the above example, the single trailhead in the top left +corner has a score of `1` because it can reach a single `9` (the one in +the bottom left). + +This trailhead has a score of `2`: + + ...0... + ...1... + ...2... + 6543456 + 7.....7 + 8.....8 + 9.....9 + +(The positions marked `.` are impassable tiles to simplify these +examples; they do not appear on your actual topographic map.) + +This trailhead has a score of `4` because every `9` is reachable via a +hiking trail except the one immediately to the left of the trailhead: + + ..90..9 + ...1.98 + ...2..7 + 6543456 + 765.987 + 876.... + 987.... + +This topographic map contains *two* trailheads; the trailhead at the top +has a score of `1`, while the trailhead at the bottom has a score of +`2`: + + 10..9.. + 2...8.. + 3...7.. + 4567654 + ...8..3 + ...9..2 + .....01 + +Here\'s a larger example: + + 89010123 + 78121874 + 87430965 + 96549874 + 45678903 + 32019012 + 01329801 + 10456732 + +This larger example has 9 trailheads. Considering the trailheads in +reading order, they have scores of `5`, `6`, `5`, `3`, `1`, `3`, `5`, +`3`, and `5`. Adding these scores together, the sum of the scores of all +trailheads is `36`. + +The reindeer gleefully carries over a protractor and adds it to the +pile. *What is the sum of the scores of all trailheads on your +topographic map?* + +To begin, [get your puzzle input](10/input). + +Answer: + diff --git a/2024/10/solution.py b/2024/10/solution.py new file mode 100644 index 0000000..61e99a5 --- /dev/null +++ b/2024/10/solution.py @@ -0,0 +1,31 @@ +#!/bin/python3 +import sys,time,re +from pprint import pprint +sys.path.insert(0, '../../') +from fred import list2int,get_re,nprint,lprint,loadFile,toGrid,TSP,dijkstra +start_time = time.time() + +input_f = 'test' + +part = 1 +######################################### +# # +# Part 1 # +# # +######################################### + +if part == 1: + grid = toGrid(input_f,True) + nprint(grid) + + print(dijkstra(grid,0,9)) + +######################################### +# # +# Part 2 # +# # +######################################### +if part == 2: + exit() + +print("--- %s seconds ---" % (time.time() - start_time)) \ No newline at end of file diff --git a/2024/10/solution_old.py b/2024/10/solution_old.py new file mode 100644 index 0000000..d584859 --- /dev/null +++ b/2024/10/solution_old.py @@ -0,0 +1,162 @@ +#!/bin/python3 +import sys,time,re +from pprint import pprint +sys.path.insert(0, '../../') +from fred import list2int,get_re,nprint,lprint,loadFile,toGrid, get_value_in_direction,addTuples +start_time = time.time() + +input_f = 'test2' + +part = 1 +######################################### +# # +# Part 1 # +# # +######################################### + +if part == 1: + + + def get_value_in_direction(grid, position, direction=None, length=1, type: str = None): + """ + Get the value(s) in a specified direction from a given position in a grid. + If no direction is provided, returns the value at the current position. + + Args: + grid (list of list of int/float/str): The 2D grid. + position (set): A set containing x (row index) and y (column index) as integers. + direction (str, optional): The direction to check. Defaults to None. + length (int, optional): The number of steps to check in the given direction. Default is 1. + type (str, optional): The type of result to return ('list' or 'str'). Defaults to None. + + Returns: + list or str: A list or string of values in the specified direction, or a single value. + + Raises: + ValueError: If direction is invalid or position is not a set of two integers. + TypeError: If grid is not a list of lists. + """ + if not all(isinstance(row, list) for row in grid): + raise TypeError("Grid must be a list of lists.") + + # Ensure position is a set of two integers + if len(position) != 2 or not all(isinstance(coord, int) for coord in position): + raise ValueError("Position must be a set containing two integers (x, y).") + + x, y = position + offsets = { + 'up': (-1, 0), + 'down': (1, 0), + 'left': (0, -1), + 'right': (0, 1), + 'up-left': (-1, -1), + 'up-right': (-1, 1), + 'down-left': (1, -1), + 'down-right': (1, 1) + } + + # If no direction is given, return the value at the current position + if direction is None: + if 0 <= x < len(grid) and 0 <= y < len(grid[x]): + return grid[x][y] + else: + return None + + # Validate direction + if direction not in offsets: + raise ValueError(f"Invalid direction: {direction}. Choose from {list(offsets.keys())}") + + dx, dy = offsets[direction] + new_x, new_y = x + dx, y + dy + + values = [] + + if length == 1: + # Check for out-of-bounds + if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[new_x]): + return grid[new_x][new_y] + else: + return None + else: + for step in range(length): + new_x, new_y = x + step * dx, y + step * dy + # Check for out-of-bounds + if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[new_x]): + values.append(grid[new_x][new_y]) + else: + return [] # Return empty list if any position is out of bounds + if type == 'list': + return values + elif type == 'str': + return ''.join(values) + else: + return values + + grid = toGrid(input_f,True) + + def extract_tuples(nested_list): + result = [] + for item in nested_list: + if isinstance(item, tuple): # Check if the item is a tuple + result.append(item) + elif isinstance(item, list): # If it's a list, recurse into it + result.extend(extract_tuples(item)) + return result + + def find_path(grid,pos:set,cur): + path = 0 + if cur == 9: + return 1 + + cur+=1 + + + if get_value_in_direction(grid,pos,'up') == cur: + path += find_path(grid,addTuples(pos,(-1,0)),cur) + + if get_value_in_direction(grid,pos,'down') == cur: + path += find_path(grid,addTuples(pos,(1,0)),cur) + + if get_value_in_direction(grid,pos,'left') == cur: + path += find_path(grid,addTuples(pos,(0,-1)),cur) + + if get_value_in_direction(grid,pos,'right') == cur: + path += find_path(grid,addTuples(pos,(0,1)),cur) + + + return path + + result = 0 + + for r, row in enumerate(grid): + for c, col in enumerate(row): + #get_value_in_direction(grid, position, direction=None, length=1, type: str = None): + if grid[r][c] == 0: + if get_value_in_direction(grid,(r,c),'up') == 1: + #print(find_path(grid,(r-1,c),1)) + result += find_path(grid,(r-1,c),1) + + if get_value_in_direction(grid,(r,c),'down') == 1: + result += find_path(grid,(r+1,c),1) + #print(find_path(grid,(r+1,c),1,0)) + + if get_value_in_direction(grid,(r,c),'left') == 1: + result += find_path(grid,(r,c-1),1) + #print(find_path(grid,(r,c-1),1,0)) + + if get_value_in_direction(grid,(r,c),'right') == 1: + result += find_path(grid,(r,c+1),1) + #print(find_path(grid,(r,c+1),1,0)) + + print(result) + + +######################################### +# # +# Part 2 # +# # +######################################### +if part == 2: + exit() + +print("--- %s seconds ---" % (time.time() - start_time)) diff --git a/__pycache__/fred.cpython-311.pyc b/__pycache__/fred.cpython-311.pyc index 97aa3fc92cf3f7b1b20c02a9564ba4413c65dfd8..3e4a8d854e841f3b5d3ff2cb38da70d4f9a96b9b 100644 GIT binary patch delta 2271 zcmah~du)?c6#wq`_1mlK=vddi3hPF@+08xK#$GVSHuivY3}H<6V1ssbvX{4=K-`oW z6EK1SP7n+aCkZNs0P|C0d;yavf(kP;A&n*w{KtQEiZKgH@SNKbHX^d5zy5X}_uTWi zryqR6KKqy%-ZmJ*B>dxLO`d^K1L)+OZ0(pXNR1}3f}dL-GD$ihd88pZRDv5;i!oms zQU;YuskL)RHzZbXNIY&aVfF}K(13#QWpe}nf`k<0@ZS$>p= z9njh&Zeo&84@TK;55MOlNhpsWQhkQ|5|?gJIwZMN@aWT7kOq324A%|OmS7%=Mx4&{ zhje#&eYst|J|0UlJy;`FzF*;2zyIqv?QtpZ=r9tCp4{HOJSyV>_MxZu*IglNsao!U=ofxTR>q zQgqc)^sVWl>&oU!o4@Y)rf0miWumra+}Ju{Y`yBikFj-95vM8?CJ-!uzl*?s3Y;l_ z7@wM&dWZ_T=L{9UG-sJvg7UOwVaoX>;mF6rbju=w$08Ksk&O6U!ObZZW@W52x*}5f zB2uj|YYU8KB{hZ0mP+s#Rg5OVYPIqx{Pyd-TRQsr<49L)?NMjtluV>N3&ATR+%pU9 zaJkkD^mn_xya2^rP-Wi8GJqAtL6~X3))-UAYIDewoOmw5LITmESqFIsHclT@ga*%% z(ISEjf@FkE404Pn?N01n#&Y3Kd@M@_b3zF_4673gG3F}?7Ax6#vGG!SAdAq>u3lH= zKtEn@DN1+4R|)kjLyNIomf2#sIlq*h25Vv&dbcNTW98saoTt{K;Zg0M#Lrn;9a4wP zMe3`N&q_V0yPwnWtwzQB@N-fo9vqc?LylRD0>8rhw#+o=HK4aIU{@f^o*zaz-JVy? zyIioLBp!C!;|ysi5@YR9xeZR)Q&|&?mPElXc7xi1x-t0M{sTrBPid1aYst8gU>(8( zVOBVjntvtTlLVrC>xs1xP{|!S-by@EH5_7cFGy{Xo(pUu8zVB2_ieQkrHg zc1?b|x(%rfw&w4|yjVerZ0jc7Aj0ft5rie#z}@_L)D%N|VZ(GfUlz`L#0~EjC$d&Z zEXhZYwI#N~rzk)df^$|sdPpp4IDN@p67&)D6Fh@cVNr*Xu7dANMuJ3tbG5CdYRLbO z#p{)s(OdtcLM`xPWt)j63MV~=LeNMcUkuKw7*+%5$Od756`5eEIQo)Ez&%b*$c68;z2Ld9X*o|4R4j2(b}Ee{bY|1wujST|6(o+phRv@|(!WR% z#KX*jy6O(~ApY;x&QyOYV+VWc{!s9Jw>!(&c^Gjz@aC7CxuQNNBz^=PyoZu z`RoELs$URHC3W&0&{3alC`ayBy}l0a<4?oU`n~EIl$_D>R^{O&Yh4Yms%#Xd8hc_# zQO*wuSE|Gsk?V40%}V9d$Y#ic?$#tH9}w zjzquW-R9+D!ybd{>*tH#%)lZLJ)ot}^9X3A^CE(!1au)z>ycBN{JM>OecfXH@eUHw zj^H9wPArLl-j#SPe3%$@iBkpnIf6F{GE9W@qjNi?w5QKC(CuErFTmbrk12r}C#Bg? MtcAB6XJR${3zkOs@Bjb+ delta 2397 zcmaJ?drVVT7{BMd(+uaF(`B&nhiPWA$3HA)87`WT{k88ql>x@tw7>hi-*?V; zzUS$e7s;nz5M@MBq6GM?aKF%U_kzN7qN^Yq4j zQy!!0k8+ZF_Hk5hqhU^K7icUIwCFiWv(zgb7n*g0(rIw)?0?Q3AX?1aD%fZ0leI;2 zl4hCj3u7hv3=$sb(A!0|C#`yy*V^TwelN9lbo(`Hlh^98?(np?dz#w4)}7s*JG53` zr;{B~;xZzG5wjYa2!<&JNHK@Oi1t>$mety+Q9a6xY)sj>KNV;${QPa;WWO+N6(S7d z;R&bG&*V)cXH6z&!OIxI``$ezxmrsk~a?u@S(P77H4X-y$3u0s) zd8_=k(L5~>rH+K~u@odO{rTPF=9rU(5Mc z_k;dB{SD=oGEr7DSynR9h|GFWvX;FIj5=1MflB_KJ(DibTgnfDTJilmseS&GO7cE<7yak44P z-jq_@xfsBYKF&rM*4#z0uQq{fDDdjC%S71#R23-?bu+898RaUFe8$>sPOyI5_N%zG z7z9Cy`u5DXMb|NAPazZRb9*kF`KP@|$$)jdgH@S2Se_$|Y-QUV)~F_se+@tXEmo=K zvCEEkbQmOal6ZC_b1A!N+rX44g)Ltl9hgqNPRuoEs1~6Px6O+HPW>s}mOqWUdIX-{ z24sy0xD=AN4LRnGnh?-2NS=dbs3zG9FTb<(st>}usJe9|n?*X!nK)assn%#P(%aeH z;iVqU%Xd?rrf}-ORXY({SdDXq><9WFFyJ&3uy$(YN5q7Q^y57eYATwHixJ{jTV^?| zI-hw~d~$?)a+33N!Nj8x^5CR-!ST4{Q0-iJj)RToWXL^0Q;+5jKv`Vz34!6gr;LEJm`OjTB=2?-be#TJek* z0o)5p(1~K6zlW~+P|$_&5&~sUuQJOAfNo*+tA@gONwY_b{7 z`Fx9^3*q5ifz-+0J^Q+1BRahf7qSyeHJY8Yazk(+`yoG+O@W^k& zdrP3;*-IkS>A||cC7ArF=bs^0S-M*V&$qa<5-{u!1$qJ=3t}8%gKiu7hFx)|gky@` zbb$Tgb}6O6gR)=qP>r^+)XF3B1(1veE>-4WQ{UTkP$r|Szox@D3Uc}`-->Cd=7Cnw zPncX=wQ&t9-#|D95R^R4&A~A0?eOjP(m@pCRU5j{4kE+erRxEL67*oGKMWL|p(E^M zZ8AB>uGglK^X#u$E9qh}bvF4cQ2rLks|y!1c#nh%>~^b?o4W!jpy;Ez46e()e%g!1 zK481*E&SgzbQkaf;2lr-#OEU`L?}T(hxqMCu|`2%lh4;qt5Dd4fOiL7gWyL diff --git a/fred.py b/fred.py index ff9ab81..f291ac6 100644 --- a/fred.py +++ b/fred.py @@ -66,14 +66,12 @@ def toGrid(input, parser=None): FileNotFoundError: If the file cannot be found (if input is a file path). ValueError: If the parser function is invalid. """ - if parser is not None and not callable(parser): - raise ValueError("The parser must be a callable function.") - + grid = [] try: with open(input) as file: for line in file: - grid.append(list2int(line.rstrip()) if parser else list(line.rstrip())) # Use parser or default processing + grid.append(list2int(list(line.rstrip())) if parser else list(line.rstrip())) # Use parser or default processing except FileNotFoundError: raise FileNotFoundError(f"The file '{input}' was not found.") except IOError as e: