#30
by angel-wing » 5年前
調べましたが、分からないところがたくさんです;;
お助けいただければ幸いです<(..)>。
(1) return 0と1が使い分けられていますが、何か意図があるのでしょうか(全て0にしてみてもエラーは出ない様子ですが)。
(2) 最初の64個の配列(二次元配列)が持つ意味や順序が分かりません……。
(3) int game内の if (!fgets(buf, sizeof buf, stdin)) return 0;
には、どのような意味がありますか。「stdinでキーボードから文字列を受け取り、関数冒頭で定義したbufに当てはめてサイズを取得する→もしサイズが取得できなければ、printfの内容を表示する」という解釈で大丈夫でしょうか……。
(4) int user以下で、if (conv(i, user) == 0) { puts("エラー"); continue; }
ですが、「userの入力が0ならば、エラー表示をする」ように読めたのですが、実際は消し方が違う場合(例えば12のように縦に消したり)に出るエラーだと思います。このプログラムの0はどのような意味なのでしょうか。
(5) (4)の続き、if (user
== 1) if (st == 0) i = 9; else st = 0;
ここの3行ですが、「userが入力した配列が1の場合、または配列の中が0になった場合かiが9の場合、もしくは配列内が0の場合、iが5になるまで繰り返す(for)」と読みましたが、違いますよね……どのように解釈すればよいのでしょうか。
(6) i = st[0]*32 + st[1]*16 + st[2]*8 + st[3]*4 + st[4]*2 + st[5];
ここがプログラムの中枢計算だと思うのですが、これはおそらく「64パターンを2進数に分解して和を求めている」ということでしょうか。
すると、次のi = pat[rand() % 2]; は、「和が偶数の場合」の処理ということでしょうか。これは凄いですね……。
(7) int mainの、while (game() == 0) {
というのは、「game関数が0の場合→ゲームが終わった場合」という意味でしょうか。
(8) 最後の、if (!fgets(buf, sizeof buf, stdin) || buf[0] != 'r') break;
というのは、「文字列がサイズを持たない場合(勝負がついた場合?) or 'r’が入力されない場合は、ゲームを終了する(main関数を抜ける)」という意味でしょうか。
↓少し弄ってあります。。。
コード:
#include <stdio.h> // fgets, printf, puts
#include <stdlib.h> // atoi, rand
int pat[64][2] = {
{ 0, 0 }, { 6, 6 }, { 5, 5 }, { 5, 6 }, { 4, 4 }, { 4, 6 }, { 4, 5 },
{45,56 }, { 3, 3 }, { 3, 6 }, { 3, 5 }, {56,56 }, { 3, 4 }, { 3, 4 },
{45,45 }, {456,456}, { 2, 2 }, { 2, 6 }, { 2, 5 }, {56,56 }, { 2, 4 }, //行数・要素数を64パターン
{ 2, 4 }, { 45,45 }, {456,456}, { 2, 3 }, { 2, 3 }, { 2, 3 }, { 2, 5 }, // 2の6乗が64だ
{23,23 }, { 2, 3 }, { 2, 4 }, { 4, 6 }, { 1, 1 }, { 1, 6 }, { 1, 5 }, //このパターンが示す意味や順序は謎すぎる→ビット関数?
{ 5, 6 }, { 1, 1 }, { 1, 4 }, {45,45 }, {456,5 }, { 1, 1 }, { 1, 3 },
{ 1, 3 }, { 5, 6 }, { 1, 3 }, { 3, 1 }, { 4, 5 }, {45,56 }, { 1, 2 },
{ 1, 2 }, { 1, 2 }, { 5, 6 }, { 1, 2 }, { 4, 6 }, { 4, 5 }, {45,56 },
{23,23 }, { 2, 3 }, { 2, 3 }, { 1, 1 }, { 2, 3 }, {23,23 }, { 1, 1 },
{ 1, 6 }
};
void print(int *st)
{
printf("\n" " ~*~*~*~*~*~*~*~*~*~*~\n" //表示させるだけで戻り値を要求しないからvoid関数
" 1 %d\n" //*はポインタを表す間接演算子で、付着したものはポインタ変数となる
" 2 3 %d %d\n" //1~6を、配列[0]~[5]と置いてポインタ設置(この順序)
" 4 5 6 %d %d %d\n\n", //ポインタ関数にしたので、ポインタに代入可能になった様子
st[0], st[1], st[2], st[3], st[4], st[5]);
}
int conv(int n, int *user) //まずは、初期設定をする
{ //convの関数で、数字と各配列を変換する
if (n >= 1 && n <= 6) return user[n-1] = 1; //1つ変換する場合、nが1~6の場合は、n-1をした箇所の配列を1に変換
if (n == 23) return user[1] = user[2] = 1;
if (n == 45) return user[3] = user[4] = 1; //2つ変換する場合、nが23→1,2を、45→3,4を、56→4,5を1に変換
if (n == 56) return user[4] = user[5] = 1;
if (n == 456) return user[3] = user[4] = user[5] = 1; //3つ選択する場合、nが456→3,4,5の配列を1に変換
return 0;
}
int game(void) //ここからがゲームのメインとなる関数!
{
char buf[256]; //文字入力用の変数bufを宣言
int st[6] = { 1, 1,1, 1,1,1 }, i; //配列を3段で認識させ、数値型iも宣言
print(st); //三段に認識された配列を表示(上で1を代入されたものが出てくる)
while (1) { //while文によってループを開始する
printf("【あなたの番だよ。どれを消すの?】\n"); //fgets(file get)はファイルから文字列を1行取得する関数
if (!fgets(buf, sizeof buf, stdin)) return 0; //stdinは標準入力(キーボード)から文字列を受け取る標準ストリームだけど、記述内
容が謎
i = atoi(buf); //atoiで読み取った文字列をint型の数字に変換する
if (i == 0) { puts("\n<エラーパターンAを確認!> そこはダメ! ふざけてないで真剣にやって!\n"); continue; } //putsはprintfでも可、continue
はwhileブロック内をループ
int user[6] = { 0 }; //userの配列を全て0で初期化して宣言
if (conv(i, user) == 0) { puts("\n<エラーパターンBを確認!> どういう消し方だよ……ねぇ、やる気あるの?\n"); continue; } //前半が謎すぎる
for (i = 0; i < 6; i++) //変数iを、0~5まで増やしていく
if (user[i] == 1) //これ以降3行のfor文が謎すぎて頭髪が抜けた
if (st[i] == 0) i = 9; //i=9って何だろう?
else st[i] = 0; //st[i]=0が分からなくて、また頭髪が抜けた
if (i > 6) { puts("\n<エラーパターンCを確認!> ねぇ知ってる? 0は消せないんだよ?\n"); continue; } //どうしてi>6 で0を表すのかが謎!
print(st); //printfじゃなくて、print??
printf("今度は私が消すから「Enter」を押してね!"); //putsにしても大丈夫だった件
if (!fgets(buf, sizeof buf, stdin)) return 0; //returnは1になっていたが、0でも問題がなかった件
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]; //上記の和を2で割る →おそらく、和が偶数になるようにランダムで選択している?
printf("\n私は %d を消したよ。\n", i); //その解をprogramの手とする
int comp[6] = { 0 }; //userと同じくprogramの配列を全て0で初期化している
conv(i, comp); //変数iとcomp(program)を宣言
for (i = 0; i < 6; i++) //変数iを0から5に増やしていく
if (comp[i] == 1) st[i] = 0; //配列が1になった場合、0を代入? ifを復習し直し!
print(st); //printfじゃなくて、またprint?
if (st[0]+st[1]+st[2]+st[3]+st[4]+st[5] == 1) { //配列の、恐らく論理和が1ということは、userの手番で1を引くから勝負あり
puts("(^.^)v† はい、あなたの負け~!!"); return 0; //上記の結果により、putsでuser敗北の記述
}
}
}
int main(void) //最後にmain関数ですと!?
{
puts("線消しGAME『お前はもうツんでいる』へようこそ☆彡"); //main関数が先処理なので、ゲーム開始文をここに入れてみた件
while (game() == 0) { //game関数が0の場合→gameが終わった場合?
char buf[256]; //文字入力用のbufを変数宣言
puts("時間の無駄だけど、もう一度やる→r\n実力不足を認めて、潔く立ち去る→他\n"); //printfでも可能
if (!fgets(buf, sizeof buf, stdin) || buf[0] != 'r') break; //main関数を抜ける条件が2つ→[43行目と同様] or [r以外を押すこと]かな?
} //[!fgets(buf, sizeof buf, stdin)の内容は、勝負がついた]場合
}
調べましたが、分からないところがたくさんです;;
お助けいただければ幸いです<(..)>。
(1) return 0と1が使い分けられていますが、何か意図があるのでしょうか(全て0にしてみてもエラーは出ない様子ですが)。
(2) 最初の64個の配列(二次元配列)が持つ意味や順序が分かりません……。
(3) int game内の if (!fgets(buf, sizeof buf, stdin)) return 0;
には、どのような意味がありますか。「stdinでキーボードから文字列を受け取り、関数冒頭で定義したbufに当てはめてサイズを取得する→もしサイズが取得できなければ、printfの内容を表示する」という解釈で大丈夫でしょうか……。
(4) int user以下で、if (conv(i, user) == 0) { puts("エラー"); continue; }
ですが、「userの入力が0ならば、エラー表示をする」ように読めたのですが、実際は消し方が違う場合(例えば12のように縦に消したり)に出るエラーだと思います。このプログラムの0はどのような意味なのでしょうか。
(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)」と読みましたが、違いますよね……どのように解釈すればよいのでしょうか。
(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]; は、「和が偶数の場合」の処理ということでしょうか。これは凄いですね……。
(7) int mainの、while (game() == 0) {
というのは、「game関数が0の場合→ゲームが終わった場合」という意味でしょうか。
(8) 最後の、if (!fgets(buf, sizeof buf, stdin) || buf[0] != 'r') break;
というのは、「文字列がサイズを持たない場合(勝負がついた場合?) or 'r’が入力されない場合は、ゲームを終了する(main関数を抜ける)」という意味でしょうか。
↓少し弄ってあります。。。
[code]
#include <stdio.h> // fgets, printf, puts
#include <stdlib.h> // atoi, rand
int pat[64][2] = {
{ 0, 0 }, { 6, 6 }, { 5, 5 }, { 5, 6 }, { 4, 4 }, { 4, 6 }, { 4, 5 },
{45,56 }, { 3, 3 }, { 3, 6 }, { 3, 5 }, {56,56 }, { 3, 4 }, { 3, 4 },
{45,45 }, {456,456}, { 2, 2 }, { 2, 6 }, { 2, 5 }, {56,56 }, { 2, 4 }, //行数・要素数を64パターン
{ 2, 4 }, { 45,45 }, {456,456}, { 2, 3 }, { 2, 3 }, { 2, 3 }, { 2, 5 }, // 2の6乗が64だ
{23,23 }, { 2, 3 }, { 2, 4 }, { 4, 6 }, { 1, 1 }, { 1, 6 }, { 1, 5 }, //このパターンが示す意味や順序は謎すぎる→ビット関数?
{ 5, 6 }, { 1, 1 }, { 1, 4 }, {45,45 }, {456,5 }, { 1, 1 }, { 1, 3 },
{ 1, 3 }, { 5, 6 }, { 1, 3 }, { 3, 1 }, { 4, 5 }, {45,56 }, { 1, 2 },
{ 1, 2 }, { 1, 2 }, { 5, 6 }, { 1, 2 }, { 4, 6 }, { 4, 5 }, {45,56 },
{23,23 }, { 2, 3 }, { 2, 3 }, { 1, 1 }, { 2, 3 }, {23,23 }, { 1, 1 },
{ 1, 6 }
};
void print(int *st)
{
printf("\n" " ~*~*~*~*~*~*~*~*~*~*~\n" //表示させるだけで戻り値を要求しないからvoid関数
" 1 %d\n" //*はポインタを表す間接演算子で、付着したものはポインタ変数となる
" 2 3 %d %d\n" //1~6を、配列[0]~[5]と置いてポインタ設置(この順序)
" 4 5 6 %d %d %d\n\n", //ポインタ関数にしたので、ポインタに代入可能になった様子
st[0], st[1], st[2], st[3], st[4], st[5]);
}
int conv(int n, int *user) //まずは、初期設定をする
{ //convの関数で、数字と各配列を変換する
if (n >= 1 && n <= 6) return user[n-1] = 1; //1つ変換する場合、nが1~6の場合は、n-1をした箇所の配列を1に変換
if (n == 23) return user[1] = user[2] = 1;
if (n == 45) return user[3] = user[4] = 1; //2つ変換する場合、nが23→1,2を、45→3,4を、56→4,5を1に変換
if (n == 56) return user[4] = user[5] = 1;
if (n == 456) return user[3] = user[4] = user[5] = 1; //3つ選択する場合、nが456→3,4,5の配列を1に変換
return 0;
}
int game(void) //ここからがゲームのメインとなる関数!
{
char buf[256]; //文字入力用の変数bufを宣言
int st[6] = { 1, 1,1, 1,1,1 }, i; //配列を3段で認識させ、数値型iも宣言
print(st); //三段に認識された配列を表示(上で1を代入されたものが出てくる)
while (1) { //while文によってループを開始する
printf("【あなたの番だよ。どれを消すの?】\n"); //fgets(file get)はファイルから文字列を1行取得する関数
if (!fgets(buf, sizeof buf, stdin)) return 0; //stdinは標準入力(キーボード)から文字列を受け取る標準ストリームだけど、記述内
容が謎
i = atoi(buf); //atoiで読み取った文字列をint型の数字に変換する
if (i == 0) { puts("\n<エラーパターンAを確認!> そこはダメ! ふざけてないで真剣にやって!\n"); continue; } //putsはprintfでも可、continue
はwhileブロック内をループ
int user[6] = { 0 }; //userの配列を全て0で初期化して宣言
if (conv(i, user) == 0) { puts("\n<エラーパターンBを確認!> どういう消し方だよ……ねぇ、やる気あるの?\n"); continue; } //前半が謎すぎる
for (i = 0; i < 6; i++) //変数iを、0~5まで増やしていく
if (user[i] == 1) //これ以降3行のfor文が謎すぎて頭髪が抜けた
if (st[i] == 0) i = 9; //i=9って何だろう?
else st[i] = 0; //st[i]=0が分からなくて、また頭髪が抜けた
if (i > 6) { puts("\n<エラーパターンCを確認!> ねぇ知ってる? 0は消せないんだよ?\n"); continue; } //どうしてi>6 で0を表すのかが謎!
print(st); //printfじゃなくて、print??
printf("今度は私が消すから「Enter」を押してね!"); //putsにしても大丈夫だった件
if (!fgets(buf, sizeof buf, stdin)) return 0; //returnは1になっていたが、0でも問題がなかった件
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]; //上記の和を2で割る →おそらく、和が偶数になるようにランダムで選択している?
printf("\n私は %d を消したよ。\n", i); //その解をprogramの手とする
int comp[6] = { 0 }; //userと同じくprogramの配列を全て0で初期化している
conv(i, comp); //変数iとcomp(program)を宣言
for (i = 0; i < 6; i++) //変数iを0から5に増やしていく
if (comp[i] == 1) st[i] = 0; //配列が1になった場合、0を代入? ifを復習し直し!
print(st); //printfじゃなくて、またprint?
if (st[0]+st[1]+st[2]+st[3]+st[4]+st[5] == 1) { //配列の、恐らく論理和が1ということは、userの手番で1を引くから勝負あり
puts("(^.^)v† はい、あなたの負け~!!"); return 0; //上記の結果により、putsでuser敗北の記述
}
}
}
int main(void) //最後にmain関数ですと!?
{
puts("線消しGAME『お前はもうツんでいる』へようこそ☆彡"); //main関数が先処理なので、ゲーム開始文をここに入れてみた件
while (game() == 0) { //game関数が0の場合→gameが終わった場合?
char buf[256]; //文字入力用のbufを変数宣言
puts("時間の無駄だけど、もう一度やる→r\n実力不足を認めて、潔く立ち去る→他\n"); //printfでも可能
if (!fgets(buf, sizeof buf, stdin) || buf[0] != 'r') break; //main関数を抜ける条件が2つ→[43行目と同様] or [r以外を押すこと]かな?
} //[!fgets(buf, sizeof buf, stdin)の内容は、勝負がついた]場合
}
[/code]