Last active
April 7, 2021 16:38
-
-
Save shiracamus/a7b46c1dab5969189c1d1f07dfc56e8d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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