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  }