aboutsummaryrefslogtreecommitdiff
path: root/src/2016/day17/aoc.cpp
blob: dee844c16a28549b8e7ddcdf4a25f95e031f53d0 (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "aoc.h"
#include "md5.h"
#include <deque>
#include <map>
#include <set>

namespace aoc2016 {

struct pos {
  int x;
  int y;
  int n;
  std::string* path;

  bool operator==(pos p) { return x == p.x && y == p.y; }
  friend bool operator<(pos p1, pos p2) { return p1.x < p2.x ? true : p1.x > p2.x ? false : p1.y < p2.y; }
  bool isvalid() const noexcept { return x > 0 && x < 5 && y > 0 && y < 5; }
};

static pos bfs(pos p, pos target, const std::string& passcode) {
  std::deque<pos> q;
  // std::set<pos> visited;
  q.push_back(p);

  auto is_open = [](char c) { return c > 'a' && c <= 'f'; };
  while (!q.empty()) {
    auto s = q.size();
    while (s-- > 0) {
      pos p0 = q.front();
      q.pop_front();
      if (p0 == target) {
        return p0;
      }

      pos ns[4] = {
          {p0.x, p0.y - 1, p0.n + 1, new std::string(*p0.path)},
          {p0.x, p0.y + 1, p0.n + 1, new std::string(*p0.path)},
          {p0.x - 1, p0.y, p0.n + 1, new std::string(*p0.path)},
          {p0.x + 1, p0.y, p0.n + 1, new std::string(*p0.path)},
      };

      for (size_t i = 0; i < 4; i++) {
        pos nx = ns[i];
        std::string pass{passcode};
        pass.append(*nx.path);
        char md5[33] = {0};
        memcpy(md5, md5sum((char*)pass.c_str()), 32);
        // printf("%s: %d %d %d %s\n", md5, p0.x, p0.y, p0.n, (*p0.path).c_str());
        if (nx.isvalid() && is_open(*(md5 + i))) {
          char direction[] = {'U', 'D', 'L', 'R'};
          nx.path->push_back(direction[i]);
          q.push_back(nx);
        }
      }
    }
  }

  return target;
}

static void dfs(pos p0, pos target, const std::string& passcode, int* max) {
  if (p0 == target) {
    if (*max < p0.n) {
      *max = p0.n;
    }
  } else {
    pos ns[4] = {
        {p0.x, p0.y - 1, p0.n + 1, new std::string(*p0.path)},
        {p0.x, p0.y + 1, p0.n + 1, new std::string(*p0.path)},
        {p0.x - 1, p0.y, p0.n + 1, new std::string(*p0.path)},
        {p0.x + 1, p0.y, p0.n + 1, new std::string(*p0.path)},
    };

    auto is_open = [](char c) { return c > 'a' && c <= 'f'; };
    for (size_t i = 0; i < 4; i++) {
      pos nx = ns[i];
      std::string pass{passcode};
      pass.append(*nx.path);
      char md5[33] = {0};
      memcpy(md5, md5sum((char*)pass.c_str()), 32);
      if (nx.isvalid() && is_open(*(md5 + i))) {
        char direction[] = {'U', 'D', 'L', 'R'};
        nx.path->push_back(direction[i]);
        dfs(nx, target, passcode, max);
      }
    }
  }
}

std::pair<std::string, int64_t> day17(line_view) {
  static std::string ss[] = {"", "UNKNOWN"};
  pos b = {1, 1, 0, ss};
  pos e = {4, 4, INT32_MAX, ss + 1};

  auto p = bfs(b, e, "bwnlcvfs");
  int max{INT32_MIN};
  dfs(b, e, "bwnlcvfs", &max);

  return {*p.path, max};
}
} // namespace aoc2016