angel-wing さんが書きました: ↑5年前
(1) return 0と1が使い分けられていますが、何か意図があるのでしょうか(全て0にしてみてもエラーは出ない様子ですが)。
conv は、入力が正しい時 1 を返し、正しくない時 0 を返します。
game は、fgets で EOF を検出したとき 1 を返し、
もうこれ以上入力がないと判断しプログラムの実行を終了します。
入力があった場合は 0 を返し、main で終了の確認を行います。
angel-wing さんが書きました: ↑5年前
(2) 最初の64個の配列(二次元配列)が持つ意味や順序が分かりません……。
main の st は「棒の状態(state)」を表します。
int st[6] = { 1, 1,1, 1,1,1 }; で 6本の棒はすべてあります。
プレイヤーが 1番上の棒を消すと
st が { 0, 1,1, 1,1,1 } になります。
これを 2進数の 011111 とすると、その値は 31 です。
pat[31] は { 4, 6 } です。
これは、コンピュータの次の手が 4 または 6 であることを示します。
どちらにするかは、乱数で決めます。
最初にプレイヤーが 456 を消すと、
st が { 1, 1,1, 0,0,0 } になります。
これを 2進数の 111000 とすると、その値は 56 です。
pat[56] は { 23, 23 } です。
これは、コンピュータの次の手が 23 であることを示します。
乱数の値にかかわらず、23 になります。
angel-wing さんが書きました: ↑5年前
(3) int game内の if (!fgets(buf, sizeof buf, stdin)) return 0;
には、どのような意味がありますか。「stdinでキーボードから文字列を受け取り、関数冒頭で定義したbufに当てはめてサイズを取得する→もしサイズが取得できなければ、printfの内容を表示する」という解釈で大丈夫でしょうか……。
char buf[256]; と宣言されているので、sizeof buf は 256 です。
fgets(buf, 256, stdin) と書くのと同じです。
fgets は通常 buf の値、すなわち buf[0] のアドレスを返します。
しかし、EOF に遭遇するなどのエラーがあった場合、NULL を返します。
「!アドレス」は 0 であり、「!NULL」は 1 です。
だから、fgets が EOF に遭遇したとき、return します。
angel-wing さんが書きました: ↑5年前
(4) int user以下で、if (conv(i, user) == 0) { puts("エラー"); continue; }
ですが、「userの入力が0ならば、エラー表示をする」ように読めたのですが、実際は消し方が違う場合(例えば12のように縦に消したり)に出るエラーだと思います。このプログラムの0はどのような意味なのでしょうか。
int user[6] = { 0 }; で user は { 0, 0, 0, 0, 0, 0 } と初期化されます。
i にはプレイヤーの入力が入っています。例えば 23 とします。
conv(23, user) で conv を呼び出すと、conv の中で
user[1] = user[2] = 1 が実行され、
user は { 0, 1, 1, 0, 0, 0 } となります。
これはプレーヤが消したい棒を表しています。
return user[1] = user[2] = 1; なので、
conv は 1 を返します。
conv が 0 を返さなかったので、{ puts("エラー"); continue; } は
実行されません。
プレイヤーの入力が例えば 34 であったとすると、
conv は 0 を返します。
0 だったらエラー表示です。
angel-wing さんが書きました: ↑5年前
(5) (4)の続き、if (user[ i] == 1) if (st[ i] == 0) i = 9; else st[ i] = 0;
ここの3行ですが、「userが入力した配列が1の場合、または配列の中が0になった場合かiが9の場合、もしくは配列内が0の場合、iが5になるまで繰り返す(for)」と読みましたが、違いますよね……どのように解釈すればよいのでしょうか。
user の値が { 0, 1, 1, 0, 0, 0 } だったとすると、
user[1] == 1 ですから、2 の棒を消したいということです。
st[1] == 0 だと、2の棒は既に消されているので、エラーです。
i を 6以上の値にして、for文の i++ で 6 より大きい値にして
forループを終了させます。
st[1] が 1 だと、2の棒があるので、st[1] = 0; でその棒を消します。
user[2] == 1 は 3の棒を消したいということで、以下同様。
user[ i] が 0 の時は、棒を消しません。
angel-wing さんが書きました: ↑5年前
(6) i = st[0]*32 + st[1]*16 + st[2]*8 + st[3]*4 + st[4]*2 + st[5];
ここがプログラムの中枢計算だと思うのですが、これはおそらく「64パターンを2進数に分解して和を求めている」ということでしょうか。
すると、次のi = pat[ i][rand() % 2]; は、「和が偶数の場合」の処理ということでしょうか。これは凄いですね……。
st の値が { 0, 1,1, 1,1,1 } だと、これを 2進数の 011111 だと解釈して
i = 0*32 + 1*16 + 1*8 + 1*4 + 1*2 + 1 = 31 という値を得ます。
st の値が { 1, 1,1, 0,0,0 } だと、これを 2進数の 111000 だと解釈して
i = 1*32 + 1*16 + 1*8 + 0*4 + 0*2 + 0 = 56 という値を得ます。
これらの値は pat の何番目を選択するかということに使います。
rand() % 2 は乱数を 2で割った余りなので、0 または 1 です。
pat の i番目は 2つの値があるので、どちらかを乱数で選ぶことになります。
angel-wing さんが書きました: ↑5年前
(7) int mainの、while (game() == 0) {
というのは、「game関数が0の場合→ゲームが終わった場合」という意味でしょうか。
game が 0 を返すのは、勝敗がついた(プレイヤーが負けた)時です。
game が 0以外を返すのは、game の中でエラーがあった時です。
angel-wing さんが書きました: ↑5年前
(8) 最後の、if (!fgets(buf, sizeof buf, stdin) || buf[0] != 'r') break;
というのは、「文字列がサイズを持たない場合(勝負がついた場合?) or 'r’が入力されない場合は、ゲームを終了する(main関数を抜ける)」という意味でしょうか。
EOFの入力などで行入力が失敗したか、または 'r' が入力されない場合は、
whileループを終了する、という意味です。