ライフゲーム
Posted feedbacks - C
LifeGame書いたことなかったから、間引きなしで。 グライダーが動いたので多分合ってる?
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 | #include <stdio.h>
#include <conio.h>
#define WIDTH 10
#define HIGHT 10
void next_gen(int a[HIGHT][WIDTH]){
int life;
int x,y;
int x_l,x_r,y_u,y_d;
for(y=0;y<HIGHT;y++){
y_u=(y+ 9)%HIGHT;
y_d=(y+11)%HIGHT;
for(x=0;x<WIDTH;x++){
x_l=(x+ 9)%WIDTH;
x_r=(x+11)%WIDTH;
life= (a[y_u][x_l]&1)+(a[y_u][x]&1)+(a[y_u][x_r]&1)
+(a[ y ][x_l]&1) +(a[ y ][x_r]&1)
+(a[y_d][x_l]&1)+(a[y_d][x]&1)+(a[y_d][x_r]&1);
if((life|(a[y][x]&1))==3) a[y][x]|=2;
}
}
for(y=0;y<HIGHT;y++){
for(x=0;x<WIDTH;x++){
a[x][y]>>=1;
}
}
}
void put_gen(int a[HIGHT][WIDTH]){
int x,y;
for(y=0;y<HIGHT;y++){
for(x=0;x<WIDTH;x++){
putchar('[');
putchar(a[y][x]==1?'*':' ');
putchar(']');
}
putchar('\n');
}
}
void lifegame(int a[HIGHT][WIDTH]){
int gen=0;
do{
printf("T=%d\n",gen);
put_gen(a);
next_gen(a);
gen++;
}while(getch()==0x20);
}
int main(){
int a[HIGHT][WIDTH]={
/* 出題
{0,1,0,0,0,0,1,1,1,0},
{0,0,0,0,1,0,0,1,1,0},
{0,0,0,1,0,0,1,0,1,0},
{1,0,1,1,0,0,1,0,0,0},
{0,1,0,0,0,0,0,0,1,0},
{1,0,0,0,1,0,1,1,0,1},
{0,1,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,1,0,0,1},
{0,0,0,0,1,1,0,0,1,0}
/*/
//グライダー
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,0,0},
{0,0,1,1,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
//*/
};
lifegame(a);
return 0;
}
|
題意を間違えたみたいなんで追加修正
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 | void init_life(int a[HEIGHT][WIDTH]){
int x,y;
int count=0;
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
a[y][x]=0;
}
}
srand(time(NULL));
do{
x=rand()/(RAND_MAX/WIDTH);
y=rand()/(RAND_MAX/HEIGHT);
if(calc_life(a,x,y)<=(2+(rand()/(RAND_MAX/2)))){
a[y][x]=1;
count++;
}
}while(count<((HEIGHT*WIDTH)*(2+(rand()/(RAND_MAX/2)))/10));
}
int main(){
int a[HEIGHT][WIDTH];
init_life(a);
lifegame(a);
return 0;
}
|
失敗しました。 全部貼らなきゃだった・・・ 題意を取り違えてたっぽいので追加修正。
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 | #include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define WIDTH 10
#define HEIGHT 10
int calc_life(int a[HEIGHT][WIDTH],int x,int y){
int life;
int x_l,x_r,y_u,y_d;
y_u=(y+HEIGHT-1)%HEIGHT;
y_d=(y+1)%HEIGHT;
x_l=(x+WIDTH-1)%WIDTH;
x_r=(x+1)%WIDTH;
life= (a[y_u][x_l]&1)+(a[y_u][x]&1)+(a[y_u][x_r]&1)
+(a[ y ][x_l]&1) +(a[ y ][x_r]&1)
+(a[y_d][x_l]&1)+(a[y_d][x]&1)+(a[y_d][x_r]&1);
return life;
}
void next_gen(int a[HEIGHT][WIDTH]){
int life;
int x,y;
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
life=calc_life(a,x,y);
if((life|(a[y][x]&1))==3) a[y][x]|=2;
}
}
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
a[x][y]>>=1;
}
}
}
void put_gen(int a[HEIGHT][WIDTH]){
int x,y;
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
putchar('[');
putchar(a[y][x]==1?'*':' ');
putchar(']');
}
putchar('\n');
}
}
void lifegame(int a[HEIGHT][WIDTH]){
int gen=0;
do{
printf("T=%d\n",gen);
put_gen(a);
next_gen(a);
gen++;
}while(getch()==0x20);
}
void init_life(int a[HEIGHT][WIDTH]){
int x,y;
int count=0;
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
a[y][x]=0;
}
}
srand(time(NULL));
do{
x=rand()/(RAND_MAX/WIDTH);
y=rand()/(RAND_MAX/HEIGHT);
if(calc_life(a,x,y)<=(2+(rand()/(RAND_MAX/2)))){
a[y][x]=1;
count++;
}
}while(count<((HEIGHT*WIDTH)*(2+(rand()/(RAND_MAX/2)))/10));
}
int main(){
int a[HEIGHT][WIDTH];
init_life(a);
lifegame(a);
return 0;
}
|
グダグダしてきましたが、Wikipediaによると"23/3"などというルール表記があるようなのでそれに対応。 世代スキップも追加。
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 | #include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define WIDTH 10
#define HEIGHT 10
/* セルの生死判定 */
int calc_life(int a[HEIGHT][WIDTH],int x,int y){
int life;
int x_l,x_r,y_u,y_d;
y_u=(y+HEIGHT-1)%HEIGHT;
y_d=(y+1)%HEIGHT;
x_l=(x+WIDTH-1)%WIDTH;
x_r=(x+1)%WIDTH;
life= (a[y_u][x_l]&1)+(a[y_u][x]&1)+(a[y_u][x_r]&1)
+(a[ y ][x_l]&1) /*注目セル */+(a[ y ][x_r]&1)
+(a[y_d][x_l]&1)+(a[y_d][x]&1)+(a[y_d][x_r]&1);
return life;
}
/* 世代の進行 */
void next_gen(int a[HEIGHT][WIDTH],char* rule){
int life;
int x,y;
char* birth;
char* ptr_rule;
/* 誕生ルール検出 */
birth=rule;
while(*birth++!='/');
/*生存・誕生判定*/
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
life=calc_life(a,x,y);
if(a[y][x]&1){
/*生存判定*/
ptr_rule=rule;
do{
if(life==*ptr_rule-'0') a[y][x]|=2;
}while(*++ptr_rule!='/');
}else{
/*誕生判定*/
ptr_rule=birth;
do{
if(life==*ptr_rule-'0') a[y][x]|=2;
}while(*++ptr_rule);
}
}
}
/* 次世代へ進行 */
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
a[x][y]>>=1;
}
}
}
/* 現世代の表示 */
void put_gen(int a[HEIGHT][WIDTH]){
int x,y;
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
printf("[%c]",a[y][x]==1?'*':' ');
}
putchar('\n');
}
}
/* ライフゲーム制御 */
void lifegame(int a[HEIGHT][WIDTH],char* rule){
int gen=0;
char c;
int step;
while(1){
printf("T=%d\n",gen);
put_gen(a);
step=0;
while(1){
c=getche();
if(c<'0'||'9'<c) break;
step*=10;
step+=c-'0';
}
if(c==0x1b) break;
if(step==0&&(c==0x20||c==0x0d)) step=1;
putchar('\n');
while(step--){
next_gen(a,rule);
gen++;
}
}
}
/* ランダム初期値の設定 */
void init_life(int a[HEIGHT][WIDTH]){
int x,y;
int count=0;
for(y=0;y<HEIGHT;y++){
for(x=0;x<WIDTH;x++){
a[y][x]=0;
}
}
srand(time(NULL));
do{
x=rand()/(RAND_MAX/WIDTH);
y=rand()/(RAND_MAX/HEIGHT);
if(calc_life(a,x,y)<=(2+(rand()/(RAND_MAX/2)))){
a[y][x]=1;
count++;
}
}while(count<((HEIGHT*WIDTH)*(2+(rand()/(RAND_MAX/2)))/10));
}
int main(){
int a[HEIGHT][WIDTH]={
/* 出題
{0,1,0,0,0,0,1,1,1,0},
{0,0,0,0,1,0,0,1,1,0},
{0,0,0,1,0,0,1,0,1,0},
{1,0,1,1,0,0,1,0,0,0},
{0,1,0,0,0,0,0,0,1,0},
{1,0,0,0,1,0,1,1,0,1},
{0,1,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,1,0,0,1},
{0,0,0,0,1,1,0,0,1,0}
/*/
//グライダー
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,0,0},
{0,0,1,1,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
/*/
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0},
{0,0,1,1,0,1,0,0,0,0},
{0,0,0,1,0,1,0,0,0,0},
{0,0,0,0,0,1,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,1,0,1,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
//*/
};
// init_life(a);
lifegame(a,"23/3");
// lifegame(a,"23/36"); //HighLife?
return 0;
}
|
コンソール専用化と思っていたら エスケープシーケンスってVT100エミュレーション下では ちゃんと機能するんですね。 20へぇ~ 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 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
typedef struct tagCell
{
int alive; // 今の状態
int life; // 次の状態
struct tagCell *around[9]; // 自分の周囲(自分含む)
} CELL;
static const char *CELL_CHAR[] = { "□", "■" };
#define HEIGHT (10)
#define WIDTH (10)
static CELL cells[ HEIGHT ][ WIDTH ];
/* 初期パターン (0:死 /1:生) */
// お題サンプル(池になって終わり)
static const int graph_paturn1[ HEIGHT * WIDTH ] =
{
// 1 2 3 4 5 6 7 8 9 10
/* 1 */ 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,
/* 2 */ 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
/* 3 */ 0, 0, 0, 1, 0, 0, 1, 0, 1, 0,
/* 4 */ 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
/* 5 */ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
/* 6 */ 1, 0, 0, 0, 1, 0, 1, 1, 0, 1,
/* 7 */ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
/* 9 */ 1, 0, 0, 0, 0, 0, 1, 0, 0, 1,
/* 10 */ 0, 0, 0, 0, 1, 1, 0, 0, 1, 0
};
// 基本パターン固定型
static const int graph_paturn2[ HEIGHT * WIDTH ] =
{
// 1 2 3 4 5 6 7 8 9 10
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2 */ 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
/* 3 */ 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
/* 4 */ 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
/* 5 */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
/* 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 8 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
inline void CLS(void){ printf("\x1b[2J"); }
inline void LOCATE(int x, int y){ printf("\x1b[%d;%dH", y, x); }
inline void STORE_LOCATE(void){ printf("\x1b[s"); }
inline void RESTORE_LOCATE(void){ printf("\x1b[u"); }
/* 指定した座標のセル取得 */
inline int getCell(CELL **out, int x, int y)
{
assert(out != NULL );
/* 座標の正規化 */
y %= HEIGHT; if( y < 0 ){ y = HEIGHT + y; }
x %= WIDTH; if( x < 0 ){ x = WIDTH + x; }
/* */
*out = &cells[y][x];
assert(*out != NULL );
return 0;
}
/* 現在の状態から次世代の状態を設定する */
int set_next_life(struct tagCell *cell)
{
int score;
assert(cell != NULL );
score = cell->around[0]->alive + cell->around[1]->alive + cell->around[2]->alive
+ cell->around[3]->alive + cell->around[5]->alive
+ cell->around[6]->alive + cell->around[7]->alive + cell->around[8]->alive;
switch( score )
{
case 2: // 維持
break;
case 3: // 誕生
cell->life = 1;
break;
default: // 死亡
cell->life = 0;
break;
}
return 0;
}
/* 初期化いろいろ */
int initialize(void)
{
static const int *graph = graph_paturn1; // 初期配置
struct tagCell *cell;
/* スクリーンの初期化 */
CLS(); LOCATE(1,3);
/* セルの初期化 */
memset( &cells, 0, sizeof(cells) );
for( int h=0; h < HEIGHT; h ++ )
{
for( int w=0; w < WIDTH; w ++ )
{
cell = &cells[ h ][ w ];
cell->alive = *graph++;
cell->life = cell->alive;
/* 周囲セルの設定 */
getCell(&cell->around[0], w-1, h-1);
getCell(&cell->around[1], w , h-1);
getCell(&cell->around[2], w+1, h-1);
getCell(&cell->around[3], w-1, h );
getCell(&cell->around[4], w , h ); //自分自身
getCell(&cell->around[5], w+1, h );
getCell(&cell->around[6], w-1, h+1);
getCell(&cell->around[7], w , h+1);
getCell(&cell->around[8], w+1, h+1);
}
}
return 0;
}
/* 現在の状態を表示 */
int print_cells(void)
{
struct tagCell *cell;
for( int h=0; h < HEIGHT; h ++ )
{
for( int w=0; w < WIDTH; w ++ )
{
cell = &cells[ h ][ w ];
// printf("[%c]", (cell->alive == 1)?'*':' ');
printf("%s", CELL_CHAR[ cell->alive ] );
cell->alive = cell->life; // 表示したので次世代の状態を反映する
}
printf("\n");
}
return 0;
}
/* */
void play(int frame)
{
struct timespec interval =
{
.tv_sec = 0,
.tv_nsec = 125000000
};
STORE_LOCATE();
for( int t=0; t<=frame || frame==-1; t++ )
{
RESTORE_LOCATE();
/* 表示前に次の状態を計算 */
for( int h=0; h < HEIGHT; h ++ )
{
for( int w=0; w < WIDTH; w ++ )
{
set_next_life( &cells[ h ][ w ] );
}
}
/* 表示 */
printf("t=%d\n", t);
print_cells();
/* ディレイ */
nanosleep(&interval, NULL);
}
}
int main(int argc, char *argv[])
{
initialize();
play( (argc>1)?atoi( argv[1] ):-1 );
return 0;
}
|




saws
#5330()
Rating6/12=0.50
see: Wikipedia:ライフゲーム
[ reply ]