alexandrajay2002

Advent of Code 2024 day 14 part 1

Dec 14th, 2024
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.82 KB | Source Code | 0 0
  1. from math import floor, ceil, prod
  2. from argparse import ArgumentParser, FileType
  3.  
  4.  
  5. def parse_number(line, index):
  6.     '''Parse the (potentially negative) number starting at line[index] and the
  7.       first index after it.'''
  8.     if line[index] == '-':
  9.         acc = '-'
  10.         index += 1
  11.     else:
  12.         acc = ''
  13.  
  14.     while index < len(line) and line[index].isdigit():
  15.         acc += line[index]
  16.         index += 1
  17.  
  18.     return int(acc), index
  19.  
  20.  
  21. def parse_pair(line, index):
  22.     '''Parse a pair of numbers separated by a single character and the first
  23.       index after them.'''
  24.     x, index = parse_number(line, index)
  25.     y, index = parse_number(line, index + 1)  # skip the comma
  26.  
  27.     return (x, y), index
  28.  
  29.  
  30. def parse_line(line):
  31.     '''Parse a line of input into the start position and velocity of a
  32.       robot.'''
  33.     # skip past 'p=' and parse the start coords
  34.     start, index = parse_pair(line, 2)
  35.  
  36.     # skip past ' v=' and parse the velocity
  37.     velocity, _ = parse_pair(line, index + 3)
  38.  
  39.     return start, velocity
  40.  
  41.  
  42. def parse(src):
  43.     '''Parse the input into a list of robots.'''
  44.     return (parse_line(line) for line in src.split('\n') if line != '')
  45.  
  46.  
  47. def position(x0, y0, dx, dy, width, height, time):
  48.     '''Return the position of a robot in the grid at the given time.'''
  49.     return (x0 + dx * time) % width, (y0 + dy * time) % height
  50.  
  51.  
  52. def inside(coords, min_coords, max_coords):
  53.     '''Test if the coords are in range.'''
  54.     x, y = coords
  55.     min_x, min_y = min_coords
  56.     max_x, max_y = max_coords
  57.  
  58.     return min_x <= x < max_x and min_y <= y < max_y
  59.  
  60.  
  61. def main(robots, width, height, time):
  62.     '''Calculate the product of the populations of each quadrant after time
  63.       steps.'''
  64.     middle_x = width / 2
  65.     middle_y = height / 2
  66.  
  67.     boundaries = [
  68.         ((0, 0), (floor(middle_x), floor(middle_y))),  # top left
  69.         ((ceil(middle_x), 0), (width, floor(middle_y))),  # top right
  70.         ((0, ceil(middle_y)), (floor(middle_x), height)),  # bottom left
  71.         ((ceil(middle_x), ceil(middle_y)), (width, height))  # bottom right
  72.     ]
  73.  
  74.     totals = [0, 0, 0, 0]
  75.     for start, velocity in robots:
  76.         coords = position(*start, *velocity, width, height, time)
  77.         for n, (min_coords, max_coords) in enumerate(boundaries):
  78.             if inside(coords, min_coords, max_coords):
  79.                 totals[n] += 1
  80.  
  81.     return prod(totals)
  82.  
  83.  
  84. parser = ArgumentParser()
  85. parser.add_argument('src', type=FileType('r'))
  86. parser.add_argument('width', nargs='?', type=int, default=101)
  87. parser.add_argument('height', nargs='?', type=int, default=103)
  88. parser.add_argument('time', nargs='?', type=int, default=100)
  89.  
  90. if __name__ == '__main__':
  91.     args = parser.parse_args()
  92.     robots = parse(args.src.read())
  93.     print(main(robots, args.width, args.height, args.time))
  94.  
Advertisement
Add Comment
Please, Sign In to add comment