Advertisement
mykdavies

AOC 2022 Day 24

Dec 24th, 2022 (edited)
1,399
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 3.53 KB | None | 0 0
  1. /// Move round a map avoiding blizzards
  2. /// 1) once
  3. /// 2) there and back and there again
  4.  
  5. import 'dart:collection';
  6. import 'dart:math';
  7.  
  8. import 'package:more/more.dart';
  9.  
  10. class Point3 {
  11.   final int x, y, z;
  12.   const Point3(this.x, this.y, this.z);
  13.   Point3 operator +(Point3 o) => Point3(o.x + x, o.y + y, o.z + z);
  14.   bool get isInBounds =>
  15.       Point(x, y) == start ||
  16.       Point(x, y) == end ||
  17.       x.between(0, width - 1) &&
  18.           y.between(0, height - 1); //don't worry about time dimension
  19.   @override
  20.   int get hashCode => Object.hash(x, y, z);
  21.   @override
  22.   bool operator ==(Object o) => o is Point3 && o.x == x && o.y == y && o.z == z;
  23. }
  24.  
  25. class Blizzard {
  26.   Point<int> pos, dir;
  27.   Blizzard(this.pos, this.dir);
  28.   move() => pos = Point((pos.x + dir.x) % width, (pos.y + dir.y) % height);
  29. }
  30.  
  31. const headings = {
  32.   'N': Point3(0, -1, 1),
  33.   'W': Point3(-1, 0, 1),
  34.   'E': Point3(1, 0, 1),
  35.   'S': Point3(0, 1, 1),
  36.   'F': Point3(0, 0, 1), // just sit here for a round
  37.   //'B': Point3(0, 0, -1) Can't go back in time!
  38. };
  39. var n6 = headings.values;
  40.  
  41. const bDirs = {
  42.   '^': Point(0, -1),
  43.   '<': Point(-1, 0),
  44.   '>': Point(1, 0),
  45.   'v': Point(0, 1),
  46. };
  47.  
  48. var cameFrom = <Point3, Point3>{};
  49. // Returns map of Points examined and their distances from the start.
  50. Map<Point3, int> dijkstra(Point3 start, Point<int> end) {
  51.   cameFrom = {start: Point3(-1, -1, -1)};
  52.   var bestCost = {start: 0};
  53.   var frontier = ListQueue<Point3>();
  54.   frontier.add(start);
  55.   while (frontier.isNotEmpty) {
  56.     var here = frontier.removeFirst();
  57.     if (here.x == end.x && here.y == end.y) break;
  58.     var ns =
  59.         n6.map((e) => here + e).where((e) => e.isInBounds && !isBlocked(e));
  60.     for (var next in ns) {
  61.       var newCost = bestCost[here]! + 1;
  62.       if (!bestCost.containsKey(next) || newCost < bestCost[next]!) {
  63.         bestCost[next] = newCost;
  64.         frontier.add(next);
  65.         cameFrom[next] = here;
  66.       }
  67.     }
  68.   }
  69.   return bestCost;
  70. }
  71.  
  72. isBlocked(Point3 p3) => blocks.contains(Point3(p3.x, p3.y, p3.z % duration));
  73.  
  74. void buildBlocks(List<String> lines) {
  75.   var bs = lines.map((e) => e.split('')).toList();
  76.   height = bs.length - 2;
  77.   width = bs.first.length - 2;
  78.   start = Point(bs.first.indexOf('.') - 1, -1);
  79.   end = Point(bs.last.indexOf('.') - 1, height);
  80.   var blizzards = <Blizzard>{};
  81.   for (var y in 1.to(bs.length - 1)) {
  82.     for (var x in 1.to(bs.first.length - 1).where((x) => bs[y][x] != '.')) {
  83.       // Don't ever need to look at the walls, so offset the co-ords by 1.
  84.       blizzards.add(Blizzard(Point(x - 1, y - 1), bDirs[bs[y][x]]!));
  85.     }
  86.   }
  87.   // Blizzards will all cycle after this time.
  88.   duration = width.lcm(height);
  89.   blocks = <Point3>{};
  90.   for (var t in 0.to(duration)) {
  91.     for (var b in blizzards) {
  92.       blocks.add(Point3(b.pos.x, b.pos.y, t));
  93.       b.move();
  94.     }
  95.   }
  96. }
  97.  
  98. late int height, width;
  99. late Point<int> start, end;
  100. late Set<Point3> blocks;
  101. var duration = 1000;
  102.  
  103. part1(List<String> lines) {
  104.   buildBlocks(lines);
  105.   var pp = dijkstra(Point3(start.x, start.y, 0), end);
  106.   return pp.keys.firstWhere((e) => e.x == end.x && e.y == end.y).z;
  107. }
  108.  
  109. part2(List<String> lines) {
  110.   buildBlocks(lines);
  111.   var pp = dijkstra(Point3(start.x, start.y, 0), end);
  112.   var t = pp.keys.firstWhere((e) => e.x == end.x && e.y == end.y).z;
  113.   pp = dijkstra(Point3(end.x, end.y, t), start);
  114.   t = pp.keys.firstWhere((e) => e.x == start.x && e.y == start.y).z;
  115.   pp = dijkstra(Point3(start.x, start.y, t), end);
  116.   t = pp.keys.firstWhere((e) => e.x == end.x && e.y == end.y).z;
  117.   return t;
  118. }
  119.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement