github.com/cycloss/advent-of-code@v0.0.0-20221210145555-15039b95faa6/2021/day12/day12.dart (about) 1 import 'dart:convert'; 2 import 'dart:io'; 3 4 void main() async { 5 var lines = await File("day12.txt") 6 .openRead() 7 .transform(Utf8Decoder()) 8 .transform(LineSplitter()) 9 .toList(); 10 11 var solution = Solution(lines); 12 13 print("Part 1 Solution: ${solution.findRouteCount()}"); 14 solution.allowOneTimeDouble = true; 15 print("Part 2 Solution: ${solution.findRouteCount()}"); 16 } 17 18 class Solution { 19 final Map<String, Node> nodeMap; 20 bool allowOneTimeDouble = false; 21 Solution(List<String> lines) : nodeMap = Parser(lines).generateNodeMap(); 22 23 int findRouteCount() { 24 var emptyRoute = 25 Route(nodeRoute: [], visited: {}, oneSmallVisitedTwice: false); 26 var routes = findAllRoutesFrom(nodeMap['start']!, emptyRoute); 27 // routes.forEach((r) => r.printRoute()); 28 return routes.length; 29 } 30 31 List<Route> findAllRoutesFrom(Node currentNode, Route routeSoFar) { 32 var visited = routeSoFar.nodeAlreadyVisited(currentNode); 33 var visitedTwice = routeSoFar.oneSmallVisitedTwice; 34 if (visited && currentNode.smallCave) { 35 if (!allowOneTimeDouble) { 36 return []; 37 } else { 38 if (currentNode.name == 'start') { 39 return []; 40 } 41 if (routeSoFar.oneSmallVisitedTwice) { 42 return []; 43 } else { 44 visitedTwice = true; 45 } 46 } 47 } 48 49 var copy = routeSoFar.copyAndAdd(currentNode, visitedTwice); 50 if (currentNode.name == 'end') { 51 return [copy]; 52 } 53 var routes = <Route>[]; 54 for (var node in currentNode.connectingNodes) { 55 var nextRoutes = findAllRoutesFrom(node, copy); 56 routes.addAll(nextRoutes); 57 } 58 return routes; 59 } 60 } 61 62 class Parser { 63 Map<String, Node> nodeMap = {}; 64 final List<String> lines; 65 66 Parser(this.lines); 67 68 Map<String, Node> generateNodeMap() { 69 setupNodeMap(); 70 linkNodes(); 71 return nodeMap; 72 } 73 74 void setupNodeMap() { 75 nodeMap = {}; 76 for (var line in lines) { 77 var pair = line.split("-"); 78 processCave(pair[0]); 79 processCave(pair[1]); 80 } 81 } 82 83 void processCave(String cave) { 84 if (!nodeMap.containsKey(cave)) { 85 nodeMap[cave] = Node(smallCave: isSmallCave(cave), name: cave); 86 } 87 } 88 89 static bool isSmallCave(String cave) { 90 return cave == cave.toLowerCase(); 91 } 92 93 void linkNodes() { 94 for (var line in lines) { 95 var pair = line.split("-"); 96 linkPair(pair[0], pair[1]); 97 } 98 } 99 100 void linkPair(String cave1, String cave2) { 101 var node1 = nodeMap[cave1]!; 102 var node2 = nodeMap[cave2]!; 103 node1.connectingNodes.add(node2); 104 node2.connectingNodes.add(node1); 105 } 106 } 107 108 class Node { 109 String name; 110 bool smallCave; 111 List<Node> connectingNodes = []; 112 113 Node({ 114 required this.name, 115 required this.smallCave, 116 }); 117 } 118 119 class Route { 120 List<Node> nodeRoute; 121 Set<Node> visited; 122 bool oneSmallVisitedTwice; 123 Route( 124 {required this.nodeRoute, 125 required this.visited, 126 required this.oneSmallVisitedTwice}); 127 128 Route copyAndAdd(Node node, bool visitedTwice) { 129 var routeCopy = List<Node>.from(nodeRoute); 130 routeCopy.add(node); 131 var setCopy = Set<Node>.from(visited); 132 setCopy.add(node); 133 return Route( 134 nodeRoute: routeCopy, 135 visited: setCopy, 136 oneSmallVisitedTwice: visitedTwice); 137 } 138 139 bool nodeAlreadyVisited(Node node) => visited.contains(node); 140 141 void printRoute() { 142 nodeRoute.forEach((n) { 143 stdout.write("${n.name},"); 144 }); 145 print(""); 146 } 147 }