質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

1312閲覧

C言語でライフゲーム 終了

kokok

総合スコア145

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/07/26 05:01

C

1 2#include<stdio.h> 3#include<stdlib.h> 4#include <Windows.h> 5#include <time.h> 6 7 8#define WORLD_H 38 9#define WORLD_W 38 10 11//プロトタイプ宣言 12void init_map(char map[WORLD_H][WORLD_W]); 13void print_map(char map[WORLD_H][WORLD_W]); 14void next_gen(char map[WORLD_H][WORLD_W]); 15int lifeCount(char temp[WORLD_H][WORLD_W], int ypos, int xpos); 16 17 18int main(void) { 19 20 char map[WORLD_H][WORLD_W]; 21 22 COORD coord; HANDLE hStdout; hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 23 24 25 srand((unsigned)time(NULL)); 26 27 init_map( map); //初期化 28 29 30 while (1) { 31 coord.X = 0;// Xの位置(横) 32 coord.Y = 1; // Yの位置(縦) 33 SetConsoleCursorPosition(hStdout, coord); // カーソルの移動 34 35 print_map(map); //マップの表示 36 void next_gen(map); //世代を進める 37 } 38} 39 40 41 42//初期化する関数 43void init_map(char map[WORLD_H][WORLD_W]) { 44 45 46 int tate, yoko; 47 int rudval; 48 49 for (tate = 0; tate < WORLD_H; tate++) { 50 51 for (yoko = 0; yoko < WORLD_W; yoko++) { 52 53 int rudval = rand() % 10; 54 55 if (rudval >= 6) { 56 map[tate][yoko] = 1; 57 } 58 else { 59 map[tate][yoko] = 0; 60 61 } 62 63 } 64 } 65 66} 67 68//マップ表示 69 70void print_map(char map[WORLD_H][WORLD_W]) { 71 72 int tate, yoko; 73 74 75 for (tate = 0; tate < WORLD_H; tate++) { 76 77 for (yoko = 0; yoko < WORLD_W; yoko++) { 78 79 if (map[tate][yoko] == 1) { 80 81 printf("@"); 82 83 84 } 85 else if (map[tate][yoko] == 0) { 86 87 88 printf("."); 89 90 } 91 92 } 93 printf("\n"); 94 } 95 96 97} 98 99//世代を進める 100 101void next_gen(char map[WORLD_H][WORLD_W]) { 102 103 int rowtbl; 104 int coltbl; 105 106 char temp[WORLD_H][WORLD_W]; 107 108 for (coltbl = 0; coltbl < WORLD_H; coltbl++) { 109 110 for (rowtbl = 0; rowtbl < WORLD_W; rowtbl++) { 111 112 temp[coltbl][rowtbl] = map[coltbl][rowtbl]; 113 114 115 temp[coltbl][rowtbl] = lifeCount( temp[coltbl][rowtbl], coltbl, rowtbl); 116 117 if (temp[coltbl][rowtbl] == 3 && map[coltbl][rowtbl] ==0) { 118 map[coltbl][rowtbl] = 1; 119 }else if(temp[coltbl][rowtbl ]<= 1 && map[coltbl][rowtbl] == 1){ 120 map[coltbl][rowtbl] = 0; 121 } 122 else if (temp[coltbl][rowtbl] >= 4 && map[coltbl][rowtbl] == 1) { 123 124 map[coltbl][rowtbl] = 0; 125 126 } 127 } 128 129 } 130 131 132 133} 134 135//生存数を数える 136 137int lifeCount (char temp[WORLD_H][WORLD_W], int ypos, int xpos) { 138 139 140 int sum = 0; 141 142 if (ypos > 0 && xpos > 0) { 143 sum += temp[ypos - 1][xpos - 1]; //左上 144 } 145 146 if (xpos > 0) { 147 sum += temp[ypos][xpos - 1]; // 左 148 149 } 150 if (ypos < WORLD_H - 1 && xpos > 0) { 151 sum += temp[ypos + 1][xpos - 1]; //左下 152 } 153 if (ypos < WORLD_H - 1) { 154 sum += temp[ypos + 1][xpos]; //下 155 } 156 if(ypos < WORLD_H - 1 && xpos < WORLD_W - 1){ 157 sum += temp[ypos + 1][xpos + 1]; //右下 158 } 159 if (xpos < WORLD_W - 1) { 160 161 sum += temp[ypos][xpos + 1]; //右 162 } 163 if (ypos > 0 && xpos < WORLD_W - 1) { 164 sum += temp[ypos - 1][xpos + 1]; //右上 165 166 } 167 if (ypos > 0) { 168 sum += temp[ypos - 1][xpos]; //上 169 170 } 171 172 return sum; //周り8個の生存数 173} 174

現在、C言語の勉強のためにライフゲームというものを作っているのですが、

コンソールに表示させることは出来たのですが

永遠に表示されます。

どのような条件で終了(画面が止まる)こうやったら終わりみたいな 感じでしたいのですが
あまり思いつかなかったので何かアドバイス頂けると助かります。

また、コードが間違ってるなども指摘いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

next_genがなんかおかしいですね、正しくはこんな感じかな?

for (coltbl = 0; coltbl < WORLD_H; coltbl++) { for (rowtbl = 0; rowtbl < WORLD_W; rowtbl++) { temp[coltbl][rowtbl] = map[coltbl][rowtbl]; } } for (coltbl = 0; coltbl < WORLD_H; coltbl++) { for (rowtbl = 0; rowtbl < WORLD_W; rowtbl++) { int count = lifeCount( temp, coltbl, rowtbl); map[coltbl][rowtbl] = (count == 2 || count == 3) ? 1 : 0; } }

ライフゲームに関してはこの動画が面白いです
特に後半にヤバい物が出てくるので、ぜひ全部見てください
https://www.nicovideo.jp/mylist/34610498

投稿2019/07/26 06:10

編集2019/07/26 06:45
izmktr

総合スコア2856

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2019/07/27 04:24

2つの二重forループは次のような感じですね。 1. まず現状(現世代)を temp配列にコピーしてしまってから 2. temp 配列を使って、次世代の配列となる map 配列を更新する
guest

0

何かキーを押せば状態を保存して(あるいは破棄して)終了でいいんじゃないでしょうか。

ライフゲームは永遠に生き続けるパターン、増え続けるパターン、キャッチボールするパターンなど、様々なパターンを探すのが醍醐味です。乱数で生成するのではなく、計算してそのようなパターンを探ってみてはどうでしょうか。

また、ライフゲームはチューリング完全だそうです。つまり、あらかじめ置いておくパターンによってプログラミングをすることができます。Hello World を作ってみてはどうでしょうか?

また、最初のパターンを完全な乱数や固定されたパターンではなく、プログラムによって生成することができます。あらかじめどのようなパターンのスコアが高くなるかを決めておき、少しでも高いスコアのパターンを求めるようプログラミングすることで、進化するプログラムを作ることができます。人工知能に挑戦してみてはどうでしょうか?

様々な可能性を持ったライフゲームです。ただ表示して終わりではなく、自分でも可能性を探ってみてください。

投稿2019/07/26 05:49

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ライフゲームに終わりはありません。
あえて言えば、表示画面に変化がなくなれば終わり、としたいところですが、それでも終わらないパターンもありますね

投稿2019/07/26 05:14

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

コードが間違ってるなども指摘いただけると幸いです

ありがちな、大いなる間違いがあります。間違いは lifecount() 関数の引数に関して、です。「表示させることは出来た」のなら、お使いのCコンパイラはそのコードをエラーにしなかったのでしょうか?私には奇怪な話に思えます。

C

1// プロトタイプ宣言 2int lifeCount(char temp[WORLD_H][WORLD_W], int ypos, int xpos); 3 4//生存数を数える -- 関数本体 5int lifeCount(char temp[WORLD_H][WORLD_W], int ypos, int xpos) 6{ 7 int sum = 0; 8 9 if (ypos > 0 && xpos > 0) { 10 sum += temp[ypos - 1][xpos - 1]; //左上 11 } 12 .... 13

lifecount() 関数は、引数の temp という名前の(38 * 38の大きさの)配列を使って計算するので、仮引数として配列全体を受け取る必要があります。
配列全体を引数として渡す、とは配列の先頭アドレスを渡すこと、と言い換えられます。

ところが、next_gen() 関数の中では、こう関数呼出しをしています。ここが誤り。

C

1void next_gen(char map[WORLD_H][WORLD_W]) { 2 char temp[WORLD_H][WORLD_W]; 3 // 途中省略 4 temp[coltbl][rowtbl] = lifeCount( temp[coltbl][rowtbl], coltbl, rowtbl);

ここのように、関数呼出しに書く引数を実引数と呼びます。
ここにある実引数 temp[coltbl][rowtbl] とは、何か。
temp配列のなかの、一箇所([coltbl][rowtbl] という位置)の、一要素の値、即ち 0, 1, 2 ... という値であって、(配列全体を渡せる)配列の先頭アドレスではありません。
配列の先頭アドレスを渡すはずだったのに、配列の中の、たった一個の値だけを渡したなら、lifecount() 関数が期待通りの計算をできるわけがありません。普通コンパイラはエラーを表示し、動作するプログラムは作られないと思うのですが。

仮引数と実引数は、同じ格好になるとは限りません。なぜなら2つは文法が異なるから。
配列名(ここでは temp)は配列の先頭アドレスである、ことを思い出してください。正しい呼出し方はこんな格好です。

C

1次世代の配列[coltbl][rowtbl] = lifeCount(temp, coltbl, rowtbl);

ここで「次世代の配列」としたのは、izmktr さんの指摘を念頭に置いたからです。

投稿2019/07/27 04:18

rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kokok

2019/07/28 06:57

ありがとうがざいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問