32 lines
		
	
	
		
			964 B
		
	
	
	
		
			Crystal
		
	
	
	
	
	
			
		
		
	
	
			32 lines
		
	
	
		
			964 B
		
	
	
	
		
			Crystal
		
	
	
	
	
	
| require "advent"
 | |
| input = input(2020, 21).lines.map do |line|
 | |
|   data = line.match(/^([a-z ]+) \(contains (.+)\)$/).not_nil!
 | |
|   {data[1].split(" ").to_set, data[2].split(", ").to_set}
 | |
| end
 | |
| 
 | |
| allergens = input.flat_map(&.last.to_a).to_set
 | |
| ingredients = input.flat_map(&.first.to_a).to_set
 | |
| 
 | |
| allergen_sets = {} of String => Set(String)
 | |
| allergens.each do |a|
 | |
|   input.each do |ings, als|
 | |
|     next unless als.includes? a
 | |
|     allergen_sets[a] ||= ings
 | |
|     allergen_sets[a] &= ings
 | |
|   end
 | |
| end
 | |
| 
 | |
| safe = ingredients.reject { |i| allergen_sets.any? &.last.includes?(i) }
 | |
| puts "Part 1: #{input.sum &.first.count { |i| safe.includes? i }}"
 | |
| 
 | |
| known_allergens = {} of String => String
 | |
| while allergen_sets.size > known_allergens.size
 | |
|   allergen_sets.each do |a, s|
 | |
|     next unless s.size == 1
 | |
|     new_known = s.first
 | |
|     known_allergens[a] = new_known
 | |
|     allergen_sets.each &.last.delete(new_known)
 | |
|   end
 | |
| end
 | |
| puts "Part 2: #{known_allergens.to_a.sort_by(&.first).map(&.last).join(",")}"
 |