this post was submitted on 15 Dec 2024
14 points (93.8% liked)

Advent Of Code

1006 readers
2 users here now

An unofficial home for the advent of code community on programming.dev!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

AoC 2024

Solution Threads

M T W T F S S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 2 years ago
MODERATORS
 

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

you are viewing a single comment's thread
view the rest of the comments
[โ€“] [email protected] 2 points 1 month ago

C#

beautiful

public class Day15 : Solver
{
  private char[][] map;
  private int width, height;
  private string movements;

  public void Presolve(string input) {
    var blocks = input.Trim().Split("\n\n").ToList();
    map = blocks[0].Split("\n").Select(line => line.ToArray()).ToArray();
    width = map[0].Length;
    height = map.Length;
    movements = blocks[1];
  }

  public string SolveFirst() {
    var data = map.Select(row => row.ToArray()).ToArray();
    int robot_x = -1, robot_y = -1;
    for (int i = 0; i < width; i++) {
      for (int j = 0; j < height; j++) {
        if (data[j][i] == '@') {
          robot_x = i;
          robot_y = j;
          data[j][i] = '.';
          break;
        }
      }
    }
    foreach (var m in movements) {
      var (dx, dy) = m switch {
        '^' => (0, -1), '>' => (1, 0), 'v' => (0, 1), '<' => (-1, 0),
          _ => (0, 0)
      };
      if ((dx, dy) == (0, 0)) continue;
      var (x, y) = (robot_x + dx, robot_y + dy);
      if (data[y][x] == '#') continue;
      if (data[y][x] == '.') {
        (robot_x, robot_y) = (x, y);
        continue;
      }
      var (end_of_block_x, end_of_block_y) = (x + dx, y + dy);
      while (data[end_of_block_y][end_of_block_x] == 'O') {
        (end_of_block_x, end_of_block_y) = (end_of_block_x + dx, end_of_block_y + dy);
      }
      if (data[end_of_block_y][end_of_block_x] == '.') {
        data[end_of_block_y][end_of_block_x] = 'O';
        data[y][x] = '.';
        (robot_x, robot_y) = (x, y);
      }
    }
    long answer = 0;
    for (int i = 0; i < width; i++) {
      for (int j = 0; j < height; j++) {
        if (data[j][i] == 'O') {
          answer += i + 100 * j;
        }
      }
    }
    return answer.ToString();
  }

  public string SolveSecond() {
    var expanded_data = map.Select(row => row.SelectMany<char, char>(ch => ch switch {
          '#' => ['#', '#'], 'O' => ['[', ']'], '.' => ['.', '.'], '@' => ['@', '.'] }).ToArray()).ToArray();
    int robot_x = -1, robot_y = -1;
    for (int i = 0; i < width * 2; i++) {
      for (int j = 0; j < height; j++) {
        if (expanded_data[j][i] == '@') {
          robot_x = i;
          robot_y = j;
          expanded_data[j][i] = '.';
          break;
        }
      }
    }
    if (robot_x < 0) throw new InvalidDataException();
    foreach (var m in movements) {
      var (dx, dy) = m switch {
        '^' => (0, -1), '>' => (1, 0), 'v' => (0, 1), '<' => (-1, 0),
          _ => (0, 0)
      };
      if ((dx, dy) == (0, 0)) continue;
      var (x, y) = (robot_x + dx, robot_y + dy);
      if (expanded_data[y][x] == '#') continue;
      if (expanded_data[y][x] == '.') {
        (robot_x, robot_y) = (x, y);
        continue;
      }
      if (dy == 0) {
        var (end_of_block_x, end_of_block_y) = (x + dx * 2, y);
        while (expanded_data[end_of_block_y][end_of_block_x] == '[' ||
               expanded_data[end_of_block_y][end_of_block_x] == ']') {
          (end_of_block_x, end_of_block_y) = (end_of_block_x + dx, end_of_block_y);
        }
        if (expanded_data[end_of_block_y][end_of_block_x] == '.') {
          var (fill_start, fill_end) = dx > 0 ? (x + 1, end_of_block_x) : (end_of_block_x, x);
          for (int fill_x = fill_start; fill_x < fill_end; fill_x += 2) {
            expanded_data[y][fill_x] = '[';
            expanded_data[y][fill_x + 1] = ']';
          }
          expanded_data[y][x] = '.';
          (robot_x, robot_y) = (x, y);
        }
        continue;
      }
      List<(int, int)> boxes_to_move = [(x, y)];
      if (expanded_data[y][x] == ']') {
        boxes_to_move.Add((x - 1, y));
      } else {
        boxes_to_move.Add((x + 1, y));
      }
      List<(int, int)> boxes_move_ordered = [];
      bool impossible = false;
      while (boxes_to_move.Count > 0) {
        HashSet<(int, int)> next_boxes = [];
        foreach (var (box_x, box_y) in boxes_to_move) {
          boxes_move_ordered.Add((box_x, box_y));
          if (expanded_data[box_y + dy][box_x] == '.') continue;
          if (expanded_data[box_y + dy][box_x] == '#') {
            impossible = true;
            break;
          }
          next_boxes.Add((box_x, box_y + dy));
          if (expanded_data[box_y + dy][box_x] == ']') {
            next_boxes.Add((box_x - 1, box_y + dy));
          } else {
            next_boxes.Add((box_x + 1, box_y + dy));
          }
        }
        if (impossible) break;
        boxes_to_move = [..next_boxes];
      }
      if (impossible) continue;
      boxes_move_ordered.Reverse();
      foreach (var (box_x, box_y) in boxes_move_ordered) {
        expanded_data[box_y + dy][box_x] = expanded_data[box_y][box_x];
        expanded_data[box_y][box_x] = '.';
      }
      (robot_x, robot_y) = (x, y);
    }
    long answer = 0;
    for (int i = 0; i < width * 2; i++) {
      for (int j = 0; j < height; j++) {
        if (expanded_data[j][i] == '[') {
          answer += i + 100 * j;
        }
      }
    }
    return answer.ToString();
  }
}