aboutsummaryrefslogtreecommitdiff
path: root/src/2017/day22/aoc.cpp
blob: 8a70bc856d3cde191dda2304b818d5b1392dc6b0 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "aoc.h"
#include <map>
#include <set>

namespace aoc2017 {

static int radias = 12; // demo 25/2 = 12 input
enum facing {
  f_up,
  f_down,
  f_right,
  f_left,
};

enum virus_state {
  v_clean,
  v_weakened,
  v_infected,
  v_flaged,
  v_unknown,
};

struct vpos {
  int x;
  int y;
  facing f;
};

static vpos turn_right(vpos p) {
  facing fs[4] = {f_right, f_left, f_down, f_up};
  return {p.x, p.y, fs[(int)p.f]};
}

static vpos turn_left(vpos p) {
  facing fs[4] = {f_left, f_right, f_up, f_down};
  return {p.x, p.y, fs[(int)p.f]};
}

static vpos reverse(vpos p) {
  facing fs[4] = {f_down, f_up, f_left, f_right};
  return {p.x, p.y, fs[(int)p.f]};
}

static vpos move(vpos p) {
  vpos vs[4] = {
      {p.x, p.y - 1, p.f},
      {p.x, p.y + 1, p.f},
      {p.x + 1, p.y, p.f},
      {p.x - 1, p.y, p.f},
  };
  return vs[(int)p.f];
}

vpos burst1(std::map<node22, virus_state>& infected, vpos p, int* c) {
  auto it = infected.find({p.x, p.y});
  bool is_infected = it != infected.end();
  // If the current node is infected, it turns to its right. Otherwise, it turns to its left. (Turning is done in-place;
  // the current node does not change.)
  vpos px = is_infected ? turn_right(p) : turn_left(p);

  // If the current node is clean, it becomes infected. Otherwise, it becomes
  // cleaned. (This is done after the node is considered for the purposes of changing direction.) The virus carrier
  if (!is_infected) {
    infected.insert({{p.x, p.y}, v_infected});
    *c += 1;
  } else {
    infected.erase(it);
  }

  // moves forward one node in the direction it is facing.
  px = move(px);
  return px;
}

vpos burst2(std::map<node22, virus_state>& nodes, vpos p, int* c) {
  // 1. Decide which way to turn based on the current node:
  // If it is clean, it turns left.
  // If it is weakened, it does not turn, and will continue moving in the same direction.
  // If it is infected, it turns right.
  // If it is flagged, it reverses direction, and will go back the way it came.
  auto it = nodes.find({p.x, p.y});
  virus_state s{v_unknown};
  if (it == nodes.end()) {
    s = v_clean;
    p = turn_left(p);
  } else {
    s = it->second;
    if (s == v_infected) {
      p = turn_right(p);
    }
    if (s == v_flaged) {
      p = reverse(p);
    }
  }

  // 2. Modify the state of the current node, as described below.
  // Clean nodes become weakened.
  // Weakened nodes become infected.
  // Infected nodes become flagged.
  // Flagged nodes become clean.
  if (s == v_clean) {
    nodes.insert({{p.x, p.y}, v_weakened});
  } else {
    if (s == v_weakened) {
      *c += 1;
      it->second = v_infected;
    }

    if (s == v_infected) {
      it->second = v_flaged;
    }

    if (s == v_flaged) {
      nodes.erase(it);
    }
  }

  // 3. The virus carrier moves forward one node in the direction it is facing.
  p = move(p);
  return p;
}

static void load(std::map<node22, virus_state>& is, int r, line_view lv) {
  const char* p = lv.line;
  int x = 0;
  while (*(p + x) != '\n') {
    if (*(p + x) == '#') {
      node22 n{x - radias, r - radias};
      is.insert({n, v_infected});
    }
    x++;
  }
}

static void part1(std::map<node22, virus_state> nodes, int* c) {
  vpos p{0, 0, f_up};
  for (int i = 0; i < 10000; i++) {
    p = burst1(nodes, p, c);
  }
}

static void part2(std::map<node22, virus_state> nodes, int* c) {
  vpos p{0, 0, f_up};
  for (int i = 0; i < 10000000; i++) {
    p = burst2(nodes, p, c);
  }
}

std::pair<int64_t, int64_t> day22(line_view file) {
  std::map<node22, virus_state> nodes;

  int r{0};
  per_line(file, [&r, &nodes](line_view lv) {
    load(nodes, r++, lv);
    return true;
  });

  int t0{0}, t1{0};
  part1(nodes, &t0);
  part2(nodes, &t1);

  // for (auto& n : infected) {
  //   printf("%d,%d\n", n.x, n.y);
  // }
  return {t0, t1};
}

} // namespace aoc2017