Advent of Code Day 16–Aunt Sue’s Clues
In day 16’s Advent of Code challenge, we’re working out which of our many Aunt Sue’s sent us a present, based on a number of clues we have and a series of facts we know about each Aunt. Here’s how I solved it in C# and F#:
For my C# solution, I decided to use C# 6’s new dictionary initialiser syntax to set up my clues. The input parsing is fairly standard use of Regex and LINQ. Then for each Sue, we see if she is a candidate by checking if all the clues match.
Directory.SetCurrentDirectory(Path.GetDirectoryName(Util.CurrentQueryPath));
var clues = new Dictionary<string, int> {
["children"] = 3, ["cats"] = 7, ["samoyeds"] = 2, ["pomeranians"] = 3, ["akitas"] = 0,
["vizslas"] = 0, ["goldfish"] = 5, ["trees"] = 3, ["cars"] = 2, ["perfumes"] = 1 };
var sues = File.ReadAllLines("day16.txt")
.Select(r => Regex.Matches(r, @"(\w+)\: (\d+)")
.Cast<Match>()
.Select(m => m.Groups.Cast<Group>().Select(g=>g.Value).Skip(1).ToArray())
.ToDictionary(g => g[0],g => int.Parse(g[1])))
.ToArray();
sues.Select((s, n) => new
{
Sue = n + 1,
Match = clues.All(kvp => !s.ContainsKey(kvp.Key) || s[kvp.Key] == kvp.Value)
}).Single(x => x.Match).Sue.Dump("a"); //213
sues.Select((s, n) => new
{
Sue = n + 1,
Match = clues.All(kvp =>
!s.ContainsKey(kvp.Key) ||
((kvp.Key == "cats" || kvp.Key == "trees") ? s[kvp.Key] > kvp.Value :
(kvp.Key == "pomeranians" || kvp.Key == "goldfish") ? s[kvp.Key] < kvp.Value :
s[kvp.Key] == kvp.Value))
}).Single(x => x.Match).Sue.Dump("b");
One trick I missed in C# was that the clues have more keys than the sues, so if you switch around the checking (“do the facts about this Sue match the clues?” instead of “do the clues match the facts about this Sue?”) then you don’t need to check if keys are present. We need to use Seq.forall
which is the F# equivalent to LINQ’s All
, and Array.findIndex
turns out useful to get the number of the matching aunt Sue.
let parseFacts s =
[for m in Regex.Matches(s, @"(\w+)\: (\d+)") ->
[for g in m.Groups -> g.Value] |> Seq.skip 1 |> Seq.toArray]
|> Seq.map (fun [|a;b|] -> (a, int b))
let sues = "day16.txt" |> File.ReadAllLines |> Array.map parseFacts
let clues = parseFacts "children: 3, cats: 7, samoyeds: 2, pomeranians: 3, akitas: 0, vizslas: 0, goldfish: 5, trees: 3, cars: 2, perfumes: 1" |> Map.ofSeq
let f1 (t, n) = clues.[t] = n
let f2 (t, n) =
match t with
| "cats" | "trees" -> n > clues.[t]
| "pomeranians" |"goldfish" -> n < clues.[t]
| _ -> n = clues.[t]
let find f = sues |> Array.findIndex (fun traits -> traits |> Seq.forall f) |> (+) 1
find f1 |> printfn "a: %d"
find f2 |> printfn "b: %d"