1
+ package com .macasaet ;
2
+
3
+ import java .io .IOException ;
4
+ import java .util .Comparator ;
5
+ import java .util .HashMap ;
6
+ import java .util .HashSet ;
7
+ import java .util .Map .Entry ;
8
+ import java .util .Set ;
9
+ import java .util .stream .Collectors ;
10
+ import java .util .stream .StreamSupport ;
11
+
12
+ public class Day21 {
13
+
14
+ public static void main (final String [] args ) throws IOException {
15
+ try (var spliterator = new LineSpliterator (Day21 .class .getResourceAsStream ("/day-21-input.txt" ))) {
16
+
17
+ final var foods = StreamSupport .stream (spliterator , false )
18
+ .map (String ::strip )
19
+ .map (Food ::fromLine )
20
+ .collect (Collectors .toUnmodifiableSet ());
21
+ final var allergenToFood = new HashMap <String , Set <Food >>();
22
+ final var ingredientToFood = new HashMap <String , Set <Food >>();
23
+ for (final var food : foods ) {
24
+ for (final var allergen : food .allergens ) {
25
+ allergenToFood .computeIfAbsent (allergen , key -> new HashSet <>()).add (food );
26
+ }
27
+ for (final var ingredient : food .ingredients ) {
28
+ ingredientToFood .computeIfAbsent (ingredient , key -> new HashSet <>()).add (food );
29
+ }
30
+ }
31
+
32
+ final var ingredientsThatContainNoAllergens = new HashSet <>(ingredientToFood .keySet ());
33
+ final var allergenToIngredient = new HashMap <String , Set <String >>();
34
+ allergenToFood .entrySet ().stream ().forEach (entry -> {
35
+ final var allergen = entry .getKey ();
36
+ final var appearances = entry .getValue ();
37
+ Set <String > commonIngredients = null ;
38
+ for (final var food : appearances ) {
39
+ if (commonIngredients == null ) {
40
+ commonIngredients = new HashSet <>(food .ingredients );
41
+ } else {
42
+ commonIngredients .retainAll (food .ingredients );
43
+ }
44
+ }
45
+ System .err .println (allergen + " may be found in: " + commonIngredients );
46
+ allergenToIngredient .put (allergen , commonIngredients );
47
+ ingredientsThatContainNoAllergens .removeAll (commonIngredients );
48
+ });
49
+
50
+ int sum = 0 ;
51
+ for (final var food : foods ) {
52
+ for (final var ingredient : ingredientsThatContainNoAllergens ) {
53
+ if (food .ingredients .contains (ingredient )) {
54
+ sum ++;
55
+ }
56
+ }
57
+ }
58
+ System .out .println ("Part 1: " + sum );
59
+
60
+ final var ingredientToAllergen = new HashMap <String , String >();
61
+
62
+ final var dangerousIngredients = new HashSet <>(ingredientToFood .keySet ());
63
+ dangerousIngredients .removeAll (ingredientsThatContainNoAllergens );
64
+ while (!dangerousIngredients .isEmpty ()) {
65
+ for (final var i = dangerousIngredients .iterator (); i .hasNext (); ) {
66
+ final var ingredient = i .next ();
67
+ boolean mappedIngredient = false ;
68
+ for (final var j = allergenToIngredient .entrySet ().iterator (); j .hasNext (); ) {
69
+ final var entry = j .next ();
70
+ final var allergen = entry .getKey ();
71
+ final var ingredients = entry .getValue ();
72
+ if (ingredients .size () == 1 && ingredients .contains (ingredient )) {
73
+ // this is the only ingredient known to contain this allergen
74
+ ingredientToAllergen .put (ingredient , allergen );
75
+ System .err .println ("Mapping " + ingredient + " to " + allergen );
76
+ j .remove ();
77
+ mappedIngredient |= true ;
78
+ break ;
79
+ }
80
+ }
81
+ if (mappedIngredient ) {
82
+ for (final var entry : allergenToIngredient .entrySet ()) {
83
+ final var ingredients = entry .getValue ();
84
+ ingredients .remove (ingredient );
85
+ }
86
+ i .remove ();
87
+ }
88
+ }
89
+ }
90
+
91
+ final var result =
92
+ ingredientToAllergen
93
+ .entrySet ()
94
+ .stream ()
95
+ .sorted (Comparator .comparing (Entry ::getValue ))
96
+ .map (Entry ::getKey )
97
+ .collect (Collectors .joining ("," ));
98
+ System .out .println ("Part 2: " + result );
99
+ }
100
+ }
101
+
102
+ public static class Food {
103
+ private final Set <String > ingredients ;
104
+ private final Set <String > allergens ;
105
+
106
+ public Food (final Set <String > ingredients , final Set <String > allergens ) {
107
+ this .ingredients = ingredients ;
108
+ this .allergens = allergens ;
109
+ }
110
+
111
+ public static Food fromLine (final String line ) {
112
+ final var components = line .split ("\\ (contains " );
113
+ final var ingredientsArray = components [0 ].strip ().split (" " );
114
+ final var allergensString = components [1 ].strip ().replaceAll ("\\ )" , "" );
115
+ final var allergensArray = allergensString .split (", " );
116
+ return new Food (Set .of (ingredientsArray ), Set .of (allergensArray ));
117
+ }
118
+
119
+ }
120
+ }
0 commit comments