-
Notifications
You must be signed in to change notification settings - Fork 0
/
day17.c
239 lines (217 loc) · 6.89 KB
/
day17.c
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "htab.h"
#include "lines.h"
#include "subprojects/xxHash-0.6.5/xxhash.h"
typedef struct point {
int x;
int y;
int z;
int w;
list_t ls; /* so that we can store this somewhere */
hash_entry_t ht;
} point_t;
XXH64_hash_t point_hash(int x, int y, int z, int w) {
int hashes[4];
hashes[0] = x;
hashes[1] = y;
hashes[2] = z;
hashes[3] = w;
XXH64_hash_t hash = XXH64(hashes, sizeof(int) * 4, 0);
assert(hash);
return hash;
}
void point_sethash(point_t *p) {
p->ht.hashval = point_hash(p->x, p->y, p->z, p->w);
}
typedef struct pocket_dimension {
point_t * points_; /* for storage */
hash_entry_ptr_t * active_points;
} pocket_dimension_t;
void pocket_dimension_set_active_point(pocket_dimension_t * pd, int x, int y, int z, int w) {
// this entire thing can be an implementation detail.
// create a point
point_t * point = calloc(sizeof(point_t), 1);
point->x = x;
point->y = y;
point->z = z;
point->z = w;
if (!pd->points_) {
pd->points_ = point;
} else {
ls_insert(pd->points_, point);
}
// now we have a handle now make it hashable.
point_sethash(point); // now
ht_insert(pd->active_points, point);
}
void point_clear(point_t * points) {
if (!points) return;
point_clear(list_next(points, point_t));
free(points);
}
void pocket_dimension_clear(pocket_dimension_t *pd){
// clear the points you are holding
point_clear(pd->points_);
// destroy hashtable
hashtable_destroy(pd->active_points);
}
void points_from_lines(lines_t * lines, struct pocket_dimension * pd) {
// only set the active points.
// at the start, z is always zero.
// each line creates n points
int linecount = 0;
int y = 0;
// first figure out how many lines we have
for (lines_t *l = lines; l != NULL; l = list_next(l, lines_t)) {
linecount++;
}
// how wide are the lines?
// we are now ready to create the plane.
// plane_t * plane = plane_make(pd->xmax, pd->ymax, 0);
for (lines_t *l = lines; l != NULL; l = list_next(l, lines_t)) {
if (isspace(l->line[0])) continue; // ignore newlines.
for (int x = 0; !isspace(l->line[x]); x++) {
if (l->line[x] == '#') {
pocket_dimension_set_active_point(pd, x, y, 0, 0);
}
}
y++;
}
}
void pocket_dimension_print(pocket_dimension_t * pd) {
int active_count =0;
for (point_t * p = pd->points_ ; p != NULL ; p = list_next(p, point_t)) {
if(ht_search(pd->active_points, p)) {
active_count++;
}
}
printf("active count: %d\n", active_count);
}
int pocket_dimension_active_neighbors_for_point(pocket_dimension_t * pd, point_t * p) {
// for each of the neighbour of the point check if it is in the hash table of active points and return that
int actives = 0;
for (int x = (p->x-1); x <= (p->x + 1); x++) {
for (int y = (p->y-1); y <= (p->y+1) ; y++) {
for (int z = (p->z -1); z <= (p->z+1); z++) {
for (int w = (p->w -1); w <= (p->w+1); w++) {
if (x == p->x && y == p->y && z == p->z && w == p->w) continue;
XXH64_hash_t h = point_hash(x, y, z, w);
if (ht_searchval(pd->active_points, h)) {
actives++;
}
}
}
}
}
return actives;
}
point_t * point_create(int x, int y, int z, int w) {
point_t * np = calloc(sizeof(point_t), 1);
assert(np);
np->x = x;
np->y = y;
np->z = z;
np->w = w;
point_sethash(np);
return np;
}
void pocket_dimension_cycle(pocket_dimension_t * pd) {
// 1) what are the points to consider/ consider each point and its neighbours. (done)
// 2) collect the list of points to consider by looking at the active points form the previous cycle (done)
// 3) add it to a hash table and check that table, so you do not add duplicates. (done)
// 4) next, for each of those points, apply the rules (based on the old hash table) you can use the function above.
// 5) if the point is inactive, then you remove it from the hash table and list
// 6) if the point is active, you keep it, else you remove it.
// 7) swap the hash table and linked list out.
// point_t * new_points = NULL;
point_t * neighbor_points = NULL;
hash_entry_ptr_t * new_active_points = hashtable_new();
for(point_t * p = pd->points_; p != NULL; p = list_next(p, point_t)) {
if (ht_search(pd->active_points, p)) {
// lets look for its neighbors and add it to the list.
for (int x = p->x-1; x <= p->x + 1; x++) {
for (int y = p->y-1; y <= p->y+1 ; y++) {
for (int z = p->z -1; z <= p->z+1; z++) {
for (int w = p->w -1; w <= p->w+1; w++) {
if (x == p->x && y == p->y && z == p->z && w == p->w) continue;
// create this point, its a neighbour
// create the hash
XXH64_hash_t h = point_hash(x, y, z, w);
if (!ht_searchval(new_active_points, h)) { // every point is added to new active points.
point_t * np = point_create(x,y,z, w);
if (!neighbor_points) {
neighbor_points = np;
} else {
ls_insert(neighbor_points, np);
}
ht_insert(new_active_points, np);
}
}
}
}
}
}
}
// now everything is populated.
point_t * old_point = NULL;
for (point_t * p = neighbor_points; p != NULL ; p = list_next(p, point_t)) {
if (old_point) { // clear out from the previous loop
free(old_point);
old_point = NULL;
}
if (ht_search(pd->active_points, p)) { // an active point, see if 2 or 3 of it's neighbors are also active.
int npt = pocket_dimension_active_neighbors_for_point(pd, p);
if (npt == 2 || npt == 3) {
ht_insert(new_active_points, p);
} else {
ht_delete(new_active_points, p);
ls_remove(neighbor_points, p);
if (p == neighbor_points) { // did we remove the head? update there reference.
neighbor_points = list_next(p, point_t);
}
old_point = p;
}
} else { // not an active point..
if (pocket_dimension_active_neighbors_for_point(pd, p) ==3) {
ht_insert(new_active_points, p);
} else {
ht_delete(new_active_points, p);
list_remove(&neighbor_points->ls, &p->ls);
if (p == neighbor_points) { // did we remove the head? update there reference.
neighbor_points = list_next(p, point_t);
}
old_point = p;
}
}
}
if (old_point) { // clear out from the previous loop
free(old_point);
old_point = NULL;
}
// here is where you need to remove the point. // or predicate with ->active_point.
hashtable_destroy(pd->active_points);
point_clear(pd->points_);
pd->active_points = new_active_points;
pd->points_ = neighbor_points;
}
int main(int argc, char *argv[])
{
lines_t * lines = read_lines("day17_input.txt");
// print_lines(lines);
// read in all the points from the lines
struct pocket_dimension pd = {0};
pd.active_points = hashtable_new();
points_from_lines(lines, &pd);
// pocket_dimension_print(&pd);
for(int i = 0; i < 6 ;i++) {
pocket_dimension_cycle(&pd);
}
pocket_dimension_print(&pd);
pocket_dimension_clear(&pd);
free_lines(lines);
return 0;
}