Advertisement
illuminati229

AoC 2023 Day 14

Dec 14th, 2023
951
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.54 KB | None | 0 0
  1. from time import time
  2.  
  3.  
  4. def timer_func(func):
  5.     # This function shows the execution time of
  6.     # the function object passed
  7.     def wrap_func(*args, **kwargs):
  8.         t1 = time()
  9.         result = func(*args, **kwargs)
  10.         t2 = time()
  11.         print(f'Function {func.__name__!r} executed in {(t2 - t1):.4f}s')
  12.         return result
  13.  
  14.     return wrap_func
  15.  
  16.  
  17. def tilt_north(rock_map: list):
  18.     move = True
  19.     while move:
  20.         move = False
  21.         for x, line in enumerate(rock_map[1:]):
  22.             # x will be off by one
  23.             for y, c in enumerate(line):
  24.                 if rock_map[x + 1][y] in '.#':
  25.                     continue
  26.                 if rock_map[x][y] in '#O':
  27.                     continue
  28.                 else:
  29.                     rock_map[x][y] = 'O'
  30.                     rock_map[x + 1][y] = '.'
  31.                     move = True
  32.     return rock_map
  33.  
  34.  
  35. def transpose(m: list):
  36.     # transposes a list of lists
  37.     return [list(r) for r in list(zip(*m))]
  38.  
  39.  
  40. def flip(m: list):
  41.     return m[::-1]
  42.  
  43.  
  44. def spin_platform(rock_map):
  45.     for _ in range(4):
  46.         rock_map = tilt_north(rock_map)
  47.         rock_map = flip(rock_map)
  48.         rock_map = transpose(rock_map)
  49.     return rock_map
  50.  
  51.  
  52. @timer_func
  53. def day14(filepath, part2=False):
  54.     with open(filepath) as fin:
  55.         lines = [line.strip() for line in fin.readlines()]
  56.  
  57.     if not part2:
  58.         round_rocks = []
  59.         cube_rocks = set()
  60.         stuck_rocks = set()
  61.         for x, line in enumerate(lines):
  62.             for y, c in enumerate(line):
  63.                 if c == '#':
  64.                     cube_rocks.add(complex(x, y))
  65.                 elif c == 'O':
  66.                     round_rocks.append(complex(x, y))
  67.         while round_rocks:
  68.             moved_rocks = []
  69.             for rock in round_rocks:
  70.                 if rock.real == 0:
  71.                     stuck_rocks.add(rock)
  72.                 elif stuck_rocks.intersection([rock - 1]) or cube_rocks.intersection([rock - 1]):
  73.                     stuck_rocks.add(rock)
  74.                 else:
  75.                     moved_rocks.append(rock - 1)
  76.             round_rocks = [*moved_rocks]
  77.         round_rocks = stuck_rocks
  78.         rock_load = 0
  79.         height = len(lines)
  80.         for rock in round_rocks:
  81.             rock_load += height - rock.real
  82.  
  83.         return int(rock_load)
  84.     else:
  85.         rock_map = [list(x) for x in lines]
  86.         rm_dict = {}
  87.         loop_start = 0
  88.         loop_length = 0
  89.         for i in range(1, 1000000000):
  90.             rock_map = spin_platform(rock_map)
  91.             # make a string representation of the map for hashing
  92.             rmh = ''.join(''.join(r) for r in rock_map)
  93.             if rmh in rm_dict:
  94.                 loop_start = rm_dict[rmh]
  95.                 loop_length = i - loop_start
  96.                 break
  97.             else:
  98.                 rm_dict[rmh] = i
  99.         i_f = (1000000000 - loop_start) % loop_length + loop_start
  100.         rmh = 0
  101.         for rmh, i in rm_dict.items():
  102.             if i == i_f:
  103.                 break
  104.         # unpack the string map into something easier to calculate on
  105.         n = len(rock_map[0])
  106.         rock_map = [rmh[i:i+n] for i in range(0, len(rmh), n)]
  107.         load = 0
  108.         for i, row in enumerate(rock_map[::-1]):
  109.             load += row.count('O') * (i + 1)
  110.         return load
  111.  
  112.  
  113. def main():
  114.     assert day14('test14') == 136
  115.     print(f"Part 1: {day14('input14')}")
  116.  
  117.     assert day14('test14', True) == 64
  118.     print(f"Part 2: {day14('input14', True)}")
  119.  
  120.  
  121. if __name__ == '__main__':
  122.     main()
  123.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement