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

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

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

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

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

3220閲覧

C++(ほぼC言語の記述法)でライフゲームを作ったのですが、挙動がおかしいので、おかしいソースコードを指摘してもらえないでしょうか。

JUN_SAN

総合スコア5

C

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

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/03/10 04:23

編集2020/03/10 04:50

前提・実現したいこと

C++(ほぼC言語の書き方)でライフゲーム(wikipediaに載っている一般的なもの)を作っていたのですが、
挙動が明らかに違います(挙動に規則がみつからなく、また、wikipediaの例と違う挙動をします)。
なので、正しい挙動をするように、おかしいところを指摘してもらえないでしょうか。

発生している問題・エラーメッセージ

上の通り、明らかに違う挙動をします(エラーメッセージは出ていません)

該当のソースコード

C++

1#include <stdio.h> 2#include <conio.h> 3#include <stdlib.h> 4 5#define FIELD_WIDTH 50 6#define FIELD_HEIGHT 45 7 8enum alive { 9 CELL_DEAD = 0, 10 CELL_ALIVE = 1, 11 CELL_MAX 12}; 13 14// 8方向のベクトルの管理 15enum vector { 16 VECTOR_UP, 17 VECTOR_DOWN, 18 VECTOR_LEFT, 19 VECTOR_RIGHT, 20 VECTOR_UP_LEFT, 21 VECTOR_UP_RIGHT, 22 VECTOR_DOWN_LEFT, 23 VECTOR_DOWN_RIGHT, 24 VECTOR_MAX 25}; 26 27int vectors[][2] = { 28 {0, -1}, // VECTOR_UP 29 {0, 1}, // VECTOR_DOWN 30 {-1, 0}, // VECTOR_LEFT 31 {1, 0}, // VECTOR_RIGHT 32 {-1, -1}, // VECTOR_UP_LEFT 33 {1, -1}, // VECTOR_UP_RIGHT 34 {-1, 1}, // VECTOR_DOWN_LEFT 35 {1, 1} // VECTOR_DOWN_RIGHT 36}; 37 38// 一つ一つの細胞の定義 39int cells[FIELD_HEIGHT][FIELD_WIDTH]; 40 41// カーソルの定義 42int cursorX = 0, cursorY = 0; 43 44// 最初に盤面のセットアップ 45void setup(void) { 46 for (int y = 0; y < FIELD_HEIGHT; y++) 47 for (int x = 0; x < FIELD_WIDTH; x++) { 48 cells[y][x] = CELL_DEAD; 49 } 50} 51 52// 盤面の更新(firstはカーソルの表示非表示) 53void update(bool cursor) { 54 // 盤面のクリア 55 system("cls"); 56 57 for (int y = 0; y < FIELD_HEIGHT; y++) { 58 for (int x = 0; x < FIELD_WIDTH; x++) { 59 // カーソルの表示 60 if (cursor) { 61 if (x == cursorX && y == cursorY) { 62 printf("◆"); 63 } 64 65 else { 66 if (cells[y][x] == CELL_DEAD) { 67 printf("□"); 68 } 69 70 if (cells[y][x] == CELL_ALIVE) { 71 printf("●"); 72 } 73 } 74 } 75 76 // 死んでいると□, 生きていると● 77 else { 78 if (cells[y][x] == CELL_DEAD) { 79 printf("□"); 80 } 81 82 if (cells[y][x] == CELL_ALIVE) { 83 printf("●"); 84 } 85 } 86 } 87 88 // FIELD_WIDTHごとに改行 89 printf("\n"); 90 } 91} 92 93// 周りの生きているセルの数のカウント 94int livesAlong(int _x, int _y) { 95 // カウント 96 int count = 0; 97 98 for (int i = 0; i < VECTOR_MAX; i++) { 99 int x2 = _x, y2 = _y; 100 x2 += vectors[i][0]; 101 y2 += vectors[i][1]; 102 103 // はみ出さないように 104 if (x2 < 0 || x2 >= FIELD_WIDTH) { 105 continue; 106 } 107 108 if (y2 < 0 || y2 >= FIELD_HEIGHT) { 109 continue; 110 } 111 112 // カウントの追加 113 if (cells[y2][x2] == CELL_ALIVE) { 114 count += 1; 115 } 116 } 117 118 return count; 119} 120 121// 次に生きているか(_alivesは周りの生きているセルの数, _cellは今のセルが生きているか死んでいるか) 122bool nextAlive(int _alives, int _cell) { 123 if (_cell == CELL_ALIVE) { 124 switch (_alives) { 125 case 1: return false; break; 126 case 2: return true; break; 127 case 3: return true; break; 128 case 4: return false; break; 129 } 130 } 131 132 if (_cell == CELL_DEAD) { 133 if (_alives == 3) { 134 return true; 135 } 136 137 else { 138 return false; 139 } 140 } 141 142 return false; 143} 144 145int main(void) { 146 // 盤面のセットアップ 147 setup(); 148 149 // ループ管理 150 bool Set = true; 151 152 int alvalg = 0; 153 154 // 最初に命をセット 155 while (Set) { 156 update(true); 157 switch (_getch()) { 158 // 移動 159 case 'w': cursorY--; break; 160 case 's': cursorY++; break; 161 case 'a': cursorX--; break; 162 case 'd': cursorX++; break; 163 164 // 命を置く 165 case 'r': cells[cursorY][cursorX] = CELL_ALIVE; break; 166 167 // ライフゲームを始める 168 case 'e': Set = false; break; 169 }; 170 171 // カーソルがはみ出さないように 172 cursorX = (FIELD_WIDTH + cursorX) % FIELD_WIDTH; 173 cursorY = (FIELD_HEIGHT + cursorY) % FIELD_HEIGHT; 174 } 175 176 // ライフゲームのループ(rキー入力で次の世代, eで終わる) 177 bool _continue = true; 178 179 while (1) { 180 update(false); 181 switch (_getch()) { 182 183 // rを押すと次の生死を判断(次の世代へ) 184 case 'r': 185 for (int y = 0; y < FIELD_HEIGHT; y++) { 186 for (int x = 0; x < FIELD_WIDTH; x++) { 187 if (nextAlive(livesAlong(x, y), cells[y][x])) { 188 cells[y][x] = CELL_ALIVE; 189 } 190 191 else { 192 cells[y][x] = CELL_DEAD; 193 } 194 } 195 } 196 break; 197 198 // eでプログラムを終える 199 case 'e': _continue = false; break; 200 default: break; 201 } 202 } 203 return 0; 204}

試したこと

周りの生きているセルの数を確認する関数(livesAlong)の値は、数回試しましたが、おそらく正常です。
次の生死の判断(nextAlive)も、おそらく正常です。

補足情報(FW/ツールのバージョンなど)

visual studio 2019の「C++コンソールアプリ」で開発しております。

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

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

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

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

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

Y.H.

2020/03/10 04:25

> 明らかに違う挙動をします どういう挙動を期待して、質問記載のコードではどのような挙動になり 具体的にどのように期待と異なるのかを質問に記載ください。
JUN_SAN

2020/03/10 04:51

ご指摘ありがとうございます。規則がどうしても見つからなかったので 、あいまいな表現になってしまいました。これからは修正します。
guest

回答3

0

ベストアンサー

現在の盤面→次の盤面 の計算中に

cells[y][x] = CELL_ALIVE;

のようにしてcellsを書き換えてしまっているのが問題なのではないでしょうか.

投稿2020/03/10 04:30

fana

総合スコア11632

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

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

fana

2020/03/10 04:34 編集

回答文面だけで伝わると思うけども,一応具体例を書いておく: 例えば,cells[0][0]の値を0から1に更新してしまうと,cells[0][1]の処理には更新後のcells[0][0]の値(1)が使われることになってしまう,という話. (本来は更新前のcells[0][0]の値(0)を用いてcells[0][1]の処理が行われるべきところを.)
JUN_SAN

2020/03/10 04:47

ありがとうございます、解決できました。
guest

0

どうでもいい指摘ではありますが、メインループを抜ける処理が入っていません。

bool _continue = true; while (1) { //ここ1ではなく_continue です。 update(false); switch (_getch()) { // rを押すと次の生死を判断(次の世代へ) case 'r': for (int y = 0; y < FIELD_HEIGHT; y++) { //割愛 } break; // eでプログラムを終える case 'e': _continue = false; break; default: break; } }

投稿2020/03/10 04:55

編集2020/03/10 04:56
stdio

総合スコア3307

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

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

JUN_SAN

2020/03/10 06:30

ご指摘ありがとうございます。そういえば抜けていました。
guest

0

文字で説明するのは面倒なので簡単な回答ですみません。

ライフゲームは確かデータを2面持つ必要があったと思います。
表示中のデータを直接書き換えてしまうと次のマスを判定するときにその書き換えたデータを使ってしまうため正しい判定ができません。
表示中のデータを基に次に表示するためのデータを別に作っていき、交互に表示するようなイメージになるかと思います。

投稿2020/03/10 04:42

ttyp03

総合スコア16996

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

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

JUN_SAN

2020/03/10 04:53

回答ありがとうございます。これからライフゲームを作るとき、役立てます。
fana

2020/03/10 05:04

割とどうでもいい話ですが, あるセルAが以降他セル群の更新処理において参照されないならば,セルAの値は更新しても差し支えないので, 2面「丸ごと」持つことが必須というわけではないですね. 2行分くらいのバッファがあれば良いのかな?
JUN_SAN

2020/03/10 06:44

確かにそれだとメモリの削減ができるかもしれませんね。 挑戦してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問