Advertisement
illuminati229

AoC 2023 Day 12

Dec 12th, 2023
1,067
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.40 KB | None | 0 0
  1. from time import time
  2. from functools import cache
  3.  
  4.  
  5. def timer_func(func):
  6.     # This function shows the execution time of
  7.     # the function object passed
  8.     def wrap_func(*args, **kwargs):
  9.         t1 = time()
  10.         result = func(*args, **kwargs)
  11.         t2 = time()
  12.         print(f'Function {func.__name__!r} executed in {(t2 - t1):.4f}s')
  13.         return result
  14.  
  15.     return wrap_func
  16.  
  17.  
  18. @cache
  19. def count_groups(string):
  20.     # return an empty list if the input is empty
  21.     if not string:
  22.         return tuple()
  23.     # Initialize an empty list to store the output
  24.     output = []
  25.     # Initialize a variable to store the current group count
  26.     count = 0
  27.     # Loop through each character in the string
  28.     for char in string:
  29.         # Check if the character is '#'
  30.         if char == '#':
  31.             # Increment the count by 1
  32.             count += 1
  33.         # Check if the character is '.'
  34.         elif char == '.':
  35.             # Check if the count is not zero
  36.             if count != 0:
  37.                 # Add the count to the output list
  38.                 output.append(count)
  39.                 # Reset the count to zero
  40.                 count = 0
  41.     # Append the last count if the last character was a '#'
  42.     if string[-1] == '#':
  43.         output.append(count)
  44.     # Return the output list as a tuple (tuple for caching)
  45.     return tuple(output)
  46.  
  47.  
  48. @cache
  49. def fcs(s, g):
  50.     if len(s) < sum(g):
  51.         return 0
  52.     if not s:  # if s is empty, check if there are entries left in g
  53.         return g == ()  # return True if g is empty
  54.     if not g:  # if g is empty, check if there are any broken springs left in s
  55.         return '#' not in s
  56.     combos = 0
  57.     if '?' in s:
  58.         i = s.index('?')
  59.     else:
  60.         return count_groups(s) == g
  61.     sbi = s[:i]  # slice before
  62.     sai = s[i+1:]  # slice after
  63.  
  64.     # if the ? is a .
  65.     gb = count_groups(sbi)  # finding the groups before the ?
  66.     gt = g[:len(gb)]  # trimming g to match the len of gb
  67.     if gt == gb:  # if they match, continue searching with the string after the ? and the reduced groups
  68.         combos += fcs(sai, g[len(gb):])
  69.  
  70.     # if the ? is a #
  71.     gb = count_groups(sbi + '#')  # find the group counts with the additional #
  72.     gt = g[:len(gb)]  # trim like before
  73.     if gb[:-1] == gt[:-1]:  # only match all but the last
  74.         if gb[-1] < gt[-1]:  # if the last doesn't match, flip the current ? to a # and continue matching
  75.             combos += fcs(sbi + '#' + sai, g)
  76.         # if the last of the groups match, and sai is not empty or the next character isn't a #
  77.         if gb[-1] == gt[-1] and (not sai or sai[0] != '#'):
  78.             combos += fcs(sai[1:], g[len(gb):])
  79.  
  80.     return combos
  81.  
  82.  
  83. @timer_func
  84. def day12(filepath, part2=False):
  85.     with open(filepath) as fin:
  86.         lines = [line.strip() for line in fin.readlines()]
  87.     combos = 0
  88.     for line in lines:
  89.         records, groups = line.split()
  90.         groups = tuple([int(x) for x in groups.split(',')])
  91.  
  92.         if not part2:
  93.             combos += fcs(records, groups)
  94.         else:
  95.             combo = fcs('?'.join([records for _ in range(5)]), groups * 5)
  96.             combos += combo
  97.  
  98.     return combos
  99.  
  100.  
  101. def main():
  102.     assert day12('test12') == 21
  103.     print(f"Part 1: {day12('input12')}")
  104.  
  105.     assert day12('test12', True) == 525152
  106.     print(f"Part 2: {day12('input12', True)}")
  107.  
  108.  
  109. if __name__ == '__main__':
  110.     main()
  111.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement