You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.9 KiB
Dart
163 lines
4.9 KiB
Dart
import 'package:aoc2020/aocbase.dart';
|
|
import 'package:aoc2020/model/readdata.dart';
|
|
|
|
class Bag {
|
|
final String color;
|
|
int count;
|
|
Bag parent;
|
|
List<Bag> children;
|
|
|
|
Bag({this.color, this.parent, this.count, List<Bag> children}) : children = [];
|
|
|
|
Bag.copy(Bag source)
|
|
: color = source.color,
|
|
count = source.count,
|
|
parent = Bag(color: source.color),
|
|
children = List.from(source.children);
|
|
|
|
@override
|
|
String toString() => 'Bag($color, parent: ${parent?.color ?? 'TOP'}, count: $count, with: ${children.map((child) => '${child.count}:${child.color}')})';
|
|
}
|
|
|
|
class AOC20201207 extends AOCBase {
|
|
// Create a List of all the leaves, then piece together all the trees
|
|
|
|
List<Bag> leaves;
|
|
List<Bag> trees;
|
|
|
|
void parseLine(String line) {
|
|
// Split line by "bags contain" first part is color of holding bag, second part is contents
|
|
// split contents by ", " List of number and color of content bag(s)
|
|
var split_one = line.split('bags contain');
|
|
var holdingBagColor = split_one[0].trim();
|
|
var holdingBag = Bag(color: holdingBagColor);
|
|
var split_two = split_one[1].substring(0, split_one[1].length - 1).trim().split(',');
|
|
for (var _bag in split_two) {
|
|
var split_three = _bag.trim().split(' ');
|
|
if (split_three[0] != 'no') {
|
|
var numBags = int.parse(split_three[0]);
|
|
var childColor = split_three[1] + ' ' + split_three[2];
|
|
var child = Bag(color: childColor);
|
|
child.count = numBags;
|
|
child.parent = holdingBag;
|
|
// leaves.add(child);
|
|
holdingBag.children.add(child);
|
|
}
|
|
}
|
|
leaves.add(holdingBag);
|
|
}
|
|
|
|
Set<String> findTops() {
|
|
var leavesWithParents = <String>{};
|
|
var allLeaves = <String>{};
|
|
for (var leaf in leaves.where((bag) => bag.children.isNotEmpty)) {
|
|
leavesWithParents.addAll(leaf.children.map((child) => child.color));
|
|
}
|
|
allLeaves.addAll(leaves.map((leaf) => leaf.color));
|
|
return allLeaves.difference(leavesWithParents);
|
|
}
|
|
|
|
Bag constructTreeFromTopBag({Bag top, int count, int level = 0}) {
|
|
// var topBag = leaves.firstWhere((bag) => bag.color == top);
|
|
var _newBag = top;
|
|
var _newChildren = <Bag>[];
|
|
// print(''.padLeft(level * 4) + 'Top = $top');
|
|
for (var child in top.children) {
|
|
var _firstChild = leaves.firstWhere((bag) => bag.color == child.color, orElse: () => null);
|
|
var _newChild = Bag.copy(_firstChild);
|
|
if (_newChild != null) {
|
|
_newChild.parent = top;
|
|
_newChild.count = child.count;
|
|
// print(''.padLeft(level * 4) + 'newChild = $_newChild $child');
|
|
_newChildren.add(constructTreeFromTopBag(top: _newChild, level: level + 1));
|
|
}
|
|
}
|
|
_newBag.children = _newChildren;
|
|
// print(''.padLeft(level * 4) + 'newBag = $_newBag');
|
|
return _newBag;
|
|
}
|
|
|
|
List<Bag> findAll({String color, Set<String> tops}) {
|
|
var _bags = <Bag>[];
|
|
|
|
void _find({String findColor, Bag findTop}) {
|
|
if (findTop.color == findColor) _bags.add(findTop);
|
|
for (var child in findTop.children) {
|
|
_find(findColor: findColor, findTop: child);
|
|
}
|
|
}
|
|
|
|
for (var top in tops) {
|
|
var topBag = leaves.firstWhere((bag) => bag.color == top);
|
|
_find(findColor: color, findTop: topBag);
|
|
}
|
|
return _bags;
|
|
}
|
|
|
|
int countContents(Bag top) {
|
|
var _count = 0;
|
|
if (top.children.isEmpty) return 0;
|
|
for (var child in top.children) {
|
|
_count += child.count;
|
|
_count += child.count * countContents(child);
|
|
}
|
|
return _count;
|
|
}
|
|
|
|
@override
|
|
Future<void> a({bool test}) async {
|
|
var mylist = await ReadData.readFile<String>(classString, test: test);
|
|
leaves = []; // Zero out list
|
|
trees = [];
|
|
|
|
for (var line in mylist) {
|
|
parseLine(line);
|
|
}
|
|
|
|
var tops = findTops();
|
|
for (var top in tops) {
|
|
var topBag = leaves.firstWhere((bag) => bag.color == top);
|
|
trees.add(constructTreeFromTopBag(top: topBag));
|
|
}
|
|
// print('Number of Tops = ${tops.length}');
|
|
|
|
var _uniqueParents = <String>{};
|
|
void _setUniqueParents(Bag bag) {
|
|
if (bag.parent != null) {
|
|
_uniqueParents.add(bag.parent.color);
|
|
_setUniqueParents(bag.parent);
|
|
}
|
|
}
|
|
|
|
_uniqueParents = {};
|
|
for (var bag in findAll(color: 'shiny gold', tops: tops)) {
|
|
_setUniqueParents(bag);
|
|
}
|
|
|
|
answerA = _uniqueParents.length;
|
|
}
|
|
|
|
@override
|
|
Future<void> b({bool test}) async {
|
|
var mylist = await ReadData.readFile<String>(classString, test: test);
|
|
leaves = []; // Zero out list
|
|
trees = [];
|
|
|
|
for (var line in mylist) {
|
|
parseLine(line);
|
|
}
|
|
|
|
var tops = findTops();
|
|
for (var top in tops) {
|
|
var topBag = leaves.firstWhere((bag) => bag.color == top);
|
|
trees.add(constructTreeFromTopBag(top: topBag));
|
|
}
|
|
// print('Number of Tops = ${tops.length}');
|
|
|
|
var _bags = findAll(color: 'shiny gold', tops: tops);
|
|
var _shiny = _bags.first;
|
|
|
|
answerB = countContents(_shiny);
|
|
}
|
|
}
|