-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday21-2.ts
100 lines (83 loc) · 2.78 KB
/
day21-2.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import parseLinesFromInputFile from '../utils/parseLinesFromInputFile';
const lines = parseLinesFromInputFile(`${__dirname}/input`);
type AllergenMap = Map<string, string[]>;
const allIngredients: string[] = [];
const potentialAllergenMap: AllergenMap = new Map();
type PotentialAllergen = {
allergen: string;
ingredients: string[];
};
type IngredientListEntry = {
allergens: string[];
ingredientsSet: Set<string>;
};
const ingredientsList: IngredientListEntry[] = [];
function parseLine(line: string) {
const [, ingredientsString, allergensString] = line.match(
/^(.*) \(contains (.*)\)$/,
)!;
const ingredients = ingredientsString.split(' ');
const allergens = allergensString.split(', ');
allIngredients.push(...ingredients);
ingredientsList.push({
ingredientsSet: new Set(ingredients),
allergens,
});
for (const allergen of allergens) {
let ingredientsForAllergen = potentialAllergenMap.get(allergen) || [];
ingredientsForAllergen = [
...new Set([...ingredientsForAllergen, ...ingredients]),
];
potentialAllergenMap.set(allergen, ingredientsForAllergen);
}
}
lines.forEach(parseLine);
const dangerousList: { allergen: string; ingredient: string }[] = [];
const initialPotentialAllergens = [
...potentialAllergenMap.entries(),
].map(([allergen, ingredients]) => ({ allergen, ingredients }));
function tryAllergens(
potentialAllergens: PotentialAllergen[],
currentAllergenMap = new Map<string, string>(),
) {
if (!potentialAllergens.length) {
for (const [allergen, ingredient] of currentAllergenMap) {
dangerousList.push({ allergen, ingredient });
}
return;
}
const potentialAllergensClone = [...potentialAllergens];
const { allergen, ingredients } = potentialAllergensClone.pop()!;
for (const ingredient of ingredients) {
if ([...currentAllergenMap.values()].includes(ingredient)) {
continue;
}
const currentAllergenMapClone = new Map(currentAllergenMap);
currentAllergenMapClone.set(allergen, ingredient);
const isValidCurrentAllergenMap = ingredientsList.every(
({ allergens, ingredientsSet }) => {
const ingredientsFromAllergens = allergens
.map((allergen) => currentAllergenMapClone.get(allergen))
.filter((x) => x);
return ingredientsFromAllergens.every((ingredient) =>
ingredientsSet.has(ingredient!),
);
},
);
if (!isValidCurrentAllergenMap) {
continue;
}
tryAllergens(potentialAllergensClone, currentAllergenMapClone);
}
}
tryAllergens(initialPotentialAllergens);
const output = dangerousList
.sort(({ allergen: allergenA }, { allergen: allergenB }) => {
if (allergenA < allergenB) {
return -1;
}
return 1;
})
.map(({ ingredient }) => ingredient)
.join(',');
console.log(output);