166 lines
3.8 KiB
C
166 lines
3.8 KiB
C
/* ex1-c: Advent2020 game, day 17/game 1
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include "list.h"
|
|
|
|
#define LOOPS 6
|
|
#define MAXINIT 8
|
|
#define SIZE ((2*LOOPS)+MAXINIT)
|
|
#define ZERO (SIZE/2)
|
|
|
|
#define ACTIVE '#'
|
|
#define INACTIVE '.'
|
|
|
|
typedef struct cell {
|
|
char state;
|
|
char oldstate;
|
|
bool visited; /* redundant ? */
|
|
unsigned count; /* active neighbors */
|
|
// for runs, we don't care unused cells
|
|
struct list_head set; /* current actives */
|
|
struct list_head viewed; /* current visited */
|
|
} CELL;
|
|
|
|
LIST_HEAD(qset);
|
|
LIST_HEAD(qviewed);
|
|
|
|
static CELL cube[SIZE][SIZE][SIZE];
|
|
|
|
#define CUBE2X(cell) (((cell)-&cube[0][0][0])/SIZE/SIZE)
|
|
#define CUBE2Y(cell) (((cell)-&cube[0][0][0])/SIZE%SIZE)
|
|
#define CUBE2Z(cell) (((cell)-&cube[0][0][0])/(SIZE/SIZE)%SIZE)
|
|
|
|
#define HEADRESET(elt) { \
|
|
(elt)->next=POISON_POINTER1;(elt)->prev=POISON_POINTER1; }
|
|
|
|
|
|
static void reset_cell(CELL *pcell)
|
|
{
|
|
pcell->state=INACTIVE;
|
|
pcell->oldstate=INACTIVE;
|
|
pcell->visited=false;
|
|
pcell->count=0;
|
|
}
|
|
|
|
static void reset_cube()
|
|
{
|
|
int i, j, k;
|
|
|
|
for (i=0; i<SIZE; ++i)
|
|
for (j=0; j<SIZE; ++j)
|
|
for (k=0; k<SIZE; ++k)
|
|
reset_cell(&cube[i][j][k]);
|
|
}
|
|
|
|
static int count_active()
|
|
{
|
|
struct list_head *p;
|
|
int i=0;
|
|
|
|
list_for_each(p, &qset) {
|
|
++i;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static void init_row(char *line, int row)
|
|
{
|
|
int i, x, y, z;
|
|
static int ncols=0;
|
|
CELL *pcell;
|
|
|
|
if (ncols == 0)
|
|
ncols=strlen(line)-1;
|
|
y=ZERO-ncols/2+row;
|
|
z=ZERO;
|
|
|
|
for (i=0; *line; ++i, ++line) {
|
|
x=ZERO+i-ncols/2;
|
|
pcell=&cube[x][y][z];
|
|
if (*line == '#') {
|
|
list_add(&pcell->set, &qset);
|
|
list_add(&pcell->viewed, &qviewed);
|
|
pcell->state=ACTIVE;
|
|
pcell->visited=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void run_life()
|
|
{
|
|
struct cell *pcell, *ptmp;
|
|
int x, y, z, x1, y1, z1;
|
|
|
|
/* 1) count +1 for neighbors */
|
|
list_for_each_entry(pcell, &qset, set) {
|
|
x=CUBE2X(pcell);
|
|
y=CUBE2Y(pcell);
|
|
z=CUBE2Z(pcell);
|
|
for (x1=x-1; x1<=x+1; x1++) {
|
|
for (y1=y-1; y1<=y+1; y1++) {
|
|
for (z1=z-1; z1<=z+1; z1++) {
|
|
if ((x1!=x || y1!=y || z1!=z)) {
|
|
ptmp=&cube[x1][y1][z1];
|
|
++ptmp->count;
|
|
if (!ptmp->visited) {
|
|
list_add(&ptmp->viewed, &qviewed);
|
|
ptmp->visited=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
list_for_each_entry_safe(pcell, ptmp, &qviewed, viewed) {
|
|
switch (pcell->state) {
|
|
case ACTIVE:
|
|
if (pcell->count != 2 && pcell->count != 3) {
|
|
list_del(&pcell->set);
|
|
pcell->state=INACTIVE;
|
|
pcell->visited=0;
|
|
}
|
|
break;
|
|
case INACTIVE:
|
|
if (pcell->count == 3) {
|
|
list_add(&pcell->set, &qset);
|
|
pcell->state=ACTIVE;
|
|
pcell->visited=1;
|
|
}
|
|
break;
|
|
}
|
|
pcell->count=0;
|
|
if (pcell->state == INACTIVE) {
|
|
pcell->visited=0;
|
|
list_del(&pcell->viewed);
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
char line[16];
|
|
int nline=0;
|
|
|
|
reset_cube();
|
|
INIT_LIST_HEAD(&qset);
|
|
INIT_LIST_HEAD(&qviewed);
|
|
|
|
while (fgets(line, sizeof line, stdin)) {
|
|
init_row(line, nline);
|
|
nline++;
|
|
}
|
|
for (int i=0; i<LOOPS; ++i)
|
|
run_life();
|
|
|
|
printf("%s : res=%d\n", *av, count_active());
|
|
|
|
exit (0);
|
|
}
|