C: 2020 day 24 part 2 (dirty code)
This commit is contained in:
@@ -16,6 +16,11 @@
|
|||||||
* a new list after each process.
|
* a new list after each process.
|
||||||
* So we will rely on a hashtable, which will allow to quickly find a
|
* So we will rely on a hashtable, which will allow to quickly find a
|
||||||
* given point.
|
* given point.
|
||||||
|
* We use here two hash-tables: One for the current situation(cur), one
|
||||||
|
* for the next step (next); between steps, we clean cur and memcopy next
|
||||||
|
* to cur. It would be much better to swap hashtable pointers, but I wanted
|
||||||
|
* to use the hashtable.h API, where HASH_BITS() and HASH_SIZE() have to be
|
||||||
|
* macros (calculated during compilation; pointers not allowed here).
|
||||||
*/
|
*/
|
||||||
typedef union coord {
|
typedef union coord {
|
||||||
u64 val;
|
u64 val;
|
||||||
@@ -26,24 +31,27 @@ typedef union coord {
|
|||||||
|
|
||||||
typedef struct point {
|
typedef struct point {
|
||||||
coord_t pos;
|
coord_t pos;
|
||||||
|
int count;
|
||||||
struct hlist_node coll; /* entry in hash table */
|
struct hlist_node coll; /* entry in hash table */
|
||||||
struct list_head all;
|
struct list_head all;
|
||||||
} point_t;
|
} point_t;
|
||||||
|
|
||||||
#define HBITS 12 /* in bits: 12 bits = 4096 */
|
#define HBITS 9 /* in bits: 12 bits = 4096 */
|
||||||
#define HSIZE (1 << HBITS)
|
//#define HSIZE (1 << HBITS)
|
||||||
|
|
||||||
DEFINE_HASHTABLE(hash1, HBITS);
|
DEFINE_HASHTABLE(hasht_cur, HBITS);
|
||||||
DEFINE_HASHTABLE(hash2, HBITS);
|
DEFINE_HASHTABLE(hasht_count, HBITS);
|
||||||
struct hlist_head *cur = hash1, *next = hash2;
|
|
||||||
|
|
||||||
pool_t *pt_pool;
|
pool_t *pt_pool;
|
||||||
|
|
||||||
static __always_inline u32 hash(coord_t p)
|
static __always_inline u32 hash(coord_t p)
|
||||||
{
|
{
|
||||||
return hash_64(p.val, HBITS);
|
return hash_64(p.val, HASH_BITS(hasht_cur));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_point - find point in hashtable
|
||||||
|
*/
|
||||||
static point_t *find_point(struct hlist_head *head, coord_t p)
|
static point_t *find_point(struct hlist_head *head, coord_t p)
|
||||||
{
|
{
|
||||||
point_t *point;
|
point_t *point;
|
||||||
@@ -54,21 +62,29 @@ static point_t *find_point(struct hlist_head *head, coord_t p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static point_t *add_point(struct hlist_head *p, coord_t pos)
|
/**
|
||||||
|
* add_point - add point in hasht_count hashtable (used to count neighbours)
|
||||||
|
*/
|
||||||
|
static point_t *add_point(coord_t pos)
|
||||||
{
|
{
|
||||||
point_t *new;
|
point_t *new;
|
||||||
u32 h;
|
u32 h;
|
||||||
|
|
||||||
h = hash(pos);
|
h = hash(pos);
|
||||||
if (!(new = find_point(p + h, pos))) {
|
if (!(new = find_point(&hasht_count[h], pos))) {
|
||||||
new = pool_get(pt_pool);
|
new = pool_get(pt_pool);
|
||||||
new->pos.val = pos.val;
|
new->pos.val = pos.val;
|
||||||
hlist_add_head(&new->coll, p + h);
|
new->count = 0;
|
||||||
|
hlist_add_head(&new->coll, &hasht_count[h]);
|
||||||
}
|
}
|
||||||
|
new->count++;
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
static point_t *flip_point(struct hlist_head *p, coord_t pos)
|
/**
|
||||||
|
* flip_point - add point in hasht_cur hashtable, remove if it exists (init)
|
||||||
|
*/
|
||||||
|
static point_t *flip_point(coord_t pos)
|
||||||
{
|
{
|
||||||
point_t *new;
|
point_t *new;
|
||||||
u32 h;
|
u32 h;
|
||||||
@@ -76,7 +92,7 @@ static point_t *flip_point(struct hlist_head *p, coord_t pos)
|
|||||||
log_f(3, "val=%lu x=%d y=%d ", pos.val, pos.x, pos.y);
|
log_f(3, "val=%lu x=%d y=%d ", pos.val, pos.x, pos.y);
|
||||||
h = hash(pos);
|
h = hash(pos);
|
||||||
log(3, "hash=%d ", h);
|
log(3, "hash=%d ", h);
|
||||||
if ((new = find_point(p + h, pos))) {
|
if ((new = find_point(&hasht_cur[h], pos))) {
|
||||||
log(3, "removing tile\n");
|
log(3, "removing tile\n");
|
||||||
hlist_del(&new->coll);
|
hlist_del(&new->coll);
|
||||||
pool_add(pt_pool, new);
|
pool_add(pt_pool, new);
|
||||||
@@ -85,23 +101,125 @@ static point_t *flip_point(struct hlist_head *p, coord_t pos)
|
|||||||
log(3, "adding tile\n");
|
log(3, "adding tile\n");
|
||||||
new = pool_get(pt_pool);
|
new = pool_get(pt_pool);
|
||||||
new->pos.val = pos.val;
|
new->pos.val = pos.val;
|
||||||
hlist_add_head(&new->coll, p + h);
|
new->count = 0;
|
||||||
|
hlist_add_head(&new->coll, &hasht_cur[h]);
|
||||||
}
|
}
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_points(struct hlist_head *h)
|
/**
|
||||||
|
* count_black - count elements in hasht_cur
|
||||||
|
*/
|
||||||
|
static int count_black()
|
||||||
{
|
{
|
||||||
point_t *cur;
|
point_t *cur;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
for (int bkt = 0; bkt < HSIZE; ++bkt) {
|
ulong bucket;
|
||||||
hlist_for_each_entry(cur, &h[bkt], coll) {
|
|
||||||
|
hash_for_each(hasht_cur, bucket, cur, coll)
|
||||||
res++;
|
res++;
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reset_hasht_count - remove all points from hasht_count hashtable.
|
||||||
|
*/
|
||||||
|
static void reset_hasht_count()
|
||||||
|
{
|
||||||
|
point_t *cur;
|
||||||
|
struct hlist_node *tmp;
|
||||||
|
u32 bucket;
|
||||||
|
int count = 0;
|
||||||
|
hash_for_each_safe(hasht_count, bucket, tmp, cur, coll) {
|
||||||
|
hlist_del(&cur->coll);
|
||||||
|
pool_add(pt_pool, cur);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
printf("removed %d counts\n", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move_next_cur - move hasht_next to hasht_cur
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
static void move_next_cur()
|
||||||
|
{
|
||||||
|
release_hasht_cur();
|
||||||
|
memcpy(hasht_cur, hasht_next, sizeof(hasht_next));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const coord_t neighbours [] = {
|
||||||
|
{ .x = 2, .y = 0 }, { .x = -2, .y = 0 }, /* east and west */
|
||||||
|
{ .x = 1, .y = -1}, { .x = 1, .y = 1 }, /* SE and NE */
|
||||||
|
{ .x = -1, .y = -1}, { .x = -1, .y = 1 } /* SW and NW */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* count_neighbours - count hasht_cur neighbours, result in hasht_next
|
||||||
|
*/
|
||||||
|
static void count_neighbours()
|
||||||
|
{
|
||||||
|
point_t *cur;
|
||||||
|
u32 bucket;
|
||||||
|
|
||||||
|
hash_for_each(hasht_cur, bucket, cur, coll) {
|
||||||
|
for (ulong i = 0; i < ARRAY_SIZE(neighbours); ++i) {
|
||||||
|
coord_t neigh = cur->pos;
|
||||||
|
neigh.x += neighbours[i].x;
|
||||||
|
neigh.y += neighbours[i].y;
|
||||||
|
add_point(neigh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hash_for_each(hasht_count, bucket, cur, coll) {
|
||||||
|
log(3, "(%d,%d)=%d ", cur->pos.x, cur->pos.y, cur->count);
|
||||||
|
u32 h = hash(cur->pos);
|
||||||
|
point_t *tmp = find_point(&hasht_count[h], cur->pos);
|
||||||
|
if (tmp != cur)
|
||||||
|
log(3, "err:%p!=%p ", cur, tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adjust_neighbours - adjust hasht_next according to rules
|
||||||
|
*/
|
||||||
|
static void adjust_neighbours()
|
||||||
|
{
|
||||||
|
point_t *pt_cur, *pt_count;
|
||||||
|
u32 bucket;
|
||||||
|
struct hlist_node *tmp;
|
||||||
|
|
||||||
|
/* 1) check hasht_cur tiles (currently black)
|
||||||
|
*/
|
||||||
|
hash_for_each_safe(hasht_cur, bucket, tmp, pt_cur, coll) {
|
||||||
|
int h = hash(pt_cur->pos);
|
||||||
|
point_t *pt_count = find_point(&hasht_count[h], pt_cur->pos);
|
||||||
|
if (!pt_count || pt_count->count > 2) {
|
||||||
|
log(3, "P1 removing %d (%d,%d)\n", pt_count? pt_count->count: 0,
|
||||||
|
pt_cur->pos.x, pt_cur->pos.y);
|
||||||
|
hlist_del(&pt_cur->coll);
|
||||||
|
pool_add(pt_pool, pt_cur);
|
||||||
|
} else {
|
||||||
|
log(3, "P1 keeping %d (%d,%d)\n", pt_count? pt_count->count: 0,
|
||||||
|
pt_cur->pos.x, pt_cur->pos.y);
|
||||||
|
}
|
||||||
|
/* we do not want to re-consider this point in next loop
|
||||||
|
*/
|
||||||
|
if (pt_count) {
|
||||||
|
hlist_del(&pt_count->coll);
|
||||||
|
pool_add(pt_pool, pt_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 2) check remaining points in hasht_next (currently white)
|
||||||
|
*/
|
||||||
|
hash_for_each_safe(hasht_count, bucket, tmp, pt_count, coll) {
|
||||||
|
if (pt_count->count == 2) {
|
||||||
|
hash_del(&pt_count->coll);
|
||||||
|
hash_add(hasht_cur, &pt_count->coll, hash(pt_count->pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void parse()
|
static void parse()
|
||||||
{
|
{
|
||||||
size_t alloc;
|
size_t alloc;
|
||||||
@@ -115,19 +233,10 @@ static void parse()
|
|||||||
char *c = buf;
|
char *c = buf;
|
||||||
while (*c) {
|
while (*c) {
|
||||||
switch (*c) {
|
switch (*c) {
|
||||||
case 'e':
|
case 'e': ++p.x; break;
|
||||||
++p.x;
|
case 'w': --p.x; break;
|
||||||
break;
|
case 's': --p.y; ++c; break;
|
||||||
case 'w':
|
case 'n': ++p.y; ++c;
|
||||||
--p.x;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
--p.y;
|
|
||||||
++c;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
++p.y;
|
|
||||||
++c;
|
|
||||||
}
|
}
|
||||||
if (*c == 'e')
|
if (*c == 'e')
|
||||||
++p.x;
|
++p.x;
|
||||||
@@ -136,7 +245,7 @@ static void parse()
|
|||||||
c++;
|
c++;
|
||||||
//printf("pos=%ld x=%d y=%d\n", c - buf, p.x, p.y);
|
//printf("pos=%ld x=%d y=%d\n", c - buf, p.x, p.y);
|
||||||
}
|
}
|
||||||
flip_point(cur, p);
|
flip_point(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +260,7 @@ int main(ac, av)
|
|||||||
char **av;
|
char **av;
|
||||||
{
|
{
|
||||||
int opt, part = 1;
|
int opt, part = 1;
|
||||||
ulong res = 0;
|
int res = 0;
|
||||||
|
|
||||||
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -165,10 +274,20 @@ int main(ac, av)
|
|||||||
return usage(*av);
|
return usage(*av);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pt_pool = pool_create("pool_points", 256, sizeof(point_t));
|
pt_pool = pool_create("pool_points", 512, sizeof(point_t));
|
||||||
|
|
||||||
parse();
|
parse();
|
||||||
printf("count=%d\n", count_points(cur));
|
printf("initial count = %d\n", count_black());
|
||||||
printf("%s : res=%lu\n", *av, res);
|
if (part == 2) {
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
reset_hasht_count();
|
||||||
|
count_neighbours();
|
||||||
|
adjust_neighbours();
|
||||||
|
printf("count after loop %d = %d\n", i + 1, count_black());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = count_black();
|
||||||
|
printf("size=%lu\n", sizeof(hasht_count));
|
||||||
|
printf("%s : res=%d\n", *av, res);
|
||||||
|
pool_stats(pt_pool);
|
||||||
exit (0);
|
exit (0);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user