import 'package:aoc2020/aocbase.dart'; import 'package:aoc2020/model/readdata.dart'; class Bag { final String color; int count; Bag parent; List children; Bag({this.color, this.parent, this.count, List 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 leaves; List 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 findTops() { var leavesWithParents = {}; var allLeaves = {}; 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 = []; // 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 findAll({String color, Set tops}) { var _bags = []; 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 a({bool test}) async { var filename = (test ?? false) ? classStringTest : classString; var mylist = await ReadData.readFileString(filename); 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 = {}; 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 b({bool test}) async { var filename = (test ?? false) ? classStringTest : classString; var mylist = await ReadData.readFileString(filename); 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); } }