![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
外枠と、中の柱を建てることはできたのですが、棒を倒すことができません。
コンパイルしようとすると、停止してしまいます。
どこがまずいのか、教えてください。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int field[13][13]={0}; //0で初期化
int dice=0;
srand((unsigned)time(NULL));
/*
9が■、0が□
外枠
*/
for(int i=0; i<13; ++i){
for(int j=0; j<13; ++j){
field[0][j]=9;
field[12][j]=9;
field[i][0]=9;
field[i][12]=9;
/*
中の柱 5本×5本
*/
for(int i=1; i<=5; ++i){
for(int j=1; j<=5; ++j){
field[i*2][j*2]=9;
}
}
/*
わかりません ><;
フリーズします・・・
*/
if(i == 2){ //2列目なら
dice=rand()%4; //サイコロで上下左右
}else if(i>=3){ //3列目以降
dice=rand()%3; //サイコロで下左右
switch(dice){
case 0:
field[i*2][j*2-1]=9;// 左
printf("■");
break;
case 1:
field[i*2+1][j*2]=9;// 下
printf("■");
break;
case 2:
field[i*2][j*2+1]=9;// 右
printf("■");
break;
case 3:
field[i*2-1][j*2]=9;// 上
printf("■");
break;
defalult: break;
}
}else{
printf("□");
}
}
printf("\n");
}
return 0;
}
No.4ベストアンサー
- 回答日時:
うーん、多分・・・まあ、ぶっちゃけ、「棒倒し法」とか初めて聞いたんで(笑)、ググりながら組み立ててみたんですが、次のようなロジックになるんじゃないでしょうか。
// ここから
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
enum Direction { RIGHT, DOWN, LEFT, UP }; /* 列挙体で方向を定義 */
enum Element { EMPTY, WALL }; /* 列挙体で壁(WALL)と空(EMPTY)を定義 */
#define MAX 13 /* 取り敢えず field の長さを指定する */
/* 関数のプロトタイプ宣言 */
void initialize_field(int array[][MAX]);
void print_field(int array[][MAX]);
int dice(int n);
void make_maze(int array[][MAX]);
void selector(int n, int i, int j, int array[][MAX]);
int main(void) {
int field[MAX][MAX];
srand((unsigned)time(NULL));
/* field の初期化 */
initialize_field(field);
/* maze の作成 */
make_maze(field);
/* field の表示 */
print_field(field);
return 0;
}
/* field の初期化 */
void initialize_field(int array[][MAX]) {
int i, j;
for (i = 0; i < MAX; i++) {
for (j = 0; j < MAX; j++) {
/* 最初の行と最後の行は全部 WALL で埋まる */
if (i == 0 || i == 12)
array[i][j] = WALL;
/* 行数(i)・列数(j) 共に偶数の場合は WALL になる */
else if (i % 2 == 0) {
if (j % 2 == 0)
array[i][j] = WALL;
else
array[i][j] = EMPTY;
}
/* それ以外は行の最初と最後は WALL、それ以外は EMPTY で埋める */
else {
if (j == 0 || j == MAX-1)
array[i][j] = WALL;
else
array[i][j] = EMPTY;
}
}
}
}
/* field の表示 */
void print_field(int array[][MAX]) {
int i, j;
for (i = 0; i < MAX; i++) {
for (j = 0; j < MAX; j++) {
switch (array[i][j]) {
case WALL:
printf("%s", "■");
break;
default :
printf("%s", "□");
break;
}
}
printf("\n");
}
}
/* サイコロの定義 */
int dice(int n) {
return rand()%n;
}
/* maze(迷路)作成 */
void make_maze(int array[][MAX]) {
int i, j;
/* 端以外は行・列共に偶数の時壁なので、ループを回す初期値は2、以降カウンタは2づつ増やす */
for (i = 2; i < MAX-1; i += 2) {
for (j = 2; j < MAX-1; j += 2) {
if (i == 2)
selector(4, i, j, array);
else {
if (array[i][j-1] == WALL)
selector(2, i, j, array);
else
selector(3, i, j, array);
}
}
}
}
/* 条件でn面体サイコロを変えて配列のどこを変更するか決める */
void selector(int n, int i, int j, int array[][MAX]) {
switch(dice(n)) {
case RIGHT:
array[i][j+1] = WALL;
break;
case DOWN:
array[i+1][j] = WALL;
break;
case LEFT:
array[i][j-1] = WALL;
break;
default :
array[i-1][j] = WALL;
break;
}
}
// ここまで
まあ、ググりながら書いてみたんですが、どうもこう・・・ハッキリくっきり解説してるサイトが見つからなかったんですよね(笑)。
でも多分こういう事だと思います。
コメントでも書いてますが、要点は次のようなカンジです。
★最重要:「棒倒し」のループの中では行数・列数のコンビは偶数でないとならない。
まあ、最初の行と最後の行は「全部壁」なんで除外しますが、基本的にはループは2から初めて偶数飛びにしていかないといけません。
イメージ的には棒の上を飛んでくカンジでしょうか。
だから、forループを回す際に、
for (i = 0, ...
for(j = 0, ...
だとダメなんです。
for (i = 2, ...
for (j = 2, ....
じゃないといけない。
かつ、手癖で、カウンタ更新を
i++
とやっちゃうのも良くないですね。棒は必ず(偶数, 偶数)に存在するので、i += 2じゃないと「棒から落ちちゃい」ます。
そして「棒の上に立ってる」状態でサイコロを振って、その結果に従って棒を上下左右のどれかに「蹴り倒す」(つまり、多元配列の隣り合った4つの要素の「どれか」を「壁」として書き換える)わけです。
んで、棒倒し法の場合、大まかに言うと次のルールがあります。
1. 多元配列で言う2行目だけは乱数に従って上下左右どこへでも棒を蹴り倒して良い。
2. 2行目以外は棒を上に蹴ってはならない。棒は下と左右だけに蹴る事が出来るが、次の付随ルールがある。
a. 左に棒が倒れてる場合は下と右にしか蹴れない
b. 左に棒が倒れてなかったら下と左右どれかに蹴飛ばして構わない。
まあ、壁がどこに作れるのか、って言い換えても良いでしょうが、上のようなルールがあります。上のコードで言うと、make_mazeって関数はこのルールに従って書いています。
さて、上のコードの解説をちょっとだけしますが、ここで気づいたでしょうが、実は「棒を蹴る方向」ってのには優先度があるんですね。
1. 右と下は「いつでも」蹴られる可能性がある。
2. 左は蹴られる可能性があったり無かったりする。
3. 上はループが多元配列の2行目にいない限り蹴られる可能性は全く無い。
つまり、乱数生成でサイコロを作る場合「サイコロの面の数」さえ変えればこの状況は割に簡単に記述出来るんです。
つまり、
・上下左右どこに蹴っても良い(多元配列二行目)のケース -> rand()%4を適用すれば良い
・下と左右どこに蹴っても良いケース -> rand()%3を適用すれば良い
・下と右どっちに蹴っても良いケース->rand()%2を適用すれば良い
rand()%nは0, 1, 2...(n-1)のどれかを返すわけですから、そうなると確実に蹴られる可能性がある右と下には0や1の値を与えて、優先度に従って「適当な数」に「適当な方向」を与えてやれば良い、って事になるわけです。
そこで出てきたのが列挙体でのDirection定義なわけです。
enum Direction { RIGHT, DOWN, LEFT, UP };
これは実は
int RIGHT = 0;
int DOWN = 1;
int LEFT = 2;
int UP = 3;
って宣言と同じなんですが、まあ、メンド臭いので(笑)、こういうカタチで定義してます。
RIGHTとDOWNに関してはどっちも「必ず蹴られる可能性がある」んで0と1、どっちにしてもいいんですが、LEFTは「やや弱い蹴られる可能性」がある、UPは「殆ど蹴られる可能性が」無い、ってぇんでこういう数値割り振りをしてます(つまり、置いた順序には意味があるのです)。
こうしておけば、例えば多元配列の2行目だった場合
rand()%4 -> 0, 1, 2, 3のどれか -> RIGHT, DOWN, LEFT, UPのどれかが選ばれる
わけですし、二行目以外で、特定の(偶数, 偶数)座標の左に「棒が蹴倒されてた場合」(つまり壁があった場合)、
rand()%2 -> 0, 1のどっちか -> RIGHTかDOWNが選ばれる
と自動的に決まるわけです。
No.3
- 回答日時:
確かに default ラベルのスペルは間違っていますが, この質問文にあるプログラムに関して言えばそこは現在の問題とは関係ありません (dice の値は case ラベルのどれかと一致するためそもそも default に落ちない).
プログラムを
#include <stdio.h>
int main(void)
{
int field[13][13]={0}; //0で初期化
/*
9が■、0が□
外枠
*/
for(int i=0; i<13; ++i){
for(int j=0; j<13; ++j){
if(i>=3){ //3列目以降
field[i*2][j*2-1]=9;// 左
printf("■");
}
}
printf("\n");
}
return 0;
}
まで圧縮したら気づくかな?
No.2
- 回答日時:
うん、#1さんが言う通りですか。
>とりあえず
>× defalult: break;
>○ default: break;
そこがおかしいと、例えばclangでコンパイルして実行すると、
~ $ ./a.out
□□□□□□□□□□□□□
□□□□□□□□□□□□□
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
segmentation fault (core dumped)
とセグメンテーションフォールトが起きるんですが、そこを直すと
~ $ ./a.out
□□□□□□□□□□□□□
□□□□□□□□□□□□□
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
■■■■■■■■■■■■■
とセグフォが起きないんで、デフォルトがタイポでフツーに動かなかったんですかね。
No.1
- 回答日時:
> コンパイルしようとすると、停止してしまいます。
エラーメッセージが表示されると思いますが、まずそれを提示すべきではないでしょうか?
とりあえず
× defalult: break;
○ default: break;
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# C言語 3 2022/11/09 13:27
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「指定されたキャストは有効で...
-
複数桁10進数の*桁目だけを抽出...
-
C言語での引数の省略方法
-
市松模様
-
構造体の勉強中です 合計点の高...
-
#define _CRT_SECURE_NO_WARNIN...
-
「{ } で囲むだけ」は正しい?
-
C言語初心者です、、、お助けく...
-
C言語の構造体について
-
C言語でDxlibを使って3x3の奇数...
-
C言語における対称行列の作り方...
-
このプログラミング誰か教えて...
-
CStringの配列要素を関数で受け...
-
if と配列の組み合わせ
-
因数分解を行うプログラムについて
-
式は定数値が必要です」という...
-
C言語 エラーの原因がわからな...
-
数字列を3桁ごとにカンマで区切...
-
C言語のサイコロシミュレート
-
ファイルから読みこむ方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
複数桁10進数の*桁目だけを抽出...
-
【C++】関数ポインタの使い方
-
C言語 エラーの原因がわからな...
-
c++でテンプレートのコードでわ...
-
(int *)の意味
-
ラップ関数とはどんなものですか?
-
数字列を3桁ごとにカンマで区切...
-
c言語のリダイレクトによる円...
-
比較回数と交換回数表示について
-
実数の整数部,小数部の取得
-
if と配列の組み合わせ
-
構造体の勉強中です 合計点の高...
-
PowerShellがうまくいかない
-
c言語の配列を使ってサイコロを...
-
課題でつまってます・・・
-
C言語のサイコロシミュレート
-
エラー 添字が付けられた値が、...
おすすめ情報
このようなポップアップが出て、停止します。
~略~
/*
中の柱 5本×5本
*/
for(int i=1; i<=5; ++i){
for(int j=1; j<=5; ++j){
field[i*2][j*2]=9;
}
}
/*
とりあえず、柱だけにしてみて、考えてみましたが、
条件式がおかしいのでしょうか?
どうすればいいのか全然わかかりません・・・。
*/
if(field[i][j]==9){
printf("■");
}else{
printf("□");
}
}
printf("\n");
}
return 0;
}