Advertisement
Guest User

aoc24-day9b

a guest
Feb 7th, 2025
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.88 KB | None | 0 0
  1. # Setup
  2.  
  3. import sys
  4. import time
  5.  
  6. sys.path.append('../utils')
  7. from pyutils import *
  8.  
  9. sample="2333133121414131402"
  10.  
  11. with open('input.txt', 'r', encoding='utf-8') as f:
  12.     puzzle = f.read()
  13.  
  14. def read_diskmap(diskmap: str) -> list[int]:
  15.     processed: list[int] = []
  16.     mode: int = 1 # 1 == file, -1 == free space
  17.     files: int = -1
  18.     for digit in diskmap:
  19.         if not digit.isnumeric():
  20.             continue
  21.         digit = int(digit)
  22.         if mode == 1:
  23.             files += 1
  24.             processed.extend([files] * digit)
  25.         elif mode == -1:
  26.             processed.extend([-1] * digit)
  27.         mode *= -1
  28.     return processed
  29.  
  30. def block_report(disk: list[int]):
  31.     groups = {'used': {}, 'free': []}
  32.     """
  33.    gruops dict structure is: {
  34.        'used': {
  35.            <int; file id>: (<int; index of first block for this file>, [<list[int]; block contents>])
  36.        },
  37.        'free': [
  38.            (<int; index of first block for this free space>, <int; size of this free space, i.e. number of blocks>)
  39.        ]
  40.    }
  41.    """
  42.     freeblock = 0
  43.     for n, file_id in enumerate(disk):
  44.         if file_id == -1:
  45.             freeblock += 1
  46.         else:
  47.             if freeblock > 0:
  48.                 # If we've reached a non-free block, and we *were* counting free blocks before, save the counted blocks
  49.                 groups['free'].append((n - freeblock, freeblock))
  50.                 freeblock = 0
  51.             if file_id not in groups['used']:
  52.                 groups['used'][file_id] = (n, [])
  53.             groups['used'][file_id][1].append(file_id)
  54.     return groups
  55.  
  56. def optimize_disk(disk: list[int], defrag: bool=True) -> list[int]:
  57.     disk = disk.copy()
  58.     if defrag:
  59.         report = block_report(disk)
  60.         # Reverse order of used blocks to iterate from the end as per instructions
  61.         report['used'] = {k:report['used'][k] for k in sorted(report['used'].keys(), reverse=True)}
  62.         for used_id, ublock in report['used'].items():
  63.             # Tried to visualize what was going on so I could fix it, but it didn't help much...
  64.             # clear_output(wait=True)
  65.             # time.sleep(0.1)
  66.             # print(''.join(map(str, d)).replace('-1', '.')[:1000])
  67.             for free_id, fblock in enumerate(report['free']):
  68.                 if fblock[1] >= len(ublock[1]):
  69.                     fblock = report['free'].pop(free_id)
  70.                     # Replace free space with file
  71.                     disk[fblock[0]:fblock[0] + len(ublock[1])] = ublock[1]
  72.                     # Replace previous file space with free space
  73.                     disk[ublock[0]:ublock[0] + len(ublock[1])] = [-1] * len(ublock[1])
  74.                     # Add free block back into same list position, adjust index and shrink size in report
  75.                     report['free'].insert(free_id, (fblock[0] + len(ublock[1]), fblock[1] - len(ublock[1])))
  76.                     break
  77.     else:
  78.         for n in range(len(disk)):
  79.             n = abs(n - len(disk)) - 1
  80.             if disk[n] != -1:
  81.                 leftmost_free = disk.index(-1)
  82.                 if leftmost_free > n:
  83.                     # All sorted, no more work to do
  84.                     break
  85.                 disk[leftmost_free], disk[n] = disk[n], disk[leftmost_free]
  86.     return disk
  87.  
  88. def calc_disk_checksum(d: list[int], show: bool=False) -> int:
  89.     chsum: int = 0
  90.     for n, digit in enumerate(d):
  91.         if show:
  92.             time.sleep(0.005)
  93.             clear_output(wait=True)
  94.             print(f'{repr(n):^8}{repr(digit):^8}{chsum}')
  95.         if digit == -1:
  96.             continue
  97.         chsum += n * digit
  98.     return chsum
  99.  
  100. # Solve
  101.  
  102. disk: list[int] = read_diskmap(puzzle)
  103.  
  104. ta = time.perf_counter()
  105. optimized = optimize_disk(disk, defrag=True)
  106. tb = time.perf_counter()
  107. print(f'Optimized disk of length {len(optimized)} in {tb - ta:.05f}s')
  108.  
  109. calc_disk_checksum(optimized, show=False)
  110.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement