Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Last active April 7, 2021 16:38
Show Gist options
  • Save shiracamus/a7b46c1dab5969189c1d1f07dfc56e8d to your computer and use it in GitHub Desktop.
Save shiracamus/a7b46c1dab5969189c1d1f07dfc56e8d to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
typedef enum {
WALL = 'X',
DEAD = ' ',
ALIVE = 'O',
} Cell;
typedef struct {
int width, height;
Cell *cells;
} *Field;
Field Field_New(int width, int height) {
Field this = malloc(sizeof(*this));
this->width = width;
this->height = height;
this->cells = calloc(width * height, sizeof(Cell));
for (int i = 0; i < width * height; i++)
this->cells[i] = DEAD;
return this;
}
void Field_Free(Field this) {
free(this->cells);
free(this);
}
void Field_Set(Field this, int x, int y, Cell cell) {
this->cells[y * this->width + x] = cell;
}
Cell Field_Get(Field this, int x, int y) {
return this->cells[y * this->width + x];
}
void Field_Initialize(Field this) {
srandom((unsigned)time(NULL));
for (int y = 0; y < this->height; y++) {
for (int x = 0; x < this->width; x++) {
if (y == 0 || y == this->height-1 || x == 0 || x == this->width-1)
Field_Set(this, x, y, WALL);
else if (random() % 2 == 0)
Field_Set(this, x, y, DEAD);
else
Field_Set(this, x, y, ALIVE);
}
}
}
bool Field_IsWall(Field this, int x, int y) {
return Field_Get(this, x, y) == WALL;
}
bool Field_IsAlive(Field this, int x, int y) {
return Field_Get(this, x, y) == ALIVE;
}
int Field_CountNeighborAlives(Field this, int x, int y) {
int alives = 0;
if (Field_IsAlive(this, x-1, y-1)) alives++;
if (Field_IsAlive(this, x+0, y-1)) alives++;
if (Field_IsAlive(this, x+1, y-1)) alives++;
if (Field_IsAlive(this, x-1, y+0)) alives++;
if (Field_IsAlive(this, x+1, y+0)) alives++;
if (Field_IsAlive(this, x-1, y+1)) alives++;
if (Field_IsAlive(this, x+0, y+1)) alives++;
if (Field_IsAlive(this, x+1, y+1)) alives++;
return alives;
}
bool Field_IsSame(Field this, Field other) {
if (this->width != other->width || this->height != other->height)
return false;
for (int y = 0; y < this->height; y++) {
for (int x = 0; x < this->width; x++) {
if (Field_Get(this, x, y) != Field_Get(other, x, y))
return false;
}
}
return true;
}
void Field_Draw(Field this) {
for (int y = 0; y < this->height; y++) {
for (int x = 0; x < this->width; x++)
printf("%c", Field_Get(this, x, y));
printf("\n");
}
}
typedef struct {
Field field;
Field last;
int generation;
} *LifeGame;
LifeGame LifeGame_New(int width, int height) {
LifeGame this = malloc(sizeof(*this));
this->field = Field_New(width, height);
this->last = NULL;
Field_Initialize(this->field);
this->generation = 0;
return this;
}
void LifeGame_Free(LifeGame this) {
Field_Free(this->field);
free(this);
}
void LifeGame_Draw(LifeGame this) {
printf("\033[2J\033[H現在%d世代目\n", this->generation);
Field_Draw(this->field);
}
bool LifeGame_NextGeneration(LifeGame this) {
Field field = this->field;
Field next = Field_New(field->width, field->height);
for (int y = 0; y < field->height; y++) {
for (int x = 0; x < field->width; x++) {
if (Field_IsWall(field, x, y)) {
Field_Set(next, x, y, WALL);
continue;
}
int neighbors = Field_CountNeighborAlives(field, x, y);
if (Field_IsAlive(field, x, y))
Field_Set(next, x, y,
neighbors == 2 || neighbors == 3 ? ALIVE : DEAD);
else
Field_Set(next, x, y, neighbors == 3 ? ALIVE: DEAD);
}
}
bool same = Field_IsSame(next, field);
if (!same && this->last) same = Field_IsSame(next, this->last);
if (this->last) free(this->last);
this->last = this->field;
this->field = next;
this->generation++;
return !same;
}
int main(int argc, char *argv[]) {
const int WIDTH = 79;
const int HEIGHT = 20;
const int INTERVAL = 100 * 1000; // 更新間隔(マイクロ秒)
LifeGame lifegame = LifeGame_New(WIDTH, HEIGHT);
do {
LifeGame_Draw(lifegame);
usleep(INTERVAL);
} while (LifeGame_NextGeneration(lifegame));
LifeGame_Free(lifegame);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment