mirror of
https://github.com/HenkKalkwater/aoc-2020
synced 2024-11-22 19:15:18 +00:00
130 lines
3.5 KiB
D
130 lines
3.5 KiB
D
|
import std.algorithm;
|
||
|
import std.array;
|
||
|
import std.format;
|
||
|
import std.range;
|
||
|
import std.stdio;
|
||
|
import std.string;
|
||
|
import std.traits;
|
||
|
import std.variant;
|
||
|
|
||
|
import dayutil;
|
||
|
|
||
|
alias Colour = size_t;
|
||
|
|
||
|
Variant run(int part, File input, bool bigboy, string[] args) {
|
||
|
BagNode[][Colour] rules;
|
||
|
input.byLineCopy.each!(x => x.parseAndAddRule(rules));
|
||
|
|
||
|
Variant result = parts!size_t(part,
|
||
|
() => part1(rules),
|
||
|
() => part2(rules));
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
size_t part1(BagNode[][Colour] rules) {
|
||
|
Colour result = 0;
|
||
|
foreach(Colour colour; rules.byKey()) {
|
||
|
if (eventuallyContains(rules, rules[colour], colourCode("shiny gold"))) {
|
||
|
result++;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
size_t part2(BagNode[][Colour] rules) {
|
||
|
return countContaining(rules, rules[colourCode("shiny gold")]);
|
||
|
}
|
||
|
|
||
|
size_t[string] colourCodeMap;
|
||
|
size_t index = 0;
|
||
|
size_t colourCode(string colour) {
|
||
|
return colourCodeMap.require(colour, index++);
|
||
|
}
|
||
|
|
||
|
struct BagNode {
|
||
|
this(string colour, size_t count) {
|
||
|
this.colour = colourCode(colour);
|
||
|
this.count = count;
|
||
|
}
|
||
|
Colour colour;
|
||
|
size_t count = 0;
|
||
|
}
|
||
|
|
||
|
void parseAndAddRule(string rule, ref BagNode[][size_t] ruleMap) {
|
||
|
auto splitRes = rule.splitter(" bags contain ").array;
|
||
|
size_t key = colourCode(splitRes[0]);
|
||
|
BagNode[] value = [];
|
||
|
if (splitRes[1] != "no other bags.") {
|
||
|
value = splitRes[1].splitter(", ").map!((x) {
|
||
|
string colour;
|
||
|
size_t count;
|
||
|
x.splitter(" bag").array[0].formattedRead!"%d %s"(count, colour);
|
||
|
return BagNode(colour, count);
|
||
|
}).array;
|
||
|
}
|
||
|
ruleMap[key] = value;
|
||
|
}
|
||
|
|
||
|
bool eventuallyContains(BagNode[][Colour] colourMap, BagNode[] nodes, Colour colour) {
|
||
|
foreach(BagNode node; nodes) {
|
||
|
if (node.colour == colour) {
|
||
|
return true;
|
||
|
} else {
|
||
|
if (eventuallyContains(colourMap, colourMap[node.colour], colour)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
size_t countContaining(BagNode[][Colour] colourMap, BagNode[] children) {
|
||
|
size_t total = 0;
|
||
|
//writeln("Recursing into node with ", children.length, " children");
|
||
|
|
||
|
foreach(BagNode node; children) {
|
||
|
total += node.count * (1 + countContaining(colourMap, colourMap[node.colour]));
|
||
|
}
|
||
|
return total;
|
||
|
}
|
||
|
|
||
|
unittest {
|
||
|
string input = q"EOS
|
||
|
light red bags contain 1 bright white bag, 2 muted yellow bags.
|
||
|
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
|
||
|
bright white bags contain 1 shiny gold bag.
|
||
|
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
|
||
|
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
|
||
|
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
|
||
|
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
|
||
|
faded blue bags contain no other bags.
|
||
|
dotted black bags contain no other bags.
|
||
|
EOS";
|
||
|
BagNode[][size_t] testRules;
|
||
|
input.lineSplitter.each!(x => x.parseAndAddRule(testRules));
|
||
|
assert(testRules[colourCode("light red")] == [BagNode("bright white", 1), BagNode("muted yellow", 2)]);
|
||
|
assert(part1(testRules) == 4);
|
||
|
|
||
|
assert(countContaining(testRules, testRules[colourCode("faded blue")]) == 0);
|
||
|
assert(countContaining(testRules, testRules[colourCode("vibrant plum")]) == 11);
|
||
|
}
|
||
|
|
||
|
unittest {
|
||
|
string input = q"EOS
|
||
|
shiny gold bags contain 2 dark red bags.
|
||
|
dark red bags contain 2 dark orange bags.
|
||
|
dark orange bags contain 2 dark yellow bags.
|
||
|
dark yellow bags contain 2 dark green bags.
|
||
|
dark green bags contain 2 dark blue bags.
|
||
|
dark blue bags contain 2 dark violet bags.
|
||
|
dark violet bags contain no other bags.
|
||
|
EOS";
|
||
|
|
||
|
BagNode[][size_t] testRules;
|
||
|
input.lineSplitter.each!(x => x.parseAndAddRule(testRules));
|
||
|
|
||
|
size_t count = part2(testRules);
|
||
|
assert(count == 126);
|
||
|
|
||
|
}
|