Skip to content

Commit d2ab035

Browse files
committed
Working 2020 day 7
With tests and everything!
1 parent f27e7f1 commit d2ab035

File tree

6 files changed

+166
-11
lines changed

6 files changed

+166
-11
lines changed

2020/7/README.md

+69-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,71 @@
11
# Answers
22

3-
| Part 1 | Part 2 |
4-
| ------ | ------ |
5-
| ` ` | ` ` |
3+
| Part 1 | Part 2 |
4+
| ------ | ------- |
5+
| `179` | `18925` |
6+
7+
## --- Day 7: Handy Haversacks ---
8+
9+
You land at the regional airport in time for your next flight. In fact, it looks like you'll even have time to grab some food: all flights are currently delayed due to _issues in luggage processing_.
10+
11+
Due to recent aviation regulations, many rules (your puzzle input) are being enforced about bags and their contents; bags must be color-coded and must contain specific quantities of other color-coded bags. Apparently, nobody responsible for these regulations considered how long they would take to enforce!
12+
13+
For example, consider the following rules:
14+
15+
light red bags contain 1 bright white bag, 2 muted yellow bags.
16+
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
17+
bright white bags contain 1 shiny gold bag.
18+
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
19+
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
20+
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
21+
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
22+
faded blue bags contain no other bags.
23+
dotted black bags contain no other bags.
24+
25+
26+
These rules specify the required contents for 9 bag types. In this example, every `faded blue` bag is empty, every `vibrant plum` bag contains 11 bags (5 `faded blue` and 6 `dotted black`), and so on.
27+
28+
You have a _`shiny gold`_ bag. If you wanted to carry it in at least one other bag, how many different bag colors would be valid for the outermost bag? (In other words: how many colors can, eventually, contain at least one `shiny gold` bag?)
29+
30+
In the above rules, the following options would be available to you:
31+
32+
* A `bright white` bag, which can hold your `shiny gold` bag directly.
33+
* A `muted yellow` bag, which can hold your `shiny gold` bag directly, plus some other bags.
34+
* A `dark orange` bag, which can hold `bright white` and `muted yellow` bags, either of which could then hold your `shiny gold` bag.
35+
* A `light red` bag, which can hold `bright white` and `muted yellow` bags, either of which could then hold your `shiny gold` bag.
36+
37+
So, in this example, the number of bag colors that can eventually contain at least one `shiny gold` bag is _`4`_.
38+
39+
_How many bag colors can eventually contain at least one `shiny gold` bag?_ (The list of rules is quite long; make sure you get all of it.)
40+
41+
-----------------
42+
43+
## --- Part Two ---
44+
45+
It's getting pretty expensive to fly these days - not because of ticket prices, but because of the ridiculous number of bags you need to buy!
46+
47+
Consider again your `shiny gold` bag and the rules from the above example:
48+
49+
* `faded blue` bags contain `0` other bags.
50+
* `dotted black` bags contain `0` other bags.
51+
* `vibrant plum` bags contain `11` other bags: 5 `faded blue` bags and 6 `dotted black` bags.
52+
* `dark olive` bags contain `7` other bags: 3 `faded blue` bags and 4 `dotted black` bags.
53+
54+
So, a single `shiny gold` bag must contain 1 `dark olive` bag (and the 7 bags within it) plus 2 `vibrant plum` bags (and the 11 bags within _each_ of those): `1 + 1*7 + 2 + 2*11` = _`32`_ bags!
55+
56+
Of course, the actual rules have a small chance of going several levels deeper than this example; be sure to count all of the bags, even if the nesting becomes topologically impractical!
57+
58+
Here's another example:
59+
60+
shiny gold bags contain 2 dark red bags.
61+
dark red bags contain 2 dark orange bags.
62+
dark orange bags contain 2 dark yellow bags.
63+
dark yellow bags contain 2 dark green bags.
64+
dark green bags contain 2 dark blue bags.
65+
dark blue bags contain 2 dark violet bags.
66+
dark violet bags contain no other bags.
67+
68+
69+
In this example, a single `shiny gold` bag must contain _`126`_ other bags.
70+
71+
_How many individual bags are required inside your single `shiny gold` bag?_

2020/7/bags.js

+49-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const trimEnd = require('lodash/trimEnd');
33
class Luggage {
44
constructor(raw_rules) {
55
this.bags_lookup = this.parseToBagsLookup(raw_rules);
6+
this.rules = this.parseToRulesLookup(raw_rules);
67
}
78

89
parseToBagsLookup(raw_rules) {
@@ -30,11 +31,58 @@ class Luggage {
3031

3132
return bags_lookup;
3233
}
34+
35+
parseToRulesLookup(raw_rules) {
36+
let bags_lookup = {};
37+
for (let rule of raw_rules) {
38+
let [parent, children] = rule.split(' bags contain ');
39+
if (!bags_lookup[parent]) {
40+
bags_lookup[parent] = [];
41+
}
42+
if (children.includes('no other')) {
43+
continue;
44+
}
45+
children = trimEnd(children, '.').split(', ');
46+
for (let child of children) {
47+
let [, count, name] = /(\d+) (\w+ \w+) bag/.exec(child);
48+
count = parseInt(count, 10);
49+
bags_lookup[parent].push(new Bag({ name, count }));
50+
}
51+
}
52+
53+
return bags_lookup;
54+
}
55+
56+
countChildrenInside(bag_name) {
57+
if (!this.rules[bag_name]) {
58+
throw new Error(`Invalid bag name: "${bag_name}"`);
59+
}
60+
61+
let rules = this.rules[bag_name];
62+
63+
// Early escape, technically isn't necessary but provides base-case clarity on the recursion
64+
if (!rules.length) {
65+
return 0;
66+
}
67+
68+
let children_count = 0;
69+
for (let bag of rules) {
70+
let { name, count } = bag;
71+
// Add the one bag we are looking at now
72+
children_count += count;
73+
74+
// Plus its children (will be 0 if the child contains no bags itself)
75+
children_count += count * this.countChildrenInside(name);
76+
}
77+
78+
return children_count;
79+
}
3380
}
3481

3582
class Bag {
36-
constructor({ name }) {
83+
constructor({ name, count }) {
3784
this.name = name;
85+
this.count = count;
3886
this.parent_bags = [];
3987
}
4088

2020/7/input.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,34 @@ const input = fs
77
.trim()
88
.split('\n');
99

10-
const sampleInput = `light red bags contain 1 bright white bag, 2 muted yellow bags.
10+
const sampleInputs = [
11+
{
12+
input: `light red bags contain 1 bright white bag, 2 muted yellow bags.
1113
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
1214
bright white bags contain 1 shiny gold bag.
1315
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
1416
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
1517
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
1618
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
1719
faded blue bags contain no other bags.
18-
dotted black bags contain no other bags.`.split('\n');
20+
dotted black bags contain no other bags.`.split('\n'),
21+
partOne: 4,
22+
partTwo: 32,
23+
},
24+
{
25+
input: `shiny gold bags contain 2 dark red bags.
26+
dark red bags contain 2 dark orange bags.
27+
dark orange bags contain 2 dark yellow bags.
28+
dark yellow bags contain 2 dark green bags.
29+
dark green bags contain 2 dark blue bags.
30+
dark blue bags contain 2 dark violet bags.
31+
dark violet bags contain no other bags.`.split('\n'),
32+
partOne: undefined,
33+
partTwo: 126,
34+
},
35+
];
1936

2037
module.exports = {
2138
input,
22-
sampleInput,
39+
sampleInputs,
2340
};

2020/7/part-one.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
const { input, sampleInput } = require('./input');
1+
const assert = require('assert');
2+
const { input, sampleInputs } = require('./input');
23
const { Luggage } = require('./bags');
34

5+
for (let sampleInput of sampleInputs) {
6+
let sample_luggage = new Luggage(sampleInput.input);
7+
let sample_part_one = sample_luggage.bags_lookup['shiny gold'].countUniqueParents();
8+
if (sampleInput.partOne !== undefined) {
9+
assert.strictEqual(sample_part_one, sampleInput.partOne);
10+
}
11+
}
12+
413
let luggage = new Luggage(input);
514
let shiny_gold = luggage.bags_lookup['shiny gold'];
6-
console.log(shiny_gold.countUniqueParents());
15+
console.log(shiny_gold.countUniqueParents());

2020/7/part-two.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
1-
const { input } = require('./input');
1+
const assert = require('assert');
2+
const { input, sampleInputs } = require('./input');
3+
const { Luggage } = require('./bags');
4+
5+
for (let sampleInput of sampleInputs) {
6+
let sample_luggage = new Luggage(sampleInput.input);
7+
let sample_part_two = sample_luggage.countChildrenInside('shiny gold');
8+
if (sampleInput.partTwo !== undefined) {
9+
assert.strictEqual(sample_part_two, sampleInput.partTwo);
10+
}
11+
}
12+
13+
let luggage = new Luggage(input);
14+
let shiny_child_count = luggage.countChildrenInside('shiny gold');
15+
console.log(shiny_child_count);

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ of manual tinkering.
1919

2020
## 2020 Puzzles List
2121

22-
Completed: **4 / 25** (16%)
22+
Completed: **5 / 25** (20%)
2323

2424
* [✅ Day 1](2020/1/)
2525
* [✅ Day 2](2020/2/)
2626
* [✅ Day 3](2020/3/)
2727
* Day 4
2828
* Day 5
2929
* [✅ Day 6](2020/6/)
30+
* [✅ Day 7](2020/7/)
3031

3132
## 2019 Puzzles List
3233

0 commit comments

Comments
 (0)