Day 15: Warehouse Woes

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • mykl@lemmy.world
    link
    fedilink
    arrow-up
    2
    ·
    edit-2
    9 days ago

    Dart

    canMove does a recursive search and returns all locations that need moving, or none if there’s an obstacle anywhere downstream. For part2, that involves checking if there’s half of a box in front of us, and if so ensuring that we also check the other half of that box. I don’t bother tracking whether we’re double-checking as it runs fast enough as is.

    import 'dart:math';
    import 'package:collection/collection.dart';
    import 'package:more/more.dart';
    
    var d4 = <Point<num>>[Point(1, 0), Point(-1, 0), Point(0, 1), Point(0, -1)];
    var m4 = '><v^';
    
    solve(List<String> lines, {wide = false}) {
      if (wide) {
        lines = lines
            .map((e) => e
                .replaceAll('#', '##')
                .replaceAll('.', '..')
                .replaceAll('O', '[]')
                .replaceAll('@', '@.'))
            .toList();
      }
      var room = {
        for (var r in lines.takeWhile((e) => e.isNotEmpty).indexed())
          for (var c in r.value.split('').indexed().where((c) => (c.value != '.')))
            Point<num>(c.index, r.index): c.value
      };
      var bot = room.entries.firstWhere((e) => e.value == '@').key;
      var moves = lines.skipTo('').join('').split('');
      for (var d in moves.map((m) => d4[m4.indexOf(m)])) {
        if (didMove(d, bot, room)) bot += d;
      }
      return room.entries
          .where((e) => e.value == '[' || e.value == 'O')
          .map((e) => e.key.x + 100 * e.key.y)
          .sum;
    }
    
    bool didMove(Point m, Point here, Map<Point, String> room) {
      var moves = canMove(m, here, room).toSet();
      if (moves.isNotEmpty) {
        var vals = moves.map((e) => room.remove(e)!).toList();
        for (var ms in moves.indexed()) {
          room[ms.value + m] = vals[ms.index];
        }
        return true;
      }
      return false;
    }
    
    List<Point> canMove(Point m, Point here, Map<Point, String> room) {
      if (room[here + m] == '#') return [];
      if (!room.containsKey(here + m)) return [here];
      var cm1 = canMove(m, here + m, room);
      if (m.x != 0) return (cm1.isEmpty) ? [] : cm1 + [here];
    
      List<Point> cm2 = [here];
      if (room[here + m] == '[') cm2 = canMove(m, here + m + Point(1, 0), room);
      if (room[here + m] == ']') cm2 = canMove(m, here + m - Point(1, 0), room);
    
      return cm1.isEmpty || cm2.isEmpty ? [] : cm1 + cm2 + [here];
    }