#!/usr/bin/env ruby class Component < Array def self.from_line(line) new(line.map(&:chars)[1..-2].transpose.map { _1.count("#") }) end end class Lock < Component def accepts?(key) = zip(key).all? { _1.sum <= 5 } end Key = Class.new(Component) def create(line) (line.first == "#####" ? Lock : Key).from_line(line) end input = (ARGV.first.nil? ? DATA : ARGF) .readlines(chomp: true) .slice_when { |a, b| b.empty? } .map { _1.reject { |a| a.empty? } } .map(&method(:create)) locks, keys = input.partition { _1.is_a?(Lock) } p locks.sum { |lock| keys.count { lock.accepts?(_1) } } __END__ ##### .#### .#### .#### .#.#. .#... ..... ##### ##.## .#.## ...## ...#. ...#. ..... ..... #.... #.... #...# #.#.# #.### ##### ..... ..... #.#.. ###.. ###.# ###.# ##### ..... ..... ..... #.... #.#.. #.#.# #####