Advertisement
Guest User

Day 11 Ruby solution (more optimized)

a guest
Dec 11th, 2020
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 3.17 KB | None | 0 0
  1. INTIAL_SEAT_STATES = File.readlines("day11_input.txt").map { |line| line.chomp.chars }  
  2.  
  3. def print_states(states)
  4.   states.each { |r| puts "#{ r.join('') }" }
  5.   puts ""
  6. end
  7.  
  8. def between_boundary?(x, y, r, c)
  9.   (0...r).include?(x) && (0...c).include?(y)
  10. end
  11.  
  12. def seats_occupied_when_finished(seat_states, surroundings_rule, seat_occupied_threshold)
  13.   row_size = seat_states.length  
  14.   column_size = seat_states.first.length
  15.   #puts "(r, c): (#{row_size}, #{column_size})"  
  16.  
  17.   old_state = seat_states.clone.map(&:clone)
  18.   new_state = nil
  19.  
  20.   visibility_cache = {}
  21.    
  22.   loop do  
  23.     new_state = old_state.clone.map(&:clone)
  24.     new_seats_occupied = 0
  25.     new_seats_empty = 0
  26.    
  27.     #print_states(new_state)
  28.     old_state.each_with_index do |r, i|  
  29.       r.each_with_index do |c, j|  
  30.         next if c == '.'
  31.      
  32.         surroundings = surroundings_rule.call(i, j, old_state, visibility_cache)
  33.         #puts "(c, i, j): (#{c}, #{i}, #{j}),  #{surroundings}"
  34.    
  35.         seats = surroundings.map{ |x, y| old_state[x][y] }
  36.         empty_seats = seats.select { |s| s == 'L' }.size
  37.         occupied_seats = seats.select { |s| s == '#' }.size
  38.  
  39.         case c  
  40.         when 'L'
  41.           if seats.size == empty_seats
  42.             new_state[i][j] = '#'
  43.             new_seats_occupied += 1
  44.           end
  45.         when '#'
  46.           if occupied_seats >= seat_occupied_threshold
  47.             new_state[i][j] = 'L'
  48.             new_seats_empty += 1
  49.           end
  50.         end  
  51.       end  
  52.     end  
  53.  
  54.     break if new_seats_occupied + new_seats_empty == 0
  55.  
  56.     old_state = new_state
  57.   end
  58.  
  59.   new_state.flatten.select { |c| c == '#' }.size
  60. end
  61.  
  62. # Part 1
  63. nearest_surroundings = lambda do |x, y, states, cache|
  64.   return cache[[x, y]] unless cache[[x, y]].nil?
  65.  
  66.   r = states.length  
  67.   c = states.first.length
  68.  
  69.   cache[[x, y]] =
  70.     [  [x - 1, y - 1], [x, y - 1], [x + 1, y - 1],  
  71.        [x - 1, y]    ,             [x + 1, y]    ,  
  72.        [x - 1, y + 1], [x, y + 1], [x + 1, y + 1]  
  73.     ].select { |pos| between_boundary?(pos[0], pos[1], r, c) && states[pos[0]][pos[1]] != '.' }  
  74. end  
  75. puts "#{ seats_occupied_when_finished(INTIAL_SEAT_STATES, nearest_surroundings, 4) }"
  76.  
  77. # Part 2
  78. line_of_sight_surroundings = lambda do |x, y, states, cache|
  79.   return cache[[x, y]] unless cache[[x, y]].nil?
  80.  
  81.   line_of_sight = lambda do |orig, dir|
  82.     r = states.length  
  83.     c = states.first.length
  84.  
  85.     los_cells = []
  86.     x_pos = orig[0]
  87.     y_pos = orig[1]
  88.    
  89.     loop do
  90.       x_pos += dir[0]
  91.       y_pos += dir[1]
  92.    
  93.       los_cells << [x_pos, y_pos] if between_boundary?(x_pos, y_pos, r, c) && states[x_pos][y_pos] != '.'
  94.        
  95.       break unless between_boundary?(x_pos, y_pos, r, c) && states[x_pos][y_pos] == '.'
  96.     end
  97.  
  98.     # puts "(x, y): (#{x}, #{y}), surroundings: #{los_cells}"
  99.     los_cells
  100.   end
  101.  
  102.   return cache[[x, y]] =
  103.     [ [-1, -1], [0, -1], [1, -1],  
  104.       [-1,  0],          [1,  0],
  105.       [-1,  1], [0,  1], [1,  1],
  106.     ].map { |dir| line_of_sight.call([x, y], dir).reject { |p| p.empty? } }
  107.      .flatten(1)
  108. end
  109. puts "#{ seats_occupied_when_finished(INTIAL_SEAT_STATES, line_of_sight_surroundings, 5) }"
  110.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement