#!/usr/bin/env ruby require "debug" require "ostruct" MOVES = 100 input = (if ARGV.first.nil? WIDTH = 11 HEIGHT = 7 DATA else WIDTH = 101 HEIGHT = 103 ARGF end) def print_grid(grid) grid.each_with_index do |row, y| row.each_with_index do |val, x| if val.size > 0 print grid[y][x].size elsif x == WIDTH / 2 || y == HEIGHT / 2 print " " else print " " end end puts end puts puts end def move(grid, ticks = 1) new_grid = Array.new(HEIGHT) { Array.new(WIDTH) { Array.new } } grid.each_with_index do |row, y| row.each_with_index do |val, x| movements = val.map do |robot| new_x = (x + robot.first * ticks) % WIDTH new_y = (y + robot.last * ticks) % HEIGHT new_grid[new_y][new_x] << robot end end end new_grid end def safety_factor(grid) [ [[0, 0], [HEIGHT / 2 - 1, WIDTH / 2 - 1]], [[0, WIDTH / 2 + 1], [HEIGHT / 2 - 1, WIDTH - 1]], [[HEIGHT / 2 + 1, 0], [HEIGHT - 1, WIDTH / 2 - 1]], [[HEIGHT / 2 + 1, WIDTH / 2 + 1], [HEIGHT - 1, WIDTH - 1]], ].map do |(top_left, bottom_right)| (top_left.first..bottom_right.first).map do |y| (top_left.last..bottom_right.last).map do |x| grid[y][x].size end.sum end.sum end.inject(:*) end def count_top(grid) (0...HEIGHT / 2).map do |y| grid[y].select { !_1.empty? }.size end.sum end grid = Array.new(HEIGHT) { Array.new(WIDTH) { Array.new } } input = input.readlines(chomp: true) .map do |line| x, y, vx, vy = line.scan(/(-?\d+)/).flatten.map(&:to_i) grid[y][x] << [vx, vy] end new_grid = move(grid.clone.map(&:clone), MOVES) part_1 = safety_factor(new_grid) new_grid = grid.dup.map(&:dup) candidates = (WIDTH * HEIGHT).times.map.with_index do |moves| new_grid = move(new_grid) [moves + 1, safety_factor(new_grid)] end.sort_by(&:last) part_2 = candidates.first.first print_grid(move(grid, candidates.first.first)) p part_1 p part_2 __END__ p=0,4 v=3,-3 p=6,3 v=-1,-3 p=10,3 v=-1,2 p=2,0 v=2,-1 p=0,0 v=1,3 p=3,0 v=-2,-2 p=7,6 v=-1,-3 p=3,0 v=-1,-2 p=9,3 v=2,3 p=7,3 v=-1,2 p=2,4 v=2,-3 p=9,5 v=-3,-3