-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday21_part01.fs
81 lines (72 loc) · 3.12 KB
/
day21_part01.fs
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
module day21_part01
open AdventOfCode_Utilities
open AdventOfCode_2020.Modules
type Food = {
Ingredients: string list
Allergens: string list
}
let parseContent(lines: string array) =
let parseLine line =
match line with
| ParseRegex @"([\w| ]+) (?:\(contains ([\w| |,]+)\))" [ingredients; allergens] ->
{
Ingredients = ingredients |> splitBy ' ';
Allergens = allergens |> splitByString ", ";
}
| invalid -> failwithf "Couldn't match line %s" invalid
lines |> Seq.map parseLine
let getAllergenCount foods =
foods
|> Seq.collect (fun food -> food.Allergens)
|> Seq.fold (fun allergenCounts allergen ->
match allergenCounts |> Map.tryFind allergen with
| Some allergenCount -> allergenCounts |>Map.add allergen (allergenCount + 1)
| None -> allergenCounts |> Map.add allergen 1
) Map.empty
let identifyAllergens foods =
let sortedAllergenCounts =
foods
|> getAllergenCount
|> Map.toList
|> List.sortByDescending snd
let rec identifyAllergensRecursively identifiedAllergens toSkip =
let nextAllergen =
sortedAllergenCounts
|> List.filter (fun (allergen, _) -> not (identifiedAllergens |> List.map fst |> List.contains allergen))
|> List.skip toSkip
|> List.head
|> fst
let foodIngredientsContainingAllergen =
foods
|> Seq.filter (fun food -> food.Allergens |> List.contains nextAllergen)
|> Seq.map (
(fun food -> food.Ingredients)
>> List.filter (fun ingredient -> not (identifiedAllergens |> List.map snd |> List.contains ingredient))
>> Set.ofList
)
match Set.intersectMany foodIngredientsContainingAllergen with
| commonIngredients when (Set.count commonIngredients) = 1 ->
let updatedIdentifiedAllergens = (nextAllergen, commonIngredients |> Set.toList |> List.head) :: identifiedAllergens
if List.length updatedIdentifiedAllergens = List.length sortedAllergenCounts then
updatedIdentifiedAllergens
else
identifyAllergensRecursively updatedIdentifiedAllergens 0
| commonIngredients when (Set.count commonIngredients) > 1 ->
identifyAllergensRecursively identifiedAllergens (toSkip + 1)
| _ -> failwithf "Found no ingredients which match allergen %s" nextAllergen
identifyAllergensRecursively [] 0
let findIngredients foods =
let ingredientsIdentifiedAsAllergens =
identifyAllergens foods
|> List.map snd
let flatIngredients =
foods
|> Seq.collect (fun food -> food.Ingredients)
flatIngredients
|> Seq.filter (fun ingredient -> not (ingredientsIdentifiedAsAllergens |> List.contains ingredient))
|> Seq.length
let execute =
let path = "day21/day21_input.txt"
let content = LocalHelper.GetLinesFromFile path
let foods = parseContent content
findIngredients foods