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
|
#pragma once
#include "common.h"
namespace aoc2015 {
struct Bit;
template <typename T, size_t N>
struct store;
template <size_t N>
struct store<int8_t, N> {
int8_t pool[N * N] = {0};
void toggle(int x, int y) { pool[y * N + x] += 2; }
void set(int x, int y) { pool[y * N + x] += 1; }
void reset(int x, int y) {
if (pool[y * N + x] > 0) {
pool[y * N + x] -= 1;
}
}
int count() const noexcept {
int total{0};
for (auto i : pool) {
total += i;
}
return total;
}
};
template <size_t N>
struct store<Bit, N> {
constexpr static size_t size = N * N / 64 + 1;
uint64_t pool[size] = {0};
void set(int x, int y) {
uint64_t p = y * N + x;
uint64_t r = p >> 6;
uint64_t c = p & 63;
uint64_t& byte = pool[r];
uint64_t mask = 1ll << c;
byte |= mask;
}
void reset(int x, int y) {
uint64_t p = y * N + x;
uint64_t r = p >> 6;
uint64_t c = p & 63;
uint64_t& byte = pool[r];
uint64_t mask = ~(1ll << c);
byte &= mask;
}
void toggle(int x, int y) {
uint64_t p = y * N + x;
uint64_t r = p >> 6;
uint64_t c = p & 63;
uint64_t& byte = pool[r];
uint64_t mask = 1ll << c;
byte ^= mask;
}
int count() const noexcept {
int total = 0;
for (uint64_t i : pool) {
total += __builtin_popcountll(i);
}
return total;
}
};
template <typename T, size_t N>
struct grid {
struct unit {
int x;
int y;
};
store<T, N> store_;
template <typename F, typename... Args>
void traverse(unit u1, unit u2, F&& f, Args&&... args) {
for (int i = u1.x; i <= u2.x; i++) {
for (int j = u1.y; j <= u2.y; j++) {
f(i, j, std::forward<Args>(args)...);
}
}
}
void turn_on(unit u1, unit u2) {
traverse(u1, u2, [this](int i, int j) { store_.set(i, j); });
}
void turn_off(unit u1, unit u2) {
traverse(u1, u2, [this](int i, int j) { store_.reset(i, j); });
}
void toggle(unit u1, unit u2) {
traverse(u1, u2, [this](int i, int j) { store_.toggle(i, j); });
}
std::pair<unit, unit> parse(const char* p1, const char* p2) {
unit u1;
unit u2;
int* is[] = {&u1.x, &u1.y, &u2.x, &u2.y};
int i = 0;
const char* p = p1;
while (i < 4 && p < p2) {
int x = 0;
while (*p >= '0' && *p <= '9') {
x = x * 10 + *p - '0';
p++;
}
*is[i++] = x;
while (*p < '0' || *p > '9') {
p++;
}
}
return {u1, u2};
}
void parse(line_view lv) {
static struct _ {
void (grid::*action)(unit, unit);
const char* key;
} keywords[] = {{&grid::toggle, "toggle"}, {&grid::turn_off, "turn off"}, {&grid::turn_on, "turn on"}};
for (auto k : keywords) {
if (lv.contains(k.key)) {
const char* p1 = lv.line + strlen(k.key) + 1;
const char* p2 = lv.line + lv.length;
auto p = parse(p1, p2);
(this->*k.action)(p.first, p.second);
break;
}
}
}
};
std::pair<int,int> day6(line_view);
} // namespace aoc2015
|