Guest User

Day 11 part 2

a guest
Dec 11th, 2020
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.22 KB | None | 0 0
  1. from functools import lru_cache
  2. f = open("day_11_2.txt")
  3. input_data = f.read()
  4. x_rows = input_data.split('\n')
  5.  
  6.  
  7. def line_generator(delta_x,delta_y):
  8.     x=0
  9.     y=0
  10.     while True:
  11.         yield (x+delta_x,y+delta_y)
  12.  
  13. class Seat:
  14.     seats= {k:[] for k in range(len(input_data.split('\n')[0]))}
  15.     all_seats = []
  16.     all_seats_dict={}
  17.  
  18.     def __init__(self,x,y,status):
  19.         self.x =x
  20.         self.y = y
  21.         self.pos = (x,y)
  22.         self.status=status
  23.         self.pending_status_change=None
  24.         self.seats_visible_in_direction = None
  25.  
  26.     def __repr__(self):
  27.         return self.status
  28.  
  29.     def __str__(self):
  30.         return f"{self.pos} {self.status}"
  31.  
  32.     @classmethod
  33.     def print_overview_map(cls):
  34.         '''Prints an overview map'''
  35.         row_len = len(x_rows[0])
  36.         output = ""
  37.         for seat in Seat.all_seats:
  38.             output = "".join([output,seat.status])
  39.             if len(output)==row_len:
  40.                 print(output)
  41.                 output=""
  42.         print('')
  43.  
  44.     @classmethod
  45.     def overview_map(self):
  46.         return "".join([s.status for s in self.all_seats])
  47.  
  48.     def apply_status_change(self):
  49.         if self.pending_status_change is not None:
  50.             self.status = self.pending_status_change
  51.             self.pending_status_change=None
  52.  
  53.     def get_visible_seats(self):
  54.         if self.seats_visible_in_direction is None:
  55.             # the eight directions
  56.             line_slopes = [(-1,1),(0,1),(1,1),(-1,0),(1,0),(-1,-1),(0,-1),(1,-1)]
  57.  
  58.             seats_visible_in_direction = {s:[] for s in line_slopes}
  59.  
  60.             for slope in seats_visible_in_direction.keys():
  61.                 x_slope, y_slope = slope
  62.                 line = line_generator(x_slope,y_slope)
  63.  
  64.                 start_x,start_y = self.pos
  65.                 d_x, d_y = next(line)
  66.                 x = start_x+d_x
  67.                 y = start_y+d_y
  68.                 visible_seat = Seat.get_seat_at_pos(x,y)
  69.                 seats_visible_in_direction[slope].append(visible_seat)
  70.                 while visible_seat is not None:
  71.                     d_x, d_y = next(line)
  72.                     x += d_x
  73.                     y += d_y
  74.                     visible_seat = Seat.get_seat_at_pos(x,y)
  75.                     seats_visible_in_direction[slope].append(visible_seat)
  76.  
  77.  
  78.             self.seats_visible_in_direction = seats_visible_in_direction
  79.             return seats_visible_in_direction
  80.         else:
  81.             return self.seats_visible_in_direction
  82.  
  83.     def get_first_visible_seats(self):
  84.         directions = [(-1,1),(0,1),(1,1),(-1,0),(1,0),(-1,-1),(0,-1),(1,-1)]
  85.  
  86.         visible_seats = self.get_visible_seats()
  87.  
  88.         first_seen_seats = []
  89.  
  90.         for d in directions:
  91.             seats_in_this_direction = visible_seats[d]
  92.  
  93.             for seat in seats_in_this_direction:
  94.                 if seat is None: # reached the end, fill in None for good measure
  95.                     break
  96.                 if seat.status =='.': # look over floor
  97.                     continue
  98.                 if seat.status in ['L','#']:
  99.                     first_seen_seats.append(seat)
  100.                     break
  101.  
  102.         return first_seen_seats
  103.  
  104.     def get_num_occupied_visible_seats(self):
  105.         visible = [s.status for s in self.get_first_visible_seats()]
  106.         return visible.count('#')
  107.  
  108.     @classmethod
  109.     def get_seat_at_pos(cls,x,y):
  110.         try:
  111.             return Seat.all_seats_dict[(x,y)]
  112.         except IndexError:
  113.             return None
  114.         except KeyError:
  115.             return None
  116.  
  117.     @classmethod
  118.     def get_total_num_occupied_seats(cls):
  119.         return len([s for s in Seat.all_seats if s.status=='#'])
  120.  
  121.     def get_status_change_visible(self):
  122.         if self.status == '.':  # floor never changes
  123.             return None
  124.         visible_occupied = self.get_num_occupied_visible_seats()
  125.  
  126.         if self.status == 'L':
  127.             if visible_occupied == 0:
  128.                 return '#'
  129.         elif self.status == '#':
  130.             if visible_occupied >= 5:
  131.                 return 'L'
  132.  
  133.         return None
  134.  
  135.     @classmethod
  136.     def run_round_visible(cls):
  137.         # get if anything will change on any of the seats
  138.         for seat in cls.all_seats:
  139.             seat.pending_status_change = seat.get_status_change_visible()
  140.  
  141.         for seat in cls.all_seats:
  142.             seat.apply_status_change()
  143.  
  144.  
  145. # setup
  146. for y, col in enumerate(x_rows):
  147.     for x, status in enumerate(col):
  148.         s = Seat(x, y, status)
  149.         Seat.all_seats.append(s)
  150.         Seat.all_seats_dict[s.pos]=s
  151.  
  152. # print the status before start
  153. counter=0
  154. round_maps={}
  155. Seat.print_overview_map()
  156.  
  157. # save the round 0 map
  158. round_maps[counter]=Seat.overview_map()
  159. Seat.run_round_visible()
  160. Seat.print_overview_map()
  161.  
  162. # run one round
  163. counter+=1
  164. Seat.run_round_visible()
  165. Seat.print_overview_map()
  166. round_maps[counter]=Seat.overview_map()
  167.  
  168. # run until the new map generated equal the one generated in the previoud round
  169. while True:
  170.     counter += 1
  171.     Seat.run_round_visible()
  172.     round_maps[counter] = Seat.overview_map()
  173.  
  174.     if round_maps[counter]==round_maps[counter-1]:
  175.         Seat.print_overview_map()
  176.         print(Seat.get_total_num_occupied_seats())
  177.         break
  178.  
Add Comment
Please, Sign In to add comment